xref: /OK3568_Linux_fs/u-boot/arch/arm/mach-exynos/lowlevel_init.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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