1 /* 2 * Lowlevel setup for EXYNOS5 based board 3 * 4 * Copyright (C) 2013 Samsung Electronics 5 * Rajeshwari Shinde <rajeshwari.s@samsung.com> 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 <config.h> 28 #include <debug_uart.h> 29 #include <asm/arch/cpu.h> 30 #include <asm/arch/dmc.h> 31 #include <asm/arch/power.h> 32 #include <asm/arch/tzpc.h> 33 #include <asm/arch/periph.h> 34 #include <asm/arch/pinmux.h> 35 #include <asm/arch/system.h> 36 #include <asm/armv7.h> 37 #include "common_setup.h" 38 #include "exynos5_setup.h" 39 40 /* These are the things we can do during low-level init */ 41 enum { 42 DO_WAKEUP = 1 << 0, 43 DO_CLOCKS = 1 << 1, 44 DO_MEM_RESET = 1 << 2, 45 DO_UART = 1 << 3, 46 DO_POWER = 1 << 4, 47 }; 48 49 #ifdef CONFIG_EXYNOS5420 50 /* 51 * Power up secondary CPUs. 52 */ 53 static void secondary_cpu_start(void) 54 { 55 v7_enable_smp(EXYNOS5420_INFORM_BASE); 56 svc32_mode_en(); 57 branch_bx(CONFIG_EXYNOS_RELOCATE_CODE_BASE); 58 } 59 60 /* 61 * This is the entry point of hotplug-in and 62 * cluster switching. 63 */ 64 static void low_power_start(void) 65 { 66 uint32_t val, reg_val; 67 68 reg_val = readl(EXYNOS5420_SPARE_BASE); 69 if (reg_val != CPU_RST_FLAG_VAL) { 70 writel(0x0, CONFIG_LOWPOWER_FLAG); 71 branch_bx(0x0); 72 } 73 74 reg_val = readl(CONFIG_PHY_IRAM_BASE + 0x4); 75 if (reg_val != (uint32_t)&low_power_start) { 76 /* Store jump address as low_power_start if not present */ 77 writel((uint32_t)&low_power_start, CONFIG_PHY_IRAM_BASE + 0x4); 78 dsb(); 79 sev(); 80 } 81 82 /* Set the CPU to SVC32 mode */ 83 svc32_mode_en(); 84 85 #ifndef CONFIG_SYS_L2CACHE_OFF 86 /* Read MIDR for Primary Part Number */ 87 mrc_midr(val); 88 val = (val >> 4); 89 val &= 0xf; 90 91 if (val == 0xf) { 92 configure_l2_ctlr(); 93 configure_l2_actlr(); 94 v7_enable_l2_hazard_detect(); 95 } 96 #endif 97 98 /* Invalidate L1 & TLB */ 99 val = 0x0; 100 mcr_tlb(val); 101 mcr_icache(val); 102 103 /* Disable MMU stuff and caches */ 104 mrc_sctlr(val); 105 106 val &= ~((0x2 << 12) | 0x7); 107 val |= ((0x1 << 12) | (0x8 << 8) | 0x2); 108 mcr_sctlr(val); 109 110 /* CPU state is hotplug or reset */ 111 secondary_cpu_start(); 112 113 /* Core should not enter into WFI here */ 114 wfi(); 115 } 116 117 /* 118 * Pointer to this function is stored in iRam which is used 119 * for jump and power down of a specific core. 120 */ 121 static void power_down_core(void) 122 { 123 uint32_t tmp, core_id, core_config; 124 125 /* Get the unique core id */ 126 /* 127 * Multiprocessor Affinity Register 128 * [11:8] Cluster ID 129 * [1:0] CPU ID 130 */ 131 mrc_mpafr(core_id); 132 tmp = core_id & 0x3; 133 core_id = (core_id >> 6) & ~3; 134 core_id |= tmp; 135 core_id &= 0x3f; 136 137 /* Set the status of the core to low */ 138 core_config = (core_id * CPU_CONFIG_STATUS_OFFSET); 139 core_config += EXYNOS5420_CPU_CONFIG_BASE; 140 writel(0x0, core_config); 141 142 /* Core enter WFI */ 143 wfi(); 144 } 145 146 /* 147 * Configurations for secondary cores are inapt at this stage. 148 * Reconfigure secondary cores. Shutdown and change the status 149 * of all cores except the primary core. 150 */ 151 static void secondary_cores_configure(void) 152 { 153 /* Clear secondary boot iRAM base */ 154 writel(0x0, (CONFIG_EXYNOS_RELOCATE_CODE_BASE + 0x1C)); 155 156 /* set lowpower flag and address */ 157 writel(CPU_RST_FLAG_VAL, CONFIG_LOWPOWER_FLAG); 158 writel((uint32_t)&low_power_start, CONFIG_LOWPOWER_ADDR); 159 writel(CPU_RST_FLAG_VAL, EXYNOS5420_SPARE_BASE); 160 /* Store jump address for power down */ 161 writel((uint32_t)&power_down_core, CONFIG_PHY_IRAM_BASE + 0x4); 162 163 /* Need all core power down check */ 164 dsb(); 165 sev(); 166 } 167 168 extern void relocate_wait_code(void); 169 #endif 170 171 int do_lowlevel_init(void) 172 { 173 uint32_t reset_status; 174 int actions = 0; 175 176 arch_cpu_init(); 177 178 #if !defined(CONFIG_SYS_L2CACHE_OFF) && defined(CONFIG_EXYNOS5420) 179 /* 180 * Init L2 cache parameters here for use by boot and resume 181 * 182 * These are here instead of in v7_outer_cache_enable() so that the 183 * L2 cache settings get properly set even at resume time or if we're 184 * running U-Boot with the cache off. The kernel still needs us to 185 * set these for it. 186 */ 187 configure_l2_ctlr(); 188 configure_l2_actlr(); 189 dsb(); 190 isb(); 191 192 relocate_wait_code(); 193 194 /* Reconfigure secondary cores */ 195 secondary_cores_configure(); 196 #endif 197 198 reset_status = get_reset_status(); 199 200 switch (reset_status) { 201 case S5P_CHECK_SLEEP: 202 actions = DO_CLOCKS | DO_WAKEUP; 203 break; 204 case S5P_CHECK_DIDLE: 205 case S5P_CHECK_LPA: 206 actions = DO_WAKEUP; 207 break; 208 default: 209 /* This is a normal boot (not a wake from sleep) */ 210 actions = DO_CLOCKS | DO_MEM_RESET | DO_POWER; 211 } 212 213 if (actions & DO_POWER) 214 set_ps_hold_ctrl(); 215 216 if (actions & DO_CLOCKS) { 217 system_clock_init(); 218 #ifdef CONFIG_DEBUG_UART 219 exynos_pinmux_config(PERIPH_ID_UART3, PINMUX_FLAG_NONE); 220 debug_uart_init(); 221 #endif 222 mem_ctrl_init(actions & DO_MEM_RESET); 223 tzpc_init(); 224 } 225 226 return actions & DO_WAKEUP; 227 } 228