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