xref: /rk3399_ARM-atf/plat/xilinx/versal/pm_service/pm_client.c (revision 31b684898f71c80366ed539de63f796bb9c9712b)
1c73a90e5STejas Patel /*
20b151872STanmay Shah  * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
3*31b68489SJay Buddhabhatti  * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
4c73a90e5STejas Patel  *
5c73a90e5STejas Patel  * SPDX-License-Identifier: BSD-3-Clause
6c73a90e5STejas Patel  */
7c73a90e5STejas Patel 
8c73a90e5STejas Patel /*
9c73a90e5STejas Patel  * APU specific definition of processors in the subsystem as well as functions
10c73a90e5STejas Patel  * for getting information about and changing state of the APU.
11c73a90e5STejas Patel  */
12c73a90e5STejas Patel 
136e82cd8cSTejas Patel #include <assert.h>
14c73a90e5STejas Patel #include <plat_ipi.h>
15c73a90e5STejas Patel #include <platform_def.h>
16c73a90e5STejas Patel #include <versal_def.h>
17c73a90e5STejas Patel #include <lib/bakery_lock.h>
18fbb32695STejas Patel #include <lib/mmio.h>
196e82cd8cSTejas Patel #include <lib/utils.h>
20fbb32695STejas Patel #include <drivers/arm/gicv3.h>
216e82cd8cSTejas Patel #include <drivers/arm/gic_common.h>
22fbb32695STejas Patel #include <plat/common/platform.h>
236e82cd8cSTejas Patel #include "pm_api_sys.h"
24c73a90e5STejas Patel #include "pm_client.h"
250b151872STanmay Shah #include "pm_defs.h"
26c73a90e5STejas Patel 
2725b1a910STejas Patel #define UNDEFINED_CPUID		(~0)
285d1c211eSAbhyuday Godhasara #define IRQ_MAX		142U
295d1c211eSAbhyuday Godhasara #define NUM_GICD_ISENABLER	((IRQ_MAX >> 5U) + 1U)
3025b1a910STejas Patel 
31c73a90e5STejas Patel DEFINE_BAKERY_LOCK(pm_client_secure_lock);
32c73a90e5STejas Patel 
33c73a90e5STejas Patel static const struct pm_ipi apu_ipi = {
34c73a90e5STejas Patel 	.local_ipi_id = IPI_ID_APU,
35c73a90e5STejas Patel 	.remote_ipi_id = IPI_ID_PMC,
36c73a90e5STejas Patel 	.buffer_base = IPI_BUFFER_APU_BASE,
37c73a90e5STejas Patel };
38c73a90e5STejas Patel 
39c73a90e5STejas Patel /* Order in pm_procs_all array must match cpu ids */
40c73a90e5STejas Patel static const struct pm_proc pm_procs_all[] = {
41c73a90e5STejas Patel 	{
42c73a90e5STejas Patel 		.node_id = XPM_DEVID_ACPU_0,
43c73a90e5STejas Patel 		.ipi = &apu_ipi,
44fbb32695STejas Patel 		.pwrdn_mask = APU_0_PWRCTL_CPUPWRDWNREQ_MASK,
45c73a90e5STejas Patel 	},
46c73a90e5STejas Patel 	{
47c73a90e5STejas Patel 		.node_id = XPM_DEVID_ACPU_1,
48c73a90e5STejas Patel 		.ipi = &apu_ipi,
49fbb32695STejas Patel 		.pwrdn_mask = APU_1_PWRCTL_CPUPWRDWNREQ_MASK,
50c73a90e5STejas Patel 	}
51c73a90e5STejas Patel };
52c73a90e5STejas Patel 
53c73a90e5STejas Patel const struct pm_proc *primary_proc = &pm_procs_all[0];
54fbb32695STejas Patel 
556e82cd8cSTejas Patel /* Interrupt to PM node index map */
566e82cd8cSTejas Patel static enum pm_device_node_idx irq_node_map[IRQ_MAX + 1] = {
576e82cd8cSTejas Patel 	[13] = XPM_NODEIDX_DEV_GPIO,
586e82cd8cSTejas Patel 	[14] = XPM_NODEIDX_DEV_I2C_0,
596e82cd8cSTejas Patel 	[15] = XPM_NODEIDX_DEV_I2C_1,
606e82cd8cSTejas Patel 	[16] = XPM_NODEIDX_DEV_SPI_0,
616e82cd8cSTejas Patel 	[17] = XPM_NODEIDX_DEV_SPI_1,
626e82cd8cSTejas Patel 	[18] = XPM_NODEIDX_DEV_UART_0,
636e82cd8cSTejas Patel 	[19] = XPM_NODEIDX_DEV_UART_1,
646e82cd8cSTejas Patel 	[20] = XPM_NODEIDX_DEV_CAN_FD_0,
656e82cd8cSTejas Patel 	[21] = XPM_NODEIDX_DEV_CAN_FD_1,
666e82cd8cSTejas Patel 	[22] = XPM_NODEIDX_DEV_USB_0,
676e82cd8cSTejas Patel 	[23] = XPM_NODEIDX_DEV_USB_0,
686e82cd8cSTejas Patel 	[24] = XPM_NODEIDX_DEV_USB_0,
696e82cd8cSTejas Patel 	[25] = XPM_NODEIDX_DEV_USB_0,
706e82cd8cSTejas Patel 	[26] = XPM_NODEIDX_DEV_USB_0,
716e82cd8cSTejas Patel 	[37] = XPM_NODEIDX_DEV_TTC_0,
726e82cd8cSTejas Patel 	[38] = XPM_NODEIDX_DEV_TTC_0,
736e82cd8cSTejas Patel 	[39] = XPM_NODEIDX_DEV_TTC_0,
746e82cd8cSTejas Patel 	[40] = XPM_NODEIDX_DEV_TTC_1,
756e82cd8cSTejas Patel 	[41] = XPM_NODEIDX_DEV_TTC_1,
766e82cd8cSTejas Patel 	[42] = XPM_NODEIDX_DEV_TTC_1,
776e82cd8cSTejas Patel 	[43] = XPM_NODEIDX_DEV_TTC_2,
786e82cd8cSTejas Patel 	[44] = XPM_NODEIDX_DEV_TTC_2,
796e82cd8cSTejas Patel 	[45] = XPM_NODEIDX_DEV_TTC_2,
806e82cd8cSTejas Patel 	[46] = XPM_NODEIDX_DEV_TTC_3,
816e82cd8cSTejas Patel 	[47] = XPM_NODEIDX_DEV_TTC_3,
826e82cd8cSTejas Patel 	[48] = XPM_NODEIDX_DEV_TTC_3,
836e82cd8cSTejas Patel 	[56] = XPM_NODEIDX_DEV_GEM_0,
846e82cd8cSTejas Patel 	[57] = XPM_NODEIDX_DEV_GEM_0,
856e82cd8cSTejas Patel 	[58] = XPM_NODEIDX_DEV_GEM_1,
866e82cd8cSTejas Patel 	[59] = XPM_NODEIDX_DEV_GEM_1,
876e82cd8cSTejas Patel 	[60] = XPM_NODEIDX_DEV_ADMA_0,
886e82cd8cSTejas Patel 	[61] = XPM_NODEIDX_DEV_ADMA_1,
896e82cd8cSTejas Patel 	[62] = XPM_NODEIDX_DEV_ADMA_2,
906e82cd8cSTejas Patel 	[63] = XPM_NODEIDX_DEV_ADMA_3,
916e82cd8cSTejas Patel 	[64] = XPM_NODEIDX_DEV_ADMA_4,
926e82cd8cSTejas Patel 	[65] = XPM_NODEIDX_DEV_ADMA_5,
936e82cd8cSTejas Patel 	[66] = XPM_NODEIDX_DEV_ADMA_6,
946e82cd8cSTejas Patel 	[67] = XPM_NODEIDX_DEV_ADMA_7,
956e82cd8cSTejas Patel 	[74] = XPM_NODEIDX_DEV_USB_0,
966e82cd8cSTejas Patel 	[126] = XPM_NODEIDX_DEV_SDIO_0,
976e82cd8cSTejas Patel 	[127] = XPM_NODEIDX_DEV_SDIO_0,
986e82cd8cSTejas Patel 	[128] = XPM_NODEIDX_DEV_SDIO_1,
996e82cd8cSTejas Patel 	[129] = XPM_NODEIDX_DEV_SDIO_1,
1006e82cd8cSTejas Patel 	[142] = XPM_NODEIDX_DEV_RTC,
1016e82cd8cSTejas Patel };
1026e82cd8cSTejas Patel 
1036e82cd8cSTejas Patel /**
1046e82cd8cSTejas Patel  * irq_to_pm_node_idx - Get PM node index corresponding to the interrupt number
1056e82cd8cSTejas Patel  * @irq:	Interrupt number
1066e82cd8cSTejas Patel  *
1076e82cd8cSTejas Patel  * Return:	PM node index corresponding to the specified interrupt
1086e82cd8cSTejas Patel  */
109912b7a6fSVenkatesh Yadav Abbarapu static enum pm_device_node_idx irq_to_pm_node_idx(uint32_t irq)
1106e82cd8cSTejas Patel {
1116e82cd8cSTejas Patel 	assert(irq <= IRQ_MAX);
1126e82cd8cSTejas Patel 	return irq_node_map[irq];
1136e82cd8cSTejas Patel }
1146e82cd8cSTejas Patel 
1156e82cd8cSTejas Patel /**
1166e82cd8cSTejas Patel  * pm_client_set_wakeup_sources - Set all devices with enabled interrupts as
1176e82cd8cSTejas Patel  *				  wake sources in the LibPM.
118b05d2792SRavi Patel  * @node_id:	Node id of processor
1196e82cd8cSTejas Patel  */
120b05d2792SRavi Patel static void pm_client_set_wakeup_sources(uint32_t node_id)
1216e82cd8cSTejas Patel {
1226e82cd8cSTejas Patel 	uint32_t reg_num;
1236e82cd8cSTejas Patel 	uint32_t device_id;
124cd73d62bSNaman Patel 	uint8_t pm_wakeup_nodes_set[XPM_NODEIDX_DEV_MAX] = { 0U };
125*31b68489SJay Buddhabhatti 	uintptr_t isenabler1 = PLAT_GICD_BASE_VALUE + GICD_ISENABLER + 4;
1266e82cd8cSTejas Patel 
1275d1c211eSAbhyuday Godhasara 	for (reg_num = 0U; reg_num < NUM_GICD_ISENABLER; reg_num++) {
1286e82cd8cSTejas Patel 		uint32_t base_irq = reg_num << ISENABLER_SHIFT;
1296e82cd8cSTejas Patel 		uint32_t reg = mmio_read_32(isenabler1 + (reg_num << 2));
1306e82cd8cSTejas Patel 
131775bf1bbSAbhyuday Godhasara 		if (reg == 0U) {
1326e82cd8cSTejas Patel 			continue;
13341567195SAbhyuday Godhasara 		}
1346e82cd8cSTejas Patel 
135775bf1bbSAbhyuday Godhasara 		while (reg != 0U) {
1366e82cd8cSTejas Patel 			enum pm_device_node_idx node_idx;
137fa98d7f2SAbhyuday Godhasara 			uint32_t idx, irq, lowest_set = reg & (-reg);
138fa98d7f2SAbhyuday Godhasara 			enum pm_ret_status ret;
139bb1768c6SMichal Simek 
1406e82cd8cSTejas Patel 			idx = __builtin_ctz(lowest_set);
1416e82cd8cSTejas Patel 			irq = base_irq + idx;
1426e82cd8cSTejas Patel 
14341567195SAbhyuday Godhasara 			if (irq > IRQ_MAX) {
1446e82cd8cSTejas Patel 				break;
14541567195SAbhyuday Godhasara 			}
1466e82cd8cSTejas Patel 
1476e82cd8cSTejas Patel 			node_idx = irq_to_pm_node_idx(irq);
1486e82cd8cSTejas Patel 			reg &= ~lowest_set;
1496e82cd8cSTejas Patel 
1500b151872STanmay Shah 			if (node_idx > XPM_NODEIDX_DEV_MIN && node_idx < XPM_NODEIDX_DEV_MAX) {
1510b151872STanmay Shah 				if (pm_wakeup_nodes_set[node_idx] == 0U) {
1526e82cd8cSTejas Patel 					/* Get device ID from node index */
1536e82cd8cSTejas Patel 					device_id = PERIPH_DEVID(node_idx);
154b05d2792SRavi Patel 					ret = pm_set_wakeup_source(node_id,
1554697164aSTejas Patel 								   device_id, 1,
1564697164aSTejas Patel 								   SECURE_FLAG);
1570b151872STanmay Shah 					pm_wakeup_nodes_set[node_idx] = (ret == PM_RET_SUCCESS) ?
1580b151872STanmay Shah 											 1 : 0;
1590b151872STanmay Shah 				}
1606e82cd8cSTejas Patel 			}
1616e82cd8cSTejas Patel 		}
1626e82cd8cSTejas Patel 	}
1636e82cd8cSTejas Patel }
1646e82cd8cSTejas Patel 
165fbb32695STejas Patel /**
166fbb32695STejas Patel  * pm_client_suspend() - Client-specific suspend actions
167fbb32695STejas Patel  *
168fbb32695STejas Patel  * This function should contain any PU-specific actions
169fbb32695STejas Patel  * required prior to sending suspend request to PMU
170fbb32695STejas Patel  * Actions taken depend on the state system is suspending to.
171fbb32695STejas Patel  */
172912b7a6fSVenkatesh Yadav Abbarapu void pm_client_suspend(const struct pm_proc *proc, uint32_t state)
173fbb32695STejas Patel {
174fbb32695STejas Patel 	bakery_lock_get(&pm_client_secure_lock);
175fbb32695STejas Patel 
17641567195SAbhyuday Godhasara 	if (state == PM_STATE_SUSPEND_TO_RAM) {
1775d1c211eSAbhyuday Godhasara 		pm_client_set_wakeup_sources((uint32_t)proc->node_id);
17841567195SAbhyuday Godhasara 	}
1796e82cd8cSTejas Patel 
180fbb32695STejas Patel 	/* Set powerdown request */
181fbb32695STejas Patel 	mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) |
182775bf1bbSAbhyuday Godhasara 		      (uint32_t)proc->pwrdn_mask);
183fbb32695STejas Patel 
184fbb32695STejas Patel 	bakery_lock_release(&pm_client_secure_lock);
185fbb32695STejas Patel }
186fbb32695STejas Patel 
187fbb32695STejas Patel /**
188fbb32695STejas Patel  * pm_client_abort_suspend() - Client-specific abort-suspend actions
189fbb32695STejas Patel  *
190fbb32695STejas Patel  * This function should contain any PU-specific actions
191fbb32695STejas Patel  * required for aborting a prior suspend request
192fbb32695STejas Patel  */
193fbb32695STejas Patel void pm_client_abort_suspend(void)
194fbb32695STejas Patel {
195fbb32695STejas Patel 	/* Enable interrupts at processor level (for current cpu) */
196fbb32695STejas Patel 	gicv3_cpuif_enable(plat_my_core_pos());
197fbb32695STejas Patel 
198fbb32695STejas Patel 	bakery_lock_get(&pm_client_secure_lock);
199fbb32695STejas Patel 
200fbb32695STejas Patel 	/* Clear powerdown request */
201fbb32695STejas Patel 	mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) &
202775bf1bbSAbhyuday Godhasara 		      ~((uint32_t)primary_proc->pwrdn_mask));
203fbb32695STejas Patel 
204fbb32695STejas Patel 	bakery_lock_release(&pm_client_secure_lock);
205fbb32695STejas Patel }
206fbb32695STejas Patel 
207fbb32695STejas Patel /**
20825b1a910STejas Patel  * pm_get_cpuid() - get the local cpu ID for a global node ID
20925b1a910STejas Patel  * @nid:	node id of the processor
21025b1a910STejas Patel  *
21125b1a910STejas Patel  * Return: the cpu ID (starting from 0) for the subsystem
21225b1a910STejas Patel  */
213912b7a6fSVenkatesh Yadav Abbarapu static uint32_t pm_get_cpuid(uint32_t nid)
21425b1a910STejas Patel {
2155d1c211eSAbhyuday Godhasara 	for (size_t i = 0U; i < ARRAY_SIZE(pm_procs_all); i++) {
21641567195SAbhyuday Godhasara 		if (pm_procs_all[i].node_id == nid) {
21725b1a910STejas Patel 			return i;
21825b1a910STejas Patel 		}
21941567195SAbhyuday Godhasara 	}
22025b1a910STejas Patel 	return UNDEFINED_CPUID;
22125b1a910STejas Patel }
22225b1a910STejas Patel 
22325b1a910STejas Patel /**
22425b1a910STejas Patel  * pm_client_wakeup() - Client-specific wakeup actions
22525b1a910STejas Patel  *
22625b1a910STejas Patel  * This function should contain any PU-specific actions
22725b1a910STejas Patel  * required for waking up another APU core
22825b1a910STejas Patel  */
22925b1a910STejas Patel void pm_client_wakeup(const struct pm_proc *proc)
23025b1a910STejas Patel {
231912b7a6fSVenkatesh Yadav Abbarapu 	uint32_t cpuid = pm_get_cpuid(proc->node_id);
23225b1a910STejas Patel 
23341567195SAbhyuday Godhasara 	if (cpuid == UNDEFINED_CPUID) {
23425b1a910STejas Patel 		return;
23541567195SAbhyuday Godhasara 	}
23625b1a910STejas Patel 
23725b1a910STejas Patel 	bakery_lock_get(&pm_client_secure_lock);
23825b1a910STejas Patel 
23925b1a910STejas Patel 	/* clear powerdown bit for affected cpu */
24025b1a910STejas Patel 	uint32_t val = mmio_read_32(FPD_APU_PWRCTL);
24125b1a910STejas Patel 	val &= ~(proc->pwrdn_mask);
24225b1a910STejas Patel 	mmio_write_32(FPD_APU_PWRCTL, val);
24325b1a910STejas Patel 
24425b1a910STejas Patel 	bakery_lock_release(&pm_client_secure_lock);
24525b1a910STejas Patel }
24625b1a910STejas Patel 
24725b1a910STejas Patel /**
248fbb32695STejas Patel  * pm_get_proc() - returns pointer to the proc structure
249fbb32695STejas Patel  * @cpuid:	id of the cpu whose proc struct pointer should be returned
250fbb32695STejas Patel  *
251fbb32695STejas Patel  * Return: pointer to a proc structure if proc is found, otherwise NULL
252fbb32695STejas Patel  */
253912b7a6fSVenkatesh Yadav Abbarapu const struct pm_proc *pm_get_proc(uint32_t cpuid)
254fbb32695STejas Patel {
25541567195SAbhyuday Godhasara 	if (cpuid < ARRAY_SIZE(pm_procs_all)) {
256fbb32695STejas Patel 		return &pm_procs_all[cpuid];
25741567195SAbhyuday Godhasara 	}
258fbb32695STejas Patel 
259fbb32695STejas Patel 	return NULL;
260fbb32695STejas Patel }
261