1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu * 6*91f16700Schasinglulu * The RPi4 has a single nonstandard PCI config region. It is broken into two 7*91f16700Schasinglulu * pieces, the root port config registers and a window to a single device's 8*91f16700Schasinglulu * config space which can move between devices. There isn't (yet) an 9*91f16700Schasinglulu * authoritative public document on this since the available BCM2711 reference 10*91f16700Schasinglulu * notes that there is a PCIe root port in the memory map but doesn't describe 11*91f16700Schasinglulu * it. Given that it's not ECAM compliant yet reasonably simple, it makes for 12*91f16700Schasinglulu * an excellent example of the PCI SMCCC interface. 13*91f16700Schasinglulu * 14*91f16700Schasinglulu * The PCI SMCCC interface is described in DEN0115 available from: 15*91f16700Schasinglulu * https://developer.arm.com/documentation/den0115/latest 16*91f16700Schasinglulu */ 17*91f16700Schasinglulu 18*91f16700Schasinglulu #include <assert.h> 19*91f16700Schasinglulu #include <stdint.h> 20*91f16700Schasinglulu 21*91f16700Schasinglulu #include <common/debug.h> 22*91f16700Schasinglulu #include <common/runtime_svc.h> 23*91f16700Schasinglulu #include <lib/pmf/pmf.h> 24*91f16700Schasinglulu #include <lib/runtime_instr.h> 25*91f16700Schasinglulu #include <services/pci_svc.h> 26*91f16700Schasinglulu #include <services/sdei.h> 27*91f16700Schasinglulu #include <services/std_svc.h> 28*91f16700Schasinglulu #include <smccc_helpers.h> 29*91f16700Schasinglulu 30*91f16700Schasinglulu #include <lib/mmio.h> 31*91f16700Schasinglulu 32*91f16700Schasinglulu static spinlock_t pci_lock; 33*91f16700Schasinglulu 34*91f16700Schasinglulu #define PCIE_REG_BASE U(RPI_IO_BASE + 0x01500000) 35*91f16700Schasinglulu #define PCIE_MISC_PCIE_STATUS 0x4068 36*91f16700Schasinglulu #define PCIE_EXT_CFG_INDEX 0x9000 37*91f16700Schasinglulu /* A small window pointing at the ECAM of the device selected by CFG_INDEX */ 38*91f16700Schasinglulu #define PCIE_EXT_CFG_DATA 0x8000 39*91f16700Schasinglulu #define INVALID_PCI_ADDR 0xFFFFFFFF 40*91f16700Schasinglulu 41*91f16700Schasinglulu #define PCIE_EXT_BUS_SHIFT 20 42*91f16700Schasinglulu #define PCIE_EXT_DEV_SHIFT 15 43*91f16700Schasinglulu #define PCIE_EXT_FUN_SHIFT 12 44*91f16700Schasinglulu 45*91f16700Schasinglulu 46*91f16700Schasinglulu static uint64_t pci_segment_lib_get_base(uint32_t address, uint32_t offset) 47*91f16700Schasinglulu { 48*91f16700Schasinglulu uint64_t base; 49*91f16700Schasinglulu uint32_t bus, dev, fun; 50*91f16700Schasinglulu uint32_t status; 51*91f16700Schasinglulu 52*91f16700Schasinglulu base = PCIE_REG_BASE; 53*91f16700Schasinglulu 54*91f16700Schasinglulu offset &= PCI_OFFSET_MASK; /* Pick off the 4k register offset */ 55*91f16700Schasinglulu 56*91f16700Schasinglulu /* The root port is at the base of the PCIe register space */ 57*91f16700Schasinglulu if (address != 0U) { 58*91f16700Schasinglulu /* 59*91f16700Schasinglulu * The current device must be at CFG_DATA, a 4K window mapped, 60*91f16700Schasinglulu * via CFG_INDEX, to the device we are accessing. At the same 61*91f16700Schasinglulu * time we must avoid accesses to certain areas of the cfg 62*91f16700Schasinglulu * space via CFG_DATA. Detect those accesses and report that 63*91f16700Schasinglulu * the address is invalid. 64*91f16700Schasinglulu */ 65*91f16700Schasinglulu base += PCIE_EXT_CFG_DATA; 66*91f16700Schasinglulu bus = PCI_ADDR_BUS(address); 67*91f16700Schasinglulu dev = PCI_ADDR_DEV(address); 68*91f16700Schasinglulu fun = PCI_ADDR_FUN(address); 69*91f16700Schasinglulu address = (bus << PCIE_EXT_BUS_SHIFT) | 70*91f16700Schasinglulu (dev << PCIE_EXT_DEV_SHIFT) | 71*91f16700Schasinglulu (fun << PCIE_EXT_FUN_SHIFT); 72*91f16700Schasinglulu 73*91f16700Schasinglulu /* Allow only dev = 0 on root port and bus 1 */ 74*91f16700Schasinglulu if ((bus < 2U) && (dev > 0U)) { 75*91f16700Schasinglulu return INVALID_PCI_ADDR; 76*91f16700Schasinglulu } 77*91f16700Schasinglulu 78*91f16700Schasinglulu /* Assure link up before reading bus 1 */ 79*91f16700Schasinglulu status = mmio_read_32(PCIE_REG_BASE + PCIE_MISC_PCIE_STATUS); 80*91f16700Schasinglulu if ((status & 0x30) != 0x30) { 81*91f16700Schasinglulu return INVALID_PCI_ADDR; 82*91f16700Schasinglulu } 83*91f16700Schasinglulu 84*91f16700Schasinglulu /* Adjust which device the CFG_DATA window is pointing at */ 85*91f16700Schasinglulu mmio_write_32(PCIE_REG_BASE + PCIE_EXT_CFG_INDEX, address); 86*91f16700Schasinglulu } 87*91f16700Schasinglulu return base + offset; 88*91f16700Schasinglulu } 89*91f16700Schasinglulu 90*91f16700Schasinglulu /** 91*91f16700Schasinglulu * pci_read_config() - Performs a config space read at addr 92*91f16700Schasinglulu * @addr: 32-bit, segment, BDF of requested function encoded per DEN0115 93*91f16700Schasinglulu * @off: register offset of function described by @addr to read 94*91f16700Schasinglulu * @sz: size of read (8,16,32) bits. 95*91f16700Schasinglulu * @val: returned zero extended value read from config space 96*91f16700Schasinglulu * 97*91f16700Schasinglulu * sz bits of PCI config space is read at addr:offset, and the value 98*91f16700Schasinglulu * is returned in val. Invalid segment/offset values return failure. 99*91f16700Schasinglulu * Reads to valid functions that don't exist return INVALID_PCI_ADDR 100*91f16700Schasinglulu * as is specified by PCI for requests that aren't completed by EPs. 101*91f16700Schasinglulu * The boilerplate in pci_svc.c tends to do basic segment, off 102*91f16700Schasinglulu * and sz validation. This routine should avoid duplicating those 103*91f16700Schasinglulu * checks. 104*91f16700Schasinglulu * 105*91f16700Schasinglulu * This function maps directly to the PCI_READ function in DEN0115 106*91f16700Schasinglulu * where detailed requirements may be found. 107*91f16700Schasinglulu * 108*91f16700Schasinglulu * Return: SMC_PCI_CALL_SUCCESS with val set 109*91f16700Schasinglulu * SMC_PCI_CALL_INVAL_PARAM, on parameter error 110*91f16700Schasinglulu */ 111*91f16700Schasinglulu uint32_t pci_read_config(uint32_t addr, uint32_t off, uint32_t sz, uint32_t *val) 112*91f16700Schasinglulu { 113*91f16700Schasinglulu uint32_t ret = SMC_PCI_CALL_SUCCESS; 114*91f16700Schasinglulu uint64_t base; 115*91f16700Schasinglulu 116*91f16700Schasinglulu spin_lock(&pci_lock); 117*91f16700Schasinglulu base = pci_segment_lib_get_base(addr, off); 118*91f16700Schasinglulu 119*91f16700Schasinglulu if (base == INVALID_PCI_ADDR) { 120*91f16700Schasinglulu *val = base; 121*91f16700Schasinglulu } else { 122*91f16700Schasinglulu switch (sz) { 123*91f16700Schasinglulu case SMC_PCI_SZ_8BIT: 124*91f16700Schasinglulu *val = mmio_read_8(base); 125*91f16700Schasinglulu break; 126*91f16700Schasinglulu case SMC_PCI_SZ_16BIT: 127*91f16700Schasinglulu *val = mmio_read_16(base); 128*91f16700Schasinglulu break; 129*91f16700Schasinglulu case SMC_PCI_SZ_32BIT: 130*91f16700Schasinglulu *val = mmio_read_32(base); 131*91f16700Schasinglulu break; 132*91f16700Schasinglulu default: /* should be unreachable */ 133*91f16700Schasinglulu *val = 0; 134*91f16700Schasinglulu ret = SMC_PCI_CALL_INVAL_PARAM; 135*91f16700Schasinglulu } 136*91f16700Schasinglulu } 137*91f16700Schasinglulu spin_unlock(&pci_lock); 138*91f16700Schasinglulu return ret; 139*91f16700Schasinglulu } 140*91f16700Schasinglulu 141*91f16700Schasinglulu /** 142*91f16700Schasinglulu * pci_write_config() - Performs a config space write at addr 143*91f16700Schasinglulu * @addr: 32-bit, segment, BDF of requested function encoded per DEN0115 144*91f16700Schasinglulu * @off: register offset of function described by @addr to write 145*91f16700Schasinglulu * @sz: size of write (8,16,32) bits. 146*91f16700Schasinglulu * @val: value to be written 147*91f16700Schasinglulu * 148*91f16700Schasinglulu * sz bits of PCI config space is written at addr:offset. Invalid 149*91f16700Schasinglulu * segment/BDF values return failure. Writes to valid functions 150*91f16700Schasinglulu * without valid EPs are ignored, as is specified by PCI. 151*91f16700Schasinglulu * The boilerplate in pci_svc.c tends to do basic segment, off 152*91f16700Schasinglulu * and sz validation, so it shouldn't need to be repeated here. 153*91f16700Schasinglulu * 154*91f16700Schasinglulu * This function maps directly to the PCI_WRITE function in DEN0115 155*91f16700Schasinglulu * where detailed requirements may be found. 156*91f16700Schasinglulu * 157*91f16700Schasinglulu * Return: SMC_PCI_CALL_SUCCESS 158*91f16700Schasinglulu * SMC_PCI_CALL_INVAL_PARAM, on parameter error 159*91f16700Schasinglulu */ 160*91f16700Schasinglulu uint32_t pci_write_config(uint32_t addr, uint32_t off, uint32_t sz, uint32_t val) 161*91f16700Schasinglulu { 162*91f16700Schasinglulu uint32_t ret = SMC_PCI_CALL_SUCCESS; 163*91f16700Schasinglulu uint64_t base; 164*91f16700Schasinglulu 165*91f16700Schasinglulu spin_lock(&pci_lock); 166*91f16700Schasinglulu base = pci_segment_lib_get_base(addr, off); 167*91f16700Schasinglulu 168*91f16700Schasinglulu if (base != INVALID_PCI_ADDR) { 169*91f16700Schasinglulu switch (sz) { 170*91f16700Schasinglulu case SMC_PCI_SZ_8BIT: 171*91f16700Schasinglulu mmio_write_8(base, val); 172*91f16700Schasinglulu break; 173*91f16700Schasinglulu case SMC_PCI_SZ_16BIT: 174*91f16700Schasinglulu mmio_write_16(base, val); 175*91f16700Schasinglulu break; 176*91f16700Schasinglulu case SMC_PCI_SZ_32BIT: 177*91f16700Schasinglulu mmio_write_32(base, val); 178*91f16700Schasinglulu break; 179*91f16700Schasinglulu default: /* should be unreachable */ 180*91f16700Schasinglulu ret = SMC_PCI_CALL_INVAL_PARAM; 181*91f16700Schasinglulu } 182*91f16700Schasinglulu } 183*91f16700Schasinglulu spin_unlock(&pci_lock); 184*91f16700Schasinglulu return ret; 185*91f16700Schasinglulu } 186*91f16700Schasinglulu 187*91f16700Schasinglulu /** 188*91f16700Schasinglulu * pci_get_bus_for_seg() - returns the start->end bus range for a segment 189*91f16700Schasinglulu * @seg: segment being queried 190*91f16700Schasinglulu * @bus_range: returned bus begin + (end << 8) 191*91f16700Schasinglulu * @nseg: returns next segment in this machine or 0 for end 192*91f16700Schasinglulu * 193*91f16700Schasinglulu * pci_get_bus_for_seg is called to check if a given segment is 194*91f16700Schasinglulu * valid on this machine. If it is valid, then its bus ranges are 195*91f16700Schasinglulu * returned along with the next valid segment on the machine. If 196*91f16700Schasinglulu * this is the last segment, then nseg must be 0. 197*91f16700Schasinglulu * 198*91f16700Schasinglulu * This function maps directly to the PCI_GET_SEG_INFO function 199*91f16700Schasinglulu * in DEN0115 where detailed requirements may be found. 200*91f16700Schasinglulu * 201*91f16700Schasinglulu * Return: SMC_PCI_CALL_SUCCESS, and appropriate bus_range and nseg 202*91f16700Schasinglulu * SMC_PCI_CALL_NOT_IMPL, if the segment is invalid 203*91f16700Schasinglulu */ 204*91f16700Schasinglulu uint32_t pci_get_bus_for_seg(uint32_t seg, uint32_t *bus_range, uint32_t *nseg) 205*91f16700Schasinglulu { 206*91f16700Schasinglulu uint32_t ret = SMC_PCI_CALL_SUCCESS; 207*91f16700Schasinglulu *nseg = 0U; /* only a single segment */ 208*91f16700Schasinglulu if (seg == 0U) { 209*91f16700Schasinglulu *bus_range = 0xFF00; /* start 0, end 255 */ 210*91f16700Schasinglulu } else { 211*91f16700Schasinglulu *bus_range = 0U; 212*91f16700Schasinglulu ret = SMC_PCI_CALL_NOT_IMPL; 213*91f16700Schasinglulu } 214*91f16700Schasinglulu return ret; 215*91f16700Schasinglulu } 216