summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVencislav Atanasov <user890104@freemyipod.org>2024-12-13 00:33:51 +0200
committerSolomon Peachy <pizza@shaftnet.org>2024-12-13 08:32:19 -0500
commit23d185b7fef03f08c0b9d31a883ee1a7c1b40e4f (patch)
tree8c98a390ee791171ce2da2961076042942bb2b29
parent06963a5ce41450b57631e10ffb39d9012cbde39c (diff)
downloadrockbox-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.c93
-rw-r--r--firmware/target/arm/s5l8702/clocking-s5l8702.h84
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 */