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