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 UNDEFINED_CPUID (~0) 47 48 DEFINE_BAKERY_LOCK(pm_client_secure_lock); 49 50 extern const struct pm_ipi apu_ipi; 51 52 /* Order in pm_procs_all array must match cpu ids */ 53 static const struct pm_proc const pm_procs_all[] = { 54 { 55 .node_id = NODE_APU_0, 56 .pwrdn_mask = APU_0_PWRCTL_CPUPWRDWNREQ_MASK, 57 .ipi = &apu_ipi, 58 }, 59 { 60 .node_id = NODE_APU_1, 61 .pwrdn_mask = APU_1_PWRCTL_CPUPWRDWNREQ_MASK, 62 .ipi = &apu_ipi, 63 }, 64 { 65 .node_id = NODE_APU_2, 66 .pwrdn_mask = APU_2_PWRCTL_CPUPWRDWNREQ_MASK, 67 .ipi = &apu_ipi, 68 }, 69 { 70 .node_id = NODE_APU_3, 71 .pwrdn_mask = APU_3_PWRCTL_CPUPWRDWNREQ_MASK, 72 .ipi = &apu_ipi, 73 }, 74 }; 75 76 /** 77 * pm_get_proc() - returns pointer to the proc structure 78 * @cpuid: id of the cpu whose proc struct pointer should be returned 79 * 80 * Return: pointer to a proc structure if proc is found, otherwise NULL 81 */ 82 const struct pm_proc *pm_get_proc(unsigned int cpuid) 83 { 84 if (cpuid < ARRAY_SIZE(pm_procs_all)) 85 return &pm_procs_all[cpuid]; 86 87 return NULL; 88 } 89 90 /** 91 * pm_get_proc_by_node() - returns pointer to the proc structure 92 * @nid: node id of the processor 93 * 94 * Return: pointer to a proc structure if proc is found, otherwise NULL 95 */ 96 const struct pm_proc *pm_get_proc_by_node(enum pm_node_id nid) 97 { 98 for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) { 99 if (nid == pm_procs_all[i].node_id) 100 return &pm_procs_all[i]; 101 } 102 return NULL; 103 } 104 105 /** 106 * pm_get_cpuid() - get the local cpu ID for a global node ID 107 * @nid: node id of the processor 108 * 109 * Return: the cpu ID (starting from 0) for the subsystem 110 */ 111 static unsigned int pm_get_cpuid(enum pm_node_id nid) 112 { 113 for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) { 114 if (pm_procs_all[i].node_id == nid) 115 return i; 116 } 117 return UNDEFINED_CPUID; 118 } 119 120 const struct pm_proc *primary_proc = &pm_procs_all[0]; 121 122 /** 123 * pm_client_suspend() - Client-specific suspend actions 124 * 125 * This function should contain any PU-specific actions 126 * required prior to sending suspend request to PMU 127 */ 128 void pm_client_suspend(const struct pm_proc *proc) 129 { 130 bakery_lock_get(&pm_client_secure_lock); 131 132 /* Set powerdown request */ 133 mmio_write_32(APU_PWRCTL, mmio_read_32(APU_PWRCTL) | proc->pwrdn_mask); 134 135 bakery_lock_release(&pm_client_secure_lock); 136 } 137 138 139 /** 140 * pm_client_abort_suspend() - Client-specific abort-suspend actions 141 * 142 * This function should contain any PU-specific actions 143 * required for aborting a prior suspend request 144 */ 145 void pm_client_abort_suspend(void) 146 { 147 /* Enable interrupts at processor level (for current cpu) */ 148 gicv2_cpuif_enable(); 149 150 bakery_lock_get(&pm_client_secure_lock); 151 152 /* Clear powerdown request */ 153 mmio_write_32(APU_PWRCTL, 154 mmio_read_32(APU_PWRCTL) & ~primary_proc->pwrdn_mask); 155 156 bakery_lock_release(&pm_client_secure_lock); 157 } 158 159 /** 160 * pm_client_wakeup() - Client-specific wakeup actions 161 * 162 * This function should contain any PU-specific actions 163 * required for waking up another APU core 164 */ 165 void pm_client_wakeup(const struct pm_proc *proc) 166 { 167 unsigned int cpuid = pm_get_cpuid(proc->node_id); 168 169 if (cpuid == UNDEFINED_CPUID) 170 return; 171 172 bakery_lock_get(&pm_client_secure_lock); 173 174 /* clear powerdown bit for affected cpu */ 175 uint32_t val = mmio_read_32(APU_PWRCTL); 176 val &= ~(proc->pwrdn_mask); 177 mmio_write_32(APU_PWRCTL, val); 178 179 bakery_lock_release(&pm_client_secure_lock); 180 } 181