Skip to content

Commit 7f91ae3

Browse files
committed
lk2nd: smp: add msm8994 cpu boot support
Signed-off-by: Eugene Lepshy <[email protected]>
1 parent 2008249 commit 7f91ae3

File tree

4 files changed

+301
-0
lines changed

4 files changed

+301
-0
lines changed

lk2nd/smp/cpu-boot.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ bool cpu_boot(const void *dtb, int node, uint32_t mpidr)
9090
*/
9191
extra_reg = read_phandle_reg(dtb, node, "clocks");
9292
cpu_boot_cortex_a(acc, extra_reg);
93+
#elif CPU_BOOT_CORTEX_A_MSM8994
94+
cpu_boot_cortex_a_msm8994(mpidr);
9395
#elif CPU_BOOT_KPSSV1
9496
extra_reg = read_phandle_reg(dtb, node, "qcom,saw");
9597
if (!extra_reg)

lk2nd/smp/cpu-boot.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@ int cpu_boot_set_addr(uintptr_t addr, bool arm64);
66

77
bool cpu_boot(const void *dtb, int node, uint32_t mpidr);
88
void cpu_boot_cortex_a(uint32_t base, uint32_t apcs_base);
9+
10+
/**
11+
* cpu_boot_cortex_a_msm8994() - This function enables msm8994/2 core
12+
* @mpidr: This param used to determine which exactly core this function enables
13+
*
14+
* As l2 cache for first(boot) cluster enabled by lk1st,
15+
* this function skips it and work only for second cluster
16+
*/
17+
void cpu_boot_cortex_a_msm8994(uint32_t mpidr);
918
void cpu_boot_kpssv1(uint32_t reg, uint32_t saw_reg);
1019
void cpu_boot_kpssv2(uint32_t reg, uint32_t l2_saw_base);
1120

lk2nd/smp/gpl/cortex-a-msm8994.c

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
3+
#include <arch/defines.h>
4+
#include <bits.h>
5+
#include <debug.h>
6+
#include <kernel/thread.h>
7+
#include <platform/timer.h>
8+
#include <reg.h>
9+
10+
#include "../cpu-boot.h"
11+
12+
#define CPU_PWR_CTL 0x4
13+
#define APC_PWR_GATE_CTL 0x14
14+
15+
#define L1_RST_DIS 0x284
16+
17+
#define L2_VREG_CTL 0x1c
18+
#define L2_PWR_CTL 0x14
19+
#define L2_PWR_CTL_OVERRIDE 0xc
20+
#define L2_PWR_STATUS_L2_HS_STS_MSM8994 (BIT(9) | BIT(28))
21+
22+
// delay for voltage to settle on the core
23+
#define REGULATOR_SETUP_VOLTAGE_TIMEOUT 2000
24+
25+
/**
26+
* enum msm8994_cpu_node_mpidrs - Enum that used for mapping cores and its mpidrs
27+
*/
28+
enum msm8994_cpu_node_mpidrs {
29+
CPU0 = 0x0,
30+
CPU1 = 0x1,
31+
CPU2 = 0x2,
32+
CPU3 = 0x3,
33+
CPU4 = 0x100,
34+
CPU5 = 0x101,
35+
CPU6 = 0x102,
36+
CPU7 = 0x103,
37+
};
38+
39+
/**
40+
* enum msm8994_cpu_clusters - Enum that used for clusters
41+
* @first: describes little cluster
42+
* @second: describes BIG cluster
43+
*/
44+
enum msm8994_cpu_clusters {
45+
first,
46+
second,
47+
};
48+
49+
/**
50+
* struct msm8994_cpu_info - This struct used to describe the core values
51+
* needed to enable it
52+
* @base: this value had got from downstream dts this way: cpu@X -> qcom,acc -> reg
53+
* @cache_info: description of next-level-cache node in cpu@X
54+
*/
55+
struct msm8994_cpu_info {
56+
uint32_t base;
57+
const struct msm8994_cpu_cache_info *cache_info;
58+
};
59+
60+
/**
61+
* struct msm8994_cpu_cache_info - This struct used to describe cache node
62+
* (and children's) values needed to enable the cpu cache
63+
* @l2ccc_base: this value had got from downstream dts this way: l2-cache -> power-domain -> reg
64+
* @vctl_base_0: l2-cache -> power-domain -> qcom,vctl-node -> reg (first value of first tuple)
65+
* @vctl_base_1: l2-cache -> power-domain -> qcom,vctl-node -> reg (first value of second tuple)
66+
* @vctl_val: l2-cache -> power-domain -> qcom,vctl-val (may be absent, then set as 0)
67+
*/
68+
struct msm8994_cpu_cache_info {
69+
uint32_t l2ccc_base;
70+
uint32_t vctl_base_0;
71+
uint32_t vctl_base_1;
72+
uint32_t vctl_val;
73+
};
74+
75+
static const struct msm8994_cpu_cache_info cache_info[] = {
76+
[first] = {
77+
.l2ccc_base = 0xf900d000,
78+
.vctl_base_0 = 0xf9012000,
79+
.vctl_base_1 = 0xf900d210,
80+
.vctl_val = 0,
81+
},
82+
[second] = {
83+
.l2ccc_base = 0xf900f000,
84+
.vctl_base_0 = 0xf9013000,
85+
.vctl_base_1 = 0xf900f210,
86+
.vctl_val = 0xb8,
87+
},
88+
};
89+
90+
static const struct msm8994_cpu_info cpu_info[] = {
91+
[CPU0] = {
92+
.base = 0xf908b000,
93+
.cache_info = &cache_info[first],
94+
},
95+
[CPU1] = {
96+
.base = 0xf909b000,
97+
.cache_info = &cache_info[first],
98+
},
99+
[CPU2] = {
100+
.base = 0xf90ab000,
101+
.cache_info = &cache_info[first],
102+
},
103+
[CPU3] = {
104+
.base = 0xf90bb000,
105+
.cache_info = &cache_info[first],
106+
},
107+
[CPU4] = {
108+
.base = 0xf90cb000,
109+
.cache_info = &cache_info[second],
110+
},
111+
[CPU5] = {
112+
.base = 0xf90db000,
113+
.cache_info = &cache_info[second],
114+
},
115+
[CPU6] = {
116+
.base = 0xf90eb000,
117+
.cache_info = &cache_info[second],
118+
},
119+
[CPU7] = {
120+
.base = 0xf90fb000,
121+
.cache_info = &cache_info[second],
122+
},
123+
};
124+
125+
/**
126+
* msm_spm_turn_on_cpu_rail() - Power on cpu rail before turning on core
127+
* @vctl_base_0: first qcom,vctl-node reg address
128+
* @vctl_base_1: second qcom,vctl-node reg address
129+
* @vctl_val: The value to be set on the rail
130+
*/
131+
static void msm_spm_turn_on_cpu_rail(uint32_t vctl_base_0, uint32_t vctl_base_1,
132+
unsigned int vctl_val)
133+
{
134+
if (vctl_base_1) {
135+
/*
136+
* Program Q2S to disable SPM legacy mode and ignore Q2S
137+
* channel requests.
138+
* bit[1] = qchannel_ignore = 1
139+
* bit[2] = spm_legacy_mode = 0
140+
*/
141+
writel(0x2, vctl_base_1);
142+
dsb();
143+
}
144+
145+
/* Set the CPU supply regulator voltage */
146+
vctl_val = (vctl_val & 0xFF);
147+
writel(vctl_val, vctl_base_0 + L2_VREG_CTL);
148+
dsb();
149+
udelay(REGULATOR_SETUP_VOLTAGE_TIMEOUT);
150+
151+
/* Enable the CPU supply regulator*/
152+
vctl_val = 0x30080;
153+
writel(vctl_val, vctl_base_0 + L2_VREG_CTL);
154+
dsb();
155+
udelay(REGULATOR_SETUP_VOLTAGE_TIMEOUT);
156+
}
157+
158+
/**
159+
* power_on_l2_cache_msm8994() - This function used to enable l2 cache
160+
* @l2ccc_base: value of l2 clock controller reg
161+
* @vctl_base_0: first qcom,vctl-node reg address
162+
* @vctl_base_1: second qcom,vctl-node reg address
163+
* @vctl_val: The value to be set on the rail
164+
*
165+
* As l2 cache for first(boot) cluster enabled by lk1st,
166+
* this function skips it and work only for second cluster
167+
* Function has a check if cache at @l2ccc_base already enabled
168+
*/
169+
static void power_on_l2_cache_msm8994(uint32_t l2ccc_base, uint32_t vctl_base_0,
170+
uint32_t vctl_base_1, uint32_t vctl_val) {
171+
/* Skip if cluster L2 is already powered on */
172+
if (readl(l2ccc_base + L2_PWR_CTL) & L2_PWR_STATUS_L2_HS_STS_MSM8994)
173+
return;
174+
175+
dprintf(INFO, "Powering on L2 cache @ %#08x\n", l2ccc_base);
176+
177+
if(vctl_val != 0) {
178+
dprintf(INFO, "Not found qcom,vctl-val for this l2 cache node, so skip msm_spm_turn_on_cpu_rail\n");
179+
msm_spm_turn_on_cpu_rail(vctl_base_0, vctl_base_1, vctl_val);
180+
}
181+
182+
enter_critical_section();
183+
184+
/* Enable L1 invalidation by h/w */
185+
writel(0x00000000, l2ccc_base + L1_RST_DIS);
186+
dsb();
187+
188+
/* Assert PRESETDBGn */
189+
writel(0x00400000 , l2ccc_base + L2_PWR_CTL_OVERRIDE);
190+
dsb();
191+
192+
/* Close L2/SCU Logic GDHS and power up the cache */
193+
writel(0x00029716 , l2ccc_base + L2_PWR_CTL);
194+
dsb();
195+
udelay(8);
196+
197+
/* De-assert L2/SCU memory Clamp */
198+
writel(0x00023716 , l2ccc_base + L2_PWR_CTL);
199+
dsb();
200+
201+
/* Wakeup L2/SCU RAMs by deasserting sleep signals */
202+
writel(0x0002371E , l2ccc_base + L2_PWR_CTL);
203+
dsb();
204+
udelay(8);
205+
206+
/* Un-gate clock and wait for sequential waking up
207+
* of L2 rams with a delay of 2*X0 cycles
208+
*/
209+
writel(0x0002371C , l2ccc_base + L2_PWR_CTL);
210+
dsb();
211+
udelay(4);
212+
213+
/* De-assert L2/SCU logic clamp */
214+
writel(0x0002361C , l2ccc_base + L2_PWR_CTL);
215+
dsb();
216+
udelay(2);
217+
218+
/* De-assert L2/SCU logic reset */
219+
writel(0x00022218 , l2ccc_base + L2_PWR_CTL);
220+
dsb();
221+
udelay(4);
222+
223+
/* Turn on the PMIC_APC */
224+
writel(0x10022218 , l2ccc_base + L2_PWR_CTL);
225+
dsb();
226+
227+
/* De-assert PRESETDBGn */
228+
writel(0x00000000 , l2ccc_base + L2_PWR_CTL_OVERRIDE);
229+
dsb();
230+
exit_critical_section();
231+
}
232+
233+
void cpu_boot_cortex_a_msm8994(uint32_t mpidr)
234+
{
235+
uint32_t base, l2ccc_base, vctl_base_0, vctl_base_1, vctl_val;
236+
237+
struct msm8994_cpu_info *info = &cpu_info[mpidr];
238+
base = info->base;
239+
l2ccc_base = info->cache_info->l2ccc_base;
240+
vctl_base_0 = info->cache_info->vctl_base_0;
241+
vctl_base_1 = info->cache_info->vctl_base_1;
242+
vctl_val = info->cache_info->vctl_val;
243+
244+
if (l2ccc_base)
245+
power_on_l2_cache_msm8994(l2ccc_base, vctl_base_0, vctl_base_1, vctl_val);
246+
247+
enter_critical_section();
248+
249+
/* Assert head switch enable few */
250+
writel(0x00000001, base + APC_PWR_GATE_CTL);
251+
dsb();
252+
udelay(1);
253+
254+
/* Assert head switch enable rest */
255+
writel(0x00000003, base + APC_PWR_GATE_CTL);
256+
dsb();
257+
udelay(1);
258+
259+
/* De-assert coremem clamp. This is asserted by default */
260+
writel(0x00000079, base + CPU_PWR_CTL);
261+
dsb();
262+
udelay(2);
263+
264+
/* Close coremem array gdhs */
265+
writel(0x0000007D, base + CPU_PWR_CTL);
266+
dsb();
267+
udelay(2);
268+
269+
/* De-assert clamp */
270+
writel(0x0000003D, base + CPU_PWR_CTL);
271+
dsb();
272+
273+
/* De-assert clamp */
274+
writel(0x0000003C, base + CPU_PWR_CTL);
275+
dsb();
276+
udelay(1);
277+
278+
/* De-assert core0 reset */
279+
writel(0x0000000C, base + CPU_PWR_CTL);
280+
dsb();
281+
282+
/* Assert PWRDUP */
283+
writel(0x0000008C, base + CPU_PWR_CTL);
284+
dsb();
285+
286+
exit_critical_section();
287+
}

lk2nd/smp/rules.mk

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ OBJS += $(patsubst %.c,%.o, $(wildcard $(LOCAL_DIR)/clock-$(PLATFORM).c))
88
ifneq ($(filter msm8226 msm8610 msm8909 msm8916, $(PLATFORM)),)
99
CPU_BOOT_OBJ := $(LOCAL_DIR)/cortex-a.o
1010
DEFINES += CPU_BOOT_CORTEX_A=1
11+
else ifneq ($(filter msm8994, $(PLATFORM)),)
12+
CPU_BOOT_OBJ := $(if $(BUILD_GPL), $(LOCAL_DIR)/gpl/cortex-a-msm8994.o)
13+
DEFINES += CPU_BOOT_CORTEX_A_MSM8994=1
1114
else ifneq ($(filter apq8084 msm8974, $(PLATFORM)),)
1215
CPU_BOOT_OBJ := $(if $(BUILD_GPL), $(LOCAL_DIR)/gpl/krait.o)
1316
DEFINES += CPU_BOOT_KPSSV2=1

0 commit comments

Comments
 (0)