linux/drivers/video/fbdev/via/via_clock.c
<<
>>
Prefs
   1/*
   2 * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
   3 * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
   4 * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public
   8 * License as published by the Free Software Foundation;
   9 * either version 2, or (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
  13 * the implied warranty of MERCHANTABILITY or FITNESS FOR
  14 * A PARTICULAR PURPOSE.See the GNU General Public License
  15 * for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc.,
  20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21 */
  22/*
  23 * clock and PLL management functions
  24 */
  25
  26#include <linux/kernel.h>
  27#include <linux/via-core.h>
  28#include <asm/olpc.h>
  29#include "via_clock.h"
  30#include "global.h"
  31#include "debug.h"
  32
  33static const char *via_slap = "Please slap VIA Technologies to motivate them "
  34        "releasing full documentation for your platform!\n";
  35
  36static inline u32 cle266_encode_pll(struct via_pll_config pll)
  37{
  38        return (pll.multiplier << 8)
  39                | (pll.rshift << 6)
  40                | pll.divisor;
  41}
  42
  43static inline u32 k800_encode_pll(struct via_pll_config pll)
  44{
  45        return ((pll.divisor - 2) << 16)
  46                | (pll.rshift << 10)
  47                | (pll.multiplier - 2);
  48}
  49
  50static inline u32 vx855_encode_pll(struct via_pll_config pll)
  51{
  52        return (pll.divisor << 16)
  53                | (pll.rshift << 10)
  54                | pll.multiplier;
  55}
  56
  57static inline void cle266_set_primary_pll_encoded(u32 data)
  58{
  59        via_write_reg_mask(VIASR, 0x40, 0x02, 0x02); /* enable reset */
  60        via_write_reg(VIASR, 0x46, data & 0xFF);
  61        via_write_reg(VIASR, 0x47, (data >> 8) & 0xFF);
  62        via_write_reg_mask(VIASR, 0x40, 0x00, 0x02); /* disable reset */
  63}
  64
  65static inline void k800_set_primary_pll_encoded(u32 data)
  66{
  67        via_write_reg_mask(VIASR, 0x40, 0x02, 0x02); /* enable reset */
  68        via_write_reg(VIASR, 0x44, data & 0xFF);
  69        via_write_reg(VIASR, 0x45, (data >> 8) & 0xFF);
  70        via_write_reg(VIASR, 0x46, (data >> 16) & 0xFF);
  71        via_write_reg_mask(VIASR, 0x40, 0x00, 0x02); /* disable reset */
  72}
  73
  74static inline void cle266_set_secondary_pll_encoded(u32 data)
  75{
  76        via_write_reg_mask(VIASR, 0x40, 0x04, 0x04); /* enable reset */
  77        via_write_reg(VIASR, 0x44, data & 0xFF);
  78        via_write_reg(VIASR, 0x45, (data >> 8) & 0xFF);
  79        via_write_reg_mask(VIASR, 0x40, 0x00, 0x04); /* disable reset */
  80}
  81
  82static inline void k800_set_secondary_pll_encoded(u32 data)
  83{
  84        via_write_reg_mask(VIASR, 0x40, 0x04, 0x04); /* enable reset */
  85        via_write_reg(VIASR, 0x4A, data & 0xFF);
  86        via_write_reg(VIASR, 0x4B, (data >> 8) & 0xFF);
  87        via_write_reg(VIASR, 0x4C, (data >> 16) & 0xFF);
  88        via_write_reg_mask(VIASR, 0x40, 0x00, 0x04); /* disable reset */
  89}
  90
  91static inline void set_engine_pll_encoded(u32 data)
  92{
  93        via_write_reg_mask(VIASR, 0x40, 0x01, 0x01); /* enable reset */
  94        via_write_reg(VIASR, 0x47, data & 0xFF);
  95        via_write_reg(VIASR, 0x48, (data >> 8) & 0xFF);
  96        via_write_reg(VIASR, 0x49, (data >> 16) & 0xFF);
  97        via_write_reg_mask(VIASR, 0x40, 0x00, 0x01); /* disable reset */
  98}
  99
 100static void cle266_set_primary_pll(struct via_pll_config config)
 101{
 102        cle266_set_primary_pll_encoded(cle266_encode_pll(config));
 103}
 104
 105static void k800_set_primary_pll(struct via_pll_config config)
 106{
 107        k800_set_primary_pll_encoded(k800_encode_pll(config));
 108}
 109
 110static void vx855_set_primary_pll(struct via_pll_config config)
 111{
 112        k800_set_primary_pll_encoded(vx855_encode_pll(config));
 113}
 114
 115static void cle266_set_secondary_pll(struct via_pll_config config)
 116{
 117        cle266_set_secondary_pll_encoded(cle266_encode_pll(config));
 118}
 119
 120static void k800_set_secondary_pll(struct via_pll_config config)
 121{
 122        k800_set_secondary_pll_encoded(k800_encode_pll(config));
 123}
 124
 125static void vx855_set_secondary_pll(struct via_pll_config config)
 126{
 127        k800_set_secondary_pll_encoded(vx855_encode_pll(config));
 128}
 129
 130static void k800_set_engine_pll(struct via_pll_config config)
 131{
 132        set_engine_pll_encoded(k800_encode_pll(config));
 133}
 134
 135static void vx855_set_engine_pll(struct via_pll_config config)
 136{
 137        set_engine_pll_encoded(vx855_encode_pll(config));
 138}
 139
 140static void set_primary_pll_state(u8 state)
 141{
 142        u8 value;
 143
 144        switch (state) {
 145        case VIA_STATE_ON:
 146                value = 0x20;
 147                break;
 148        case VIA_STATE_OFF:
 149                value = 0x00;
 150                break;
 151        default:
 152                return;
 153        }
 154
 155        via_write_reg_mask(VIASR, 0x2D, value, 0x30);
 156}
 157
 158static void set_secondary_pll_state(u8 state)
 159{
 160        u8 value;
 161
 162        switch (state) {
 163        case VIA_STATE_ON:
 164                value = 0x08;
 165                break;
 166        case VIA_STATE_OFF:
 167                value = 0x00;
 168                break;
 169        default:
 170                return;
 171        }
 172
 173        via_write_reg_mask(VIASR, 0x2D, value, 0x0C);
 174}
 175
 176static void set_engine_pll_state(u8 state)
 177{
 178        u8 value;
 179
 180        switch (state) {
 181        case VIA_STATE_ON:
 182                value = 0x02;
 183                break;
 184        case VIA_STATE_OFF:
 185                value = 0x00;
 186                break;
 187        default:
 188                return;
 189        }
 190
 191        via_write_reg_mask(VIASR, 0x2D, value, 0x03);
 192}
 193
 194static void set_primary_clock_state(u8 state)
 195{
 196        u8 value;
 197
 198        switch (state) {
 199        case VIA_STATE_ON:
 200                value = 0x20;
 201                break;
 202        case VIA_STATE_OFF:
 203                value = 0x00;
 204                break;
 205        default:
 206                return;
 207        }
 208
 209        via_write_reg_mask(VIASR, 0x1B, value, 0x30);
 210}
 211
 212static void set_secondary_clock_state(u8 state)
 213{
 214        u8 value;
 215
 216        switch (state) {
 217        case VIA_STATE_ON:
 218                value = 0x80;
 219                break;
 220        case VIA_STATE_OFF:
 221                value = 0x00;
 222                break;
 223        default:
 224                return;
 225        }
 226
 227        via_write_reg_mask(VIASR, 0x1B, value, 0xC0);
 228}
 229
 230static inline u8 set_clock_source_common(enum via_clksrc source, bool use_pll)
 231{
 232        u8 data = 0;
 233
 234        switch (source) {
 235        case VIA_CLKSRC_X1:
 236                data = 0x00;
 237                break;
 238        case VIA_CLKSRC_TVX1:
 239                data = 0x02;
 240                break;
 241        case VIA_CLKSRC_TVPLL:
 242                data = 0x04; /* 0x06 should be the same */
 243                break;
 244        case VIA_CLKSRC_DVP1TVCLKR:
 245                data = 0x0A;
 246                break;
 247        case VIA_CLKSRC_CAP0:
 248                data = 0xC;
 249                break;
 250        case VIA_CLKSRC_CAP1:
 251                data = 0x0E;
 252                break;
 253        }
 254
 255        if (!use_pll)
 256                data |= 1;
 257
 258        return data;
 259}
 260
 261static void set_primary_clock_source(enum via_clksrc source, bool use_pll)
 262{
 263        u8 data = set_clock_source_common(source, use_pll) << 4;
 264        via_write_reg_mask(VIACR, 0x6C, data, 0xF0);
 265}
 266
 267static void set_secondary_clock_source(enum via_clksrc source, bool use_pll)
 268{
 269        u8 data = set_clock_source_common(source, use_pll);
 270        via_write_reg_mask(VIACR, 0x6C, data, 0x0F);
 271}
 272
 273static void dummy_set_clock_state(u8 state)
 274{
 275        printk(KERN_INFO "Using undocumented set clock state.\n%s", via_slap);
 276}
 277
 278static void dummy_set_clock_source(enum via_clksrc source, bool use_pll)
 279{
 280        printk(KERN_INFO "Using undocumented set clock source.\n%s", via_slap);
 281}
 282
 283static void dummy_set_pll_state(u8 state)
 284{
 285        printk(KERN_INFO "Using undocumented set PLL state.\n%s", via_slap);
 286}
 287
 288static void dummy_set_pll(struct via_pll_config config)
 289{
 290        printk(KERN_INFO "Using undocumented set PLL.\n%s", via_slap);
 291}
 292
 293static void noop_set_clock_state(u8 state)
 294{
 295}
 296
 297void via_clock_init(struct via_clock *clock, int gfx_chip)
 298{
 299        switch (gfx_chip) {
 300        case UNICHROME_CLE266:
 301        case UNICHROME_K400:
 302                clock->set_primary_clock_state = dummy_set_clock_state;
 303                clock->set_primary_clock_source = dummy_set_clock_source;
 304                clock->set_primary_pll_state = dummy_set_pll_state;
 305                clock->set_primary_pll = cle266_set_primary_pll;
 306
 307                clock->set_secondary_clock_state = dummy_set_clock_state;
 308                clock->set_secondary_clock_source = dummy_set_clock_source;
 309                clock->set_secondary_pll_state = dummy_set_pll_state;
 310                clock->set_secondary_pll = cle266_set_secondary_pll;
 311
 312                clock->set_engine_pll_state = dummy_set_pll_state;
 313                clock->set_engine_pll = dummy_set_pll;
 314                break;
 315        case UNICHROME_K800:
 316        case UNICHROME_PM800:
 317        case UNICHROME_CN700:
 318        case UNICHROME_CX700:
 319        case UNICHROME_CN750:
 320        case UNICHROME_K8M890:
 321        case UNICHROME_P4M890:
 322        case UNICHROME_P4M900:
 323        case UNICHROME_VX800:
 324                clock->set_primary_clock_state = set_primary_clock_state;
 325                clock->set_primary_clock_source = set_primary_clock_source;
 326                clock->set_primary_pll_state = set_primary_pll_state;
 327                clock->set_primary_pll = k800_set_primary_pll;
 328
 329                clock->set_secondary_clock_state = set_secondary_clock_state;
 330                clock->set_secondary_clock_source = set_secondary_clock_source;
 331                clock->set_secondary_pll_state = set_secondary_pll_state;
 332                clock->set_secondary_pll = k800_set_secondary_pll;
 333
 334                clock->set_engine_pll_state = set_engine_pll_state;
 335                clock->set_engine_pll = k800_set_engine_pll;
 336                break;
 337        case UNICHROME_VX855:
 338        case UNICHROME_VX900:
 339                clock->set_primary_clock_state = set_primary_clock_state;
 340                clock->set_primary_clock_source = set_primary_clock_source;
 341                clock->set_primary_pll_state = set_primary_pll_state;
 342                clock->set_primary_pll = vx855_set_primary_pll;
 343
 344                clock->set_secondary_clock_state = set_secondary_clock_state;
 345                clock->set_secondary_clock_source = set_secondary_clock_source;
 346                clock->set_secondary_pll_state = set_secondary_pll_state;
 347                clock->set_secondary_pll = vx855_set_secondary_pll;
 348
 349                clock->set_engine_pll_state = set_engine_pll_state;
 350                clock->set_engine_pll = vx855_set_engine_pll;
 351                break;
 352
 353        }
 354
 355        if (machine_is_olpc()) {
 356                /* The OLPC XO-1.5 cannot suspend/resume reliably if the
 357                 * IGA1/IGA2 clocks are set as on or off (memory rot
 358                 * occasionally happens during suspend under such
 359                 * configurations).
 360                 *
 361                 * The only known stable scenario is to leave this bits as-is,
 362                 * which in their default states are documented to enable the
 363                 * clock only when it is needed.
 364                 */
 365                clock->set_primary_clock_state = noop_set_clock_state;
 366                clock->set_secondary_clock_state = noop_set_clock_state;
 367        }
 368}
 369