diff options
author | Vencislav Atanasov <user890104@freemyipod.org> | 2024-12-13 00:33:51 +0200 |
---|---|---|
committer | Solomon Peachy <pizza@shaftnet.org> | 2024-12-13 08:32:19 -0500 |
commit | 23d185b7fef03f08c0b9d31a883ee1a7c1b40e4f (patch) | |
tree | 8c98a390ee791171ce2da2961076042942bb2b29 | |
parent | 06963a5ce41450b57631e10ffb39d9012cbde39c (diff) | |
download | rockbox-23d185b7fe.tar.gz rockbox-23d185b7fe.zip |
S5L8720: Add partial clocking support
Tested on ipod6g (normal + bootloader).
This is a part of the large iPod Nano 3G and iPod Nano 4G support patch.
Credit: Cástor Muñoz <cmvidal@gmail.com>
Change-Id: I5b56eaaa8a5621f4293c00c53e50e5ca39831eb6
-rw-r--r-- | firmware/target/arm/s5l8702/clocking-s5l8702.c | 93 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/clocking-s5l8702.h | 84 |
2 files changed, 127 insertions, 50 deletions
diff --git a/firmware/target/arm/s5l8702/clocking-s5l8702.c b/firmware/target/arm/s5l8702/clocking-s5l8702.c index 44ce88a2c3..d7b1a037b2 100644 --- a/firmware/target/arm/s5l8702/clocking-s5l8702.c +++ b/firmware/target/arm/s5l8702/clocking-s5l8702.c @@ -18,6 +18,7 @@ * KIND, either express or implied. * ****************************************************************************/ +#include <inttypes.h> #include <stdbool.h> #include "config.h" @@ -28,6 +29,7 @@ /* returns configured frequency (PLLxFreq, when locked) */ unsigned pll_get_cfg_freq(int pll) { +#if CONFIG_CPU == S5L8702 unsigned pdiv, mdiv, sdiv, f_in; uint32_t pllpms; @@ -57,6 +59,11 @@ unsigned pll_get_cfg_freq(int pll) f_in = S5L8702_OSC1_HZ; return (f_in * mdiv * pdiv) >> sdiv; /* multiply */ } +#else /* S5L8720 */ + // TODO + (void) pll; + return 0; +#endif } /* returns PLLxClk */ @@ -106,6 +113,7 @@ unsigned cg16_get_freq(volatile uint16_t* cg16) void soc_set_system_divs(unsigned cdiv, unsigned hdiv, unsigned hprat) { +#if CONFIG_CPU == S5L8702 uint32_t val = 0; unsigned pdiv = hdiv * hprat; @@ -119,11 +127,19 @@ void soc_set_system_divs(unsigned cdiv, unsigned hdiv, unsigned hprat) val |= CLKCON1_PDIV_EN_BIT | ((((pdiv >> 1) - 1) & CLKCON1_PDIV_MSK) << CLKCON1_PDIV_POS); + // TODO: The 8720 puts the EN_BIT here, it is not used in s5l8702, see if it influences, + // it seems that it does NOT behave the same, and when it is all 0 -> 0x40 it does not work (TBC), see EFI val |= ((hprat - 1) & CLKCON1_HPRAT_MSK) << CLKCON1_HPRAT_POS; CLKCON1 = val; while ((CLKCON1 >> 8) != (val >> 8)); +#else + // TODO + (void) cdiv; + (void) hdiv; + (void) hprat; +#endif } unsigned soc_get_system_divs(unsigned *cdiv, unsigned *hdiv, unsigned *pdiv) @@ -215,12 +231,37 @@ void set_clocking_level(int level) void clockgate_enable(int gate, bool enable) { - int i = (gate >> 5) & 1; + int i = gate >> 5; uint32_t bit = 1 << (gate & 0x1f); if (enable) PWRCON(i) &= ~bit; else PWRCON(i) |= bit; } +int soc_get_sec_epoch(void) +{ +#if CONFIG_CPU == S5L8702 +#if 1 + return 0; // In classics/nano3g it seems to always be 0, also PDAT3 is used by LCD(TBC) and that's why we can't + // look at it in RB, only at the beginning of BL + // We can also try to read it only in the preinit and save it for later. +#else + GPIOCMD = 0x30500; /* configure GPIO3.5 as input */ + return !!(PDAT3 & 0x20); +#endif +#elif CONFIG_CPU == S5L8720 + // TBC: sec_epoch == 0 -> OSC0 = 24MHz (TBC) -> or it is equal to 12 + // internal SDRAM (TBC) -> or maybe it is a multiplier of the SDRAM? + // 1 -> OSC0 = 48MHz (TBC) -> or it is equal to 24 + // external SDRAM (TBC) -> or maybe it is a multiplier of the SDRAM? + // according to ROMBOOT bit2 of sec_epoch == 1 -> use /CN=Apple Secure Boot Certification Auth... (see bootrom_main) + // 0 -> /CN=Apple IPod Certification Authority... + clockgate_enable(CLOCKGATE_CHIPID, true); + int sec_epoch = CHIPID_INFO & 1; + clockgate_enable(CLOCKGATE_CHIPID, false); + return sec_epoch; +#endif +} + #ifdef BOOTLOADER int pll_config(int pll, int op_mode, int p, int m, int s, int lock_time) { @@ -231,6 +272,7 @@ int pll_config(int pll, int op_mode, int p, int m, int s, int lock_time) /* lock_time are PClk ticks */ PLLCNT(pll) = lock_time & PLLCNT_MSK; +#if CONFIG_CPU == S5L8702 if (pll < 2) { if (op_mode == PLLOP_MM) { @@ -264,6 +306,22 @@ int pll_config(int pll, int op_mode, int p, int m, int s, int lock_time) PLLMOD2 = (PLLMOD2 & ~PLLMOD2_ALTOSC_BIT(pll)) | ((op_mode == PLLOP_ALT0) ? 0 : PLLMOD2_ALTOSC_BIT(pll)); +#elif CONFIG_CPU == S5L8720 + // In the 8702, PLL0,1 do not behave the same as in 8702, it seems that they could behave in a similar way + // to PLL2 in 8702 (TODO: check, possibly they could not have MM mode), + // see the ALTOSC topic, maybe PLLUNK3C does a similar function in 8720 to PLLMOD2 in 8702 + if (op_mode == PLLOP_DM) { + PLLMODE &= ~PLLMODE_PMSMOD_BIT(pll); + return 0; + } + return -1; + // TBC: + // if (op_mode == PLLOP_MM) + // return -1; /* PLLx does not support MM */ + // PLLMODE |= PLLMODE_PMSMOD_BIT(pll); + // PLLUNK3C = ??? +#endif + return 0; } @@ -289,12 +347,20 @@ int pll_onoff(int pll, bool onoff) } /* configure and enable/disable 16-bit clockgate */ +#if (CONFIG_CPU == S5L8702) void cg16_config(volatile uint16_t* cg16, bool onoff, int clksel, int div1, int div2) +#elif (CONFIG_CPU == S5L8720) +void cg16_config(volatile uint16_t* cg16, + bool onoff, int clksel, int div1, int div2, int flags) +#endif { 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) +#if (CONFIG_CPU == S5L8720) + | flags +#endif | (onoff ? 0 : CG16_DISABLE_BIT); volatile uint32_t* reg32 = (uint32_t *)((int)cg16 & ~3); @@ -311,16 +377,25 @@ void cg16_config(volatile uint16_t* cg16, * this clock should be initialized by the bootloader, so USEC_TIMER * is ready to use for RB. */ +// TODO: I think usec timer is not reset to 0 void usec_timer_init(void) { /* select OSC0 for CG16 SEL_OSC */ PLLMODE &= ~PLLMODE_OSCSEL_BIT; /* configure and enable ECLK */ +#if CONFIG_CPU == S5L8702 cg16_config(&CG16_RTIME, true, CG16_SEL_OSC, 1, 1); /* unmask timer controller clock gate */ clockgate_enable(CLOCKGATE_TIMER, true); +#elif CONFIG_CPU == S5L8720 + cg16_config(&CG16_RTIME, true, CG16_SEL_OSC, 1, 1, 0x0); + + /* unmask timer controller clock gates */ + clockgate_enable(CLOCKGATE_TIMERE, true); + clockgate_enable(CLOCKGATE_TIMERE_2, true); +#endif /* configure and start timer E */ TECON = (4 << 8) | /* TE_CS = ECLK / 1 */ @@ -332,20 +407,4 @@ void usec_timer_init(void) (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. - * - ATM it is unknown if 24 MHz are used on other targets (i.e. Nano 3G), - * other SoC (ROMBOOT identifies itself as s5l8900/s5l8702), a Classic - * prototype, or (probably) never used... - * - This function should be called only at boot time, GPIO3.5 is also - * used for ATA controller. - */ -unsigned soc_get_osc0(void) -{ - GPIOCMD = 0x30500; /* configure GPIO3.5 as input */ - 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 8c401e3d6e..f1cc5cffe5 100644 --- a/firmware/target/arm/s5l8702/clocking-s5l8702.h +++ b/firmware/target/arm/s5l8702/clocking-s5l8702.h @@ -152,14 +152,14 @@ */ #include <inttypes.h> +#include <stdbool.h> #include "config.h" #define CLOCKING_DEBUG -#if defined(IPOD_6G) -/* iPod Classic target */ -#define S5L8702_OSC0_HZ 12000000 /* external OSC */ -#define S5L8702_OSC1_HZ 32768 /* from PMU */ +#if defined(IPOD_6G) || defined(IPOD_NANO3G) +#define S5L8702_OSC0_HZ 12000000 /* crystal */ +#define S5L8702_OSC1_HZ 32768 /* crystal (n3g), from PMU (6g) */ #define S5L8702_ALTOSC0_HZ 0 /* TBC */ #define S5L8702_ALTOSC1_HZ 0 /* TBC */ @@ -169,35 +169,32 @@ /* TBC: OSC0*2 ???, 24 MHz Xtal ???, USB ??? */ #define S5L8702_UNKOSC_HZ 24000000 +#elif defined(IPOD_NANO4G) +#define S5L8702_OSC0_HZ (soc_get_sec_epoch() ? 24000000 : 12000000) +#define S5L8702_OSC1_HZ 32768 /* from ??? */ + +// TBC: +#define S5L8702_ALTOSC0_HZ 0 /* TBC */ +#define S5L8702_ALTOSC1_HZ 0 /* TBC */ + +// TBC: +/* this clock is selected when CG16_UNKOSC_BIT is set, + ignoring PLLMODE_CLKSEL and CG16_SEL settings */ +/* TBC: OSC0*2 ???, 24 MHz Xtal ???, USB ??? */ +#define S5L8702_UNKOSC_HZ 48000000 + #else /* s5l8702 ROMBOOT */ -#define S5L8702_OSC0_HZ (soc_get_osc0()) /* external OSC */ -#define S5L8702_OSC1_HZ 32768 /* from PMU */ +#define S5L8702_OSC0_HZ (soc_get_sec_epoch() ? 24000000 : 12000000) +#define S5L8702_OSC1_HZ 32768 -#define S5L8702_ALTOSC0_HZ 1800000 +#define S5L8702_ALTOSC0_HZ 1800000 // TODO: see if this depends on the sec_epoch #define S5L8702_ALTOSC1_HZ 27000000 + +#define S5L8702_UNKOSC_HZ (S5L8702_OSC0_HZ*2) /* TBC */ #endif -/* TODO: join all these definitions in an unique place */ -#if 1 #include "s5l87xx.h" -#else -#define CLKCON0 (*((volatile uint32_t*)(0x3C500000))) -#define CLKCON1 (*((volatile uint32_t*)(0x3C500004))) -#define CLKCON2 (*((volatile uint32_t*)(0x3C500008))) -#define CLKCON3 (*((volatile uint32_t*)(0x3C50000C))) -#define CLKCON4 (*((volatile uint32_t*)(0x3C500010))) -#define CLKCON5 (*((volatile uint32_t*)(0x3C500014))) -#define PLL0PMS (*((volatile uint32_t*)(0x3C500020))) -#define PLL1PMS (*((volatile uint32_t*)(0x3C500024))) -#define PLL2PMS (*((volatile uint32_t*)(0x3C500028))) -#define PLL0LCNT (*((volatile uint32_t*)(0x3C500030))) -#define PLL1LCNT (*((volatile uint32_t*)(0x3C500034))) -#define PLL2LCNT (*((volatile uint32_t*)(0x3C500038))) -#define PLLLOCK (*((volatile uint32_t*)(0x3C500040))) -#define PLLMODE (*((volatile uint32_t*)(0x3C500044))) -#define PWRCON(i) (*((volatile uint32_t*)(0x3C500048 + ((i)*4)))) /*i=1,2*/ -#endif /* TBC: ATM i am assuming that PWRCON_AHB/APB registers are clockgates * for SoC internal controllers sitting on AHB/APB buses, this is based @@ -209,8 +206,13 @@ #define PLLPMS(i) (*((volatile uint32_t*)(0x3C500020 + ((i) * 4)))) #define PLLCNT(i) (*((volatile uint32_t*)(0x3C500030 + ((i) * 4)))) -#define PLLMOD2 (*((volatile uint32_t*)(0x3C500060))) #define PLLCNT_MSK 0x3fffff +#if CONFIG_CPU == S5L8702 +#define PLLMOD2 (*((volatile uint32_t*)(0x3C500060))) +#elif CONFIG_CPU == S5L8720 +#define PLLUNK3C (*((volatile uint32_t*)(0x3C50003C))) +#define PLLUNK64 (*((volatile uint32_t*)(0x3C500064))) // used by efi_ClockAndReset +#endif /* TBC: Clk_SM1 = HClk / (SM1_DIV[3:0] + 1) */ #define SM1_DIV (*((volatile uint32_t*)(0x38501000))) @@ -235,23 +237,30 @@ * on experimental test using emCORE: * - CG16_SYS and CG16_RTIME were tested mainly using time benchs. * - EClk is used as a fixed clock (not depending on CPU/AHB/APB - * settings) for the timer contrller. MIU_Clk is used by the MIU + * settings) for the timer controller. MIU_Clk is used by the MIU * controller to generate the DRAM refresh signals. * - AUDxClk are a source selection for I2Sx modules, so they can * can be scaled and routed to the I2S GPIO ports, where they * were sampled (using emCORE) to inspect how they behave. * - CG16_SVID seem to be used for external video, this info is * based on OF diagnostics reverse engineering. - * - CG16_2L an CG16_5L usage is unknown. + * - CG16_2L and CG16_5L usage is unknown. */ #define CG16_SYS (*((volatile uint16_t*)(0x3C500000))) +#if CONFIG_CPU == S5L8702 #define CG16_2L (*((volatile uint16_t*)(0x3C500008))) +#elif CONFIG_CPU == S5L8720 +#define CG16_LCD (*((volatile uint16_t*)(0x3C500008))) +#endif #define CG16_SVID (*((volatile uint16_t*)(0x3C50000A))) #define CG16_AUD0 (*((volatile uint16_t*)(0x3C50000C))) #define CG16_AUD1 (*((volatile uint16_t*)(0x3C50000E))) #define CG16_AUD2 (*((volatile uint16_t*)(0x3C500010))) #define CG16_RTIME (*((volatile uint16_t*)(0x3C500012))) #define CG16_5L (*((volatile uint16_t*)(0x3C500014))) +#if CONFIG_CPU == S5L8720 +#define CG16_6L (*((volatile uint16_t*)(0x3C500070))) +#endif /* CG16 output frequency = !DISABLE_BIT * SEL_x frequency / DIV1+1 / DIV2+1 */ @@ -277,6 +286,9 @@ * CLKCON0 */ #define CLKCON0_SDR_DISABLE_BIT (1 << 31) +#if CONFIG_CPU == S5L8720 +#define CLKCON0_UNK30_BIT (1 << 30) +#endif /* * CLKCON1 @@ -351,7 +363,7 @@ 0 -> S5L8702_OSC0, 1 -> S5L8702_OSC1 */ #define PLLMODE_OSCSEL_BIT (1 << 8) -/* Select PLLxClk (a.k.a. "slow mode" (see s3c2440-DS) for PLL0,1,2: +/* Select PLLxClk (a.k.a. "slow mode", see s3c2440-DS) for PLL0,1,2: O -> S5L8702_OSC1, 1 -> PLLxFreq */ #define PLLMODE_PLLOUT_BIT(n) (1 << (16 + (n))) @@ -427,6 +439,9 @@ void clocking_init(struct clocking_mode *modes, int init_level); void set_clocking_level(int level); unsigned get_system_freqs(unsigned *cclk, unsigned *hclk, unsigned *pclk); void clockgate_enable(int gate, bool enable); +#if CONFIG_CPU == S5L8720 +int soc_get_sec_epoch(void); +#endif /* debug */ unsigned pll_get_cfg_freq(int pll); @@ -435,19 +450,22 @@ unsigned soc_get_oscsel_freq(void); int soc_get_hsdiv(void); #ifdef BOOTLOADER -#include <stdbool.h> - void usec_timer_init(void); 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); +#if CONFIG_CPU == S5L8702 void cg16_config(volatile uint16_t* cg16, bool onoff, int clksel, int div1, int div2); +#elif CONFIG_CPU == S5L8720 +void cg16_config(volatile uint16_t* cg16, + bool onoff, int clksel, int div1, int div2, int flags); +#endif 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 /* BOOTLOADER */ #endif /* __CLOCKING_S5L8702_H */ |