[U-Boot] [PATCH 2/9] MX51: Add initial support for the Freescale MX51
Stefano Babic
sbabic at denx.de
Mon Jan 11 13:25:53 CET 2010
The patch add initial support for the Freescale i.MX51 processor
(family arm cortex_a8).
Signed-off-by: Fred Fan fanyefeng at gmail.com
Signed-off-by: Stefano Babic <sbabic at denx.de>
---
cpu/arm_cortexa8/mx51/Makefile | 48 +++++
cpu/arm_cortexa8/mx51/clock.c | 282 +++++++++++++++++++++++++++++
cpu/arm_cortexa8/mx51/iomux.c | 205 +++++++++++++++++++++
cpu/arm_cortexa8/mx51/lowlevel_init.S | 320 +++++++++++++++++++++++++++++++++
cpu/arm_cortexa8/mx51/soc.c | 78 ++++++++
cpu/arm_cortexa8/mx51/timer.c | 122 +++++++++++++
cpu/arm_cortexa8/mx51/u-boot.lds | 61 +++++++
7 files changed, 1116 insertions(+), 0 deletions(-)
create mode 100644 cpu/arm_cortexa8/mx51/Makefile
create mode 100644 cpu/arm_cortexa8/mx51/clock.c
create mode 100644 cpu/arm_cortexa8/mx51/iomux.c
create mode 100644 cpu/arm_cortexa8/mx51/lowlevel_init.S
create mode 100644 cpu/arm_cortexa8/mx51/soc.c
create mode 100644 cpu/arm_cortexa8/mx51/timer.c
create mode 100644 cpu/arm_cortexa8/mx51/u-boot.lds
diff --git a/cpu/arm_cortexa8/mx51/Makefile b/cpu/arm_cortexa8/mx51/Makefile
new file mode 100644
index 0000000..4d82293
--- /dev/null
+++ b/cpu/arm_cortexa8/mx51/Makefile
@@ -0,0 +1,48 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# (C) Copyright 2009 Freescale Semiconductor, Inc.
+#
+# 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 $(TOPDIR)/config.mk
+
+LIB = $(obj)lib$(SOC).a
+
+COBJS = soc.o clock.o iomux.o timer.o
+SOBJS = lowlevel_init.o
+
+SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
+
+all: $(obj).depend $(LIB)
+
+$(LIB): $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/cpu/arm_cortexa8/mx51/clock.c b/cpu/arm_cortexa8/mx51/clock.c
new file mode 100644
index 0000000..763c994
--- /dev/null
+++ b/cpu/arm_cortexa8/mx51/clock.c
@@ -0,0 +1,282 @@
+/*
+ * (C) Copyright 2007
+ * Sascha Hauer, Pengutronix
+ *
+ * (C) Copyright 2009 Freescale Semiconductor, Inc.
+ *
+ * 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 <asm/io.h>
+#include <asm/errno.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/crm_regs.h>
+
+enum pll_clocks {
+ PLL1_CLOCK = 0,
+ PLL2_CLOCK,
+ PLL3_CLOCK,
+ PLL_CLOCKS,
+};
+
+struct mxc_pll_reg *mxc_plls[PLL_CLOCKS] = {
+ [PLL1_CLOCK] = (struct mxc_pll_reg *)PLL1_BASE_ADDR,
+ [PLL2_CLOCK] = (struct mxc_pll_reg *)PLL2_BASE_ADDR,
+ [PLL3_CLOCK] = (struct mxc_pll_reg *)PLL3_BASE_ADDR,
+};
+
+struct mxc_ccm_reg *mxc_ccm = MXC_CCM_BASE;
+
+/*
+ * Calculate the frequence of this pll.
+ */
+static u32 decode_pll(struct mxc_pll_reg *pll, u32 infreq)
+{
+ u32 mfi, mfn, mfd, pd;
+
+ mfn = __raw_readl(&pll->mfn);
+ mfd = __raw_readl(&pll->mfd) + 1;
+ mfi = __raw_readl(&pll->op);
+ pd = (mfi & 0xF) + 1;
+ mfi = (mfi >> 4) & 0xF;
+ mfi = (mfi >= 5) ? mfi : 5;
+
+ return ((4 * (infreq / 1000) * (mfi * mfd + mfn)) / (mfd * pd)) * 1000;
+}
+
+/*
+ * Get mcu main rate
+ */
+u32 get_mcu_main_clk(void)
+{
+ u32 reg, freq;
+
+ reg = (__raw_readl(&mxc_ccm->cacrr) & MXC_CCM_CACRR_ARM_PODF_MASK) >>
+ MXC_CCM_CACRR_ARM_PODF_OFFSET;
+ freq = decode_pll(mxc_plls[PLL1_CLOCK], CONFIG_MX51_HCLK_FREQ);
+ return freq / (reg + 1);
+}
+
+/*
+ * Get the rate of peripheral's root clock.
+ */
+static u32 get_periph_clk(void)
+{
+ u32 reg;
+
+ reg = __raw_readl(&mxc_ccm->cbcdr);
+ if (!(reg & MXC_CCM_CBCDR_PERIPH_CLK_SEL))
+ return decode_pll(mxc_plls[PLL2_CLOCK], CONFIG_MX51_HCLK_FREQ);
+ reg = __raw_readl(&mxc_ccm->cbcmr);
+ switch ((reg & MXC_CCM_CBCMR_PERIPH_CLK_SEL_MASK) >>
+ MXC_CCM_CBCMR_PERIPH_CLK_SEL_OFFSET) {
+ case 0:
+ return decode_pll(mxc_plls[PLL1_CLOCK], CONFIG_MX51_HCLK_FREQ);
+ case 1:
+ return decode_pll(mxc_plls[PLL3_CLOCK], CONFIG_MX51_HCLK_FREQ);
+ default:
+ return 0;
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * Get the rate of ipg clock.
+ */
+static u32 get_ipg_clk(void)
+{
+ u32 ahb_podf, ipg_podf;
+
+ ahb_podf = __raw_readl(&mxc_ccm->cbcdr);
+ ipg_podf = (ahb_podf & MXC_CCM_CBCDR_IPG_PODF_MASK) >>
+ MXC_CCM_CBCDR_IPG_PODF_OFFSET;
+ ahb_podf = (ahb_podf & MXC_CCM_CBCDR_AHB_PODF_MASK) >>
+ MXC_CCM_CBCDR_AHB_PODF_OFFSET;
+ return get_periph_clk() / ((ahb_podf + 1) * (ipg_podf + 1));
+}
+
+/*
+ * Get the rate of ipg_per clock.
+ */
+static u32 get_ipg_per_clk(void)
+{
+ u32 pred1, pred2, podf;
+
+ if (__raw_readl(&mxc_ccm->cbcmr) & MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL)
+ return get_ipg_clk();
+ /* Fixme: not handle what about lpm*/
+ podf = __raw_readl(&mxc_ccm->cbcdr);
+ pred1 = (podf & MXC_CCM_CBCDR_PERCLK_PRED1_MASK) >>
+ MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET;
+ pred2 = (podf & MXC_CCM_CBCDR_PERCLK_PRED2_MASK) >>
+ MXC_CCM_CBCDR_PERCLK_PRED2_OFFSET;
+ podf = (podf & MXC_CCM_CBCDR_PERCLK_PODF_MASK) >>
+ MXC_CCM_CBCDR_PERCLK_PODF_OFFSET;
+
+ return get_periph_clk() / ((pred1 + 1) * (pred2 + 1) * (podf + 1));
+}
+
+/*
+ * Get the rate of uart clk.
+ */
+static u32 get_uart_clk(void)
+{
+ unsigned int freq, reg, pred, podf;
+
+ reg = __raw_readl(&mxc_ccm->cscmr1);
+ switch ((reg & MXC_CCM_CSCMR1_UART_CLK_SEL_MASK) >>
+ MXC_CCM_CSCMR1_UART_CLK_SEL_OFFSET) {
+ case 0x0:
+ freq = decode_pll(mxc_plls[PLL1_CLOCK],
+ CONFIG_MX51_HCLK_FREQ);
+ break;
+ case 0x1:
+ freq = decode_pll(mxc_plls[PLL2_CLOCK],
+ CONFIG_MX51_HCLK_FREQ);
+ break;
+ case 0x2:
+ freq = decode_pll(mxc_plls[PLL3_CLOCK],
+ CONFIG_MX51_HCLK_FREQ);
+ break;
+ default:
+ return 66500000;
+ }
+
+ reg = __raw_readl(&mxc_ccm->cscdr1);
+
+ pred = (reg & MXC_CCM_CSCDR1_UART_CLK_PRED_MASK) >>
+ MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET;
+
+ podf = (reg & MXC_CCM_CSCDR1_UART_CLK_PODF_MASK) >>
+ MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET;
+ freq /= (pred + 1) * (podf + 1);
+
+ return freq;
+}
+
+/*
+ * This function returns the low power audio clock.
+ */
+u32 get_lp_apm(void)
+{
+ u32 ret_val = 0;
+ u32 ccsr = __raw_readl(&mxc_ccm->ccsr);
+
+ if (((ccsr >> 9) & 1) == 0)
+ ret_val = CONFIG_MX51_HCLK_FREQ;
+ else
+ ret_val = ((32768 * 1024));
+
+ return ret_val;
+}
+
+/*
+ * get cspi clock rate.
+ */
+static u32 get_cspi_clk(void)
+{
+ u32 ret_val = 0, pdf, pre_pdf, clk_sel;
+ u32 cscmr1 = __raw_readl(&mxc_ccm->cscmr1);
+ u32 cscdr2 = __raw_readl(&mxc_ccm->cscdr2);
+
+ pre_pdf = (cscdr2 & MXC_CCM_CSCDR2_CSPI_CLK_PRED_MASK) \
+ >> MXC_CCM_CSCDR2_CSPI_CLK_PRED_OFFSET;
+ pdf = (cscdr2 & MXC_CCM_CSCDR2_CSPI_CLK_PODF_MASK) \
+ >> MXC_CCM_CSCDR2_CSPI_CLK_PODF_OFFSET;
+ clk_sel = (cscmr1 & MXC_CCM_CSCMR1_CSPI_CLK_SEL_MASK) \
+ >> MXC_CCM_CSCMR1_CSPI_CLK_SEL_OFFSET;
+
+ switch (clk_sel) {
+ case 0:
+ ret_val = decode_pll(mxc_plls[PLL1_CLOCK],
+ CONFIG_MX51_HCLK_FREQ) /
+ ((pre_pdf + 1) * (pdf + 1));
+ break;
+ case 1:
+ ret_val = decode_pll(mxc_plls[PLL2_CLOCK],
+ CONFIG_MX51_HCLK_FREQ) /
+ ((pre_pdf + 1) * (pdf + 1));
+ break;
+ case 2:
+ ret_val = decode_pll(mxc_plls[PLL3_CLOCK],
+ CONFIG_MX51_HCLK_FREQ) /
+ ((pre_pdf + 1) * (pdf + 1));
+ break;
+ default:
+ ret_val = get_lp_apm() / ((pre_pdf + 1) * (pdf + 1));
+ break;
+ }
+
+ return ret_val;
+}
+
+/*
+ * The API of get mxc clockes.
+ */
+unsigned int mxc_get_clock(enum mxc_clock clk)
+{
+ switch (clk) {
+ case MXC_ARM_CLK:
+ return get_mcu_main_clk();
+ case MXC_AHB_CLK:
+ break;
+ case MXC_IPG_CLK:
+ return get_ipg_clk();
+ case MXC_IPG_PERCLK:
+ return get_ipg_per_clk();
+ case MXC_UART_CLK:
+ return get_uart_clk();
+ case MXC_CSPI_CLK:
+ return get_cspi_clk();
+ case MXC_FEC_CLK:
+ return decode_pll(mxc_plls[PLL1_CLOCK],
+ CONFIG_MX51_HCLK_FREQ);
+ default:
+ break;
+ }
+ return -1;
+}
+
+/*
+ * Dump some core clockes.
+ */
+int do_mx51_showclocks (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ u32 freq;
+
+ freq = decode_pll(mxc_plls[PLL1_CLOCK], CONFIG_MX51_HCLK_FREQ);
+ printf("mx51 pll1: %dMHz\n", freq / 1000000);
+ freq = decode_pll(mxc_plls[PLL2_CLOCK], CONFIG_MX51_HCLK_FREQ);
+ printf("mx51 pll2: %dMHz\n", freq / 1000000);
+ freq = decode_pll(mxc_plls[PLL3_CLOCK], CONFIG_MX51_HCLK_FREQ);
+ printf("mx51 pll3: %dMHz\n", freq / 1000000);
+ printf("ipg clock : %dHz\n", mxc_get_clock(MXC_IPG_CLK));
+ printf("ipg per clock : %dHz\n", mxc_get_clock(MXC_IPG_PERCLK));
+
+ return 0;
+}
+
+/***************************************************/
+
+U_BOOT_CMD(
+ mx51clocks, CONFIG_SYS_MAXARGS, 1, do_mx51_showclocks,
+ "display mx51 clocks\n",
+ ""
+);
diff --git a/cpu/arm_cortexa8/mx51/iomux.c b/cpu/arm_cortexa8/mx51/iomux.c
new file mode 100644
index 0000000..a42ec3a
--- /dev/null
+++ b/cpu/arm_cortexa8/mx51/iomux.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @defgroup GPIO_MX51 Board GPIO and Muxing Setup
+ * @ingroup MSL_MX51
+ */
+/*!
+ * @file mach-mx51/iomux.c
+ *
+ * @brief I/O Muxing control functions
+ *
+ * @ingroup GPIO_MX51
+ */
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/mx51_pins.h>
+#include <asm/arch/iomux.h>
+
+/*!
+ * IOMUX register (base) addresses
+ */
+enum iomux_reg_addr {
+ IOMUXGPR0 = IOMUXC_BASE_ADDR,
+ IOMUXGPR1 = IOMUXC_BASE_ADDR + 0x004,
+ IOMUXSW_MUX_CTL = IOMUXC_BASE_ADDR,
+ IOMUXSW_MUX_END = IOMUXC_BASE_ADDR + MUX_I_END,
+ IOMUXSW_PAD_CTL = IOMUXC_BASE_ADDR + PAD_I_START,
+ IOMUXSW_INPUT_CTL = IOMUXC_BASE_ADDR,
+};
+
+#define MUX_PIN_NUM_MAX (((MUX_I_END - MUX_I_START) >> 2) + 1)
+
+/* Get the iomux register address of this pin */
+static inline u32 get_mux_reg(iomux_pin_name_t pin)
+{
+ u32 mux_reg = PIN_TO_IOMUX_MUX(pin);
+
+ if (is_soc_rev(CHIP_REV_2_0) < 0) {
+ /*
+ * Fixup register address:
+ * i.MX51 TO1 has offset with the register
+ * which is define as TO2.
+ */
+ if ((pin == MX51_PIN_NANDF_RB5) ||
+ (pin == MX51_PIN_NANDF_RB6) ||
+ (pin == MX51_PIN_NANDF_RB7))
+ ; /* Do nothing */
+ else if (mux_reg >= 0x2FC)
+ mux_reg += 8;
+ else if (mux_reg >= 0x130)
+ mux_reg += 0xC;
+ }
+ mux_reg += IOMUXSW_MUX_CTL;
+ return mux_reg;
+}
+
+/* Get the pad register address of this pin */
+static inline u32 get_pad_reg(iomux_pin_name_t pin)
+{
+ u32 pad_reg = PIN_TO_IOMUX_PAD(pin);
+
+ if (is_soc_rev(CHIP_REV_2_0) < 0) {
+ /*
+ * Fixup register address:
+ * i.MX51 TO1 has offset with the register
+ * which is define as TO2.
+ */
+ if ((pin == MX51_PIN_NANDF_RB5) ||
+ (pin == MX51_PIN_NANDF_RB6) ||
+ (pin == MX51_PIN_NANDF_RB7))
+ ; /* Do nothing */
+ else if (pad_reg == 0x4D0 - PAD_I_START)
+ pad_reg += 0x4C;
+ else if (pad_reg == 0x860 - PAD_I_START)
+ pad_reg += 0x9C;
+ else if (pad_reg >= 0x804 - PAD_I_START)
+ pad_reg += 0xB0;
+ else if (pad_reg >= 0x7FC - PAD_I_START)
+ pad_reg += 0xB4;
+ else if (pad_reg >= 0x4E4 - PAD_I_START)
+ pad_reg += 0xCC;
+ else
+ pad_reg += 8;
+ }
+ pad_reg += IOMUXSW_PAD_CTL;
+ return pad_reg;
+}
+
+/* Get the last iomux register address */
+static inline u32 get_mux_end(void)
+{
+ if (is_soc_rev(CHIP_REV_2_0) < 0)
+ return IOMUXC_BASE_ADDR + (0x3F8 - 4);
+ else
+ return IOMUXC_BASE_ADDR + (0x3F0 - 4);
+}
+
+/*!
+ * This function is used to configure a pin through the IOMUX module.
+ * @param pin a pin number as defined in \b #iomux_pin_name_t
+ * @param cfg an output function as defined in \b #iomux_pin_cfg_t
+ *
+ * @return 0 if successful; Non-zero otherwise
+ */
+static void iomux_config_mux(iomux_pin_name_t pin, iomux_pin_cfg_t cfg)
+{
+ u32 mux_reg = get_mux_reg(pin);
+
+ if ((mux_reg > get_mux_end()) || (mux_reg < IOMUXSW_MUX_CTL))
+ return ;
+ if (cfg == IOMUX_CONFIG_GPIO)
+ writel(PIN_TO_ALT_GPIO(pin), mux_reg);
+ else
+ writel(cfg, mux_reg);
+}
+
+/*!
+ * Request ownership for an IO pin. This function has to be the first one
+ * being called before that pin is used. The caller has to check the
+ * return value to make sure it returns 0.
+ *
+ * @param pin a name defined by \b iomux_pin_name_t
+ * @param cfg an input function as defined in \b #iomux_pin_cfg_t
+ *
+ */
+void mxc_request_iomux(iomux_pin_name_t pin, iomux_pin_cfg_t cfg)
+{
+ iomux_config_mux(pin, cfg);
+}
+
+/*!
+ * Release ownership for an IO pin
+ *
+ * @param pin a name defined by \b iomux_pin_name_t
+ * @param cfg an input function as defined in \b #iomux_pin_cfg_t
+ */
+void mxc_free_iomux(iomux_pin_name_t pin, iomux_pin_cfg_t cfg)
+{
+}
+
+/*!
+ * This function configures the pad value for a IOMUX pin.
+ *
+ * @param pin a pin number as defined in \b #iomux_pin_name_t
+ * @param config the ORed value of elements defined in \b #iomux_pad_config_t
+ */
+void mxc_iomux_set_pad(iomux_pin_name_t pin, u32 config)
+{
+ u32 pad_reg = get_pad_reg(pin);
+ writel(config, pad_reg);
+}
+
+unsigned int mxc_iomux_get_pad(iomux_pin_name_t pin)
+{
+ u32 pad_reg = get_pad_reg(pin);
+ return readl(pad_reg);
+}
+/*!
+ * This function configures input path.
+ *
+ * @param input index of input select register as defined in \b
+ * #iomux_input_select_t
+ * @param config the binary value of elements defined in \b
+ * #iomux_input_config_t
+ */
+void mxc_iomux_set_input(iomux_input_select_t input, u32 config)
+{
+ u32 reg;
+
+ if (is_soc_rev(CHIP_REV_2_0) < 0) {
+ if (input == MUX_IN_IPU_IPP_DI_0_IND_DISPB_SD_D_SELECT_INPUT)
+ input -= 4;
+ else if (input ==
+ MUX_IN_IPU_IPP_DI_1_IND_DISPB_SD_D_SELECT_INPUT)
+ input -= 3;
+ else if (input >= MUX_IN_KPP_IPP_IND_COL_6_SELECT_INPUT)
+ input -= 2;
+ else if (input >=
+ MUX_IN_HSC_MIPI_MIX_PAR_SISG_TRIG_SELECT_INPUT)
+ input -= 5;
+ else if (input >=
+ MUX_IN_HSC_MIPI_MIX_IPP_IND_SENS1_DATA_EN_SELECT_INPUT)
+ input -= 3;
+ else if (input >= MUX_IN_ECSPI2_IPP_IND_SS_B_3_SELECT_INPUT)
+ input -= 2;
+ else if (input >= MUX_IN_CCM_PLL1_BYPASS_CLK_SELECT_INPUT)
+ input -= 1;
+ reg = IOMUXSW_INPUT_CTL + (input << 2) + INPUT_CTL_START_TO1;
+ } else
+ reg = IOMUXSW_INPUT_CTL + (input << 2) + INPUT_CTL_START;
+
+ writel(config, reg);
+}
diff --git a/cpu/arm_cortexa8/mx51/lowlevel_init.S b/cpu/arm_cortexa8/mx51/lowlevel_init.S
new file mode 100644
index 0000000..843a7b8
--- /dev/null
+++ b/cpu/arm_cortexa8/mx51/lowlevel_init.S
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2007, Guennadi Liakhovetski <lg at denx.de>
+ *
+ * (C) Copyright 2009 Freescale Semiconductor, Inc.
+ *
+ * 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 <config.h>
+#include <asm/arch/imx-regs.h>
+
+/*
+ * return soc version
+ * 0x10: TO1
+ * 0x20: TO2
+ * 0x30: TO3
+ */
+.macro check_soc_version ret, tmp
+.endm
+
+/*
+ * L2CC Cache setup/invalidation/disable
+ */
+.macro init_l2cc
+ /* explicitly disable L2 cache */
+ mrc 15, 0, r0, c1, c0, 1
+ bic r0, r0, #0x2
+ mcr 15, 0, r0, c1, c0, 1
+
+ /* reconfigure L2 cache aux control reg */
+ mov r0, #0xC0 /* tag RAM */
+ add r0, r0, #0x4 /* data RAM */
+ orr r0, r0, #(1 << 24) /* disable write allocate delay */
+ orr r0, r0, #(1 << 23) /* disable write allocate combine */
+ orr r0, r0, #(1 << 22) /* disable write allocate */
+
+ cmp r3, #0x10 /* r3 contains the silicon rev */
+ orrls r0, r0, #(1 << 25) /* disable write combine for TO 2 and lower revs */
+
+ mcr 15, 1, r0, c9, c0, 2
+.endm /* init_l2cc */
+
+/* AIPS setup - Only setup MPROTx registers.
+ * The PACR default values are good.*/
+.macro init_aips
+ /*
+ * Set all MPROTx to be non-bufferable, trusted for R/W,
+ * not forced to user-mode.
+ */
+ ldr r0, =AIPS1_BASE_ADDR
+ ldr r1, =0x77777777
+ str r1, [r0, #0x0]
+ str r1, [r0, #0x4]
+ ldr r0, =AIPS2_BASE_ADDR
+ str r1, [r0, #0x0]
+ str r1, [r0, #0x4]
+ /*
+ * Clear the on and off peripheral modules Supervisor Protect bit
+ * for SDMA to access them. Did not change the AIPS control registers
+ * (offset 0x20) access type
+ */
+.endm /* init_aips */
+
+/* MAX (Multi-Layer AHB Crossbar Switch) setup */
+.macro init_max
+.endm /* init_max */
+
+/* M4IF setup */
+.macro init_m4if
+ /* VPU and IPU given higher priority (0x4)
+ * IPU accesses with ID=0x1 given highest priority (=0xA)
+ */
+ ldr r0, =M4IF_BASE_ADDR
+
+ ldr r1, =0x00000203
+ str r1, [r0, #0x40]
+
+ ldr r1, =0x0
+ str r1, [r0, #0x44]
+
+ ldr r1, =0x00120125
+ str r1, [r0, #0x9C]
+
+ ldr r1, =0x001901A3
+ str r1, [r0, #0x48]
+
+/*
+ ldr r1, =0x00000a01
+ str r1, [r0, #0x48]
+ ldr r1, =0x00000404
+ str r1, [r0, #0x40]
+*/
+.endm /* init_m4if */
+
+/* To support 133MHz DDR */
+.macro init_drive_strength
+.endm /* init_drive_strength */
+
+/* CPLD on CS5 setup */
+.macro init_debug_board
+.endm /* init_debug_board */
+
+.macro setup_pll pll, freq
+ ldr r2, =\pll
+ ldr r1, =0x00001232
+ str r1, [r2, #PLL_DP_CTL] /* Set DPLL ON (set UPEN bit): BRMO=1 */
+ mov r1, #0x2
+ str r1, [r2, #PLL_DP_CONFIG] /* Enable auto-restart AREN bit */
+
+ str r3, [r2, #PLL_DP_OP]
+ str r3, [r2, #PLL_DP_HFS_OP]
+
+ str r4, [r2, #PLL_DP_MFD]
+ str r4, [r2, #PLL_DP_HFS_MFD]
+
+ str r5, [r2, #PLL_DP_MFN]
+ str r5, [r2, #PLL_DP_HFS_MFN]
+
+ ldr r1, =0x00001232
+ str r1, [r2, #PLL_DP_CTL]
+1: ldr r1, [r2, #PLL_DP_CTL]
+ ands r1, r1, #0x1
+ beq 1b
+.endm
+
+.macro init_clock
+ ldr r0, =CCM_BASE_ADDR
+
+ /* Gate of clocks to the peripherals first */
+ ldr r1, =0x3FFFFFFF
+ str r1, [r0, #CLKCTL_CCGR0]
+ ldr r1, =0x0
+ str r1, [r0, #CLKCTL_CCGR1]
+ str r1, [r0, #CLKCTL_CCGR2]
+ str r1, [r0, #CLKCTL_CCGR3]
+
+ ldr r1, =0x00030000
+ str r1, [r0, #CLKCTL_CCGR4]
+ ldr r1, =0x00FFF030
+ str r1, [r0, #CLKCTL_CCGR5]
+ ldr r1, =0x00000300
+ str r1, [r0, #CLKCTL_CCGR6]
+
+ /* Disable IPU and HSC dividers */
+ mov r1, #0x60000
+ str r1, [r0, #CLKCTL_CCDR]
+
+ /* Make sure to switch the DDR away from PLL 1 */
+ ldr r1, =0x19239145
+ str r1, [r0, #CLKCTL_CBCDR]
+ /* make sure divider effective */
+1: ldr r1, [r0, #CLKCTL_CDHIPR]
+ cmp r1, #0x0
+ bne 1b
+
+ /* Switch ARM to step clock */
+ mov r1, #0x4
+ str r1, [r0, #CLKCTL_CCSR]
+ mov r3, #DP_OP_800
+ mov r4, #DP_MFD_800
+ mov r5, #DP_MFN_800
+ setup_pll PLL1_BASE_ADDR
+
+ mov r3, #DP_OP_665
+ mov r4, #DP_MFD_665
+ mov r5, #DP_MFN_665
+ setup_pll PLL3_BASE_ADDR
+
+ /* Switch peripheral to PLL 3 */
+ ldr r0, =CCM_BASE_ADDR
+ ldr r1, =0x000010C0
+ str r1, [r0, #CLKCTL_CBCMR]
+ ldr r1, =0x13239145
+ str r1, [r0, #CLKCTL_CBCDR]
+ mov r3, #DP_OP_665
+ mov r4, #DP_MFD_665
+ mov r5, #DP_MFN_665
+ setup_pll PLL2_BASE_ADDR
+
+ /* Switch peripheral to PLL2 */
+ ldr r0, =CCM_BASE_ADDR
+ ldr r1, =0x19239145
+ str r1, [r0, #CLKCTL_CBCDR]
+ ldr r1, =0x000020C0
+ str r1, [r0, #CLKCTL_CBCMR]
+
+ mov r3, #DP_OP_216
+ mov r4, #DP_MFD_216
+ mov r5, #DP_MFN_216
+ setup_pll PLL3_BASE_ADDR
+
+
+ /* Set the platform clock dividers */
+ ldr r0, =ARM_BASE_ADDR
+ ldr r1, =0x00000725
+ str r1, [r0, #0x14]
+
+ ldr r0, =CCM_BASE_ADDR
+ /* Run TO 3.0 at Full speed, for other TO's wait till we increase VDDGP */
+ ldr r1, =0x0
+ ldr r3, [r1, #ROM_SI_REV]
+ cmp r3, #0x10
+ movls r1, #0x1
+ movhi r1, #0
+ str r1, [r0, #CLKCTL_CACRR]
+
+ /* Switch ARM back to PLL 1 */
+ mov r1, #0
+ str r1, [r0, #CLKCTL_CCSR]
+
+ /* setup the rest */
+ /* Use lp_apm (24MHz) source for perclk */
+ ldr r1, =0x000020C2
+ str r1, [r0, #CLKCTL_CBCMR]
+ /* ddr clock from PLL 1, all perclk dividers are 1 since using 24MHz */
+ ldr r1, =0x59E35100
+ str r1, [r0, #CLKCTL_CBCDR]
+
+ /* Restore the default values in the Gate registers */
+ ldr r1, =0xFFFFFFFF
+ str r1, [r0, #CLKCTL_CCGR0]
+ str r1, [r0, #CLKCTL_CCGR1]
+ str r1, [r0, #CLKCTL_CCGR2]
+ str r1, [r0, #CLKCTL_CCGR3]
+ str r1, [r0, #CLKCTL_CCGR4]
+ str r1, [r0, #CLKCTL_CCGR5]
+ str r1, [r0, #CLKCTL_CCGR6]
+
+ /* Use PLL 2 for UART's, get 66.5MHz from it */
+ ldr r1, =0xA5A2A020
+ str r1, [r0, #CLKCTL_CSCMR1]
+ ldr r1, =0x00C30321
+ str r1, [r0, #CLKCTL_CSCDR1]
+
+ /* make sure divider effective */
+1: ldr r1, [r0, #CLKCTL_CDHIPR]
+ cmp r1, #0x0
+ bne 1b
+
+ mov r1, #0x0
+ str r1, [r0, #CLKCTL_CCDR]
+
+ /* for cko - for ARM div by 8 */
+ mov r1, #0x000A0000
+ add r1, r1, #0x00000F0
+ str r1, [r0, #CLKCTL_CCOSR]
+.endm
+
+.macro setup_wdog
+ ldr r0, =WDOG1_BASE_ADDR
+ mov r1, #0x30
+ strh r1, [r0]
+.endm
+
+.section ".text.init", "x"
+
+.globl lowlevel_init
+lowlevel_init:
+ ldr r0, =GPIO1_BASE_ADDR
+ ldr r1, [r0, #0x0]
+ orr r1, r1, #(1 << 23)
+ str r1, [r0, #0x0]
+ ldr r1, [r0, #0x4]
+ orr r1, r1, #(1 << 23)
+ str r1, [r0, #0x4]
+
+#ifdef ENABLE_IMPRECISE_ABORT
+ mrs r1, spsr /* save old spsr */
+ mrs r0, cpsr /* read out the cpsr */
+ bic r0, r0, #0x100 /* clear the A bit */
+ msr spsr, r0 /* update spsr */
+ add lr, pc, #0x8 /* update lr */
+ movs pc, lr /* update cpsr */
+ nop
+ nop
+ nop
+ nop
+ msr spsr, r1 /* restore old spsr */
+#endif
+
+ init_l2cc
+
+ init_aips
+
+ init_max
+
+ init_m4if
+
+ init_drive_strength
+
+ init_clock
+
+ init_debug_board
+
+ /* return from mxc_nand_load */
+ /* r12 saved upper lr*/
+ mov pc,lr
+
+/* b mxc_nand_load */
+
+/* Board level setting value */
+DDR_PERCHARGE_CMD: .word 0x04008008
+DDR_REFRESH_CMD: .word 0x00008010
+DDR_LMR1_W: .word 0x00338018
+DDR_LMR_CMD: .word 0xB2220000
+DDR_TIMING_W: .word 0xB02567A9
+DDR_MISC_W: .word 0x000A0104
diff --git a/cpu/arm_cortexa8/mx51/soc.c b/cpu/arm_cortexa8/mx51/soc.c
new file mode 100644
index 0000000..e91e72a
--- /dev/null
+++ b/cpu/arm_cortexa8/mx51/soc.c
@@ -0,0 +1,78 @@
+/*
+ * (C) Copyright 2007
+ * Sascha Hauer, Pengutronix
+ *
+ * (C) Copyright 2009 Freescale Semiconductor, Inc.
+ *
+ * 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 <asm/arch/imx-regs.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+
+#if defined(CONFIG_DISPLAY_CPUINFO)
+int print_cpuinfo(void)
+{
+ printf("CPU: Freescale i.MX51 family %d.%dV at %d MHz\n",
+ (get_board_rev() & 0xFF) >> 4,
+ (get_board_rev() & 0xF),
+ get_mcu_main_clk() / 1000000);
+ return 0;
+}
+#endif
+
+/*
+ * Initializes on-chip ethernet controllers.
+ * to override, implement board_eth_init()
+ */
+#if defined(CONFIG_MXC_FEC)
+extern int mxc_fec_initialize(bd_t *bis);
+#endif
+
+int cpu_eth_init(bd_t *bis)
+{
+ int rc = -ENODEV;
+
+#if defined(CONFIG_MXC_FEC)
+ rc = mxc_fec_initialize(bis);
+#endif
+
+ return rc;
+}
+
+/*
+ * Initializes on-chip MMC controllers.
+ * to override, implement board_mmc_init()
+ */
+int cpu_mmc_init(bd_t *bis)
+{
+#ifdef CONFIG_FSL_ESDHC
+ return fsl_esdhc_mmc_init(bis);
+#else
+ return 0;
+#endif
+}
+
+
+void reset_cpu(ulong addr)
+{
+ __raw_writew(4, WDOG1_BASE_ADDR);
+}
diff --git a/cpu/arm_cortexa8/mx51/timer.c b/cpu/arm_cortexa8/mx51/timer.c
new file mode 100644
index 0000000..0937998
--- /dev/null
+++ b/cpu/arm_cortexa8/mx51/timer.c
@@ -0,0 +1,122 @@
+/*
+ * (C) Copyright 2007
+ * Sascha Hauer, Pengutronix
+ *
+ * (C) Copyright 2009 Freescale Semiconductor, Inc.
+ *
+ * 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 <asm/io.h>
+#include <asm/arch/imx-regs.h>
+
+/* General purpose timers registers */
+struct mxc_gpt {
+ unsigned int control;
+ unsigned int prescaler;
+ unsigned int status;
+ unsigned int nouse[6];
+ unsigned int counter;
+};
+
+static struct mxc_gpt *cur_gpt = (struct mxc_gpt *)GPT1_BASE_ADDR;
+
+/* General purpose timers bitfields */
+#define GPTCR_SWR (1<<15) /* Software reset */
+#define GPTCR_FRR (1<<9) /* Freerun / restart */
+#define GPTCR_CLKSOURCE_32 (4<<6) /* Clock source */
+#define GPTCR_TEN (1) /* Timer enable */
+
+static ulong timestamp;
+static ulong lastinc;
+
+int timer_init(void)
+{
+ int i;
+
+ /* setup GP Timer 1 */
+ __raw_writel(GPTCR_SWR, &cur_gpt->control);
+
+ /* We have no udelay by now */
+ for (i = 0; i < 100; i++)
+ __raw_writel(0, &cur_gpt->control);
+
+ __raw_writel(0, &cur_gpt->prescaler); /* 32Khz */
+
+ /* Freerun Mode, PERCLK1 input */
+ i = __raw_readl(&cur_gpt->control);
+ __raw_writel(i | GPTCR_CLKSOURCE_32 | GPTCR_TEN, &cur_gpt->control);
+ reset_timer_masked();
+ return 0;
+}
+
+void reset_timer(void)
+{
+ reset_timer_masked();
+}
+
+void reset_timer_masked(void)
+{
+ ulong val = __raw_readl(&cur_gpt->counter);
+ lastinc = val / (CONFIG_MX51_CLK32 / CONFIG_SYS_HZ);
+ timestamp = 0;
+}
+
+ulong get_timer_masked(void)
+{
+ ulong val = __raw_readl(&cur_gpt->counter);
+ val /= (CONFIG_MX51_CLK32 / CONFIG_SYS_HZ);
+ if (val >= lastinc)
+ timestamp += (val - lastinc);
+ else
+ timestamp += ((0xFFFFFFFF / (CONFIG_MX51_CLK32 / CONFIG_SYS_HZ))
+ - lastinc) + val;
+ lastinc = val;
+ return val;
+}
+
+ulong get_timer(ulong base)
+{
+ return get_timer_masked() - base;
+}
+
+void set_timer(ulong t)
+{
+ timestamp = t;
+}
+
+/* delay x useconds AND perserve advance timstamp value */
+void __udelay(unsigned long usec)
+{
+ unsigned long now, last = readl(&cur_gpt->counter);
+ long tmo = usec * (CONFIG_MX51_CLK32 / 1000) / 1000;
+
+ if (!tmo)
+ tmo = 1;
+
+ while (tmo > 0) {
+ now = readl(&cur_gpt->counter);
+ if (last > now)
+ tmo -= 0xFFFFFFFF - last + now;
+ else
+ tmo -= now - last;
+ last = now;
+ }
+}
diff --git a/cpu/arm_cortexa8/mx51/u-boot.lds b/cpu/arm_cortexa8/mx51/u-boot.lds
new file mode 100644
index 0000000..84c173a
--- /dev/null
+++ b/cpu/arm_cortexa8/mx51/u-boot.lds
@@ -0,0 +1,61 @@
+/*
+ * January 2004 - Changed to support H4 device
+ * Copyright (c) 2004 Texas Instruments
+ *
+ * (C) Copyright 2002
+ * Gary Jennejohn, DENX Software Engineering, <gj at denx.de>
+ *
+ * (C) Copyright 2009 Freescale Semiconductor, Inc.
+ *
+ * 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
+ */
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+ . = 0x00000000;
+
+ . = ALIGN(4);
+ .text :
+ {
+ cpu/arm_cortexa8/start.o
+ *(.text)
+ }
+
+ . = ALIGN(4);
+ .rodata : { *(.rodata) }
+
+ . = ALIGN(4);
+ .data : { *(.data) }
+
+ . = ALIGN(4);
+ .got : { *(.got) }
+
+ . = .;
+ __u_boot_cmd_start = .;
+ .u_boot_cmd : { *(.u_boot_cmd) }
+ __u_boot_cmd_end = .;
+
+ . = ALIGN(4);
+ __bss_start = .;
+ .bss : { *(.bss) }
+ _end = .;
+}
--
1.6.3.3
More information about the U-Boot
mailing list