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 
32 const char *via_slap = "Please slap VIA Technologies to motivate them "
33 	"releasing full documentation for your platform!\n";
34 
cle266_encode_pll(struct via_pll_config pll)35 static 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 
k800_encode_pll(struct via_pll_config pll)42 static 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 
vx855_encode_pll(struct via_pll_config pll)49 static 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 
cle266_set_primary_pll_encoded(u32 data)56 static 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 
k800_set_primary_pll_encoded(u32 data)64 static 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 
cle266_set_secondary_pll_encoded(u32 data)73 static 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 
k800_set_secondary_pll_encoded(u32 data)81 static 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 
set_engine_pll_encoded(u32 data)90 static 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 
cle266_set_primary_pll(struct via_pll_config config)99 static void cle266_set_primary_pll(struct via_pll_config config)
100 {
101 	cle266_set_primary_pll_encoded(cle266_encode_pll(config));
102 }
103 
k800_set_primary_pll(struct via_pll_config config)104 static void k800_set_primary_pll(struct via_pll_config config)
105 {
106 	k800_set_primary_pll_encoded(k800_encode_pll(config));
107 }
108 
vx855_set_primary_pll(struct via_pll_config config)109 static void vx855_set_primary_pll(struct via_pll_config config)
110 {
111 	k800_set_primary_pll_encoded(vx855_encode_pll(config));
112 }
113 
cle266_set_secondary_pll(struct via_pll_config config)114 static void cle266_set_secondary_pll(struct via_pll_config config)
115 {
116 	cle266_set_secondary_pll_encoded(cle266_encode_pll(config));
117 }
118 
k800_set_secondary_pll(struct via_pll_config config)119 static void k800_set_secondary_pll(struct via_pll_config config)
120 {
121 	k800_set_secondary_pll_encoded(k800_encode_pll(config));
122 }
123 
vx855_set_secondary_pll(struct via_pll_config config)124 static void vx855_set_secondary_pll(struct via_pll_config config)
125 {
126 	k800_set_secondary_pll_encoded(vx855_encode_pll(config));
127 }
128 
k800_set_engine_pll(struct via_pll_config config)129 static void k800_set_engine_pll(struct via_pll_config config)
130 {
131 	set_engine_pll_encoded(k800_encode_pll(config));
132 }
133 
vx855_set_engine_pll(struct via_pll_config config)134 static void vx855_set_engine_pll(struct via_pll_config config)
135 {
136 	set_engine_pll_encoded(vx855_encode_pll(config));
137 }
138 
set_primary_pll_state(u8 state)139 static 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 
set_secondary_pll_state(u8 state)157 static 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 
set_engine_pll_state(u8 state)175 static 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 
set_primary_clock_state(u8 state)193 static 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 
set_secondary_clock_state(u8 state)211 static 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 
set_clock_source_common(enum via_clksrc source,bool use_pll)229 static 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 
set_primary_clock_source(enum via_clksrc source,bool use_pll)260 static 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 
set_secondary_clock_source(enum via_clksrc source,bool use_pll)266 static 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 
dummy_set_clock_state(u8 state)272 static void dummy_set_clock_state(u8 state)
273 {
274 	printk(KERN_INFO "Using undocumented set clock state.\n%s", via_slap);
275 }
276 
dummy_set_clock_source(enum via_clksrc source,bool use_pll)277 static 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 
dummy_set_pll_state(u8 state)282 static void dummy_set_pll_state(u8 state)
283 {
284 	printk(KERN_INFO "Using undocumented set PLL state.\n%s", via_slap);
285 }
286 
dummy_set_pll(struct via_pll_config config)287 static void dummy_set_pll(struct via_pll_config config)
288 {
289 	printk(KERN_INFO "Using undocumented set PLL.\n%s", via_slap);
290 }
291 
via_clock_init(struct via_clock * clock,int gfx_chip)292 void 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