xref: /optee_os/core/arch/arm/plat-rockchip/psci_rk322x.c (revision c2e4eb43b7b7211345cd38ceceac97773bd78d2c)
11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
27176a0b4SJoseph Chen /*
37176a0b4SJoseph Chen  * Copyright (C) 2017, Fuzhou Rockchip Electronics Co., Ltd.
47176a0b4SJoseph Chen  */
57176a0b4SJoseph Chen 
67176a0b4SJoseph Chen #include <common.h>
77176a0b4SJoseph Chen #include <console.h>
87176a0b4SJoseph Chen #include <cru.h>
97176a0b4SJoseph Chen #include <grf.h>
107176a0b4SJoseph Chen #include <initcall.h>
117176a0b4SJoseph Chen #include <io.h>
127176a0b4SJoseph Chen #include <kernel/delay.h>
1365401337SJens Wiklander #include <kernel/boot.h>
147176a0b4SJoseph Chen #include <kernel/misc.h>
15110da4bcSJoseph Chen #include <kernel/panic.h>
167176a0b4SJoseph Chen #include <mm/core_mmu.h>
177176a0b4SJoseph Chen #include <mm/core_memprot.h>
187176a0b4SJoseph Chen #include <platform_config.h>
197176a0b4SJoseph Chen #include <sm/optee_smc.h>
207176a0b4SJoseph Chen #include <sm/psci.h>
217176a0b4SJoseph Chen #include <stdint.h>
227176a0b4SJoseph Chen #include <tee/entry_std.h>
237176a0b4SJoseph Chen #include <tee/entry_fast.h>
247176a0b4SJoseph Chen 
25110da4bcSJoseph Chen struct dram_data {
26110da4bcSJoseph Chen 	uint32_t cru_mode_con;
27110da4bcSJoseph Chen 	uint32_t cru_clksel0;
28110da4bcSJoseph Chen 	uint32_t cru_clksel1;
29110da4bcSJoseph Chen 	uint32_t cru_clksel10;
30110da4bcSJoseph Chen 	uint32_t cru_clksel21;
31110da4bcSJoseph Chen 	uint32_t cru_clkgate[CRU_CLKGATE_CON_CNT];
32110da4bcSJoseph Chen };
33110da4bcSJoseph Chen 
34110da4bcSJoseph Chen static struct dram_data dram_d;
35110da4bcSJoseph Chen 
36a557db0aSHeiko Stuebner register_phys_mem_pgdir(MEM_AREA_IO_SEC, CRU_BASE, CRU_SIZE);
37a557db0aSHeiko Stuebner register_phys_mem_pgdir(MEM_AREA_IO_SEC, GRF_BASE, GRF_SIZE);
38a557db0aSHeiko Stuebner register_phys_mem_pgdir(MEM_AREA_IO_NSEC, ISRAM_BASE, ISRAM_SIZE);
39a557db0aSHeiko Stuebner 
40110da4bcSJoseph Chen static const uint32_t clks_gating_table[CRU_CLKGATE_CON_CNT] = {
41110da4bcSJoseph Chen 	/* gate: 0-3 */
42110da4bcSJoseph Chen 	0xefb8,
43110da4bcSJoseph Chen 	0x0ff7,
44110da4bcSJoseph Chen 	0xfff4,
45110da4bcSJoseph Chen 	0x887f,
46110da4bcSJoseph Chen 	/* gate: 4-7 */
47110da4bcSJoseph Chen 	0x0030,
48110da4bcSJoseph Chen 	0x00f8,
49110da4bcSJoseph Chen 	0x07e0,
50110da4bcSJoseph Chen 	0xc000,
51110da4bcSJoseph Chen 	/* gate: 8-11 */
52110da4bcSJoseph Chen 	0xff84,
53110da4bcSJoseph Chen 	0xb047,
54110da4bcSJoseph Chen 	0x1ca0,
55110da4bcSJoseph Chen 	0x57ff,
56110da4bcSJoseph Chen 	/* gate: 12-15 */
57110da4bcSJoseph Chen 	0x0000,
58110da4bcSJoseph Chen 	0x00ff,
59110da4bcSJoseph Chen 	0x1cc0,
60110da4bcSJoseph Chen 	0x000f,
61110da4bcSJoseph Chen };
62110da4bcSJoseph Chen 
clks_disable(void)63110da4bcSJoseph Chen static void clks_disable(void)
64110da4bcSJoseph Chen {
65110da4bcSJoseph Chen 	uint32_t i;
66*c2e4eb43SAnton Rybakov 	vaddr_t va_base = (vaddr_t)phys_to_virt_io(CRU_BASE, CRU_SIZE);
67110da4bcSJoseph Chen 
68110da4bcSJoseph Chen 	for (i = 0; i < CRU_CLKGATE_CON_CNT; i++) {
6922e7ddf8SEtienne Carriere 		dram_d.cru_clkgate[i] = io_read32(va_base + CRU_CLKGATE_CON(i));
7022e7ddf8SEtienne Carriere 		io_write32(va_base + CRU_CLKGATE_CON(i),
7122e7ddf8SEtienne Carriere 			   BITS_WITH_WMASK(clks_gating_table[i], 0xffff, 0));
72110da4bcSJoseph Chen 	}
73110da4bcSJoseph Chen }
74110da4bcSJoseph Chen 
clks_restore(void)75110da4bcSJoseph Chen static void clks_restore(void)
76110da4bcSJoseph Chen {
77110da4bcSJoseph Chen 	uint32_t i;
78*c2e4eb43SAnton Rybakov 	vaddr_t va_base = (vaddr_t)phys_to_virt_io(CRU_BASE, CRU_SIZE);
79110da4bcSJoseph Chen 
80110da4bcSJoseph Chen 	for (i = 0; i < CRU_CLKGATE_CON_CNT; i++)
8122e7ddf8SEtienne Carriere 		io_write32(va_base + CRU_CLKGATE_CON(i),
8222e7ddf8SEtienne Carriere 			   BITS_WITH_WMASK(dram_d.cru_clkgate[i], 0xffff, 0));
83110da4bcSJoseph Chen }
84110da4bcSJoseph Chen 
pll_power_down(uint32_t pll)85110da4bcSJoseph Chen static void pll_power_down(uint32_t pll)
86110da4bcSJoseph Chen {
87*c2e4eb43SAnton Rybakov 	vaddr_t va_base = (vaddr_t)phys_to_virt_io(CRU_BASE, CRU_SIZE);
88110da4bcSJoseph Chen 
8922e7ddf8SEtienne Carriere 	io_write32(va_base + CRU_MODE_CON, PLL_SLOW_MODE(pll));
9022e7ddf8SEtienne Carriere 	io_write32(va_base + CRU_PLL_CON1(pll), PLL_POWER_DOWN);
91110da4bcSJoseph Chen }
92110da4bcSJoseph Chen 
pll_power_up(uint32_t pll)93110da4bcSJoseph Chen static void pll_power_up(uint32_t pll)
94110da4bcSJoseph Chen {
95*c2e4eb43SAnton Rybakov 	vaddr_t va_base = (vaddr_t)phys_to_virt_io(CRU_BASE, CRU_SIZE);
96110da4bcSJoseph Chen 
9722e7ddf8SEtienne Carriere 	io_write32(va_base + CRU_PLL_CON1(pll), PLL_POWER_UP);
98110da4bcSJoseph Chen }
99110da4bcSJoseph Chen 
pll_wait_lock(uint32_t pll)100110da4bcSJoseph Chen static void pll_wait_lock(uint32_t pll)
101110da4bcSJoseph Chen {
102110da4bcSJoseph Chen 	uint32_t loop = 0;
103*c2e4eb43SAnton Rybakov 	vaddr_t va_base = (vaddr_t)phys_to_virt_io(CRU_BASE, CRU_SIZE);
104110da4bcSJoseph Chen 
10522e7ddf8SEtienne Carriere 	while (!(io_read32(va_base + CRU_PLL_CON1(pll)) & PLL_LOCK) &&
106110da4bcSJoseph Chen 	       (loop < 500)) {
107110da4bcSJoseph Chen 		udelay(2);
108110da4bcSJoseph Chen 		loop++;
109110da4bcSJoseph Chen 	}
110110da4bcSJoseph Chen 
11122e7ddf8SEtienne Carriere 	if (!(io_read32(va_base + CRU_PLL_CON1(pll)) & PLL_LOCK)) {
112110da4bcSJoseph Chen 		EMSG("PLL can't lock, index = %" PRIu32, pll);
113110da4bcSJoseph Chen 		panic();
114110da4bcSJoseph Chen 	}
115110da4bcSJoseph Chen }
116110da4bcSJoseph Chen 
117110da4bcSJoseph Chen /*
118110da4bcSJoseph Chen  * Select clock from external 24MHz OSC(slow mode) and power down plls,
119110da4bcSJoseph Chen  * then set frequency division of relevant bus to 24MHz.
120110da4bcSJoseph Chen  */
plls_power_down(void)121110da4bcSJoseph Chen static void plls_power_down(void)
122110da4bcSJoseph Chen {
123*c2e4eb43SAnton Rybakov 	vaddr_t va_base = (vaddr_t)phys_to_virt_io(CRU_BASE, CRU_SIZE);
124110da4bcSJoseph Chen 
12522e7ddf8SEtienne Carriere 	dram_d.cru_clksel0 = io_read32(va_base + CRU_CLKSEL_CON(0));
12622e7ddf8SEtienne Carriere 	dram_d.cru_clksel1 = io_read32(va_base + CRU_CLKSEL_CON(1));
12722e7ddf8SEtienne Carriere 	dram_d.cru_clksel10 = io_read32(va_base + CRU_CLKSEL_CON(10));
12822e7ddf8SEtienne Carriere 	dram_d.cru_clksel21 = io_read32(va_base + CRU_CLKSEL_CON(21));
12922e7ddf8SEtienne Carriere 	dram_d.cru_mode_con = io_read32(va_base + CRU_MODE_CON);
130110da4bcSJoseph Chen 
131110da4bcSJoseph Chen 	pll_power_down(GPLL_ID);
132110da4bcSJoseph Chen 	pll_power_down(CPLL_ID);
133110da4bcSJoseph Chen 	pll_power_down(APLL_ID);
134110da4bcSJoseph Chen 
135110da4bcSJoseph Chen 	/* core */
13622e7ddf8SEtienne Carriere 	io_write32(va_base + CRU_CLKSEL_CON(0), BITS_WITH_WMASK(0, 0x1f, 0));
13722e7ddf8SEtienne Carriere 	io_write32(va_base + CRU_CLKSEL_CON(1),
13822e7ddf8SEtienne Carriere 		   BITS_WITH_WMASK(0, 0xf, 0) | BITS_WITH_WMASK(0, 0x7, 4));
139110da4bcSJoseph Chen 
140110da4bcSJoseph Chen 	/* peri aclk, hclk, pclk */
14122e7ddf8SEtienne Carriere 	io_write32(va_base + CRU_CLKSEL_CON(10),
14222e7ddf8SEtienne Carriere 		   BITS_WITH_WMASK(0, 0x1f, 0) | BITS_WITH_WMASK(0, 0x3, 8) |
14322e7ddf8SEtienne Carriere 		   BITS_WITH_WMASK(0, 0x7, 12));
144110da4bcSJoseph Chen 
145110da4bcSJoseph Chen 	/* pdbus */
14622e7ddf8SEtienne Carriere 	io_write32(va_base + CRU_CLKSEL_CON(0), BITS_WITH_WMASK(0, 0x1f, 8));
14722e7ddf8SEtienne Carriere 	io_write32(va_base + CRU_CLKSEL_CON(1),
14822e7ddf8SEtienne Carriere 		   BITS_WITH_WMASK(0, 0x3, 8) | BITS_WITH_WMASK(0, 0x7, 12));
149110da4bcSJoseph Chen 
150110da4bcSJoseph Chen 	/* hdmi cec 32k */
15122e7ddf8SEtienne Carriere 	io_write32(va_base + CRU_CLKSEL_CON(21),
15222e7ddf8SEtienne Carriere 		   BITS_WITH_WMASK(732, 0x3fff, 0) |
15322e7ddf8SEtienne Carriere 		   BITS_WITH_WMASK(2, 0x3, 14));
154110da4bcSJoseph Chen }
155110da4bcSJoseph Chen 
plls_restore(void)156110da4bcSJoseph Chen static void plls_restore(void)
157110da4bcSJoseph Chen {
158*c2e4eb43SAnton Rybakov 	vaddr_t va_base = (vaddr_t)phys_to_virt_io(CRU_BASE, CRU_SIZE);
159110da4bcSJoseph Chen 
160110da4bcSJoseph Chen 	/* power up plls */
161110da4bcSJoseph Chen 	pll_power_up(APLL_ID);
162110da4bcSJoseph Chen 	pll_power_up(GPLL_ID);
163110da4bcSJoseph Chen 	pll_power_up(CPLL_ID);
164110da4bcSJoseph Chen 
165110da4bcSJoseph Chen 	udelay(200);
166110da4bcSJoseph Chen 
167110da4bcSJoseph Chen 	/* wait lock*/
168110da4bcSJoseph Chen 	pll_wait_lock(APLL_ID);
169110da4bcSJoseph Chen 	pll_wait_lock(GPLL_ID);
170110da4bcSJoseph Chen 	pll_wait_lock(CPLL_ID);
171110da4bcSJoseph Chen 
172110da4bcSJoseph Chen 	/* hdmi cec 32k */
17322e7ddf8SEtienne Carriere 	io_write32(va_base + CRU_CLKSEL_CON(21),
17422e7ddf8SEtienne Carriere 		   dram_d.cru_clksel21 | BITS_WMSK(0x3fff, 0) |
17522e7ddf8SEtienne Carriere 		   BITS_WMSK(0x3, 14));
176110da4bcSJoseph Chen 
177110da4bcSJoseph Chen 	/* pdbus */
17822e7ddf8SEtienne Carriere 	io_write32(va_base + CRU_CLKSEL_CON(0),
17922e7ddf8SEtienne Carriere 		   dram_d.cru_clksel0 | BITS_WMSK(0x1f, 8));
18022e7ddf8SEtienne Carriere 	io_write32(va_base + CRU_CLKSEL_CON(1),
18122e7ddf8SEtienne Carriere 		   dram_d.cru_clksel1 | BITS_WMSK(0x3, 8) | BITS_WMSK(0x7, 12));
182110da4bcSJoseph Chen 
183110da4bcSJoseph Chen 	/* peri aclk, hclk, pclk */
18422e7ddf8SEtienne Carriere 	io_write32(va_base + CRU_CLKSEL_CON(10),
18522e7ddf8SEtienne Carriere 		   dram_d.cru_clksel10 | BITS_WMSK(0x1f, 0) |
18622e7ddf8SEtienne Carriere 		   BITS_WMSK(0x3, 8) | BITS_WMSK(0x7, 12));
187110da4bcSJoseph Chen 
188110da4bcSJoseph Chen 	/* core */
18922e7ddf8SEtienne Carriere 	io_write32(va_base + CRU_CLKSEL_CON(0),
19022e7ddf8SEtienne Carriere 		   dram_d.cru_clksel0 | BITS_WMSK(0x1f, 0));
19122e7ddf8SEtienne Carriere 	io_write32(va_base + CRU_CLKSEL_CON(1),
19222e7ddf8SEtienne Carriere 		   dram_d.cru_clksel1 | BITS_WMSK(0xf, 0) | BITS_WMSK(0x7, 4));
193110da4bcSJoseph Chen 
194110da4bcSJoseph Chen 	/* resume plls mode */
19522e7ddf8SEtienne Carriere 	io_write32(va_base + CRU_MODE_CON,
19622e7ddf8SEtienne Carriere 		   dram_d.cru_mode_con | BITS_WMSK(0x1, PLL_MODE_BIT(APLL_ID)));
19722e7ddf8SEtienne Carriere 	io_write32(va_base + CRU_MODE_CON,
19822e7ddf8SEtienne Carriere 		   dram_d.cru_mode_con | BITS_WMSK(0x1, PLL_MODE_BIT(CPLL_ID)));
19922e7ddf8SEtienne Carriere 	io_write32(va_base + CRU_MODE_CON,
20022e7ddf8SEtienne Carriere 		   dram_d.cru_mode_con | BITS_WMSK(0x1, PLL_MODE_BIT(GPLL_ID)));
201110da4bcSJoseph Chen }
202110da4bcSJoseph Chen 
wait_core_wfe_i(uint32_t core)2037176a0b4SJoseph Chen static bool wait_core_wfe_i(uint32_t core)
2047176a0b4SJoseph Chen {
2057176a0b4SJoseph Chen 	uint32_t wfei_mask, loop = 0;
206*c2e4eb43SAnton Rybakov 	vaddr_t va_base = (vaddr_t)phys_to_virt_io(GRF_BASE, GRF_SIZE);
2077176a0b4SJoseph Chen 
2087176a0b4SJoseph Chen 	wfei_mask = CORE_WFE_I_MASK(core);
20922e7ddf8SEtienne Carriere 	while (!(io_read32(va_base + GRF_CPU_STATUS1) & wfei_mask) &&
21022e7ddf8SEtienne Carriere 	       loop < 500) {
2117176a0b4SJoseph Chen 		udelay(2);
2127176a0b4SJoseph Chen 		loop++;
2137176a0b4SJoseph Chen 	}
2147176a0b4SJoseph Chen 
21522e7ddf8SEtienne Carriere 	return io_read32(va_base + GRF_CPU_STATUS1) & wfei_mask;
2167176a0b4SJoseph Chen }
2177176a0b4SJoseph Chen 
core_held_in_reset(uint32_t core)2187176a0b4SJoseph Chen static bool core_held_in_reset(uint32_t core)
2197176a0b4SJoseph Chen {
2207176a0b4SJoseph Chen 	uint32_t val;
221*c2e4eb43SAnton Rybakov 	vaddr_t va_base = (vaddr_t)phys_to_virt_io(CRU_BASE, CRU_SIZE);
2227176a0b4SJoseph Chen 
22322e7ddf8SEtienne Carriere 	val = io_read32(va_base + CRU_SOFTRST_CON(0));
2247176a0b4SJoseph Chen 
2257176a0b4SJoseph Chen 	return val & CORE_HELD_IN_RESET(core);
2267176a0b4SJoseph Chen }
2277176a0b4SJoseph Chen 
psci_version(void)228f1ecb128SJoseph Chen uint32_t psci_version(void)
229f1ecb128SJoseph Chen {
230f1ecb128SJoseph Chen 	return PSCI_VERSION_1_0;
231f1ecb128SJoseph Chen }
232f1ecb128SJoseph Chen 
psci_features(uint32_t psci_fid)2331032b987SJoseph Chen int psci_features(uint32_t psci_fid)
2341032b987SJoseph Chen {
2351032b987SJoseph Chen 	switch (psci_fid) {
2361032b987SJoseph Chen 	case PSCI_PSCI_FEATURES:
2371032b987SJoseph Chen 	case PSCI_VERSION:
2381032b987SJoseph Chen 	case PSCI_CPU_ON:
2391032b987SJoseph Chen 	case PSCI_CPU_OFF:
240110da4bcSJoseph Chen 	case PSCI_SYSTEM_SUSPEND:
2411032b987SJoseph Chen 	case PSCI_SYSTEM_RESET:
2421032b987SJoseph Chen 		return PSCI_RET_SUCCESS;
2431032b987SJoseph Chen 	default:
2441032b987SJoseph Chen 		return PSCI_RET_NOT_SUPPORTED;
2451032b987SJoseph Chen 	}
2461032b987SJoseph Chen }
2471032b987SJoseph Chen 
psci_cpu_on(uint32_t core_idx,uint32_t entry,uint32_t context_id)2487176a0b4SJoseph Chen int psci_cpu_on(uint32_t core_idx, uint32_t entry,
249fb9489aaSJordan Rhee 		uint32_t context_id)
2507176a0b4SJoseph Chen {
2517176a0b4SJoseph Chen 	bool wfei;
252*c2e4eb43SAnton Rybakov 	vaddr_t cru_base = (vaddr_t)phys_to_virt_io(CRU_BASE, CRU_SIZE);
253*c2e4eb43SAnton Rybakov 	vaddr_t isram_base = (vaddr_t)phys_to_virt_io(ISRAM_BASE, ISRAM_SIZE);
2547176a0b4SJoseph Chen 
2557176a0b4SJoseph Chen 	core_idx &= MPIDR_CPU_MASK;
2567176a0b4SJoseph Chen 	if ((core_idx == 0) || (core_idx >= CFG_TEE_CORE_NB_CORE))
2577176a0b4SJoseph Chen 		return PSCI_RET_INVALID_PARAMETERS;
2587176a0b4SJoseph Chen 
2597176a0b4SJoseph Chen 	DMSG("core_id: %" PRIu32, core_idx);
2607176a0b4SJoseph Chen 
2617176a0b4SJoseph Chen 	/* set secondary cores' NS entry addresses */
26265401337SJens Wiklander 	boot_set_core_ns_entry(core_idx, entry, context_id);
2637176a0b4SJoseph Chen 
2647176a0b4SJoseph Chen 	/* wait */
2657176a0b4SJoseph Chen 	if (!core_held_in_reset(core_idx)) {
2667176a0b4SJoseph Chen 		wfei = wait_core_wfe_i(core_idx);
2677176a0b4SJoseph Chen 		if (!wfei) {
2687176a0b4SJoseph Chen 			EMSG("Can't wait cpu%" PRIu32 " wfei before softrst",
2697176a0b4SJoseph Chen 			     core_idx);
2707176a0b4SJoseph Chen 			return PSCI_RET_DENIED;
2717176a0b4SJoseph Chen 		}
2727176a0b4SJoseph Chen 	}
2737176a0b4SJoseph Chen 
2747176a0b4SJoseph Chen 	/* soft reset core */
27522e7ddf8SEtienne Carriere 	io_write32(cru_base + CRU_SOFTRST_CON(0), CORE_SOFT_RESET(core_idx));
2767176a0b4SJoseph Chen 	dsb();
2777176a0b4SJoseph Chen 
2787176a0b4SJoseph Chen 	udelay(2);
2797176a0b4SJoseph Chen 
2807176a0b4SJoseph Chen 	/* soft release core */
28122e7ddf8SEtienne Carriere 	io_write32(cru_base + CRU_SOFTRST_CON(0), CORE_SOFT_RELEASE(core_idx));
2827176a0b4SJoseph Chen 	dsb();
2837176a0b4SJoseph Chen 
2847176a0b4SJoseph Chen 	/* wait */
2857176a0b4SJoseph Chen 	wfei = wait_core_wfe_i(core_idx);
2867176a0b4SJoseph Chen 	if (!wfei) {
2877176a0b4SJoseph Chen 		EMSG("Can't wait cpu%" PRIu32 " wfei after softrst", core_idx);
2887176a0b4SJoseph Chen 		return PSCI_RET_DENIED;
2897176a0b4SJoseph Chen 	}
2907176a0b4SJoseph Chen 
2917176a0b4SJoseph Chen 	/* set secondary secure entry address and lock tag */
29222e7ddf8SEtienne Carriere 	io_write32(isram_base + BOOT_ADDR_OFFSET, TEE_LOAD_ADDR);
29322e7ddf8SEtienne Carriere 	io_write32(isram_base + LOCK_ADDR_OFFSET, LOCK_TAG);
2947176a0b4SJoseph Chen 	dsb();
2957176a0b4SJoseph Chen 
2967176a0b4SJoseph Chen 	sev();
2977176a0b4SJoseph Chen 	dsb();
2987176a0b4SJoseph Chen 
2997176a0b4SJoseph Chen 	return PSCI_RET_SUCCESS;
3007176a0b4SJoseph Chen }
3017176a0b4SJoseph Chen 
psci_cpu_off(void)3027176a0b4SJoseph Chen int psci_cpu_off(void)
3037176a0b4SJoseph Chen {
3047176a0b4SJoseph Chen 	uint32_t core = get_core_pos();
3057176a0b4SJoseph Chen 
3067176a0b4SJoseph Chen 	if ((core == 0) || (core >= CFG_TEE_CORE_NB_CORE))
3077176a0b4SJoseph Chen 		return PSCI_RET_INVALID_PARAMETERS;
3087176a0b4SJoseph Chen 
3097176a0b4SJoseph Chen 	DMSG("core_id: %" PRIu32, core);
3107176a0b4SJoseph Chen 
3117176a0b4SJoseph Chen 	psci_armv7_cpu_off();
3127176a0b4SJoseph Chen 	thread_mask_exceptions(THREAD_EXCP_ALL);
3137176a0b4SJoseph Chen 
3147176a0b4SJoseph Chen 	while (1)
3157176a0b4SJoseph Chen 		wfi();
3167176a0b4SJoseph Chen 
3177176a0b4SJoseph Chen 	return PSCI_RET_INTERNAL_FAILURE;
3187176a0b4SJoseph Chen }
3197176a0b4SJoseph Chen 
psci_affinity_info(uint32_t affinity,uint32_t lowest_affnity_level __unused)3207176a0b4SJoseph Chen int psci_affinity_info(uint32_t affinity,
3217176a0b4SJoseph Chen 		       uint32_t lowest_affnity_level __unused)
3227176a0b4SJoseph Chen {
3237176a0b4SJoseph Chen 	uint32_t core_idx = affinity & MPIDR_CPU_MASK;
3247176a0b4SJoseph Chen 	uint32_t wfi_mask = CORE_WFI_MASK(core_idx);
325*c2e4eb43SAnton Rybakov 	vaddr_t va_base = (vaddr_t)phys_to_virt_io(GRF_BASE, GRF_SIZE);
3267176a0b4SJoseph Chen 
3277176a0b4SJoseph Chen 	DMSG("core_id: %" PRIu32 " STATUS: %" PRIx32 " MASK: %" PRIx32,
32822e7ddf8SEtienne Carriere 	     core_idx, io_read32(va_base + GRF_CPU_STATUS1), wfi_mask);
3297176a0b4SJoseph Chen 
33022e7ddf8SEtienne Carriere 	return (io_read32(va_base + GRF_CPU_STATUS1) & wfi_mask) ?
3317176a0b4SJoseph Chen 		PSCI_AFFINITY_LEVEL_OFF : PSCI_AFFINITY_LEVEL_ON;
3327176a0b4SJoseph Chen }
3337176a0b4SJoseph Chen 
psci_system_reset(void)3347176a0b4SJoseph Chen void psci_system_reset(void)
3357176a0b4SJoseph Chen {
336*c2e4eb43SAnton Rybakov 	vaddr_t va_base = (vaddr_t)phys_to_virt_io(CRU_BASE, CRU_SIZE);
3377176a0b4SJoseph Chen 
3387176a0b4SJoseph Chen 	/* PLLs enter slow mode */
33922e7ddf8SEtienne Carriere 	io_write32(va_base + CRU_MODE_CON, PLLS_SLOW_MODE);
3407176a0b4SJoseph Chen 	dsb();
3417176a0b4SJoseph Chen 
3427176a0b4SJoseph Chen 	/* Global second reset */
34322e7ddf8SEtienne Carriere 	io_write32(va_base + CRU_SNDRST_VAL_BASE, CRU_SNDRST_VAL);
3447176a0b4SJoseph Chen 	dsb();
3457176a0b4SJoseph Chen }
3467176a0b4SJoseph Chen 
psci_system_suspend(uintptr_t entry __unused,uint32_t context_id __unused,struct sm_nsec_ctx * nsec __unused)347110da4bcSJoseph Chen int psci_system_suspend(uintptr_t entry __unused,
348789e38a6SZeng Tao 			uint32_t context_id __unused,
349789e38a6SZeng Tao 			struct sm_nsec_ctx *nsec __unused)
350110da4bcSJoseph Chen {
351110da4bcSJoseph Chen 	DMSG("system suspend");
352110da4bcSJoseph Chen 
353110da4bcSJoseph Chen 	clks_disable();
354110da4bcSJoseph Chen 	plls_power_down();
355110da4bcSJoseph Chen 
356110da4bcSJoseph Chen 	cache_op_inner(DCACHE_CLEAN_INV, NULL, 0);
357110da4bcSJoseph Chen 
358110da4bcSJoseph Chen 	wfi();
359110da4bcSJoseph Chen 
360110da4bcSJoseph Chen 	plls_restore();
361110da4bcSJoseph Chen 	clks_restore();
362110da4bcSJoseph Chen 
363110da4bcSJoseph Chen 	return PSCI_RET_SUCCESS;
364110da4bcSJoseph Chen }
365110da4bcSJoseph Chen 
3667176a0b4SJoseph Chen /* When SMP bootup, we release cores one by one */
reset_nonboot_cores(void)3677176a0b4SJoseph Chen static TEE_Result reset_nonboot_cores(void)
3687176a0b4SJoseph Chen {
369*c2e4eb43SAnton Rybakov 	vaddr_t va_base = (vaddr_t)phys_to_virt_io(CRU_BASE, CRU_SIZE);
3707176a0b4SJoseph Chen 
37122e7ddf8SEtienne Carriere 	io_write32(va_base + CRU_SOFTRST_CON(0), NONBOOT_CORES_SOFT_RESET);
3727176a0b4SJoseph Chen 
3737176a0b4SJoseph Chen 	return TEE_SUCCESS;
3747176a0b4SJoseph Chen }
3757176a0b4SJoseph Chen 
3767176a0b4SJoseph Chen service_init_late(reset_nonboot_cores);
377