]>
Commit | Line | Data |
---|---|---|
e074da3f | 1 | #include <linux/kernel.h> |
4cf26d85 MR |
2 | #include <linux/sizes.h> |
3 | ||
81dee67e SM |
4 | #include "ddk750_help.h" |
5 | #include "ddk750_reg.h" | |
6 | #include "ddk750_chip.h" | |
7 | #include "ddk750_power.h" | |
81dee67e | 8 | |
603dd493 MR |
9 | /* n / d + 1 / 2 = (2n + d) / 2d */ |
10 | #define roundedDiv(num, denom) ((2 * (num) + (denom)) / (2 * (denom))) | |
11 | #define MHz(x) ((x) * 1000000) | |
12 | ||
6fa7db83 | 13 | logical_chip_type_t getChipType(void) |
81dee67e SM |
14 | { |
15 | unsigned short physicalID; | |
16 | char physicalRev; | |
17 | logical_chip_type_t chip; | |
18 | ||
5ee35ea7 | 19 | physicalID = devId750; /* either 0x718 or 0x750 */ |
81dee67e SM |
20 | physicalRev = revId750; |
21 | ||
de99befd | 22 | if (physicalID == 0x718) |
de99befd | 23 | chip = SM718; |
9767fc51 | 24 | else if (physicalID == 0x750) { |
de99befd | 25 | chip = SM750; |
81dee67e | 26 | /* SM750 and SM750LE are different in their revision ID only. */ |
9767fc51 | 27 | if (physicalRev == SM750LE_REVISION_ID) |
81dee67e | 28 | chip = SM750LE; |
9767fc51 | 29 | } else |
de99befd | 30 | chip = SM_UNKNOWN; |
81dee67e SM |
31 | |
32 | return chip; | |
33 | } | |
34 | ||
7092d76f | 35 | static unsigned int get_mxclk_freq(void) |
81dee67e | 36 | { |
7751e0e2 MR |
37 | unsigned int pll_reg; |
38 | unsigned int M, N, OD, POD; | |
39 | ||
82736d22 | 40 | if (getChipType() == SM750LE) |
81dee67e | 41 | return MHz(130); |
81dee67e | 42 | |
7751e0e2 | 43 | pll_reg = PEEK32(MXCLK_PLL_CTRL); |
cdd5df64 MR |
44 | M = (pll_reg & PLL_CTRL_M_MASK) >> PLL_CTRL_M_SHIFT; |
45 | N = (pll_reg & PLL_CTRL_N_MASK) >> PLL_CTRL_M_SHIFT; | |
46 | OD = (pll_reg & PLL_CTRL_OD_MASK) >> PLL_CTRL_OD_SHIFT; | |
47 | POD = (pll_reg & PLL_CTRL_POD_MASK) >> PLL_CTRL_POD_SHIFT; | |
7751e0e2 MR |
48 | |
49 | return DEFAULT_INPUT_CLOCK * M / N / (1 << OD) / (1 << POD); | |
81dee67e SM |
50 | } |
51 | ||
81dee67e SM |
52 | /* |
53 | * This function set up the main chip clock. | |
54 | * | |
55 | * Input: Frequency to be set. | |
56 | */ | |
fb6f37a8 | 57 | static void setChipClock(unsigned int frequency) |
81dee67e | 58 | { |
de99befd RN |
59 | pll_value_t pll; |
60 | unsigned int ulActualMxClk; | |
cfac7d6a | 61 | |
de99befd RN |
62 | /* Cheok_0509: For SM750LE, the chip clock is fixed. Nothing to set. */ |
63 | if (getChipType() == SM750LE) | |
64 | return; | |
81dee67e | 65 | |
59f08407 | 66 | if (frequency) { |
de99befd RN |
67 | /* |
68 | * Set up PLL, a structure to hold the value to be set in clocks. | |
69 | */ | |
70 | pll.inputFreq = DEFAULT_INPUT_CLOCK; /* Defined in CLOCK.H */ | |
71 | pll.clockType = MXCLK_PLL; | |
72 | ||
73 | /* | |
46b7dd7c MG |
74 | * Call calcPllValue() to fill the other fields of PLL structure. |
75 | * Sometime, the chip cannot set up the exact clock | |
76 | * required by the User. | |
77 | * Return value of calcPllValue gives the actual possible clock. | |
de99befd RN |
78 | */ |
79 | ulActualMxClk = calcPllValue(frequency, &pll); | |
80 | ||
81 | /* Master Clock Control: MXCLK_PLL */ | |
82 | POKE32(MXCLK_PLL_CTRL, formatPllReg(&pll)); | |
83 | } | |
81dee67e SM |
84 | } |
85 | ||
fb6f37a8 | 86 | static void setMemoryClock(unsigned int frequency) |
81dee67e | 87 | { |
19aa2113 | 88 | unsigned int reg, divisor; |
cfac7d6a | 89 | |
f90416df MG |
90 | /* Cheok_0509: For SM750LE, the memory clock is fixed. |
91 | * Nothing to set. | |
92 | */ | |
81dee67e SM |
93 | if (getChipType() == SM750LE) |
94 | return; | |
cfac7d6a | 95 | |
59f08407 | 96 | if (frequency) { |
d943005a | 97 | /* |
46b7dd7c MG |
98 | * Set the frequency to the maximum frequency |
99 | * that the DDR Memory can take which is 336MHz. | |
d943005a | 100 | */ |
de99befd RN |
101 | if (frequency > MHz(336)) |
102 | frequency = MHz(336); | |
103 | ||
104 | /* Calculate the divisor */ | |
b02f9240 | 105 | divisor = roundedDiv(get_mxclk_freq(), frequency); |
de99befd RN |
106 | |
107 | /* Set the corresponding divisor in the register. */ | |
6e8aa4a1 | 108 | reg = PEEK32(CURRENT_GATE) & ~CURRENT_GATE_M2XCLK_MASK; |
c107243b | 109 | switch (divisor) { |
de99befd RN |
110 | default: |
111 | case 1: | |
6e8aa4a1 | 112 | reg |= CURRENT_GATE_M2XCLK_DIV_1; |
de99befd RN |
113 | break; |
114 | case 2: | |
6e8aa4a1 | 115 | reg |= CURRENT_GATE_M2XCLK_DIV_2; |
de99befd RN |
116 | break; |
117 | case 3: | |
6e8aa4a1 | 118 | reg |= CURRENT_GATE_M2XCLK_DIV_3; |
de99befd RN |
119 | break; |
120 | case 4: | |
6e8aa4a1 | 121 | reg |= CURRENT_GATE_M2XCLK_DIV_4; |
de99befd RN |
122 | break; |
123 | } | |
124 | ||
19aa2113 | 125 | setCurrentGate(reg); |
de99befd | 126 | } |
81dee67e SM |
127 | } |
128 | ||
81dee67e SM |
129 | /* |
130 | * This function set up the master clock (MCLK). | |
131 | * | |
132 | * Input: Frequency to be set. | |
133 | * | |
134 | * NOTE: | |
135 | * The maximum frequency the engine can run is 168MHz. | |
136 | */ | |
fb6f37a8 | 137 | static void setMasterClock(unsigned int frequency) |
81dee67e | 138 | { |
19aa2113 | 139 | unsigned int reg, divisor; |
cfac7d6a | 140 | |
83d62831 MG |
141 | /* Cheok_0509: For SM750LE, the memory clock is fixed. |
142 | * Nothing to set. | |
143 | */ | |
81dee67e SM |
144 | if (getChipType() == SM750LE) |
145 | return; | |
cfac7d6a | 146 | |
59f08407 | 147 | if (frequency) { |
de99befd RN |
148 | /* Set the frequency to the maximum frequency that the SM750 engine can |
149 | run, which is about 190 MHz. */ | |
150 | if (frequency > MHz(190)) | |
151 | frequency = MHz(190); | |
152 | ||
153 | /* Calculate the divisor */ | |
b02f9240 | 154 | divisor = roundedDiv(get_mxclk_freq(), frequency); |
de99befd RN |
155 | |
156 | /* Set the corresponding divisor in the register. */ | |
6e8aa4a1 | 157 | reg = PEEK32(CURRENT_GATE) & ~CURRENT_GATE_MCLK_MASK; |
c107243b | 158 | switch (divisor) { |
de99befd RN |
159 | default: |
160 | case 3: | |
6e8aa4a1 | 161 | reg |= CURRENT_GATE_MCLK_DIV_3; |
de99befd RN |
162 | break; |
163 | case 4: | |
6e8aa4a1 | 164 | reg |= CURRENT_GATE_MCLK_DIV_4; |
de99befd RN |
165 | break; |
166 | case 6: | |
6e8aa4a1 | 167 | reg |= CURRENT_GATE_MCLK_DIV_6; |
de99befd RN |
168 | break; |
169 | case 8: | |
6e8aa4a1 | 170 | reg |= CURRENT_GATE_MCLK_DIV_8; |
de99befd RN |
171 | break; |
172 | } | |
173 | ||
19aa2113 | 174 | setCurrentGate(reg); |
de99befd | 175 | } |
81dee67e SM |
176 | } |
177 | ||
6fa7db83 | 178 | unsigned int ddk750_getVMSize(void) |
81dee67e SM |
179 | { |
180 | unsigned int reg; | |
181 | unsigned int data; | |
182 | ||
183 | /* sm750le only use 64 mb memory*/ | |
82736d22 | 184 | if (getChipType() == SM750LE) |
4cf26d85 | 185 | return SZ_64M; |
81dee67e SM |
186 | |
187 | /* for 750,always use power mode0*/ | |
188 | reg = PEEK32(MODE0_GATE); | |
05e9d9ea | 189 | reg |= MODE0_GATE_GPIO; |
c04051f5 | 190 | POKE32(MODE0_GATE, reg); |
81dee67e SM |
191 | |
192 | /* get frame buffer size from GPIO */ | |
5538d5c8 | 193 | reg = PEEK32(MISC_CTRL) & MISC_CTRL_LOCALMEM_SIZE_MASK; |
c107243b | 194 | switch (reg) { |
ae59c465 | 195 | case MISC_CTRL_LOCALMEM_SIZE_8M: |
4cf26d85 | 196 | data = SZ_8M; break; /* 8 Mega byte */ |
ae59c465 | 197 | case MISC_CTRL_LOCALMEM_SIZE_16M: |
4cf26d85 | 198 | data = SZ_16M; break; /* 16 Mega byte */ |
ae59c465 | 199 | case MISC_CTRL_LOCALMEM_SIZE_32M: |
4cf26d85 | 200 | data = SZ_32M; break; /* 32 Mega byte */ |
ae59c465 | 201 | case MISC_CTRL_LOCALMEM_SIZE_64M: |
4cf26d85 | 202 | data = SZ_64M; break; /* 64 Mega byte */ |
ae59c465 | 203 | default: |
e261e69e AKC |
204 | data = 0; |
205 | break; | |
81dee67e SM |
206 | } |
207 | return data; | |
81dee67e SM |
208 | } |
209 | ||
f8da055a | 210 | int ddk750_initHw(initchip_param_t *pInitParam) |
81dee67e | 211 | { |
8bc728cf | 212 | unsigned int reg; |
81dee67e | 213 | |
8332d94c | 214 | if (pInitParam->powerMode != 0) |
81dee67e SM |
215 | pInitParam->powerMode = 0; |
216 | setPowerMode(pInitParam->powerMode); | |
217 | ||
218 | /* Enable display power gate & LOCALMEM power gate*/ | |
8bc728cf | 219 | reg = PEEK32(CURRENT_GATE); |
90946e52 | 220 | reg |= (CURRENT_GATE_DISPLAY | CURRENT_GATE_LOCALMEM); |
8bc728cf | 221 | setCurrentGate(reg); |
81dee67e | 222 | |
82736d22 | 223 | if (getChipType() != SM750LE) { |
81dee67e | 224 | /* set panel pll and graphic mode via mmio_88 */ |
8bc728cf | 225 | reg = PEEK32(VGA_CONFIGURATION); |
d9798143 | 226 | reg |= (VGA_CONFIGURATION_PLL | VGA_CONFIGURATION_MODE); |
8bc728cf | 227 | POKE32(VGA_CONFIGURATION, reg); |
9767fc51 | 228 | } else { |
31296ba5 | 229 | #if defined(__i386__) || defined(__x86_64__) |
81dee67e | 230 | /* set graphic mode via IO method */ |
c04051f5 HF |
231 | outb_p(0x88, 0x3d4); |
232 | outb_p(0x06, 0x3d5); | |
81dee67e SM |
233 | #endif |
234 | } | |
235 | ||
236 | /* Set the Main Chip Clock */ | |
237 | setChipClock(MHz((unsigned int)pInitParam->chipClock)); | |
238 | ||
239 | /* Set up memory clock. */ | |
240 | setMemoryClock(MHz(pInitParam->memClock)); | |
241 | ||
242 | /* Set up master clock */ | |
243 | setMasterClock(MHz(pInitParam->masterClock)); | |
244 | ||
245 | ||
246 | /* Reset the memory controller. If the memory controller is not reset in SM750, | |
247 | the system might hang when sw accesses the memory. | |
248 | The memory should be resetted after changing the MXCLK. | |
249 | */ | |
9767fc51 | 250 | if (pInitParam->resetMemory == 1) { |
8bc728cf | 251 | reg = PEEK32(MISC_CTRL); |
5372350b | 252 | reg &= ~MISC_CTRL_LOCALMEM_RESET; |
8bc728cf | 253 | POKE32(MISC_CTRL, reg); |
81dee67e | 254 | |
5372350b | 255 | reg |= MISC_CTRL_LOCALMEM_RESET; |
8bc728cf | 256 | POKE32(MISC_CTRL, reg); |
81dee67e SM |
257 | } |
258 | ||
9767fc51 | 259 | if (pInitParam->setAllEngOff == 1) { |
81dee67e SM |
260 | enable2DEngine(0); |
261 | ||
262 | /* Disable Overlay, if a former application left it on */ | |
8bc728cf | 263 | reg = PEEK32(VIDEO_DISPLAY_CTRL); |
6fba39cf | 264 | reg &= ~DISPLAY_CTRL_PLANE; |
8bc728cf | 265 | POKE32(VIDEO_DISPLAY_CTRL, reg); |
81dee67e SM |
266 | |
267 | /* Disable video alpha, if a former application left it on */ | |
8bc728cf | 268 | reg = PEEK32(VIDEO_ALPHA_DISPLAY_CTRL); |
6fba39cf | 269 | reg &= ~DISPLAY_CTRL_PLANE; |
8bc728cf | 270 | POKE32(VIDEO_ALPHA_DISPLAY_CTRL, reg); |
81dee67e SM |
271 | |
272 | /* Disable alpha plane, if a former application left it on */ | |
8bc728cf | 273 | reg = PEEK32(ALPHA_DISPLAY_CTRL); |
6fba39cf | 274 | reg &= ~DISPLAY_CTRL_PLANE; |
8bc728cf | 275 | POKE32(ALPHA_DISPLAY_CTRL, reg); |
81dee67e | 276 | |
81dee67e | 277 | /* Disable DMA Channel, if a former application left it on */ |
8bc728cf | 278 | reg = PEEK32(DMA_ABORT_INTERRUPT); |
0f23be70 | 279 | reg |= DMA_ABORT_INTERRUPT_ABORT_1; |
8bc728cf | 280 | POKE32(DMA_ABORT_INTERRUPT, reg); |
81dee67e SM |
281 | |
282 | /* Disable DMA Power, if a former application left it on */ | |
283 | enableDMA(0); | |
284 | } | |
285 | ||
286 | /* We can add more initialization as needed. */ | |
287 | ||
288 | return 0; | |
289 | } | |
290 | ||
81dee67e SM |
291 | /* |
292 | monk liu @ 4/6/2011: | |
293 | re-write the calculatePLL function of ddk750. | |
294 | the original version function does not use some mathematics tricks and shortcut | |
295 | when it doing the calculation of the best N,M,D combination | |
296 | I think this version gives a little upgrade in speed | |
297 | ||
298 | 750 pll clock formular: | |
299 | Request Clock = (Input Clock * M )/(N * X) | |
300 | ||
301 | Input Clock = 14318181 hz | |
302 | X = 2 power D | |
303 | D ={0,1,2,3,4,5,6} | |
304 | M = {1,...,255} | |
305 | N = {2,...,15} | |
306 | */ | |
c04051f5 | 307 | unsigned int calcPllValue(unsigned int request_orig, pll_value_t *pll) |
81dee67e | 308 | { |
46b7dd7c MG |
309 | /* as sm750 register definition, |
310 | * N located in 2,15 and M located in 1,255 | |
311 | */ | |
c04051f5 | 312 | int N, M, X, d; |
43ce0b53 | 313 | int mini_diff; |
c04051f5 HF |
314 | unsigned int RN, quo, rem, fl_quo; |
315 | unsigned int input, request; | |
316 | unsigned int tmpClock, ret; | |
a61dc139 | 317 | const int max_OD = 3; |
f0e00da2 | 318 | int max_d = 6; |
81dee67e | 319 | |
9767fc51 | 320 | if (getChipType() == SM750LE) { |
de99befd RN |
321 | /* SM750LE don't have prgrammable PLL and M/N values to work on. |
322 | Just return the requested clock. */ | |
323 | return request_orig; | |
324 | } | |
81dee67e SM |
325 | |
326 | ret = 0; | |
43ce0b53 | 327 | mini_diff = ~0; |
81dee67e SM |
328 | request = request_orig / 1000; |
329 | input = pll->inputFreq / 1000; | |
330 | ||
46b7dd7c MG |
331 | /* for MXCLK register, |
332 | * no POD provided, so need be treated differently | |
333 | */ | |
a61dc139 MR |
334 | if (pll->clockType == MXCLK_PLL) |
335 | max_d = 3; | |
81dee67e | 336 | |
ce02a16a | 337 | for (N = 15; N > 1; N--) { |
46b7dd7c MG |
338 | /* RN will not exceed maximum long |
339 | * if @request <= 285 MHZ (for 32bit cpu) | |
340 | */ | |
81dee67e SM |
341 | RN = N * request; |
342 | quo = RN / input; | |
343 | rem = RN % input;/* rem always small than 14318181 */ | |
6ab5b6d1 | 344 | fl_quo = (rem * 10000 / input); |
81dee67e | 345 | |
a61dc139 MR |
346 | for (d = max_d; d >= 0; d--) { |
347 | X = (1 << d); | |
f40917ea | 348 | M = quo * X; |
81dee67e SM |
349 | M += fl_quo * X / 10000; |
350 | /* round step */ | |
07387cba | 351 | M += (fl_quo * X % 10000) > 5000 ? 1 : 0; |
82736d22 | 352 | if (M < 256 && M > 0) { |
81dee67e | 353 | unsigned int diff; |
40403c1b | 354 | |
6ab5b6d1 | 355 | tmpClock = pll->inputFreq * M / N / X; |
e074da3f | 356 | diff = abs(tmpClock - request_orig); |
43ce0b53 | 357 | if (diff < mini_diff) { |
81dee67e SM |
358 | pll->M = M; |
359 | pll->N = N; | |
a61dc139 MR |
360 | pll->POD = 0; |
361 | if (d > max_OD) | |
362 | pll->POD = d - max_OD; | |
363 | pll->OD = d - pll->POD; | |
43ce0b53 | 364 | mini_diff = diff; |
81dee67e SM |
365 | ret = tmpClock; |
366 | } | |
367 | } | |
368 | } | |
369 | } | |
81dee67e SM |
370 | return ret; |
371 | } | |
372 | ||
81dee67e SM |
373 | unsigned int formatPllReg(pll_value_t *pPLL) |
374 | { | |
cdd5df64 MR |
375 | #ifndef VALIDATION_CHIP |
376 | unsigned int POD = pPLL->POD; | |
377 | #endif | |
378 | unsigned int OD = pPLL->OD; | |
379 | unsigned int M = pPLL->M; | |
380 | unsigned int N = pPLL->N; | |
375b4d42 | 381 | unsigned int reg = 0; |
81dee67e | 382 | |
0c4d85fc MR |
383 | /* |
384 | * Note that all PLL's have the same format. Here, we just use | |
385 | * Panel PLL parameter to work out the bit fields in the | |
386 | * register. On returning a 32 bit number, the value can be | |
387 | * applied to any PLL in the calling function. | |
388 | */ | |
cdd5df64 | 389 | reg = PLL_CTRL_POWER | |
81dee67e | 390 | #ifndef VALIDATION_CHIP |
cdd5df64 | 391 | ((POD << PLL_CTRL_POD_SHIFT) & PLL_CTRL_POD_MASK) | |
81dee67e | 392 | #endif |
cdd5df64 MR |
393 | ((OD << PLL_CTRL_OD_SHIFT) & PLL_CTRL_OD_MASK) | |
394 | ((N << PLL_CTRL_N_SHIFT) & PLL_CTRL_N_MASK) | | |
395 | ((M << PLL_CTRL_M_SHIFT) & PLL_CTRL_M_MASK); | |
81dee67e | 396 | |
375b4d42 | 397 | return reg; |
81dee67e SM |
398 | } |
399 | ||
400 |