xref: /rk3399_ARM-atf/drivers/renesas/rcar_gen4/pwrc/pwrc.c (revision b8ad1a16d501c7a32e72d674a70b76320dbf9a1e)
1b45b5bacSMarek Vasut /*
2b45b5bacSMarek Vasut  * Copyright (c) 2015-2025, Renesas Electronics Corporation. All rights reserved.
3b45b5bacSMarek Vasut  *
4b45b5bacSMarek Vasut  * SPDX-License-Identifier: BSD-3-Clause
5b45b5bacSMarek Vasut  */
6b45b5bacSMarek Vasut 
7b45b5bacSMarek Vasut #include <assert.h>
8b45b5bacSMarek Vasut #include <string.h>
9b45b5bacSMarek Vasut 
10b45b5bacSMarek Vasut #include <arch.h>
11b45b5bacSMarek Vasut #include <arch_helpers.h>
12b45b5bacSMarek Vasut #include <common/debug.h>
13b45b5bacSMarek Vasut #include <lib/bakery_lock.h>
14b45b5bacSMarek Vasut #include <lib/mmio.h>
15b45b5bacSMarek Vasut #include <lib/xlat_tables/xlat_tables_v2.h>
16b45b5bacSMarek Vasut #include <plat/common/platform.h>
17b45b5bacSMarek Vasut 
18b45b5bacSMarek Vasut #include "pwrc.h"
19*92196d4fSMarek Vasut #include "timer.h"
20*92196d4fSMarek Vasut 
21b45b5bacSMarek Vasut #include "rcar_def.h"
22b45b5bacSMarek Vasut #include "rcar_private.h"
23b45b5bacSMarek Vasut 
24b45b5bacSMarek Vasut #ifndef __ASSEMBLER__
25b45b5bacSMarek Vasut IMPORT_SYM(uintptr_t, __system_ram_start__, SYSTEM_RAM_START);
26b45b5bacSMarek Vasut IMPORT_SYM(uintptr_t, __system_ram_end__, SYSTEM_RAM_END);
27b45b5bacSMarek Vasut IMPORT_SYM(uintptr_t, __SRAM_COPY_START__, SRAM_COPY_START);
28b45b5bacSMarek Vasut #endif /*__ASSEMBLER__*/
29b45b5bacSMarek Vasut 
30b45b5bacSMarek Vasut #define	RCAR_CODE_COPY_NONE	0
31b45b5bacSMarek Vasut #define	RCAR_CODE_COPY_DONE	1
32b45b5bacSMarek Vasut 
33b45b5bacSMarek Vasut static uint32_t dummy_sdram = 0xAAAAAAAA;
34b45b5bacSMarek Vasut static uint32_t rcar_pwrc_code_copy_state;
35b45b5bacSMarek Vasut 
36b45b5bacSMarek Vasut /*
37b45b5bacSMarek Vasut  * Someday there will be a generic power controller API. At the moment each
38b45b5bacSMarek Vasut  * platform has its own PWRC so just exporting functions should be acceptable.
39b45b5bacSMarek Vasut  */
40b45b5bacSMarek Vasut static RCAR_INSTANTIATE_LOCK;
41b45b5bacSMarek Vasut 
42b45b5bacSMarek Vasut static u_register_t rcar_boot_mpidr;
43b45b5bacSMarek Vasut 
44b45b5bacSMarek Vasut /* APSREG boot configuration */
apsreg_ap_cluster_aux0(uint32_t n)45b45b5bacSMarek Vasut static uintptr_t apsreg_ap_cluster_aux0(uint32_t n)
46b45b5bacSMarek Vasut {
47b45b5bacSMarek Vasut 	return APSREG_BASE + 0x10UL + ((n & 0x3) * 0x1000UL);
48b45b5bacSMarek Vasut }
49b45b5bacSMarek Vasut 
50b45b5bacSMarek Vasut /* APMU */
rcar_apmu_cluster_base(uint32_t n)51b45b5bacSMarek Vasut static uintptr_t rcar_apmu_cluster_base(uint32_t n)
52b45b5bacSMarek Vasut {
53b45b5bacSMarek Vasut 	return RCAR_APMU_BASE + 0x400UL + ((n & 0x3) * 0x40UL);
54b45b5bacSMarek Vasut }
55b45b5bacSMarek Vasut 
rcar_apmu_cpu_base(uint32_t n)56b45b5bacSMarek Vasut static uintptr_t rcar_apmu_cpu_base(uint32_t n)
57b45b5bacSMarek Vasut {
58b45b5bacSMarek Vasut 	return RCAR_APMU_BASE + 0x800UL + ((n & 0x6) * 0x100UL) +
59b45b5bacSMarek Vasut 	       ((n & 0x1) * 0x40UL);
60b45b5bacSMarek Vasut }
61b45b5bacSMarek Vasut 
rcar_apmu_pwrctrlcl(uint32_t n)62b45b5bacSMarek Vasut static uintptr_t rcar_apmu_pwrctrlcl(uint32_t n)
63b45b5bacSMarek Vasut {
64b45b5bacSMarek Vasut 	return rcar_apmu_cluster_base(n);
65b45b5bacSMarek Vasut }
66b45b5bacSMarek Vasut 
rcar_apmu_pwrctrlc(uint32_t n)67b45b5bacSMarek Vasut static uintptr_t rcar_apmu_pwrctrlc(uint32_t n)
68b45b5bacSMarek Vasut {
69b45b5bacSMarek Vasut 	return rcar_apmu_cpu_base(n);
70b45b5bacSMarek Vasut }
71b45b5bacSMarek Vasut 
rcar_apmu_safectrlc(uint32_t n)72b45b5bacSMarek Vasut static uintptr_t rcar_apmu_safectrlc(uint32_t n)
73b45b5bacSMarek Vasut {
74b45b5bacSMarek Vasut 	return rcar_apmu_cpu_base(n) + 0x20UL;
75b45b5bacSMarek Vasut }
76b45b5bacSMarek Vasut 
rcar_apmu_rvbarplc(uint32_t n)77b45b5bacSMarek Vasut static uintptr_t rcar_apmu_rvbarplc(uint32_t n)
78b45b5bacSMarek Vasut {
79b45b5bacSMarek Vasut 	return rcar_apmu_cpu_base(n) + 0x38UL;
80b45b5bacSMarek Vasut }
81b45b5bacSMarek Vasut 
rcar_apmu_rvbarphc(uint32_t n)82b45b5bacSMarek Vasut static uintptr_t rcar_apmu_rvbarphc(uint32_t n)
83b45b5bacSMarek Vasut {
84b45b5bacSMarek Vasut 	return rcar_apmu_cpu_base(n) + 0x3cUL;
85b45b5bacSMarek Vasut }
86b45b5bacSMarek Vasut 
rcar_apmu_fsmstsrc(uint32_t n)87b45b5bacSMarek Vasut static uintptr_t rcar_apmu_fsmstsrc(uint32_t n)
88b45b5bacSMarek Vasut {
89b45b5bacSMarek Vasut 	return rcar_apmu_cpu_base(n) + 0x18UL;
90b45b5bacSMarek Vasut }
91b45b5bacSMarek Vasut 
92b45b5bacSMarek Vasut /* Product register */
prr_caxx_xx_en_cpu(uint32_t n)93b45b5bacSMarek Vasut static uint32_t prr_caxx_xx_en_cpu(uint32_t n)
94b45b5bacSMarek Vasut {
95b45b5bacSMarek Vasut 	return BIT(n & 0x1);
96b45b5bacSMarek Vasut }
97b45b5bacSMarek Vasut 
write_cpupwrctlr(u_register_t v)98b45b5bacSMarek Vasut static void write_cpupwrctlr(u_register_t v)
99b45b5bacSMarek Vasut {
100b45b5bacSMarek Vasut 	__asm__ volatile ("msr S3_0_C15_C2_7, %0" : : "r" (v));
101b45b5bacSMarek Vasut }
102b45b5bacSMarek Vasut 
rcar_pwrc_core_pos(u_register_t mpidr)103b45b5bacSMarek Vasut static uint32_t rcar_pwrc_core_pos(u_register_t mpidr)
104b45b5bacSMarek Vasut {
105b45b5bacSMarek Vasut 	int cpu;
106b45b5bacSMarek Vasut 
107b45b5bacSMarek Vasut 	cpu = plat_core_pos_by_mpidr(mpidr);
108b45b5bacSMarek Vasut 	if (cpu < 0) {
109b45b5bacSMarek Vasut 		ERROR("BL3-1 : The value of passed MPIDR is invalid.");
110b45b5bacSMarek Vasut 		panic();
111b45b5bacSMarek Vasut 	}
112b45b5bacSMarek Vasut 
113b45b5bacSMarek Vasut 	return (uint32_t)cpu;
114b45b5bacSMarek Vasut }
115b45b5bacSMarek Vasut 
rcar_pwrc_cpuon(u_register_t mpidr)116b45b5bacSMarek Vasut void rcar_pwrc_cpuon(u_register_t mpidr)
117b45b5bacSMarek Vasut {
118b45b5bacSMarek Vasut 	uint32_t cluster, cpu;
119b45b5bacSMarek Vasut 
120b45b5bacSMarek Vasut 	rcar_lock_get();
121b45b5bacSMarek Vasut 
122b45b5bacSMarek Vasut 	cpu = rcar_pwrc_core_pos(mpidr);
123b45b5bacSMarek Vasut 
124b45b5bacSMarek Vasut 	cluster = rcar_pwrc_get_mpidr_cluster(mpidr);
125b45b5bacSMarek Vasut 
126b45b5bacSMarek Vasut 	/* clear Cluster OFF bit */
127b45b5bacSMarek Vasut 	mmio_clrbits_32(rcar_apmu_pwrctrlcl(cluster),
128b45b5bacSMarek Vasut 			RCAR_APMU_PWRCTRLCL_PCHPDNEN);
129b45b5bacSMarek Vasut 
130b45b5bacSMarek Vasut 	/* clear Core OFF bit */
131b45b5bacSMarek Vasut 	mmio_clrbits_32(rcar_apmu_pwrctrlc(cpu), RCAR_APMU_PWRCTRLC_PCHPDNEN);
132b45b5bacSMarek Vasut 	while (mmio_read_32(rcar_apmu_pwrctrlc(cpu)) & RCAR_APMU_PWRCTRLC_PCHPDNEN)
133b45b5bacSMarek Vasut 		;
134b45b5bacSMarek Vasut 
135b45b5bacSMarek Vasut 	mmio_setbits_32(rcar_apmu_pwrctrlc(cpu), RCAR_APMU_PWRCTRLC_WUP_REQ);
136b45b5bacSMarek Vasut 
137b45b5bacSMarek Vasut 	/* Wait until CAXX wake up sequence finishes */
138b45b5bacSMarek Vasut 	while ((mmio_read_32(rcar_apmu_pwrctrlc(cpu)) & RCAR_APMU_PWRCTRLC_WUP_REQ) ==
139b45b5bacSMarek Vasut 	       RCAR_APMU_PWRCTRLC_WUP_REQ)
140b45b5bacSMarek Vasut 		;
141b45b5bacSMarek Vasut 
142b45b5bacSMarek Vasut 	rcar_lock_release();
143b45b5bacSMarek Vasut 
144b45b5bacSMarek Vasut 	/*
145b45b5bacSMarek Vasut 	 * mask should match the kernel's MPIDR_HWID_BITMASK so the core can be
146b45b5bacSMarek Vasut 	 * identified during cpuhotplug (check the kernel's psci migrate set of
147b45b5bacSMarek Vasut 	 * functions
148b45b5bacSMarek Vasut 	 */
149b45b5bacSMarek Vasut 	rcar_boot_mpidr = read_mpidr_el1() & RCAR_MPIDR_AFFMASK;
150b45b5bacSMarek Vasut }
151b45b5bacSMarek Vasut 
rcar_pwrc_cpu_migrate_info(u_register_t * resident_cpu)152b45b5bacSMarek Vasut int32_t rcar_pwrc_cpu_migrate_info(u_register_t *resident_cpu)
153b45b5bacSMarek Vasut {
154b45b5bacSMarek Vasut 	*resident_cpu = rcar_boot_mpidr;
155b45b5bacSMarek Vasut 
156b45b5bacSMarek Vasut 	return PSCI_TOS_NOT_UP_MIG_CAP;
157b45b5bacSMarek Vasut }
158b45b5bacSMarek Vasut 
rcar_pwrc_mpidr_is_boot_cpu(u_register_t mpidr)159b45b5bacSMarek Vasut bool rcar_pwrc_mpidr_is_boot_cpu(u_register_t mpidr)
160b45b5bacSMarek Vasut {
161b45b5bacSMarek Vasut 	return (mpidr & RCAR_MPIDR_AFFMASK) == rcar_boot_mpidr;
162b45b5bacSMarek Vasut }
163b45b5bacSMarek Vasut 
rcar_pwrc_cpuoff_sub(uint32_t cpu)164b45b5bacSMarek Vasut static void rcar_pwrc_cpuoff_sub(uint32_t cpu)
165b45b5bacSMarek Vasut {
166b45b5bacSMarek Vasut 	/* Clear DBGGEN_PPDN bit for core down to 'OFF' mode */
167b45b5bacSMarek Vasut 	mmio_clrbits_32(rcar_apmu_safectrlc(cpu), RCAR_APMU_SAFECTRLC_DBGGEN);
168b45b5bacSMarek Vasut 	/* for Core OFF */
169b45b5bacSMarek Vasut 	mmio_setbits_32(rcar_apmu_pwrctrlc(cpu), RCAR_APMU_PWRCTRLC_PCHPDNEN);
170b45b5bacSMarek Vasut 
171b45b5bacSMarek Vasut 	write_cpupwrctlr(CPUPWRCTLR_PWDN);
172b45b5bacSMarek Vasut }
173b45b5bacSMarek Vasut 
rcar_pwrc_cpuoff(u_register_t mpidr)174b45b5bacSMarek Vasut void rcar_pwrc_cpuoff(u_register_t mpidr)
175b45b5bacSMarek Vasut {
176b45b5bacSMarek Vasut 	uint32_t cpu;
177b45b5bacSMarek Vasut 
178b45b5bacSMarek Vasut 	rcar_lock_get();
179b45b5bacSMarek Vasut 
180b45b5bacSMarek Vasut 	cpu = rcar_pwrc_core_pos(mpidr);
181b45b5bacSMarek Vasut 
182b45b5bacSMarek Vasut 	rcar_pwrc_cpuoff_sub(cpu);
183b45b5bacSMarek Vasut 
184b45b5bacSMarek Vasut 	rcar_lock_release();
185b45b5bacSMarek Vasut }
186b45b5bacSMarek Vasut 
rcar_pwrc_enable_interrupt_wakeup(u_register_t mpidr)187b45b5bacSMarek Vasut void rcar_pwrc_enable_interrupt_wakeup(u_register_t mpidr)
188b45b5bacSMarek Vasut {
189b45b5bacSMarek Vasut 	uint32_t cpu;
190b45b5bacSMarek Vasut 
191b45b5bacSMarek Vasut 	rcar_lock_get();
192b45b5bacSMarek Vasut 
193b45b5bacSMarek Vasut 	cpu = rcar_pwrc_core_pos(mpidr);
194b45b5bacSMarek Vasut 
195b45b5bacSMarek Vasut 	mmio_setbits_32(rcar_apmu_pwrctrlc(cpu), RCAR_APMU_PWRCTRLC_IWUP_EN);
196b45b5bacSMarek Vasut 
197b45b5bacSMarek Vasut 	rcar_lock_release();
198b45b5bacSMarek Vasut }
199b45b5bacSMarek Vasut 
rcar_pwrc_disable_interrupt_wakeup(u_register_t mpidr)200b45b5bacSMarek Vasut void rcar_pwrc_disable_interrupt_wakeup(u_register_t mpidr)
201b45b5bacSMarek Vasut {
202b45b5bacSMarek Vasut 	uint32_t cpu;
203b45b5bacSMarek Vasut 
204b45b5bacSMarek Vasut 	rcar_lock_get();
205b45b5bacSMarek Vasut 
206b45b5bacSMarek Vasut 	cpu = rcar_pwrc_core_pos(mpidr);
207b45b5bacSMarek Vasut 
208b45b5bacSMarek Vasut 	mmio_clrbits_32(rcar_apmu_pwrctrlc(cpu), RCAR_APMU_PWRCTRLC_IWUP_EN);
209b45b5bacSMarek Vasut 
210b45b5bacSMarek Vasut 	rcar_lock_release();
211b45b5bacSMarek Vasut }
212b45b5bacSMarek Vasut 
rcar_pwrc_clusteroff(u_register_t mpidr)213b45b5bacSMarek Vasut void rcar_pwrc_clusteroff(u_register_t mpidr)
214b45b5bacSMarek Vasut {
215b45b5bacSMarek Vasut 	uint32_t cluster, cpu;
216b45b5bacSMarek Vasut 
217b45b5bacSMarek Vasut 	rcar_lock_get();
218b45b5bacSMarek Vasut 
219b45b5bacSMarek Vasut 	cpu = rcar_pwrc_core_pos(mpidr);
220b45b5bacSMarek Vasut 
221b45b5bacSMarek Vasut 	cluster = rcar_pwrc_get_mpidr_cluster(mpidr);
222b45b5bacSMarek Vasut 
223b45b5bacSMarek Vasut 	/* for Cluster OFF */
224b45b5bacSMarek Vasut 	mmio_setbits_32(rcar_apmu_pwrctrlcl(cluster),
225b45b5bacSMarek Vasut 			RCAR_APMU_PWRCTRLCL_PCHPDNEN);
226b45b5bacSMarek Vasut 
227b45b5bacSMarek Vasut 	rcar_pwrc_cpuoff_sub(cpu);
228b45b5bacSMarek Vasut 
229b45b5bacSMarek Vasut 	rcar_lock_release();
230b45b5bacSMarek Vasut }
231b45b5bacSMarek Vasut 
rcar_pwrc_setup(void)232b45b5bacSMarek Vasut void rcar_pwrc_setup(void)
233b45b5bacSMarek Vasut {
234b45b5bacSMarek Vasut 	uintptr_t rst_barh, rst_barl;
235b45b5bacSMarek Vasut 	uint32_t cpu, i, j, reg;
236b45b5bacSMarek Vasut 	uint64_t reset;
237b45b5bacSMarek Vasut 
238b45b5bacSMarek Vasut 	reset = (uint64_t)(&plat_secondary_reset) & 0xFFFFFFFFU;
239b45b5bacSMarek Vasut 	reset &= RCAR_APMU_RVBARPLC_MASK;
240b45b5bacSMarek Vasut 	reset |= RCAR_APMU_RVBARPL_VLD;
241b45b5bacSMarek Vasut 
242b45b5bacSMarek Vasut 	reg = mmio_read_32(RCAR_PRR) >> 17;
243b45b5bacSMarek Vasut 	for (i = 0; i < PLATFORM_CLUSTER_COUNT; i++) {
244b45b5bacSMarek Vasut 		reg >>= 3;
245b45b5bacSMarek Vasut 
246b45b5bacSMarek Vasut 		if ((reg & PRR_CAXX_XX_EN_CLUSTER_MASK) != RCAR_CPU_HAVE_CAXX)
247b45b5bacSMarek Vasut 			continue;
248b45b5bacSMarek Vasut 
249b45b5bacSMarek Vasut 		mmio_setbits_32(apsreg_ap_cluster_aux0(i),
250b45b5bacSMarek Vasut 			      APSREG_AP_CLUSTER_AUX0_INIT);
251b45b5bacSMarek Vasut 
252b45b5bacSMarek Vasut 		for (j = 0; j < PLATFORM_MAX_CPUS_PER_CLUSTER; j++) {
253b45b5bacSMarek Vasut 			cpu = (i * PLATFORM_MAX_CPUS_PER_CLUSTER) + j;
254b45b5bacSMarek Vasut 
255b45b5bacSMarek Vasut 			if ((reg & prr_caxx_xx_en_cpu(cpu)) != RCAR_CPU_HAVE_CAXX)
256b45b5bacSMarek Vasut 				continue;
257b45b5bacSMarek Vasut 
258b45b5bacSMarek Vasut 			rst_barh = rcar_apmu_rvbarphc(cpu);
259b45b5bacSMarek Vasut 			rst_barl = rcar_apmu_rvbarplc(cpu);
260b45b5bacSMarek Vasut 			mmio_write_32(rst_barh, 0);
261b45b5bacSMarek Vasut 			mmio_write_32(rst_barl, (uint32_t)reset);
262b45b5bacSMarek Vasut 		}
263b45b5bacSMarek Vasut 	}
264b45b5bacSMarek Vasut 
265b45b5bacSMarek Vasut 	mmio_setbits_32(APSREG_CCI500_AUX, APSREG_CCI500_AUX_INIT);
266b45b5bacSMarek Vasut 	mmio_setbits_32(APSREG_P_CCI500_AUX, APSREG_P_CCI500_AUX_INIT);
267b45b5bacSMarek Vasut 
268b45b5bacSMarek Vasut 	rcar_lock_init();
269b45b5bacSMarek Vasut }
270b45b5bacSMarek Vasut 
rcar_pwrc_get_mpidr_cluster(u_register_t mpidr)271b45b5bacSMarek Vasut uint32_t rcar_pwrc_get_mpidr_cluster(u_register_t mpidr)
272b45b5bacSMarek Vasut {
273b45b5bacSMarek Vasut 	int32_t cluster = rcar_cluster_pos_by_mpidr(mpidr);
274b45b5bacSMarek Vasut 
275b45b5bacSMarek Vasut 	if (cluster < 0) {
276b45b5bacSMarek Vasut 		ERROR("BL3-1 : The value of passed MPIDR is invalid.");
277b45b5bacSMarek Vasut 		panic();
278b45b5bacSMarek Vasut 	}
279b45b5bacSMarek Vasut 
280b45b5bacSMarek Vasut 	return (uint32_t)cluster;
281b45b5bacSMarek Vasut }
282b45b5bacSMarek Vasut 
rcar_pwrc_cpu_on_check(u_register_t mpidr)283b45b5bacSMarek Vasut uint32_t rcar_pwrc_cpu_on_check(u_register_t mpidr)
284b45b5bacSMarek Vasut {
285b45b5bacSMarek Vasut 	uint32_t core_pos, cpu, i, j, prr, state;
286b45b5bacSMarek Vasut 	uint32_t count = 0;
287b45b5bacSMarek Vasut 
288b45b5bacSMarek Vasut 	core_pos = rcar_pwrc_core_pos(mpidr);
289b45b5bacSMarek Vasut 	prr = mmio_read_32(RCAR_PRR) >> 17;
290b45b5bacSMarek Vasut 	for (i = 0; i < PLATFORM_CLUSTER_COUNT; i++) {
291b45b5bacSMarek Vasut 		prr >>= 3;
292b45b5bacSMarek Vasut 
293b45b5bacSMarek Vasut 		/* check the cluster has cores */
294b45b5bacSMarek Vasut 		if ((prr & PRR_CAXX_XX_EN_CLUSTER_MASK) != RCAR_CPU_HAVE_CAXX)
295b45b5bacSMarek Vasut 			continue;
296b45b5bacSMarek Vasut 
297b45b5bacSMarek Vasut 		for (j = 0; j < PLATFORM_MAX_CPUS_PER_CLUSTER; j++) {
298b45b5bacSMarek Vasut 			cpu = (i * PLATFORM_MAX_CPUS_PER_CLUSTER) + j;
299b45b5bacSMarek Vasut 
300b45b5bacSMarek Vasut 			/* check the core be implemented */
301b45b5bacSMarek Vasut 			if ((prr & prr_caxx_xx_en_cpu(cpu)) != RCAR_CPU_HAVE_CAXX)
302b45b5bacSMarek Vasut 				continue;
303b45b5bacSMarek Vasut 
304b45b5bacSMarek Vasut 			if (core_pos != cpu) {
305b45b5bacSMarek Vasut 				state = mmio_read_32(rcar_apmu_fsmstsrc(cpu));
306b45b5bacSMarek Vasut 				if (state != RCAR_APMU_FSMSTSRC_STATE_OFF)
307b45b5bacSMarek Vasut 					count++;
308b45b5bacSMarek Vasut 			}
309b45b5bacSMarek Vasut 		}
310b45b5bacSMarek Vasut 	}
311b45b5bacSMarek Vasut 
312b45b5bacSMarek Vasut 	return count;
313b45b5bacSMarek Vasut }
314b45b5bacSMarek Vasut 
rcar_pwrc_set_self_refresh(void)315b45b5bacSMarek Vasut static void __section(".system_ram") rcar_pwrc_set_self_refresh(void)
316b45b5bacSMarek Vasut {
317b45b5bacSMarek Vasut 	uint64_t base_count, freq, get_count, wait_time;
318b45b5bacSMarek Vasut 	uint32_t reg;
319b45b5bacSMarek Vasut 
320b45b5bacSMarek Vasut 	/* Enable DBSC4 register access */
321b45b5bacSMarek Vasut 	mmio_write_32(DBSC4_REG_DBSYSCNT0, DBSC4_SET_DBSYSCNT0_WRITE_ENABLE);
322b45b5bacSMarek Vasut 
323b45b5bacSMarek Vasut 	/* DFI_PHYMSTR_ACK setting */
324b45b5bacSMarek Vasut 	mmio_clrbits_32(DBSC4_REG_DBDFIPMSTRCNF, DBSC4_BIT_DBDFIPMSTRCNF_PMSTREN);
325b45b5bacSMarek Vasut 
326b45b5bacSMarek Vasut 	/* Set the Self-Refresh mode */
327b45b5bacSMarek Vasut 
328b45b5bacSMarek Vasut 	/* Disable access to the SDRAM */
329b45b5bacSMarek Vasut 	mmio_write_32(DBSC4_REG_DBACEN, 0);
330b45b5bacSMarek Vasut 
331b45b5bacSMarek Vasut 	/* Flush the access request in DBSC */
332b45b5bacSMarek Vasut 	mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 1);
333b45b5bacSMarek Vasut 
334b45b5bacSMarek Vasut 	/* Wait succeed to flush */
335b45b5bacSMarek Vasut 	freq = read_cntfrq_el0();
336b45b5bacSMarek Vasut 	base_count = read_cntpct_el0();
337b45b5bacSMarek Vasut 
338b45b5bacSMarek Vasut 	while ((mmio_read_32(DBSC4_REG_DBCAM0STAT0) & DBSC4_BIT_DBCAM0STAT0)
339b45b5bacSMarek Vasut 			!= DBSC4_BIT_DBCAM0STAT0) {
340b45b5bacSMarek Vasut 
341b45b5bacSMarek Vasut 		get_count = read_cntpct_el0();
342b45b5bacSMarek Vasut 		wait_time = ((get_count - base_count) * RCAR_CONV_MICROSEC) / freq;
343b45b5bacSMarek Vasut 
344b45b5bacSMarek Vasut 		/* Get base counter */
345b45b5bacSMarek Vasut 		if (wait_time >= RCAR_WAIT_DBCS4_FLUSH) {
346b45b5bacSMarek Vasut 
347b45b5bacSMarek Vasut 			/* Stop flushing and enable access to SDRAM */
348b45b5bacSMarek Vasut 			mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 0);
349b45b5bacSMarek Vasut 			mmio_write_32(DBSC4_REG_DBACEN, 1);
350b45b5bacSMarek Vasut 
351b45b5bacSMarek Vasut 			/* Dummy write to SDRAM */
352b45b5bacSMarek Vasut 			dummy_sdram = ~dummy_sdram;
353b45b5bacSMarek Vasut 
354b45b5bacSMarek Vasut 			/* Re-Disable access and flush */
355b45b5bacSMarek Vasut 			mmio_write_32(DBSC4_REG_DBACEN, 0);
356b45b5bacSMarek Vasut 			mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 1);
357b45b5bacSMarek Vasut 
358b45b5bacSMarek Vasut 			/* refresh base counter */
359b45b5bacSMarek Vasut 			base_count = read_cntpct_el0();
360b45b5bacSMarek Vasut 		}
361b45b5bacSMarek Vasut 	}
362b45b5bacSMarek Vasut 
363b45b5bacSMarek Vasut 	/* Clear the SDRAM calibration configuration register */
364b45b5bacSMarek Vasut 	mmio_write_32(DBSC4_REG_DBCALCNF, 0);
365b45b5bacSMarek Vasut 
366b45b5bacSMarek Vasut 	/* Issue Precharge All (PREA) command */
367b45b5bacSMarek Vasut 	reg = DBSC4_SET_DBCMD_OPC_PRE | DBSC4_SET_DBCMD_CH_ALL |
368b45b5bacSMarek Vasut 	      DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_ALL;
369b45b5bacSMarek Vasut 	mmio_write_32(DBSC4_REG_DBCMD, reg);
370b45b5bacSMarek Vasut 
371b45b5bacSMarek Vasut 	/* Wait to complete PREA operation */
372b45b5bacSMarek Vasut 	while (mmio_read_32(DBSC4_REG_DBWAIT) != 0)
373b45b5bacSMarek Vasut 		;
374b45b5bacSMarek Vasut 
375b45b5bacSMarek Vasut 	/* Issue Self-Refresh Entry (SRE) command   */
376b45b5bacSMarek Vasut 	reg = DBSC4_SET_DBCMD_OPC_SR | DBSC4_SET_DBCMD_CH_ALL |
377b45b5bacSMarek Vasut 	      DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_ENTER;
378b45b5bacSMarek Vasut 	mmio_write_32(DBSC4_REG_DBCMD, reg);
379b45b5bacSMarek Vasut 
380b45b5bacSMarek Vasut 	/* Wait to complete SRE operation */
381b45b5bacSMarek Vasut 	while (mmio_read_32(DBSC4_REG_DBWAIT) != 0)
382b45b5bacSMarek Vasut 		;
383b45b5bacSMarek Vasut 
384b45b5bacSMarek Vasut 	/* Issue Mode Register 11 (MR11) write command. (ODT disabled)  */
385b45b5bacSMarek Vasut 	reg = DBSC4_SET_DBCMD_OPC_MRW | DBSC4_SET_DBCMD_CH_ALL |
386b45b5bacSMarek Vasut 	      DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_MRW_ODTC;
387b45b5bacSMarek Vasut 	mmio_write_32(DBSC4_REG_DBCMD, reg);
388b45b5bacSMarek Vasut 
389b45b5bacSMarek Vasut 	/* Wait to complete MR11 operation */
390b45b5bacSMarek Vasut 	while (mmio_read_32(DBSC4_REG_DBWAIT) != 0)
391b45b5bacSMarek Vasut 		;
392b45b5bacSMarek Vasut 
393b45b5bacSMarek Vasut 	/* Issue Power Down (PD) command */
394b45b5bacSMarek Vasut 	reg = DBSC4_SET_DBCMD_OPC_PD | DBSC4_SET_DBCMD_CH_ALL |
395b45b5bacSMarek Vasut 	      DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_ENTER;
396b45b5bacSMarek Vasut 	mmio_write_32(DBSC4_REG_DBCMD, reg);
397b45b5bacSMarek Vasut 
398b45b5bacSMarek Vasut 	/* Wait to complete PD operation */
399b45b5bacSMarek Vasut 	while (mmio_read_32(DBSC4_REG_DBWAIT) != 0)
400b45b5bacSMarek Vasut 		;
401b45b5bacSMarek Vasut 
402b45b5bacSMarek Vasut 	/* Issue set the Auto-Refresh Enable register */
403b45b5bacSMarek Vasut 	/* to stop the auto-refresh function */
404b45b5bacSMarek Vasut 	mmio_write_32(DBSC4_REG_DBRFEN, 0);
405b45b5bacSMarek Vasut 
406b45b5bacSMarek Vasut 	/* Dummy read DBWAIT register to wait tCKELPD time */
407b45b5bacSMarek Vasut 	(void)mmio_read_32(DBSC4_REG_DBWAIT);
408b45b5bacSMarek Vasut 
409b45b5bacSMarek Vasut 	/* Disable DBSC4 register access */
410b45b5bacSMarek Vasut 	mmio_write_32(DBSC4_REG_DBSYSCNT0, DBSC4_SET_DBSYSCNT0_WRITE_DISABLE);
411b45b5bacSMarek Vasut }
412b45b5bacSMarek Vasut 
413b45b5bacSMarek Vasut static void __section(".system_ram") __attribute__ ((noinline))
rcar_pwrc_go_suspend_to_ram(void)414b45b5bacSMarek Vasut 		rcar_pwrc_go_suspend_to_ram(void)
415b45b5bacSMarek Vasut {
416b45b5bacSMarek Vasut 	rcar_pwrc_set_self_refresh();
417b45b5bacSMarek Vasut 
418b45b5bacSMarek Vasut 	wfi();
419b45b5bacSMarek Vasut 
420b45b5bacSMarek Vasut 	/* Do not return */
421b45b5bacSMarek Vasut 	while (true)
422b45b5bacSMarek Vasut 		;
423b45b5bacSMarek Vasut }
424b45b5bacSMarek Vasut 
rcar_pwrc_suspend_to_ram(void)425b45b5bacSMarek Vasut void rcar_pwrc_suspend_to_ram(void)
426b45b5bacSMarek Vasut {
427b45b5bacSMarek Vasut 	uintptr_t jump = (uintptr_t) rcar_pwrc_go_suspend_to_ram;
428b45b5bacSMarek Vasut 	uintptr_t stack = (uintptr_t) (DEVICE_SRAM_STACK_BASE +
429b45b5bacSMarek Vasut 				       DEVICE_SRAM_STACK_SIZE);
430b45b5bacSMarek Vasut 
431b45b5bacSMarek Vasut 	rcar_pwrc_save_timer_state();
432b45b5bacSMarek Vasut 
433b45b5bacSMarek Vasut 	/* Clear code copy state to execute copy on next boot time */
434b45b5bacSMarek Vasut 	rcar_pwrc_code_copy_state = RCAR_CODE_COPY_NONE;
435b45b5bacSMarek Vasut 
436b45b5bacSMarek Vasut 	/* disable MMU */
437b45b5bacSMarek Vasut 	disable_mmu_el3();
438b45b5bacSMarek Vasut 
439b45b5bacSMarek Vasut 	/* cache flush */
440b45b5bacSMarek Vasut 	dcsw_op_all(DCCISW);
441b45b5bacSMarek Vasut 
442b45b5bacSMarek Vasut 	(void)rcar_pwrc_switch_stack(jump, stack, NULL);
443b45b5bacSMarek Vasut }
444b45b5bacSMarek Vasut 
rcar_pwrc_code_copy_to_system_ram(void)445b45b5bacSMarek Vasut void rcar_pwrc_code_copy_to_system_ram(void)
446b45b5bacSMarek Vasut {
447b45b5bacSMarek Vasut 	int __maybe_unused ret;
448b45b5bacSMarek Vasut 	uint32_t attr;
449b45b5bacSMarek Vasut 	struct {
450b45b5bacSMarek Vasut 		uintptr_t	base;
451b45b5bacSMarek Vasut 		size_t		len;
452b45b5bacSMarek Vasut 	} sram = {
453b45b5bacSMarek Vasut 		.base	= (uintptr_t) DEVICE_SRAM_BASE,
454b45b5bacSMarek Vasut 		.len	= DEVICE_SRAM_SIZE
455b45b5bacSMarek Vasut 	}, code = {
456b45b5bacSMarek Vasut 		.base	= (uintptr_t) SRAM_COPY_START,
457b45b5bacSMarek Vasut 		.len	= (size_t)(SYSTEM_RAM_END - SYSTEM_RAM_START)
458b45b5bacSMarek Vasut 	};
459b45b5bacSMarek Vasut 
460b45b5bacSMarek Vasut 	/*
461b45b5bacSMarek Vasut 	 * The copy of the code should only be executed for ColdBoot,
462b45b5bacSMarek Vasut 	 * and for WarmBoot from SuspendToRAM.
463b45b5bacSMarek Vasut 	 */
464b45b5bacSMarek Vasut 	if (rcar_pwrc_code_copy_state == RCAR_CODE_COPY_DONE) {
465b45b5bacSMarek Vasut 		/* No need to run because it has already been copied */
466b45b5bacSMarek Vasut 		return;
467b45b5bacSMarek Vasut 	}
468b45b5bacSMarek Vasut 
469b45b5bacSMarek Vasut 	rcar_pwrc_code_copy_state = RCAR_CODE_COPY_DONE;
470b45b5bacSMarek Vasut 	flush_dcache_range((uintptr_t)(&rcar_pwrc_code_copy_state),
471b45b5bacSMarek Vasut 			   sizeof(rcar_pwrc_code_copy_state));
472b45b5bacSMarek Vasut 
473b45b5bacSMarek Vasut 	attr = MT_MEMORY | MT_RW | MT_SECURE | MT_EXECUTE_NEVER;
474b45b5bacSMarek Vasut 	ret = xlat_change_mem_attributes(sram.base, sram.len, attr);
475b45b5bacSMarek Vasut 	assert(ret == 0);
476b45b5bacSMarek Vasut 
477b45b5bacSMarek Vasut 	(void)memcpy((void *)sram.base, (void *)code.base, code.len);
478b45b5bacSMarek Vasut 	flush_dcache_range(sram.base, code.len);
479b45b5bacSMarek Vasut 
480b45b5bacSMarek Vasut 	/* Invalidate instruction cache */
481b45b5bacSMarek Vasut 	plat_invalidate_icache();
482b45b5bacSMarek Vasut 	dsb();
483b45b5bacSMarek Vasut 	isb();
484b45b5bacSMarek Vasut 
485b45b5bacSMarek Vasut 	attr = MT_MEMORY | MT_RO | MT_SECURE | MT_EXECUTE;
486b45b5bacSMarek Vasut 	ret = xlat_change_mem_attributes(sram.base, sram.len, attr);
487b45b5bacSMarek Vasut 	assert(ret == 0);
488b45b5bacSMarek Vasut 
489b45b5bacSMarek Vasut 	/* clean up data and stack area in system ram */
490b45b5bacSMarek Vasut 	(void)memset((void *)DEVICE_SRAM_DATA_BASE, 0x0,
491b45b5bacSMarek Vasut 		     DEVICE_SRAM_DATA_SIZE + DEVICE_SRAM_STACK_SIZE);
492b45b5bacSMarek Vasut 	flush_dcache_range((uintptr_t)DEVICE_SRAM_DATA_BASE,
493b45b5bacSMarek Vasut 			   DEVICE_SRAM_DATA_SIZE + DEVICE_SRAM_STACK_SIZE);
494b45b5bacSMarek Vasut }
495