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