via_clock.c (8805B)
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}