1 /* 2 * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * Redistributions of source code must retain the above copyright notice, this 8 * list of conditions and the following disclaimer. 9 * 10 * Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * Neither the name of ARM nor the names of its contributors may be used 15 * to endorse or promote products derived from this software without specific 16 * prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 /* 32 * APU specific definition of processors in the subsystem as well as functions 33 * for getting information about and changing state of the APU. 34 */ 35 36 #include <bakery_lock.h> 37 #include <gicv2.h> 38 #include <bl_common.h> 39 #include <mmio.h> 40 #include <utils.h> 41 #include "pm_api_sys.h" 42 #include "pm_client.h" 43 #include "pm_ipi.h" 44 #include "../zynqmp_def.h" 45 46 #define OCM_BANK_0 0xFFFC0000 47 #define OCM_BANK_1 (OCM_BANK_0 + 0x10000) 48 #define OCM_BANK_2 (OCM_BANK_1 + 0x10000) 49 #define OCM_BANK_3 (OCM_BANK_2 + 0x10000) 50 51 #define UNDEFINED_CPUID (~0) 52 DEFINE_BAKERY_LOCK(pm_client_secure_lock); 53 54 /* Declaration of linker defined symbol */ 55 extern unsigned long __BL31_END__; 56 extern const struct pm_ipi apu_ipi; 57 58 /* Order in pm_procs_all array must match cpu ids */ 59 static const struct pm_proc const pm_procs_all[] = { 60 { 61 .node_id = NODE_APU_0, 62 .pwrdn_mask = APU_0_PWRCTL_CPUPWRDWNREQ_MASK, 63 .ipi = &apu_ipi, 64 }, 65 { 66 .node_id = NODE_APU_1, 67 .pwrdn_mask = APU_1_PWRCTL_CPUPWRDWNREQ_MASK, 68 .ipi = &apu_ipi, 69 }, 70 { 71 .node_id = NODE_APU_2, 72 .pwrdn_mask = APU_2_PWRCTL_CPUPWRDWNREQ_MASK, 73 .ipi = &apu_ipi, 74 }, 75 { 76 .node_id = NODE_APU_3, 77 .pwrdn_mask = APU_3_PWRCTL_CPUPWRDWNREQ_MASK, 78 .ipi = &apu_ipi, 79 }, 80 }; 81 82 /** 83 * set_ocm_retention() - Configure OCM memory banks for retention 84 * 85 * APU specific requirements for suspend action: 86 * OCM has to enter retention state in order to preserve saved 87 * context after suspend request. OCM banks are determined by 88 * __BL31_END__ linker symbol. 89 * 90 * Return: Returns status, either success or error+reason 91 */ 92 enum pm_ret_status set_ocm_retention(void) 93 { 94 enum pm_ret_status ret; 95 96 /* OCM_BANK_0 will always be occupied */ 97 ret = pm_set_requirement(NODE_OCM_BANK_0, PM_CAP_CONTEXT, 0, 98 REQ_ACK_NO); 99 100 /* Check for other OCM banks */ 101 if ((unsigned long)&__BL31_END__ >= OCM_BANK_1) 102 ret = pm_set_requirement(NODE_OCM_BANK_1, PM_CAP_CONTEXT, 0, 103 REQ_ACK_NO); 104 if ((unsigned long)&__BL31_END__ >= OCM_BANK_2) 105 ret = pm_set_requirement(NODE_OCM_BANK_2, PM_CAP_CONTEXT, 0, 106 REQ_ACK_NO); 107 if ((unsigned long)&__BL31_END__ >= OCM_BANK_3) 108 ret = pm_set_requirement(NODE_OCM_BANK_3, PM_CAP_CONTEXT, 0, 109 REQ_ACK_NO); 110 111 return ret; 112 } 113 114 /** 115 * pm_get_proc() - returns pointer to the proc structure 116 * @cpuid: id of the cpu whose proc struct pointer should be returned 117 * 118 * Return: pointer to a proc structure if proc is found, otherwise NULL 119 */ 120 const struct pm_proc *pm_get_proc(unsigned int cpuid) 121 { 122 if (cpuid < ARRAY_SIZE(pm_procs_all)) 123 return &pm_procs_all[cpuid]; 124 125 return NULL; 126 } 127 128 /** 129 * pm_get_proc_by_node() - returns pointer to the proc structure 130 * @nid: node id of the processor 131 * 132 * Return: pointer to a proc structure if proc is found, otherwise NULL 133 */ 134 const struct pm_proc *pm_get_proc_by_node(enum pm_node_id nid) 135 { 136 for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) { 137 if (nid == pm_procs_all[i].node_id) 138 return &pm_procs_all[i]; 139 } 140 return NULL; 141 } 142 143 /** 144 * pm_get_cpuid() - get the local cpu ID for a global node ID 145 * @nid: node id of the processor 146 * 147 * Return: the cpu ID (starting from 0) for the subsystem 148 */ 149 static unsigned int pm_get_cpuid(enum pm_node_id nid) 150 { 151 for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) { 152 if (pm_procs_all[i].node_id == nid) 153 return i; 154 } 155 return UNDEFINED_CPUID; 156 } 157 158 const struct pm_proc *primary_proc = &pm_procs_all[0]; 159 160 /** 161 * pm_client_suspend() - Client-specific suspend actions 162 * 163 * This function should contain any PU-specific actions 164 * required prior to sending suspend request to PMU 165 */ 166 void pm_client_suspend(const struct pm_proc *proc) 167 { 168 bakery_lock_get(&pm_client_secure_lock); 169 170 /* Set powerdown request */ 171 mmio_write_32(APU_PWRCTL, mmio_read_32(APU_PWRCTL) | proc->pwrdn_mask); 172 173 bakery_lock_release(&pm_client_secure_lock); 174 } 175 176 177 /** 178 * pm_client_abort_suspend() - Client-specific abort-suspend actions 179 * 180 * This function should contain any PU-specific actions 181 * required for aborting a prior suspend request 182 */ 183 void pm_client_abort_suspend(void) 184 { 185 /* Enable interrupts at processor level (for current cpu) */ 186 gicv2_cpuif_enable(); 187 188 bakery_lock_get(&pm_client_secure_lock); 189 190 /* Clear powerdown request */ 191 mmio_write_32(APU_PWRCTL, 192 mmio_read_32(APU_PWRCTL) & ~primary_proc->pwrdn_mask); 193 194 bakery_lock_release(&pm_client_secure_lock); 195 } 196 197 /** 198 * pm_client_wakeup() - Client-specific wakeup actions 199 * 200 * This function should contain any PU-specific actions 201 * required for waking up another APU core 202 */ 203 void pm_client_wakeup(const struct pm_proc *proc) 204 { 205 unsigned int cpuid = pm_get_cpuid(proc->node_id); 206 207 if (cpuid == UNDEFINED_CPUID) 208 return; 209 210 bakery_lock_get(&pm_client_secure_lock); 211 212 /* clear powerdown bit for affected cpu */ 213 uint32_t val = mmio_read_32(APU_PWRCTL); 214 val &= ~(proc->pwrdn_mask); 215 mmio_write_32(APU_PWRCTL, val); 216 217 bakery_lock_release(&pm_client_secure_lock); 218 } 219