summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap/am33xx_clock.c
diff options
context:
space:
mode:
authorJan Luebbe <jlu@pengutronix.de>2012-12-18 15:22:40 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2012-12-20 12:30:26 +0100
commitfa012d47e4123d0bdc9b453fdb89490e93eec57a (patch)
treef213c88cf68289a104570c6ded6589972e113a60 /arch/arm/mach-omap/am33xx_clock.c
parent024698e43ab2e5372c4994e4bbd0736b558aa5ff (diff)
downloadbarebox-fa012d47e4123d0bdc9b453fdb89490e93eec57a.tar.gz
barebox-fa012d47e4123d0bdc9b453fdb89490e93eec57a.tar.xz
arm: beaglebone: add first-stage support for AM335x and board
Signed-off-by: Jan Luebbe <jlu@pengutronix.de> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'arch/arm/mach-omap/am33xx_clock.c')
-rw-r--r--arch/arm/mach-omap/am33xx_clock.c289
1 files changed, 289 insertions, 0 deletions
diff --git a/arch/arm/mach-omap/am33xx_clock.c b/arch/arm/mach-omap/am33xx_clock.c
new file mode 100644
index 0000000000..a28540c919
--- /dev/null
+++ b/arch/arm/mach-omap/am33xx_clock.c
@@ -0,0 +1,289 @@
+/*
+ * pll.c
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <common.h>
+#include <asm/io.h>
+#include <mach/am33xx-clock.h>
+
+#define PRCM_MOD_EN 0x2
+#define PRCM_FORCE_WAKEUP 0x2
+
+#define PRCM_EMIF_CLK_ACTIVITY (0x1 << 2)
+#define PRCM_L3_GCLK_ACTIVITY (0x1 << 4)
+
+#define PLL_BYPASS_MODE 0x4
+#define PLL_LOCK_MODE 0x7
+#define PLL_MULTIPLIER_SHIFT 8
+
+static void interface_clocks_enable(void)
+{
+ /* Enable all the Interconnect Modules */
+ __raw_writel(PRCM_MOD_EN, CM_PER_L3_CLKCTRL);
+ while (__raw_readl(CM_PER_L3_CLKCTRL) != PRCM_MOD_EN);
+
+ __raw_writel(PRCM_MOD_EN, CM_PER_L4LS_CLKCTRL);
+ while (__raw_readl(CM_PER_L4LS_CLKCTRL) != PRCM_MOD_EN);
+
+ __raw_writel(PRCM_MOD_EN, CM_PER_L4FW_CLKCTRL);
+ while (__raw_readl(CM_PER_L4FW_CLKCTRL) != PRCM_MOD_EN);
+
+ __raw_writel(PRCM_MOD_EN, CM_WKUP_L4WKUP_CLKCTRL);
+ while (__raw_readl(CM_WKUP_L4WKUP_CLKCTRL) != PRCM_MOD_EN);
+
+ __raw_writel(PRCM_MOD_EN, CM_PER_L3_INSTR_CLKCTRL);
+ while (__raw_readl(CM_PER_L3_INSTR_CLKCTRL) != PRCM_MOD_EN);
+
+ __raw_writel(PRCM_MOD_EN, CM_PER_L4HS_CLKCTRL);
+ while (__raw_readl(CM_PER_L4HS_CLKCTRL) != PRCM_MOD_EN);
+
+ __raw_writel(PRCM_MOD_EN, CM_PER_SPI1_CLKCTRL);
+ while (__raw_readl(CM_PER_SPI1_CLKCTRL) != PRCM_MOD_EN);
+
+ /* GPIO0 */
+ __raw_writel(PRCM_MOD_EN, CM_WKUP_GPIO0_CLKCTRL);
+ while (__raw_readl(CM_WKUP_GPIO0_CLKCTRL) != PRCM_MOD_EN);
+}
+
+static void power_domain_transition_enable(void)
+{
+ /*
+ * Force power domain wake up transition
+ * Ensure that the corresponding interface clock is active before
+ * using the peripheral
+ */
+ __raw_writel(PRCM_FORCE_WAKEUP, CM_PER_L3_CLKSTCTRL);
+
+ __raw_writel(PRCM_FORCE_WAKEUP, CM_PER_L4LS_CLKSTCTRL);
+
+ __raw_writel(PRCM_FORCE_WAKEUP, CM_WKUP_CLKSTCTRL);
+
+ __raw_writel(PRCM_FORCE_WAKEUP, CM_PER_L4FW_CLKSTCTRL);
+
+ __raw_writel(PRCM_FORCE_WAKEUP, CM_PER_L3S_CLKSTCTRL);
+}
+
+/*
+ * Enable the module clock and the power domain for required peripherals
+ */
+static void per_clocks_enable(void)
+{
+ /* Enable the module clock */
+ __raw_writel(PRCM_MOD_EN, CM_PER_TIMER2_CLKCTRL);
+ while (__raw_readl(CM_PER_TIMER2_CLKCTRL) != PRCM_MOD_EN);
+
+ /* Select the Master osc 24 MHZ as Timer2 clock source */
+ __raw_writel(0x1, CLKSEL_TIMER2_CLK);
+
+ /* UART0 */
+ __raw_writel(PRCM_MOD_EN, CM_WKUP_UART0_CLKCTRL);
+ while (__raw_readl(CM_WKUP_UART0_CLKCTRL) != PRCM_MOD_EN);
+
+ /* UART3 */
+ __raw_writel(PRCM_MOD_EN, CM_PER_UART3_CLKCTRL);
+ while (__raw_readl(CM_PER_UART3_CLKCTRL) != PRCM_MOD_EN);
+
+ /* GPMC */
+ __raw_writel(PRCM_MOD_EN, CM_PER_GPMC_CLKCTRL);
+ while (__raw_readl(CM_PER_GPMC_CLKCTRL) != PRCM_MOD_EN);
+
+ /* ELM */
+ __raw_writel(PRCM_MOD_EN, CM_PER_ELM_CLKCTRL);
+ while (__raw_readl(CM_PER_ELM_CLKCTRL) != PRCM_MOD_EN);
+
+ /* i2c0 */
+ __raw_writel(PRCM_MOD_EN, CM_WKUP_I2C0_CLKCTRL);
+ while (__raw_readl(CM_WKUP_I2C0_CLKCTRL) != PRCM_MOD_EN);
+
+ /* i2c1 */
+ __raw_writel(PRCM_MOD_EN, CM_PER_I2C1_CLKCTRL);
+ while (__raw_readl(CM_PER_I2C1_CLKCTRL) != PRCM_MOD_EN);
+
+ /* i2c2 */
+ __raw_writel(PRCM_MOD_EN, CM_PER_I2C2_CLKCTRL);
+ while (__raw_readl(CM_PER_I2C2_CLKCTRL) != PRCM_MOD_EN);
+
+ /* Ethernet */
+ __raw_writel(PRCM_MOD_EN, CM_PER_CPGMAC0_CLKCTRL);
+ __raw_writel(PRCM_MOD_EN, CM_PER_CPSW_CLKSTCTRL);
+ while ((__raw_readl(CM_PER_CPGMAC0_CLKCTRL) & 0x30000) != 0x0);
+
+ /* MMC 0 & 1 */
+ __raw_writel(PRCM_MOD_EN, CM_PER_MMC0_CLKCTRL);
+ while (__raw_readl(CM_PER_MMC0_CLKCTRL) != PRCM_MOD_EN);
+ __raw_writel(PRCM_MOD_EN, CM_PER_MMC1_CLKCTRL);
+ while (__raw_readl(CM_PER_MMC1_CLKCTRL) != PRCM_MOD_EN);
+
+ /* Enable the control module though RBL would have done it*/
+ __raw_writel(PRCM_MOD_EN, CM_WKUP_CONTROL_CLKCTRL);
+ while (__raw_readl(CM_WKUP_CONTROL_CLKCTRL) != PRCM_MOD_EN);
+
+ /* SPI 0 & 1 */
+ __raw_writel(PRCM_MOD_EN, CM_PER_SPI0_CLKCTRL);
+ while (__raw_readl(CM_PER_SPI0_CLKCTRL) != PRCM_MOD_EN);
+
+ __raw_writel(PRCM_MOD_EN, CM_PER_SPI1_CLKCTRL);
+ while (__raw_readl(CM_PER_SPI1_CLKCTRL) != PRCM_MOD_EN);
+}
+
+static void mpu_pll_config(int mpupll_M)
+{
+ u32 clkmode, clksel, div_m2;
+
+ clkmode = __raw_readl(CM_CLKMODE_DPLL_MPU);
+ clksel = __raw_readl(CM_CLKSEL_DPLL_MPU);
+ div_m2 = __raw_readl(CM_DIV_M2_DPLL_MPU);
+
+ /* Set the PLL to bypass Mode */
+ __raw_writel(PLL_BYPASS_MODE, CM_CLKMODE_DPLL_MPU);
+
+ while(__raw_readl(CM_IDLEST_DPLL_MPU) != 0x00000100);
+
+ clksel = clksel & (~0x7ffff);
+ clksel = clksel | ((mpupll_M << 0x8) | MPUPLL_N);
+ __raw_writel(clksel, CM_CLKSEL_DPLL_MPU);
+
+ div_m2 = div_m2 & ~0x1f;
+ div_m2 = div_m2 | MPUPLL_M2;
+ __raw_writel(div_m2, CM_DIV_M2_DPLL_MPU);
+
+ clkmode = clkmode | 0x7;
+ __raw_writel(clkmode, CM_CLKMODE_DPLL_MPU);
+
+ while(__raw_readl(CM_IDLEST_DPLL_MPU) != 0x1);
+}
+
+static void core_pll_config(void)
+{
+ u32 clkmode, clksel, div_m4, div_m5, div_m6;
+
+ clkmode = __raw_readl(CM_CLKMODE_DPLL_CORE);
+ clksel = __raw_readl(CM_CLKSEL_DPLL_CORE);
+ div_m4 = __raw_readl(CM_DIV_M4_DPLL_CORE);
+ div_m5 = __raw_readl(CM_DIV_M5_DPLL_CORE);
+ div_m6 = __raw_readl(CM_DIV_M6_DPLL_CORE);
+
+ /* Set the PLL to bypass Mode */
+ __raw_writel(PLL_BYPASS_MODE, CM_CLKMODE_DPLL_CORE);
+
+ while(__raw_readl(CM_IDLEST_DPLL_CORE) != 0x00000100);
+
+ clksel = clksel & (~0x7ffff);
+ clksel = clksel | ((COREPLL_M << 0x8) | COREPLL_N);
+ __raw_writel(clksel, CM_CLKSEL_DPLL_CORE);
+
+ div_m4 = div_m4 & ~0x1f;
+ div_m4 = div_m4 | COREPLL_M4;
+ __raw_writel(div_m4, CM_DIV_M4_DPLL_CORE);
+
+ div_m5 = div_m5 & ~0x1f;
+ div_m5 = div_m5 | COREPLL_M5;
+ __raw_writel(div_m5, CM_DIV_M5_DPLL_CORE);
+
+ div_m6 = div_m6 & ~0x1f;
+ div_m6 = div_m6 | COREPLL_M6;
+ __raw_writel(div_m6, CM_DIV_M6_DPLL_CORE);
+
+
+ clkmode = clkmode | 0x7;
+ __raw_writel(clkmode, CM_CLKMODE_DPLL_CORE);
+
+ while(__raw_readl(CM_IDLEST_DPLL_CORE) != 0x1);
+}
+
+static void per_pll_config(void)
+{
+ u32 clkmode, clksel, div_m2;
+
+ clkmode = __raw_readl(CM_CLKMODE_DPLL_PER);
+ clksel = __raw_readl(CM_CLKSEL_DPLL_PER);
+ div_m2 = __raw_readl(CM_DIV_M2_DPLL_PER);
+
+ /* Set the PLL to bypass Mode */
+ __raw_writel(PLL_BYPASS_MODE, CM_CLKMODE_DPLL_PER);
+
+ while(__raw_readl(CM_IDLEST_DPLL_PER) != 0x00000100);
+
+ clksel = clksel & (~0x7ffff);
+ clksel = clksel | ((PERPLL_M << 0x8) | PERPLL_N);
+ __raw_writel(clksel, CM_CLKSEL_DPLL_PER);
+
+ div_m2 = div_m2 & ~0x7f;
+ div_m2 = div_m2 | PERPLL_M2;
+ __raw_writel(div_m2, CM_DIV_M2_DPLL_PER);
+
+ clkmode = clkmode | 0x7;
+ __raw_writel(clkmode, CM_CLKMODE_DPLL_PER);
+
+ while(__raw_readl(CM_IDLEST_DPLL_PER) != 0x1);
+}
+
+static void ddr_pll_config(void)
+{
+ u32 clkmode, clksel, div_m2;
+
+ clkmode = __raw_readl(CM_CLKMODE_DPLL_DDR);
+ clksel = __raw_readl(CM_CLKSEL_DPLL_DDR);
+ div_m2 = __raw_readl(CM_DIV_M2_DPLL_DDR);
+
+ /* Set the PLL to bypass Mode */
+ clkmode = (clkmode & 0xfffffff8) | 0x00000004;
+ __raw_writel(clkmode, CM_CLKMODE_DPLL_DDR);
+
+ while ((__raw_readl(CM_IDLEST_DPLL_DDR) & 0x00000100) != 0x00000100);
+
+ clksel = clksel & (~0x7ffff);
+ clksel = clksel | ((DDRPLL_M << 0x8) | DDRPLL_N);
+ __raw_writel(clksel, CM_CLKSEL_DPLL_DDR);
+
+ div_m2 = div_m2 & 0xFFFFFFE0;
+ div_m2 = div_m2 | DDRPLL_M2;
+ __raw_writel(div_m2, CM_DIV_M2_DPLL_DDR);
+
+ clkmode = (clkmode & 0xfffffff8) | 0x7;
+ __raw_writel(clkmode, CM_CLKMODE_DPLL_DDR);
+
+ while ((__raw_readl(CM_IDLEST_DPLL_DDR) & 0x00000001) != 0x1);
+}
+
+void enable_ddr_clocks(void)
+{
+ /* Enable the EMIF_FW Functional clock */
+ __raw_writel(PRCM_MOD_EN, CM_PER_EMIF_FW_CLKCTRL);
+ /* Enable EMIF0 Clock */
+ __raw_writel(PRCM_MOD_EN, CM_PER_EMIF_CLKCTRL);
+ /* Poll for emif_gclk & L3_G clock are active */
+ while ((__raw_readl(CM_PER_L3_CLKSTCTRL) & (PRCM_EMIF_CLK_ACTIVITY |
+ PRCM_L3_GCLK_ACTIVITY)) != (PRCM_EMIF_CLK_ACTIVITY |
+ PRCM_L3_GCLK_ACTIVITY));
+ /* Poll if module is functional */
+ while ((__raw_readl(CM_PER_EMIF_CLKCTRL)) != PRCM_MOD_EN);
+
+}
+
+/*
+ * Configure the PLL/PRCM for necessary peripherals
+ */
+void pll_init()
+{
+ mpu_pll_config(MPUPLL_M_500);
+ core_pll_config();
+ per_pll_config();
+ ddr_pll_config();
+ /* Enable the required interconnect clocks */
+ interface_clocks_enable();
+ /* Enable power domain transition */
+ power_domain_transition_enable();
+ /* Enable the required peripherals */
+ per_clocks_enable();
+}