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 * SPDX-License-Identifier: GPL-2.0+ 8 */ 9 10 #include <common.h> 11 #include <spl.h> 12 #include <version.h> 13 #include <asm/io.h> 14 #include <asm/arch/hardware.h> 15 #include <asm/arch/spr_defs.h> 16 #include <asm/arch/spr_misc.h> 17 #include <asm/arch/spr_syscntl.h> 18 #include <linux/mtd/st_smi.h> 19 20 static void ddr_clock_init(void) 21 { 22 struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; 23 u32 clkenb, ddrpll; 24 25 clkenb = readl(&misc_p->periph1_clken); 26 clkenb &= ~PERIPH_MPMCMSK; 27 clkenb |= PERIPH_MPMC_WE; 28 29 /* Intentionally done twice */ 30 writel(clkenb, &misc_p->periph1_clken); 31 writel(clkenb, &misc_p->periph1_clken); 32 33 ddrpll = readl(&misc_p->pll_ctr_reg); 34 ddrpll &= ~MEM_CLK_SEL_MSK; 35 #if (CONFIG_DDR_HCLK) 36 ddrpll |= MEM_CLK_HCLK; 37 #elif (CONFIG_DDR_2HCLK) 38 ddrpll |= MEM_CLK_2HCLK; 39 #elif (CONFIG_DDR_PLL2) 40 ddrpll |= MEM_CLK_PLL2; 41 #else 42 #error "please define one of CONFIG_DDR_(HCLK|2HCLK|PLL2)" 43 #endif 44 writel(ddrpll, &misc_p->pll_ctr_reg); 45 46 writel(readl(&misc_p->periph1_clken) | PERIPH_MPMC_EN, 47 &misc_p->periph1_clken); 48 } 49 50 static void mpmc_init_values(void) 51 { 52 u32 i; 53 u32 *mpmc_reg_p = (u32 *)CONFIG_SPEAR_MPMCBASE; 54 u32 *mpmc_val_p = &mpmc_conf_vals[0]; 55 56 for (i = 0; i < CONFIG_SPEAR_MPMCREGS; i++, mpmc_reg_p++, mpmc_val_p++) 57 writel(*mpmc_val_p, mpmc_reg_p); 58 59 mpmc_reg_p = (u32 *)CONFIG_SPEAR_MPMCBASE; 60 61 /* 62 * MPMC controller start 63 * MPMC waiting for DLLLOCKREG high 64 */ 65 writel(0x01000100, &mpmc_reg_p[7]); 66 67 while (!(readl(&mpmc_reg_p[3]) & 0x10000)) 68 ; 69 } 70 71 static void mpmc_init(void) 72 { 73 /* Clock related settings for DDR */ 74 ddr_clock_init(); 75 76 /* 77 * DDR pad register bits are different for different SoCs 78 * Compensation values are also handled separately 79 */ 80 plat_ddr_init(); 81 82 /* Initialize mpmc register values */ 83 mpmc_init_values(); 84 } 85 86 static void pll_init(void) 87 { 88 struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; 89 90 /* Initialize PLLs */ 91 writel(FREQ_332, &misc_p->pll1_frq); 92 writel(0x1C0A, &misc_p->pll1_cntl); 93 writel(0x1C0E, &misc_p->pll1_cntl); 94 writel(0x1C06, &misc_p->pll1_cntl); 95 writel(0x1C0E, &misc_p->pll1_cntl); 96 97 writel(FREQ_332, &misc_p->pll2_frq); 98 writel(0x1C0A, &misc_p->pll2_cntl); 99 writel(0x1C0E, &misc_p->pll2_cntl); 100 writel(0x1C06, &misc_p->pll2_cntl); 101 writel(0x1C0E, &misc_p->pll2_cntl); 102 103 /* wait for pll locks */ 104 while (!(readl(&misc_p->pll1_cntl) & 0x1)) 105 ; 106 while (!(readl(&misc_p->pll2_cntl) & 0x1)) 107 ; 108 } 109 110 static void mac_init(void) 111 { 112 struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; 113 114 writel(readl(&misc_p->periph1_clken) & (~PERIPH_GMAC), 115 &misc_p->periph1_clken); 116 117 writel(SYNTH23, &misc_p->gmac_synth_clk); 118 119 switch (get_socrev()) { 120 case SOC_SPEAR600_AA: 121 case SOC_SPEAR600_AB: 122 case SOC_SPEAR600_BA: 123 case SOC_SPEAR600_BB: 124 case SOC_SPEAR600_BC: 125 case SOC_SPEAR600_BD: 126 writel(0x0, &misc_p->gmac_ctr_reg); 127 break; 128 129 case SOC_SPEAR300: 130 case SOC_SPEAR310: 131 case SOC_SPEAR320: 132 writel(0x4, &misc_p->gmac_ctr_reg); 133 break; 134 } 135 136 writel(readl(&misc_p->periph1_clken) | PERIPH_GMAC, 137 &misc_p->periph1_clken); 138 139 writel(readl(&misc_p->periph1_rst) | PERIPH_GMAC, 140 &misc_p->periph1_rst); 141 writel(readl(&misc_p->periph1_rst) & (~PERIPH_GMAC), 142 &misc_p->periph1_rst); 143 } 144 145 static void sys_init(void) 146 { 147 struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; 148 struct syscntl_regs *syscntl_p = 149 (struct syscntl_regs *)CONFIG_SPEAR_SYSCNTLBASE; 150 151 /* Set system state to SLOW */ 152 writel(SLOW, &syscntl_p->scctrl); 153 writel(PLL_TIM << 3, &syscntl_p->scpllctrl); 154 155 /* Initialize PLLs */ 156 pll_init(); 157 158 /* 159 * Ethernet configuration 160 * To be done only if the tftp boot is not selected already 161 * Boot code ensures the correct configuration in tftp booting 162 */ 163 if (!tftp_boot_selected()) 164 mac_init(); 165 166 writel(RTC_DISABLE | PLLTIMEEN, &misc_p->periph_clk_cfg); 167 writel(0x555, &misc_p->amba_clk_cfg); 168 169 writel(NORMAL, &syscntl_p->scctrl); 170 171 /* Wait for system to switch to normal mode */ 172 while (((readl(&syscntl_p->scctrl) >> MODE_SHIFT) & MODE_MASK) 173 != NORMAL) 174 ; 175 } 176 177 /* 178 * get_socrev 179 * 180 * Get SoC Revision. 181 * @return SOC_SPEARXXX 182 */ 183 int get_socrev(void) 184 { 185 #if defined(CONFIG_SPEAR600) 186 struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; 187 u32 soc_id = readl(&misc_p->soc_core_id); 188 u32 pri_socid = (soc_id >> SOC_PRI_SHFT) & 0xFF; 189 u32 sec_socid = (soc_id >> SOC_SEC_SHFT) & 0xFF; 190 191 if ((pri_socid == 'B') && (sec_socid == 'B')) 192 return SOC_SPEAR600_BB; 193 else if ((pri_socid == 'B') && (sec_socid == 'C')) 194 return SOC_SPEAR600_BC; 195 else if ((pri_socid == 'B') && (sec_socid == 'D')) 196 return SOC_SPEAR600_BD; 197 else if (soc_id == 0) 198 return SOC_SPEAR600_BA; 199 else 200 return SOC_SPEAR_NA; 201 #elif defined(CONFIG_SPEAR300) 202 return SOC_SPEAR300; 203 #elif defined(CONFIG_SPEAR310) 204 return SOC_SPEAR310; 205 #elif defined(CONFIG_SPEAR320) 206 return SOC_SPEAR320; 207 #endif 208 } 209 210 /* 211 * SNOR (Serial NOR flash) related functions 212 */ 213 static void snor_init(void) 214 { 215 struct smi_regs *const smicntl = 216 (struct smi_regs * const)CONFIG_SYS_SMI_BASE; 217 218 /* Setting the fast mode values. SMI working at 166/4 = 41.5 MHz */ 219 writel(HOLD1 | FAST_MODE | BANK_EN | DSEL_TIME | PRESCAL4, 220 &smicntl->smi_cr1); 221 } 222 223 u32 spl_boot_device(void) 224 { 225 u32 mode = 0; 226 227 /* Currently only SNOR is supported as the only */ 228 if (snor_boot_selected()) { 229 /* SNOR-SMI initialization */ 230 snor_init(); 231 232 mode = BOOT_DEVICE_NOR; 233 } 234 235 return mode; 236 } 237 238 void board_init_f(ulong dummy) 239 { 240 struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; 241 242 /* Initialize PLLs */ 243 sys_init(); 244 245 preloader_console_init(); 246 arch_cpu_init(); 247 248 /* Enable IPs (release reset) */ 249 writel(PERIPH_RST_ALL, &misc_p->periph1_rst); 250 251 /* Initialize MPMC */ 252 puts("Configure DDR\n"); 253 mpmc_init(); 254 spear_late_init(); 255 256 board_init_r(NULL, 0); 257 } 258