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