X-Git-Url: https://git.kernelconcepts.de/?p=karo-tx-uboot.git;a=blobdiff_plain;f=arch%2Farm%2Fcpu%2Farm926ejs%2Fmxs%2Fmxs.c;h=cc4122dc0da35b380cc2cdfaa2717ca79f03fa0b;hp=6ce8019b835ef832a2dfdab056f8bc7215b73aec;hb=d1b8c7a8b72fefa7d67dc42fbd20a9de147d8907;hpb=8f082d78fafd94db3f21b503794e0875d3331e53 diff --git a/arch/arm/cpu/arm926ejs/mxs/mxs.c b/arch/arm/cpu/arm926ejs/mxs/mxs.c index 6ce8019b83..cc4122dc0d 100644 --- a/arch/arm/cpu/arm926ejs/mxs/mxs.c +++ b/arch/arm/cpu/arm926ejs/mxs/mxs.c @@ -1,5 +1,5 @@ /* - * Freescale i.MX28 common code + * Freescale i.MX23/i.MX28 common code * * Copyright (C) 2011 Marek Vasut * on behalf of DENX Software Engineering GmbH @@ -7,45 +7,49 @@ * Based on code from LTIB: * Copyright (C) 2010 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 + * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include -#include +#include #include #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; -/* 1 second delay should be plenty of time for block reset. */ -#define RESET_MAX_TIMEOUT 1000000 +/* Lowlevel init isn't used on i.MX28, so just have a dummy here */ +void lowlevel_init(void) {} + +#define BOOT_CAUSE_MASK (RTC_PERSISTENT0_EXTERNAL_RESET | \ + RTC_PERSISTENT0_ALARM_WAKE | \ + RTC_PERSISTENT0_THERMAL_RESET) + +static int wait_rtc_stat(u32 mask) +{ + int timeout = 5000; + u32 val; + struct mxs_rtc_regs *rtc_regs = (void *)MXS_RTC_BASE; + u32 old_val = readl(&rtc_regs->hw_rtc_stat); -#define MXS_BLOCK_SFTRST (1 << 31) -#define MXS_BLOCK_CLKGATE (1 << 30) + debug("stat=%x\n", old_val); -/* Lowlevel init isn't used on i.MX28, so just have a dummy here */ -inline void lowlevel_init(void) {} + while ((val = readl(&rtc_regs->hw_rtc_stat)) & mask) { + if (val != old_val) { + old_val = val; + debug("stat: %x -> %x\n", old_val, val); + } + udelay(1); + if (timeout-- < 0) + break; + } + return !!(readl(&rtc_regs->hw_rtc_stat) & mask); +} void reset_cpu(ulong ignored) __attribute__((noreturn)); @@ -55,6 +59,7 @@ void reset_cpu(ulong ignored) (struct mxs_rtc_regs *)MXS_RTC_BASE; struct mxs_lcdif_regs *lcdif_regs = (struct mxs_lcdif_regs *)MXS_LCDIF_BASE; + u32 reg; /* * Shut down the LCD controller as it interferes with BootROM boot mode @@ -62,7 +67,13 @@ void reset_cpu(ulong ignored) */ writel(LCDIF_CTRL_RUN, &lcdif_regs->hw_lcdif_ctrl_clr); - /* Wait 1 uS before doing the actual watchdog reset */ + reg = readl(&rtc_regs->hw_rtc_persistent0); + if (reg & BOOT_CAUSE_MASK) { + writel(reg & ~BOOT_CAUSE_MASK, &rtc_regs->hw_rtc_persistent0); + wait_rtc_stat(RTC_STAT_NEW_REGS_PERSISTENT0); + } + + /* Wait 1 mS before doing the actual watchdog reset */ writel(1, &rtc_regs->hw_rtc_watchdog); writel(RTC_CTRL_WATCHDOGEN, &rtc_regs->hw_rtc_ctrl_set); @@ -81,70 +92,29 @@ void enable_caches(void) #endif } -int mxs_wait_mask_set(struct mxs_register_32 *reg, uint32_t mask, unsigned - int timeout) -{ - while (--timeout) { - if ((readl(®->reg) & mask) == mask) - break; - udelay(1); - } - - return !timeout; -} - -int mxs_wait_mask_clr(struct mxs_register_32 *reg, uint32_t mask, unsigned - int timeout) -{ - while (--timeout) { - if ((readl(®->reg) & mask) == 0) - break; - udelay(1); - } - - return !timeout; -} - -int mxs_reset_block(struct mxs_register_32 *reg) -{ - /* Clear SFTRST */ - writel(MXS_BLOCK_SFTRST, ®->reg_clr); - - if (mxs_wait_mask_clr(reg, MXS_BLOCK_SFTRST, RESET_MAX_TIMEOUT)) - return 1; - - /* Clear CLKGATE */ - writel(MXS_BLOCK_CLKGATE, ®->reg_clr); - - /* Set SFTRST */ - writel(MXS_BLOCK_SFTRST, ®->reg_set); - - /* Wait for CLKGATE being set */ - if (mxs_wait_mask_set(reg, MXS_BLOCK_CLKGATE, RESET_MAX_TIMEOUT)) - return 1; - - /* Clear SFTRST */ - writel(MXS_BLOCK_SFTRST, ®->reg_clr); - - if (mxs_wait_mask_clr(reg, MXS_BLOCK_SFTRST, RESET_MAX_TIMEOUT)) - return 1; - - /* Clear CLKGATE */ - writel(MXS_BLOCK_CLKGATE, ®->reg_clr); - - if (mxs_wait_mask_clr(reg, MXS_BLOCK_CLKGATE, RESET_MAX_TIMEOUT)) - return 1; - - return 0; -} - +/* + * This function will craft a jumptable at 0x0 which will redirect interrupt + * vectoring to proper location of U-Boot in RAM. + * + * The structure of the jumptable will be as follows: + * ldr pc, [pc, #0x18] ..... for each vector, thus repeated 8 times + * ... for each previous ldr, thus also repeated 8 times + * + * The "ldr pc, [pc, #0x18]" instruction above loads address from memory at + * offset 0x18 from current value of PC register. Note that PC is already + * incremented by 4 when computing the offset, so the effective offset is + * actually 0x20, this the associated . Loading the PC + * register with an address performs a jump to that address. + */ void mx28_fixup_vt(uint32_t start_addr) { + /* Jumptable location is 0x0 */ uint32_t *vt = (uint32_t *)0x20; - int i; + uint32_t cr = get_cr(); - for (i = 0; i < 8; i++) - vt[i] = start_addr + (4 * i); + /* cppcheck-suppress nullPointer */ + memcpy(vt, (void *)start_addr + 0x20, 32); + set_cr(cr & ~CR_V); } #ifdef CONFIG_ARCH_MISC_INIT @@ -155,6 +125,7 @@ int arch_misc_init(void) } #endif +#ifdef CONFIG_ARCH_CPU_INIT int arch_cpu_init(void) { struct mxs_clkctrl_regs *clkctrl_regs = @@ -188,6 +159,7 @@ int arch_cpu_init(void) return 0; } +#endif #if defined(CONFIG_DISPLAY_CPUINFO) static const char *get_cpu_type(void) @@ -196,6 +168,8 @@ static const char *get_cpu_type(void) (struct mxs_digctl_regs *)MXS_DIGCTL_BASE; switch (readl(&digctl_regs->hw_digctl_chipid) & HW_DIGCTL_CHIPID_MASK) { + case HW_DIGCTL_CHIPID_MX23: + return "23"; case HW_DIGCTL_CHIPID_MX28: return "28"; default: @@ -210,6 +184,21 @@ static const char *get_cpu_rev(void) uint8_t rev = readl(&digctl_regs->hw_digctl_chipid) & 0x000000FF; switch (readl(&digctl_regs->hw_digctl_chipid) & HW_DIGCTL_CHIPID_MASK) { + case HW_DIGCTL_CHIPID_MX23: + switch (rev) { + case 0x0: + return "1.0"; + case 0x1: + return "1.1"; + case 0x2: + return "1.2"; + case 0x3: + return "1.3"; + case 0x4: + return "1.4"; + default: + return "??"; + } case HW_DIGCTL_CHIPID_MX28: switch (rev) { case 0x1: @@ -236,19 +225,28 @@ int print_cpuinfo(void) } #endif +#define pr_clk(n, c) { \ + unsigned long clk = c; \ + printf("%-5s %3lu.%03lu MHz\n", #n ":", clk / 1000000, \ + clk / 1000 % 1000); \ +} + int do_mx28_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { - printf("CPU: %3d MHz\n", mxc_get_clock(MXC_ARM_CLK) / 1000000); - printf("BUS: %3d MHz\n", mxc_get_clock(MXC_AHB_CLK) / 1000000); - printf("EMI: %3d MHz\n", mxc_get_clock(MXC_EMI_CLK)); - printf("GPMI: %3d MHz\n", mxc_get_clock(MXC_GPMI_CLK) / 1000000); + pr_clk(CPU, mxc_get_clock(MXC_ARM_CLK)); + pr_clk(APBH, mxc_get_clock(MXC_AHB_CLK)); + pr_clk(APBX, mxc_get_clock(MXC_XBUS_CLK)); + pr_clk(IO0, mxc_get_clock(MXC_IO0_CLK) * 1000); + pr_clk(IO1, mxc_get_clock(MXC_IO1_CLK) * 1000); + pr_clk(EMI, mxc_get_clock(MXC_EMI_CLK) * 1000000); + pr_clk(GPMI, mxc_get_clock(MXC_GPMI_CLK)); return 0; } /* * Initializes on-chip ethernet controllers. */ -#if defined(CONFIG_MX28) && defined(CONFIG_CMD_NET) +#if defined(CONFIG_SOC_MX28) && defined(CONFIG_CMD_NET) int cpu_eth_init(bd_t *bis) { struct mxs_clkctrl_regs *clkctrl_regs = @@ -265,18 +263,22 @@ int cpu_eth_init(bd_t *bis) udelay(10); + /* + * Enable pad output; must be done BEFORE enabling PLL + * according to i.MX28 Ref. Manual Rev. 1, 2010 p. 883 + */ + setbits_le32(&clkctrl_regs->hw_clkctrl_enet, CLKCTRL_ENET_CLK_OUT_EN); + /* Gate on ENET PLL */ writel(CLKCTRL_PLL2CTRL0_CLKGATE, &clkctrl_regs->hw_clkctrl_pll2ctrl0_clr); - /* Enable pad output */ - setbits_le32(&clkctrl_regs->hw_clkctrl_enet, CLKCTRL_ENET_CLK_OUT_EN); - + udelay(6000); return 0; } #endif -static void __mx28_adjust_mac(int dev_id, unsigned char *mac) +__weak void mx28_adjust_mac(int dev_id, unsigned char *mac) { mac[0] = 0x00; mac[1] = 0x04; /* Use FSL vendor MAC address by default */ @@ -285,9 +287,6 @@ static void __mx28_adjust_mac(int dev_id, unsigned char *mac) mac[5] += 1; } -void mx28_adjust_mac(int dev_id, unsigned char *mac) - __attribute__((weak, alias("__mx28_adjust_mac"))); - #ifdef CONFIG_MX28_FEC_MAC_IN_OCOTP #define MXS_OCOTP_MAX_TIMEOUT 1000000