xref: /rk3399_ARM-atf/plat/xilinx/versal/pm_service/pm_client.c (revision 5a8ffeabf97eb7fb1e1276cb967584af0ff7adbb)
1 /*
2  * Copyright (c) 2019, Xilinx, Inc. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 /*
8  * APU specific definition of processors in the subsystem as well as functions
9  * for getting information about and changing state of the APU.
10  */
11 
12 #include <plat_ipi.h>
13 #include <platform_def.h>
14 #include <versal_def.h>
15 #include <lib/bakery_lock.h>
16 #include <lib/mmio.h>
17 #include <drivers/arm/gicv3.h>
18 #include <plat/common/platform.h>
19 #include "pm_client.h"
20 
21 #define UNDEFINED_CPUID		(~0)
22 
23 DEFINE_BAKERY_LOCK(pm_client_secure_lock);
24 
25 static const struct pm_ipi apu_ipi = {
26 	.local_ipi_id = IPI_ID_APU,
27 	.remote_ipi_id = IPI_ID_PMC,
28 	.buffer_base = IPI_BUFFER_APU_BASE,
29 };
30 
31 /* Order in pm_procs_all array must match cpu ids */
32 static const struct pm_proc pm_procs_all[] = {
33 	{
34 		.node_id = XPM_DEVID_ACPU_0,
35 		.ipi = &apu_ipi,
36 		.pwrdn_mask = APU_0_PWRCTL_CPUPWRDWNREQ_MASK,
37 	},
38 	{
39 		.node_id = XPM_DEVID_ACPU_1,
40 		.ipi = &apu_ipi,
41 		.pwrdn_mask = APU_1_PWRCTL_CPUPWRDWNREQ_MASK,
42 	}
43 };
44 
45 const struct pm_proc *primary_proc = &pm_procs_all[0];
46 
47 /**
48  * pm_client_suspend() - Client-specific suspend actions
49  *
50  * This function should contain any PU-specific actions
51  * required prior to sending suspend request to PMU
52  * Actions taken depend on the state system is suspending to.
53  */
54 void pm_client_suspend(const struct pm_proc *proc, unsigned int state)
55 {
56 	bakery_lock_get(&pm_client_secure_lock);
57 
58 	/* Set powerdown request */
59 	mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) |
60 		      proc->pwrdn_mask);
61 
62 	bakery_lock_release(&pm_client_secure_lock);
63 }
64 
65 /**
66  * pm_client_abort_suspend() - Client-specific abort-suspend actions
67  *
68  * This function should contain any PU-specific actions
69  * required for aborting a prior suspend request
70  */
71 void pm_client_abort_suspend(void)
72 {
73 	/* Enable interrupts at processor level (for current cpu) */
74 	gicv3_cpuif_enable(plat_my_core_pos());
75 
76 	bakery_lock_get(&pm_client_secure_lock);
77 
78 	/* Clear powerdown request */
79 	mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) &
80 		      ~primary_proc->pwrdn_mask);
81 
82 	bakery_lock_release(&pm_client_secure_lock);
83 }
84 
85 /**
86  * pm_get_cpuid() - get the local cpu ID for a global node ID
87  * @nid:	node id of the processor
88  *
89  * Return: the cpu ID (starting from 0) for the subsystem
90  */
91 static unsigned int pm_get_cpuid(uint32_t nid)
92 {
93 	for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
94 		if (pm_procs_all[i].node_id == nid)
95 			return i;
96 	}
97 	return UNDEFINED_CPUID;
98 }
99 
100 /**
101  * pm_client_wakeup() - Client-specific wakeup actions
102  *
103  * This function should contain any PU-specific actions
104  * required for waking up another APU core
105  */
106 void pm_client_wakeup(const struct pm_proc *proc)
107 {
108 	unsigned int cpuid = pm_get_cpuid(proc->node_id);
109 
110 	if (cpuid == UNDEFINED_CPUID)
111 		return;
112 
113 	bakery_lock_get(&pm_client_secure_lock);
114 
115 	/* clear powerdown bit for affected cpu */
116 	uint32_t val = mmio_read_32(FPD_APU_PWRCTL);
117 	val &= ~(proc->pwrdn_mask);
118 	mmio_write_32(FPD_APU_PWRCTL, val);
119 
120 	bakery_lock_release(&pm_client_secure_lock);
121 }
122 
123 /**
124  * pm_get_proc() - returns pointer to the proc structure
125  * @cpuid:	id of the cpu whose proc struct pointer should be returned
126  *
127  * Return: pointer to a proc structure if proc is found, otherwise NULL
128  */
129 const struct pm_proc *pm_get_proc(unsigned int cpuid)
130 {
131 	if (cpuid < ARRAY_SIZE(pm_procs_all))
132 		return &pm_procs_all[cpuid];
133 
134 	return NULL;
135 }
136