1dc1dfe83SWendy Liang /* 2dc1dfe83SWendy Liang * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. 3dc1dfe83SWendy Liang * 4dc1dfe83SWendy Liang * SPDX-License-Identifier: BSD-3-Clause 5dc1dfe83SWendy Liang */ 6dc1dfe83SWendy Liang 7dc1dfe83SWendy Liang /* 8dc1dfe83SWendy Liang * Zynq UltraScale+ MPSoC IPI agent registers access management 9dc1dfe83SWendy Liang */ 10dc1dfe83SWendy Liang 11dc1dfe83SWendy Liang #include <bakery_lock.h> 12dc1dfe83SWendy Liang #include <debug.h> 13dc1dfe83SWendy Liang #include <errno.h> 14dc1dfe83SWendy Liang #include <mmio.h> 15dc1dfe83SWendy Liang #include <runtime_svc.h> 16dc1dfe83SWendy Liang #include <string.h> 17dc1dfe83SWendy Liang #include "zynqmp_ipi.h" 18dc1dfe83SWendy Liang #include "../zynqmp_private.h" 19dc1dfe83SWendy Liang 20dc1dfe83SWendy Liang /********************************************************************* 21dc1dfe83SWendy Liang * Macros definitions 22dc1dfe83SWendy Liang ********************************************************************/ 23dc1dfe83SWendy Liang 24dc1dfe83SWendy Liang /* IPI registers base address */ 25dc1dfe83SWendy Liang #define IPI_REGS_BASE 0xFF300000U 26dc1dfe83SWendy Liang 27dc1dfe83SWendy Liang /* IPI registers offsets macros */ 28dc1dfe83SWendy Liang #define IPI_TRIG_OFFSET 0x00U 29dc1dfe83SWendy Liang #define IPI_OBR_OFFSET 0x04U 30dc1dfe83SWendy Liang #define IPI_ISR_OFFSET 0x10U 31dc1dfe83SWendy Liang #define IPI_IMR_OFFSET 0x14U 32dc1dfe83SWendy Liang #define IPI_IER_OFFSET 0x18U 33dc1dfe83SWendy Liang #define IPI_IDR_OFFSET 0x1CU 34dc1dfe83SWendy Liang 35dc1dfe83SWendy Liang /* IPI register start offset */ 36dc1dfe83SWendy Liang #define IPI_REG_BASE(I) (zynqmp_ipi_table[(I)].ipi_reg_base) 37dc1dfe83SWendy Liang 38dc1dfe83SWendy Liang /* IPI register bit mask */ 39dc1dfe83SWendy Liang #define IPI_BIT_MASK(I) (zynqmp_ipi_table[(I)].ipi_bit_mask) 40dc1dfe83SWendy Liang 41dc1dfe83SWendy Liang /* IPI secure check */ 42dc1dfe83SWendy Liang #define IPI_SECURE_MASK 0x1U 43dc1dfe83SWendy Liang #define IPI_IS_SECURE(I) ((zynqmp_ipi_table[(I)].secure_only & \ 44dc1dfe83SWendy Liang IPI_SECURE_MASK) ? 1 : 0) 45dc1dfe83SWendy Liang 46dc1dfe83SWendy Liang /********************************************************************* 47dc1dfe83SWendy Liang * Struct definitions 48dc1dfe83SWendy Liang ********************************************************************/ 49dc1dfe83SWendy Liang 50dc1dfe83SWendy Liang /* structure to maintain IPI configuration information */ 51dc1dfe83SWendy Liang struct zynqmp_ipi_config { 52dc1dfe83SWendy Liang unsigned int ipi_bit_mask; 53dc1dfe83SWendy Liang unsigned int ipi_reg_base; 54dc1dfe83SWendy Liang unsigned char secure_only; 55dc1dfe83SWendy Liang }; 56dc1dfe83SWendy Liang 57dc1dfe83SWendy Liang /* Zynqmp ipi configuration table */ 58dc1dfe83SWendy Liang const static struct zynqmp_ipi_config zynqmp_ipi_table[] = { 59dc1dfe83SWendy Liang /* APU IPI */ 60dc1dfe83SWendy Liang { 61dc1dfe83SWendy Liang .ipi_bit_mask = 0x1, 62dc1dfe83SWendy Liang .ipi_reg_base = 0xFF300000, 63dc1dfe83SWendy Liang .secure_only = 0, 64dc1dfe83SWendy Liang }, 65dc1dfe83SWendy Liang /* RPU0 IPI */ 66dc1dfe83SWendy Liang { 67dc1dfe83SWendy Liang .ipi_bit_mask = 0x100, 68dc1dfe83SWendy Liang .ipi_reg_base = 0xFF310000, 69dc1dfe83SWendy Liang .secure_only = 0, 70dc1dfe83SWendy Liang }, 71dc1dfe83SWendy Liang /* RPU1 IPI */ 72dc1dfe83SWendy Liang { 73dc1dfe83SWendy Liang .ipi_bit_mask = 0x200, 74dc1dfe83SWendy Liang .ipi_reg_base = 0xFF320000, 75dc1dfe83SWendy Liang .secure_only = 0, 76dc1dfe83SWendy Liang }, 77dc1dfe83SWendy Liang /* PMU0 IPI */ 78dc1dfe83SWendy Liang { 79dc1dfe83SWendy Liang .ipi_bit_mask = 0x10000, 80dc1dfe83SWendy Liang .ipi_reg_base = 0xFF330000, 81dc1dfe83SWendy Liang .secure_only = IPI_SECURE_MASK, 82dc1dfe83SWendy Liang }, 83dc1dfe83SWendy Liang /* PMU1 IPI */ 84dc1dfe83SWendy Liang { 85dc1dfe83SWendy Liang .ipi_bit_mask = 0x20000, 86dc1dfe83SWendy Liang .ipi_reg_base = 0xFF331000, 87*85dc2d4dSRajan Vaja .secure_only = 0, 88dc1dfe83SWendy Liang }, 89dc1dfe83SWendy Liang /* PMU2 IPI */ 90dc1dfe83SWendy Liang { 91dc1dfe83SWendy Liang .ipi_bit_mask = 0x40000, 92dc1dfe83SWendy Liang .ipi_reg_base = 0xFF332000, 93dc1dfe83SWendy Liang .secure_only = IPI_SECURE_MASK, 94dc1dfe83SWendy Liang }, 95dc1dfe83SWendy Liang /* PMU3 IPI */ 96dc1dfe83SWendy Liang { 97dc1dfe83SWendy Liang .ipi_bit_mask = 0x80000, 98dc1dfe83SWendy Liang .ipi_reg_base = 0xFF333000, 99dc1dfe83SWendy Liang .secure_only = IPI_SECURE_MASK, 100dc1dfe83SWendy Liang }, 101dc1dfe83SWendy Liang /* PL0 IPI */ 102dc1dfe83SWendy Liang { 103dc1dfe83SWendy Liang .ipi_bit_mask = 0x1000000, 104dc1dfe83SWendy Liang .ipi_reg_base = 0xFF340000, 105dc1dfe83SWendy Liang .secure_only = 0, 106dc1dfe83SWendy Liang }, 107dc1dfe83SWendy Liang /* PL1 IPI */ 108dc1dfe83SWendy Liang { 109dc1dfe83SWendy Liang .ipi_bit_mask = 0x2000000, 110dc1dfe83SWendy Liang .ipi_reg_base = 0xFF350000, 111dc1dfe83SWendy Liang .secure_only = 0, 112dc1dfe83SWendy Liang }, 113dc1dfe83SWendy Liang /* PL2 IPI */ 114dc1dfe83SWendy Liang { 115dc1dfe83SWendy Liang .ipi_bit_mask = 0x4000000, 116dc1dfe83SWendy Liang .ipi_reg_base = 0xFF360000, 117dc1dfe83SWendy Liang .secure_only = 0, 118dc1dfe83SWendy Liang }, 119dc1dfe83SWendy Liang /* PL3 IPI */ 120dc1dfe83SWendy Liang { 121dc1dfe83SWendy Liang .ipi_bit_mask = 0x8000000, 122dc1dfe83SWendy Liang .ipi_reg_base = 0xFF370000, 123dc1dfe83SWendy Liang .secure_only = 0, 124dc1dfe83SWendy Liang }, 125dc1dfe83SWendy Liang }; 126dc1dfe83SWendy Liang 127dc1dfe83SWendy Liang /* is_ipi_mb_within_range() - verify if IPI mailbox is within range 128dc1dfe83SWendy Liang * 129dc1dfe83SWendy Liang * @local - local IPI ID 130dc1dfe83SWendy Liang * @remote - remote IPI ID 131dc1dfe83SWendy Liang * 132dc1dfe83SWendy Liang * return - 1 if within range, 0 if not 133dc1dfe83SWendy Liang */ 134dc1dfe83SWendy Liang static inline int is_ipi_mb_within_range(uint32_t local, uint32_t remote) 135dc1dfe83SWendy Liang { 136dc1dfe83SWendy Liang int ret = 1; 137dc1dfe83SWendy Liang uint32_t ipi_total = ARRAY_SIZE(zynqmp_ipi_table); 138dc1dfe83SWendy Liang 139dc1dfe83SWendy Liang if (remote >= ipi_total || local >= ipi_total) 140dc1dfe83SWendy Liang ret = 0; 141dc1dfe83SWendy Liang 142dc1dfe83SWendy Liang return ret; 143dc1dfe83SWendy Liang } 144dc1dfe83SWendy Liang 145dc1dfe83SWendy Liang /** 146dc1dfe83SWendy Liang * ipi_mb_validate() - validate IPI mailbox access 147dc1dfe83SWendy Liang * 148dc1dfe83SWendy Liang * @local - local IPI ID 149dc1dfe83SWendy Liang * @remote - remote IPI ID 150dc1dfe83SWendy Liang * @is_secure - indicate if the requester is from secure software 151dc1dfe83SWendy Liang * 152dc1dfe83SWendy Liang * return - 0 success, negative value for errors 153dc1dfe83SWendy Liang */ 154dc1dfe83SWendy Liang int ipi_mb_validate(uint32_t local, uint32_t remote, unsigned int is_secure) 155dc1dfe83SWendy Liang { 156dc1dfe83SWendy Liang int ret = 0; 157dc1dfe83SWendy Liang 158dc1dfe83SWendy Liang if (!is_ipi_mb_within_range(local, remote)) 159dc1dfe83SWendy Liang ret = -EINVAL; 160dc1dfe83SWendy Liang else if (IPI_IS_SECURE(local) && !is_secure) 161dc1dfe83SWendy Liang ret = -EPERM; 162dc1dfe83SWendy Liang else if (IPI_IS_SECURE(remote) && !is_secure) 163dc1dfe83SWendy Liang ret = -EPERM; 164dc1dfe83SWendy Liang 165dc1dfe83SWendy Liang return ret; 166dc1dfe83SWendy Liang } 167dc1dfe83SWendy Liang 168dc1dfe83SWendy Liang /** 169dc1dfe83SWendy Liang * ipi_mb_open() - Open IPI mailbox. 170dc1dfe83SWendy Liang * 171dc1dfe83SWendy Liang * @local - local IPI ID 172dc1dfe83SWendy Liang * @remote - remote IPI ID 173dc1dfe83SWendy Liang * 174dc1dfe83SWendy Liang */ 175dc1dfe83SWendy Liang void ipi_mb_open(uint32_t local, uint32_t remote) 176dc1dfe83SWendy Liang { 177dc1dfe83SWendy Liang mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET, 178dc1dfe83SWendy Liang IPI_BIT_MASK(remote)); 179dc1dfe83SWendy Liang mmio_write_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET, 180dc1dfe83SWendy Liang IPI_BIT_MASK(remote)); 181dc1dfe83SWendy Liang } 182dc1dfe83SWendy Liang 183dc1dfe83SWendy Liang /** 184dc1dfe83SWendy Liang * ipi_mb_release() - Open IPI mailbox. 185dc1dfe83SWendy Liang * 186dc1dfe83SWendy Liang * @local - local IPI ID 187dc1dfe83SWendy Liang * @remote - remote IPI ID 188dc1dfe83SWendy Liang * 189dc1dfe83SWendy Liang */ 190dc1dfe83SWendy Liang void ipi_mb_release(uint32_t local, uint32_t remote) 191dc1dfe83SWendy Liang { 192dc1dfe83SWendy Liang mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET, 193dc1dfe83SWendy Liang IPI_BIT_MASK(remote)); 194dc1dfe83SWendy Liang } 195dc1dfe83SWendy Liang 196dc1dfe83SWendy Liang /** 197dc1dfe83SWendy Liang * ipi_mb_enquire_status() - Enquire IPI mailbox status 198dc1dfe83SWendy Liang * 199dc1dfe83SWendy Liang * @local - local IPI ID 200dc1dfe83SWendy Liang * @remote - remote IPI ID 201dc1dfe83SWendy Liang * 202dc1dfe83SWendy Liang * return - 0 idle, positive value for pending sending or receiving, 203dc1dfe83SWendy Liang * negative value for errors 204dc1dfe83SWendy Liang */ 205dc1dfe83SWendy Liang int ipi_mb_enquire_status(uint32_t local, uint32_t remote) 206dc1dfe83SWendy Liang { 207dc1dfe83SWendy Liang int ret = 0; 208dc1dfe83SWendy Liang uint32_t status; 209dc1dfe83SWendy Liang 210dc1dfe83SWendy Liang status = mmio_read_32(IPI_REG_BASE(local) + IPI_OBR_OFFSET); 211dc1dfe83SWendy Liang if (status & IPI_BIT_MASK(remote)) 212dc1dfe83SWendy Liang ret |= IPI_MB_STATUS_SEND_PENDING; 213dc1dfe83SWendy Liang status = mmio_read_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET); 214dc1dfe83SWendy Liang if (status & IPI_BIT_MASK(remote)) 215dc1dfe83SWendy Liang ret |= IPI_MB_STATUS_RECV_PENDING; 216dc1dfe83SWendy Liang 217dc1dfe83SWendy Liang return ret; 218dc1dfe83SWendy Liang } 219dc1dfe83SWendy Liang 220dc1dfe83SWendy Liang /* ipi_mb_notify() - Trigger IPI mailbox notification 221dc1dfe83SWendy Liang * 222dc1dfe83SWendy Liang * @local - local IPI ID 223dc1dfe83SWendy Liang * @remote - remote IPI ID 224dc1dfe83SWendy Liang * @is_blocking - if to trigger the notification in blocking mode or not. 225dc1dfe83SWendy Liang * 226dc1dfe83SWendy Liang * It sets the remote bit in the IPI agent trigger register. 227dc1dfe83SWendy Liang * 228dc1dfe83SWendy Liang */ 229dc1dfe83SWendy Liang void ipi_mb_notify(uint32_t local, uint32_t remote, uint32_t is_blocking) 230dc1dfe83SWendy Liang { 231dc1dfe83SWendy Liang uint32_t status; 232dc1dfe83SWendy Liang 233dc1dfe83SWendy Liang mmio_write_32(IPI_REG_BASE(local) + IPI_TRIG_OFFSET, 234dc1dfe83SWendy Liang IPI_BIT_MASK(remote)); 235dc1dfe83SWendy Liang if (is_blocking) { 236dc1dfe83SWendy Liang do { 237dc1dfe83SWendy Liang status = mmio_read_32(IPI_REG_BASE(local) + 238dc1dfe83SWendy Liang IPI_OBR_OFFSET); 239dc1dfe83SWendy Liang } while (status & IPI_BIT_MASK(remote)); 240dc1dfe83SWendy Liang } 241dc1dfe83SWendy Liang } 242dc1dfe83SWendy Liang 243dc1dfe83SWendy Liang /* ipi_mb_ack() - Ack IPI mailbox notification from the other end 244dc1dfe83SWendy Liang * 245dc1dfe83SWendy Liang * @local - local IPI ID 246dc1dfe83SWendy Liang * @remote - remote IPI ID 247dc1dfe83SWendy Liang * 248dc1dfe83SWendy Liang * It will clear the remote bit in the isr register. 249dc1dfe83SWendy Liang * 250dc1dfe83SWendy Liang */ 251dc1dfe83SWendy Liang void ipi_mb_ack(uint32_t local, uint32_t remote) 252dc1dfe83SWendy Liang { 253dc1dfe83SWendy Liang mmio_write_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET, 254dc1dfe83SWendy Liang IPI_BIT_MASK(remote)); 255dc1dfe83SWendy Liang } 256dc1dfe83SWendy Liang 257dc1dfe83SWendy Liang /* ipi_mb_disable_irq() - Disable IPI mailbox notification interrupt 258dc1dfe83SWendy Liang * 259dc1dfe83SWendy Liang * @local - local IPI ID 260dc1dfe83SWendy Liang * @remote - remote IPI ID 261dc1dfe83SWendy Liang * 262dc1dfe83SWendy Liang * It will mask the remote bit in the idr register. 263dc1dfe83SWendy Liang * 264dc1dfe83SWendy Liang */ 265dc1dfe83SWendy Liang void ipi_mb_disable_irq(uint32_t local, uint32_t remote) 266dc1dfe83SWendy Liang { 267dc1dfe83SWendy Liang mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET, 268dc1dfe83SWendy Liang IPI_BIT_MASK(remote)); 269dc1dfe83SWendy Liang } 270dc1dfe83SWendy Liang 271dc1dfe83SWendy Liang /* ipi_mb_enable_irq() - Enable IPI mailbox notification interrupt 272dc1dfe83SWendy Liang * 273dc1dfe83SWendy Liang * @local - local IPI ID 274dc1dfe83SWendy Liang * @remote - remote IPI ID 275dc1dfe83SWendy Liang * 276dc1dfe83SWendy Liang * It will mask the remote bit in the idr register. 277dc1dfe83SWendy Liang * 278dc1dfe83SWendy Liang */ 279dc1dfe83SWendy Liang void ipi_mb_enable_irq(uint32_t local, uint32_t remote) 280dc1dfe83SWendy Liang { 281dc1dfe83SWendy Liang mmio_write_32(IPI_REG_BASE(local) + IPI_IER_OFFSET, 282dc1dfe83SWendy Liang IPI_BIT_MASK(remote)); 283dc1dfe83SWendy Liang } 284