forked from zephyrproject-rtos/zephyr
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This adds a generic PCIe Controller driver API providing the necessary callbacks & config structure to handle the PCIe config space and BAR regions handling. Signed-off-by: Neil Armstrong <[email protected]>
- Loading branch information
1 parent
3f68124
commit c714368
Showing
1 changed file
with
294 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,294 @@ | ||
/** | ||
* @file | ||
* | ||
* @brief Public APIs for the PCIe Controllers drivers. | ||
*/ | ||
|
||
/* | ||
* Copyright (c) 2021 BayLibre, SAS | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
#ifndef ZEPHYR_INCLUDE_DRIVERS_PCIE_CONTROLLERS_H_ | ||
#define ZEPHYR_INCLUDE_DRIVERS_PCIE_CONTROLLERS_H_ | ||
|
||
#include <zephyr/types.h> | ||
#include <device.h> | ||
|
||
/** | ||
* @brief PCI Express Controller Interface | ||
* @defgroup pcie_controller_interface PCI Express Controller Interface | ||
* @ingroup io_interfaces | ||
* @{ | ||
*/ | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
/** | ||
* @brief Function called to read a 32-bit word from an endpoint's configuration space. | ||
* | ||
* Read a 32-bit word from an endpoint's configuration space with the PCI Express Controller | ||
* configuration space access method (I/O port, memory mapped or custom method) | ||
* | ||
* @param dev PCI Express Controller device pointer | ||
* @param bdf PCI(e) endpoint | ||
* @param reg the configuration word index (not address) | ||
* @return the word read (0xFFFFFFFFU if nonexistent endpoint or word) | ||
*/ | ||
typedef uint32_t (*pcie_ctrl_conf_read_t)(const struct device *dev, pcie_bdf_t bdf, | ||
unsigned int reg); | ||
|
||
/** | ||
* @brief Function called to write a 32-bit word to an endpoint's configuration space. | ||
* | ||
* Write a 32-bit word to an endpoint's configuration space with the PCI Express Controller | ||
* configuration space access method (I/O port, memory mapped or custom method) | ||
* | ||
* @param dev PCI Express Controller device pointer | ||
* @param bdf PCI(e) endpoint | ||
* @param reg the configuration word index (not address) | ||
* @param data the value to write | ||
*/ | ||
typedef void (*pcie_ctrl_conf_write_t)(const struct device *dev, pcie_bdf_t bdf, | ||
unsigned int reg, uint32_t data); | ||
|
||
/** | ||
* @brief Function called to allocate a memory region subset for an endpoint Base Address Register. | ||
* | ||
* When enumerating PCIe Endpoints, Type0 endpoints can require up to 6 memory zones | ||
* via the Base Address Registers from I/O or Memory types. | ||
* | ||
* This call allocates such zone in the PCI Express Controller memory regions if | ||
* such region is available and space is still available. | ||
* | ||
* @param dev PCI Express Controller device pointer | ||
* @param bdf PCI(e) endpoint | ||
* @param mem True if the BAR is of memory type | ||
* @param mem64 True if the BAR is of 64bit memory type | ||
* @param bar_size Size in bytes of the Base Address Register as returned by HW | ||
* @param bar_bus_addr bus-centric address allocated to be written in the BAR register | ||
* @return True if allocation was possible, False if allocation failed | ||
*/ | ||
typedef bool (*pcie_ctrl_region_allocate_t)(const struct device *dev, pcie_bdf_t bdf, | ||
bool mem, bool mem64, size_t bar_size, | ||
uintptr_t *bar_bus_addr); | ||
|
||
/** | ||
* @brief Function called to translate an endpoint Base Address Register bus-centric address | ||
* into Physical address. | ||
* | ||
* When enumerating PCIe Endpoints, Type0 endpoints can require up to 6 memory zones | ||
* via the Base Address Registers from I/O or Memory types. | ||
* | ||
* The bus-centric address set in this BAR register is not necessarely accessible from the CPU, | ||
* thus must be translated by using the PCI Express Controller memory regions translation | ||
* ranges to permit mapping from the CPU. | ||
* | ||
* @param dev PCI Express Controller device pointer | ||
* @param bdf PCI(e) endpoint | ||
* @param mem True if the BAR is of memory type | ||
* @param mem64 True if the BAR is of 64bit memory type | ||
* @param bar_bus_addr bus-centric address written in the BAR register | ||
* @param bar_addr CPU-centric address translated from the bus-centric address | ||
* @return True if translation was possible, False if translation failed | ||
*/ | ||
typedef bool (*pcie_ctrl_region_xlate_t)(const struct device *dev, pcie_bdf_t bdf, | ||
bool mem, bool mem64, uintptr_t bar_bus_addr, | ||
uintptr_t *bar_addr); | ||
|
||
/** | ||
* @brief Read a 32-bit word from a Memory-Mapped endpoint's configuration space. | ||
* | ||
* Read a 32-bit word from an endpoint's configuration space from a Memory-Mapped | ||
* configuration space access method, known as PCI Control Access Method (CAM) or | ||
* PCIe Extended Control Access Method (ECAM). | ||
* | ||
* @param cfg_addr Logical address of Memory-Mapped configuration space | ||
* @param bdf PCI(e) endpoint | ||
* @param reg the configuration word index (not address) | ||
* @return the word read (0xFFFFFFFFU if nonexistent endpoint or word) | ||
*/ | ||
uint32_t generic_pcie_ctrl_conf_read(mm_reg_t cfg_addr, pcie_bdf_t bdf, unsigned int reg); | ||
|
||
|
||
/** | ||
* @brief Write a 32-bit word to a Memory-Mapped endpoint's configuration space. | ||
* | ||
* Write a 32-bit word to an endpoint's configuration space from a Memory-Mapped | ||
* configuration space access method, known as PCI Control Access Method (CAM) or | ||
* PCIe Extended Control Access Method (ECAM). | ||
* | ||
* @param cfg_addr Logical address of Memory-Mapped configuration space | ||
* @param bdf PCI(e) endpoint | ||
* @param reg the configuration word index (not address) | ||
* @param data the value to write | ||
*/ | ||
void generic_pcie_ctrl_conf_write(mm_reg_t cfg_addr, pcie_bdf_t bdf, | ||
unsigned int reg, uint32_t data); | ||
|
||
/** | ||
* @brief Start PCIe Endpoints enumeration. | ||
* | ||
* Start a PCIe Endpoints enumeration from a Bus number. | ||
* When on non-x86 architecture or when firmware didn't setup the PCIe Bus hierarchy, | ||
* the PCIe bus complex must be enumerated to setup the Endpoints Base Address Registers. | ||
* | ||
* @param dev PCI Express Controller device pointer | ||
* @param bdf_start PCI(e) start endpoint (only bus & dev are used to start enumeration) | ||
*/ | ||
void generic_pcie_ctrl_enumerate(const struct device *dev, pcie_bdf_t bdf_start); | ||
|
||
/** @brief Structure providing callbacks to be implemented for devices | ||
* that supports the PCI Express Controller API | ||
*/ | ||
__subsystem struct pcie_ctrl_driver_api { | ||
pcie_ctrl_conf_read_t conf_read; | ||
pcie_ctrl_conf_write_t conf_write; | ||
pcie_ctrl_region_allocate_t region_allocate; | ||
pcie_ctrl_region_xlate_t region_xlate; | ||
}; | ||
|
||
/** | ||
* @brief Read a 32-bit word from an endpoint's configuration space. | ||
* | ||
* Read a 32-bit word from an endpoint's configuration space with the PCI Express Controller | ||
* configuration space access method (I/O port, memory mapped or custom method) | ||
* | ||
* @param dev PCI Express Controller device pointer | ||
* @param bdf PCI(e) endpoint | ||
* @param reg the configuration word index (not address) | ||
* @return the word read (0xFFFFFFFFU if nonexistent endpoint or word) | ||
*/ | ||
static inline uint32_t pcie_ctrl_conf_read(const struct device *dev, pcie_bdf_t bdf, | ||
unsigned int reg) | ||
{ | ||
const struct pcie_ctrl_driver_api *api = | ||
(const struct pcie_ctrl_driver_api *)dev->api; | ||
|
||
return api->conf_read(dev, bdf, reg); | ||
} | ||
|
||
/** | ||
* @brief Write a 32-bit word to an endpoint's configuration space. | ||
* | ||
* Write a 32-bit word to an endpoint's configuration space with the PCI Express Controller | ||
* configuration space access method (I/O port, memory mapped or custom method) | ||
* | ||
* @param dev PCI Express Controller device pointer | ||
* @param bdf PCI(e) endpoint | ||
* @param reg the configuration word index (not address) | ||
* @param data the value to write | ||
*/ | ||
static inline void pcie_ctrl_conf_write(const struct device *dev, pcie_bdf_t bdf, | ||
unsigned int reg, uint32_t data) | ||
{ | ||
const struct pcie_ctrl_driver_api *api = | ||
(const struct pcie_ctrl_driver_api *)dev->api; | ||
|
||
api->conf_write(dev, bdf, reg, data); | ||
} | ||
|
||
/** | ||
* @brief Allocate a memory region subset for an endpoint Base Address Register. | ||
* | ||
* When enumerating PCIe Endpoints, Type0 endpoints can require up to 6 memory zones | ||
* via the Base Address Registers from I/O or Memory types. | ||
* | ||
* This call allocates such zone in the PCI Express Controller memory regions if | ||
* such region is available and space is still available. | ||
* | ||
* @param dev PCI Express Controller device pointer | ||
* @param bdf PCI(e) endpoint | ||
* @param mem True if the BAR is of memory type | ||
* @param mem64 True if the BAR is of 64bit memory type | ||
* @param bar_size Size in bytes of the Base Address Register as returned by HW | ||
* @param bar_bus_addr bus-centric address allocated to be written in the BAR register | ||
* @return True if allocation was possible, False if allocation failed | ||
*/ | ||
static inline bool pcie_ctrl_region_allocate(const struct device *dev, pcie_bdf_t bdf, | ||
bool mem, bool mem64, size_t bar_size, | ||
uintptr_t *bar_bus_addr) | ||
{ | ||
const struct pcie_ctrl_driver_api *api = | ||
(const struct pcie_ctrl_driver_api *)dev->api; | ||
|
||
return api->region_allocate(dev, bdf, mem, mem64, bar_size, bar_bus_addr); | ||
} | ||
|
||
/** | ||
* @brief Translate an endpoint Base Address Register bus-centric address into Physical address. | ||
* | ||
* When enumerating PCIe Endpoints, Type0 endpoints can require up to 6 memory zones | ||
* via the Base Address Registers from I/O or Memory types. | ||
* | ||
* The bus-centric address set in this BAR register is not necessarely accessible from the CPU, | ||
* thus must be translated by using the PCI Express Controller memory regions translation | ||
* ranges to permit mapping from the CPU. | ||
* | ||
* @param dev PCI Express Controller device pointer | ||
* @param bdf PCI(e) endpoint | ||
* @param mem True if the BAR is of memory type | ||
* @param mem64 True if the BAR is of 64bit memory type | ||
* @param bar_bus_addr bus-centric address written in the BAR register | ||
* @param bar_addr CPU-centric address translated from the bus-centric address | ||
* @return True if translation was possible, False if translation failed | ||
*/ | ||
static inline bool pcie_ctrl_region_xlate(const struct device *dev, pcie_bdf_t bdf, | ||
bool mem, bool mem64, uintptr_t bar_bus_addr, | ||
uintptr_t *bar_addr) | ||
{ | ||
const struct pcie_ctrl_driver_api *api = | ||
(const struct pcie_ctrl_driver_api *)dev->api; | ||
|
||
if (!api->region_xlate) { | ||
*bar_addr = bar_bus_addr; | ||
return true; | ||
} else { | ||
return api->region_xlate(dev, bdf, mem, mem64, bar_bus_addr, bar_addr); | ||
} | ||
} | ||
|
||
/** @brief Structure describing a device that supports the PCI Express Controller API | ||
*/ | ||
struct pcie_ctrl_config { | ||
/* Configuration space physical address */ | ||
uintptr_t cfg_addr; | ||
/* Configuration space physical size */ | ||
size_t cfg_size; | ||
/* BAR regions translation ranges count */ | ||
size_t ranges_count; | ||
/* BAR regions translation ranges table */ | ||
struct { | ||
/* Flags as defined in the PCI Bus Binding to IEEE Std 1275-1994 */ | ||
uint32_t flags; | ||
/* bus-centric offset from the start of the region */ | ||
uintptr_t pcie_bus_addr; | ||
/* CPU-centric offset from the start of the region */ | ||
uintptr_t host_map_addr; | ||
/* region size */ | ||
size_t map_length; | ||
} ranges[]; | ||
}; | ||
|
||
/* | ||
* Fills the pcie_ctrl_config.ranges table from DT | ||
*/ | ||
#define PCIE_RANGE_FORMAT(node_id, idx) \ | ||
{ \ | ||
.flags = DT_RANGES_CHILD_BUS_FLAGS_BY_IDX(node_id, idx), \ | ||
.pcie_bus_addr = DT_RANGES_CHILD_BUS_ADDRESS_BY_IDX(node_id, idx), \ | ||
.host_map_addr = DT_RANGES_PARENT_BUS_ADDRESS_BY_IDX(node_id, idx), \ | ||
.map_length = DT_RANGES_LENGTH_BY_IDX(node_id, idx), \ | ||
}, | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
/** | ||
* @} | ||
*/ | ||
|
||
#endif /* ZEPHYR_INCLUDE_DRIVERS_PCIE_CONTROLLERS_H_ */ |