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