uboot/arch/arm/cpu/arm926ejs/mxs/mxs.c
<<
>>
Prefs
   1/*
   2 * Freescale 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 * See file CREDITS for list of people who contributed to this
  11 * project.
  12 *
  13 * This program is free software; you can redistribute it and/or
  14 * modify it under the terms of the GNU General Public License as
  15 * published by the Free Software Foundation; either version 2 of
  16 * the License, or (at your option) any later version.
  17 *
  18 * This program is distributed in the hope that it will be useful,
  19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21 * GNU General Public License for more details.
  22 *
  23 * You should have received a copy of the GNU General Public License
  24 * along with this program; if not, write to the Free Software
  25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  26 * MA 02111-1307 USA
  27 */
  28
  29#include <common.h>
  30#include <asm/errno.h>
  31#include <asm/io.h>
  32#include <asm/arch/clock.h>
  33#include <asm/arch/dma.h>
  34#include <asm/arch/gpio.h>
  35#include <asm/arch/iomux.h>
  36#include <asm/arch/imx-regs.h>
  37#include <asm/arch/sys_proto.h>
  38
  39DECLARE_GLOBAL_DATA_PTR;
  40
  41/* 1 second delay should be plenty of time for block reset. */
  42#define RESET_MAX_TIMEOUT       1000000
  43
  44#define MXS_BLOCK_SFTRST        (1 << 31)
  45#define MXS_BLOCK_CLKGATE       (1 << 30)
  46
  47/* Lowlevel init isn't used on i.MX28, so just have a dummy here */
  48inline void lowlevel_init(void) {}
  49
  50void reset_cpu(ulong ignored) __attribute__((noreturn));
  51
  52void reset_cpu(ulong ignored)
  53{
  54        struct mxs_rtc_regs *rtc_regs =
  55                (struct mxs_rtc_regs *)MXS_RTC_BASE;
  56        struct mxs_lcdif_regs *lcdif_regs =
  57                (struct mxs_lcdif_regs *)MXS_LCDIF_BASE;
  58
  59        /*
  60         * Shut down the LCD controller as it interferes with BootROM boot mode
  61         * pads sampling.
  62         */
  63        writel(LCDIF_CTRL_RUN, &lcdif_regs->hw_lcdif_ctrl_clr);
  64
  65        /* Wait 1 uS before doing the actual watchdog reset */
  66        writel(1, &rtc_regs->hw_rtc_watchdog);
  67        writel(RTC_CTRL_WATCHDOGEN, &rtc_regs->hw_rtc_ctrl_set);
  68
  69        /* Endless loop, reset will exit from here */
  70        for (;;)
  71                ;
  72}
  73
  74void enable_caches(void)
  75{
  76#ifndef CONFIG_SYS_ICACHE_OFF
  77        icache_enable();
  78#endif
  79#ifndef CONFIG_SYS_DCACHE_OFF
  80        dcache_enable();
  81#endif
  82}
  83
  84int mxs_wait_mask_set(struct mxs_register_32 *reg, uint32_t mask, unsigned
  85                                                                int timeout)
  86{
  87        while (--timeout) {
  88                if ((readl(&reg->reg) & mask) == mask)
  89                        break;
  90                udelay(1);
  91        }
  92
  93        return !timeout;
  94}
  95
  96int mxs_wait_mask_clr(struct mxs_register_32 *reg, uint32_t mask, unsigned
  97                                                                int timeout)
  98{
  99        while (--timeout) {
 100                if ((readl(&reg->reg) & mask) == 0)
 101                        break;
 102                udelay(1);
 103        }
 104
 105        return !timeout;
 106}
 107
 108int mxs_reset_block(struct mxs_register_32 *reg)
 109{
 110        /* Clear SFTRST */
 111        writel(MXS_BLOCK_SFTRST, &reg->reg_clr);
 112
 113        if (mxs_wait_mask_clr(reg, MXS_BLOCK_SFTRST, RESET_MAX_TIMEOUT))
 114                return 1;
 115
 116        /* Clear CLKGATE */
 117        writel(MXS_BLOCK_CLKGATE, &reg->reg_clr);
 118
 119        /* Set SFTRST */
 120        writel(MXS_BLOCK_SFTRST, &reg->reg_set);
 121
 122        /* Wait for CLKGATE being set */
 123        if (mxs_wait_mask_set(reg, MXS_BLOCK_CLKGATE, RESET_MAX_TIMEOUT))
 124                return 1;
 125
 126        /* Clear SFTRST */
 127        writel(MXS_BLOCK_SFTRST, &reg->reg_clr);
 128
 129        if (mxs_wait_mask_clr(reg, MXS_BLOCK_SFTRST, RESET_MAX_TIMEOUT))
 130                return 1;
 131
 132        /* Clear CLKGATE */
 133        writel(MXS_BLOCK_CLKGATE, &reg->reg_clr);
 134
 135        if (mxs_wait_mask_clr(reg, MXS_BLOCK_CLKGATE, RESET_MAX_TIMEOUT))
 136                return 1;
 137
 138        return 0;
 139}
 140
 141void mx28_fixup_vt(uint32_t start_addr)
 142{
 143        uint32_t *vt = (uint32_t *)0x20;
 144        int i;
 145
 146        for (i = 0; i < 8; i++)
 147                vt[i] = start_addr + (4 * i);
 148}
 149
 150#ifdef  CONFIG_ARCH_MISC_INIT
 151int arch_misc_init(void)
 152{
 153        mx28_fixup_vt(gd->relocaddr);
 154        return 0;
 155}
 156#endif
 157
 158int arch_cpu_init(void)
 159{
 160        struct mxs_clkctrl_regs *clkctrl_regs =
 161                (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
 162        extern uint32_t _start;
 163
 164        mx28_fixup_vt((uint32_t)&_start);
 165
 166        /*
 167         * Enable NAND clock
 168         */
 169        /* Clear bypass bit */
 170        writel(CLKCTRL_CLKSEQ_BYPASS_GPMI,
 171                &clkctrl_regs->hw_clkctrl_clkseq_set);
 172
 173        /* Set GPMI clock to ref_gpmi / 12 */
 174        clrsetbits_le32(&clkctrl_regs->hw_clkctrl_gpmi,
 175                CLKCTRL_GPMI_CLKGATE | CLKCTRL_GPMI_DIV_MASK, 1);
 176
 177        udelay(1000);
 178
 179        /*
 180         * Configure GPIO unit
 181         */
 182        mxs_gpio_init();
 183
 184#ifdef  CONFIG_APBH_DMA
 185        /* Start APBH DMA */
 186        mxs_dma_init();
 187#endif
 188
 189        return 0;
 190}
 191
 192#if defined(CONFIG_DISPLAY_CPUINFO)
 193static const char *get_cpu_type(void)
 194{
 195        struct mxs_digctl_regs *digctl_regs =
 196                (struct mxs_digctl_regs *)MXS_DIGCTL_BASE;
 197
 198        switch (readl(&digctl_regs->hw_digctl_chipid) & HW_DIGCTL_CHIPID_MASK) {
 199        case HW_DIGCTL_CHIPID_MX28:
 200                return "28";
 201        default:
 202                return "??";
 203        }
 204}
 205
 206static const char *get_cpu_rev(void)
 207{
 208        struct mxs_digctl_regs *digctl_regs =
 209                (struct mxs_digctl_regs *)MXS_DIGCTL_BASE;
 210        uint8_t rev = readl(&digctl_regs->hw_digctl_chipid) & 0x000000FF;
 211
 212        switch (readl(&digctl_regs->hw_digctl_chipid) & HW_DIGCTL_CHIPID_MASK) {
 213        case HW_DIGCTL_CHIPID_MX28:
 214                switch (rev) {
 215                case 0x1:
 216                        return "1.2";
 217                default:
 218                        return "??";
 219                }
 220        default:
 221                return "??";
 222        }
 223}
 224
 225int print_cpuinfo(void)
 226{
 227        struct mxs_spl_data *data = (struct mxs_spl_data *)
 228                ((CONFIG_SYS_TEXT_BASE - sizeof(struct mxs_spl_data)) & ~0xf);
 229
 230        printf("CPU:   Freescale i.MX%s rev%s at %d MHz\n",
 231                get_cpu_type(),
 232                get_cpu_rev(),
 233                mxc_get_clock(MXC_ARM_CLK) / 1000000);
 234        printf("BOOT:  %s\n", mxs_boot_modes[data->boot_mode_idx].mode);
 235        return 0;
 236}
 237#endif
 238
 239int do_mx28_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 240{
 241        printf("CPU:   %3d MHz\n", mxc_get_clock(MXC_ARM_CLK) / 1000000);
 242        printf("BUS:   %3d MHz\n", mxc_get_clock(MXC_AHB_CLK) / 1000000);
 243        printf("EMI:   %3d MHz\n", mxc_get_clock(MXC_EMI_CLK));
 244        printf("GPMI:  %3d MHz\n", mxc_get_clock(MXC_GPMI_CLK) / 1000000);
 245        return 0;
 246}
 247
 248/*
 249 * Initializes on-chip ethernet controllers.
 250 */
 251#if defined(CONFIG_MX28) && defined(CONFIG_CMD_NET)
 252int cpu_eth_init(bd_t *bis)
 253{
 254        struct mxs_clkctrl_regs *clkctrl_regs =
 255                (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
 256
 257        /* Turn on ENET clocks */
 258        clrbits_le32(&clkctrl_regs->hw_clkctrl_enet,
 259                CLKCTRL_ENET_SLEEP | CLKCTRL_ENET_DISABLE);
 260
 261        /* Set up ENET PLL for 50 MHz */
 262        /* Power on ENET PLL */
 263        writel(CLKCTRL_PLL2CTRL0_POWER,
 264                &clkctrl_regs->hw_clkctrl_pll2ctrl0_set);
 265
 266        udelay(10);
 267
 268        /* Gate on ENET PLL */
 269        writel(CLKCTRL_PLL2CTRL0_CLKGATE,
 270                &clkctrl_regs->hw_clkctrl_pll2ctrl0_clr);
 271
 272        /* Enable pad output */
 273        setbits_le32(&clkctrl_regs->hw_clkctrl_enet, CLKCTRL_ENET_CLK_OUT_EN);
 274
 275        return 0;
 276}
 277#endif
 278
 279static void __mx28_adjust_mac(int dev_id, unsigned char *mac)
 280{
 281        mac[0] = 0x00;
 282        mac[1] = 0x04; /* Use FSL vendor MAC address by default */
 283
 284        if (dev_id == 1) /* Let MAC1 be MAC0 + 1 by default */
 285                mac[5] += 1;
 286}
 287
 288void mx28_adjust_mac(int dev_id, unsigned char *mac)
 289        __attribute__((weak, alias("__mx28_adjust_mac")));
 290
 291#ifdef  CONFIG_MX28_FEC_MAC_IN_OCOTP
 292
 293#define MXS_OCOTP_MAX_TIMEOUT   1000000
 294void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
 295{
 296        struct mxs_ocotp_regs *ocotp_regs =
 297                (struct mxs_ocotp_regs *)MXS_OCOTP_BASE;
 298        uint32_t data;
 299
 300        memset(mac, 0, 6);
 301
 302        writel(OCOTP_CTRL_RD_BANK_OPEN, &ocotp_regs->hw_ocotp_ctrl_set);
 303
 304        if (mxs_wait_mask_clr(&ocotp_regs->hw_ocotp_ctrl_reg, OCOTP_CTRL_BUSY,
 305                                MXS_OCOTP_MAX_TIMEOUT)) {
 306                printf("MXS FEC: Can't get MAC from OCOTP\n");
 307                return;
 308        }
 309
 310        data = readl(&ocotp_regs->hw_ocotp_cust0);
 311
 312        mac[2] = (data >> 24) & 0xff;
 313        mac[3] = (data >> 16) & 0xff;
 314        mac[4] = (data >> 8) & 0xff;
 315        mac[5] = data & 0xff;
 316        mx28_adjust_mac(dev_id, mac);
 317}
 318#else
 319void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
 320{
 321        memset(mac, 0, 6);
 322}
 323#endif
 324
 325int mxs_dram_init(void)
 326{
 327        struct mxs_spl_data *data = (struct mxs_spl_data *)
 328                ((CONFIG_SYS_TEXT_BASE - sizeof(struct mxs_spl_data)) & ~0xf);
 329
 330        if (data->mem_dram_size == 0) {
 331                printf("MXS:\n"
 332                        "Error, the RAM size passed up from SPL is 0!\n");
 333                hang();
 334        }
 335
 336        gd->ram_size = data->mem_dram_size;
 337        return 0;
 338}
 339
 340U_BOOT_CMD(
 341        clocks, CONFIG_SYS_MAXARGS, 1, do_mx28_showclocks,
 342        "display clocks",
 343        ""
 344);
 345