summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-imx/imx53.c
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2011-10-07 13:59:18 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2011-10-13 17:27:19 +0200
commit2d6568b40857408165a0aa3e934ce7c32f575719 (patch)
treec5b8113035442c04c84d742407022c47cf67af8b /arch/arm/mach-imx/imx53.c
parent51b74cf4264d0318bfb7771490157edebf0e1c32 (diff)
downloadbarebox-2d6568b40857408165a0aa3e934ce7c32f575719.tar.gz
barebox-2d6568b40857408165a0aa3e934ce7c32f575719.tar.xz
ARM i.MX53: Add lowlevel init code
This adds lowlevel (AIPS, PLL, L2) initialization for i.MX53 boards. This is a direct transcription of Freescales U-Boot assembler code with the exception that we initialize PLL1 with 1000MHz and assume that all necessary voltages are already adjusted when we arrive here. It must be explicitely called from the boards so a board is free to do it's own initialization. However, boards should use this code and make it more configurable if necessary. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'arch/arm/mach-imx/imx53.c')
-rw-r--r--arch/arm/mach-imx/imx53.c147
1 files changed, 147 insertions, 0 deletions
diff --git a/arch/arm/mach-imx/imx53.c b/arch/arm/mach-imx/imx53.c
index 8fb64bb96a..698a05a0fb 100644
--- a/arch/arm/mach-imx/imx53.c
+++ b/arch/arm/mach-imx/imx53.c
@@ -20,6 +20,7 @@
#include <io.h>
#include <sizes.h>
#include <mach/imx53-regs.h>
+#include <mach/clock-imx51_53.h>
#include "gpio.h"
@@ -43,3 +44,149 @@ static int imx53_init(void)
return 0;
}
coredevice_initcall(imx53_init);
+
+static void setup_pll(void __iomem *base, int freq, u32 op, u32 mfd, u32 mfn)
+{
+ u32 r;
+
+ /*
+ * If freq < 300MHz, we need to set dpdck0_2_en to 0
+ */
+ r = 0x00000232;
+ if (freq >= 300)
+ r |= 0x1000;
+
+ writel(r, base + MX5_PLL_DP_CTL);
+
+ writel(0x2, base + MX5_PLL_DP_CONFIG);
+
+ writel(op, base + MX5_PLL_DP_OP);
+ writel(op, base + MX5_PLL_DP_HFS_OP);
+
+ writel(mfd, base + MX5_PLL_DP_MFD);
+ writel(mfd, base + MX5_PLL_DP_HFS_MFD);
+
+ writel(mfn, base + MX5_PLL_DP_MFN);
+ writel(mfn, base + MX5_PLL_DP_HFS_MFN);
+
+ writel(0x00001232, base + MX5_PLL_DP_CTL);
+
+ while (!(readl(base + MX5_PLL_DP_CTL) & 1));
+}
+
+#define setup_pll_1000(base) setup_pll((base), 1000, ((10 << 4) + ((1 - 1) << 0)), (12 - 1), 5)
+#define setup_pll_400(base) setup_pll((base), 400, ((8 << 4) + ((2 - 1) << 0)), (3 - 1), 1)
+#define setup_pll_455(base) setup_pll((base), 455, ((9 << 4) + ((2 - 1) << 0)), (48 - 1), 23)
+#define setup_pll_216(base) setup_pll((base), 216, ((8 << 4) + ((2 - 1) << 0)), (1 - 1), 1)
+
+int mx53_init_lowlevel(void)
+{
+ void __iomem *ccm = (void __iomem *)MX53_CCM_BASE_ADDR;
+ u32 r;
+
+ /* ARM errata ID #468414 */
+ __asm__ __volatile__("mrc 15, 0, %0, c1, c0, 1":"=r"(r));
+ r |= (1 << 5); /* enable L1NEON bit */
+ __asm__ __volatile__("mcr 15, 0, %0, c1, c0, 1" : : "r"(r));
+
+ /* explicitly disable L2 cache */
+ __asm__ __volatile__("mrc 15, 0, %0, c1, c0, 1":"=r"(r));
+ r &= ~(1 << 1);
+ __asm__ __volatile__("mcr 15, 0, %0, c1, c0, 1" : : "r"(r));
+
+
+ /* reconfigure L2 cache aux control reg */
+ r = 0xc0 | /* tag RAM */
+ 0x4 | /* data RAM */
+ (1 << 24) | /* disable write allocate delay */
+ (1 << 23) | /* disable write allocate combine */
+ (1 << 22); /* disable write allocate */
+
+ __asm__ __volatile__("mcr 15, 1, %0, c9, c0, 2" : : "r"(r));
+
+ /*
+ * AIPS setup - Only setup MPROTx registers.
+ * The PACR default values are good.
+ * Set all MPROTx to be non-bufferable, trusted for R/W,
+ * not forced to user-mode.
+ */
+ writel(0x77777777, MX53_AIPS1_BASE_ADDR + 0);
+ writel(0x77777777, MX53_AIPS1_BASE_ADDR + 4);
+ writel(0x77777777, MX53_AIPS2_BASE_ADDR + 0);
+ writel(0x77777777, MX53_AIPS2_BASE_ADDR + 4);
+
+ /* Gate of clocks to the peripherals first */
+ writel(0x3fffffff, ccm + MX5_CCM_CCGR0);
+ writel(0x00000000, ccm + MX5_CCM_CCGR1);
+ writel(0x00000000, ccm + MX5_CCM_CCGR2);
+ writel(0x00000000, ccm + MX5_CCM_CCGR3);
+ writel(0x00030000, ccm + MX5_CCM_CCGR4);
+ writel(0x00fff030, ccm + MX5_CCM_CCGR5);
+ writel(0x0f00030f, ccm + MX5_CCM_CCGR6);
+ writel(0x00000000, ccm + MX53_CCM_CCGR7);
+
+ /* Switch ARM to step clock */
+ writel(0x4, ccm + MX5_CCM_CCSR);
+
+ setup_pll_1000((void __iomem *)MX53_PLL1_BASE_ADDR);
+ setup_pll_400((void __iomem *)MX53_PLL3_BASE_ADDR);
+
+ /* Switch peripheral to PLL3 */
+ writel(0x00015154, ccm + MX5_CCM_CBCMR);
+ writel(0x02888945 | (1<<16), ccm + MX5_CCM_CBCDR);
+
+ /* make sure change is effective */
+ while (readl(ccm + MX5_CCM_CDHIPR));
+
+ setup_pll_400((void __iomem *)MX53_PLL2_BASE_ADDR);
+
+ /* Switch peripheral to PLL2 */
+ r = 0x00808145 |
+ (2 << 10) |
+ (0 << 16) |
+ (1 << 19);
+
+ writel(r, ccm + MX5_CCM_CBCDR);
+
+ writel(0x00016154, ccm + MX5_CCM_CBCMR);
+
+ /* change uart clk parent to pll2 */
+ r = readl(ccm + MX5_CCM_CSCMR1);
+ r &= ~(3 << 24);
+ r |= (1 << 24);
+ writel(r, ccm + MX5_CCM_CSCMR1);
+
+ /* make sure change is effective */
+ while (readl(ccm + MX5_CCM_CDHIPR));
+
+ setup_pll_216((void __iomem *)MX53_PLL3_BASE_ADDR);
+ setup_pll_455((void __iomem *)MX53_PLL4_BASE_ADDR);
+
+ /* Set the platform clock dividers */
+ writel(0x00000124, MX53_ARM_BASE_ADDR + 0x14);
+
+ writel(0, ccm + MX5_CCM_CACRR);
+
+ /* Switch ARM back to PLL 1. */
+ writel(0, ccm + MX5_CCM_CCSR);
+
+ /* make uart div = 6*/
+ r = readl(ccm + MX5_CCM_CSCDR1);
+ r &= ~0x3f;
+ r |= 0x0a;
+ writel(r, ccm + MX5_CCM_CSCDR1);
+
+ /* Restore the default values in the Gate registers */
+ writel(0xffffffff, ccm + MX5_CCM_CCGR0);
+ writel(0xffffffff, ccm + MX5_CCM_CCGR1);
+ writel(0xffffffff, ccm + MX5_CCM_CCGR2);
+ writel(0xffffffff, ccm + MX5_CCM_CCGR3);
+ writel(0xffffffff, ccm + MX5_CCM_CCGR4);
+ writel(0xffffffff, ccm + MX5_CCM_CCGR5);
+ writel(0xffffffff, ccm + MX5_CCM_CCGR6);
+ writel(0xffffffff, ccm + MX53_CCM_CCGR7);
+
+ writel(0, ccm + MX5_CCM_CCDR);
+
+ return 0;
+}