xref: /rk3399_ARM-atf/plat/xilinx/versal/pm_service/pm_client.c (revision bb1768c67ea06ac466e2cdc7e5338c3d23dac79d)
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)
265d1c211eSAbhyuday Godhasara #define IRQ_MAX		142U
275d1c211eSAbhyuday 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 
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;
139*bb1768c6SMichal 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 
1506e82cd8cSTejas Patel 			if ((node_idx != XPM_NODEIDX_DEV_MIN) &&
151775bf1bbSAbhyuday Godhasara 			    (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);
157fa98d7f2SAbhyuday Godhasara 				pm_wakeup_nodes_set[node_idx] = (uint8_t)(!ret);
1586e82cd8cSTejas Patel 			}
1596e82cd8cSTejas Patel 		}
1606e82cd8cSTejas Patel 	}
1616e82cd8cSTejas Patel }
1626e82cd8cSTejas Patel 
163fbb32695STejas Patel /**
164fbb32695STejas Patel  * pm_client_suspend() - Client-specific suspend actions
165fbb32695STejas Patel  *
166fbb32695STejas Patel  * This function should contain any PU-specific actions
167fbb32695STejas Patel  * required prior to sending suspend request to PMU
168fbb32695STejas Patel  * Actions taken depend on the state system is suspending to.
169fbb32695STejas Patel  */
170fbb32695STejas Patel void pm_client_suspend(const struct pm_proc *proc, unsigned int state)
171fbb32695STejas Patel {
172fbb32695STejas Patel 	bakery_lock_get(&pm_client_secure_lock);
173fbb32695STejas Patel 
17441567195SAbhyuday Godhasara 	if (state == PM_STATE_SUSPEND_TO_RAM) {
1755d1c211eSAbhyuday Godhasara 		pm_client_set_wakeup_sources((uint32_t)proc->node_id);
17641567195SAbhyuday Godhasara 	}
1776e82cd8cSTejas Patel 
178fbb32695STejas Patel 	/* Set powerdown request */
179fbb32695STejas Patel 	mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) |
180775bf1bbSAbhyuday Godhasara 		      (uint32_t)proc->pwrdn_mask);
181fbb32695STejas Patel 
182fbb32695STejas Patel 	bakery_lock_release(&pm_client_secure_lock);
183fbb32695STejas Patel }
184fbb32695STejas Patel 
185fbb32695STejas Patel /**
186fbb32695STejas Patel  * pm_client_abort_suspend() - Client-specific abort-suspend actions
187fbb32695STejas Patel  *
188fbb32695STejas Patel  * This function should contain any PU-specific actions
189fbb32695STejas Patel  * required for aborting a prior suspend request
190fbb32695STejas Patel  */
191fbb32695STejas Patel void pm_client_abort_suspend(void)
192fbb32695STejas Patel {
193fbb32695STejas Patel 	/* Enable interrupts at processor level (for current cpu) */
194fbb32695STejas Patel 	gicv3_cpuif_enable(plat_my_core_pos());
195fbb32695STejas Patel 
196fbb32695STejas Patel 	bakery_lock_get(&pm_client_secure_lock);
197fbb32695STejas Patel 
198fbb32695STejas Patel 	/* Clear powerdown request */
199fbb32695STejas Patel 	mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) &
200775bf1bbSAbhyuday Godhasara 		      ~((uint32_t)primary_proc->pwrdn_mask));
201fbb32695STejas Patel 
202fbb32695STejas Patel 	bakery_lock_release(&pm_client_secure_lock);
203fbb32695STejas Patel }
204fbb32695STejas Patel 
205fbb32695STejas Patel /**
20625b1a910STejas Patel  * pm_get_cpuid() - get the local cpu ID for a global node ID
20725b1a910STejas Patel  * @nid:	node id of the processor
20825b1a910STejas Patel  *
20925b1a910STejas Patel  * Return: the cpu ID (starting from 0) for the subsystem
21025b1a910STejas Patel  */
21125b1a910STejas Patel static unsigned int pm_get_cpuid(uint32_t nid)
21225b1a910STejas Patel {
2135d1c211eSAbhyuday Godhasara 	for (size_t i = 0U; i < ARRAY_SIZE(pm_procs_all); i++) {
21441567195SAbhyuday Godhasara 		if (pm_procs_all[i].node_id == nid) {
21525b1a910STejas Patel 			return i;
21625b1a910STejas Patel 		}
21741567195SAbhyuday Godhasara 	}
21825b1a910STejas Patel 	return UNDEFINED_CPUID;
21925b1a910STejas Patel }
22025b1a910STejas Patel 
22125b1a910STejas Patel /**
22225b1a910STejas Patel  * pm_client_wakeup() - Client-specific wakeup actions
22325b1a910STejas Patel  *
22425b1a910STejas Patel  * This function should contain any PU-specific actions
22525b1a910STejas Patel  * required for waking up another APU core
22625b1a910STejas Patel  */
22725b1a910STejas Patel void pm_client_wakeup(const struct pm_proc *proc)
22825b1a910STejas Patel {
22925b1a910STejas Patel 	unsigned int cpuid = pm_get_cpuid(proc->node_id);
23025b1a910STejas Patel 
23141567195SAbhyuday Godhasara 	if (cpuid == UNDEFINED_CPUID) {
23225b1a910STejas Patel 		return;
23341567195SAbhyuday Godhasara 	}
23425b1a910STejas Patel 
23525b1a910STejas Patel 	bakery_lock_get(&pm_client_secure_lock);
23625b1a910STejas Patel 
23725b1a910STejas Patel 	/* clear powerdown bit for affected cpu */
23825b1a910STejas Patel 	uint32_t val = mmio_read_32(FPD_APU_PWRCTL);
23925b1a910STejas Patel 	val &= ~(proc->pwrdn_mask);
24025b1a910STejas Patel 	mmio_write_32(FPD_APU_PWRCTL, val);
24125b1a910STejas Patel 
24225b1a910STejas Patel 	bakery_lock_release(&pm_client_secure_lock);
24325b1a910STejas Patel }
24425b1a910STejas Patel 
24525b1a910STejas Patel /**
246fbb32695STejas Patel  * pm_get_proc() - returns pointer to the proc structure
247fbb32695STejas Patel  * @cpuid:	id of the cpu whose proc struct pointer should be returned
248fbb32695STejas Patel  *
249fbb32695STejas Patel  * Return: pointer to a proc structure if proc is found, otherwise NULL
250fbb32695STejas Patel  */
251fbb32695STejas Patel const struct pm_proc *pm_get_proc(unsigned int cpuid)
252fbb32695STejas Patel {
25341567195SAbhyuday Godhasara 	if (cpuid < ARRAY_SIZE(pm_procs_all)) {
254fbb32695STejas Patel 		return &pm_procs_all[cpuid];
25541567195SAbhyuday Godhasara 	}
256fbb32695STejas Patel 
257fbb32695STejas Patel 	return NULL;
258fbb32695STejas Patel }
259