uboot/arch/arm/cpu/arm926ejs/spear/spl.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2011
   3 * Heiko Schocher, DENX Software Engineering, hs@denx.de.
   4 *
   5 * Copyright (C) 2012 Stefan Roese <sr@denx.de>
   6 *
   7 * See file CREDITS for list of people who contributed to this
   8 * project.
   9 *
  10 * This program is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU General Public License as
  12 * published by the Free Software Foundation; either version 2 of
  13 * the License, or (at your option) any later version.
  14 *
  15 * This program is distributed in the hope that it will be useful,
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18 * GNU General Public License for more details.
  19 *
  20 * You should have received a copy of the GNU General Public License
  21 * along with this program; if not, write to the Free Software
  22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  23 * MA 02111-1307 USA
  24 */
  25
  26#include <common.h>
  27#include <version.h>
  28#include <asm/io.h>
  29#include <asm/arch/hardware.h>
  30#include <asm/arch/spr_defs.h>
  31#include <asm/arch/spr_misc.h>
  32#include <asm/arch/spr_syscntl.h>
  33
  34inline void hang(void)
  35{
  36        serial_puts("### ERROR ### Please RESET the board ###\n");
  37        for (;;)
  38                ;
  39}
  40
  41static void ddr_clock_init(void)
  42{
  43        struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
  44        u32 clkenb, ddrpll;
  45
  46        clkenb = readl(&misc_p->periph1_clken);
  47        clkenb &= ~PERIPH_MPMCMSK;
  48        clkenb |= PERIPH_MPMC_WE;
  49
  50        /* Intentionally done twice */
  51        writel(clkenb, &misc_p->periph1_clken);
  52        writel(clkenb, &misc_p->periph1_clken);
  53
  54        ddrpll = readl(&misc_p->pll_ctr_reg);
  55        ddrpll &= ~MEM_CLK_SEL_MSK;
  56#if (CONFIG_DDR_HCLK)
  57        ddrpll |= MEM_CLK_HCLK;
  58#elif (CONFIG_DDR_2HCLK)
  59        ddrpll |= MEM_CLK_2HCLK;
  60#elif (CONFIG_DDR_PLL2)
  61        ddrpll |= MEM_CLK_PLL2;
  62#else
  63#error "please define one of CONFIG_DDR_(HCLK|2HCLK|PLL2)"
  64#endif
  65        writel(ddrpll, &misc_p->pll_ctr_reg);
  66
  67        writel(readl(&misc_p->periph1_clken) | PERIPH_MPMC_EN,
  68                        &misc_p->periph1_clken);
  69}
  70
  71static void mpmc_init_values(void)
  72{
  73        u32 i;
  74        u32 *mpmc_reg_p = (u32 *)CONFIG_SPEAR_MPMCBASE;
  75        u32 *mpmc_val_p = &mpmc_conf_vals[0];
  76
  77        for (i = 0; i < CONFIG_SPEAR_MPMCREGS; i++, mpmc_reg_p++, mpmc_val_p++)
  78                writel(*mpmc_val_p, mpmc_reg_p);
  79
  80        mpmc_reg_p = (u32 *)CONFIG_SPEAR_MPMCBASE;
  81
  82        /*
  83         * MPMC controller start
  84         * MPMC waiting for DLLLOCKREG high
  85         */
  86        writel(0x01000100, &mpmc_reg_p[7]);
  87
  88        while (!(readl(&mpmc_reg_p[3]) & 0x10000))
  89                ;
  90}
  91
  92static void mpmc_init(void)
  93{
  94        /* Clock related settings for DDR */
  95        ddr_clock_init();
  96
  97        /*
  98         * DDR pad register bits are different for different SoCs
  99         * Compensation values are also handled separately
 100         */
 101        plat_ddr_init();
 102
 103        /* Initialize mpmc register values */
 104        mpmc_init_values();
 105}
 106
 107static void pll_init(void)
 108{
 109        struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
 110
 111        /* Initialize PLLs */
 112        writel(FREQ_332, &misc_p->pll1_frq);
 113        writel(0x1C0A, &misc_p->pll1_cntl);
 114        writel(0x1C0E, &misc_p->pll1_cntl);
 115        writel(0x1C06, &misc_p->pll1_cntl);
 116        writel(0x1C0E, &misc_p->pll1_cntl);
 117
 118        writel(FREQ_332, &misc_p->pll2_frq);
 119        writel(0x1C0A, &misc_p->pll2_cntl);
 120        writel(0x1C0E, &misc_p->pll2_cntl);
 121        writel(0x1C06, &misc_p->pll2_cntl);
 122        writel(0x1C0E, &misc_p->pll2_cntl);
 123
 124        /* wait for pll locks */
 125        while (!(readl(&misc_p->pll1_cntl) & 0x1))
 126                ;
 127        while (!(readl(&misc_p->pll2_cntl) & 0x1))
 128                ;
 129}
 130
 131static void mac_init(void)
 132{
 133        struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
 134
 135        writel(readl(&misc_p->periph1_clken) & (~PERIPH_GMAC),
 136                        &misc_p->periph1_clken);
 137
 138        writel(SYNTH23, &misc_p->gmac_synth_clk);
 139
 140        switch (get_socrev()) {
 141        case SOC_SPEAR600_AA:
 142        case SOC_SPEAR600_AB:
 143        case SOC_SPEAR600_BA:
 144        case SOC_SPEAR600_BB:
 145        case SOC_SPEAR600_BC:
 146        case SOC_SPEAR600_BD:
 147                writel(0x0, &misc_p->gmac_ctr_reg);
 148                break;
 149
 150        case SOC_SPEAR300:
 151        case SOC_SPEAR310:
 152        case SOC_SPEAR320:
 153                writel(0x4, &misc_p->gmac_ctr_reg);
 154                break;
 155        }
 156
 157        writel(readl(&misc_p->periph1_clken) | PERIPH_GMAC,
 158                        &misc_p->periph1_clken);
 159
 160        writel(readl(&misc_p->periph1_rst) | PERIPH_GMAC,
 161                        &misc_p->periph1_rst);
 162        writel(readl(&misc_p->periph1_rst) & (~PERIPH_GMAC),
 163                        &misc_p->periph1_rst);
 164}
 165
 166static void sys_init(void)
 167{
 168        struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
 169        struct syscntl_regs *syscntl_p =
 170                (struct syscntl_regs *)CONFIG_SPEAR_SYSCNTLBASE;
 171
 172        /* Set system state to SLOW */
 173        writel(SLOW, &syscntl_p->scctrl);
 174        writel(PLL_TIM << 3, &syscntl_p->scpllctrl);
 175
 176        /* Initialize PLLs */
 177        pll_init();
 178
 179        /*
 180         * Ethernet configuration
 181         * To be done only if the tftp boot is not selected already
 182         * Boot code ensures the correct configuration in tftp booting
 183         */
 184        if (!tftp_boot_selected())
 185                mac_init();
 186
 187        writel(RTC_DISABLE | PLLTIMEEN, &misc_p->periph_clk_cfg);
 188        writel(0x555, &misc_p->amba_clk_cfg);
 189
 190        writel(NORMAL, &syscntl_p->scctrl);
 191
 192        /* Wait for system to switch to normal mode */
 193        while (((readl(&syscntl_p->scctrl) >> MODE_SHIFT) & MODE_MASK)
 194                != NORMAL)
 195                ;
 196}
 197
 198/*
 199 * get_socrev
 200 *
 201 * Get SoC Revision.
 202 * @return SOC_SPEARXXX
 203 */
 204int get_socrev(void)
 205{
 206#if defined(CONFIG_SPEAR600)
 207        struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
 208        u32 soc_id = readl(&misc_p->soc_core_id);
 209        u32 pri_socid = (soc_id >> SOC_PRI_SHFT) & 0xFF;
 210        u32 sec_socid = (soc_id >> SOC_SEC_SHFT) & 0xFF;
 211
 212        if ((pri_socid == 'B') && (sec_socid == 'B'))
 213                return SOC_SPEAR600_BB;
 214        else if ((pri_socid == 'B') && (sec_socid == 'C'))
 215                return SOC_SPEAR600_BC;
 216        else if ((pri_socid == 'B') && (sec_socid == 'D'))
 217                return SOC_SPEAR600_BD;
 218        else if (soc_id == 0)
 219                return SOC_SPEAR600_BA;
 220        else
 221                return SOC_SPEAR_NA;
 222#elif defined(CONFIG_SPEAR300)
 223        return SOC_SPEAR300;
 224#elif defined(CONFIG_SPEAR310)
 225        return SOC_SPEAR310;
 226#elif defined(CONFIG_SPEAR320)
 227        return SOC_SPEAR320;
 228#endif
 229}
 230
 231void lowlevel_init(void)
 232{
 233        struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
 234        const char *u_boot_rev = U_BOOT_VERSION;
 235
 236        /* Initialize PLLs */
 237        sys_init();
 238
 239        /* Initialize UART */
 240        serial_init();
 241
 242        /* Print U-Boot SPL version string */
 243        serial_puts("\nU-Boot SPL ");
 244        /* Avoid a second "U-Boot" coming from this string */
 245        u_boot_rev = &u_boot_rev[7];
 246        serial_puts(u_boot_rev);
 247        serial_puts(" (");
 248        serial_puts(U_BOOT_DATE);
 249        serial_puts(" - ");
 250        serial_puts(U_BOOT_TIME);
 251        serial_puts(")\n");
 252
 253#if defined(CONFIG_OS_BOOT)
 254        writel(readl(&misc_p->periph1_clken) | PERIPH_UART1,
 255                        &misc_p->periph1_clken);
 256#endif
 257
 258        /* Enable IPs (release reset) */
 259        writel(PERIPH_RST_ALL, &misc_p->periph1_rst);
 260
 261        /* Initialize MPMC */
 262        serial_puts("Configure DDR\n");
 263        mpmc_init();
 264
 265        /* SoC specific initialization */
 266        soc_init();
 267}
 268
 269void spear_late_init(void)
 270{
 271        struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
 272
 273        writel(0x80000007, &misc_p->arb_icm_ml1);
 274        writel(0x80000007, &misc_p->arb_icm_ml2);
 275        writel(0x80000007, &misc_p->arb_icm_ml3);
 276        writel(0x80000007, &misc_p->arb_icm_ml4);
 277        writel(0x80000007, &misc_p->arb_icm_ml5);
 278        writel(0x80000007, &misc_p->arb_icm_ml6);
 279        writel(0x80000007, &misc_p->arb_icm_ml7);
 280        writel(0x80000007, &misc_p->arb_icm_ml8);
 281        writel(0x80000007, &misc_p->arb_icm_ml9);
 282}
 283