xref: /rk3399_ARM-atf/plat/xilinx/versal/pm_service/pm_client.c (revision 912b7a6fe46619e5df55dbd0b95d306f7bb2695c)
1c73a90e5STejas Patel /*
20b151872STanmay Shah  * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
3c73a90e5STejas Patel  *
4c73a90e5STejas Patel  * SPDX-License-Identifier: BSD-3-Clause
5c73a90e5STejas Patel  */
6c73a90e5STejas Patel 
7c73a90e5STejas Patel /*
8c73a90e5STejas Patel  * APU specific definition of processors in the subsystem as well as functions
9c73a90e5STejas Patel  * for getting information about and changing state of the APU.
10c73a90e5STejas Patel  */
11c73a90e5STejas Patel 
126e82cd8cSTejas Patel #include <assert.h>
13c73a90e5STejas Patel #include <plat_ipi.h>
14c73a90e5STejas Patel #include <platform_def.h>
15c73a90e5STejas Patel #include <versal_def.h>
16c73a90e5STejas Patel #include <lib/bakery_lock.h>
17fbb32695STejas Patel #include <lib/mmio.h>
186e82cd8cSTejas Patel #include <lib/utils.h>
19fbb32695STejas Patel #include <drivers/arm/gicv3.h>
206e82cd8cSTejas Patel #include <drivers/arm/gic_common.h>
21fbb32695STejas Patel #include <plat/common/platform.h>
226e82cd8cSTejas Patel #include "pm_api_sys.h"
23c73a90e5STejas Patel #include "pm_client.h"
240b151872STanmay Shah #include "pm_defs.h"
25c73a90e5STejas Patel 
2625b1a910STejas Patel #define UNDEFINED_CPUID		(~0)
275d1c211eSAbhyuday Godhasara #define IRQ_MAX		142U
285d1c211eSAbhyuday Godhasara #define NUM_GICD_ISENABLER	((IRQ_MAX >> 5U) + 1U)
2925b1a910STejas Patel 
30c73a90e5STejas Patel DEFINE_BAKERY_LOCK(pm_client_secure_lock);
31c73a90e5STejas Patel 
32c73a90e5STejas Patel static const struct pm_ipi apu_ipi = {
33c73a90e5STejas Patel 	.local_ipi_id = IPI_ID_APU,
34c73a90e5STejas Patel 	.remote_ipi_id = IPI_ID_PMC,
35c73a90e5STejas Patel 	.buffer_base = IPI_BUFFER_APU_BASE,
36c73a90e5STejas Patel };
37c73a90e5STejas Patel 
38c73a90e5STejas Patel /* Order in pm_procs_all array must match cpu ids */
39c73a90e5STejas Patel static const struct pm_proc pm_procs_all[] = {
40c73a90e5STejas Patel 	{
41c73a90e5STejas Patel 		.node_id = XPM_DEVID_ACPU_0,
42c73a90e5STejas Patel 		.ipi = &apu_ipi,
43fbb32695STejas Patel 		.pwrdn_mask = APU_0_PWRCTL_CPUPWRDWNREQ_MASK,
44c73a90e5STejas Patel 	},
45c73a90e5STejas Patel 	{
46c73a90e5STejas Patel 		.node_id = XPM_DEVID_ACPU_1,
47c73a90e5STejas Patel 		.ipi = &apu_ipi,
48fbb32695STejas Patel 		.pwrdn_mask = APU_1_PWRCTL_CPUPWRDWNREQ_MASK,
49c73a90e5STejas Patel 	}
50c73a90e5STejas Patel };
51c73a90e5STejas Patel 
52c73a90e5STejas Patel const struct pm_proc *primary_proc = &pm_procs_all[0];
53fbb32695STejas Patel 
546e82cd8cSTejas Patel /* Interrupt to PM node index map */
556e82cd8cSTejas Patel static enum pm_device_node_idx irq_node_map[IRQ_MAX + 1] = {
566e82cd8cSTejas Patel 	[13] = XPM_NODEIDX_DEV_GPIO,
576e82cd8cSTejas Patel 	[14] = XPM_NODEIDX_DEV_I2C_0,
586e82cd8cSTejas Patel 	[15] = XPM_NODEIDX_DEV_I2C_1,
596e82cd8cSTejas Patel 	[16] = XPM_NODEIDX_DEV_SPI_0,
606e82cd8cSTejas Patel 	[17] = XPM_NODEIDX_DEV_SPI_1,
616e82cd8cSTejas Patel 	[18] = XPM_NODEIDX_DEV_UART_0,
626e82cd8cSTejas Patel 	[19] = XPM_NODEIDX_DEV_UART_1,
636e82cd8cSTejas Patel 	[20] = XPM_NODEIDX_DEV_CAN_FD_0,
646e82cd8cSTejas Patel 	[21] = XPM_NODEIDX_DEV_CAN_FD_1,
656e82cd8cSTejas Patel 	[22] = XPM_NODEIDX_DEV_USB_0,
666e82cd8cSTejas Patel 	[23] = XPM_NODEIDX_DEV_USB_0,
676e82cd8cSTejas Patel 	[24] = XPM_NODEIDX_DEV_USB_0,
686e82cd8cSTejas Patel 	[25] = XPM_NODEIDX_DEV_USB_0,
696e82cd8cSTejas Patel 	[26] = XPM_NODEIDX_DEV_USB_0,
706e82cd8cSTejas Patel 	[37] = XPM_NODEIDX_DEV_TTC_0,
716e82cd8cSTejas Patel 	[38] = XPM_NODEIDX_DEV_TTC_0,
726e82cd8cSTejas Patel 	[39] = XPM_NODEIDX_DEV_TTC_0,
736e82cd8cSTejas Patel 	[40] = XPM_NODEIDX_DEV_TTC_1,
746e82cd8cSTejas Patel 	[41] = XPM_NODEIDX_DEV_TTC_1,
756e82cd8cSTejas Patel 	[42] = XPM_NODEIDX_DEV_TTC_1,
766e82cd8cSTejas Patel 	[43] = XPM_NODEIDX_DEV_TTC_2,
776e82cd8cSTejas Patel 	[44] = XPM_NODEIDX_DEV_TTC_2,
786e82cd8cSTejas Patel 	[45] = XPM_NODEIDX_DEV_TTC_2,
796e82cd8cSTejas Patel 	[46] = XPM_NODEIDX_DEV_TTC_3,
806e82cd8cSTejas Patel 	[47] = XPM_NODEIDX_DEV_TTC_3,
816e82cd8cSTejas Patel 	[48] = XPM_NODEIDX_DEV_TTC_3,
826e82cd8cSTejas Patel 	[56] = XPM_NODEIDX_DEV_GEM_0,
836e82cd8cSTejas Patel 	[57] = XPM_NODEIDX_DEV_GEM_0,
846e82cd8cSTejas Patel 	[58] = XPM_NODEIDX_DEV_GEM_1,
856e82cd8cSTejas Patel 	[59] = XPM_NODEIDX_DEV_GEM_1,
866e82cd8cSTejas Patel 	[60] = XPM_NODEIDX_DEV_ADMA_0,
876e82cd8cSTejas Patel 	[61] = XPM_NODEIDX_DEV_ADMA_1,
886e82cd8cSTejas Patel 	[62] = XPM_NODEIDX_DEV_ADMA_2,
896e82cd8cSTejas Patel 	[63] = XPM_NODEIDX_DEV_ADMA_3,
906e82cd8cSTejas Patel 	[64] = XPM_NODEIDX_DEV_ADMA_4,
916e82cd8cSTejas Patel 	[65] = XPM_NODEIDX_DEV_ADMA_5,
926e82cd8cSTejas Patel 	[66] = XPM_NODEIDX_DEV_ADMA_6,
936e82cd8cSTejas Patel 	[67] = XPM_NODEIDX_DEV_ADMA_7,
946e82cd8cSTejas Patel 	[74] = XPM_NODEIDX_DEV_USB_0,
956e82cd8cSTejas Patel 	[126] = XPM_NODEIDX_DEV_SDIO_0,
966e82cd8cSTejas Patel 	[127] = XPM_NODEIDX_DEV_SDIO_0,
976e82cd8cSTejas Patel 	[128] = XPM_NODEIDX_DEV_SDIO_1,
986e82cd8cSTejas Patel 	[129] = XPM_NODEIDX_DEV_SDIO_1,
996e82cd8cSTejas Patel 	[142] = XPM_NODEIDX_DEV_RTC,
1006e82cd8cSTejas Patel };
1016e82cd8cSTejas Patel 
1026e82cd8cSTejas Patel /**
1036e82cd8cSTejas Patel  * irq_to_pm_node_idx - Get PM node index corresponding to the interrupt number
1046e82cd8cSTejas Patel  * @irq:	Interrupt number
1056e82cd8cSTejas Patel  *
1066e82cd8cSTejas Patel  * Return:	PM node index corresponding to the specified interrupt
1076e82cd8cSTejas Patel  */
108*912b7a6fSVenkatesh Yadav Abbarapu static enum pm_device_node_idx irq_to_pm_node_idx(uint32_t irq)
1096e82cd8cSTejas Patel {
1106e82cd8cSTejas Patel 	assert(irq <= IRQ_MAX);
1116e82cd8cSTejas Patel 	return irq_node_map[irq];
1126e82cd8cSTejas Patel }
1136e82cd8cSTejas Patel 
1146e82cd8cSTejas Patel /**
1156e82cd8cSTejas Patel  * pm_client_set_wakeup_sources - Set all devices with enabled interrupts as
1166e82cd8cSTejas Patel  *				  wake sources in the LibPM.
117b05d2792SRavi Patel  * @node_id:	Node id of processor
1186e82cd8cSTejas Patel  */
119b05d2792SRavi Patel static void pm_client_set_wakeup_sources(uint32_t node_id)
1206e82cd8cSTejas Patel {
1216e82cd8cSTejas Patel 	uint32_t reg_num;
1226e82cd8cSTejas Patel 	uint32_t device_id;
1236e82cd8cSTejas Patel 	uint8_t pm_wakeup_nodes_set[XPM_NODEIDX_DEV_MAX];
1246e82cd8cSTejas Patel 	uintptr_t isenabler1 = PLAT_VERSAL_GICD_BASE + GICD_ISENABLER + 4;
1256e82cd8cSTejas Patel 
126fa98d7f2SAbhyuday Godhasara 	zeromem(&pm_wakeup_nodes_set, (u_register_t)sizeof(pm_wakeup_nodes_set));
1276e82cd8cSTejas Patel 
1285d1c211eSAbhyuday Godhasara 	for (reg_num = 0U; reg_num < NUM_GICD_ISENABLER; reg_num++) {
1296e82cd8cSTejas Patel 		uint32_t base_irq = reg_num << ISENABLER_SHIFT;
1306e82cd8cSTejas Patel 		uint32_t reg = mmio_read_32(isenabler1 + (reg_num << 2));
1316e82cd8cSTejas Patel 
132775bf1bbSAbhyuday Godhasara 		if (reg == 0U) {
1336e82cd8cSTejas Patel 			continue;
13441567195SAbhyuday Godhasara 		}
1356e82cd8cSTejas Patel 
136775bf1bbSAbhyuday Godhasara 		while (reg != 0U) {
1376e82cd8cSTejas Patel 			enum pm_device_node_idx node_idx;
138fa98d7f2SAbhyuday Godhasara 			uint32_t idx, irq, lowest_set = reg & (-reg);
139fa98d7f2SAbhyuday Godhasara 			enum pm_ret_status ret;
140bb1768c6SMichal Simek 
1416e82cd8cSTejas Patel 			idx = __builtin_ctz(lowest_set);
1426e82cd8cSTejas Patel 			irq = base_irq + idx;
1436e82cd8cSTejas Patel 
14441567195SAbhyuday Godhasara 			if (irq > IRQ_MAX) {
1456e82cd8cSTejas Patel 				break;
14641567195SAbhyuday Godhasara 			}
1476e82cd8cSTejas Patel 
1486e82cd8cSTejas Patel 			node_idx = irq_to_pm_node_idx(irq);
1496e82cd8cSTejas Patel 			reg &= ~lowest_set;
1506e82cd8cSTejas Patel 
1510b151872STanmay Shah 			if (node_idx > XPM_NODEIDX_DEV_MIN && node_idx < XPM_NODEIDX_DEV_MAX) {
1520b151872STanmay Shah 				if (pm_wakeup_nodes_set[node_idx] == 0U) {
1536e82cd8cSTejas Patel 					/* Get device ID from node index */
1546e82cd8cSTejas Patel 					device_id = PERIPH_DEVID(node_idx);
155b05d2792SRavi Patel 					ret = pm_set_wakeup_source(node_id,
1564697164aSTejas Patel 								   device_id, 1,
1574697164aSTejas Patel 								   SECURE_FLAG);
1580b151872STanmay Shah 					pm_wakeup_nodes_set[node_idx] = (ret == PM_RET_SUCCESS) ?
1590b151872STanmay Shah 											 1 : 0;
1600b151872STanmay Shah 				}
1616e82cd8cSTejas Patel 			}
1626e82cd8cSTejas Patel 		}
1636e82cd8cSTejas Patel 	}
1646e82cd8cSTejas Patel }
1656e82cd8cSTejas Patel 
166fbb32695STejas Patel /**
167fbb32695STejas Patel  * pm_client_suspend() - Client-specific suspend actions
168fbb32695STejas Patel  *
169fbb32695STejas Patel  * This function should contain any PU-specific actions
170fbb32695STejas Patel  * required prior to sending suspend request to PMU
171fbb32695STejas Patel  * Actions taken depend on the state system is suspending to.
172fbb32695STejas Patel  */
173*912b7a6fSVenkatesh Yadav Abbarapu void pm_client_suspend(const struct pm_proc *proc, uint32_t state)
174fbb32695STejas Patel {
175fbb32695STejas Patel 	bakery_lock_get(&pm_client_secure_lock);
176fbb32695STejas Patel 
17741567195SAbhyuday Godhasara 	if (state == PM_STATE_SUSPEND_TO_RAM) {
1785d1c211eSAbhyuday Godhasara 		pm_client_set_wakeup_sources((uint32_t)proc->node_id);
17941567195SAbhyuday Godhasara 	}
1806e82cd8cSTejas Patel 
181fbb32695STejas Patel 	/* Set powerdown request */
182fbb32695STejas Patel 	mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) |
183775bf1bbSAbhyuday Godhasara 		      (uint32_t)proc->pwrdn_mask);
184fbb32695STejas Patel 
185fbb32695STejas Patel 	bakery_lock_release(&pm_client_secure_lock);
186fbb32695STejas Patel }
187fbb32695STejas Patel 
188fbb32695STejas Patel /**
189fbb32695STejas Patel  * pm_client_abort_suspend() - Client-specific abort-suspend actions
190fbb32695STejas Patel  *
191fbb32695STejas Patel  * This function should contain any PU-specific actions
192fbb32695STejas Patel  * required for aborting a prior suspend request
193fbb32695STejas Patel  */
194fbb32695STejas Patel void pm_client_abort_suspend(void)
195fbb32695STejas Patel {
196fbb32695STejas Patel 	/* Enable interrupts at processor level (for current cpu) */
197fbb32695STejas Patel 	gicv3_cpuif_enable(plat_my_core_pos());
198fbb32695STejas Patel 
199fbb32695STejas Patel 	bakery_lock_get(&pm_client_secure_lock);
200fbb32695STejas Patel 
201fbb32695STejas Patel 	/* Clear powerdown request */
202fbb32695STejas Patel 	mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) &
203775bf1bbSAbhyuday Godhasara 		      ~((uint32_t)primary_proc->pwrdn_mask));
204fbb32695STejas Patel 
205fbb32695STejas Patel 	bakery_lock_release(&pm_client_secure_lock);
206fbb32695STejas Patel }
207fbb32695STejas Patel 
208fbb32695STejas Patel /**
20925b1a910STejas Patel  * pm_get_cpuid() - get the local cpu ID for a global node ID
21025b1a910STejas Patel  * @nid:	node id of the processor
21125b1a910STejas Patel  *
21225b1a910STejas Patel  * Return: the cpu ID (starting from 0) for the subsystem
21325b1a910STejas Patel  */
214*912b7a6fSVenkatesh Yadav Abbarapu static uint32_t pm_get_cpuid(uint32_t nid)
21525b1a910STejas Patel {
2165d1c211eSAbhyuday Godhasara 	for (size_t i = 0U; i < ARRAY_SIZE(pm_procs_all); i++) {
21741567195SAbhyuday Godhasara 		if (pm_procs_all[i].node_id == nid) {
21825b1a910STejas Patel 			return i;
21925b1a910STejas Patel 		}
22041567195SAbhyuday Godhasara 	}
22125b1a910STejas Patel 	return UNDEFINED_CPUID;
22225b1a910STejas Patel }
22325b1a910STejas Patel 
22425b1a910STejas Patel /**
22525b1a910STejas Patel  * pm_client_wakeup() - Client-specific wakeup actions
22625b1a910STejas Patel  *
22725b1a910STejas Patel  * This function should contain any PU-specific actions
22825b1a910STejas Patel  * required for waking up another APU core
22925b1a910STejas Patel  */
23025b1a910STejas Patel void pm_client_wakeup(const struct pm_proc *proc)
23125b1a910STejas Patel {
232*912b7a6fSVenkatesh Yadav Abbarapu 	uint32_t cpuid = pm_get_cpuid(proc->node_id);
23325b1a910STejas Patel 
23441567195SAbhyuday Godhasara 	if (cpuid == UNDEFINED_CPUID) {
23525b1a910STejas Patel 		return;
23641567195SAbhyuday Godhasara 	}
23725b1a910STejas Patel 
23825b1a910STejas Patel 	bakery_lock_get(&pm_client_secure_lock);
23925b1a910STejas Patel 
24025b1a910STejas Patel 	/* clear powerdown bit for affected cpu */
24125b1a910STejas Patel 	uint32_t val = mmio_read_32(FPD_APU_PWRCTL);
24225b1a910STejas Patel 	val &= ~(proc->pwrdn_mask);
24325b1a910STejas Patel 	mmio_write_32(FPD_APU_PWRCTL, val);
24425b1a910STejas Patel 
24525b1a910STejas Patel 	bakery_lock_release(&pm_client_secure_lock);
24625b1a910STejas Patel }
24725b1a910STejas Patel 
24825b1a910STejas Patel /**
249fbb32695STejas Patel  * pm_get_proc() - returns pointer to the proc structure
250fbb32695STejas Patel  * @cpuid:	id of the cpu whose proc struct pointer should be returned
251fbb32695STejas Patel  *
252fbb32695STejas Patel  * Return: pointer to a proc structure if proc is found, otherwise NULL
253fbb32695STejas Patel  */
254*912b7a6fSVenkatesh Yadav Abbarapu const struct pm_proc *pm_get_proc(uint32_t cpuid)
255fbb32695STejas Patel {
25641567195SAbhyuday Godhasara 	if (cpuid < ARRAY_SIZE(pm_procs_all)) {
257fbb32695STejas Patel 		return &pm_procs_all[cpuid];
25841567195SAbhyuday Godhasara 	}
259fbb32695STejas Patel 
260fbb32695STejas Patel 	return NULL;
261fbb32695STejas Patel }
262