summaryrefslogtreecommitdiff
path: root/firmware/target/arm/s5l8702/clocking-s5l8702.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/s5l8702/clocking-s5l8702.c')
-rw-r--r--firmware/target/arm/s5l8702/clocking-s5l8702.c121
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
217int 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
262int 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 */
284void 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
302void 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 */
314void 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 */