xref: /rk3399_ARM-atf/plat/xilinx/versal_net/plat_psci.c (revision 8529c7694f8d614e76dcc80b394ec8a6751df44c)
11d333e69SMichal Simek /*
21d333e69SMichal Simek  * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
31d333e69SMichal Simek  * Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved.
41d333e69SMichal Simek  * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
51d333e69SMichal Simek  *
61d333e69SMichal Simek  * SPDX-License-Identifier: BSD-3-Clause
71d333e69SMichal Simek  */
81d333e69SMichal Simek 
91d333e69SMichal Simek #include <assert.h>
101d333e69SMichal Simek 
111d333e69SMichal Simek #include <common/debug.h>
12*8529c769SMichal Simek #include <common/runtime_svc.h>
131d333e69SMichal Simek #include <lib/mmio.h>
141d333e69SMichal Simek #include <lib/psci/psci.h>
151d333e69SMichal Simek #include <plat/arm/common/plat_arm.h>
161d333e69SMichal Simek #include <plat/common/platform.h>
171d333e69SMichal Simek #include <plat_arm.h>
181d333e69SMichal Simek 
191d333e69SMichal Simek #include <plat_private.h>
201d333e69SMichal Simek 
21*8529c769SMichal Simek #define FUNCID_MASK	U(0xffff)
22*8529c769SMichal Simek #define PM_RET_ERROR_NOFEATURE U(19)
23*8529c769SMichal Simek 
24*8529c769SMichal Simek #define PM_IOCTL	34U
25*8529c769SMichal Simek 
261d333e69SMichal Simek static uintptr_t versal_net_sec_entry;
271d333e69SMichal Simek 
28*8529c769SMichal Simek static void zynqmp_cpu_standby(plat_local_state_t cpu_state)
29*8529c769SMichal Simek {
30*8529c769SMichal Simek 	dsb();
31*8529c769SMichal Simek 	wfi();
32*8529c769SMichal Simek }
33*8529c769SMichal Simek 
34*8529c769SMichal Simek static int32_t zynqmp_nopmu_pwr_domain_on(u_register_t mpidr)
35*8529c769SMichal Simek {
36*8529c769SMichal Simek 	uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
37*8529c769SMichal Simek 	uint32_t cpu = cpu_id % PLATFORM_CORE_COUNT_PER_CLUSTER;
38*8529c769SMichal Simek 	uint32_t cluster = cpu_id / PLATFORM_CORE_COUNT_PER_CLUSTER;
39*8529c769SMichal Simek 	uintptr_t apu_cluster_base = 0, apu_pcli_base, apu_pcli_cluster = 0;
40*8529c769SMichal Simek 	uintptr_t rst_apu_cluster = PSX_CRF + RST_APU0_OFFSET + (cluster * 0x4);
41*8529c769SMichal Simek 
42*8529c769SMichal Simek 	VERBOSE("%s: mpidr: 0x%lx, cpuid: %x, cpu: %x, cluster: %x\n",
43*8529c769SMichal Simek 		__func__, mpidr, cpu_id, cpu, cluster);
44*8529c769SMichal Simek 
45*8529c769SMichal Simek 	if (cpu_id == -1) {
46*8529c769SMichal Simek 		return PSCI_E_INTERN_FAIL;
47*8529c769SMichal Simek 	}
48*8529c769SMichal Simek 
49*8529c769SMichal Simek 	if (platform_id == VERSAL_NET_SPP && cluster > 1) {
50*8529c769SMichal Simek 		panic();
51*8529c769SMichal Simek 	}
52*8529c769SMichal Simek 
53*8529c769SMichal Simek 	if (cluster > 3) {
54*8529c769SMichal Simek 		panic();
55*8529c769SMichal Simek 	}
56*8529c769SMichal Simek 
57*8529c769SMichal Simek 	apu_pcli_cluster = APU_PCLI + APU_PCLI_CLUSTER_OFFSET + (cluster * APU_PCLI_CLUSTER_STEP);
58*8529c769SMichal Simek 	apu_cluster_base = APU_CLUSTER0 + (cluster * APU_CLUSTER_STEP);
59*8529c769SMichal Simek 
60*8529c769SMichal Simek 	/* Enable clock */
61*8529c769SMichal Simek 	mmio_setbits_32(PSX_CRF + ACPU0_CLK_CTRL + (cluster * 0x4), ACPU_CLK_CTRL_CLKACT);
62*8529c769SMichal Simek 
63*8529c769SMichal Simek 	/* Enable cluster states */
64*8529c769SMichal Simek 	mmio_setbits_32(apu_pcli_cluster + PCLI_PSTATE_OFFSET, PCLI_PSTATE_VAL_SET);
65*8529c769SMichal Simek 	mmio_setbits_32(apu_pcli_cluster + PCLI_PREQ_OFFSET, PREQ_CHANGE_REQUEST);
66*8529c769SMichal Simek 
67*8529c769SMichal Simek 	/* assert core reset */
68*8529c769SMichal Simek 	mmio_setbits_32(rst_apu_cluster, ((RST_APU_COLD_RESET|RST_APU_WARN_RESET) << cpu));
69*8529c769SMichal Simek 
70*8529c769SMichal Simek 	/* program RVBAR */
71*8529c769SMichal Simek 	mmio_write_32(apu_cluster_base + APU_RVBAR_L_0 + (cpu << 3),
72*8529c769SMichal Simek 		      (uint32_t)versal_net_sec_entry);
73*8529c769SMichal Simek 	mmio_write_32(apu_cluster_base + APU_RVBAR_H_0 + (cpu << 3),
74*8529c769SMichal Simek 		      versal_net_sec_entry >> 32);
75*8529c769SMichal Simek 
76*8529c769SMichal Simek 	/* de-assert core reset */
77*8529c769SMichal Simek 	mmio_clrbits_32(rst_apu_cluster, ((RST_APU_COLD_RESET|RST_APU_WARN_RESET) << cpu));
78*8529c769SMichal Simek 
79*8529c769SMichal Simek 	/* clear cluster resets */
80*8529c769SMichal Simek 	mmio_clrbits_32(rst_apu_cluster, RST_APU_CLUSTER_WARM_RESET);
81*8529c769SMichal Simek 	mmio_clrbits_32(rst_apu_cluster, RST_APU_CLUSTER_COLD_RESET);
82*8529c769SMichal Simek 
83*8529c769SMichal Simek 	apu_pcli_base = APU_PCLI + (APU_PCLI_CPU_STEP * cpu) +
84*8529c769SMichal Simek 			(APU_PCLI_CLUSTER_CPU_STEP * cluster);
85*8529c769SMichal Simek 
86*8529c769SMichal Simek 	mmio_write_32(apu_pcli_base + PCLI_PSTATE_OFFSET, PCLI_PSTATE_VAL_CLEAR);
87*8529c769SMichal Simek 	mmio_write_32(apu_pcli_base + PCLI_PREQ_OFFSET, PREQ_CHANGE_REQUEST);
88*8529c769SMichal Simek 
89*8529c769SMichal Simek 	return PSCI_E_SUCCESS;
90*8529c769SMichal Simek }
91*8529c769SMichal Simek 
92*8529c769SMichal Simek static void zynqmp_nopmu_pwr_domain_off(const psci_power_state_t *target_state)
93*8529c769SMichal Simek {
94*8529c769SMichal Simek }
95*8529c769SMichal Simek 
96*8529c769SMichal Simek static void __dead2 zynqmp_nopmu_system_reset(void)
97*8529c769SMichal Simek {
98*8529c769SMichal Simek 	while (1)
99*8529c769SMichal Simek 		wfi();
100*8529c769SMichal Simek }
101*8529c769SMichal Simek 
102*8529c769SMichal Simek static int32_t zynqmp_validate_ns_entrypoint(uint64_t ns_entrypoint)
103*8529c769SMichal Simek {
104*8529c769SMichal Simek 	return PSCI_E_SUCCESS;
105*8529c769SMichal Simek }
106*8529c769SMichal Simek 
107*8529c769SMichal Simek static void zynqmp_pwr_domain_suspend(const psci_power_state_t *target_state)
108*8529c769SMichal Simek {
109*8529c769SMichal Simek }
110*8529c769SMichal Simek 
111*8529c769SMichal Simek static void zynqmp_pwr_domain_on_finish(const psci_power_state_t *target_state)
112*8529c769SMichal Simek {
113*8529c769SMichal Simek 	plat_versal_net_gic_pcpu_init();
114*8529c769SMichal Simek 	plat_versal_net_gic_cpuif_enable();
115*8529c769SMichal Simek }
116*8529c769SMichal Simek 
117*8529c769SMichal Simek static void zynqmp_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
118*8529c769SMichal Simek {
119*8529c769SMichal Simek }
120*8529c769SMichal Simek 
121*8529c769SMichal Simek static void __dead2 zynqmp_system_off(void)
122*8529c769SMichal Simek {
123*8529c769SMichal Simek 	while (1)
124*8529c769SMichal Simek 		wfi();
125*8529c769SMichal Simek }
126*8529c769SMichal Simek 
127*8529c769SMichal Simek static int32_t zynqmp_validate_power_state(uint32_t power_state, psci_power_state_t *req_state)
128*8529c769SMichal Simek {
129*8529c769SMichal Simek 	return PSCI_E_SUCCESS;
130*8529c769SMichal Simek }
131*8529c769SMichal Simek 
132*8529c769SMichal Simek static void zynqmp_get_sys_suspend_power_state(psci_power_state_t *req_state)
133*8529c769SMichal Simek {
134*8529c769SMichal Simek 	req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE;
135*8529c769SMichal Simek 	req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE;
136*8529c769SMichal Simek }
137*8529c769SMichal Simek 
1381d333e69SMichal Simek static const struct plat_psci_ops versal_net_nopmc_psci_ops = {
139*8529c769SMichal Simek 	.cpu_standby			= zynqmp_cpu_standby,
140*8529c769SMichal Simek 	.pwr_domain_on			= zynqmp_nopmu_pwr_domain_on,
141*8529c769SMichal Simek 	.pwr_domain_off			= zynqmp_nopmu_pwr_domain_off,
142*8529c769SMichal Simek 	.system_reset			= zynqmp_nopmu_system_reset,
143*8529c769SMichal Simek 	.validate_ns_entrypoint		= zynqmp_validate_ns_entrypoint,
144*8529c769SMichal Simek 	.pwr_domain_suspend		= zynqmp_pwr_domain_suspend,
145*8529c769SMichal Simek 	.pwr_domain_on_finish		= zynqmp_pwr_domain_on_finish,
146*8529c769SMichal Simek 	.pwr_domain_suspend_finish	= zynqmp_pwr_domain_suspend_finish,
147*8529c769SMichal Simek 	.system_off			= zynqmp_system_off,
148*8529c769SMichal Simek 	.validate_power_state		= zynqmp_validate_power_state,
149*8529c769SMichal Simek 	.get_sys_suspend_power_state	= zynqmp_get_sys_suspend_power_state,
1501d333e69SMichal Simek };
1511d333e69SMichal Simek 
1521d333e69SMichal Simek /*******************************************************************************
1531d333e69SMichal Simek  * Export the platform specific power ops.
1541d333e69SMichal Simek  ******************************************************************************/
1551d333e69SMichal Simek int32_t plat_setup_psci_ops(uintptr_t sec_entrypoint,
1561d333e69SMichal Simek 			    const struct plat_psci_ops **psci_ops)
1571d333e69SMichal Simek {
1581d333e69SMichal Simek 	versal_net_sec_entry = sec_entrypoint;
1591d333e69SMichal Simek 
1601d333e69SMichal Simek 	VERBOSE("Setting up entry point %lx\n", versal_net_sec_entry);
1611d333e69SMichal Simek 
1621d333e69SMichal Simek 	*psci_ops = &versal_net_nopmc_psci_ops;
1631d333e69SMichal Simek 
1641d333e69SMichal Simek 	return 0;
1651d333e69SMichal Simek }
166*8529c769SMichal Simek 
167*8529c769SMichal Simek int sip_svc_setup_init(void)
168*8529c769SMichal Simek {
169*8529c769SMichal Simek 	return 0;
170*8529c769SMichal Simek }
171*8529c769SMichal Simek 
172*8529c769SMichal Simek static int32_t no_pm_ioctl(uint32_t device_id, uint32_t ioctl_id,
173*8529c769SMichal Simek 			   uint32_t arg1, uint32_t arg2)
174*8529c769SMichal Simek {
175*8529c769SMichal Simek 	VERBOSE("%s: ioctl_id: %x, arg1: %x\n", __func__, ioctl_id, arg1);
176*8529c769SMichal Simek 	if (ioctl_id == IOCTL_OSPI_MUX_SELECT) {
177*8529c769SMichal Simek 		mmio_write_32(SLCR_OSPI_QSPI_IOU_AXI_MUX_SEL, arg1);
178*8529c769SMichal Simek 		return 0;
179*8529c769SMichal Simek 	}
180*8529c769SMichal Simek 	return PM_RET_ERROR_NOFEATURE;
181*8529c769SMichal Simek }
182*8529c769SMichal Simek 
183*8529c769SMichal Simek static uint64_t no_pm_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
184*8529c769SMichal Simek 			      uint64_t x4, void *cookie, void *handle, uint64_t flags)
185*8529c769SMichal Simek {
186*8529c769SMichal Simek 	int32_t ret;
187*8529c769SMichal Simek 	uint32_t arg[4], api_id;
188*8529c769SMichal Simek 
189*8529c769SMichal Simek 	arg[0] = (uint32_t)x1;
190*8529c769SMichal Simek 	arg[1] = (uint32_t)(x1 >> 32);
191*8529c769SMichal Simek 	arg[2] = (uint32_t)x2;
192*8529c769SMichal Simek 	arg[3] = (uint32_t)(x2 >> 32);
193*8529c769SMichal Simek 
194*8529c769SMichal Simek 	api_id = smc_fid & FUNCID_NUM_MASK;
195*8529c769SMichal Simek 	VERBOSE("%s: smc_fid: %x, api_id=0x%x\n", __func__, smc_fid, api_id);
196*8529c769SMichal Simek 
197*8529c769SMichal Simek 	switch (smc_fid & FUNCID_MASK) {
198*8529c769SMichal Simek 	case PM_IOCTL:
199*8529c769SMichal Simek 	{
200*8529c769SMichal Simek 		ret = no_pm_ioctl(arg[0], arg[1], arg[2], arg[3]);
201*8529c769SMichal Simek 		SMC_RET1(handle, (uint64_t)ret);
202*8529c769SMichal Simek 	}
203*8529c769SMichal Simek 	case PM_GET_CHIPID:
204*8529c769SMichal Simek 	{
205*8529c769SMichal Simek 		uint32_t idcode, version;
206*8529c769SMichal Simek 
207*8529c769SMichal Simek 		idcode  = mmio_read_32(PMC_TAP);
208*8529c769SMichal Simek 		version = mmio_read_32(PMC_TAP_VERSION);
209*8529c769SMichal Simek 		SMC_RET2(handle, ((uint64_t)idcode << 32), version);
210*8529c769SMichal Simek 	}
211*8529c769SMichal Simek 	default:
212*8529c769SMichal Simek 		WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid);
213*8529c769SMichal Simek 		SMC_RET1(handle, SMC_UNK);
214*8529c769SMichal Simek 	}
215*8529c769SMichal Simek }
216*8529c769SMichal Simek 
217*8529c769SMichal Simek uint64_t smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4,
218*8529c769SMichal Simek 		     void *cookie, void *handle, uint64_t flags)
219*8529c769SMichal Simek {
220*8529c769SMichal Simek 	return no_pm_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
221*8529c769SMichal Simek }
222