summaryrefslogtreecommitdiff
path: root/arch/arm/mach-omap2/am33xx
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/am33xx')
-rw-r--r--arch/arm/mach-omap2/am33xx/Kconfig14
-rw-r--r--arch/arm/mach-omap2/am33xx/board.c110
-rw-r--r--arch/arm/mach-omap2/am33xx/clock.c10
-rw-r--r--arch/arm/mach-omap2/am33xx/clock_am43xx.c21
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)
{