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 33const 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