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 <assert.h> 37 #include <bakery_lock.h> 38 #include <gicv2.h> 39 #include <gic_common.h> 40 #include <bl_common.h> 41 #include <mmio.h> 42 #include <string.h> 43 #include "pm_api_sys.h" 44 #include "pm_client.h" 45 #include "pm_ipi.h" 46 #include "../zynqmp_def.h" 47 48 #define IRQ_MAX 84 49 #define NUM_GICD_ISENABLER ((IRQ_MAX >> 5) + 1) 50 #define UNDEFINED_CPUID (~0) 51 52 DEFINE_BAKERY_LOCK(pm_client_secure_lock); 53 54 extern const struct pm_ipi apu_ipi; 55 56 /* Order in pm_procs_all array must match cpu ids */ 57 static const struct pm_proc const pm_procs_all[] = { 58 { 59 .node_id = NODE_APU_0, 60 .pwrdn_mask = APU_0_PWRCTL_CPUPWRDWNREQ_MASK, 61 .ipi = &apu_ipi, 62 }, 63 { 64 .node_id = NODE_APU_1, 65 .pwrdn_mask = APU_1_PWRCTL_CPUPWRDWNREQ_MASK, 66 .ipi = &apu_ipi, 67 }, 68 { 69 .node_id = NODE_APU_2, 70 .pwrdn_mask = APU_2_PWRCTL_CPUPWRDWNREQ_MASK, 71 .ipi = &apu_ipi, 72 }, 73 { 74 .node_id = NODE_APU_3, 75 .pwrdn_mask = APU_3_PWRCTL_CPUPWRDWNREQ_MASK, 76 .ipi = &apu_ipi, 77 }, 78 }; 79 80 /* Interrupt to PM node ID map */ 81 static enum pm_node_id irq_node_map[IRQ_MAX + 1] = { 82 NODE_UNKNOWN, 83 NODE_UNKNOWN, 84 NODE_UNKNOWN, 85 NODE_UNKNOWN, /* 3 */ 86 NODE_UNKNOWN, 87 NODE_UNKNOWN, 88 NODE_UNKNOWN, 89 NODE_UNKNOWN, /* 7 */ 90 NODE_UNKNOWN, 91 NODE_UNKNOWN, 92 NODE_UNKNOWN, 93 NODE_UNKNOWN, /* 11 */ 94 NODE_UNKNOWN, 95 NODE_UNKNOWN, 96 NODE_NAND, 97 NODE_QSPI, /* 15 */ 98 NODE_GPIO, 99 NODE_I2C_0, 100 NODE_I2C_1, 101 NODE_SPI_0, /* 19 */ 102 NODE_SPI_1, 103 NODE_UART_0, 104 NODE_UART_1, 105 NODE_CAN_0, /* 23 */ 106 NODE_CAN_1, 107 NODE_UNKNOWN, 108 NODE_RTC, 109 NODE_RTC, /* 27 */ 110 NODE_UNKNOWN, 111 NODE_UNKNOWN, 112 NODE_UNKNOWN, 113 NODE_UNKNOWN, /* 31 */ 114 NODE_UNKNOWN, 115 NODE_UNKNOWN, 116 NODE_UNKNOWN, 117 NODE_UNKNOWN, /* 35, NODE_IPI_APU */ 118 NODE_TTC_0, 119 NODE_TTC_0, 120 NODE_TTC_0, 121 NODE_TTC_1, /* 39 */ 122 NODE_TTC_1, 123 NODE_TTC_1, 124 NODE_TTC_2, 125 NODE_TTC_2, /* 43 */ 126 NODE_TTC_2, 127 NODE_TTC_3, 128 NODE_TTC_3, 129 NODE_TTC_3, /* 47 */ 130 NODE_SD_0, 131 NODE_SD_1, 132 NODE_SD_0, 133 NODE_SD_1, /* 51 */ 134 NODE_UNKNOWN, 135 NODE_UNKNOWN, 136 NODE_UNKNOWN, 137 NODE_UNKNOWN, /* 55 */ 138 NODE_UNKNOWN, 139 NODE_ETH_0, 140 NODE_ETH_0, 141 NODE_ETH_1, /* 59 */ 142 NODE_ETH_1, 143 NODE_ETH_2, 144 NODE_ETH_2, 145 NODE_ETH_3, /* 63 */ 146 NODE_ETH_3, 147 NODE_USB_0, 148 NODE_USB_0, 149 NODE_USB_0, /* 67 */ 150 NODE_USB_0, 151 NODE_USB_0, 152 NODE_USB_1, 153 NODE_USB_1, /* 71 */ 154 NODE_USB_1, 155 NODE_USB_1, 156 NODE_USB_1, 157 NODE_USB_0, /* 75 */ 158 NODE_USB_0, 159 NODE_ADMA, 160 NODE_ADMA, 161 NODE_ADMA, /* 79 */ 162 NODE_ADMA, 163 NODE_ADMA, 164 NODE_ADMA, 165 NODE_ADMA, /* 83 */ 166 NODE_ADMA, 167 }; 168 169 /** 170 * irq_to_pm_node - Get PM node ID corresponding to the interrupt number 171 * @irq: Interrupt number 172 * 173 * Return: PM node ID corresponding to the specified interrupt 174 */ 175 static enum pm_node_id irq_to_pm_node(unsigned int irq) 176 { 177 assert(irq <= IRQ_MAX); 178 return irq_node_map[irq]; 179 } 180 181 /** 182 * pm_client_set_wakeup_sources - Set all slaves with enabled interrupts as wake 183 * sources in the PMU firmware 184 */ 185 static void pm_client_set_wakeup_sources(void) 186 { 187 uint32_t reg_num; 188 uint8_t pm_wakeup_nodes_set[NODE_MAX]; 189 uintptr_t isenabler1 = BASE_GICD_BASE + GICD_ISENABLER + 4; 190 191 memset(&pm_wakeup_nodes_set, 0, sizeof(pm_wakeup_nodes_set)); 192 193 for (reg_num = 0; reg_num < NUM_GICD_ISENABLER; reg_num++) { 194 uint32_t base_irq = reg_num << ISENABLER_SHIFT; 195 uint32_t reg = mmio_read_32(isenabler1 + (reg_num << 2)); 196 197 if (!reg) 198 continue; 199 200 while (reg) { 201 enum pm_node_id node; 202 uint32_t idx, ret, irq, lowest_set = reg & (-reg); 203 204 idx = __builtin_ctz(lowest_set); 205 irq = base_irq + idx; 206 207 if (irq > IRQ_MAX) 208 break; 209 210 node = irq_to_pm_node(irq); 211 reg &= ~lowest_set; 212 213 if ((node != NODE_UNKNOWN) && 214 (!pm_wakeup_nodes_set[node])) { 215 ret = pm_set_wakeup_source(NODE_APU, node, 1); 216 pm_wakeup_nodes_set[node] = !ret; 217 } 218 } 219 } 220 } 221 222 /** 223 * pm_get_proc() - returns pointer to the proc structure 224 * @cpuid: id of the cpu whose proc struct pointer should be returned 225 * 226 * Return: pointer to a proc structure if proc is found, otherwise NULL 227 */ 228 const struct pm_proc *pm_get_proc(unsigned int cpuid) 229 { 230 if (cpuid < ARRAY_SIZE(pm_procs_all)) 231 return &pm_procs_all[cpuid]; 232 233 return NULL; 234 } 235 236 /** 237 * pm_get_proc_by_node() - returns pointer to the proc structure 238 * @nid: node id of the processor 239 * 240 * Return: pointer to a proc structure if proc is found, otherwise NULL 241 */ 242 const struct pm_proc *pm_get_proc_by_node(enum pm_node_id nid) 243 { 244 for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) { 245 if (nid == pm_procs_all[i].node_id) 246 return &pm_procs_all[i]; 247 } 248 return NULL; 249 } 250 251 /** 252 * pm_get_cpuid() - get the local cpu ID for a global node ID 253 * @nid: node id of the processor 254 * 255 * Return: the cpu ID (starting from 0) for the subsystem 256 */ 257 static unsigned int pm_get_cpuid(enum pm_node_id nid) 258 { 259 for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) { 260 if (pm_procs_all[i].node_id == nid) 261 return i; 262 } 263 return UNDEFINED_CPUID; 264 } 265 266 const struct pm_proc *primary_proc = &pm_procs_all[0]; 267 268 /** 269 * pm_client_suspend() - Client-specific suspend actions 270 * 271 * This function should contain any PU-specific actions 272 * required prior to sending suspend request to PMU 273 * Actions taken depend on the state system is suspending to. 274 */ 275 void pm_client_suspend(const struct pm_proc *proc, unsigned int state) 276 { 277 bakery_lock_get(&pm_client_secure_lock); 278 279 if (state == PM_STATE_SUSPEND_TO_RAM) 280 pm_client_set_wakeup_sources(); 281 282 /* Set powerdown request */ 283 mmio_write_32(APU_PWRCTL, mmio_read_32(APU_PWRCTL) | proc->pwrdn_mask); 284 285 bakery_lock_release(&pm_client_secure_lock); 286 } 287 288 289 /** 290 * pm_client_abort_suspend() - Client-specific abort-suspend actions 291 * 292 * This function should contain any PU-specific actions 293 * required for aborting a prior suspend request 294 */ 295 void pm_client_abort_suspend(void) 296 { 297 /* Enable interrupts at processor level (for current cpu) */ 298 gicv2_cpuif_enable(); 299 300 bakery_lock_get(&pm_client_secure_lock); 301 302 /* Clear powerdown request */ 303 mmio_write_32(APU_PWRCTL, 304 mmio_read_32(APU_PWRCTL) & ~primary_proc->pwrdn_mask); 305 306 bakery_lock_release(&pm_client_secure_lock); 307 } 308 309 /** 310 * pm_client_wakeup() - Client-specific wakeup actions 311 * 312 * This function should contain any PU-specific actions 313 * required for waking up another APU core 314 */ 315 void pm_client_wakeup(const struct pm_proc *proc) 316 { 317 unsigned int cpuid = pm_get_cpuid(proc->node_id); 318 319 if (cpuid == UNDEFINED_CPUID) 320 return; 321 322 bakery_lock_get(&pm_client_secure_lock); 323 324 /* clear powerdown bit for affected cpu */ 325 uint32_t val = mmio_read_32(APU_PWRCTL); 326 val &= ~(proc->pwrdn_mask); 327 mmio_write_32(APU_PWRCTL, val); 328 329 bakery_lock_release(&pm_client_secure_lock); 330 } 331