xref: /rk3399_ARM-atf/plat/xilinx/versal/pm_service/pm_client.c (revision 5d1c211e225d40d2926bf34483c90f907a6c5dc3)
1c73a90e5STejas Patel /*
241567195SAbhyuday Godhasara  * Copyright (c) 2019-2021, 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"
24c73a90e5STejas Patel 
2525b1a910STejas Patel #define UNDEFINED_CPUID		(~0)
26*5d1c211eSAbhyuday Godhasara #define IRQ_MAX		142U
27*5d1c211eSAbhyuday Godhasara #define NUM_GICD_ISENABLER	((IRQ_MAX >> 5U) + 1U)
2825b1a910STejas Patel 
29c73a90e5STejas Patel DEFINE_BAKERY_LOCK(pm_client_secure_lock);
30c73a90e5STejas Patel 
31c73a90e5STejas Patel static const struct pm_ipi apu_ipi = {
32c73a90e5STejas Patel 	.local_ipi_id = IPI_ID_APU,
33c73a90e5STejas Patel 	.remote_ipi_id = IPI_ID_PMC,
34c73a90e5STejas Patel 	.buffer_base = IPI_BUFFER_APU_BASE,
35c73a90e5STejas Patel };
36c73a90e5STejas Patel 
37c73a90e5STejas Patel /* Order in pm_procs_all array must match cpu ids */
38c73a90e5STejas Patel static const struct pm_proc pm_procs_all[] = {
39c73a90e5STejas Patel 	{
40c73a90e5STejas Patel 		.node_id = XPM_DEVID_ACPU_0,
41c73a90e5STejas Patel 		.ipi = &apu_ipi,
42fbb32695STejas Patel 		.pwrdn_mask = APU_0_PWRCTL_CPUPWRDWNREQ_MASK,
43c73a90e5STejas Patel 	},
44c73a90e5STejas Patel 	{
45c73a90e5STejas Patel 		.node_id = XPM_DEVID_ACPU_1,
46c73a90e5STejas Patel 		.ipi = &apu_ipi,
47fbb32695STejas Patel 		.pwrdn_mask = APU_1_PWRCTL_CPUPWRDWNREQ_MASK,
48c73a90e5STejas Patel 	}
49c73a90e5STejas Patel };
50c73a90e5STejas Patel 
51c73a90e5STejas Patel const struct pm_proc *primary_proc = &pm_procs_all[0];
52fbb32695STejas Patel 
536e82cd8cSTejas Patel /* Interrupt to PM node index map */
546e82cd8cSTejas Patel static enum pm_device_node_idx irq_node_map[IRQ_MAX + 1] = {
556e82cd8cSTejas Patel 	[13] = XPM_NODEIDX_DEV_GPIO,
566e82cd8cSTejas Patel 	[14] = XPM_NODEIDX_DEV_I2C_0,
576e82cd8cSTejas Patel 	[15] = XPM_NODEIDX_DEV_I2C_1,
586e82cd8cSTejas Patel 	[16] = XPM_NODEIDX_DEV_SPI_0,
596e82cd8cSTejas Patel 	[17] = XPM_NODEIDX_DEV_SPI_1,
606e82cd8cSTejas Patel 	[18] = XPM_NODEIDX_DEV_UART_0,
616e82cd8cSTejas Patel 	[19] = XPM_NODEIDX_DEV_UART_1,
626e82cd8cSTejas Patel 	[20] = XPM_NODEIDX_DEV_CAN_FD_0,
636e82cd8cSTejas Patel 	[21] = XPM_NODEIDX_DEV_CAN_FD_1,
646e82cd8cSTejas Patel 	[22] = XPM_NODEIDX_DEV_USB_0,
656e82cd8cSTejas Patel 	[23] = XPM_NODEIDX_DEV_USB_0,
666e82cd8cSTejas Patel 	[24] = XPM_NODEIDX_DEV_USB_0,
676e82cd8cSTejas Patel 	[25] = XPM_NODEIDX_DEV_USB_0,
686e82cd8cSTejas Patel 	[26] = XPM_NODEIDX_DEV_USB_0,
696e82cd8cSTejas Patel 	[37] = XPM_NODEIDX_DEV_TTC_0,
706e82cd8cSTejas Patel 	[38] = XPM_NODEIDX_DEV_TTC_0,
716e82cd8cSTejas Patel 	[39] = XPM_NODEIDX_DEV_TTC_0,
726e82cd8cSTejas Patel 	[40] = XPM_NODEIDX_DEV_TTC_1,
736e82cd8cSTejas Patel 	[41] = XPM_NODEIDX_DEV_TTC_1,
746e82cd8cSTejas Patel 	[42] = XPM_NODEIDX_DEV_TTC_1,
756e82cd8cSTejas Patel 	[43] = XPM_NODEIDX_DEV_TTC_2,
766e82cd8cSTejas Patel 	[44] = XPM_NODEIDX_DEV_TTC_2,
776e82cd8cSTejas Patel 	[45] = XPM_NODEIDX_DEV_TTC_2,
786e82cd8cSTejas Patel 	[46] = XPM_NODEIDX_DEV_TTC_3,
796e82cd8cSTejas Patel 	[47] = XPM_NODEIDX_DEV_TTC_3,
806e82cd8cSTejas Patel 	[48] = XPM_NODEIDX_DEV_TTC_3,
816e82cd8cSTejas Patel 	[56] = XPM_NODEIDX_DEV_GEM_0,
826e82cd8cSTejas Patel 	[57] = XPM_NODEIDX_DEV_GEM_0,
836e82cd8cSTejas Patel 	[58] = XPM_NODEIDX_DEV_GEM_1,
846e82cd8cSTejas Patel 	[59] = XPM_NODEIDX_DEV_GEM_1,
856e82cd8cSTejas Patel 	[60] = XPM_NODEIDX_DEV_ADMA_0,
866e82cd8cSTejas Patel 	[61] = XPM_NODEIDX_DEV_ADMA_1,
876e82cd8cSTejas Patel 	[62] = XPM_NODEIDX_DEV_ADMA_2,
886e82cd8cSTejas Patel 	[63] = XPM_NODEIDX_DEV_ADMA_3,
896e82cd8cSTejas Patel 	[64] = XPM_NODEIDX_DEV_ADMA_4,
906e82cd8cSTejas Patel 	[65] = XPM_NODEIDX_DEV_ADMA_5,
916e82cd8cSTejas Patel 	[66] = XPM_NODEIDX_DEV_ADMA_6,
926e82cd8cSTejas Patel 	[67] = XPM_NODEIDX_DEV_ADMA_7,
936e82cd8cSTejas Patel 	[74] = XPM_NODEIDX_DEV_USB_0,
946e82cd8cSTejas Patel 	[126] = XPM_NODEIDX_DEV_SDIO_0,
956e82cd8cSTejas Patel 	[127] = XPM_NODEIDX_DEV_SDIO_0,
966e82cd8cSTejas Patel 	[128] = XPM_NODEIDX_DEV_SDIO_1,
976e82cd8cSTejas Patel 	[129] = XPM_NODEIDX_DEV_SDIO_1,
986e82cd8cSTejas Patel 	[142] = XPM_NODEIDX_DEV_RTC,
996e82cd8cSTejas Patel };
1006e82cd8cSTejas Patel 
1016e82cd8cSTejas Patel /**
1026e82cd8cSTejas Patel  * irq_to_pm_node_idx - Get PM node index corresponding to the interrupt number
1036e82cd8cSTejas Patel  * @irq:	Interrupt number
1046e82cd8cSTejas Patel  *
1056e82cd8cSTejas Patel  * Return:	PM node index corresponding to the specified interrupt
1066e82cd8cSTejas Patel  */
1076e82cd8cSTejas Patel static enum pm_device_node_idx irq_to_pm_node_idx(unsigned int irq)
1086e82cd8cSTejas Patel {
1096e82cd8cSTejas Patel 	assert(irq <= IRQ_MAX);
1106e82cd8cSTejas Patel 	return irq_node_map[irq];
1116e82cd8cSTejas Patel }
1126e82cd8cSTejas Patel 
1136e82cd8cSTejas Patel /**
1146e82cd8cSTejas Patel  * pm_client_set_wakeup_sources - Set all devices with enabled interrupts as
1156e82cd8cSTejas Patel  *				  wake sources in the LibPM.
116b05d2792SRavi Patel  * @node_id:	Node id of processor
1176e82cd8cSTejas Patel  */
118b05d2792SRavi Patel static void pm_client_set_wakeup_sources(uint32_t node_id)
1196e82cd8cSTejas Patel {
1206e82cd8cSTejas Patel 	uint32_t reg_num;
1216e82cd8cSTejas Patel 	uint32_t device_id;
1226e82cd8cSTejas Patel 	uint8_t pm_wakeup_nodes_set[XPM_NODEIDX_DEV_MAX];
1236e82cd8cSTejas Patel 	uintptr_t isenabler1 = PLAT_VERSAL_GICD_BASE + GICD_ISENABLER + 4;
1246e82cd8cSTejas Patel 
125fa98d7f2SAbhyuday Godhasara 	zeromem(&pm_wakeup_nodes_set, (u_register_t)sizeof(pm_wakeup_nodes_set));
1266e82cd8cSTejas Patel 
127*5d1c211eSAbhyuday 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 
13141567195SAbhyuday Godhasara 		if (!reg) {
1326e82cd8cSTejas Patel 			continue;
13341567195SAbhyuday Godhasara 		}
1346e82cd8cSTejas Patel 
1356e82cd8cSTejas Patel 		while (reg) {
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;
1396e82cd8cSTejas Patel 			idx = __builtin_ctz(lowest_set);
1406e82cd8cSTejas Patel 			irq = base_irq + idx;
1416e82cd8cSTejas Patel 
14241567195SAbhyuday Godhasara 			if (irq > IRQ_MAX) {
1436e82cd8cSTejas Patel 				break;
14441567195SAbhyuday Godhasara 			}
1456e82cd8cSTejas Patel 
1466e82cd8cSTejas Patel 			node_idx = irq_to_pm_node_idx(irq);
1476e82cd8cSTejas Patel 			reg &= ~lowest_set;
1486e82cd8cSTejas Patel 
1496e82cd8cSTejas Patel 			if ((node_idx != XPM_NODEIDX_DEV_MIN) &&
1506e82cd8cSTejas Patel 			    (!pm_wakeup_nodes_set[node_idx])) {
1516e82cd8cSTejas Patel 				/* Get device ID from node index */
1526e82cd8cSTejas Patel 				device_id = PERIPH_DEVID(node_idx);
153b05d2792SRavi Patel 				ret = pm_set_wakeup_source(node_id,
1544697164aSTejas Patel 							   device_id, 1,
1554697164aSTejas Patel 							   SECURE_FLAG);
156fa98d7f2SAbhyuday Godhasara 				pm_wakeup_nodes_set[node_idx] = (uint8_t)(!ret);
1576e82cd8cSTejas Patel 			}
1586e82cd8cSTejas Patel 		}
1596e82cd8cSTejas Patel 	}
1606e82cd8cSTejas Patel }
1616e82cd8cSTejas Patel 
162fbb32695STejas Patel /**
163fbb32695STejas Patel  * pm_client_suspend() - Client-specific suspend actions
164fbb32695STejas Patel  *
165fbb32695STejas Patel  * This function should contain any PU-specific actions
166fbb32695STejas Patel  * required prior to sending suspend request to PMU
167fbb32695STejas Patel  * Actions taken depend on the state system is suspending to.
168fbb32695STejas Patel  */
169fbb32695STejas Patel void pm_client_suspend(const struct pm_proc *proc, unsigned int state)
170fbb32695STejas Patel {
171fbb32695STejas Patel 	bakery_lock_get(&pm_client_secure_lock);
172fbb32695STejas Patel 
17341567195SAbhyuday Godhasara 	if (state == PM_STATE_SUSPEND_TO_RAM) {
174*5d1c211eSAbhyuday Godhasara 		pm_client_set_wakeup_sources((uint32_t)proc->node_id);
17541567195SAbhyuday Godhasara 	}
1766e82cd8cSTejas Patel 
177fbb32695STejas Patel 	/* Set powerdown request */
178fbb32695STejas Patel 	mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) |
179fbb32695STejas Patel 		      proc->pwrdn_mask);
180fbb32695STejas Patel 
181fbb32695STejas Patel 	bakery_lock_release(&pm_client_secure_lock);
182fbb32695STejas Patel }
183fbb32695STejas Patel 
184fbb32695STejas Patel /**
185fbb32695STejas Patel  * pm_client_abort_suspend() - Client-specific abort-suspend actions
186fbb32695STejas Patel  *
187fbb32695STejas Patel  * This function should contain any PU-specific actions
188fbb32695STejas Patel  * required for aborting a prior suspend request
189fbb32695STejas Patel  */
190fbb32695STejas Patel void pm_client_abort_suspend(void)
191fbb32695STejas Patel {
192fbb32695STejas Patel 	/* Enable interrupts at processor level (for current cpu) */
193fbb32695STejas Patel 	gicv3_cpuif_enable(plat_my_core_pos());
194fbb32695STejas Patel 
195fbb32695STejas Patel 	bakery_lock_get(&pm_client_secure_lock);
196fbb32695STejas Patel 
197fbb32695STejas Patel 	/* Clear powerdown request */
198fbb32695STejas Patel 	mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) &
199fbb32695STejas Patel 		      ~primary_proc->pwrdn_mask);
200fbb32695STejas Patel 
201fbb32695STejas Patel 	bakery_lock_release(&pm_client_secure_lock);
202fbb32695STejas Patel }
203fbb32695STejas Patel 
204fbb32695STejas Patel /**
20525b1a910STejas Patel  * pm_get_cpuid() - get the local cpu ID for a global node ID
20625b1a910STejas Patel  * @nid:	node id of the processor
20725b1a910STejas Patel  *
20825b1a910STejas Patel  * Return: the cpu ID (starting from 0) for the subsystem
20925b1a910STejas Patel  */
21025b1a910STejas Patel static unsigned int pm_get_cpuid(uint32_t nid)
21125b1a910STejas Patel {
212*5d1c211eSAbhyuday Godhasara 	for (size_t i = 0U; i < ARRAY_SIZE(pm_procs_all); i++) {
21341567195SAbhyuday Godhasara 		if (pm_procs_all[i].node_id == nid) {
21425b1a910STejas Patel 			return i;
21525b1a910STejas Patel 		}
21641567195SAbhyuday Godhasara 	}
21725b1a910STejas Patel 	return UNDEFINED_CPUID;
21825b1a910STejas Patel }
21925b1a910STejas Patel 
22025b1a910STejas Patel /**
22125b1a910STejas Patel  * pm_client_wakeup() - Client-specific wakeup actions
22225b1a910STejas Patel  *
22325b1a910STejas Patel  * This function should contain any PU-specific actions
22425b1a910STejas Patel  * required for waking up another APU core
22525b1a910STejas Patel  */
22625b1a910STejas Patel void pm_client_wakeup(const struct pm_proc *proc)
22725b1a910STejas Patel {
22825b1a910STejas Patel 	unsigned int cpuid = pm_get_cpuid(proc->node_id);
22925b1a910STejas Patel 
23041567195SAbhyuday Godhasara 	if (cpuid == UNDEFINED_CPUID) {
23125b1a910STejas Patel 		return;
23241567195SAbhyuday Godhasara 	}
23325b1a910STejas Patel 
23425b1a910STejas Patel 	bakery_lock_get(&pm_client_secure_lock);
23525b1a910STejas Patel 
23625b1a910STejas Patel 	/* clear powerdown bit for affected cpu */
23725b1a910STejas Patel 	uint32_t val = mmio_read_32(FPD_APU_PWRCTL);
23825b1a910STejas Patel 	val &= ~(proc->pwrdn_mask);
23925b1a910STejas Patel 	mmio_write_32(FPD_APU_PWRCTL, val);
24025b1a910STejas Patel 
24125b1a910STejas Patel 	bakery_lock_release(&pm_client_secure_lock);
24225b1a910STejas Patel }
24325b1a910STejas Patel 
24425b1a910STejas Patel /**
245fbb32695STejas Patel  * pm_get_proc() - returns pointer to the proc structure
246fbb32695STejas Patel  * @cpuid:	id of the cpu whose proc struct pointer should be returned
247fbb32695STejas Patel  *
248fbb32695STejas Patel  * Return: pointer to a proc structure if proc is found, otherwise NULL
249fbb32695STejas Patel  */
250fbb32695STejas Patel const struct pm_proc *pm_get_proc(unsigned int cpuid)
251fbb32695STejas Patel {
25241567195SAbhyuday Godhasara 	if (cpuid < ARRAY_SIZE(pm_procs_all)) {
253fbb32695STejas Patel 		return &pm_procs_all[cpuid];
25441567195SAbhyuday Godhasara 	}
255fbb32695STejas Patel 
256fbb32695STejas Patel 	return NULL;
257fbb32695STejas Patel }
258