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