xref: /rk3399_ARM-atf/plat/ti/k3low/common/am62l_psci.c (revision 1abdc20b35f7b39862f91dbf1dfb462872380f71)
1*1abdc20bSDhruva Gole /*
2*1abdc20bSDhruva Gole  * Copyright (c) 2025, Texas Instruments Incorporated - https://www.ti.com/
3*1abdc20bSDhruva Gole  *
4*1abdc20bSDhruva Gole  * SPDX-License-Identifier: BSD-3-Clause
5*1abdc20bSDhruva Gole  */
6*1abdc20bSDhruva Gole 
7*1abdc20bSDhruva Gole #include <assert.h>
8*1abdc20bSDhruva Gole #include <stdbool.h>
9*1abdc20bSDhruva Gole 
10*1abdc20bSDhruva Gole #include <arch_helpers.h>
11*1abdc20bSDhruva Gole #include <common/debug.h>
12*1abdc20bSDhruva Gole #include <drivers/delay_timer.h>
13*1abdc20bSDhruva Gole #include <lib/el3_runtime/cpu_data.h>
14*1abdc20bSDhruva Gole #include <lib/mmio.h>
15*1abdc20bSDhruva Gole #include <lib/psci/psci.h>
16*1abdc20bSDhruva Gole #include <plat/common/platform.h>
17*1abdc20bSDhruva Gole #include <ti_sci.h>
18*1abdc20bSDhruva Gole #include <ti_sci_protocol.h>
19*1abdc20bSDhruva Gole 
20*1abdc20bSDhruva Gole #include <k3_gicv3.h>
21*1abdc20bSDhruva Gole #include <platform_def.h>
22*1abdc20bSDhruva Gole 
23*1abdc20bSDhruva Gole uintptr_t am62l_sec_entrypoint;
24*1abdc20bSDhruva Gole uintptr_t am62l_sec_entrypoint_glob;
25*1abdc20bSDhruva Gole void  __aligned(16) jump_to_atf_func(void *unused);
26*1abdc20bSDhruva Gole 
27*1abdc20bSDhruva Gole static int am62l_pwr_domain_on(u_register_t mpidr)
28*1abdc20bSDhruva Gole {
29*1abdc20bSDhruva Gole 	int32_t core, ret;
30*1abdc20bSDhruva Gole 	uint8_t proc_id;
31*1abdc20bSDhruva Gole 
32*1abdc20bSDhruva Gole 	core = plat_core_pos_by_mpidr(mpidr);
33*1abdc20bSDhruva Gole 	if (core < 0) {
34*1abdc20bSDhruva Gole 		ERROR("Could not get target core id: %d\n", core);
35*1abdc20bSDhruva Gole 		ret = PSCI_E_INTERN_FAIL;
36*1abdc20bSDhruva Gole 	}
37*1abdc20bSDhruva Gole 
38*1abdc20bSDhruva Gole 	proc_id = (uint8_t)(PLAT_PROC_START_ID + (uint32_t)core);
39*1abdc20bSDhruva Gole 
40*1abdc20bSDhruva Gole 	ret = ti_sci_proc_request(proc_id);
41*1abdc20bSDhruva Gole 	if (ret != 0) {
42*1abdc20bSDhruva Gole 		ERROR("Request for processor ID 0x%x failed: %d\n",
43*1abdc20bSDhruva Gole 				proc_id, ret);
44*1abdc20bSDhruva Gole 		ret = PSCI_E_INTERN_FAIL;
45*1abdc20bSDhruva Gole 	}
46*1abdc20bSDhruva Gole 
47*1abdc20bSDhruva Gole 	if (ret != PSCI_E_INTERN_FAIL) {
48*1abdc20bSDhruva Gole 		ret = ti_sci_proc_set_boot_cfg(proc_id, am62l_sec_entrypoint, 0, 0);
49*1abdc20bSDhruva Gole 		if (ret != 0) {
50*1abdc20bSDhruva Gole 			ERROR("Request to set core boot address failed: %d\n", ret);
51*1abdc20bSDhruva Gole 			ret = PSCI_E_INTERN_FAIL;
52*1abdc20bSDhruva Gole 		}
53*1abdc20bSDhruva Gole 	}
54*1abdc20bSDhruva Gole 
55*1abdc20bSDhruva Gole 	if (ret != PSCI_E_INTERN_FAIL) {
56*1abdc20bSDhruva Gole 		/* sanity check these are off before starting a core */
57*1abdc20bSDhruva Gole 		ret = ti_sci_proc_set_boot_ctrl(proc_id,
58*1abdc20bSDhruva Gole 				0, PROC_BOOT_CTRL_FLAG_ARMV8_L2FLUSHREQ |
59*1abdc20bSDhruva Gole 				PROC_BOOT_CTRL_FLAG_ARMV8_AINACTS |
60*1abdc20bSDhruva Gole 				PROC_BOOT_CTRL_FLAG_ARMV8_ACINACTM);
61*1abdc20bSDhruva Gole 		if (ret != 0) {
62*1abdc20bSDhruva Gole 			ERROR("Request to clear boot config failed: %d\n", ret);
63*1abdc20bSDhruva Gole 			ret = PSCI_E_INTERN_FAIL;
64*1abdc20bSDhruva Gole 		}
65*1abdc20bSDhruva Gole 	}
66*1abdc20bSDhruva Gole 
67*1abdc20bSDhruva Gole 	if (ret != PSCI_E_INTERN_FAIL) {
68*1abdc20bSDhruva Gole 		/*
69*1abdc20bSDhruva Gole 		 * TODO: Add the actual PM operation call
70*1abdc20bSDhruva Gole 		 * to turn on the core here
71*1abdc20bSDhruva Gole 		 */
72*1abdc20bSDhruva Gole 		ret = PSCI_E_SUCCESS;
73*1abdc20bSDhruva Gole 	}
74*1abdc20bSDhruva Gole 
75*1abdc20bSDhruva Gole 	return ret;
76*1abdc20bSDhruva Gole }
77*1abdc20bSDhruva Gole 
78*1abdc20bSDhruva Gole static void am62l_pwr_domain_off(const psci_power_state_t *target_state)
79*1abdc20bSDhruva Gole {
80*1abdc20bSDhruva Gole 	/* At very least the local core should be powering down */
81*1abdc20bSDhruva Gole 	assert(((target_state)->pwr_domain_state[MPIDR_AFFLVL0]) == PLAT_MAX_OFF_STATE);
82*1abdc20bSDhruva Gole 
83*1abdc20bSDhruva Gole 	/* Prevent interrupts from spuriously waking up this cpu */
84*1abdc20bSDhruva Gole 	k3_gic_cpuif_disable();
85*1abdc20bSDhruva Gole 
86*1abdc20bSDhruva Gole }
87*1abdc20bSDhruva Gole 
88*1abdc20bSDhruva Gole static void am62l_pwr_down_domain(const psci_power_state_t *target_state)
89*1abdc20bSDhruva Gole {
90*1abdc20bSDhruva Gole 	/* TODO: Add the actual pm operation call to turn off the core */
91*1abdc20bSDhruva Gole }
92*1abdc20bSDhruva Gole 
93*1abdc20bSDhruva Gole void am62l_pwr_domain_on_finish(const psci_power_state_t *target_state)
94*1abdc20bSDhruva Gole {
95*1abdc20bSDhruva Gole 	k3_gic_pcpu_init();
96*1abdc20bSDhruva Gole 	k3_gic_cpuif_enable();
97*1abdc20bSDhruva Gole }
98*1abdc20bSDhruva Gole 
99*1abdc20bSDhruva Gole static void am62l_system_reset(void)
100*1abdc20bSDhruva Gole {
101*1abdc20bSDhruva Gole 	mmio_write_32(WKUP_CTRL_MMR0_DEVICE_MANAGEMENT_BASE + WKUP_CTRL_MMR0_DEVICE_RESET_OFFSET,
102*1abdc20bSDhruva Gole 		      0x6);
103*1abdc20bSDhruva Gole 
104*1abdc20bSDhruva Gole 	/* Wait for reset to complete for 500ms before printing error */
105*1abdc20bSDhruva Gole 	mdelay(500);
106*1abdc20bSDhruva Gole 
107*1abdc20bSDhruva Gole 	/* Ideally we should not reach here */
108*1abdc20bSDhruva Gole 	ERROR("%s: Failed to reset device\n", __func__);
109*1abdc20bSDhruva Gole }
110*1abdc20bSDhruva Gole 
111*1abdc20bSDhruva Gole static plat_psci_ops_t am62l_plat_psci_ops = {
112*1abdc20bSDhruva Gole 	.pwr_domain_on = am62l_pwr_domain_on,
113*1abdc20bSDhruva Gole 	.pwr_domain_off = am62l_pwr_domain_off,
114*1abdc20bSDhruva Gole 	.pwr_domain_pwr_down = am62l_pwr_down_domain,
115*1abdc20bSDhruva Gole 	.pwr_domain_on_finish = am62l_pwr_domain_on_finish,
116*1abdc20bSDhruva Gole 	.system_reset = am62l_system_reset,
117*1abdc20bSDhruva Gole };
118*1abdc20bSDhruva Gole 
119*1abdc20bSDhruva Gole void  __aligned(16) jump_to_atf_func(void *unused)
120*1abdc20bSDhruva Gole {
121*1abdc20bSDhruva Gole 	/*
122*1abdc20bSDhruva Gole 	 * MISRA Deviation observed:
123*1abdc20bSDhruva Gole 	 * Rule 11.1 (MISRA C:2012) Prohibits conversion performed between a
124*1abdc20bSDhruva Gole 	 * pointer to a function and another incompatible type.
125*1abdc20bSDhruva Gole 	 * This conversion is required for handling secure boot entry points.
126*1abdc20bSDhruva Gole 	 * The conversion is safe as the address is verified before execution.
127*1abdc20bSDhruva Gole 	 */
128*1abdc20bSDhruva Gole 	void (*bl31_loc_warm_entry)(void) = (void *)am62l_sec_entrypoint_glob;
129*1abdc20bSDhruva Gole 
130*1abdc20bSDhruva Gole 	bl31_loc_warm_entry();
131*1abdc20bSDhruva Gole }
132*1abdc20bSDhruva Gole 
133*1abdc20bSDhruva Gole int plat_setup_psci_ops(uintptr_t sec_entrypoint,
134*1abdc20bSDhruva Gole 			const plat_psci_ops_t **psci_ops)
135*1abdc20bSDhruva Gole {
136*1abdc20bSDhruva Gole 	am62l_sec_entrypoint_glob = sec_entrypoint;
137*1abdc20bSDhruva Gole 	/* Note that boot vector reg in sec mmr requires 16B aligned start address */
138*1abdc20bSDhruva Gole 	am62l_sec_entrypoint = (uint64_t)(void *)&jump_to_atf_func;
139*1abdc20bSDhruva Gole 	VERBOSE("am62l_sec_entrypoint = 0x%lx\n", am62l_sec_entrypoint);
140*1abdc20bSDhruva Gole 
141*1abdc20bSDhruva Gole 	*psci_ops = &am62l_plat_psci_ops;
142*1abdc20bSDhruva Gole 
143*1abdc20bSDhruva Gole 	return 0;
144*1abdc20bSDhruva Gole }
145