]>
Commit | Line | Data |
---|---|---|
81dee67e SM |
1 | #include "ddk750_help.h" |
2 | #include "ddk750_reg.h" | |
3 | #include "ddk750_chip.h" | |
4 | #include "ddk750_power.h" | |
569a6dcf | 5 | typedef struct _pllcalparam { |
81dee67e SM |
6 | unsigned char power;/* d : 0~ 6*/ |
7 | unsigned char pod; | |
8 | unsigned char od; | |
9 | unsigned char value;/* value of 2 power d (2^d) */ | |
10 | } | |
11 | pllcalparam; | |
12 | ||
13 | ||
6fa7db83 | 14 | logical_chip_type_t getChipType(void) |
81dee67e SM |
15 | { |
16 | unsigned short physicalID; | |
17 | char physicalRev; | |
18 | logical_chip_type_t chip; | |
19 | ||
5ee35ea7 | 20 | physicalID = devId750; /* either 0x718 or 0x750 */ |
81dee67e SM |
21 | physicalRev = revId750; |
22 | ||
de99befd | 23 | if (physicalID == 0x718) |
de99befd | 24 | chip = SM718; |
9767fc51 | 25 | else if (physicalID == 0x750) { |
de99befd | 26 | chip = SM750; |
81dee67e | 27 | /* SM750 and SM750LE are different in their revision ID only. */ |
9767fc51 | 28 | if (physicalRev == SM750LE_REVISION_ID) |
81dee67e | 29 | chip = SM750LE; |
9767fc51 | 30 | } else |
de99befd | 31 | chip = SM_UNKNOWN; |
81dee67e SM |
32 | |
33 | return chip; | |
34 | } | |
35 | ||
36 | ||
37 | inline unsigned int twoToPowerOfx(unsigned long x) | |
38 | { | |
de99befd RN |
39 | unsigned long i; |
40 | unsigned long result = 1; | |
81dee67e | 41 | |
ce02a16a | 42 | for (i = 1; i <= x; i++) |
de99befd RN |
43 | result *= 2; |
44 | return result; | |
81dee67e SM |
45 | } |
46 | ||
47 | inline unsigned int calcPLL(pll_value_t *pPLL) | |
48 | { | |
de99befd | 49 | return (pPLL->inputFreq * pPLL->M / pPLL->N / twoToPowerOfx(pPLL->OD) / twoToPowerOfx(pPLL->POD)); |
81dee67e SM |
50 | } |
51 | ||
52 | unsigned int getPllValue(clock_type_t clockType, pll_value_t *pPLL) | |
53 | { | |
de99befd RN |
54 | unsigned int ulPllReg = 0; |
55 | ||
56 | pPLL->inputFreq = DEFAULT_INPUT_CLOCK; | |
57 | pPLL->clockType = clockType; | |
58 | ||
9767fc51 | 59 | switch (clockType) { |
de99befd RN |
60 | case MXCLK_PLL: |
61 | ulPllReg = PEEK32(MXCLK_PLL_CTRL); | |
62 | break; | |
63 | case PRIMARY_PLL: | |
64 | ulPllReg = PEEK32(PANEL_PLL_CTRL); | |
65 | break; | |
66 | case SECONDARY_PLL: | |
67 | ulPllReg = PEEK32(CRT_PLL_CTRL); | |
68 | break; | |
69 | case VGA0_PLL: | |
70 | ulPllReg = PEEK32(VGA_PLL0_CTRL); | |
71 | break; | |
72 | case VGA1_PLL: | |
73 | ulPllReg = PEEK32(VGA_PLL1_CTRL); | |
74 | break; | |
75 | } | |
76 | ||
77 | pPLL->M = FIELD_GET(ulPllReg, PANEL_PLL_CTRL, M); | |
78 | pPLL->N = FIELD_GET(ulPllReg, PANEL_PLL_CTRL, N); | |
79 | pPLL->OD = FIELD_GET(ulPllReg, PANEL_PLL_CTRL, OD); | |
80 | pPLL->POD = FIELD_GET(ulPllReg, PANEL_PLL_CTRL, POD); | |
81 | ||
82 | return calcPLL(pPLL); | |
81dee67e SM |
83 | } |
84 | ||
85 | ||
6fa7db83 | 86 | unsigned int getChipClock(void) |
81dee67e | 87 | { |
de99befd | 88 | pll_value_t pll; |
81dee67e | 89 | #if 1 |
82736d22 | 90 | if (getChipType() == SM750LE) |
81dee67e SM |
91 | return MHz(130); |
92 | #endif | |
93 | ||
de99befd | 94 | return getPllValue(MXCLK_PLL, &pll); |
81dee67e SM |
95 | } |
96 | ||
97 | ||
98 | /* | |
99 | * This function set up the main chip clock. | |
100 | * | |
101 | * Input: Frequency to be set. | |
102 | */ | |
103 | void setChipClock(unsigned int frequency) | |
104 | { | |
de99befd RN |
105 | pll_value_t pll; |
106 | unsigned int ulActualMxClk; | |
81dee67e | 107 | #if 1 |
de99befd RN |
108 | /* Cheok_0509: For SM750LE, the chip clock is fixed. Nothing to set. */ |
109 | if (getChipType() == SM750LE) | |
110 | return; | |
81dee67e SM |
111 | #endif |
112 | ||
59f08407 | 113 | if (frequency) { |
de99befd RN |
114 | /* |
115 | * Set up PLL, a structure to hold the value to be set in clocks. | |
116 | */ | |
117 | pll.inputFreq = DEFAULT_INPUT_CLOCK; /* Defined in CLOCK.H */ | |
118 | pll.clockType = MXCLK_PLL; | |
119 | ||
120 | /* | |
121 | * Call calcPllValue() to fill up the other fields for PLL structure. | |
122 | * Sometime, the chip cannot set up the exact clock required by User. | |
123 | * Return value from calcPllValue() gives the actual possible clock. | |
124 | */ | |
125 | ulActualMxClk = calcPllValue(frequency, &pll); | |
126 | ||
127 | /* Master Clock Control: MXCLK_PLL */ | |
128 | POKE32(MXCLK_PLL_CTRL, formatPllReg(&pll)); | |
129 | } | |
81dee67e SM |
130 | } |
131 | ||
132 | ||
133 | ||
134 | void setMemoryClock(unsigned int frequency) | |
135 | { | |
de99befd | 136 | unsigned int ulReg, divisor; |
81dee67e SM |
137 | #if 1 |
138 | /* Cheok_0509: For SM750LE, the memory clock is fixed. Nothing to set. */ | |
139 | if (getChipType() == SM750LE) | |
140 | return; | |
141 | #endif | |
59f08407 | 142 | if (frequency) { |
de99befd RN |
143 | /* Set the frequency to the maximum frequency that the DDR Memory can take |
144 | which is 336MHz. */ | |
145 | if (frequency > MHz(336)) | |
146 | frequency = MHz(336); | |
147 | ||
148 | /* Calculate the divisor */ | |
149 | divisor = (unsigned int) roundedDiv(getChipClock(), frequency); | |
150 | ||
151 | /* Set the corresponding divisor in the register. */ | |
152 | ulReg = PEEK32(CURRENT_GATE); | |
c107243b | 153 | switch (divisor) { |
de99befd RN |
154 | default: |
155 | case 1: | |
156 | ulReg = FIELD_SET(ulReg, CURRENT_GATE, M2XCLK, DIV_1); | |
157 | break; | |
158 | case 2: | |
159 | ulReg = FIELD_SET(ulReg, CURRENT_GATE, M2XCLK, DIV_2); | |
160 | break; | |
161 | case 3: | |
162 | ulReg = FIELD_SET(ulReg, CURRENT_GATE, M2XCLK, DIV_3); | |
163 | break; | |
164 | case 4: | |
165 | ulReg = FIELD_SET(ulReg, CURRENT_GATE, M2XCLK, DIV_4); | |
166 | break; | |
167 | } | |
168 | ||
169 | setCurrentGate(ulReg); | |
170 | } | |
81dee67e SM |
171 | } |
172 | ||
173 | ||
174 | /* | |
175 | * This function set up the master clock (MCLK). | |
176 | * | |
177 | * Input: Frequency to be set. | |
178 | * | |
179 | * NOTE: | |
180 | * The maximum frequency the engine can run is 168MHz. | |
181 | */ | |
182 | void setMasterClock(unsigned int frequency) | |
183 | { | |
de99befd RN |
184 | unsigned int ulReg, divisor; |
185 | #if 1 | |
81dee67e SM |
186 | /* Cheok_0509: For SM750LE, the memory clock is fixed. Nothing to set. */ |
187 | if (getChipType() == SM750LE) | |
188 | return; | |
189 | #endif | |
59f08407 | 190 | if (frequency) { |
de99befd RN |
191 | /* Set the frequency to the maximum frequency that the SM750 engine can |
192 | run, which is about 190 MHz. */ | |
193 | if (frequency > MHz(190)) | |
194 | frequency = MHz(190); | |
195 | ||
196 | /* Calculate the divisor */ | |
197 | divisor = (unsigned int) roundedDiv(getChipClock(), frequency); | |
198 | ||
199 | /* Set the corresponding divisor in the register. */ | |
200 | ulReg = PEEK32(CURRENT_GATE); | |
c107243b | 201 | switch (divisor) { |
de99befd RN |
202 | default: |
203 | case 3: | |
204 | ulReg = FIELD_SET(ulReg, CURRENT_GATE, MCLK, DIV_3); | |
205 | break; | |
206 | case 4: | |
207 | ulReg = FIELD_SET(ulReg, CURRENT_GATE, MCLK, DIV_4); | |
208 | break; | |
209 | case 6: | |
210 | ulReg = FIELD_SET(ulReg, CURRENT_GATE, MCLK, DIV_6); | |
211 | break; | |
212 | case 8: | |
213 | ulReg = FIELD_SET(ulReg, CURRENT_GATE, MCLK, DIV_8); | |
214 | break; | |
215 | } | |
216 | ||
217 | setCurrentGate(ulReg); | |
218 | } | |
81dee67e SM |
219 | } |
220 | ||
221 | ||
6fa7db83 | 222 | unsigned int ddk750_getVMSize(void) |
81dee67e SM |
223 | { |
224 | unsigned int reg; | |
225 | unsigned int data; | |
226 | ||
227 | /* sm750le only use 64 mb memory*/ | |
82736d22 | 228 | if (getChipType() == SM750LE) |
81dee67e SM |
229 | return MB(64); |
230 | ||
231 | /* for 750,always use power mode0*/ | |
232 | reg = PEEK32(MODE0_GATE); | |
c04051f5 HF |
233 | reg = FIELD_SET(reg, MODE0_GATE, GPIO, ON); |
234 | POKE32(MODE0_GATE, reg); | |
81dee67e SM |
235 | |
236 | /* get frame buffer size from GPIO */ | |
c04051f5 | 237 | reg = FIELD_GET(PEEK32(MISC_CTRL), MISC_CTRL, LOCALMEM_SIZE); |
c107243b | 238 | switch (reg) { |
ae59c465 HF |
239 | case MISC_CTRL_LOCALMEM_SIZE_8M: |
240 | data = MB(8); break; /* 8 Mega byte */ | |
241 | case MISC_CTRL_LOCALMEM_SIZE_16M: | |
242 | data = MB(16); break; /* 16 Mega byte */ | |
243 | case MISC_CTRL_LOCALMEM_SIZE_32M: | |
244 | data = MB(32); break; /* 32 Mega byte */ | |
245 | case MISC_CTRL_LOCALMEM_SIZE_64M: | |
246 | data = MB(64); break; /* 64 Mega byte */ | |
247 | default: | |
e261e69e AKC |
248 | data = 0; |
249 | break; | |
81dee67e SM |
250 | } |
251 | return data; | |
252 | ||
253 | } | |
254 | ||
f8da055a | 255 | int ddk750_initHw(initchip_param_t *pInitParam) |
81dee67e SM |
256 | { |
257 | ||
258 | unsigned int ulReg; | |
259 | #if 0 | |
5ee35ea7 | 260 | /* move the code to map regiter function. */ |
82736d22 | 261 | if (getChipType() == SM718) { |
81dee67e SM |
262 | /* turn on big endian bit*/ |
263 | ulReg = PEEK32(0x74); | |
264 | /* now consider register definition in a big endian pattern*/ | |
c04051f5 | 265 | POKE32(0x74, ulReg|0x80000000); |
81dee67e SM |
266 | } |
267 | ||
268 | #endif | |
269 | ||
270 | ||
8332d94c | 271 | if (pInitParam->powerMode != 0) |
81dee67e SM |
272 | pInitParam->powerMode = 0; |
273 | setPowerMode(pInitParam->powerMode); | |
274 | ||
275 | /* Enable display power gate & LOCALMEM power gate*/ | |
276 | ulReg = PEEK32(CURRENT_GATE); | |
277 | ulReg = FIELD_SET(ulReg, CURRENT_GATE, DISPLAY, ON); | |
c04051f5 | 278 | ulReg = FIELD_SET(ulReg, CURRENT_GATE, LOCALMEM, ON); |
81dee67e SM |
279 | setCurrentGate(ulReg); |
280 | ||
82736d22 | 281 | if (getChipType() != SM750LE) { |
81dee67e SM |
282 | /* set panel pll and graphic mode via mmio_88 */ |
283 | ulReg = PEEK32(VGA_CONFIGURATION); | |
c04051f5 HF |
284 | ulReg = FIELD_SET(ulReg, VGA_CONFIGURATION, PLL, PANEL); |
285 | ulReg = FIELD_SET(ulReg, VGA_CONFIGURATION, MODE, GRAPHIC); | |
286 | POKE32(VGA_CONFIGURATION, ulReg); | |
9767fc51 | 287 | } else { |
31296ba5 | 288 | #if defined(__i386__) || defined(__x86_64__) |
81dee67e | 289 | /* set graphic mode via IO method */ |
c04051f5 HF |
290 | outb_p(0x88, 0x3d4); |
291 | outb_p(0x06, 0x3d5); | |
81dee67e SM |
292 | #endif |
293 | } | |
294 | ||
295 | /* Set the Main Chip Clock */ | |
296 | setChipClock(MHz((unsigned int)pInitParam->chipClock)); | |
297 | ||
298 | /* Set up memory clock. */ | |
299 | setMemoryClock(MHz(pInitParam->memClock)); | |
300 | ||
301 | /* Set up master clock */ | |
302 | setMasterClock(MHz(pInitParam->masterClock)); | |
303 | ||
304 | ||
305 | /* Reset the memory controller. If the memory controller is not reset in SM750, | |
306 | the system might hang when sw accesses the memory. | |
307 | The memory should be resetted after changing the MXCLK. | |
308 | */ | |
9767fc51 | 309 | if (pInitParam->resetMemory == 1) { |
81dee67e SM |
310 | ulReg = PEEK32(MISC_CTRL); |
311 | ulReg = FIELD_SET(ulReg, MISC_CTRL, LOCALMEM_RESET, RESET); | |
312 | POKE32(MISC_CTRL, ulReg); | |
313 | ||
314 | ulReg = FIELD_SET(ulReg, MISC_CTRL, LOCALMEM_RESET, NORMAL); | |
315 | POKE32(MISC_CTRL, ulReg); | |
316 | } | |
317 | ||
9767fc51 | 318 | if (pInitParam->setAllEngOff == 1) { |
81dee67e SM |
319 | enable2DEngine(0); |
320 | ||
321 | /* Disable Overlay, if a former application left it on */ | |
322 | ulReg = PEEK32(VIDEO_DISPLAY_CTRL); | |
323 | ulReg = FIELD_SET(ulReg, VIDEO_DISPLAY_CTRL, PLANE, DISABLE); | |
324 | POKE32(VIDEO_DISPLAY_CTRL, ulReg); | |
325 | ||
326 | /* Disable video alpha, if a former application left it on */ | |
327 | ulReg = PEEK32(VIDEO_ALPHA_DISPLAY_CTRL); | |
328 | ulReg = FIELD_SET(ulReg, VIDEO_ALPHA_DISPLAY_CTRL, PLANE, DISABLE); | |
329 | POKE32(VIDEO_ALPHA_DISPLAY_CTRL, ulReg); | |
330 | ||
331 | /* Disable alpha plane, if a former application left it on */ | |
332 | ulReg = PEEK32(ALPHA_DISPLAY_CTRL); | |
333 | ulReg = FIELD_SET(ulReg, ALPHA_DISPLAY_CTRL, PLANE, DISABLE); | |
334 | POKE32(ALPHA_DISPLAY_CTRL, ulReg); | |
335 | ||
336 | #if 0 | |
337 | /* Disable LCD hardware cursor, if a former application left it on */ | |
338 | ulReg = PEEK32(PANEL_HWC_ADDRESS); | |
339 | ulReg = FIELD_SET(ulReg, PANEL_HWC_ADDRESS, ENABLE, DISABLE); | |
340 | POKE32(PANEL_HWC_ADDRESS, ulReg); | |
341 | ||
342 | /* Disable CRT hardware cursor, if a former application left it on */ | |
343 | ulReg = PEEK32(CRT_HWC_ADDRESS); | |
344 | ulReg = FIELD_SET(ulReg, CRT_HWC_ADDRESS, ENABLE, DISABLE); | |
345 | POKE32(CRT_HWC_ADDRESS, ulReg); | |
346 | ||
347 | /* Disable ZV Port 0, if a former application left it on */ | |
348 | ulReg = PEEK32(ZV0_CAPTURE_CTRL); | |
349 | ulReg = FIELD_SET(ulReg, ZV0_CAPTURE_CTRL, CAP, DISABLE); | |
350 | POKE32(ZV0_CAPTURE_CTRL, ulReg); | |
351 | ||
352 | /* Disable ZV Port 1, if a former application left it on */ | |
353 | ulReg = PEEK32(ZV1_CAPTURE_CTRL); | |
354 | ulReg = FIELD_SET(ulReg, ZV1_CAPTURE_CTRL, CAP, DISABLE); | |
355 | POKE32(ZV1_CAPTURE_CTRL, ulReg); | |
356 | ||
357 | /* Disable ZV Port Power, if a former application left it on */ | |
358 | enableZVPort(0); | |
359 | /* Disable DMA Channel, if a former application left it on */ | |
360 | ulReg = PEEK32(DMA_ABORT_INTERRUPT); | |
361 | ulReg = FIELD_SET(ulReg, DMA_ABORT_INTERRUPT, ABORT_1, ABORT); | |
362 | POKE32(DMA_ABORT_INTERRUPT, ulReg); | |
363 | ||
364 | /* Disable i2c */ | |
365 | enableI2C(0); | |
366 | #endif | |
367 | /* Disable DMA Channel, if a former application left it on */ | |
368 | ulReg = PEEK32(DMA_ABORT_INTERRUPT); | |
369 | ulReg = FIELD_SET(ulReg, DMA_ABORT_INTERRUPT, ABORT_1, ABORT); | |
370 | POKE32(DMA_ABORT_INTERRUPT, ulReg); | |
371 | ||
372 | /* Disable DMA Power, if a former application left it on */ | |
373 | enableDMA(0); | |
374 | } | |
375 | ||
376 | /* We can add more initialization as needed. */ | |
377 | ||
378 | return 0; | |
379 | } | |
380 | ||
381 | #if 0 | |
382 | ||
383 | unsigned int absDiff(unsigned int a, unsigned int b) | |
384 | { | |
31296ba5 | 385 | if (a > b) |
de99befd RN |
386 | return(a - b); |
387 | else | |
388 | return(b - a); | |
81dee67e SM |
389 | } |
390 | ||
391 | #endif | |
392 | /* | |
393 | monk liu @ 4/6/2011: | |
394 | re-write the calculatePLL function of ddk750. | |
395 | the original version function does not use some mathematics tricks and shortcut | |
396 | when it doing the calculation of the best N,M,D combination | |
397 | I think this version gives a little upgrade in speed | |
398 | ||
399 | 750 pll clock formular: | |
400 | Request Clock = (Input Clock * M )/(N * X) | |
401 | ||
402 | Input Clock = 14318181 hz | |
403 | X = 2 power D | |
404 | D ={0,1,2,3,4,5,6} | |
405 | M = {1,...,255} | |
406 | N = {2,...,15} | |
407 | */ | |
c04051f5 | 408 | unsigned int calcPllValue(unsigned int request_orig, pll_value_t *pll) |
81dee67e SM |
409 | { |
410 | /* used for primary and secondary channel pixel clock pll */ | |
411 | static pllcalparam xparm_PIXEL[] = { | |
c04051f5 HF |
412 | /* 2^0 = 1*/ {0, 0, 0, 1}, |
413 | /* 2^ 1 =2*/ {1, 0, 1, 2}, | |
414 | /* 2^ 2 = 4*/ {2, 0, 2, 4}, | |
415 | {3, 0, 3, 8}, | |
416 | {4, 1, 3, 16}, | |
417 | {5, 2, 3, 32}, | |
418 | /* 2^6 = 64 */ {6, 3, 3, 64}, | |
81dee67e SM |
419 | }; |
420 | ||
421 | /* used for MXCLK (chip clock) */ | |
422 | static pllcalparam xparm_MXCLK[] = { | |
c04051f5 HF |
423 | /* 2^0 = 1*/ {0, 0, 0, 1}, |
424 | /* 2^ 1 =2*/ {1, 0, 1, 2}, | |
425 | /* 2^ 2 = 4*/ {2, 0, 2, 4}, | |
426 | {3, 0, 3, 8}, | |
81dee67e SM |
427 | }; |
428 | ||
de99befd | 429 | /* as sm750 register definition, N located in 2,15 and M located in 1,255 */ |
c04051f5 | 430 | int N, M, X, d; |
81dee67e SM |
431 | int xcnt; |
432 | int miniDiff; | |
c04051f5 HF |
433 | unsigned int RN, quo, rem, fl_quo; |
434 | unsigned int input, request; | |
435 | unsigned int tmpClock, ret; | |
eb0f4271 | 436 | pllcalparam *xparm; |
81dee67e SM |
437 | |
438 | #if 1 | |
9767fc51 | 439 | if (getChipType() == SM750LE) { |
de99befd RN |
440 | /* SM750LE don't have prgrammable PLL and M/N values to work on. |
441 | Just return the requested clock. */ | |
442 | return request_orig; | |
443 | } | |
81dee67e SM |
444 | #endif |
445 | ||
446 | ret = 0; | |
447 | miniDiff = ~0; | |
448 | request = request_orig / 1000; | |
449 | input = pll->inputFreq / 1000; | |
450 | ||
451 | /* for MXCLK register , no POD provided, so need be treated differently */ | |
452 | ||
82736d22 | 453 | if (pll->clockType != MXCLK_PLL) { |
81dee67e SM |
454 | xparm = &xparm_PIXEL[0]; |
455 | xcnt = sizeof(xparm_PIXEL)/sizeof(xparm_PIXEL[0]); | |
9767fc51 | 456 | } else { |
81dee67e SM |
457 | xparm = &xparm_MXCLK[0]; |
458 | xcnt = sizeof(xparm_MXCLK)/sizeof(xparm_MXCLK[0]); | |
459 | } | |
460 | ||
461 | ||
ce02a16a | 462 | for (N = 15; N > 1; N--) { |
81dee67e SM |
463 | /* RN will not exceed maximum long if @request <= 285 MHZ (for 32bit cpu) */ |
464 | RN = N * request; | |
465 | quo = RN / input; | |
466 | rem = RN % input;/* rem always small than 14318181 */ | |
6ab5b6d1 | 467 | fl_quo = (rem * 10000 / input); |
81dee67e | 468 | |
ce02a16a | 469 | for (d = xcnt - 1; d >= 0; d--) { |
81dee67e SM |
470 | X = xparm[d].value; |
471 | M = quo*X; | |
472 | M += fl_quo * X / 10000; | |
473 | /* round step */ | |
0d5e63c4 | 474 | M += (fl_quo*X % 10000) > 5000?1:0; |
82736d22 | 475 | if (M < 256 && M > 0) { |
81dee67e | 476 | unsigned int diff; |
40403c1b | 477 | |
6ab5b6d1 | 478 | tmpClock = pll->inputFreq * M / N / X; |
c04051f5 | 479 | diff = absDiff(tmpClock, request_orig); |
82736d22 | 480 | if (diff < miniDiff) { |
81dee67e SM |
481 | pll->M = M; |
482 | pll->N = N; | |
483 | pll->OD = xparm[d].od; | |
484 | pll->POD = xparm[d].pod; | |
485 | miniDiff = diff; | |
486 | ret = tmpClock; | |
487 | } | |
488 | } | |
489 | } | |
490 | } | |
81dee67e SM |
491 | return ret; |
492 | } | |
493 | ||
494 | unsigned int calcPllValue2( | |
495 | unsigned int ulRequestClk, /* Required pixel clock in Hz unit */ | |
496 | pll_value_t *pPLL /* Structure to hold the value to be set in PLL */ | |
497 | ) | |
498 | { | |
de99befd RN |
499 | unsigned int M, N, OD, POD = 0, diff, pllClk, odPower, podPower; |
500 | unsigned int bestDiff = 0xffffffff; /* biggest 32 bit unsigned number */ | |
81dee67e SM |
501 | unsigned int ret; |
502 | /* Init PLL structure to know states */ | |
de99befd RN |
503 | pPLL->M = 0; |
504 | pPLL->N = 0; | |
505 | pPLL->OD = 0; | |
506 | pPLL->POD = 0; | |
81dee67e SM |
507 | |
508 | /* Sanity check: None at the moment */ | |
509 | ||
510 | /* Convert everything in Khz range in order to avoid calculation overflow */ | |
de99befd RN |
511 | pPLL->inputFreq /= 1000; |
512 | ulRequestClk /= 1000; | |
81dee67e SM |
513 | |
514 | #ifndef VALIDATION_CHIP | |
515 | /* The maximum of post divider is 8. */ | |
ce02a16a | 516 | for (POD = 0; POD <= 3; POD++) |
81dee67e | 517 | #endif |
de99befd | 518 | { |
81dee67e SM |
519 | |
520 | #ifndef VALIDATION_CHIP | |
de99befd RN |
521 | /* MXCLK_PLL does not have post divider. */ |
522 | if ((POD > 0) && (pPLL->clockType == MXCLK_PLL)) | |
523 | break; | |
81dee67e SM |
524 | #endif |
525 | ||
de99befd RN |
526 | /* Work out 2 to the power of POD */ |
527 | podPower = twoToPowerOfx(POD); | |
81dee67e | 528 | |
de99befd | 529 | /* OD has only 2 bits [15:14] and its value must between 0 to 3 */ |
ce02a16a | 530 | for (OD = 0; OD <= 3; OD++) { |
de99befd RN |
531 | /* Work out 2 to the power of OD */ |
532 | odPower = twoToPowerOfx(OD); | |
81dee67e SM |
533 | |
534 | #ifdef VALIDATION_CHIP | |
de99befd RN |
535 | if (odPower > 4) |
536 | podPower = 4; | |
537 | else | |
538 | podPower = odPower; | |
81dee67e SM |
539 | #endif |
540 | ||
de99befd RN |
541 | /* N has 4 bits [11:8] and its value must between 2 and 15. |
542 | The N == 1 will behave differently --> Result is not correct. */ | |
ce02a16a | 543 | for (N = 2; N <= 15; N++) { |
de99befd RN |
544 | /* The formula for PLL is ulRequestClk = inputFreq * M / N / (2^OD) |
545 | In the following steps, we try to work out a best M value given the others are known. | |
546 | To avoid decimal calculation, we use 1000 as multiplier for up to 3 decimal places of accuracy. | |
547 | */ | |
548 | M = ulRequestClk * N * odPower * 1000 / pPLL->inputFreq; | |
549 | M = roundedDiv(M, 1000); | |
550 | ||
551 | /* M field has only 8 bits, reject value bigger than 8 bits */ | |
9767fc51 | 552 | if (M < 256) { |
de99befd RN |
553 | /* Calculate the actual clock for a given M & N */ |
554 | pllClk = pPLL->inputFreq * M / N / odPower / podPower; | |
555 | ||
556 | /* How much are we different from the requirement */ | |
557 | diff = absDiff(pllClk, ulRequestClk); | |
558 | ||
9767fc51 | 559 | if (diff < bestDiff) { |
de99befd RN |
560 | bestDiff = diff; |
561 | ||
562 | /* Store M and N values */ | |
563 | pPLL->M = M; | |
564 | pPLL->N = N; | |
565 | pPLL->OD = OD; | |
81dee67e SM |
566 | |
567 | #ifdef VALIDATION_CHIP | |
de99befd RN |
568 | if (OD > 2) |
569 | POD = 2; | |
570 | else | |
571 | POD = OD; | |
81dee67e SM |
572 | #endif |
573 | ||
de99befd RN |
574 | pPLL->POD = POD; |
575 | } | |
576 | } | |
577 | } | |
578 | } | |
579 | } | |
81dee67e SM |
580 | |
581 | /* Restore input frequency from Khz to hz unit */ | |
de99befd RN |
582 | ulRequestClk *= 1000; |
583 | pPLL->inputFreq = DEFAULT_INPUT_CLOCK; /* Default reference clock */ | |
81dee67e | 584 | |
81dee67e SM |
585 | /* Return actual frequency that the PLL can set */ |
586 | ret = calcPLL(pPLL); | |
de99befd | 587 | return ret; |
81dee67e SM |
588 | } |
589 | ||
590 | ||
591 | ||
592 | ||
593 | ||
594 | unsigned int formatPllReg(pll_value_t *pPLL) | |
595 | { | |
de99befd | 596 | unsigned int ulPllReg = 0; |
81dee67e SM |
597 | |
598 | /* Note that all PLL's have the same format. Here, we just use Panel PLL parameter | |
599 | to work out the bit fields in the register. | |
600 | On returning a 32 bit number, the value can be applied to any PLL in the calling function. | |
601 | */ | |
de99befd | 602 | ulPllReg = |
7f0ebcc2 JL |
603 | FIELD_SET(0, PANEL_PLL_CTRL, BYPASS, OFF) |
604 | | FIELD_SET(0, PANEL_PLL_CTRL, POWER, ON) | |
605 | | FIELD_SET(0, PANEL_PLL_CTRL, INPUT, OSC) | |
81dee67e | 606 | #ifndef VALIDATION_CHIP |
de99befd | 607 | | FIELD_VALUE(0, PANEL_PLL_CTRL, POD, pPLL->POD) |
81dee67e | 608 | #endif |
de99befd RN |
609 | | FIELD_VALUE(0, PANEL_PLL_CTRL, OD, pPLL->OD) |
610 | | FIELD_VALUE(0, PANEL_PLL_CTRL, N, pPLL->N) | |
611 | | FIELD_VALUE(0, PANEL_PLL_CTRL, M, pPLL->M); | |
81dee67e | 612 | |
63de0eb0 | 613 | return ulPllReg; |
81dee67e SM |
614 | } |
615 | ||
616 |