summaryrefslogtreecommitdiff
path: root/firmware/target/arm/s5l8702/clocking-s5l8702.c
diff options
context:
space:
mode:
authorCástor Muñoz <cmvidal@gmail.com>2016-02-04 22:49:01 +0100
committerCástor Muñoz <cmvidal@gmail.com>2016-05-25 10:59:31 +0200
commit1aefd9ea4146ebb7eee606be4efb5cf22654b082 (patch)
treeffbe9f88c2e0624faf93419c5bc9bd63963766ec /firmware/target/arm/s5l8702/clocking-s5l8702.c
parentc31fcddd985a9855ece85f4209a4bdae77f3f9c8 (diff)
downloadrockbox-1aefd9ea4146ebb7eee606be4efb5cf22654b082.tar.gz
rockbox-1aefd9ea4146ebb7eee606be4efb5cf22654b082.zip
iPod Classic: HW preliminary initialization for bootloader
When the bootloader starts, most of HW never has been initialized. This patch includes all code needed to perform the preliminary initialization on SYSCON, GPIO, i2c, and MIU. The code is based on emCORE and OF reverse engineering, ported to C for readability. Change-Id: I9ecf2c3e8b1b636241a211dbba8735137accd05c
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 */