xref: /rk3399_ARM-atf/plat/ti/k3low/common/am62l_psci.c (revision 06bf26bc1f76265237df2303d78a8f475eab703d)
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 
am62l_pwr_domain_on(u_register_t mpidr)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 		return 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 		return PSCI_E_INTERN_FAIL;
45 	}
46 
47 	ret = ti_sci_proc_set_boot_cfg(proc_id, am62l_sec_entrypoint, 0, 0);
48 	if (ret != 0) {
49 		ERROR("Request to set core boot address failed: %d\n", ret);
50 		return PSCI_E_INTERN_FAIL;
51 	}
52 
53 	/* sanity check these are off before starting a core */
54 	ret = ti_sci_proc_set_boot_ctrl(proc_id,
55 			0, PROC_BOOT_CTRL_FLAG_ARMV8_L2FLUSHREQ |
56 			PROC_BOOT_CTRL_FLAG_ARMV8_AINACTS |
57 			PROC_BOOT_CTRL_FLAG_ARMV8_ACINACTM);
58 	if (ret != 0) {
59 		ERROR("Request to clear boot config failed: %d\n", ret);
60 		return PSCI_E_INTERN_FAIL;
61 	}
62 
63 	/*
64 	 * TODO: Add the actual PM operation call
65 	 * to turn on the core here
66 	 */
67 	return PSCI_E_SUCCESS;
68 }
69 
am62l_pwr_domain_off(const psci_power_state_t * target_state)70 static void am62l_pwr_domain_off(const psci_power_state_t *target_state)
71 {
72 	/* At very least the local core should be powering down */
73 	assert(((target_state)->pwr_domain_state[MPIDR_AFFLVL0]) == PLAT_MAX_OFF_STATE);
74 
75 	/* Prevent interrupts from spuriously waking up this cpu */
76 	k3_gic_cpuif_disable();
77 
78 }
79 
am62l_pwr_down_domain(const psci_power_state_t * target_state)80 static void am62l_pwr_down_domain(const psci_power_state_t *target_state)
81 {
82 	/* TODO: Add the actual pm operation call to turn off the core */
83 }
84 
am62l_pwr_domain_on_finish(const psci_power_state_t * target_state)85 void am62l_pwr_domain_on_finish(const psci_power_state_t *target_state)
86 {
87 	k3_gic_pcpu_init();
88 	k3_gic_cpuif_enable();
89 }
90 
am62l_system_reset(void)91 static void am62l_system_reset(void)
92 {
93 	mmio_write_32(WKUP_CTRL_MMR0_BASE + WKUP_CTRL_MMR0_DEVICE_RESET_OFFSET,
94 		      0x6);
95 
96 	/* Wait for reset to complete for 500ms before printing error */
97 	mdelay(500);
98 
99 	/* Ideally we should not reach here */
100 	ERROR("%s: Failed to reset device\n", __func__);
101 }
102 
103 static plat_psci_ops_t am62l_plat_psci_ops = {
104 	.pwr_domain_on = am62l_pwr_domain_on,
105 	.pwr_domain_off = am62l_pwr_domain_off,
106 	.pwr_domain_pwr_down = am62l_pwr_down_domain,
107 	.pwr_domain_on_finish = am62l_pwr_domain_on_finish,
108 	.system_reset = am62l_system_reset,
109 };
110 
jump_to_atf_func(void * unused)111 void  __aligned(16) jump_to_atf_func(void *unused)
112 {
113 	/*
114 	 * MISRA Deviation observed:
115 	 * Rule 11.1 (MISRA C:2012) Prohibits conversion performed between a
116 	 * pointer to a function and another incompatible type.
117 	 * This conversion is required for handling secure boot entry points.
118 	 * The conversion is safe as the address is verified before execution.
119 	 */
120 	void (*bl31_loc_warm_entry)(void) = (void *)am62l_sec_entrypoint_glob;
121 
122 	bl31_loc_warm_entry();
123 }
124 
plat_setup_psci_ops(uintptr_t sec_entrypoint,const plat_psci_ops_t ** psci_ops)125 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
126 			const plat_psci_ops_t **psci_ops)
127 {
128 	am62l_sec_entrypoint_glob = sec_entrypoint;
129 	/* Note that boot vector reg in sec mmr requires 16B aligned start address */
130 	am62l_sec_entrypoint = (uint64_t)(void *)&jump_to_atf_func;
131 	VERBOSE("am62l_sec_entrypoint = 0x%lx\n", am62l_sec_entrypoint);
132 
133 	*psci_ops = &am62l_plat_psci_ops;
134 
135 	return 0;
136 }
137