diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/export/i2c-s5l8702.h | 1 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/clocking-s5l8702.c | 121 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/clocking-s5l8702.h | 17 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/gpio-s5l8702.c | 19 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/gpio-s5l8702.h | 4 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/i2c-s5l8702.c | 28 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/ipod6g/pmu-ipod6g.c | 109 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/ipod6g/pmu-target.h | 9 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/system-s5l8702.c | 121 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/system-target.h | 4 |
10 files changed, 429 insertions, 4 deletions
diff --git a/firmware/export/i2c-s5l8702.h b/firmware/export/i2c-s5l8702.h index 3883c8abc0..aef0e536bf 100644 --- a/firmware/export/i2c-s5l8702.h +++ b/firmware/export/i2c-s5l8702.h @@ -29,6 +29,7 @@ int i2c_write(int bus, unsigned char slave, int address, int len, const unsigned int i2c_read(int bus, unsigned char slave, int address, int len, unsigned char *data); #ifdef BOOTLOADER +void i2c_preinit(int bus); int i2c_wr(int bus, unsigned char slave, int address, int len, const unsigned char *data); int i2c_rd(int bus, unsigned char slave, int address, int len, unsigned char *data); #endif 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) udelay(50); /* TBC: probably not needed */ } +#ifdef BOOTLOADER +int pll_config(int pll, int op_mode, int p, int m, int s, int lock_time) +{ + PLLPMS(pll) = ((p & PLLPMS_PDIV_MSK) << PLLPMS_PDIV_POS) + | ((m & PLLPMS_MDIV_MSK) << PLLPMS_MDIV_POS) + | ((s & PLLPMS_SDIV_MSK) << PLLPMS_SDIV_POS); + + /* lock_time are PClk ticks */ + PLLCNT(pll) = lock_time & PLLCNT_MSK; + + if (pll < 2) + { + if (op_mode == PLLOP_MM) { + PLLMODE &= ~PLLMODE_PMSMOD_BIT(pll); /* MM */ + return 0; + } + + PLLMODE |= PLLMODE_PMSMOD_BIT(pll); + + if (op_mode == PLLOP_DM) { + PLLMOD2 &= ~PLLMOD2_DMOSC_BIT(pll); /* DM */ + return 0; + } + + PLLMOD2 |= PLLMOD2_DMOSC_BIT(pll); + } + else + { + if (op_mode == PLLOP_MM) + return -1; /* PLL2 does not support MM */ + + if (op_mode == PLLOP_DM) { + PLLMODE &= ~PLLMODE_PLL2DMOSC_BIT; /* DM */ + return 0; + } + + PLLMODE |= PLLMODE_PLL2DMOSC_BIT; + } + + /* ALTOSCx */ + PLLMOD2 = (PLLMOD2 & ~PLLMOD2_ALTOSC_BIT(pll)) | + ((op_mode == PLLOP_ALT0) ? 0 : PLLMOD2_ALTOSC_BIT(pll)); + + return 0; +} + +int pll_onoff(int pll, bool onoff) +{ + if (onoff) + { + PLLMODE |= PLLMODE_EN_BIT(pll); /* start PLL */ + while (!(PLLLOCK & PLLLOCK_LCK_BIT(pll))); /* locking... */ + PLLMODE |= PLLMODE_PLLOUT_BIT(pll); /* slow mode OFF */ + + /* returns DMLCK status, only meaningful for Divisor Mode (DM) */ + return (PLLLOCK & PLLLOCK_DMLCK_BIT(pll)) ? 1 : 0; + } + else + { + PLLMODE &= ~PLLMODE_PLLOUT_BIT(pll); /* slow mode ON */ + udelay(50); /* TBC: needed when current F_in is 0 Hz */ + PLLMODE &= ~PLLMODE_EN_BIT(pll); /* stop PLL */ + + return 0; + } +} + +/* configure and enable/disable 16-bit clockgate */ +void cg16_config(volatile uint16_t* cg16, + bool onoff, int clksel, int div1, int div2) +{ + uint16_t val16 = ((clksel & CG16_SEL_MSK) << CG16_SEL_POS) + | (((div1 - 1) & CG16_DIV1_MSK) << CG16_DIV1_POS) + | (((div2 - 1) & CG16_DIV2_MSK) << CG16_DIV2_POS) + | (onoff ? 0 : CG16_DISABLE_BIT); + + volatile uint32_t* reg32 = (uint32_t *)((int)cg16 & ~3); + int shift = ((int)cg16 & 2) << 3; + + *reg32 = (*reg32 & (0xffff0000 >> shift)) | (val16 << shift); + + /*udelay(100);*/ /* probably not needed */ + + while (*cg16 != val16); +} + +void clockgate_enable(int gate, bool enable) +{ + int i = (gate >> 5) & 1; + uint32_t bit = 1 << (gate & 0x1f); + if (enable) PWRCON(i) &= ~bit; + else PWRCON(i) |= bit; +} + +/* Configures EClk for USEC_TIMER. DRAM refresh also depends on EClk, + * this clock should be initialized by the bootloader, so USEC_TIMER + * is ready to use for RB. + */ +void usec_timer_init(void) +{ + /* select OSC0 for CG16 SEL_OSC */ + PLLMODE &= ~PLLMODE_OSCSEL_BIT; + + /* configure and enable ECLK */ + cg16_config(&CG16_RTIME, true, CG16_SEL_OSC, 1, 1); + + /* unmask timer controller clock gate */ + clockgate_enable(CLOCKGATE_TIMER, true); + + /* configure and start timer E */ + TECON = (4 << 8) | /* TE_CS = ECLK / 1 */ + (1 << 6) | /* select ECLK (12 MHz on Classic) */ + (0 << 4); /* TE_MODE_SEL = interval mode */ + TEPRE = (S5L8702_OSC0_HZ / 1000000) - 1; /* prescaler */ + TEDATA0 = ~0; + TECMD = (1 << 1) | /* TE_CLR = initialize timer */ + (1 << 0); /* TE_EN = enable */ +} + #if 0 /* - This function is mainly to documment how s5l8702 ROMBOOT and iPod * Classic diagnostic OF detects primary external clock. @@ -228,3 +347,5 @@ unsigned soc_get_osc0(void) return (PDAT3 & 0x20) ? 24000000 : 12000000; } #endif + +#endif /* BOOTLOADER */ diff --git a/firmware/target/arm/s5l8702/clocking-s5l8702.h b/firmware/target/arm/s5l8702/clocking-s5l8702.h index e7e4fab3bd..f21c25929b 100644 --- a/firmware/target/arm/s5l8702/clocking-s5l8702.h +++ b/firmware/target/arm/s5l8702/clocking-s5l8702.h @@ -433,4 +433,21 @@ unsigned pll_get_out_freq(int pll); unsigned soc_get_oscsel_freq(void); int soc_get_hsdiv(void); +#ifdef BOOTLOADER +#include <stdbool.h> + +void usec_timer_init(void); +void clockgate_enable(int gate, bool enable); + +void soc_set_system_divs(unsigned cdiv, unsigned hdiv, unsigned hprat); +unsigned soc_get_system_divs(unsigned *cdiv, unsigned *hdiv, unsigned *pdiv); +void soc_set_hsdiv(int hsdiv); + +void cg16_config(volatile uint16_t* cg16, + bool onoff, int clksel, int div1, int div2); + +int pll_config(int pll, int op_mode, int p, int m, int s, int lock_time); +int pll_onoff(int pll, bool onoff); +#endif + #endif /* __CLOCKING_S5L8702_H */ diff --git a/firmware/target/arm/s5l8702/gpio-s5l8702.c b/firmware/target/arm/s5l8702/gpio-s5l8702.c index bd87005ad8..85033de78c 100644 --- a/firmware/target/arm/s5l8702/gpio-s5l8702.c +++ b/firmware/target/arm/s5l8702/gpio-s5l8702.c @@ -214,3 +214,22 @@ void ICODE_ATTR INT_EXT6(void) gpio_handler(0); } #endif + +#ifdef BOOTLOADER +static uint32_t gpio_data[16] = +{ + 0x5322222F, 0xEEEEEE00, 0x2332EEEE, 0x3333E222, + 0x33333333, 0x33333333, 0x3F000E33, 0xEEEEEEEE, + 0xEEEEEEEE, 0xEEEEEEEE, 0xE0EEEEEE, 0xEE00EE0E, + 0xEEEE0EEE, 0xEEEEEEEE, 0xEE2222EE, 0xEEEE0EEE +}; + +void gpio_preinit(void) +{ + for (int i = 0; i < 16; i++) { + PCON(i) = gpio_data[i]; + PUNB(i) = 0; + PUNC(i) = 0; + } +} +#endif diff --git a/firmware/target/arm/s5l8702/gpio-s5l8702.h b/firmware/target/arm/s5l8702/gpio-s5l8702.h index 00f5ba18f3..108d8feb0d 100644 --- a/firmware/target/arm/s5l8702/gpio-s5l8702.h +++ b/firmware/target/arm/s5l8702/gpio-s5l8702.h @@ -142,4 +142,8 @@ void gpio_int_disable(int gpio_n); uint32_t gpio_group_get(int group); void gpio_group_set(int group, uint32_t mask, uint32_t cfg); +#ifdef BOOTLOADER +void gpio_preinit(void); +#endif + #endif /* __GPIO_S5L8702_H__ */ diff --git a/firmware/target/arm/s5l8702/i2c-s5l8702.c b/firmware/target/arm/s5l8702/i2c-s5l8702.c index 619768410a..13787d7357 100644 --- a/firmware/target/arm/s5l8702/i2c-s5l8702.c +++ b/firmware/target/arm/s5l8702/i2c-s5l8702.c @@ -179,3 +179,31 @@ int i2c_read(int bus, unsigned char slave, int address, int len, unsigned char * mutex_unlock(&i2c_mtx[bus]); return ret; } + +#ifdef BOOTLOADER +#include "clocking-s5l8702.h" + +static void wait_rdy(int bus) +{ + while (IICUNK10(bus)); +} + +void i2c_preinit(int bus) +{ + clockgate_enable(I2CCLKGATE(bus), true); + wait_rdy(bus); + IICADD(bus) = 0x40; /* own slave address */ + wait_rdy(bus); + IICUNK14(bus) = 0; + wait_rdy(bus); + IICUNK18(bus) = 0; + wait_rdy(bus); + IICSTAT(bus) = 0x80; /* master Rx mode, Tx/Rx off */ + wait_rdy(bus); + IICCON(bus) = 0; + wait_rdy(bus); + IICSTAT(bus) = 0; /* slave Rx mode, Tx/Rx off */ + wait_rdy(bus); + clockgate_enable(I2CCLKGATE(bus), false); +} +#endif diff --git a/firmware/target/arm/s5l8702/ipod6g/pmu-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/pmu-ipod6g.c index 2a9236046c..9c3ec8e711 100644 --- a/firmware/target/arm/s5l8702/ipod6g/pmu-ipod6g.c +++ b/firmware/target/arm/s5l8702/ipod6g/pmu-ipod6g.c @@ -165,4 +165,113 @@ int pmu_wr(int address, unsigned char val) { return pmu_wr_multiple(address, 1, &val); } + +void pmu_preinit(void) +{ + static const char init_data[] = + { + /* reset OOC shutdown register */ + PCF5063X_REG_OOCSHDWN, 0x0, + + /* LDO_UNK1: 3000 mV, enabled */ + PCF5063X_REG_LDO1OUT, 0x15, + PCF5063X_REG_LDO1ENA, 0x1, + + /* LDO_UNK2: 3000 mV, enabled */ + PCF5063X_REG_LDO2OUT, 0x15, + PCF5063X_REG_LDO2ENA, 0x1, + + /* LDO_LCD: 3000 mV, enabled */ + PCF5063X_REG_LDO3OUT, 0x15, + PCF5063X_REG_LDO3ENA, 0x1, + + /* LDO_CODEC: 1800 mV, enabled */ + PCF5063X_REG_LDO4OUT, 0x9, + PCF5063X_REG_LDO4ENA, 0x1, + + /* LDO_UNK5: 3000 mV, disabled */ + PCF5063X_REG_LDO5OUT, 0x15, + PCF5063X_REG_LDO5ENA, 0x0, + + /* LDO_CWHEEL: 3000 mV, ON when GPIO2 High */ + PCF5063X_REG_LDO6OUT, 0x15, + PCF5063X_REG_LDO6ENA, 0x4, + + /* LDO_ACCY: 3300 mV, disabled */ + PCF5063X_REG_HCLDOOUT, 0x18, + PCF5063X_REG_HCLDOENA, 0x0, + + /* LDO_CWHEEL is ON in STANDBY state, + LDO_CWHEEL and MEMLDO are ON in UNKNOWN state (TBC) */ + PCF5063X_REG_STBYCTL1, 0x0, + PCF5063X_REG_STBYCTL2, 0x8c, + + /* GPIO1,2 = input, GPIO3 = output */ + PCF5063X_REG_GPIOCTL, 0x3, + PCF5063X_REG_GPIO1CFG, 0x0, + PCF5063X_REG_GPIO2CFG, 0x0, + + /* DOWN2 converter (SDRAM): 1800 mV, enabled, + startup current limit = 15mA*0x10 (TBC) */ + PCF5063X_REG_DOWN2OUT, 0x2f, + PCF5063X_REG_DOWN2ENA, 0x1, + PCF5063X_REG_DOWN2CTL, 0x0, + PCF5063X_REG_DOWN2MXC, 0x10, + + /* MEMLDO: 1800 mV, enabled */ + PCF5063X_REG_MEMLDOOUT, 0x9, + PCF5063X_REG_MEMLDOENA, 0x1, + + /* AUTOLDO (HDD): 3400 mV, disabled, + limit = 1000 mA (40mA*0x19), limit always active */ + PCF5063X_REG_AUTOOUT, 0x6f, + PCF5063X_REG_AUTOENA, 0x0, + PCF5063X_REG_AUTOCTL, 0x0, + PCF5063X_REG_AUTOMXC, 0x59, + + /* Vsysok = 3100 mV */ + PCF5063X_REG_SVMCTL, 0x8, + + /* Reserved */ + 0x58, 0x0, + + /* Mask all PMU interrupts */ + PCF5063X_REG_INT1M, 0xff, + PCF5063X_REG_INT2M, 0xff, + PCF5063X_REG_INT3M, 0xff, + PCF5063X_REG_INT4M, 0xff, + PCF5063X_REG_INT5M, 0xff, + PCF50635_REG_INT6M, 0xff, + + /* Wakeup on rising edge for EXTON1 and EXTON2, + wakeup on falling edge for EXTON3 and !ONKEY, + wakeup on RTC alarm, wakeup on adapter insert, + Vbat status has no effect in state machine */ + PCF5063X_REG_OOCWAKE, 0xdf, + PCF5063X_REG_OOCTIM1, 0xaa, + PCF5063X_REG_OOCTIM2, 0x4a, + PCF5063X_REG_OOCMODE, 0x5, + PCF5063X_REG_OOCCTL, 0x27, + + /* GPO selection = LED external NFET drive signal */ + PCF5063X_REG_GPOCFG, 0x1, + /* LED converter OFF, overvoltage protection enabled, + OCP limit is 500 mA, led_dimstep = 16*0x6/32768 */ + PCF5063X_REG_LEDENA, 0x0, + PCF5063X_REG_LEDCTL, 0x5, + PCF5063X_REG_LEDDIM, 0x6, + + /* end marker */ + 0 + }; + + const char* ptr; + for (ptr = init_data; *ptr != 0; ptr += 2) + pmu_wr(ptr[0], ptr[1]); + + /* clear PMU interrupts */ + unsigned char rd_buf[5]; + pmu_rd_multiple(PCF5063X_REG_INT1, 5, rd_buf); + pmu_rd(PCF50635_REG_INT6); +} #endif /* BOOTLOADER */ diff --git a/firmware/target/arm/s5l8702/ipod6g/pmu-target.h b/firmware/target/arm/s5l8702/ipod6g/pmu-target.h index 3a90ad8789..e4bef6f47c 100644 --- a/firmware/target/arm/s5l8702/ipod6g/pmu-target.h +++ b/firmware/target/arm/s5l8702/ipod6g/pmu-target.h @@ -40,8 +40,8 @@ #define LDO_UNK5 5 /* TBC: nano3g NAND */ #define LDO_CWHEEL 6 #define LDO_ACCY 7 /* HCLDO */ - -/* Other LDOs: +/* + * Other LDOs: * AUTOLDO: Hard Disk * DOWN1: CPU * DOWN2: SDRAM @@ -50,9 +50,9 @@ * EXTON inputs: * EXTON1: button/holdswitch related (TBC) * EXTON2: USB Vbus (High when present) - * EXTON3: ACCESORY (Low when present) + * EXTON3: ACCESSORY (Low when present) * - * GPIO: + * PMU GPIO: * GPIO1: input, Mikey (jack remote ctrl) interrupt (TBC) * GPIO2: input, hold switch (TBC) * GPIO3: output, unknown @@ -82,6 +82,7 @@ unsigned char pmu_rd(int address); int pmu_wr(int address, unsigned char val); int pmu_rd_multiple(int address, int count, unsigned char* buffer); int pmu_wr_multiple(int address, int count, unsigned char* buffer); +void pmu_preinit(void); #endif #endif /* __PMU_TARGET_H__ */ diff --git a/firmware/target/arm/s5l8702/system-s5l8702.c b/firmware/target/arm/s5l8702/system-s5l8702.c index fd3a464e2f..d285efde78 100644 --- a/firmware/target/arm/s5l8702/system-s5l8702.c +++ b/firmware/target/arm/s5l8702/system-s5l8702.c @@ -277,3 +277,124 @@ void memory_init(void) set_page_tables(); enable_mmu(); } + +#ifdef BOOTLOADER +#include "i2c-s5l8702.h" + +static void syscon_preinit(void) +{ + /* after ROM boot, CG16_SYS is using PLL0 @108 MHz + CClk = 108 MHz, HClk = 54 MHz, PClk = 27 MHz */ + + CLKCON0 &= ~CLKCON0_SDR_DISABLE_BIT; + + PLLMODE &= ~PLLMODE_OSCSEL_BIT; /* CG16_SEL_OSC = OSC0 */ + cg16_config(&CG16_SYS, true, CG16_SEL_OSC, 1, 1); + soc_set_system_divs(1, 1, 1); + + /* stop all PLLs */ + for (int pll = 0; pll < 3; pll++) + pll_onoff(pll, false); + + pll_config(2, PLLOP_DM, 1, 36, 1, 32400); + pll_onoff(2, true); + soc_set_system_divs(1, 2, 2 /*hprat*/); + cg16_config(&CG16_SYS, true, CG16_SEL_PLL2, 1, 1); + cg16_config(&CG16_2L, false, CG16_SEL_OSC, 1, 1); + cg16_config(&CG16_SVID, false, CG16_SEL_OSC, 1, 1); + cg16_config(&CG16_AUD0, false, CG16_SEL_OSC, 1, 1); + cg16_config(&CG16_AUD1, false, CG16_SEL_OSC, 1, 1); + cg16_config(&CG16_AUD2, false, CG16_SEL_OSC, 1, 1); + cg16_config(&CG16_RTIME, true, CG16_SEL_OSC, 1, 1); + cg16_config(&CG16_5L, false, CG16_SEL_OSC, 1, 1); + + soc_set_hsdiv(1); + + PWRCON_AHB = ~((1 << CLOCKGATE_SMx) | + (1 << CLOCKGATE_SM1)); + PWRCON_APB = ~((1 << (CLOCKGATE_TIMER - 32)) | + (1 << (CLOCKGATE_GPIO - 32))); +} + +static void miu_preinit(bool selfrefreshing) +{ + if (selfrefreshing) + MIUCON = 0x11; /* TBC: self-refresh -> IDLE */ + + MIUCON = 0x80D; /* remap = 1 (IRAM mapped to 0x0), + TBC: SDRAM bank and column configuration */ + MIU_REG(0xF0) = 0x0; + + MIUAREF = 0x6105D; /* Auto-Refresh enabled, + Row refresh interval = 0x5d/12MHz = 7.75 uS */ + MIUSDPARA = 0x1FB621; + + MIU_REG(0x200) = 0x1845; + MIU_REG(0x204) = 0x1845; + MIU_REG(0x210) = 0x1800; + MIU_REG(0x214) = 0x1800; + MIU_REG(0x220) = 0x1845; + MIU_REG(0x224) = 0x1845; + MIU_REG(0x230) = 0x1885; + MIU_REG(0x234) = 0x1885; + MIU_REG(0x14) = 0x19; /* 2^19 = 0x2000000 = SDRAMSIZE (32Mb) */ + MIU_REG(0x18) = 0x19; /* 2^19 = 0x2000000 = SDRAMSIZE (32Mb) */ + MIU_REG(0x1C) = 0x790682B; + MIU_REG(0x314) &= ~0x10; + + for (int i = 0; i < 0x24; i++) + MIU_REG(0x2C + i*4) &= ~(1 << 24); + + MIU_REG(0x1CC) = 0x540; + MIU_REG(0x1D4) |= 0x80; + + MIUCOM = 0x33; /* No action CMD */ + MIUCOM = 0x33; + MIUCOM = 0x233; /* Precharge all banks CMD */ + MIUCOM = 0x33; + MIUCOM = 0x33; + MIUCOM = 0x33; + MIUCOM = 0x333; /* Auto-refresh CMD */ + MIUCOM = 0x33; + MIUCOM = 0x33; + MIUCOM = 0x33; + MIUCOM = 0x333; /* Auto-refresh CMD */ + MIUCOM = 0x33; + MIUCOM = 0x33; + MIUCOM = 0x33; + + if (!selfrefreshing) + { + MIUMRS = 0x33; /* MRS: Bust Length = 8, CAS = 3 */ + MIUCOM = 0x133; /* Mode Register Set CMD */ + MIUCOM = 0x33; + MIUCOM = 0x33; + MIUCOM = 0x33; + MIUMRS = 0x8040; /* EMRS: Strength = 1/4, Self refresh area = Full */ + MIUCOM = 0x133; /* Mode Register Set CMD */ + MIUCOM = 0x33; + MIUCOM = 0x33; + MIUCOM = 0x33; + } + + MIUAREF |= 0x61000; /* Auto-refresh enabled */ +} + +/* Preliminary HW initialization */ +void system_preinit(void) +{ + bool gpio3out, coldboot; + + syscon_preinit(); + gpio_preinit(); + i2c_preinit(0); + + /* get (previously) configured output selection for GPIO3 */ + gpio3out = (pmu_rd(PCF5063X_REG_GPIO3CFG) & 7); + /* coldboot: when set, device has been in NoPower state */ + coldboot = (pmu_rd(PCF5063X_REG_OOCSHDWN) & PCF5063X_OOCSHDWN_COLDBOOT); + pmu_preinit(); + + miu_preinit(!coldboot && !gpio3out); +} +#endif diff --git a/firmware/target/arm/s5l8702/system-target.h b/firmware/target/arm/s5l8702/system-target.h index 235e68e8ca..b40d563e46 100644 --- a/firmware/target/arm/s5l8702/system-target.h +++ b/firmware/target/arm/s5l8702/system-target.h @@ -47,4 +47,8 @@ static inline void udelay(unsigned usecs) while (TIME_BEFORE(USEC_TIMER, stop)); } +#ifdef BOOTLOADER +void system_preinit(void); +#endif + #endif /* SYSTEM_TARGET_H */ |