]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/armv7/exynos/lowlevel_init.c
Exynos542x: Add workaround for exynos iROM errata
[karo-tx-uboot.git] / arch / arm / cpu / armv7 / exynos / lowlevel_init.c
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 <asm/arch/cpu.h>
29 #include <asm/arch/dmc.h>
30 #include <asm/arch/power.h>
31 #include <asm/arch/tzpc.h>
32 #include <asm/arch/periph.h>
33 #include <asm/arch/pinmux.h>
34 #include <asm/arch/system.h>
35 #include <asm/armv7.h>
36 #include "common_setup.h"
37 #include "exynos5_setup.h"
38
39 /* These are the things we can do during low-level init */
40 enum {
41         DO_WAKEUP       = 1 << 0,
42         DO_CLOCKS       = 1 << 1,
43         DO_MEM_RESET    = 1 << 2,
44         DO_UART         = 1 << 3,
45         DO_POWER        = 1 << 4,
46 };
47
48 #ifdef CONFIG_EXYNOS5420
49 /*
50  * Power up secondary CPUs.
51  */
52 static void secondary_cpu_start(void)
53 {
54         v7_enable_smp(EXYNOS5420_INFORM_BASE);
55         svc32_mode_en();
56         set_pc(CONFIG_EXYNOS_RELOCATE_CODE_BASE);
57 }
58
59 /*
60  * This is the entry point of hotplug-in and
61  * cluster switching.
62  */
63 static void low_power_start(void)
64 {
65         uint32_t val, reg_val;
66
67         reg_val = readl(EXYNOS5420_SPARE_BASE);
68         if (reg_val != CPU_RST_FLAG_VAL) {
69                 writel(0x0, CONFIG_LOWPOWER_FLAG);
70                 set_pc(0x0);
71         }
72
73         reg_val = readl(CONFIG_PHY_IRAM_BASE + 0x4);
74         if (reg_val != (uint32_t)&low_power_start) {
75                 /* Store jump address as low_power_start if not present */
76                 writel((uint32_t)&low_power_start, CONFIG_PHY_IRAM_BASE + 0x4);
77                 dsb();
78                 sev();
79         }
80
81         /* Set the CPU to SVC32 mode */
82         svc32_mode_en();
83         v7_enable_l2_hazard_detect();
84
85         /* Invalidate L1 & TLB */
86         val = 0x0;
87         mcr_tlb(val);
88         mcr_icache(val);
89
90         /* Disable MMU stuff and caches */
91         mrc_sctlr(val);
92
93         val &= ~((0x2 << 12) | 0x7);
94         val |= ((0x1 << 12) | (0x8 << 8) | 0x2);
95         mcr_sctlr(val);
96
97         /* CPU state is hotplug or reset */
98         secondary_cpu_start();
99
100         /* Core should not enter into WFI here */
101         wfi();
102 }
103
104 /*
105  * Pointer to this function is stored in iRam which is used
106  * for jump and power down of a specific core.
107  */
108 static void power_down_core(void)
109 {
110         uint32_t tmp, core_id, core_config;
111
112         /* Get the unique core id */
113         /*
114          * Multiprocessor Affinity Register
115          * [11:8]       Cluster ID
116          * [1:0]        CPU ID
117          */
118         mrc_mpafr(core_id);
119         tmp = core_id & 0x3;
120         core_id = (core_id >> 6) & ~3;
121         core_id |= tmp;
122         core_id &= 0x3f;
123
124         /* Set the status of the core to low */
125         core_config = (core_id * CPU_CONFIG_STATUS_OFFSET);
126         core_config += EXYNOS5420_CPU_CONFIG_BASE;
127         writel(0x0, core_config);
128
129         /* Core enter WFI */
130         wfi();
131 }
132
133 /*
134  * Configurations for secondary cores are inapt at this stage.
135  * Reconfigure secondary cores. Shutdown and change the status
136  * of all cores except the primary core.
137  */
138 static void secondary_cores_configure(void)
139 {
140         /* Setup L2 cache */
141         v7_enable_l2_hazard_detect();
142
143         /* Clear secondary boot iRAM base */
144         writel(0x0, (CONFIG_EXYNOS_RELOCATE_CODE_BASE + 0x1C));
145
146         /* set lowpower flag and address */
147         writel(CPU_RST_FLAG_VAL, CONFIG_LOWPOWER_FLAG);
148         writel((uint32_t)&low_power_start, CONFIG_LOWPOWER_ADDR);
149         writel(CPU_RST_FLAG_VAL, EXYNOS5420_SPARE_BASE);
150         /* Store jump address for power down */
151         writel((uint32_t)&power_down_core, CONFIG_PHY_IRAM_BASE + 0x4);
152
153         /* Need all core power down check */
154         dsb();
155         sev();
156 }
157
158 extern void relocate_wait_code(void);
159 #endif
160
161 int do_lowlevel_init(void)
162 {
163         uint32_t reset_status;
164         int actions = 0;
165
166         arch_cpu_init();
167
168 #ifdef CONFIG_EXYNOS5420
169         relocate_wait_code();
170
171         /* Reconfigure secondary cores */
172         secondary_cores_configure();
173 #endif
174
175         reset_status = get_reset_status();
176
177         switch (reset_status) {
178         case S5P_CHECK_SLEEP:
179                 actions = DO_CLOCKS | DO_WAKEUP;
180                 break;
181         case S5P_CHECK_DIDLE:
182         case S5P_CHECK_LPA:
183                 actions = DO_WAKEUP;
184                 break;
185         default:
186                 /* This is a normal boot (not a wake from sleep) */
187                 actions = DO_CLOCKS | DO_MEM_RESET | DO_POWER;
188         }
189
190         if (actions & DO_POWER)
191                 set_ps_hold_ctrl();
192
193         if (actions & DO_CLOCKS) {
194                 system_clock_init();
195                 mem_ctrl_init(actions & DO_MEM_RESET);
196                 tzpc_init();
197         }
198
199         return actions & DO_WAKEUP;
200 }