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