fix(lib/pcie): import pcie enumeration helpers from rmm-acs
Import PCIe enumeration helpers from rmm-acs[1] at tag v1.0_REL0_12.24.
This patch adds the missing device enumeration logic added as part of
the initial commit.
This change is verified with FVP default PCI topology. The helper
pcie_init() might need some enhancements for other platforms with
different PCI topology.
[1] https://github.com/ARM-software/cca-rmm-acs
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: I46724c458fe0071272fc7bca73d51e27181bb1b4
diff --git a/include/lib/pcie/pcie.h b/include/lib/pcie/pcie.h
index d7188a0..7dd165c 100644
--- a/include/lib/pcie/pcie.h
+++ b/include/lib/pcie/pcie.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2024-2025, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -100,7 +100,7 @@
#define CC_BASE_SHIFT 24
void pcie_init(void);
-void pcie_create_info_table(void);
+
pcie_device_bdf_table_t *pcie_get_bdf_table(void);
uint32_t pcie_find_capability(uint32_t bdf, uint32_t cid_type, uint32_t cid,
uint32_t *cid_offset);
diff --git a/include/plat/common/plat_pcie_enum.h b/include/plat/common/plat_pcie_enum.h
new file mode 100644
index 0000000..667fe05
--- /dev/null
+++ b/include/plat/common/plat_pcie_enum.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2025, Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PLAT_PCIE_ENUM_H__
+#define __PLAT_PCIE_ENUM_H__
+
+#include <stdio.h>
+#include <stdint.h>
+
+/* Header Offset and Type */
+#define HEADER_OFFSET 0xC
+#define TYPE0_HEADER 0
+#define TYPE1_HEADER 1
+
+#define TYPE01_RIDR 0x8
+
+#define DEVICE_ID_OFFSET 16
+
+/* Initial BUS definitions */
+#define PRI_BUS 0
+#define SEC_BUS 1
+#define BUS_NUM_REG_OFFSET 0x18
+
+/* BAR offset */
+#define BAR0_OFFSET 0x10
+#define TYPE1_BAR_MAX_OFF 0x14
+#define TYPE0_BAR_MAX_OFF 0x24
+
+#define BAR_NON_PRE_MEM 0
+#define BAR_PRE_MEM 0x1
+
+#define MEM_BASE32_LIM_MASK 0xFFF00000
+#define MEM_BASE64_LIM_MASK 0xFFFFFFFFFFF00000
+#define NON_PRE_FET_OFFSET 0x20
+#define PRE_FET_OFFSET 0x24
+#define BAR_INCREMENT 0x100000
+
+#define PRI_BUS_CLEAR_MASK 0xFFFFFF00
+
+#define TYPE0_MAX_BARS 6
+#define TYPE1_MAX_BARS 2
+
+/* BAR register masks */
+#define BAR_MIT_MASK 0x1
+#define BAR_MDT_MASK 0x3
+#define BAR_MT_MASK 0x1
+#define BAR_BASE_MASK 0xfffffff
+
+/* BAR register shifts */
+#define BAR_MIT_SHIFT 0
+#define BAR_MDT_SHIFT 1
+#define BAR_MT_SHIFT 3
+#define BAR_BASE_SHIFT 4
+
+/* TYPE 0/1 Cmn Cfg reg offsets and mask*/
+#define TYPE01_CPR 0x34
+#define TYPE01_CPR_MASK 0xff
+#define COMMAND_REG_OFFSET 0x04
+#define REG_ACC_DATA 0x7
+
+#define BAR_MASK 0xFFFFFFF0
+
+#define PCIE_HEADER_TYPE(header_value) ((header_value >> 16) & 0x3)
+#define BUS_NUM_REG_CFG(sub_bus, sec_bus, pri_bus) (sub_bus << 16 | sec_bus << 8 | bus)
+
+#define BAR_REG(bar_reg_value) ((bar_reg_value >> 2) & 0x1)
+#define BAR_MEM(bar_reg_value) ((bar_reg_value & 0xF) >> 3)
+#define REG_MASK_SHIFT(bar_value) ((bar_value & MEM_BASE32_LIM_MASK) >> 16)
+
+#endif /* __PLAT_PCIE_ENUM_H__ */
diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h
index e5032fa..077ccb3 100644
--- a/include/plat/common/platform.h
+++ b/include/plat/common/platform.h
@@ -208,6 +208,11 @@
*/
const struct pcie_info_table *plat_pcie_get_info_table(void);
+/* Retrieve platform PCIe bar config values */
+int plat_pcie_get_bar_config(uint64_t *bar64_val, uint64_t *rp_bar64_val,
+ uint32_t *bar32np_val, uint32_t *bar32p_val,
+ uint32_t *rp_bar32_val);
+
/*
* This function provides an address that is recognized as invalid for use
* as an entry point in the CPU_ON and CPU_SUSPEND calls on this platform.
diff --git a/lib/pcie/pcie.c b/lib/pcie/pcie.c
index 8de2825..ea187a6 100644
--- a/lib/pcie/pcie.c
+++ b/lib/pcie/pcie.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2024-2025, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -14,16 +14,35 @@
#include <pcie_doe.h>
#include <pcie_spec.h>
#include <platform.h>
+#include <plat_pcie_enum.h>
#include <tftf_lib.h>
#define PCIE_DEBUG VERBOSE
const struct pcie_info_table *g_pcie_info_table;
-pcie_device_bdf_table_t *g_pcie_bdf_table;
+static pcie_device_bdf_table_t *g_pcie_bdf_table;
-pcie_device_bdf_table_t pcie_bdf_table[PCIE_DEVICE_BDF_TABLE_SZ];
+static pcie_device_bdf_table_t pcie_bdf_table[PCIE_DEVICE_BDF_TABLE_SZ];
-uintptr_t pcie_cfg_addr(uint32_t bdf)
+static uint32_t g_pcie_index;
+static uint32_t g_enumerate;
+
+/* 64-bit address initialisation */
+static uint64_t g_bar64_p_start;
+static uint64_t g_rp_bar64_value;
+static uint64_t g_bar64_p_max;
+static uint32_t g_64_bus, g_bar64_size;
+
+/* 32-bit address initialisation */
+static uint32_t g_bar32_np_start;
+static uint32_t g_bar32_p_start;
+static uint32_t g_rp_bar32_value;
+static uint32_t g_bar32_np_max;
+static uint32_t g_bar32_p_max;
+static uint32_t g_np_bar_size, g_p_bar_size;
+static uint32_t g_np_bus, g_p_bus;
+
+static uintptr_t pcie_cfg_addr(uint32_t bdf)
{
uint32_t bus = PCIE_EXTRACT_BDF_BUS(bdf);
uint32_t dev = PCIE_EXTRACT_BDF_DEV(bdf);
@@ -102,7 +121,7 @@
* @param bdf - Function's Segment/Bus/Dev/Func in PCIE_CREATE_BDF format
* @return false If not a Host Bridge, true If it's a Host Bridge.
*/
-bool pcie_is_host_bridge(uint32_t bdf)
+static bool pcie_is_host_bridge(uint32_t bdf)
{
uint32_t reg_value = pcie_read_cfg(bdf, TYPE01_RIDR);
@@ -168,7 +187,7 @@
* @param bdf
* @return true if bdf is valid else false
*/
-bool pcie_check_device_valid(uint32_t bdf)
+static bool pcie_check_device_valid(uint32_t bdf)
{
(void) bdf;
/*
@@ -185,7 +204,7 @@
* @return Returns TRUE if the Function is on-chip peripheral, FALSE if it is
* not an on-chip peripheral
*/
-bool pcie_is_onchip_peripheral(uint32_t bdf)
+static bool pcie_is_onchip_peripheral(uint32_t bdf)
{
(void)bdf;
return false;
@@ -200,7 +219,7 @@
* (1 << 0b1100) for iEP_EP, (1 << 0b1011) for iEP_RP,
* (1 << PCIECR[7:4]) for any other device type.
*/
-uint32_t pcie_device_port_type(uint32_t bdf)
+static uint32_t pcie_device_port_type(uint32_t bdf)
{
uint32_t pciecs_base, reg_value, dp_type;
@@ -236,7 +255,7 @@
* @param usrp_bdf - Upstream Rootport bdf in PCIE_CREATE_BDF format
* @return 0 for success, 1 for failure.
*/
-uint32_t pcie_get_rootport(uint32_t bdf, uint32_t *rp_bdf)
+static uint32_t pcie_get_rootport(uint32_t bdf, uint32_t *rp_bdf)
{
uint32_t seg_num, sec_bus, sub_bus;
uint32_t reg_value, dp_type, index = 0;
@@ -334,7 +353,7 @@
*
* @return None
*/
-void pcie_create_device_bdf_table(void)
+static void pcie_create_device_bdf_table(void)
{
uint32_t seg_num, start_bus, end_bus;
uint32_t bus_index, dev_index, func_index, ecam_index;
@@ -404,7 +423,7 @@
* @return TYPE0_HEADER for functions with Type 0 config space header,
* TYPE1_HEADER for functions with Type 1 config space header,
*/
-uint32_t pcie_function_header_type(uint32_t bdf)
+static uint32_t pcie_function_header_type(uint32_t bdf)
{
/* Read four bytes of config space starting from cache line size register */
uint32_t reg_value = pcie_read_cfg(bdf, TYPE01_CLSR);
@@ -422,7 +441,7 @@
* @param bdf - Segment/Bus/Dev/Func in PCIE_CREATE_BDF format
* @return ECAM address if success, else NULL address
*/
-uintptr_t pcie_get_ecam_base(uint32_t bdf)
+static uintptr_t pcie_get_ecam_base(uint32_t bdf)
{
uint8_t ecam_index = 0, sec_bus = 0, sub_bus;
uint16_t seg_num = (uint16_t)PCIE_EXTRACT_BDF_SEG(bdf);
@@ -466,7 +485,7 @@
* @param None
* @return None
*/
-void pcie_print_device_info(void)
+static void pcie_print_device_info(void)
{
uint32_t bdf, dp_type;
uint32_t tbl_index = 0;
@@ -596,18 +615,11 @@
* @param void
* @return void
*/
-void pcie_create_info_table(void)
+static void pcie_create_info_table(void)
{
unsigned int num_ecam;
INFO("Creating PCIe info table\n");
-
- g_pcie_info_table = plat_pcie_get_info_table();
- if (g_pcie_info_table == NULL) {
- ERROR("PCIe info not returned by platform\n");
- panic();
- }
-
g_pcie_bdf_table = pcie_bdf_table;
num_ecam = g_pcie_info_table->num_entries;
@@ -620,12 +632,611 @@
pcie_print_device_info();
}
+static void pal_pci_cfg_write(uint32_t bus, uint32_t dev, uint32_t func,
+ uint32_t offset, uint32_t data)
+{
+ pcie_write_cfg(PCIE_CREATE_BDF(0, bus, dev, func), offset, data);
+}
+
+static void pal_pci_cfg_read(uint32_t bus, uint32_t dev, uint32_t func,
+ uint32_t offset, uint32_t *value)
+{
+ *value = pcie_read_cfg(PCIE_CREATE_BDF(0, bus, dev, func), offset);
+}
+
+/*
+ * This API programs the Memory Base and Memeory limit register of the Bus,
+ * Device and Function of Type1 Header
+ */
+static void get_resource_base_32(uint32_t bus, uint32_t dev, uint32_t func,
+ uint32_t bar32_p_base, uint32_t bar32_np_base,
+ uint32_t bar32_p_limit, uint32_t bar32_np_limit)
+{
+ uint32_t mem_bar_np;
+ uint32_t mem_bar_p;
+
+ /* Update the 32 bit NP-BAR start address for the next iteration */
+ if (bar32_np_base != g_bar32_np_start) {
+ if ((g_bar32_np_start << 12) != 0) {
+ g_bar32_np_start = (g_bar32_np_start &
+ MEM_BASE32_LIM_MASK) + BAR_INCREMENT;
+ }
+
+ if (bar32_np_limit == g_bar32_np_start) {
+ bar32_np_limit = bar32_np_limit - BAR_INCREMENT;
+ }
+
+ pal_pci_cfg_read(bus, dev, func, NON_PRE_FET_OFFSET,
+ &mem_bar_np);
+ mem_bar_np = ((bar32_np_limit & MEM_BASE32_LIM_MASK) |
+ mem_bar_np);
+ pal_pci_cfg_write(bus, dev, func, NON_PRE_FET_OFFSET,
+ mem_bar_np);
+ }
+
+ /* Update the 32 bit P-BAR start address for the next iteration */
+ if (bar32_p_base != g_bar32_p_start) {
+ if ((g_bar32_p_start << 12) != 0) {
+ g_bar32_p_start = (g_bar32_p_start &
+ MEM_BASE32_LIM_MASK) + BAR_INCREMENT;
+ }
+
+ if (bar32_p_limit == g_bar32_p_start) {
+ bar32_p_limit = bar32_p_limit - BAR_INCREMENT;
+ }
+
+ pal_pci_cfg_read(bus, dev, func, PRE_FET_OFFSET, &mem_bar_p);
+ mem_bar_p = ((bar32_p_limit & MEM_BASE32_LIM_MASK) | mem_bar_p);
+ pal_pci_cfg_write(bus, dev, func, PRE_FET_OFFSET, mem_bar_p);
+ }
+}
+
+/*
+ * This API programs the Memory Base and Memeory limit register of the Bus,
+ * Device and Function of Type1 Header
+ */
+static void get_resource_base_64(uint32_t bus, uint32_t dev, uint32_t func,
+ uint64_t bar64_p_base, uint64_t g_bar64_p_max)
+{
+ uint32_t bar64_p_lower32_base = (uint32_t)bar64_p_base;
+ uint32_t bar64_p_upper32_base = (uint32_t)(bar64_p_base >> 32);
+ uint32_t bar64_p_lower32_limit = (uint32_t)g_bar64_p_max;
+ uint32_t bar64_p_upper32_limit = (uint32_t)(g_bar64_p_max >> 32);
+
+ /* Obtain the memory base and memory limit */
+ bar64_p_lower32_base = REG_MASK_SHIFT(bar64_p_lower32_base);
+ bar64_p_lower32_limit = REG_MASK_SHIFT(bar64_p_lower32_limit);
+ uint32_t mem_bar_p = ((bar64_p_lower32_limit << 16) |
+ bar64_p_lower32_base);
+
+ /* Configure Memory base and Memory limit register */
+ if ((bar64_p_base != g_bar64_p_max) && (g_bar64_p_start <=
+ g_bar64_p_max)) {
+ if ((g_bar64_p_start << 12) != 0) {
+ g_bar64_p_start = (g_bar64_p_start &
+ MEM_BASE64_LIM_MASK) + BAR_INCREMENT;
+ }
+
+ if (bar64_p_lower32_limit == g_bar64_p_start) {
+ bar64_p_lower32_limit = bar64_p_lower32_limit -
+ BAR_INCREMENT;
+ }
+
+ g_bar64_p_start = (g_bar64_p_start & MEM_BASE64_LIM_MASK) +
+ BAR_INCREMENT;
+
+ pal_pci_cfg_write(bus, dev, func, PRE_FET_OFFSET, mem_bar_p);
+ pal_pci_cfg_write(bus, dev, func, PRE_FET_OFFSET + 4,
+ bar64_p_upper32_base);
+ pal_pci_cfg_write(bus, dev, func, PRE_FET_OFFSET + 8,
+ bar64_p_upper32_limit);
+ }
+}
+
+static void pcie_rp_program_bar(uint32_t bus, uint32_t dev, uint32_t func)
+{
+ uint64_t bar_size, bar_upper_bits;
+ uint32_t offset = BAR0_OFFSET;
+ uint32_t bar_reg_value, bar_lower_bits;
+
+ while (offset <= TYPE1_BAR_MAX_OFF) {
+ pal_pci_cfg_read(bus, dev, func, offset, &bar_reg_value);
+
+ if (BAR_REG(bar_reg_value) == BAR_64_BIT) {
+ /*
+ * BAR supports 64-bit address therefore, write all 1's
+ * to BARn and BARn+1 and identify the size requested
+ */
+ pal_pci_cfg_write(bus, dev, func, offset, 0xFFFFFFF0);
+ pal_pci_cfg_write(bus, dev, func, offset + 4,
+ 0xFFFFFFFF);
+ pal_pci_cfg_read(bus, dev, func, offset,
+ &bar_lower_bits);
+ bar_size = bar_lower_bits & BAR_MASK;
+
+ pal_pci_cfg_read(bus, dev, func, offset + 4,
+ &bar_reg_value);
+ bar_upper_bits = bar_reg_value;
+ bar_size = bar_size | (bar_upper_bits << 32);
+
+ bar_size = ~bar_size + 1;
+
+ /*
+ * If BAR size is 0, then BAR not implemented, move to
+ * next BAR
+ */
+ if (bar_size == 0) {
+ offset = offset + 8;
+ continue;
+ }
+
+ pal_pci_cfg_write(bus, dev, func, offset,
+ (uint32_t)g_rp_bar64_value);
+ pal_pci_cfg_write(bus, dev, func, offset + 4,
+ (uint32_t)(g_rp_bar64_value >> 32));
+ offset = offset + 8;
+ } else {
+ /*
+ * BAR supports 32-bit address. Write all 1's to BARn
+ * and identify the size requested
+ */
+ pal_pci_cfg_write(bus, dev, func, offset, 0xFFFFFFF0);
+ pal_pci_cfg_read(bus, dev, func, offset,
+ &bar_lower_bits);
+ bar_reg_value = bar_lower_bits & BAR_MASK;
+ bar_size = ~bar_reg_value + 1;
+
+ /*
+ * If BAR size is 0, then BAR not implemented, move to
+ * next BAR
+ */
+ if (bar_size == 0) {
+ offset = offset + 4;
+ continue;
+ }
+
+ pal_pci_cfg_write(bus, dev, func, offset,
+ g_rp_bar32_value);
+ g_rp_bar32_value = g_rp_bar32_value + (uint32_t)bar_size;
+ offset = offset + 4;
+ }
+ }
+}
+
+/*
+ * This API programs all the BAR register in PCIe config space pointed by Bus,
+ * Device and Function for an End Point PCIe device
+ */
+static void pcie_program_bar_reg(uint32_t bus, uint32_t dev, uint32_t func)
+{
+ uint64_t bar_size, bar_upper_bits;
+ uint32_t bar_reg_value, bar_lower_bits;
+ uint32_t offset = BAR0_OFFSET;
+ uint32_t np_bar_size = 0;
+ uint32_t p_bar_size = 0, p_bar64_size = 0;
+
+ while (offset <= TYPE0_BAR_MAX_OFF) {
+ pal_pci_cfg_read(bus, dev, func, offset, &bar_reg_value);
+
+ if (BAR_MEM(bar_reg_value) == BAR_PRE_MEM) {
+ if (BAR_REG(bar_reg_value) == BAR_64_BIT) {
+ /*
+ * BAR supports 64-bit address therefore,
+ * write all 1's to BARn and BARn+1 and identify
+ * the size requested
+ */
+
+ pal_pci_cfg_write(bus, dev, func, offset,
+ 0xFFFFFFF0);
+ pal_pci_cfg_write(bus, dev, func, offset + 4,
+ 0xFFFFFFFF);
+ pal_pci_cfg_read(bus, dev, func, offset,
+ &bar_lower_bits);
+ bar_size = bar_lower_bits & BAR_MASK;
+
+ pal_pci_cfg_read(bus, dev, func, offset + 4,
+ &bar_reg_value);
+ bar_upper_bits = bar_reg_value;
+ bar_size = bar_size | (bar_upper_bits << 32);
+
+ bar_size = ~bar_size + 1;
+
+ /*
+ * If BAR size is 0, then BAR not implemented,
+ * move to next BAR
+ */
+ if (bar_size == 0) {
+ offset = offset + 8;
+ continue;
+ }
+
+ /*
+ * If p_bar64_size = 0 and bus number is same as
+ * bus of previous bus number, then check if the
+ * current PCIe Device BAR size is greater than
+ * the previous BAR size, if yes then add current
+ * BAR size to the updated start address else
+ * add the previous BAR size to the updated
+ * start address
+ */
+ if ((p_bar64_size == 0) && ((g_64_bus == bus))) {
+ if (g_bar64_size < bar_size) {
+ g_bar64_p_start =
+ g_bar64_p_start +
+ bar_size;
+ } else {
+ g_bar64_p_start =
+ g_bar64_p_start +
+ g_bar64_size;
+ }
+ } else if ((g_bar64_size < bar_size) &&
+ (p_bar64_size != 0)) {
+ g_bar64_p_start = g_bar64_p_start +
+ bar_size;
+ } else {
+ g_bar64_p_start = g_bar64_p_start +
+ p_bar64_size;
+ }
+
+ pal_pci_cfg_write(bus, dev, func, offset,
+ (uint32_t)g_bar64_p_start);
+ pal_pci_cfg_write(bus, dev, func, offset + 4,
+ (uint32_t)(g_bar64_p_start >>
+ 32));
+
+ p_bar64_size = (uint32_t)bar_size;
+ g_bar64_size = (uint32_t)bar_size;
+ g_64_bus = bus;
+ offset = offset + 8;
+ } else {
+ /*
+ * BAR supports 32-bit address. Write all 1's
+ * to BARn and identify the size requested
+ */
+ pal_pci_cfg_write(bus, dev, func, offset,
+ 0xFFFFFFF0);
+ pal_pci_cfg_read(bus, dev, func, offset,
+ &bar_lower_bits);
+ bar_reg_value = bar_lower_bits & BAR_MASK;
+ bar_size = ~bar_reg_value + 1;
+
+ /*
+ * If BAR size is 0, then BAR not implemented,
+ * move to next BAR
+ */
+ if (bar_size == 0) {
+ offset = offset + 4;
+ continue;
+ }
+
+ /*
+ * If p_bar_size = 0 and bus number is same as
+ * bus of previous bus number, then check if the
+ * current PCIe Device BAR size is greater than
+ * the previous BAR size, if yes then add
+ * current BAR size to the updated start
+ * address else add the previous BAR size to the
+ * updated start address
+ */
+ if ((p_bar_size == 0) && ((g_p_bus == bus))) {
+ if (g_p_bar_size < bar_size) {
+ g_bar32_p_start =
+ g_bar32_p_start +
+ (uint32_t)bar_size;
+ } else {
+ g_bar32_p_start =
+ g_bar32_p_start +
+ g_p_bar_size;
+ }
+ } else if ((g_p_bar_size < bar_size) &&
+ (p_bar_size != 0)) {
+ g_bar32_p_start = g_bar32_p_start +
+ (uint32_t)bar_size;
+ } else {
+ g_bar32_p_start = g_bar32_p_start +
+ p_bar_size;
+ }
+
+ pal_pci_cfg_write(bus, dev, func, offset,
+ g_bar32_p_start);
+ p_bar_size = (uint32_t)bar_size;
+ g_p_bar_size = (uint32_t)bar_size;
+ g_p_bus = bus;
+
+ offset = offset + 4;
+ }
+ } else {
+ /*
+ * BAR supports 32-bit address. Write all 1's to BARn
+ * and identify the size requested
+ */
+ pal_pci_cfg_write(bus, dev, func, offset, 0xFFFFFFF0);
+ pal_pci_cfg_read(bus, dev, func, offset,
+ &bar_lower_bits);
+ bar_reg_value = bar_lower_bits & BAR_MASK;
+ bar_size = ~bar_reg_value + 1;
+
+ /*
+ * If BAR size is 0, then BAR not implemented, move to
+ * next BAR
+ */
+ if (bar_size == 0) {
+ if (BAR_REG(bar_lower_bits) == BAR_64_BIT) {
+ offset = offset + 8;
+ }
+
+ if (BAR_REG(bar_lower_bits) == BAR_32_BIT) {
+ offset = offset + 4;
+ }
+
+ continue;
+ }
+
+ /*
+ * If np_bar_size = 0 and bus number is same as bus of
+ * previous bus number, then check if the current PCIe
+ * Device BAR size is greater than the previous BAR
+ * size, if yes then add current BAR size to the
+ * updated start address else add the previous BAR size
+ * to the updated start address
+ */
+ if ((np_bar_size == 0) && ((g_np_bus == bus))) {
+ if (g_np_bar_size < bar_size) {
+ g_bar32_np_start = g_bar32_np_start +
+ (uint32_t)bar_size;
+ } else {
+ g_bar32_np_start = g_bar32_np_start +
+ g_np_bar_size;
+ }
+ } else if ((g_np_bar_size < bar_size) &&
+ (np_bar_size != 0)) {
+ g_bar32_np_start = g_bar32_np_start +
+ (uint32_t)bar_size;
+ } else {
+ g_bar32_np_start = g_bar32_np_start +
+ np_bar_size;
+ }
+
+ pal_pci_cfg_write(bus, dev, func, offset,
+ g_bar32_np_start);
+ np_bar_size = (uint32_t)bar_size;
+ g_np_bar_size = (uint32_t)bar_size;
+ g_np_bus = bus;
+
+ pal_pci_cfg_read(bus, dev, func, offset, &bar_reg_value);
+ if (BAR_REG(bar_reg_value) == BAR_64_BIT) {
+ pal_pci_cfg_write(bus, dev, func,
+ offset + 4, 0);
+ offset = offset + 8;
+ }
+
+ if (BAR_REG(bar_reg_value) == BAR_32_BIT) {
+ offset = offset + 4;
+ }
+ }
+
+ g_bar32_p_max = g_bar32_p_start;
+ g_bar32_np_max = g_bar32_np_start;
+ g_bar64_p_max = g_bar64_p_start;
+ }
+}
+
+/*
+ * This API performs the PCIe bus enumeration
+ *
+ * bus,sec_bus - Bus(8-bits), secondary bus (8-bits)
+ * sub_bus - Subordinate bus
+ */
+static uint32_t pcie_enumerate_device(uint32_t bus, uint32_t sec_bus)
+{
+ uint32_t vendor_id = 0;
+ uint32_t header_value;
+ uint32_t sub_bus = bus;
+ uint32_t dev;
+ uint32_t func;
+ uint32_t class_code;
+ uint32_t com_reg_value;
+ uint32_t bar32_p_limit;
+ uint32_t bar32_np_limit;
+ uint32_t bar32_p_base = g_bar32_p_start;
+ uint32_t bar32_np_base = g_bar32_np_start;
+ uint64_t bar64_p_base = g_bar64_p_start;
+
+ if (bus == ((g_pcie_info_table->block[g_pcie_index].end_bus_num) + 1)) {
+ return sub_bus;
+ }
+
+ for (dev = 0; dev < PCIE_MAX_DEV; dev++) {
+ for (func = 0; func < PCIE_MAX_FUNC; func++) {
+ pal_pci_cfg_read(bus, dev, func, 0, &vendor_id);
+
+ if ((vendor_id == 0x0) || (vendor_id == 0xFFFFFFFF)) {
+ continue;
+ }
+
+ /* Skip Hostbridge configuration */
+ pal_pci_cfg_read(bus, dev, func, TYPE01_RIDR,
+ &class_code);
+
+ if ((((class_code >> CC_BASE_SHIFT) & CC_BASE_MASK) ==
+ HB_BASE_CLASS) &&
+ (((class_code >> CC_SUB_SHIFT) & CC_SUB_MASK)) ==
+ HB_SUB_CLASS) {
+ continue;
+ }
+
+ pal_pci_cfg_read(bus, dev, func, HEADER_OFFSET,
+ &header_value);
+ if (PCIE_HEADER_TYPE(header_value) == TYPE1_HEADER) {
+ /*
+ * Enable memory access, Bus master enable and
+ * I/O access
+ */
+ pal_pci_cfg_read(bus, dev, func,
+ COMMAND_REG_OFFSET,
+ &com_reg_value);
+
+ pal_pci_cfg_write(bus, dev, func,
+ COMMAND_REG_OFFSET,
+ (com_reg_value |
+ REG_ACC_DATA));
+
+ pal_pci_cfg_write(bus, dev, func,
+ BUS_NUM_REG_OFFSET,
+ BUS_NUM_REG_CFG(0xFF, sec_bus,
+ bus));
+
+ pal_pci_cfg_write(bus, dev, func,
+ NON_PRE_FET_OFFSET,
+ ((g_bar32_np_start >> 16) &
+ 0xFFF0));
+
+ pal_pci_cfg_write(bus, dev, func,
+ PRE_FET_OFFSET,
+ ((g_bar32_p_start >> 16) &
+ 0xFFF0));
+
+ sub_bus = pcie_enumerate_device(sec_bus,
+ (sec_bus + 1));
+ pal_pci_cfg_write(bus, dev, func,
+ BUS_NUM_REG_OFFSET,
+ BUS_NUM_REG_CFG(sub_bus,
+ sec_bus, bus));
+ sec_bus = sub_bus + 1;
+
+ /*
+ * Obtain the start memory base address & the
+ * final memory base address of 32 bit BAR
+ */
+ bar32_p_limit = g_bar32_p_max;
+ bar32_np_limit = g_bar32_np_max;
+
+ get_resource_base_32(bus, dev, func,
+ bar32_p_base,
+ bar32_np_base,
+ bar32_p_limit,
+ bar32_np_limit);
+
+ /*
+ * Obtain the start memory base address & the
+ * final memory base address of 64 bit BAR
+ */
+ get_resource_base_64(bus, dev, func,
+ bar64_p_base,
+ g_bar64_p_max);
+
+ /* Update the BAR values of Type 1 Devices */
+ pcie_rp_program_bar(bus, dev, func);
+
+ /* Update the base and limit values */
+ bar32_p_base = g_bar32_p_start;
+ bar32_np_base = g_bar32_np_start;
+ bar64_p_base = g_bar64_p_start;
+ }
+
+ if (PCIE_HEADER_TYPE(header_value) == TYPE0_HEADER) {
+ pcie_program_bar_reg(bus, dev, func);
+ sub_bus = sec_bus - 1;
+ }
+ }
+ }
+
+ return sub_bus;
+}
+
+/*
+ * This API clears the primary bus number configured in the Type1 Header.
+ * Note: This is done to make sure the hardware is compatible
+ * with Linux enumeration.
+ */
+static void pcie_clear_pri_bus(void)
+{
+ uint32_t bus;
+ uint32_t dev;
+ uint32_t func;
+ uint32_t bus_value;
+ uint32_t header_value;
+ uint32_t vendor_id;
+
+ for (bus = 0; bus <= g_pcie_info_table->block[g_pcie_index].end_bus_num;
+ bus++) {
+ for (dev = 0; dev < PCIE_MAX_DEV; dev++) {
+ for (func = 0; func < PCIE_MAX_FUNC; func++) {
+ pal_pci_cfg_read(bus, dev, func, 0, &vendor_id);
+
+ if ((vendor_id == 0x0) ||
+ (vendor_id == 0xFFFFFFFF)) {
+ continue;
+ }
+
+ pal_pci_cfg_read(bus, dev, func, HEADER_OFFSET,
+ &header_value);
+ if (PCIE_HEADER_TYPE(header_value) ==
+ TYPE1_HEADER) {
+ pal_pci_cfg_read(bus, dev, func,
+ BUS_NUM_REG_OFFSET,
+ &bus_value);
+
+ bus_value = bus_value &
+ PRI_BUS_CLEAR_MASK;
+
+ pal_pci_cfg_write(bus, dev, func,
+ BUS_NUM_REG_OFFSET,
+ bus_value);
+ }
+ }
+ }
+ }
+}
+
+static void pcie_enumerate_devices(void)
+{
+ uint32_t pri_bus, sec_bus;
+ int rc;
+
+ g_pcie_info_table = plat_pcie_get_info_table();
+ if (g_pcie_info_table == NULL) {
+ ERROR("PCIe info not returned by platform\n");
+ panic();
+ }
+
+ if (g_pcie_info_table->num_entries == 0) {
+ INFO("Skipping Enumeration\n");
+ return;
+ }
+
+ /* Get platform specific bar config parameters */
+ rc = plat_pcie_get_bar_config(&g_bar64_p_start, &g_rp_bar64_value,
+ &g_bar32_np_start, &g_bar32_p_start,
+ &g_rp_bar32_value);
+ if (rc != 0) {
+ ERROR("PCIe bar config parameters not returned by platform\n");
+ panic();
+ }
+
+ INFO("Starting Enumeration\n");
+ while (g_pcie_index < g_pcie_info_table->num_entries) {
+ pri_bus = g_pcie_info_table->block[g_pcie_index].start_bus_num;
+
+ sec_bus = pri_bus + 1;
+
+ pcie_enumerate_device(pri_bus, sec_bus);
+ pcie_clear_pri_bus();
+
+ g_pcie_index++;
+ }
+ g_enumerate = 0;
+ g_pcie_index = 0;
+}
+
void pcie_init(void)
{
static bool is_init;
/* Create PCIe table and enumeration */
if (!is_init) {
+ pcie_enumerate_devices();
+
pcie_create_info_table();
is_init = true;
}
diff --git a/plat/arm/fvp/fvp_pcie.c b/plat/arm/fvp/fvp_pcie.c
index 38bdf39..4bba516 100644
--- a/plat/arm/fvp/fvp_pcie.c
+++ b/plat/arm/fvp/fvp_pcie.c
@@ -27,6 +27,28 @@
return &fvp_pcie_cfg;
}
+/* Retrieve platform PCIe bar config values */
+int plat_pcie_get_bar_config(uint64_t *bar64_val, uint64_t *rp_bar64_val,
+ uint32_t *bar32np_val, uint32_t *bar32p_val,
+ uint32_t *rp_bar32_val)
+{
+#ifdef __aarch64__
+ assert((bar64_val != NULL) && (rp_bar64_val != NULL) &&
+ (bar32np_val != NULL) && (bar32p_val != NULL) &&
+ (rp_bar32_val != NULL));
+
+ *bar64_val = PLATFORM_OVERRIDE_PCIE_BAR64_VALUE;
+ *rp_bar64_val = PLATFORM_OVERRIDE_RP_BAR64_VALUE;
+
+ *bar32np_val = PLATFORM_OVERRIDE_PCIE_BAR32NP_VALUE;
+ *bar32p_val = PLATFORM_OVERRIDE_PCIE_BAR32P_VALUE;
+ *rp_bar32_val = PLATOFRM_OVERRIDE_RP_BAR32_VALUE;
+
+ return 0;
+#endif
+ return -1;
+}
+
/*
* Retrieve platform PCIe memory region (Base Platform RevC only)
*/
diff --git a/plat/arm/fvp/include/platform_pcie.h b/plat/arm/fvp/include/platform_pcie.h
index 4b3a0e9..4a2817e 100644
--- a/plat/arm/fvp/include/platform_pcie.h
+++ b/plat/arm/fvp/include/platform_pcie.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2024-2025, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -19,4 +19,11 @@
#define PLATFORM_PCIE_START_BUS_NUM_0 0x0
#define PLATFORM_PCIE_END_BUS_NUM_0 0xFF
+/* PCIe BAR config parameters*/
+#define PLATFORM_OVERRIDE_PCIE_BAR64_VALUE 0x4000100000
+#define PLATFORM_OVERRIDE_RP_BAR64_VALUE 0x4000000000
+#define PLATFORM_OVERRIDE_PCIE_BAR32NP_VALUE 0x50000000
+#define PLATFORM_OVERRIDE_PCIE_BAR32P_VALUE 0x50600000
+#define PLATOFRM_OVERRIDE_RP_BAR32_VALUE 0x50850000
+
#endif /* PLATFORM_PCIE_H */
diff --git a/plat/common/plat_common.c b/plat/common/plat_common.c
index c06ad13..f8524cf 100644
--- a/plat/common/plat_common.c
+++ b/plat/common/plat_common.c
@@ -1,3 +1,4 @@
+
/*
* Copyright (c) 2018-2025, Arm Limited. All rights reserved.
*
@@ -25,6 +26,7 @@
#pragma weak tftf_plat_reset
#pragma weak plat_get_prot_regions
#pragma weak plat_pcie_get_info_table
+#pragma weak plat_pcie_get_bar_config
#pragma weak plat_get_invalid_addr
#pragma weak plat_get_dev_region
@@ -157,6 +159,13 @@
return NULL;
}
+int plat_pcie_get_bar_config(uint64_t *bar64_val, uint64_t *rp_bar64_val,
+ uint32_t *bar32np_val, uint32_t *bar32p_val,
+ uint32_t *rp_bar32_val)
+{
+ return -1;
+}
+
uintptr_t plat_get_invalid_addr(void)
{
return (uintptr_t)0x0;