uboot/arch/arm/cpu/arm926ejs/spear/spl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2011
   4 * Heiko Schocher, DENX Software Engineering, hs@denx.de.
   5 *
   6 * Copyright (C) 2012 Stefan Roese <sr@denx.de>
   7 */
   8
   9#include <common.h>
  10#include <spl.h>
  11#include <version.h>
  12#include <asm/io.h>
  13#include <asm/arch/hardware.h>
  14#include <asm/arch/spr_defs.h>
  15#include <asm/arch/spr_misc.h>
  16#include <asm/arch/spr_syscntl.h>
  17#include <linux/mtd/st_smi.h>
  18
  19/* Reserve some space to store the BootROM's stack pointer during SPL operation.
  20 * The BSS cannot be used for this purpose because it will be zeroed after
  21 * having stored the pointer, so force the location to the data section.
  22 */
  23u32 bootrom_stash_sp __attribute__((section(".data")));
  24
  25static void ddr_clock_init(void)
  26{
  27        struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
  28        u32 clkenb, ddrpll;
  29
  30        clkenb = readl(&misc_p->periph1_clken);
  31        clkenb &= ~PERIPH_MPMCMSK;
  32        clkenb |= PERIPH_MPMC_WE;
  33
  34        /* Intentionally done twice */
  35        writel(clkenb, &misc_p->periph1_clken);
  36        writel(clkenb, &misc_p->periph1_clken);
  37
  38        ddrpll = readl(&misc_p->pll_ctr_reg);
  39        ddrpll &= ~MEM_CLK_SEL_MSK;
  40#if (CONFIG_DDR_HCLK)
  41        ddrpll |= MEM_CLK_HCLK;
  42#elif (CONFIG_DDR_2HCLK)
  43        ddrpll |= MEM_CLK_2HCLK;
  44#elif (CONFIG_DDR_PLL2)
  45        ddrpll |= MEM_CLK_PLL2;
  46#else
  47#error "please define one of CONFIG_DDR_(HCLK|2HCLK|PLL2)"
  48#endif
  49        writel(ddrpll, &misc_p->pll_ctr_reg);
  50
  51        writel(readl(&misc_p->periph1_clken) | PERIPH_MPMC_EN,
  52                        &misc_p->periph1_clken);
  53}
  54
  55static void mpmc_init_values(void)
  56{
  57        u32 i;
  58        u32 *mpmc_reg_p = (u32 *)CONFIG_SPEAR_MPMCBASE;
  59        u32 *mpmc_val_p = &mpmc_conf_vals[0];
  60
  61        for (i = 0; i < CONFIG_SPEAR_MPMCREGS; i++, mpmc_reg_p++, mpmc_val_p++)
  62                writel(*mpmc_val_p, mpmc_reg_p);
  63
  64        mpmc_reg_p = (u32 *)CONFIG_SPEAR_MPMCBASE;
  65
  66        /*
  67         * MPMC controller start
  68         * MPMC waiting for DLLLOCKREG high
  69         */
  70        writel(0x01000100, &mpmc_reg_p[7]);
  71
  72        while (!(readl(&mpmc_reg_p[3]) & 0x10000))
  73                ;
  74}
  75
  76static void mpmc_init(void)
  77{
  78        /* Clock related settings for DDR */
  79        ddr_clock_init();
  80
  81        /*
  82         * DDR pad register bits are different for different SoCs
  83         * Compensation values are also handled separately
  84         */
  85        plat_ddr_init();
  86
  87        /* Initialize mpmc register values */
  88        mpmc_init_values();
  89}
  90
  91static void pll_init(void)
  92{
  93        struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
  94
  95        /* Initialize PLLs */
  96        writel(FREQ_332, &misc_p->pll1_frq);
  97        writel(0x1C0A, &misc_p->pll1_cntl);
  98        writel(0x1C0E, &misc_p->pll1_cntl);
  99        writel(0x1C06, &misc_p->pll1_cntl);
 100        writel(0x1C0E, &misc_p->pll1_cntl);
 101
 102        writel(FREQ_332, &misc_p->pll2_frq);
 103        writel(0x1C0A, &misc_p->pll2_cntl);
 104        writel(0x1C0E, &misc_p->pll2_cntl);
 105        writel(0x1C06, &misc_p->pll2_cntl);
 106        writel(0x1C0E, &misc_p->pll2_cntl);
 107
 108        /* wait for pll locks */
 109        while (!(readl(&misc_p->pll1_cntl) & 0x1))
 110                ;
 111        while (!(readl(&misc_p->pll2_cntl) & 0x1))
 112                ;
 113}
 114
 115static void mac_init(void)
 116{
 117        struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
 118
 119        writel(readl(&misc_p->periph1_clken) & (~PERIPH_GMAC),
 120                        &misc_p->periph1_clken);
 121
 122        writel(SYNTH23, &misc_p->gmac_synth_clk);
 123
 124        switch (get_socrev()) {
 125        case SOC_SPEAR600_AA:
 126        case SOC_SPEAR600_AB:
 127        case SOC_SPEAR600_BA:
 128        case SOC_SPEAR600_BB:
 129        case SOC_SPEAR600_BC:
 130        case SOC_SPEAR600_BD:
 131                writel(0x0, &misc_p->gmac_ctr_reg);
 132                break;
 133
 134        case SOC_SPEAR300:
 135        case SOC_SPEAR310:
 136        case SOC_SPEAR320:
 137                writel(0x4, &misc_p->gmac_ctr_reg);
 138                break;
 139        }
 140
 141        writel(readl(&misc_p->periph1_clken) | PERIPH_GMAC,
 142                        &misc_p->periph1_clken);
 143
 144        writel(readl(&misc_p->periph1_rst) | PERIPH_GMAC,
 145                        &misc_p->periph1_rst);
 146        writel(readl(&misc_p->periph1_rst) & (~PERIPH_GMAC),
 147                        &misc_p->periph1_rst);
 148}
 149
 150static void sys_init(void)
 151{
 152        struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
 153        struct syscntl_regs *syscntl_p =
 154                (struct syscntl_regs *)CONFIG_SPEAR_SYSCNTLBASE;
 155
 156        /* Set system state to SLOW */
 157        writel(SLOW, &syscntl_p->scctrl);
 158        writel(PLL_TIM << 3, &syscntl_p->scpllctrl);
 159
 160        /* Initialize PLLs */
 161        pll_init();
 162
 163        /*
 164         * Ethernet configuration
 165         * To be done only if the tftp boot is not selected already
 166         * Boot code ensures the correct configuration in tftp booting
 167         */
 168        if (!tftp_boot_selected())
 169                mac_init();
 170
 171        writel(RTC_DISABLE | PLLTIMEEN, &misc_p->periph_clk_cfg);
 172        writel(0x555, &misc_p->amba_clk_cfg);
 173
 174        writel(NORMAL, &syscntl_p->scctrl);
 175
 176        /* Wait for system to switch to normal mode */
 177        while (((readl(&syscntl_p->scctrl) >> MODE_SHIFT) & MODE_MASK)
 178                != NORMAL)
 179                ;
 180}
 181
 182/*
 183 * get_socrev
 184 *
 185 * Get SoC Revision.
 186 * @return SOC_SPEARXXX
 187 */
 188int get_socrev(void)
 189{
 190#if defined(CONFIG_SPEAR600)
 191        struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
 192        u32 soc_id = readl(&misc_p->soc_core_id);
 193        u32 pri_socid = (soc_id >> SOC_PRI_SHFT) & 0xFF;
 194        u32 sec_socid = (soc_id >> SOC_SEC_SHFT) & 0xFF;
 195
 196        if ((pri_socid == 'B') && (sec_socid == 'B'))
 197                return SOC_SPEAR600_BB;
 198        else if ((pri_socid == 'B') && (sec_socid == 'C'))
 199                return SOC_SPEAR600_BC;
 200        else if ((pri_socid == 'B') && (sec_socid == 'D'))
 201                return SOC_SPEAR600_BD;
 202        else if (soc_id == 0)
 203                return SOC_SPEAR600_BA;
 204        else
 205                return SOC_SPEAR_NA;
 206#elif defined(CONFIG_SPEAR300)
 207        return SOC_SPEAR300;
 208#elif defined(CONFIG_SPEAR310)
 209        return SOC_SPEAR310;
 210#elif defined(CONFIG_SPEAR320)
 211        return SOC_SPEAR320;
 212#endif
 213}
 214
 215/*
 216 * SNOR (Serial NOR flash) related functions
 217 */
 218static void snor_init(void)
 219{
 220        struct smi_regs *const smicntl =
 221                (struct smi_regs * const)CONFIG_SYS_SMI_BASE;
 222
 223        /* Setting the fast mode values. SMI working at 166/4 = 41.5 MHz */
 224        writel(HOLD1 | FAST_MODE | BANK_EN | DSEL_TIME | PRESCAL4,
 225               &smicntl->smi_cr1);
 226}
 227
 228u32 spl_boot_device(void)
 229{
 230        u32 mode = 0;
 231
 232        if (usb_boot_selected()) {
 233                mode = BOOT_DEVICE_BOOTROM;
 234        } else if (snor_boot_selected()) {
 235                /* SNOR-SMI initialization */
 236                snor_init();
 237
 238                mode = BOOT_DEVICE_NOR;
 239        }
 240
 241        return mode;
 242}
 243
 244void board_boot_order(u32 *spl_boot_list)
 245{
 246        spl_boot_list[0] = spl_boot_device();
 247
 248        /*
 249         * If the main boot device (eg. NOR) is empty, try to jump back into the
 250         * BootROM for USB boot process.
 251         */
 252        if (USB_BOOT_SUPPORTED)
 253                spl_boot_list[1] = BOOT_DEVICE_BOOTROM;
 254}
 255
 256void board_init_f(ulong dummy)
 257{
 258        struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
 259
 260        /* Initialize PLLs */
 261        sys_init();
 262
 263        preloader_console_init();
 264        arch_cpu_init();
 265
 266        /* Enable IPs (release reset) */
 267        writel(PERIPH_RST_ALL, &misc_p->periph1_rst);
 268
 269        /* Initialize MPMC */
 270        puts("Configure DDR\n");
 271        mpmc_init();
 272        spear_late_init();
 273}
 274
 275/*
 276 * In a few cases (Ethernet, UART or USB boot, we might want to go back into the
 277 * BootROM code right after having initialized a few components like the DRAM).
 278 * The following function is called from SPL common code (board_init_r).
 279 */
 280int board_return_to_bootrom(struct spl_image_info *spl_image,
 281                            struct spl_boot_device *bootdev)
 282{
 283        /*
 284         * Retrieve the BootROM's stack pointer and jump back to the start of
 285         * the SPL, where we can easily branch back into the BootROM. Don't do
 286         * it right here because SPL might be compiled in Thumb mode while the
 287         * BootROM expects ARM mode.
 288         */
 289        asm volatile ("ldr r0, =bootrom_stash_sp;"
 290                      "ldr r0, [r0];"
 291                      "mov sp, r0;"
 292#if defined(CONFIG_SPL_SYS_THUMB_BUILD)
 293                      "blx back_to_bootrom;"
 294#else
 295                      "bl back_to_bootrom;"
 296#endif
 297                      );
 298
 299        return 0;
 300}
 301