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