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