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