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