forked from len0rd/rockbox
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
This commit is contained in:
parent
06963a5ce4
commit
23d185b7fe
2 changed files with 127 additions and 50 deletions
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue