1 /* 2 * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <arch_helpers.h> 8 #include <bakery_lock.h> 9 #include <mmio.h> 10 #include <platform.h> 11 #include "../zynqmp_private.h" 12 #include "pm_ipi.h" 13 14 /* IPI message buffers */ 15 #define IPI_BUFFER_BASEADDR 0xFF990000U 16 17 #define IPI_BUFFER_RPU_0_BASE (IPI_BUFFER_BASEADDR + 0x0U) 18 #define IPI_BUFFER_RPU_1_BASE (IPI_BUFFER_BASEADDR + 0x200U) 19 #define IPI_BUFFER_APU_BASE (IPI_BUFFER_BASEADDR + 0x400U) 20 #define IPI_BUFFER_PL_0_BASE (IPI_BUFFER_BASEADDR + 0x600U) 21 #define IPI_BUFFER_PL_1_BASE (IPI_BUFFER_BASEADDR + 0x800U) 22 #define IPI_BUFFER_PL_2_BASE (IPI_BUFFER_BASEADDR + 0xA00U) 23 #define IPI_BUFFER_PL_3_BASE (IPI_BUFFER_BASEADDR + 0xC00U) 24 #define IPI_BUFFER_PMU_BASE (IPI_BUFFER_BASEADDR + 0xE00U) 25 26 #define IPI_BUFFER_TARGET_RPU_0_OFFSET 0x0U 27 #define IPI_BUFFER_TARGET_RPU_1_OFFSET 0x40U 28 #define IPI_BUFFER_TARGET_APU_OFFSET 0x80U 29 #define IPI_BUFFER_TARGET_PL_0_OFFSET 0xC0U 30 #define IPI_BUFFER_TARGET_PL_1_OFFSET 0x100U 31 #define IPI_BUFFER_TARGET_PL_2_OFFSET 0x140U 32 #define IPI_BUFFER_TARGET_PL_3_OFFSET 0x180U 33 #define IPI_BUFFER_TARGET_PMU_OFFSET 0x1C0U 34 35 #define IPI_BUFFER_MAX_WORDS 8 36 37 #define IPI_BUFFER_REQ_OFFSET 0x0U 38 #define IPI_BUFFER_RESP_OFFSET 0x20U 39 40 /* IPI Base Address */ 41 #define IPI_BASEADDR 0XFF300000 42 43 /* APU's IPI registers */ 44 #define IPI_APU_ISR (IPI_BASEADDR + 0X00000010) 45 #define IPI_APU_IER (IPI_BASEADDR + 0X00000018) 46 #define IPI_APU_IDR (IPI_BASEADDR + 0X0000001C) 47 #define IPI_APU_IXR_PMU_0_MASK (1 << 16) 48 49 #define IPI_TRIG_OFFSET 0 50 #define IPI_OBS_OFFSET 4 51 52 /* Power Management IPI interrupt number */ 53 #define PM_INT_NUM 0 54 #define IPI_PMU_PM_INT_BASE (IPI_PMU_0_TRIG + (PM_INT_NUM * 0x1000)) 55 #define IPI_PMU_PM_INT_MASK (IPI_APU_IXR_PMU_0_MASK << PM_INT_NUM) 56 #if (PM_INT_NUM < 0 || PM_INT_NUM > 3) 57 #error PM_INT_NUM value out of range 58 #endif 59 60 #define IPI_APU_MASK 1U 61 62 DEFINE_BAKERY_LOCK(pm_secure_lock); 63 64 const struct pm_ipi apu_ipi = { 65 .mask = IPI_APU_MASK, 66 .base = IPI_BASEADDR, 67 .buffer_base = IPI_BUFFER_APU_BASE, 68 }; 69 70 /** 71 * pm_ipi_init() - Initialize IPI peripheral for communication with PMU 72 * 73 * @return On success, the initialization function must return 0. 74 * Any other return value will cause the framework to ignore 75 * the service 76 * 77 * Called from pm_setup initialization function 78 */ 79 int pm_ipi_init(void) 80 { 81 bakery_lock_init(&pm_secure_lock); 82 83 /* IPI Interrupts Clear & Disable */ 84 mmio_write_32(IPI_APU_ISR, 0xffffffff); 85 mmio_write_32(IPI_APU_IDR, 0xffffffff); 86 87 return 0; 88 } 89 90 /** 91 * pm_ipi_wait() - wait for pmu to handle request 92 * @proc proc which is waiting for PMU to handle request 93 */ 94 static enum pm_ret_status pm_ipi_wait(const struct pm_proc *proc) 95 { 96 int status; 97 98 /* Wait until previous interrupt is handled by PMU */ 99 do { 100 status = mmio_read_32(proc->ipi->base + IPI_OBS_OFFSET) & 101 IPI_PMU_PM_INT_MASK; 102 /* TODO: 1) Use timer to add delay between read attempts */ 103 /* TODO: 2) Return PM_RET_ERR_TIMEOUT if this times out */ 104 } while (status); 105 106 return PM_RET_SUCCESS; 107 } 108 109 /** 110 * pm_ipi_send_common() - Sends IPI request to the PMU 111 * @proc Pointer to the processor who is initiating request 112 * @payload API id and call arguments to be written in IPI buffer 113 * 114 * Send an IPI request to the power controller. Caller needs to hold 115 * the 'pm_secure_lock' lock. 116 * 117 * @return Returns status, either success or error+reason 118 */ 119 static enum pm_ret_status pm_ipi_send_common(const struct pm_proc *proc, 120 uint32_t payload[PAYLOAD_ARG_CNT]) 121 { 122 unsigned int offset = 0; 123 uintptr_t buffer_base = proc->ipi->buffer_base + 124 IPI_BUFFER_TARGET_PMU_OFFSET + 125 IPI_BUFFER_REQ_OFFSET; 126 127 /* Wait until previous interrupt is handled by PMU */ 128 pm_ipi_wait(proc); 129 130 /* Write payload into IPI buffer */ 131 for (size_t i = 0; i < PAYLOAD_ARG_CNT; i++) { 132 mmio_write_32(buffer_base + offset, payload[i]); 133 offset += PAYLOAD_ARG_SIZE; 134 } 135 /* Generate IPI to PMU */ 136 mmio_write_32(proc->ipi->base + IPI_TRIG_OFFSET, IPI_PMU_PM_INT_MASK); 137 138 return PM_RET_SUCCESS; 139 } 140 141 /** 142 * pm_ipi_send() - Sends IPI request to the PMU 143 * @proc Pointer to the processor who is initiating request 144 * @payload API id and call arguments to be written in IPI buffer 145 * 146 * Send an IPI request to the power controller. 147 * 148 * @return Returns status, either success or error+reason 149 */ 150 enum pm_ret_status pm_ipi_send(const struct pm_proc *proc, 151 uint32_t payload[PAYLOAD_ARG_CNT]) 152 { 153 enum pm_ret_status ret; 154 155 bakery_lock_get(&pm_secure_lock); 156 157 ret = pm_ipi_send_common(proc, payload); 158 159 bakery_lock_release(&pm_secure_lock); 160 161 return ret; 162 } 163 164 165 /** 166 * pm_ipi_buff_read() - Reads IPI response after PMU has handled interrupt 167 * @proc Pointer to the processor who is waiting and reading response 168 * @value Used to return value from IPI buffer element (optional) 169 * @count Number of values to return in @value 170 * 171 * @return Returns status, either success or error+reason 172 */ 173 static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc, 174 unsigned int *value, size_t count) 175 { 176 size_t i; 177 uintptr_t buffer_base = proc->ipi->buffer_base + 178 IPI_BUFFER_TARGET_PMU_OFFSET + 179 IPI_BUFFER_RESP_OFFSET; 180 181 pm_ipi_wait(proc); 182 183 /* 184 * Read response from IPI buffer 185 * buf-0: success or error+reason 186 * buf-1: value 187 * buf-2: unused 188 * buf-3: unused 189 */ 190 for (i = 1; i <= count; i++) { 191 *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE)); 192 value++; 193 } 194 195 return mmio_read_32(buffer_base); 196 } 197 198 /** 199 * pm_ipi_buff_read_callb() - Reads IPI response after PMU has handled interrupt 200 * @value Used to return value from IPI buffer element (optional) 201 * @count Number of values to return in @value 202 * 203 * @return Returns status, either success or error+reason 204 */ 205 void pm_ipi_buff_read_callb(unsigned int *value, size_t count) 206 { 207 size_t i; 208 uintptr_t buffer_base = IPI_BUFFER_PMU_BASE + 209 IPI_BUFFER_TARGET_APU_OFFSET + 210 IPI_BUFFER_REQ_OFFSET; 211 212 if (count > IPI_BUFFER_MAX_WORDS) 213 count = IPI_BUFFER_MAX_WORDS; 214 215 for (i = 0; i <= count; i++) { 216 *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE)); 217 value++; 218 } 219 } 220 221 /** 222 * pm_ipi_send_sync() - Sends IPI request to the PMU 223 * @proc Pointer to the processor who is initiating request 224 * @payload API id and call arguments to be written in IPI buffer 225 * @value Used to return value from IPI buffer element (optional) 226 * @count Number of values to return in @value 227 * 228 * Send an IPI request to the power controller and wait for it to be handled. 229 * 230 * @return Returns status, either success or error+reason and, optionally, 231 * @value 232 */ 233 enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc, 234 uint32_t payload[PAYLOAD_ARG_CNT], 235 unsigned int *value, size_t count) 236 { 237 enum pm_ret_status ret; 238 239 bakery_lock_get(&pm_secure_lock); 240 241 ret = pm_ipi_send_common(proc, payload); 242 if (ret != PM_RET_SUCCESS) 243 goto unlock; 244 245 ret = pm_ipi_buff_read(proc, value, count); 246 247 unlock: 248 bakery_lock_release(&pm_secure_lock); 249 250 return ret; 251 } 252 253 void pm_ipi_irq_enable(void) 254 { 255 mmio_write_32(IPI_APU_IER, IPI_APU_IXR_PMU_0_MASK); 256 } 257 258 void pm_ipi_irq_disable(void) 259 { 260 mmio_write_32(IPI_APU_IDR, IPI_APU_IXR_PMU_0_MASK); 261 } 262 263 void pm_ipi_irq_clear(void) 264 { 265 mmio_write_32(IPI_APU_ISR, IPI_APU_IXR_PMU_0_MASK); 266 } 267