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