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