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 34 inline void hang(void) 35 { 36 serial_puts("### ERROR ### Please RESET the board ###\n"); 37 for (;;) 38 ; 39 } 40 41 static 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 71 static 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 92 static 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 107 static 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 131 static 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 166 static 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 */ 204 int 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 231 void 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 269 void 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