summaryrefslogtreecommitdiffstats
path: root/arch/arm/cpu/arm926ejs
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/cpu/arm926ejs')
-rw-r--r--arch/arm/cpu/arm926ejs/config.mk6
-rw-r--r--arch/arm/cpu/arm926ejs/lpc32xx/Makefile45
-rw-r--r--arch/arm/cpu/arm926ejs/lpc32xx/clk.c117
-rw-r--r--arch/arm/cpu/arm926ejs/lpc32xx/cpu.c70
-rw-r--r--arch/arm/cpu/arm926ejs/lpc32xx/devices.c52
-rw-r--r--arch/arm/cpu/arm926ejs/lpc32xx/timer.c95
-rw-r--r--arch/arm/cpu/arm926ejs/mx25/generic.c27
-rw-r--r--arch/arm/cpu/arm926ejs/mx28/Makefile2
-rw-r--r--arch/arm/cpu/arm926ejs/mx28/mx28.c29
-rw-r--r--arch/arm/cpu/arm926ejs/mx28/mx28_init.h4
-rw-r--r--arch/arm/cpu/arm926ejs/mx28/spl_boot.c57
-rw-r--r--arch/arm/cpu/arm926ejs/mx28/spl_lradc_init.c86
-rw-r--r--arch/arm/cpu/arm926ejs/mx28/spl_mem_init.c14
-rw-r--r--arch/arm/cpu/arm926ejs/mx28/spl_power_init.c224
14 files changed, 738 insertions, 90 deletions
diff --git a/arch/arm/cpu/arm926ejs/config.mk b/arch/arm/cpu/arm926ejs/config.mk
index ffb2e6c3ea..6a3a1bb354 100644
--- a/arch/arm/cpu/arm926ejs/config.mk
+++ b/arch/arm/cpu/arm926ejs/config.mk
@@ -31,3 +31,9 @@ PLATFORM_CPPFLAGS += -march=armv5te
# =========================================================================
PF_RELFLAGS_SLB_AT := $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,))
PLATFORM_RELFLAGS += $(PF_RELFLAGS_SLB_AT)
+
+ifneq ($(CONFIG_IMX_CONFIG),)
+
+ALL-y += $(obj)u-boot.imx
+
+endif
diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/Makefile b/arch/arm/cpu/arm926ejs/lpc32xx/Makefile
new file mode 100644
index 0000000000..ae1f0a5c0c
--- /dev/null
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/Makefile
@@ -0,0 +1,45 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)lib$(SOC).o
+
+COBJS = cpu.o clk.o devices.o timer.o
+
+SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS))
+
+all: $(obj).depend $(LIB)
+
+$(LIB): $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/clk.c b/arch/arm/cpu/arm926ejs/lpc32xx/clk.c
new file mode 100644
index 0000000000..6f26d626a7
--- /dev/null
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/clk.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2011 by Vladimir Zapolskiy <vz@mleia.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; 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <common.h>
+#include <div64.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/clk.h>
+#include <asm/io.h>
+
+static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE;
+
+unsigned int get_sys_clk_rate(void)
+{
+ if (readl(&clk->sysclk_ctrl) & CLK_SYSCLK_PLL397)
+ return RTC_CLK_FREQUENCY * 397;
+ else
+ return OSC_CLK_FREQUENCY;
+}
+
+unsigned int get_hclk_pll_rate(void)
+{
+ unsigned long long fin, fref, fcco, fout;
+ u32 val, m_div, n_div, p_div;
+
+ /*
+ * Valid frequency ranges:
+ * 1 * 10^6 <= Fin <= 20 * 10^6
+ * 1 * 10^6 <= Fref <= 27 * 10^6
+ * 156 * 10^6 <= Fcco <= 320 * 10^6
+ */
+
+ fref = fin = get_sys_clk_rate();
+ if (fin > 20000000ULL || fin < 1000000ULL)
+ return 0;
+
+ val = readl(&clk->hclkpll_ctrl);
+ m_div = ((val & CLK_HCLK_PLL_FEEDBACK_DIV_MASK) >> 1) + 1;
+ n_div = ((val & CLK_HCLK_PLL_PREDIV_MASK) >> 9) + 1;
+ if (val & CLK_HCLK_PLL_DIRECT)
+ p_div = 0;
+ else
+ p_div = ((val & CLK_HCLK_PLL_POSTDIV_MASK) >> 11) + 1;
+ p_div = 1 << p_div;
+
+ if (val & CLK_HCLK_PLL_BYPASS) {
+ do_div(fin, p_div);
+ return fin;
+ }
+
+ do_div(fref, n_div);
+ if (fref > 27000000ULL || fref < 1000000ULL)
+ return 0;
+
+ fout = fref * m_div;
+ if (val & CLK_HCLK_PLL_FEEDBACK) {
+ fcco = fout;
+ do_div(fout, p_div);
+ } else
+ fcco = fout * p_div;
+
+ if (fcco > 320000000ULL || fcco < 156000000ULL)
+ return 0;
+
+ return fout;
+}
+
+unsigned int get_hclk_clk_div(void)
+{
+ u32 val;
+
+ val = readl(&clk->hclkdiv_ctrl) & CLK_HCLK_ARM_PLL_DIV_MASK;
+
+ return 1 << val;
+}
+
+unsigned int get_hclk_clk_rate(void)
+{
+ return get_hclk_pll_rate() / get_hclk_clk_div();
+}
+
+unsigned int get_periph_clk_div(void)
+{
+ u32 val;
+
+ val = readl(&clk->hclkdiv_ctrl) & CLK_HCLK_PERIPH_DIV_MASK;
+
+ return (val >> 2) + 1;
+}
+
+unsigned int get_periph_clk_rate(void)
+{
+ if (!(readl(&clk->pwr_ctrl) & CLK_PWR_NORMAL_RUN))
+ return get_sys_clk_rate();
+
+ return get_hclk_pll_rate() / get_periph_clk_div();
+}
+
+int get_serial_clock(void)
+{
+ return get_periph_clk_rate();
+}
diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c b/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c
new file mode 100644
index 0000000000..e29e130338
--- /dev/null
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2011 by Vladimir Zapolskiy <vz@mleia.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; 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <common.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/wdt.h>
+#include <asm/io.h>
+
+static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE;
+static struct wdt_regs *wdt = (struct wdt_regs *)WDT_BASE;
+
+void reset_cpu(ulong addr)
+{
+ /* Enable watchdog clock */
+ setbits_le32(&clk->timclk_ctrl, CLK_TIMCLK_WATCHDOG);
+
+ /* Reset pulse length is 13005 peripheral clock frames */
+ writel(13000, &wdt->pulse);
+
+ /* Force WDOG_RESET2 and RESOUT_N signal active */
+ writel(WDTIM_MCTRL_RESFRC2 | WDTIM_MCTRL_RESFRC1 | WDTIM_MCTRL_M_RES2,
+ &wdt->mctrl);
+
+ while (1)
+ /* NOP */;
+}
+
+#if defined(CONFIG_ARCH_CPU_INIT)
+int arch_cpu_init(void)
+{
+ /*
+ * It might be necessary to flush data cache, if U-boot is loaded
+ * from kickstart bootloader, e.g. from S1L loader
+ */
+ flush_dcache_all();
+
+ return 0;
+}
+#else
+#error "You have to select CONFIG_ARCH_CPU_INIT"
+#endif
+
+#if defined(CONFIG_DISPLAY_CPUINFO)
+int print_cpuinfo(void)
+{
+ printf("CPU: NXP LPC32XX\n");
+ printf("CPU clock: %uMHz\n", get_hclk_pll_rate() / 1000000);
+ printf("AHB bus clock: %uMHz\n", get_hclk_clk_rate() / 1000000);
+ printf("Peripheral clock: %uMHz\n", get_periph_clk_rate() / 1000000);
+
+ return 0;
+}
+#endif
diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
new file mode 100644
index 0000000000..9f305b5ba5
--- /dev/null
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011 by Vladimir Zapolskiy <vz@mleia.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; 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <common.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/uart.h>
+#include <asm/io.h>
+
+static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE;
+static struct uart_ctrl_regs *ctrl = (struct uart_ctrl_regs *)UART_CTRL_BASE;
+
+void lpc32xx_uart_init(unsigned int uart_id)
+{
+ if (uart_id < 1 || uart_id > 7)
+ return;
+
+ /* Disable loopback mode, if it is set by S1L bootloader */
+ clrbits_le32(&ctrl->loop,
+ UART_LOOPBACK(CONFIG_SYS_LPC32XX_UART));
+
+ if (uart_id < 3 || uart_id > 6)
+ return;
+
+ /* Enable UART system clock */
+ setbits_le32(&clk->uartclk_ctrl, CLK_UART(uart_id));
+
+ /* Set UART into autoclock mode */
+ clrsetbits_le32(&ctrl->clkmode,
+ UART_CLKMODE_MASK(uart_id),
+ UART_CLKMODE_AUTO(uart_id));
+
+ /* Bypass pre-divider of UART clock */
+ writel(CLK_UART_X_DIV(1) | CLK_UART_Y_DIV(1),
+ &clk->u3clk + (uart_id - 3));
+}
diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/timer.c b/arch/arm/cpu/arm926ejs/lpc32xx/timer.c
new file mode 100644
index 0000000000..1ce2358afd
--- /dev/null
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/timer.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2011 Vladimir Zapolskiy <vz@mleia.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; 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <common.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/timer.h>
+#include <asm/io.h>
+
+static struct timer_regs *timer0 = (struct timer_regs *)TIMER0_BASE;
+static struct timer_regs *timer1 = (struct timer_regs *)TIMER1_BASE;
+static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE;
+
+static void lpc32xx_timer_clock(u32 bit, int enable)
+{
+ if (enable)
+ setbits_le32(&clk->timclk_ctrl1, bit);
+ else
+ clrbits_le32(&clk->timclk_ctrl1, bit);
+}
+
+static void lpc32xx_timer_reset(struct timer_regs *timer, u32 freq)
+{
+ writel(TIMER_TCR_COUNTER_RESET, &timer->tcr);
+ writel(TIMER_TCR_COUNTER_DISABLE, &timer->tcr);
+ writel(0, &timer->tc);
+ writel(0, &timer->pr);
+
+ /* Count mode is every rising PCLK edge */
+ writel(TIMER_CTCR_MODE_TIMER, &timer->ctcr);
+
+ /* Set prescale counter value */
+ writel((get_periph_clk_rate() / freq) - 1, &timer->pr);
+}
+
+static void lpc32xx_timer_count(struct timer_regs *timer, int enable)
+{
+ if (enable)
+ writel(TIMER_TCR_COUNTER_ENABLE, &timer->tcr);
+ else
+ writel(TIMER_TCR_COUNTER_DISABLE, &timer->tcr);
+}
+
+int timer_init(void)
+{
+ lpc32xx_timer_clock(CLK_TIMCLK_TIMER0, 1);
+ lpc32xx_timer_reset(timer0, CONFIG_SYS_HZ);
+ lpc32xx_timer_count(timer0, 1);
+
+ return 0;
+}
+
+ulong get_timer(ulong base)
+{
+ return readl(&timer0->tc) - base;
+}
+
+void __udelay(unsigned long usec)
+{
+ lpc32xx_timer_clock(CLK_TIMCLK_TIMER1, 1);
+ lpc32xx_timer_reset(timer1, CONFIG_SYS_HZ * 1000);
+ lpc32xx_timer_count(timer1, 1);
+
+ while (readl(&timer1->tc) < usec)
+ /* NOP */;
+
+ lpc32xx_timer_count(timer1, 0);
+ lpc32xx_timer_clock(CLK_TIMCLK_TIMER1, 0);
+}
+
+unsigned long long get_ticks(void)
+{
+ return get_timer(0);
+}
+
+ulong get_tbclk(void)
+{
+ return CONFIG_SYS_HZ;
+}
diff --git a/arch/arm/cpu/arm926ejs/mx25/generic.c b/arch/arm/cpu/arm926ejs/mx25/generic.c
index 9cadb7c34c..8b07dae2b9 100644
--- a/arch/arm/cpu/arm926ejs/mx25/generic.c
+++ b/arch/arm/cpu/arm926ejs/mx25/generic.c
@@ -28,10 +28,15 @@
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/imx25-pinmux.h>
+#include <asm/arch/clock.h>
#ifdef CONFIG_MXC_MMC
#include <asm/arch/mxcmmc.h>
#endif
+#ifdef CONFIG_FSL_ESDHC
+DECLARE_GLOBAL_DATA_PTR;
+#endif
+
/*
* get the system pll clock in Hz
*
@@ -105,6 +110,20 @@ ulong imx_get_perclk(int clk)
return lldiv(fref, div);
}
+unsigned int mxc_get_clock(enum mxc_clock clk)
+{
+ if (clk >= MXC_CLK_NUM)
+ return -1;
+ switch (clk) {
+ case MXC_ARM_CLK:
+ return imx_get_armclk();
+ case MXC_FEC_CLK:
+ return imx_get_ahbclk();
+ default:
+ return imx_get_perclk(clk);
+ }
+}
+
u32 get_cpu_rev(void)
{
u32 srev;
@@ -182,6 +201,14 @@ int cpu_eth_init(bd_t *bis)
#endif
}
+int get_clocks(void)
+{
+#ifdef CONFIG_FSL_ESDHC
+ gd->sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK);
+#endif
+ return 0;
+}
+
/*
* Initializes on-chip MMC controllers.
* to override, implement board_mmc_init()
diff --git a/arch/arm/cpu/arm926ejs/mx28/Makefile b/arch/arm/cpu/arm926ejs/mx28/Makefile
index a2e3f771c2..674a3af1be 100644
--- a/arch/arm/cpu/arm926ejs/mx28/Makefile
+++ b/arch/arm/cpu/arm926ejs/mx28/Makefile
@@ -28,7 +28,7 @@ LIB = $(obj)lib$(SOC).o
COBJS = clock.o mx28.o iomux.o timer.o
ifdef CONFIG_SPL_BUILD
-COBJS += spl_boot.o spl_mem_init.o spl_power_init.o
+COBJS += spl_boot.o spl_lradc_init.o spl_mem_init.o spl_power_init.o
endif
SRCS := $(START:.o=.S) $(COBJS:.o=.c)
diff --git a/arch/arm/cpu/arm926ejs/mx28/mx28.c b/arch/arm/cpu/arm926ejs/mx28/mx28.c
index dc0338dfb5..a82ff2564b 100644
--- a/arch/arm/cpu/arm926ejs/mx28/mx28.c
+++ b/arch/arm/cpu/arm926ejs/mx28/mx28.c
@@ -51,9 +51,16 @@ void reset_cpu(ulong ignored) __attribute__((noreturn));
void reset_cpu(ulong ignored)
{
-
struct mx28_rtc_regs *rtc_regs =
(struct mx28_rtc_regs *)MXS_RTC_BASE;
+ struct mx28_lcdif_regs *lcdif_regs =
+ (struct mx28_lcdif_regs *)MXS_LCDIF_BASE;
+
+ /*
+ * Shut down the LCD controller as it interferes with BootROM boot mode
+ * pads sampling.
+ */
+ writel(LCDIF_CTRL_RUN, &lcdif_regs->hw_lcdif_ctrl_clr);
/* Wait 1 uS before doing the actual watchdog reset */
writel(1, &rtc_regs->hw_rtc_watchdog);
@@ -185,8 +192,12 @@ int arch_cpu_init(void)
#if defined(CONFIG_DISPLAY_CPUINFO)
int print_cpuinfo(void)
{
+ struct mx28_spl_data *data = (struct mx28_spl_data *)
+ ((CONFIG_SYS_TEXT_BASE - sizeof(struct mx28_spl_data)) & ~0xf);
+
printf("Freescale i.MX28 family at %d MHz\n",
mxc_get_clock(MXC_ARM_CLK) / 1000000);
+ printf("BOOT: %s\n", mx28_boot_modes[data->boot_mode_idx].mode);
return 0;
}
#endif
@@ -279,22 +290,16 @@ void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
int mx28_dram_init(void)
{
- struct mx28_digctl_regs *digctl_regs =
- (struct mx28_digctl_regs *)MXS_DIGCTL_BASE;
- uint32_t sz[2];
-
- sz[0] = readl(&digctl_regs->hw_digctl_scratch0);
- sz[1] = readl(&digctl_regs->hw_digctl_scratch1);
+ struct mx28_spl_data *data = (struct mx28_spl_data *)
+ ((CONFIG_SYS_TEXT_BASE - sizeof(struct mx28_spl_data)) & ~0xf);
- if (sz[0] != sz[1]) {
+ if (data->mem_dram_size == 0) {
printf("MX28:\n"
- "Error, the RAM size in HW_DIGCTRL_SCRATCH0 and\n"
- "HW_DIGCTRL_SCRATCH1 is not the same. Please\n"
- "verify these two registers contain valid RAM size!\n");
+ "Error, the RAM size passed up from SPL is 0!\n");
hang();
}
- gd->ram_size = sz[0];
+ gd->ram_size = data->mem_dram_size;
return 0;
}
diff --git a/arch/arm/cpu/arm926ejs/mx28/mx28_init.h b/arch/arm/cpu/arm926ejs/mx28/mx28_init.h
index 98d363199d..e3a4493fbd 100644
--- a/arch/arm/cpu/arm926ejs/mx28/mx28_init.h
+++ b/arch/arm/cpu/arm926ejs/mx28/mx28_init.h
@@ -37,5 +37,9 @@ static inline void mx28_power_wait_pswitch(void) { }
#endif
void mx28_mem_init(void);
+uint32_t mx28_mem_get_size(void);
+
+void mx28_lradc_init(void);
+void mx28_lradc_enable_batt_measurement(void);
#endif /* __M28_INIT_H__ */
diff --git a/arch/arm/cpu/arm926ejs/mx28/spl_boot.c b/arch/arm/cpu/arm926ejs/mx28/spl_boot.c
index dfb8309e70..a6dfca3f51 100644
--- a/arch/arm/cpu/arm926ejs/mx28/spl_boot.c
+++ b/arch/arm/cpu/arm926ejs/mx28/spl_boot.c
@@ -28,6 +28,8 @@
#include <asm/io.h>
#include <asm/arch/iomux-mx28.h>
#include <asm/arch/imx-regs.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/gpio.h>
#include "mx28_init.h"
@@ -46,12 +48,65 @@ void early_delay(int delay)
;
}
+#define MUX_CONFIG_BOOTMODE_PAD (MXS_PAD_3V3 | MXS_PAD_4MA | MXS_PAD_NOPULL)
+const iomux_cfg_t iomux_boot[] = {
+ MX28_PAD_LCD_D00__GPIO_1_0 | MUX_CONFIG_BOOTMODE_PAD,
+ MX28_PAD_LCD_D01__GPIO_1_1 | MUX_CONFIG_BOOTMODE_PAD,
+ MX28_PAD_LCD_D02__GPIO_1_2 | MUX_CONFIG_BOOTMODE_PAD,
+ MX28_PAD_LCD_D03__GPIO_1_3 | MUX_CONFIG_BOOTMODE_PAD,
+ MX28_PAD_LCD_D04__GPIO_1_4 | MUX_CONFIG_BOOTMODE_PAD,
+ MX28_PAD_LCD_D05__GPIO_1_5 | MUX_CONFIG_BOOTMODE_PAD,
+};
+
+uint8_t mx28_get_bootmode_index(void)
+{
+ uint8_t bootmode = 0;
+ int i;
+ uint8_t masked;
+
+ /* Setup IOMUX of bootmode pads to GPIO */
+ mxs_iomux_setup_multiple_pads(iomux_boot, ARRAY_SIZE(iomux_boot));
+
+ /* Setup bootmode pins as GPIO input */
+ gpio_direction_input(MX28_PAD_LCD_D00__GPIO_1_0);
+ gpio_direction_input(MX28_PAD_LCD_D01__GPIO_1_1);
+ gpio_direction_input(MX28_PAD_LCD_D02__GPIO_1_2);
+ gpio_direction_input(MX28_PAD_LCD_D03__GPIO_1_3);
+ gpio_direction_input(MX28_PAD_LCD_D04__GPIO_1_4);
+ gpio_direction_input(MX28_PAD_LCD_D05__GPIO_1_5);
+
+ /* Read bootmode pads */
+ bootmode |= (gpio_get_value(MX28_PAD_LCD_D00__GPIO_1_0) ? 1 : 0) << 0;
+ bootmode |= (gpio_get_value(MX28_PAD_LCD_D01__GPIO_1_1) ? 1 : 0) << 1;
+ bootmode |= (gpio_get_value(MX28_PAD_LCD_D02__GPIO_1_2) ? 1 : 0) << 2;
+ bootmode |= (gpio_get_value(MX28_PAD_LCD_D03__GPIO_1_3) ? 1 : 0) << 3;
+ bootmode |= (gpio_get_value(MX28_PAD_LCD_D04__GPIO_1_4) ? 1 : 0) << 4;
+ bootmode |= (gpio_get_value(MX28_PAD_LCD_D05__GPIO_1_5) ? 1 : 0) << 5;
+
+ for (i = 0; i < ARRAY_SIZE(mx28_boot_modes); i++) {
+ masked = bootmode & mx28_boot_modes[i].boot_mask;
+ if (masked == mx28_boot_modes[i].boot_pads)
+ break;
+ }
+
+ return i;
+}
+
void mx28_common_spl_init(const iomux_cfg_t *iomux_setup,
const unsigned int iomux_size)
{
+ struct mx28_spl_data *data = (struct mx28_spl_data *)
+ ((CONFIG_SYS_TEXT_BASE - sizeof(struct mx28_spl_data)) & ~0xf);
+ uint8_t bootmode = mx28_get_bootmode_index();
+
mxs_iomux_setup_multiple_pads(iomux_setup, iomux_size);
mx28_power_init();
+
mx28_mem_init();
+ data->mem_dram_size = mx28_mem_get_size();
+
+ data->boot_mode_idx = bootmode;
+
mx28_power_wait_pswitch();
}
@@ -68,8 +123,10 @@ inline void board_init_r(gd_t *id, ulong dest_addr)
;
}
+#ifndef CONFIG_SPL_SERIAL_SUPPORT
void serial_putc(const char c) {}
void serial_puts(const char *s) {}
+#endif
void hang(void) __attribute__ ((noreturn));
void hang(void)
{
diff --git a/arch/arm/cpu/arm926ejs/mx28/spl_lradc_init.c b/arch/arm/cpu/arm926ejs/mx28/spl_lradc_init.c
new file mode 100644
index 0000000000..88a603c11d
--- /dev/null
+++ b/arch/arm/cpu/arm926ejs/mx28/spl_lradc_init.c
@@ -0,0 +1,86 @@
+/*
+ * Freescale i.MX28 Battery measurement init
+ *
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ * on behalf of DENX Software Engineering GmbH
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ */
+
+#include <common.h>
+#include <config.h>
+#include <asm/io.h>
+#include <asm/arch/imx-regs.h>
+
+#include "mx28_init.h"
+
+void mx28_lradc_init(void)
+{
+ struct mx28_lradc_regs *regs = (struct mx28_lradc_regs *)MXS_LRADC_BASE;
+
+ writel(LRADC_CTRL0_SFTRST, &regs->hw_lradc_ctrl0_clr);
+ writel(LRADC_CTRL0_CLKGATE, &regs->hw_lradc_ctrl0_clr);
+ writel(LRADC_CTRL0_ONCHIP_GROUNDREF, &regs->hw_lradc_ctrl0_clr);
+
+ clrsetbits_le32(&regs->hw_lradc_ctrl3,
+ LRADC_CTRL3_CYCLE_TIME_MASK,
+ LRADC_CTRL3_CYCLE_TIME_6MHZ);
+
+ clrsetbits_le32(&regs->hw_lradc_ctrl4,
+ LRADC_CTRL4_LRADC7SELECT_MASK |
+ LRADC_CTRL4_LRADC6SELECT_MASK,
+ LRADC_CTRL4_LRADC7SELECT_CHANNEL7 |
+ LRADC_CTRL4_LRADC6SELECT_CHANNEL10);
+}
+
+void mx28_lradc_enable_batt_measurement(void)
+{
+ struct mx28_lradc_regs *regs = (struct mx28_lradc_regs *)MXS_LRADC_BASE;
+
+ /* Check if the channel is present at all. */
+ if (!(readl(&regs->hw_lradc_status) & LRADC_STATUS_CHANNEL7_PRESENT))
+ return;
+
+ writel(LRADC_CTRL1_LRADC7_IRQ_EN, &regs->hw_lradc_ctrl1_clr);
+ writel(LRADC_CTRL1_LRADC7_IRQ, &regs->hw_lradc_ctrl1_clr);
+
+ clrsetbits_le32(&regs->hw_lradc_conversion,
+ LRADC_CONVERSION_SCALE_FACTOR_MASK,
+ LRADC_CONVERSION_SCALE_FACTOR_LI_ION);
+ writel(LRADC_CONVERSION_AUTOMATIC, &regs->hw_lradc_conversion_set);
+
+ /* Configure the channel. */
+ writel((1 << 7) << LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET,
+ &regs->hw_lradc_ctrl2_clr);
+ writel(0xffffffff, &regs->hw_lradc_ch7_clr);
+ clrbits_le32(&regs->hw_lradc_ch7, LRADC_CH_NUM_SAMPLES_MASK);
+ writel(LRADC_CH_ACCUMULATE, &regs->hw_lradc_ch7_clr);
+
+ /* Schedule the channel. */
+ writel(1 << 7, &regs->hw_lradc_ctrl0_set);
+
+ /* Start the channel sampling. */
+ writel(((1 << 7) << LRADC_DELAY_TRIGGER_LRADCS_OFFSET) |
+ ((1 << 3) << LRADC_DELAY_TRIGGER_DELAYS_OFFSET) |
+ 100, &regs->hw_lradc_delay3);
+
+ writel(0xffffffff, &regs->hw_lradc_ch7_clr);
+
+ writel(LRADC_DELAY_KICK, &regs->hw_lradc_delay3_set);
+}
diff --git a/arch/arm/cpu/arm926ejs/mx28/spl_mem_init.c b/arch/arm/cpu/arm926ejs/mx28/spl_mem_init.c
index 911bbefc06..9fa5d29e6c 100644
--- a/arch/arm/cpu/arm926ejs/mx28/spl_mem_init.c
+++ b/arch/arm/cpu/arm926ejs/mx28/spl_mem_init.c
@@ -39,7 +39,7 @@ uint32_t dram_vals[] = {
0x00000000, 0x00000100, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00010101, 0x01010101,
- 0x000f0f01, 0x0f02010a, 0x00000000, 0x00010101,
+ 0x000f0f01, 0x0f02020a, 0x00000000, 0x00010101,
0x00000100, 0x00000100, 0x00000000, 0x00000002,
0x01010000, 0x05060302, 0x06005003, 0x0a0000c8,
0x02009c40, 0x0000030c, 0x0036a609, 0x031a0612,
@@ -149,6 +149,8 @@ void mx28_mem_setup_cpu_and_hbus(void)
/* Disable CPU bypass */
writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
&clkctrl_regs->hw_clkctrl_clkseq_clr);
+
+ early_delay(15000);
}
void mx28_mem_setup_vdda(void)
@@ -173,10 +175,8 @@ void mx28_mem_setup_vddd(void)
&power_regs->hw_power_vdddctrl);
}
-void mx28_mem_get_size(void)
+uint32_t mx28_mem_get_size(void)
{
- struct mx28_digctl_regs *digctl_regs =
- (struct mx28_digctl_regs *)MXS_DIGCTL_BASE;
uint32_t sz, da;
uint32_t *vt = (uint32_t *)0x20;
/* The following is "subs pc, r14, #4", used as return from DABT. */
@@ -187,11 +187,11 @@ void mx28_mem_get_size(void)
vt[4] = data_abort_memdetect_handler;
sz = get_ram_size((long *)PHYS_SDRAM_1, PHYS_SDRAM_1_SIZE);
- writel(sz, &digctl_regs->hw_digctl_scratch0);
- writel(sz, &digctl_regs->hw_digctl_scratch1);
/* Restore the old DABT handler. */
vt[4] = da;
+
+ return sz;
}
void mx28_mem_init(void)
@@ -239,6 +239,4 @@ void mx28_mem_init(void)
early_delay(10000);
mx28_mem_setup_cpu_and_hbus();
-
- mx28_mem_get_size();
}
diff --git a/arch/arm/cpu/arm926ejs/mx28/spl_power_init.c b/arch/arm/cpu/arm926ejs/mx28/spl_power_init.c
index aa4117d3a2..4b09b0c3ba 100644
--- a/arch/arm/cpu/arm926ejs/mx28/spl_power_init.c
+++ b/arch/arm/cpu/arm926ejs/mx28/spl_power_init.c
@@ -45,11 +45,11 @@ void mx28_power_clock2pll(void)
struct mx28_clkctrl_regs *clkctrl_regs =
(struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
- writel(CLKCTRL_PLL0CTRL0_POWER,
- &clkctrl_regs->hw_clkctrl_pll0ctrl0_set);
+ setbits_le32(&clkctrl_regs->hw_clkctrl_pll0ctrl0,
+ CLKCTRL_PLL0CTRL0_POWER);
early_delay(100);
- writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
- &clkctrl_regs->hw_clkctrl_clkseq_clr);
+ setbits_le32(&clkctrl_regs->hw_clkctrl_clkseq,
+ CLKCTRL_CLKSEQ_BYPASS_CPU);
}
void mx28_power_clear_auto_restart(void)
@@ -104,6 +104,62 @@ void mx28_power_set_linreg(void)
POWER_VDDIOCTRL_LINREG_OFFSET_1STEPS_BELOW);
}
+int mx28_get_batt_volt(void)
+{
+ struct mx28_power_regs *power_regs =
+ (struct mx28_power_regs *)MXS_POWER_BASE;
+ uint32_t volt = readl(&power_regs->hw_power_battmonitor);
+ volt &= POWER_BATTMONITOR_BATT_VAL_MASK;
+ volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET;
+ volt *= 8;
+ return volt;
+}
+
+int mx28_is_batt_ready(void)
+{
+ return (mx28_get_batt_volt() >= 3600);
+}
+
+int mx28_is_batt_good(void)
+{
+ struct mx28_power_regs *power_regs =
+ (struct mx28_power_regs *)MXS_POWER_BASE;
+ uint32_t volt = mx28_get_batt_volt();
+
+ if ((volt >= 2400) && (volt <= 4300))
+ return 1;
+
+ clrsetbits_le32(&power_regs->hw_power_5vctrl,
+ POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
+ 0x3 << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET);
+ writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
+ &power_regs->hw_power_5vctrl_clr);
+
+ clrsetbits_le32(&power_regs->hw_power_charge,
+ POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK,
+ POWER_CHARGE_STOP_ILIMIT_10MA | 0x3);
+
+ writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_clr);
+ writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
+ &power_regs->hw_power_5vctrl_clr);
+
+ early_delay(500000);
+
+ volt = mx28_get_batt_volt();
+
+ if (volt >= 3500)
+ return 0;
+
+ if (volt >= 2400)
+ return 1;
+
+ writel(POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK,
+ &power_regs->hw_power_charge_clr);
+ writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_set);
+
+ return 0;
+}
+
void mx28_power_setup_5v_detect(void)
{
struct mx28_power_regs *power_regs =
@@ -399,9 +455,14 @@ void mx28_power_enable_4p2(void)
mx28_power_init_4p2_regulator();
/* Shutdown battery (none present) */
- clrbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_BO_MASK);
- writel(POWER_CTRL_DCDC4P2_BO_IRQ, &power_regs->hw_power_ctrl_clr);
- writel(POWER_CTRL_ENIRQ_DCDC4P2_BO, &power_regs->hw_power_ctrl_clr);
+ if (!mx28_is_batt_ready()) {
+ clrbits_le32(&power_regs->hw_power_dcdc4p2,
+ POWER_DCDC4P2_BO_MASK);
+ writel(POWER_CTRL_DCDC4P2_BO_IRQ,
+ &power_regs->hw_power_ctrl_clr);
+ writel(POWER_CTRL_ENIRQ_DCDC4P2_BO,
+ &power_regs->hw_power_ctrl_clr);
+ }
mx28_power_init_dcdc_4p2_source();
@@ -459,6 +520,50 @@ void mx28_powerdown(void)
&power_regs->hw_power_reset);
}
+void mx28_batt_boot(void)
+{
+ struct mx28_power_regs *power_regs =
+ (struct mx28_power_regs *)MXS_POWER_BASE;
+
+ clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_PWDN_5VBRNOUT);
+ clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_ENABLE_DCDC);
+
+ clrbits_le32(&power_regs->hw_power_dcdc4p2,
+ POWER_DCDC4P2_ENABLE_DCDC | POWER_DCDC4P2_ENABLE_4P2);
+ writel(POWER_CHARGE_ENABLE_LOAD, &power_regs->hw_power_charge_clr);
+
+ /* 5V to battery handoff. */
+ setbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER);
+ early_delay(30);
+ clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER);
+
+ writel(POWER_CTRL_ENIRQ_DCDC4P2_BO, &power_regs->hw_power_ctrl_clr);
+
+ clrsetbits_le32(&power_regs->hw_power_minpwr,
+ POWER_MINPWR_HALFFETS, POWER_MINPWR_DOUBLE_FETS);
+
+ mx28_power_set_linreg();
+
+ clrbits_le32(&power_regs->hw_power_vdddctrl,
+ POWER_VDDDCTRL_DISABLE_FET | POWER_VDDDCTRL_ENABLE_LINREG);
+
+ clrbits_le32(&power_regs->hw_power_vddactrl,
+ POWER_VDDACTRL_DISABLE_FET | POWER_VDDACTRL_ENABLE_LINREG);
+
+ clrbits_le32(&power_regs->hw_power_vddioctrl,
+ POWER_VDDIOCTRL_DISABLE_FET);
+
+ setbits_le32(&power_regs->hw_power_5vctrl,
+ POWER_5VCTRL_PWD_CHARGE_4P2_MASK);
+
+ setbits_le32(&power_regs->hw_power_5vctrl,
+ POWER_5VCTRL_ENABLE_DCDC);
+
+ clrsetbits_le32(&power_regs->hw_power_5vctrl,
+ POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
+ 0x8 << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET);
+}
+
void mx28_handle_5v_conflict(void)
{
struct mx28_power_regs *power_regs =
@@ -483,23 +588,12 @@ void mx28_handle_5v_conflict(void)
mx28_powerdown();
break;
}
- }
-}
-int mx28_get_batt_volt(void)
-{
- struct mx28_power_regs *power_regs =
- (struct mx28_power_regs *)MXS_POWER_BASE;
- uint32_t volt = readl(&power_regs->hw_power_battmonitor);
- volt &= POWER_BATTMONITOR_BATT_VAL_MASK;
- volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET;
- volt *= 8;
- return volt;
-}
-
-int mx28_is_batt_ready(void)
-{
- return (mx28_get_batt_volt() >= 3600);
+ if (tmp & POWER_STS_PSWITCH_MASK) {
+ mx28_batt_boot();
+ break;
+ }
+ }
}
void mx28_5v_boot(void)
@@ -553,62 +647,44 @@ void mx28_switch_vddd_to_dcdc_source(void)
POWER_VDDDCTRL_DISABLE_STEPPING);
}
-int mx28_is_batt_good(void)
+void mx28_power_configure_power_source(void)
{
+ int batt_ready, batt_good;
struct mx28_power_regs *power_regs =
(struct mx28_power_regs *)MXS_POWER_BASE;
- uint32_t volt;
-
- volt = readl(&power_regs->hw_power_battmonitor);
- volt &= POWER_BATTMONITOR_BATT_VAL_MASK;
- volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET;
- volt *= 8;
+ struct mx28_lradc_regs *lradc_regs =
+ (struct mx28_lradc_regs *)MXS_LRADC_BASE;
- if ((volt >= 2400) && (volt <= 4300))
- return 1;
-
- clrsetbits_le32(&power_regs->hw_power_5vctrl,
- POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
- 0x3 << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET);
- writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
- &power_regs->hw_power_5vctrl_clr);
-
- clrsetbits_le32(&power_regs->hw_power_charge,
- POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK,
- POWER_CHARGE_STOP_ILIMIT_10MA | 0x3);
-
- writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_clr);
- writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
- &power_regs->hw_power_5vctrl_clr);
-
- early_delay(500000);
-
- volt = readl(&power_regs->hw_power_battmonitor);
- volt &= POWER_BATTMONITOR_BATT_VAL_MASK;
- volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET;
- volt *= 8;
-
- if (volt >= 3500)
- return 0;
-
- if (volt >= 2400)
- return 1;
-
- writel(POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK,
- &power_regs->hw_power_charge_clr);
- writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_set);
+ mx28_src_power_init();
- return 0;
-}
+ batt_ready = mx28_is_batt_ready();
-void mx28_power_configure_power_source(void)
-{
- mx28_src_power_init();
+ if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
+ batt_good = mx28_is_batt_good();
+ if (batt_ready) {
+ /* 5V source detected, good battery detected. */
+ mx28_batt_boot();
+ } else {
+ if (batt_good) {
+ /* 5V source detected, low battery detceted. */
+ } else {
+ /* 5V source detected, bad battery detected. */
+ writel(LRADC_CONVERSION_AUTOMATIC,
+ &lradc_regs->hw_lradc_conversion_clr);
+ clrbits_le32(&power_regs->hw_power_battmonitor,
+ POWER_BATTMONITOR_BATT_VAL_MASK);
+ }
+ mx28_5v_boot();
+ }
+ } else {
+ /* 5V not detected, booting from battery. */
+ mx28_batt_boot();
+ }
- mx28_5v_boot();
mx28_power_clock2pll();
mx28_init_batt_bo();
+
mx28_switch_vddd_to_dcdc_source();
}
@@ -883,6 +959,13 @@ void mx28_power_set_vddd(uint32_t new_target, uint32_t new_brownout)
new_brownout << POWER_VDDDCTRL_BO_OFFSET_OFFSET);
}
+void mx28_setup_batt_detect(void)
+{
+ mx28_lradc_init();
+ mx28_lradc_enable_batt_measurement();
+ early_delay(10);
+}
+
void mx28_power_init(void)
{
struct mx28_power_regs *power_regs =
@@ -892,6 +975,9 @@ void mx28_power_init(void)
mx28_power_clear_auto_restart();
mx28_power_set_linreg();
mx28_power_setup_5v_detect();
+
+ mx28_setup_batt_detect();
+
mx28_power_configure_power_source();
mx28_enable_output_rail_protection();
OpenPOWER on IntegriCloud