summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorJuergen Beisert <jbe@pengutronix.de>2010-10-08 11:02:43 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2010-10-12 22:10:35 +0200
commitb531c53e74ed686947bd45eab22fb4d3b793a33b (patch)
tree05bfa125936489c8997b533828e1ed0c2a9c70f9 /arch
parent857b9f558b1cdd2912ccc65f248c85d7c5acb372 (diff)
downloadbarebox-b531c53e74ed686947bd45eab22fb4d3b793a33b.tar.gz
barebox-b531c53e74ed686947bd45eab22fb4d3b793a33b.tar.xz
Switch the i.MX27's PLL in a safe manner
Changing PLL settings is somehow tricky on the i.MX27: Whenever the clock speed of the main PLL is changed, the clock stops for about 100 us until the PLL locks into the new frequency. While this clock stop, also the SDRAM controller cannot refresh the memory, because it uses the same clock source. This can lead into data loss and random system crashes. This patch divides the PLL setting in two steps. First step is to re-program the PLL and clock settings to values possible at a core supply of 1.25 V. Second step is to increase the core power supply to 1.45 V and switch the CPU clock to the specified 400 MHz. Signed-off-by: Juergen Beisert <jbe@pengutronix.de> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/boards/pcm038/Makefile2
-rw-r--r--arch/arm/boards/pcm038/lowlevel.c7
-rw-r--r--arch/arm/boards/pcm038/pcm038.c65
-rw-r--r--arch/arm/boards/pcm038/pll.h70
-rw-r--r--arch/arm/boards/pcm038/pll_init.S48
5 files changed, 114 insertions, 78 deletions
diff --git a/arch/arm/boards/pcm038/Makefile b/arch/arm/boards/pcm038/Makefile
index a681ddafb9..970804e280 100644
--- a/arch/arm/boards/pcm038/Makefile
+++ b/arch/arm/boards/pcm038/Makefile
@@ -1,3 +1,3 @@
-obj-y += lowlevel.o pll_init.o
+obj-y += lowlevel.o
obj-y += pcm038.o
diff --git a/arch/arm/boards/pcm038/lowlevel.c b/arch/arm/boards/pcm038/lowlevel.c
index eb85e8f27b..b50e1c8386 100644
--- a/arch/arm/boards/pcm038/lowlevel.c
+++ b/arch/arm/boards/pcm038/lowlevel.c
@@ -31,6 +31,8 @@
#include <asm/system.h>
#include <asm-generic/memory_layout.h>
+#include "pll.h"
+
#ifdef CONFIG_NAND_IMX_BOOT
static void __bare_init __naked insdram(void)
{
@@ -68,6 +70,11 @@ void __bare_init __naked board_init_lowlevel(void)
if (r > 0xa0000000 && r < 0xb0000000)
board_init_lowlevel_return();
+ /* re-program the PLL prior(!) starting the SDRAM controller */
+ MPCTL0 = MPCTL0_VAL;
+ SPCTL0 = SPCTL0_VAL;
+ CSCR = CSCR_VAL | CSCR_UPDATE_DIS | CSCR_MPLL_RESTART | CSCR_SPLL_RESTART;
+
/*
* DDR on CSD0
*/
diff --git a/arch/arm/boards/pcm038/pcm038.c b/arch/arm/boards/pcm038/pcm038.c
index fda326240b..3a9b41352b 100644
--- a/arch/arm/boards/pcm038/pcm038.c
+++ b/arch/arm/boards/pcm038/pcm038.c
@@ -44,6 +44,8 @@
#include <mach/spi.h>
#include <mach/iomux-mx27.h>
+#include "pll.h"
+
static struct device_d cfi_dev = {
.id = -1,
.name = "cfi_flash",
@@ -379,11 +381,6 @@ static struct device_d pcm038_serial_device = {
static int pcm038_console_init(void)
{
- /* bring PLLs to reset default */
- MPCTL0 = 0x00211803;
- SPCTL0 = 0x1002700c;
- CSCR = 0x33fc1307;
-
register_device(&pcm038_serial_device);
return 0;
@@ -391,40 +388,50 @@ static int pcm038_console_init(void)
console_initcall(pcm038_console_init);
-extern void *pcm038_pll_init, *pcm038_pll_init_end;
-
-static int pcm038_power_init(void)
+/**
+ * The spctl0 register is a beast: Seems you can read it
+ * only one times without writing it again.
+ */
+static inline uint32_t get_pll_spctl10(void)
{
- int ret;
- void *vram = (void*)0xffff4c00;
- void (*pllfunc)(void) = vram;
+ uint32_t reg;
- printf("initialising PLLs: 0x%p 0x%p\n", &pcm038_pll_init);
+ reg = SPCTL0;
+ SPCTL0 = reg;
- memcpy(vram, &pcm038_pll_init, 0x100);
+ return reg;
+}
- console_flush();
+/**
+ * If the PLL settings are in place switch the CPU core frequency to the max. value
+ */
+static int pcm038_power_init(void)
+{
+ uint32_t spctl0;
+ int ret;
- ret = pmic_power();
- if (ret) {
- printf("Failed to initialize PMIC. Will continue with low CPU speed\n");
- return 0;
+ spctl0 = get_pll_spctl10();
+
+ /* PLL registers already set to their final values? */
+ if (spctl0 == SPCTL0_VAL && MPCTL0 == MPCTL0_VAL) {
+ console_flush();
+ ret = pmic_power();
+ if (ret == 0) {
+ /* wait for required power level to run the CPU at 400 MHz */
+ udelay(100000);
+ CSCR = CSCR_VAL_FINAL;
+ PCDR0 = 0x130410c3;
+ PCDR1 = 0x09030911;
+ /* Clocks have changed. Notify clients */
+ clock_notifier_call_chain();
+ } else {
+ printf("Failed to initialize PMIC. Will continue with low CPU speed\n");
+ }
}
- /* wait for good power level */
- udelay(100000);
-
- pllfunc();
-
/* clock gating enable */
GPCR = 0x00050f08;
- PCDR0 = 0x130410c3;
- PCDR1 = 0x09030911;
-
- /* Clocks have changed. Notify clients */
- clock_notifier_call_chain();
-
return 0;
}
diff --git a/arch/arm/boards/pcm038/pll.h b/arch/arm/boards/pcm038/pll.h
new file mode 100644
index 0000000000..13a7989cb5
--- /dev/null
+++ b/arch/arm/boards/pcm038/pll.h
@@ -0,0 +1,70 @@
+/*
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/**
+ * @file
+ * @brief phyCORE-i.MX27 specific PLL setup
+ */
+
+#ifndef __PCM038_PLL_H
+#define __PCM038_PLL_H
+
+/* define the PLL setting we want to run the system */
+
+/* main clock divider settings immediately after reset (at 1.25 V core supply) */
+#define CSCR_VAL (CSCR_USB_DIV(3) | \
+ CSCR_SD_CNT(3) | \
+ CSCR_MSHC_SEL | \
+ CSCR_H264_SEL | \
+ CSCR_SSI1_SEL | \
+ CSCR_SSI2_SEL | \
+ CSCR_SP_SEL | /* 26 MHz reference */ \
+ CSCR_MCU_SEL | /* 26 MHz reference */ \
+ CSCR_ARM_DIV(0) | /* CPU runs at MPLL/3 clock */ \
+ CSCR_AHB_DIV(1) | /* AHB runs at MPLL/6 clock */ \
+ CSCR_SPEN | \
+ CSCR_MPEN)
+
+/* main clock divider settings after core voltage increases to 1.45 V */
+#define CSCR_VAL_FINAL (CSCR_USB_DIV(3) | \
+ CSCR_SD_CNT(3) | \
+ CSCR_MSHC_SEL | \
+ CSCR_H264_SEL | \
+ CSCR_SSI1_SEL | \
+ CSCR_SSI2_SEL | \
+ CSCR_SP_SEL | /* 26 MHz reference */ \
+ CSCR_MCU_SEL | /* 26 MHz reference */ \
+ CSCR_ARM_SRC_MPLL | /* use main MPLL clock */ \
+ CSCR_ARM_DIV(0) | /* CPU run at full MPLL clock */ \
+ CSCR_AHB_DIV(1) | /* AHB runs at MPLL/6 clock */ \
+ CSCR_SPEN | \
+ CSCR_MPEN)
+
+/* MPLL should provide a 399 MHz clock from the 26 MHz reference */
+#define MPCTL0_VAL (IMX_PLL_PD(0) | \
+ IMX_PLL_MFD(51) | \
+ IMX_PLL_MFI(7) | \
+ IMX_PLL_MFN(35))
+
+/* SPLL should provide a 240 MHz clock from the 26 MHz reference */
+#define SPCTL0_VAL (IMX_PLL_PD(1) | \
+ IMX_PLL_MFD(12) | \
+ IMX_PLL_MFI(9) | \
+ IMX_PLL_MFN(3))
+
+
+#endif /* __PCM038_PLL_H */
diff --git a/arch/arm/boards/pcm038/pll_init.S b/arch/arm/boards/pcm038/pll_init.S
deleted file mode 100644
index 0c1ff13415..0000000000
--- a/arch/arm/boards/pcm038/pll_init.S
+++ /dev/null
@@ -1,48 +0,0 @@
-#include <config.h>
-#include <mach/imx-regs.h>
-#include <mach/imx-pll.h>
-#include <linux/linkage.h>
-
-#define writel(val, reg) \
- ldr r0, =reg; \
- ldr r1, =val; \
- str r1, [r0];
-
-#define CSCR_VAL CSCR_USB_DIV(3) | \
- CSCR_SD_CNT(3) | \
- CSCR_MSHC_SEL | \
- CSCR_H264_SEL | \
- CSCR_SSI1_SEL | \
- CSCR_SSI2_SEL | \
- CSCR_MCU_SEL | \
- CSCR_ARM_SRC_MPLL | \
- CSCR_SP_SEL | \
- CSCR_ARM_DIV(0) | \
- CSCR_FPM_EN | \
- CSCR_SPEN | \
- CSCR_MPEN | \
- CSCR_AHB_DIV(1)
-
-ENTRY(pcm038_pll_init)
-
- writel(IMX_PLL_PD(0) |
- IMX_PLL_MFD(51) |
- IMX_PLL_MFI(7) |
- IMX_PLL_MFN(35), MPCTL0) /* 399 MHz */
-
- writel(IMX_PLL_PD(1) |
- IMX_PLL_MFD(12) |
- IMX_PLL_MFI(9) |
- IMX_PLL_MFN(3), SPCTL0) /* SPLL = 2 * 26 * 4.61538 MHz = 240 MHz */
-
- writel(CSCR_VAL | CSCR_MPLL_RESTART | CSCR_SPLL_RESTART, CSCR)
-
- ldr r2, =16000
-1:
- subs r2, r2, #1
- nop
- bcs 1b
-
- mov pc, lr
-ENDPROC(pcm038_pll_init)
-