pcie: add PCIe Controller API
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 <narmstrong@baylibre.com>
This commit is contained in:
parent
3f68124c56
commit
c714368691
1 changed files with 294 additions and 0 deletions
294
include/drivers/pcie/controller.h
Normal file
294
include/drivers/pcie/controller.h
Normal file
|
@ -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_ */
|
Loading…
Add table
Add a link
Reference in a new issue