diff options
Diffstat (limited to 'arch/arm/mach-omap2/am33xx')
-rw-r--r-- | arch/arm/mach-omap2/am33xx/Kconfig | 14 | ||||
-rw-r--r-- | arch/arm/mach-omap2/am33xx/board.c | 110 | ||||
-rw-r--r-- | arch/arm/mach-omap2/am33xx/clock.c | 10 | ||||
-rw-r--r-- | arch/arm/mach-omap2/am33xx/clock_am43xx.c | 21 |
4 files changed, 147 insertions, 8 deletions
diff --git a/arch/arm/mach-omap2/am33xx/Kconfig b/arch/arm/mach-omap2/am33xx/Kconfig index 9a9ccd7b0b..76da6d911e 100644 --- a/arch/arm/mach-omap2/am33xx/Kconfig +++ b/arch/arm/mach-omap2/am33xx/Kconfig @@ -239,6 +239,20 @@ config TARGET_CM_T43 endchoice +config SPL_RTC_DDR_SUPPORT + bool + depends on SPL + prompt "Enable RTC-DDR ONLY Support" + help + If you want RTC-DDR ONLY Support, say Y. RTC Only with DDR in + self-refresh mode is a special power saving mode where in all + the other voltages are turned off apart from the RTC domain and DDR. + So only RTC is alive and ticking and one can program it to wake + up after a predetermined period. Once RTC alarm fires, the PMIC + powers up all the voltage domains. U-Boot takes a special path + as the DDR has contents is in self-refresh and restore path is + followed. + endif if AM43XX || AM33XX diff --git a/arch/arm/mach-omap2/am33xx/board.c b/arch/arm/mach-omap2/am33xx/board.c index ea0cabad97..ef1de1a115 100644 --- a/arch/arm/mach-omap2/am33xx/board.c +++ b/arch/arm/mach-omap2/am33xx/board.c @@ -147,6 +147,16 @@ int cpu_mmc_init(bd_t *bis) } #endif +/* + * RTC only with DDR in self-refresh mode magic value, checked against during + * boot to see if we have a valid config. This should be in sync with the value + * that will be in drivers/soc/ti/pm33xx.c. + */ +#define RTC_MAGIC_VAL 0x8cd0 + +/* Board type field bit shift for RTC only with DDR in self-refresh mode */ +#define RTC_BOARD_TYPE_SHIFT 16 + /* AM33XX has two MUSB controllers which can be host or gadget */ #if (defined(CONFIG_USB_MUSB_GADGET) || defined(CONFIG_USB_MUSB_HOST)) && \ (defined(CONFIG_AM335X_USB0) || defined(CONFIG_AM335X_USB1)) && \ @@ -252,6 +262,48 @@ int arch_misc_init(void) #endif /* CONFIG_USB_MUSB_* && CONFIG_AM335X_USB* && !CONFIG_DM_USB */ #ifndef CONFIG_SKIP_LOWLEVEL_INIT + +#if defined(CONFIG_SPL_AM33XX_ENABLE_RTC32K_OSC) || \ + (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_RTC_DDR_SUPPORT)) +static void rtc32k_unlock(struct davinci_rtc *rtc) +{ + /* + * Unlock the RTC's registers. For more details please see the + * RTC_SS section of the TRM. In order to unlock we need to + * write these specific values (keys) in this order. + */ + writel(RTC_KICK0R_WE, &rtc->kick0r); + writel(RTC_KICK1R_WE, &rtc->kick1r); +} +#endif + +#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_RTC_DDR_SUPPORT) +/* + * Write contents of the RTC_SCRATCH1 register based on board type + * Two things are passed + * on. First 16 bits (0:15) are written with RTC_MAGIC value. Once the + * control gets to kernel, kernel reads the scratchpad register and gets to + * know that bootloader has rtc_only support. + * + * Second important thing is the board type (16:31). This is needed in the + * rtc_only boot where in we want to avoid costly i2c reads to eeprom to + * identify the board type and we go ahead and copy the board strings to + * am43xx_board_name. + */ +void update_rtc_magic(void) +{ + struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE; + u32 magic = RTC_MAGIC_VAL; + + magic |= (rtc_only_get_board_type() << RTC_BOARD_TYPE_SHIFT); + + rtc32k_unlock(rtc); + + /* write magic */ + writel(magic, &rtc->scratch1); +} +#endif + /* * In the case of non-SPL based booting we'll want to call these * functions a tiny bit later as it will require gd to be set and cleared @@ -261,7 +313,9 @@ int board_early_init_f(void) { prcm_init(); set_mux_conf_regs(); - +#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_RTC_DDR_SUPPORT) + update_rtc_magic(); +#endif return 0; } @@ -278,13 +332,7 @@ static void rtc32k_enable(void) { struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE; - /* - * Unlock the RTC's registers. For more details please see the - * RTC_SS section of the TRM. In order to unlock we need to - * write these specific values (keys) in this order. - */ - writel(RTC_KICK0R_WE, &rtc->kick0r); - writel(RTC_KICK1R_WE, &rtc->kick1r); + rtc32k_unlock(rtc); /* Enable the RTC 32K OSC by setting bits 3 and 6. */ writel((1 << 3) | (1 << 6), &rtc->osc); @@ -321,8 +369,54 @@ static void watchdog_disable(void) ; } +#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_RTC_DDR_SUPPORT) +/* + * Check if we are executing rtc-only + DDR mode, and resume from it if needed + */ +static void rtc_only(void) +{ + struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE; + u32 scratch1; + void (*resume_func)(void); + + scratch1 = readl(&rtc->scratch1); + + /* + * Check RTC scratch against RTC_MAGIC_VAL, RTC_MAGIC_VAL is only + * written to this register when we want to wake up from RTC only + * with DDR in self-refresh mode. Contents of the RTC_SCRATCH1: + * bits 0-15: RTC_MAGIC_VAL + * bits 16-31: board type (needed for sdram_init) + */ + if ((scratch1 & 0xffff) != RTC_MAGIC_VAL) + return; + + rtc32k_unlock(rtc); + + /* Clear RTC magic */ + writel(0, &rtc->scratch1); + + /* + * Update board type based on value stored on RTC_SCRATCH1, this + * is done so that we don't need to read the board type from eeprom + * over i2c bus which is expensive + */ + rtc_only_update_board_type(scratch1 >> RTC_BOARD_TYPE_SHIFT); + + rtc_only_prcm_init(); + sdram_init(); + + resume_func = (void *)readl(&rtc->scratch0); + if (resume_func) + resume_func(); +} +#endif + void s_init(void) { +#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_RTC_DDR_SUPPORT) + rtc_only(); +#endif } void early_system_init(void) diff --git a/arch/arm/mach-omap2/am33xx/clock.c b/arch/arm/mach-omap2/am33xx/clock.c index 3d17698e18..ad28d205ee 100644 --- a/arch/arm/mach-omap2/am33xx/clock.c +++ b/arch/arm/mach-omap2/am33xx/clock.c @@ -244,3 +244,13 @@ void prcm_init(void) scale_vcores(); setup_dplls(); } + +void rtc_only_prcm_init(void) +{ + const struct dpll_params *params; + + rtc_only_enable_basic_clocks(); + + params = get_dpll_ddr_params(); + do_setup_dpll(&dpll_ddr_regs, params); +} diff --git a/arch/arm/mach-omap2/am33xx/clock_am43xx.c b/arch/arm/mach-omap2/am33xx/clock_am43xx.c index 73ea955a6c..117a63e7ad 100644 --- a/arch/arm/mach-omap2/am33xx/clock_am43xx.c +++ b/arch/arm/mach-omap2/am33xx/clock_am43xx.c @@ -124,6 +124,27 @@ void enable_basic_clocks(void) writel(0x4, &cmdpll->clkselmacclk); } +void rtc_only_enable_basic_clocks(void) +{ + u32 *const clk_domains[] = { + &cmper->emifclkstctrl, + 0 + }; + + u32 *const clk_modules_explicit_en[] = { + &cmper->gpio5clkctrl, + &cmper->emiffwclkctrl, + &cmper->emifclkctrl, + &cmper->otfaemifclkctrl, + 0 + }; + + do_enable_clocks(clk_domains, clk_modules_explicit_en, 1); + + /* Select the Master osc clk as Timer2 clock source */ + writel(0x1, &cmdpll->clktimer2clk); +} + #ifdef CONFIG_TI_EDMA3 void enable_edma3_clocks(void) { |