Browse Source

Merge "feat(rpi5): add PCI SMCCC support" into integration

pull/1996/merge
Olivier Deprez 4 months ago
committed by TrustedFirmware Code Review
parent
commit
4d88423578
  1. 95
      plat/rpi/common/rpi_pci_svc.c
  2. 7
      plat/rpi/rpi4/include/rpi_hw.h
  3. 2
      plat/rpi/rpi4/platform.mk
  4. 7
      plat/rpi/rpi5/include/rpi_hw.h
  5. 8
      plat/rpi/rpi5/platform.mk

95
plat/rpi/rpi4/rpi4_pci_svc.c → plat/rpi/common/rpi_pci_svc.c

@ -1,9 +1,10 @@
/* /*
* Copyright (c) 2021, ARM Limited and Contributors. All rights reserved. * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2024, Mario Bălănică <mariobalanica02@gmail.com>
* *
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
* *
* The RPi4 has a single nonstandard PCI config region. It is broken into two * The RPi has a single nonstandard PCI config region. It is broken into two
* pieces, the root port config registers and a window to a single device's * pieces, the root port config registers and a window to a single device's
* config space which can move between devices. There isn't (yet) an * config space which can move between devices. There isn't (yet) an
* authoritative public document on this since the available BCM2711 reference * authoritative public document on this since the available BCM2711 reference
@ -29,62 +30,63 @@
#include <lib/mmio.h> #include <lib/mmio.h>
static spinlock_t pci_lock;
#define PCIE_REG_BASE U(RPI_IO_BASE + 0x01500000)
#define PCIE_MISC_PCIE_STATUS 0x4068 #define PCIE_MISC_PCIE_STATUS 0x4068
#define PCIE_EXT_CFG_INDEX 0x9000 #define PCIE_EXT_CFG_INDEX 0x9000
/* A small window pointing at the ECAM of the device selected by CFG_INDEX */
#define PCIE_EXT_CFG_DATA 0x8000 #define PCIE_EXT_CFG_DATA 0x8000
#define PCIE_EXT_CFG_BDF_SHIFT 12
#define INVALID_PCI_ADDR 0xFFFFFFFF #define INVALID_PCI_ADDR 0xFFFFFFFF
#define PCIE_EXT_BUS_SHIFT 20 static spinlock_t pci_lock;
#define PCIE_EXT_DEV_SHIFT 15
#define PCIE_EXT_FUN_SHIFT 12
static uint64_t pcie_rc_bases[] = { RPI_PCIE_RC_BASES };
static uint64_t pci_segment_lib_get_base(uint32_t address, uint32_t offset) static uint64_t pci_segment_lib_get_base(uint32_t address, uint32_t offset)
{ {
uint64_t base; uint64_t base;
uint32_t bus, dev, fun; uint32_t seg, bus, dev, fun;
uint32_t status;
base = PCIE_REG_BASE; seg = PCI_ADDR_SEG(address);
offset &= PCI_OFFSET_MASK; /* Pick off the 4k register offset */ if (seg >= ARRAY_SIZE(pcie_rc_bases)) {
return INVALID_PCI_ADDR;
}
/* The root port is at the base of the PCIe register space */ /* The root port is at the base of the PCIe register space */
if (address != 0U) { base = pcie_rc_bases[seg];
/*
* The current device must be at CFG_DATA, a 4K window mapped, bus = PCI_ADDR_BUS(address);
* via CFG_INDEX, to the device we are accessing. At the same dev = PCI_ADDR_DEV(address);
* time we must avoid accesses to certain areas of the cfg fun = PCI_ADDR_FUN(address);
* space via CFG_DATA. Detect those accesses and report that
* the address is invalid.
*/
base += PCIE_EXT_CFG_DATA;
bus = PCI_ADDR_BUS(address);
dev = PCI_ADDR_DEV(address);
fun = PCI_ADDR_FUN(address);
address = (bus << PCIE_EXT_BUS_SHIFT) |
(dev << PCIE_EXT_DEV_SHIFT) |
(fun << PCIE_EXT_FUN_SHIFT);
/* Allow only dev = 0 on root port and bus 1 */
if ((bus < 2U) && (dev > 0U)) {
return INVALID_PCI_ADDR;
}
/* Assure link up before reading bus 1 */ /* There can only be the root port on bus 0 */
status = mmio_read_32(PCIE_REG_BASE + PCIE_MISC_PCIE_STATUS); if ((bus == 0U) && ((dev > 0U) || (fun > 0U))) {
if ((status & 0x30) != 0x30) { return INVALID_PCI_ADDR;
}
/* There can only be one device on bus 1 */
if ((bus == 1U) && (dev > 0U)) {
return INVALID_PCI_ADDR;
}
if (bus > 0) {
#if RPI_PCIE_ECAM_SERROR_QUIRK
uint32_t status = mmio_read_32(base + PCIE_MISC_PCIE_STATUS);
/* Assure link up before accessing downstream of root port */
if ((status & 0x30) == 0U) {
return INVALID_PCI_ADDR; return INVALID_PCI_ADDR;
} }
#endif
/* Adjust which device the CFG_DATA window is pointing at */ /*
mmio_write_32(PCIE_REG_BASE + PCIE_EXT_CFG_INDEX, address); * Device function is mapped at CFG_DATA, a 4 KB window
* movable by writing its B/D/F location to CFG_INDEX.
*/
mmio_write_32(base + PCIE_EXT_CFG_INDEX, address << PCIE_EXT_CFG_BDF_SHIFT);
base += PCIE_EXT_CFG_DATA;
} }
return base + offset;
return base + (offset & PCI_OFFSET_MASK);
} }
/** /**
@ -130,7 +132,7 @@ uint32_t pci_read_config(uint32_t addr, uint32_t off, uint32_t sz, uint32_t *val
*val = mmio_read_32(base); *val = mmio_read_32(base);
break; break;
default: /* should be unreachable */ default: /* should be unreachable */
*val = 0; *val = 0U;
ret = SMC_PCI_CALL_INVAL_PARAM; ret = SMC_PCI_CALL_INVAL_PARAM;
} }
} }
@ -204,9 +206,12 @@ uint32_t pci_write_config(uint32_t addr, uint32_t off, uint32_t sz, uint32_t val
uint32_t pci_get_bus_for_seg(uint32_t seg, uint32_t *bus_range, uint32_t *nseg) uint32_t pci_get_bus_for_seg(uint32_t seg, uint32_t *bus_range, uint32_t *nseg)
{ {
uint32_t ret = SMC_PCI_CALL_SUCCESS; uint32_t ret = SMC_PCI_CALL_SUCCESS;
*nseg = 0U; /* only a single segment */ uint32_t rc_count = ARRAY_SIZE(pcie_rc_bases);
if (seg == 0U) {
*bus_range = 0xFF00; /* start 0, end 255 */ *nseg = (seg < rc_count - 1U) ? seg + 1U : 0U;
if (seg < rc_count) {
*bus_range = 0U + (0xFF << 8); /* start 0, end 255 */
} else { } else {
*bus_range = 0U; *bus_range = 0U;
ret = SMC_PCI_CALL_NOT_IMPL; ret = SMC_PCI_CALL_NOT_IMPL;

7
plat/rpi/rpi4/include/rpi_hw.h

@ -69,4 +69,11 @@
#define RPI4_LOCAL_CONTROL_BASE_ADDRESS ULL(0xff800000) #define RPI4_LOCAL_CONTROL_BASE_ADDRESS ULL(0xff800000)
#define RPI4_LOCAL_CONTROL_PRESCALER ULL(0xff800008) #define RPI4_LOCAL_CONTROL_PRESCALER ULL(0xff800008)
/*
* PCI Express
*/
#define RPI_PCIE_RC_BASES (RPI_IO_BASE + ULL(0x01500000))
#define RPI_PCIE_ECAM_SERROR_QUIRK 1
#endif /* RPI_HW_H */ #endif /* RPI_HW_H */

2
plat/rpi/rpi4/platform.mk

@ -113,5 +113,5 @@ PLAT_BL_COMMON_SOURCES += drivers/rpi3/rng/rpi3_rng.c \
endif endif
ifeq ($(SMC_PCI_SUPPORT), 1) ifeq ($(SMC_PCI_SUPPORT), 1)
BL31_SOURCES += plat/rpi/rpi4/rpi4_pci_svc.c BL31_SOURCES += plat/rpi/common/rpi_pci_svc.c
endif endif

7
plat/rpi/rpi5/include/rpi_hw.h

@ -48,4 +48,11 @@
#define RPI4_LOCAL_CONTROL_BASE_ADDRESS (RPI_IO_BASE + ULL(0x7c280000)) #define RPI4_LOCAL_CONTROL_BASE_ADDRESS (RPI_IO_BASE + ULL(0x7c280000))
#define RPI4_LOCAL_CONTROL_PRESCALER (RPI_IO_BASE + ULL(0x7c280008)) #define RPI4_LOCAL_CONTROL_PRESCALER (RPI_IO_BASE + ULL(0x7c280008))
/*
* PCI Express
*/
#define RPI_PCIE_RC_BASES RPI_IO_BASE + ULL(0x00100000), \
RPI_IO_BASE + ULL(0x00110000), \
RPI_IO_BASE + ULL(0x00120000)
#endif /* RPI_HW_H */ #endif /* RPI_HW_H */

8
plat/rpi/rpi5/platform.mk

@ -86,6 +86,9 @@ RPI3_RUNTIME_UART := 0
# Use normal memory mapping for ROM, FIP, SRAM and DRAM # Use normal memory mapping for ROM, FIP, SRAM and DRAM
RPI3_USE_UEFI_MAP := 0 RPI3_USE_UEFI_MAP := 0
# SMCCC PCI support (should be enabled for ACPI builds)
SMC_PCI_SUPPORT := 0
# Process platform flags # Process platform flags
# ---------------------- # ----------------------
@ -96,6 +99,7 @@ $(eval $(call add_define,RPI3_PRELOADED_DTB_BASE))
endif endif
$(eval $(call add_define,RPI3_RUNTIME_UART)) $(eval $(call add_define,RPI3_RUNTIME_UART))
$(eval $(call add_define,RPI3_USE_UEFI_MAP)) $(eval $(call add_define,RPI3_USE_UEFI_MAP))
$(eval $(call add_define,SMC_PCI_SUPPORT))
ifeq (${ARCH},aarch32) ifeq (${ARCH},aarch32)
$(error Error: AArch32 not supported on rpi5) $(error Error: AArch32 not supported on rpi5)
@ -105,3 +109,7 @@ ifneq ($(ENABLE_STACK_PROTECTOR), 0)
PLAT_BL_COMMON_SOURCES += drivers/rpi3/rng/rpi3_rng.c \ PLAT_BL_COMMON_SOURCES += drivers/rpi3/rng/rpi3_rng.c \
plat/rpi/common/rpi3_stack_protector.c plat/rpi/common/rpi3_stack_protector.c
endif endif
ifeq ($(SMC_PCI_SUPPORT), 1)
BL31_SOURCES += plat/rpi/common/rpi_pci_svc.c
endif

Loading…
Cancel
Save