diff options
Diffstat (limited to 'firmware/target/arm/s5l8702/clocking-s5l8702.c')
-rw-r--r-- | firmware/target/arm/s5l8702/clocking-s5l8702.c | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/firmware/target/arm/s5l8702/clocking-s5l8702.c b/firmware/target/arm/s5l8702/clocking-s5l8702.c index 5293385453..3ef70ba1de 100644 --- a/firmware/target/arm/s5l8702/clocking-s5l8702.c +++ b/firmware/target/arm/s5l8702/clocking-s5l8702.c | |||
@@ -213,6 +213,125 @@ void set_clocking_level(int level) | |||
213 | udelay(50); /* TBC: probably not needed */ | 213 | udelay(50); /* TBC: probably not needed */ |
214 | } | 214 | } |
215 | 215 | ||
216 | #ifdef BOOTLOADER | ||
217 | int pll_config(int pll, int op_mode, int p, int m, int s, int lock_time) | ||
218 | { | ||
219 | PLLPMS(pll) = ((p & PLLPMS_PDIV_MSK) << PLLPMS_PDIV_POS) | ||
220 | | ((m & PLLPMS_MDIV_MSK) << PLLPMS_MDIV_POS) | ||
221 | | ((s & PLLPMS_SDIV_MSK) << PLLPMS_SDIV_POS); | ||
222 | |||
223 | /* lock_time are PClk ticks */ | ||
224 | PLLCNT(pll) = lock_time & PLLCNT_MSK; | ||
225 | |||
226 | if (pll < 2) | ||
227 | { | ||
228 | if (op_mode == PLLOP_MM) { | ||
229 | PLLMODE &= ~PLLMODE_PMSMOD_BIT(pll); /* MM */ | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | PLLMODE |= PLLMODE_PMSMOD_BIT(pll); | ||
234 | |||
235 | if (op_mode == PLLOP_DM) { | ||
236 | PLLMOD2 &= ~PLLMOD2_DMOSC_BIT(pll); /* DM */ | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | PLLMOD2 |= PLLMOD2_DMOSC_BIT(pll); | ||
241 | } | ||
242 | else | ||
243 | { | ||
244 | if (op_mode == PLLOP_MM) | ||
245 | return -1; /* PLL2 does not support MM */ | ||
246 | |||
247 | if (op_mode == PLLOP_DM) { | ||
248 | PLLMODE &= ~PLLMODE_PLL2DMOSC_BIT; /* DM */ | ||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | PLLMODE |= PLLMODE_PLL2DMOSC_BIT; | ||
253 | } | ||
254 | |||
255 | /* ALTOSCx */ | ||
256 | PLLMOD2 = (PLLMOD2 & ~PLLMOD2_ALTOSC_BIT(pll)) | | ||
257 | ((op_mode == PLLOP_ALT0) ? 0 : PLLMOD2_ALTOSC_BIT(pll)); | ||
258 | |||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | int pll_onoff(int pll, bool onoff) | ||
263 | { | ||
264 | if (onoff) | ||
265 | { | ||
266 | PLLMODE |= PLLMODE_EN_BIT(pll); /* start PLL */ | ||
267 | while (!(PLLLOCK & PLLLOCK_LCK_BIT(pll))); /* locking... */ | ||
268 | PLLMODE |= PLLMODE_PLLOUT_BIT(pll); /* slow mode OFF */ | ||
269 | |||
270 | /* returns DMLCK status, only meaningful for Divisor Mode (DM) */ | ||
271 | return (PLLLOCK & PLLLOCK_DMLCK_BIT(pll)) ? 1 : 0; | ||
272 | } | ||
273 | else | ||
274 | { | ||
275 | PLLMODE &= ~PLLMODE_PLLOUT_BIT(pll); /* slow mode ON */ | ||
276 | udelay(50); /* TBC: needed when current F_in is 0 Hz */ | ||
277 | PLLMODE &= ~PLLMODE_EN_BIT(pll); /* stop PLL */ | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | /* configure and enable/disable 16-bit clockgate */ | ||
284 | void cg16_config(volatile uint16_t* cg16, | ||
285 | bool onoff, int clksel, int div1, int div2) | ||
286 | { | ||
287 | uint16_t val16 = ((clksel & CG16_SEL_MSK) << CG16_SEL_POS) | ||
288 | | (((div1 - 1) & CG16_DIV1_MSK) << CG16_DIV1_POS) | ||
289 | | (((div2 - 1) & CG16_DIV2_MSK) << CG16_DIV2_POS) | ||
290 | | (onoff ? 0 : CG16_DISABLE_BIT); | ||
291 | |||
292 | volatile uint32_t* reg32 = (uint32_t *)((int)cg16 & ~3); | ||
293 | int shift = ((int)cg16 & 2) << 3; | ||
294 | |||
295 | *reg32 = (*reg32 & (0xffff0000 >> shift)) | (val16 << shift); | ||
296 | |||
297 | /*udelay(100);*/ /* probably not needed */ | ||
298 | |||
299 | while (*cg16 != val16); | ||
300 | } | ||
301 | |||
302 | void clockgate_enable(int gate, bool enable) | ||
303 | { | ||
304 | int i = (gate >> 5) & 1; | ||
305 | uint32_t bit = 1 << (gate & 0x1f); | ||
306 | if (enable) PWRCON(i) &= ~bit; | ||
307 | else PWRCON(i) |= bit; | ||
308 | } | ||
309 | |||
310 | /* Configures EClk for USEC_TIMER. DRAM refresh also depends on EClk, | ||
311 | * this clock should be initialized by the bootloader, so USEC_TIMER | ||
312 | * is ready to use for RB. | ||
313 | */ | ||
314 | void usec_timer_init(void) | ||
315 | { | ||
316 | /* select OSC0 for CG16 SEL_OSC */ | ||
317 | PLLMODE &= ~PLLMODE_OSCSEL_BIT; | ||
318 | |||
319 | /* configure and enable ECLK */ | ||
320 | cg16_config(&CG16_RTIME, true, CG16_SEL_OSC, 1, 1); | ||
321 | |||
322 | /* unmask timer controller clock gate */ | ||
323 | clockgate_enable(CLOCKGATE_TIMER, true); | ||
324 | |||
325 | /* configure and start timer E */ | ||
326 | TECON = (4 << 8) | /* TE_CS = ECLK / 1 */ | ||
327 | (1 << 6) | /* select ECLK (12 MHz on Classic) */ | ||
328 | (0 << 4); /* TE_MODE_SEL = interval mode */ | ||
329 | TEPRE = (S5L8702_OSC0_HZ / 1000000) - 1; /* prescaler */ | ||
330 | TEDATA0 = ~0; | ||
331 | TECMD = (1 << 1) | /* TE_CLR = initialize timer */ | ||
332 | (1 << 0); /* TE_EN = enable */ | ||
333 | } | ||
334 | |||
216 | #if 0 | 335 | #if 0 |
217 | /* - This function is mainly to documment how s5l8702 ROMBOOT and iPod | 336 | /* - This function is mainly to documment how s5l8702 ROMBOOT and iPod |
218 | * Classic diagnostic OF detects primary external clock. | 337 | * Classic diagnostic OF detects primary external clock. |
@@ -228,3 +347,5 @@ unsigned soc_get_osc0(void) | |||
228 | return (PDAT3 & 0x20) ? 24000000 : 12000000; | 347 | return (PDAT3 & 0x20) ? 24000000 : 12000000; |
229 | } | 348 | } |
230 | #endif | 349 | #endif |
350 | |||
351 | #endif /* BOOTLOADER */ | ||