uboot/arch/arm/cpu/arm926ejs/mxs/mxs.c
<<
>>
Prefs
   1/*
   2 * Freescale i.MX23/i.MX28 common code
   3 *
   4 * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
   5 * on behalf of DENX Software Engineering GmbH
   6 *
   7 * Based on code from LTIB:
   8 * Copyright (C) 2010 Freescale Semiconductor, Inc.
   9 *
  10 * SPDX-License-Identifier:     GPL-2.0+
  11 */
  12
  13#include <common.h>
  14#include <linux/errno.h>
  15#include <asm/io.h>
  16#include <asm/arch/clock.h>
  17#include <asm/mach-imx/dma.h>
  18#include <asm/arch/gpio.h>
  19#include <asm/arch/iomux.h>
  20#include <asm/arch/imx-regs.h>
  21#include <asm/arch/sys_proto.h>
  22#include <linux/compiler.h>
  23
  24DECLARE_GLOBAL_DATA_PTR;
  25
  26/* Lowlevel init isn't used on i.MX28, so just have a dummy here */
  27void lowlevel_init(void) {}
  28
  29void reset_cpu(ulong ignored) __attribute__((noreturn));
  30
  31void reset_cpu(ulong ignored)
  32{
  33        struct mxs_rtc_regs *rtc_regs =
  34                (struct mxs_rtc_regs *)MXS_RTC_BASE;
  35        struct mxs_lcdif_regs *lcdif_regs =
  36                (struct mxs_lcdif_regs *)MXS_LCDIF_BASE;
  37
  38        /*
  39         * Shut down the LCD controller as it interferes with BootROM boot mode
  40         * pads sampling.
  41         */
  42        writel(LCDIF_CTRL_RUN, &lcdif_regs->hw_lcdif_ctrl_clr);
  43
  44        /* Wait 1 uS before doing the actual watchdog reset */
  45        writel(1, &rtc_regs->hw_rtc_watchdog);
  46        writel(RTC_CTRL_WATCHDOGEN, &rtc_regs->hw_rtc_ctrl_set);
  47
  48        /* Endless loop, reset will exit from here */
  49        for (;;)
  50                ;
  51}
  52
  53void enable_caches(void)
  54{
  55#ifndef CONFIG_SYS_ICACHE_OFF
  56        icache_enable();
  57#endif
  58#ifndef CONFIG_SYS_DCACHE_OFF
  59        dcache_enable();
  60#endif
  61}
  62
  63/*
  64 * This function will craft a jumptable at 0x0 which will redirect interrupt
  65 * vectoring to proper location of U-Boot in RAM.
  66 *
  67 * The structure of the jumptable will be as follows:
  68 *  ldr pc, [pc, #0x18] ..... for each vector, thus repeated 8 times
  69 *  <destination address> ... for each previous ldr, thus also repeated 8 times
  70 *
  71 * The "ldr pc, [pc, #0x18]" instruction above loads address from memory at
  72 * offset 0x18 from current value of PC register. Note that PC is already
  73 * incremented by 4 when computing the offset, so the effective offset is
  74 * actually 0x20, this the associated <destination address>. Loading the PC
  75 * register with an address performs a jump to that address.
  76 */
  77void mx28_fixup_vt(uint32_t start_addr)
  78{
  79        /* ldr pc, [pc, #0x18] */
  80        const uint32_t ldr_pc = 0xe59ff018;
  81        /* Jumptable location is 0x0 */
  82        uint32_t *vt = (uint32_t *)0x0;
  83        int i;
  84
  85        for (i = 0; i < 8; i++) {
  86                /* cppcheck-suppress nullPointer */
  87                vt[i] = ldr_pc;
  88                /* cppcheck-suppress nullPointer */
  89                vt[i + 8] = start_addr + (4 * i);
  90        }
  91}
  92
  93#ifdef  CONFIG_ARCH_MISC_INIT
  94int arch_misc_init(void)
  95{
  96        mx28_fixup_vt(gd->relocaddr);
  97        return 0;
  98}
  99#endif
 100
 101int arch_cpu_init(void)
 102{
 103        struct mxs_clkctrl_regs *clkctrl_regs =
 104                (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
 105        extern uint32_t _start;
 106
 107        mx28_fixup_vt((uint32_t)&_start);
 108
 109        /*
 110         * Enable NAND clock
 111         */
 112        /* Clear bypass bit */
 113        writel(CLKCTRL_CLKSEQ_BYPASS_GPMI,
 114                &clkctrl_regs->hw_clkctrl_clkseq_set);
 115
 116        /* Set GPMI clock to ref_gpmi / 12 */
 117        clrsetbits_le32(&clkctrl_regs->hw_clkctrl_gpmi,
 118                CLKCTRL_GPMI_CLKGATE | CLKCTRL_GPMI_DIV_MASK, 1);
 119
 120        udelay(1000);
 121
 122        /*
 123         * Configure GPIO unit
 124         */
 125        mxs_gpio_init();
 126
 127#ifdef  CONFIG_APBH_DMA
 128        /* Start APBH DMA */
 129        mxs_dma_init();
 130#endif
 131
 132        return 0;
 133}
 134
 135u32 get_cpu_rev(void)
 136{
 137        struct mxs_digctl_regs *digctl_regs =
 138                (struct mxs_digctl_regs *)MXS_DIGCTL_BASE;
 139        uint8_t rev = readl(&digctl_regs->hw_digctl_chipid) & 0x000000FF;
 140
 141        switch (readl(&digctl_regs->hw_digctl_chipid) & HW_DIGCTL_CHIPID_MASK) {
 142        case HW_DIGCTL_CHIPID_MX23:
 143                switch (rev) {
 144                case 0x0:
 145                case 0x1:
 146                case 0x2:
 147                case 0x3:
 148                case 0x4:
 149                        return (MXC_CPU_MX23 << 12) | (rev + 0x10);
 150                default:
 151                        return 0;
 152                }
 153        case HW_DIGCTL_CHIPID_MX28:
 154                switch (rev) {
 155                case 0x1:
 156                        return (MXC_CPU_MX28 << 12) | 0x12;
 157                default:
 158                        return 0;
 159                }
 160        default:
 161                return 0;
 162        }
 163}
 164
 165#if defined(CONFIG_DISPLAY_CPUINFO)
 166const char *get_imx_type(u32 imxtype)
 167{
 168        switch (imxtype) {
 169        case MXC_CPU_MX23:
 170                return "23";
 171        case MXC_CPU_MX28:
 172                return "28";
 173        default:
 174                return "??";
 175        }
 176}
 177
 178int print_cpuinfo(void)
 179{
 180        u32 cpurev;
 181        struct mxs_spl_data *data = (struct mxs_spl_data *)
 182                ((CONFIG_SYS_TEXT_BASE - sizeof(struct mxs_spl_data)) & ~0xf);
 183
 184        cpurev = get_cpu_rev();
 185        printf("CPU:   Freescale i.MX%s rev%d.%d at %d MHz\n",
 186                get_imx_type((cpurev & 0xFF000) >> 12),
 187                (cpurev & 0x000F0) >> 4,
 188                (cpurev & 0x0000F) >> 0,
 189                mxc_get_clock(MXC_ARM_CLK) / 1000000);
 190        printf("BOOT:  %s\n", mxs_boot_modes[data->boot_mode_idx].mode);
 191        return 0;
 192}
 193#endif
 194
 195int do_mx28_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 196{
 197        printf("CPU:   %3d MHz\n", mxc_get_clock(MXC_ARM_CLK) / 1000000);
 198        printf("BUS:   %3d MHz\n", mxc_get_clock(MXC_AHB_CLK) / 1000000);
 199        printf("EMI:   %3d MHz\n", mxc_get_clock(MXC_EMI_CLK));
 200        printf("GPMI:  %3d MHz\n", mxc_get_clock(MXC_GPMI_CLK) / 1000000);
 201        return 0;
 202}
 203
 204/*
 205 * Initializes on-chip ethernet controllers.
 206 */
 207#if defined(CONFIG_MX28) && defined(CONFIG_CMD_NET)
 208int cpu_eth_init(bd_t *bis)
 209{
 210        struct mxs_clkctrl_regs *clkctrl_regs =
 211                (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
 212
 213        /* Turn on ENET clocks */
 214        clrbits_le32(&clkctrl_regs->hw_clkctrl_enet,
 215                CLKCTRL_ENET_SLEEP | CLKCTRL_ENET_DISABLE);
 216
 217        /* Set up ENET PLL for 50 MHz */
 218        /* Power on ENET PLL */
 219        writel(CLKCTRL_PLL2CTRL0_POWER,
 220                &clkctrl_regs->hw_clkctrl_pll2ctrl0_set);
 221
 222        udelay(10);
 223
 224        /* Gate on ENET PLL */
 225        writel(CLKCTRL_PLL2CTRL0_CLKGATE,
 226                &clkctrl_regs->hw_clkctrl_pll2ctrl0_clr);
 227
 228        /* Enable pad output */
 229        setbits_le32(&clkctrl_regs->hw_clkctrl_enet, CLKCTRL_ENET_CLK_OUT_EN);
 230
 231        return 0;
 232}
 233#endif
 234
 235__weak void mx28_adjust_mac(int dev_id, unsigned char *mac)
 236{
 237        mac[0] = 0x00;
 238        mac[1] = 0x04; /* Use FSL vendor MAC address by default */
 239
 240        if (dev_id == 1) /* Let MAC1 be MAC0 + 1 by default */
 241                mac[5] += 1;
 242}
 243
 244#ifdef  CONFIG_MX28_FEC_MAC_IN_OCOTP
 245
 246#define MXS_OCOTP_MAX_TIMEOUT   1000000
 247void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
 248{
 249        struct mxs_ocotp_regs *ocotp_regs =
 250                (struct mxs_ocotp_regs *)MXS_OCOTP_BASE;
 251        uint32_t data;
 252
 253        memset(mac, 0, 6);
 254
 255        writel(OCOTP_CTRL_RD_BANK_OPEN, &ocotp_regs->hw_ocotp_ctrl_set);
 256
 257        if (mxs_wait_mask_clr(&ocotp_regs->hw_ocotp_ctrl_reg, OCOTP_CTRL_BUSY,
 258                                MXS_OCOTP_MAX_TIMEOUT)) {
 259                printf("MXS FEC: Can't get MAC from OCOTP\n");
 260                return;
 261        }
 262
 263        data = readl(&ocotp_regs->hw_ocotp_cust0);
 264
 265        mac[2] = (data >> 24) & 0xff;
 266        mac[3] = (data >> 16) & 0xff;
 267        mac[4] = (data >> 8) & 0xff;
 268        mac[5] = data & 0xff;
 269        mx28_adjust_mac(dev_id, mac);
 270}
 271#else
 272void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
 273{
 274        memset(mac, 0, 6);
 275}
 276#endif
 277
 278int mxs_dram_init(void)
 279{
 280        struct mxs_spl_data *data = (struct mxs_spl_data *)
 281                ((CONFIG_SYS_TEXT_BASE - sizeof(struct mxs_spl_data)) & ~0xf);
 282
 283        if (data->mem_dram_size == 0) {
 284                printf("MXS:\n"
 285                        "Error, the RAM size passed up from SPL is 0!\n");
 286                hang();
 287        }
 288
 289        gd->ram_size = data->mem_dram_size;
 290        return 0;
 291}
 292
 293U_BOOT_CMD(
 294        clocks, CONFIG_SYS_MAXARGS, 1, do_mx28_showclocks,
 295        "display clocks",
 296        ""
 297);
 298