| /** |
| * @file |
| * |
| * @brief Public APIs for the PCIe EP drivers. |
| */ |
| |
| /* |
| * SPDX-License-Identifier: Apache-2.0 |
| * |
| * Copyright 2020 Broadcom |
| * |
| */ |
| #ifndef ZEPHYR_INCLUDE_DRIVERS_PCIE_EP_H_ |
| #define ZEPHYR_INCLUDE_DRIVERS_PCIE_EP_H_ |
| |
| #include <device.h> |
| #include <init.h> |
| #include <kernel.h> |
| #include <stdint.h> |
| |
| enum pcie_ob_mem_type { |
| PCIE_OB_ANYMEM, /**< PCIe OB window within any address range */ |
| PCIE_OB_LOWMEM, /**< PCIe OB window within 32-bit address range */ |
| PCIE_OB_HIGHMEM, /**< PCIe OB window above 32-bit address range */ |
| }; |
| |
| enum pci_ep_irq_type { |
| PCIE_EP_IRQ_LEGACY, /**< Raise Legacy interrupt */ |
| PCIE_EP_IRQ_MSI, /**< Raise MSI interrupt */ |
| PCIE_EP_IRQ_MSIX, /**< Raise MSIX interrupt */ |
| }; |
| |
| enum xfer_direction { |
| HOST_TO_DEVICE, /**< Read from Host */ |
| DEVICE_TO_HOST, /**< Write to Host */ |
| }; |
| |
| enum pcie_reset { |
| PCIE_PERST, /**< Cold reset */ |
| PCIE_PERST_INB, /**< Inband hot reset */ |
| PCIE_FLR, /**< Functional Level Reset */ |
| PCIE_RESET_MAX |
| }; |
| |
| /** |
| * @typedef pcie_ep_reset_callback_t |
| * @brief Callback API for PCIe reset interrupts |
| * |
| * These callbacks execute in interrupt context. Therefore, use only |
| * interrupt-safe APIS. Registration of callbacks is done via |
| * @a pcie_ep_register_reset_cb |
| * |
| * @param arg Pointer provided at registration time, later to be |
| * passed back as argument to callback function |
| */ |
| |
| typedef void (*pcie_ep_reset_callback_t)(void *arg); |
| |
| struct pcie_ep_driver_api { |
| int (*conf_read)(const struct device *dev, uint32_t offset, |
| uint32_t *data); |
| void (*conf_write)(const struct device *dev, uint32_t offset, |
| uint32_t data); |
| int (*map_addr)(const struct device *dev, uint64_t pcie_addr, |
| uint64_t *mapped_addr, uint32_t size, |
| enum pcie_ob_mem_type ob_mem_type); |
| void (*unmap_addr)(const struct device *dev, uint64_t mapped_addr); |
| int (*raise_irq)(const struct device *dev, |
| enum pci_ep_irq_type irq_type, |
| uint32_t irq_num); |
| int (*register_reset_cb)(const struct device *dev, |
| enum pcie_reset reset, |
| pcie_ep_reset_callback_t cb, void *arg); |
| int (*dma_xfer)(const struct device *dev, uint64_t mapped_addr, |
| uintptr_t local_addr, uint32_t size, |
| enum xfer_direction dir); |
| }; |
| |
| /** |
| * @brief Read PCIe EP configuration space |
| * |
| * @details This API reads EP's own configuration space |
| * |
| * @param dev Pointer to the device structure for the driver instance |
| * @param offset Offset within configuration space |
| * @param data Pointer to data read from the offset |
| * |
| * @return 0 if successful, negative errno code if failure. |
| */ |
| |
| static inline int pcie_ep_conf_read(const struct device *dev, |
| uint32_t offset, uint32_t *data) |
| { |
| const struct pcie_ep_driver_api *api = |
| (const struct pcie_ep_driver_api *)dev->api; |
| |
| return api->conf_read(dev, offset, data); |
| } |
| |
| /** |
| * @brief Write PCIe EP configuration space |
| * |
| * @details This API writes EP's own configuration space |
| * |
| * @param dev Pointer to the device structure for the driver instance |
| * @param offset Offset within configuration space |
| * @param data Data to be written at the offset |
| */ |
| |
| static inline void pcie_ep_conf_write(const struct device *dev, |
| uint32_t offset, uint32_t data) |
| { |
| const struct pcie_ep_driver_api *api = |
| (const struct pcie_ep_driver_api *)dev->api; |
| |
| api->conf_write(dev, offset, data); |
| } |
| |
| /** |
| * @brief Map a host memory buffer to PCIe outbound region |
| * |
| * @details This API maps a host memory buffer to PCIe outbound region, |
| * It is left to EP driver to manage multiple mappings through |
| * multiple PCIe outbound regions if supported by SoC |
| * |
| * @param dev Pointer to the device structure for the driver instance |
| * @param pcie_addr Host memory buffer address to be mapped |
| * @param mapped_addr Mapped PCIe outbound region address |
| * @param size Host memory buffer size (bytes) |
| * @param ob_mem_type Hint if lowmem/highmem outbound region has to be used, |
| * this is useful in cases where bus master cannot generate |
| * more than 32-bit address; it becomes essential to use |
| * lowmem outbound region |
| * |
| * @return Mapped size : If mapped size is less than requested size, |
| * then requestor has to call the same API again to map |
| * the unmapped host buffer after data transfer is done with |
| * mapped size. This situation may arise because of the |
| * mapping alignment requirements. |
| * |
| * @return Negative errno code if failure. |
| */ |
| |
| static inline int pcie_ep_map_addr(const struct device *dev, |
| uint64_t pcie_addr, |
| uint64_t *mapped_addr, uint32_t size, |
| enum pcie_ob_mem_type ob_mem_type) |
| { |
| const struct pcie_ep_driver_api *api = |
| (const struct pcie_ep_driver_api *)dev->api; |
| |
| return api->map_addr(dev, pcie_addr, mapped_addr, size, ob_mem_type); |
| } |
| |
| /** |
| * @brief Remove mapping to PCIe outbound region |
| * |
| * @details This API removes mapping to PCIe outbound region. |
| * Mapped PCIe outbound region address is given as argument |
| * to figure out the outbound region to be unmapped |
| * |
| * @param dev Pointer to the device structure for the driver instance |
| * @param mapped_addr PCIe outbound region address |
| */ |
| |
| static inline void pcie_ep_unmap_addr(const struct device *dev, |
| uint64_t mapped_addr) |
| { |
| const struct pcie_ep_driver_api *api = |
| (const struct pcie_ep_driver_api *)dev->api; |
| |
| api->unmap_addr(dev, mapped_addr); |
| } |
| |
| /** |
| * @brief Raise interrupt to Host |
| * |
| * @details This API raises interrupt to Host |
| * |
| * @param dev Pointer to the device structure for the driver instance |
| * @param irq_type Type of Interrupt be raised (legacy, MSI or MSI-X) |
| * @param irq_num MSI or MSI-X interrupt number |
| * |
| * @return 0 if successful, negative errno code if failure. |
| */ |
| |
| static inline int pcie_ep_raise_irq(const struct device *dev, |
| enum pci_ep_irq_type irq_type, |
| uint32_t irq_num) |
| { |
| const struct pcie_ep_driver_api *api = |
| (const struct pcie_ep_driver_api *)dev->api; |
| return api->raise_irq(dev, irq_type, irq_num); |
| } |
| |
| /** |
| * @brief Register callback function for reset interrupts |
| * |
| * @details If reset interrupts are handled by device, this API can be |
| * used to register callback function, which will be |
| * executed part of corresponding PCIe reset handler |
| * |
| * @param dev Pointer to the device structure for the driver instance |
| * @param reset Reset interrupt type |
| * @param cb Callback function being registered |
| * @param arg Argument to be passed back to callback function |
| * |
| * @return 0 if successful, negative errno code if failure. |
| */ |
| |
| static inline int pcie_ep_register_reset_cb(const struct device *dev, |
| enum pcie_reset reset, |
| pcie_ep_reset_callback_t cb, |
| void *arg) |
| { |
| const struct pcie_ep_driver_api *api = |
| (const struct pcie_ep_driver_api *)dev->api; |
| |
| if (api->register_reset_cb) { |
| return api->register_reset_cb(dev, reset, cb, arg); |
| } |
| |
| return -ENOTSUP; |
| } |
| |
| /** |
| * @brief Data transfer between mapped Host memory and device memory with |
| * "System DMA". The term "System DMA" is used to clarify that we |
| * are not talking about dedicated "PCIe DMA"; rather the one |
| * which does not understand PCIe address directly, and |
| * uses the mapped Host memory. |
| * |
| * @details If DMA controller is available in the EP device, this API can be |
| * used to achieve data transfer between mapped Host memory, |
| * i.e. outbound memory and EP device's local memory with DMA |
| * |
| * @param dev Pointer to the device structure for the driver instance |
| * @param mapped_addr Mapped Host memory address |
| * @param local_addr Device memory address |
| * @param size DMA transfer length (bytes) |
| * @param dir Direction of DMA transfer |
| * |
| * @return 0 if successful, negative errno code if failure. |
| */ |
| |
| static inline int pcie_ep_dma_xfer(const struct device *dev, |
| uint64_t mapped_addr, |
| uintptr_t local_addr, uint32_t size, |
| const enum xfer_direction dir) |
| { |
| const struct pcie_ep_driver_api *api = |
| (const struct pcie_ep_driver_api *)dev->api; |
| |
| if (api->dma_xfer) { |
| return api->dma_xfer(dev, mapped_addr, local_addr, size, dir); |
| } |
| |
| return -ENOTSUP; |
| } |
| |
| /** |
| * @brief Data transfer using memcpy |
| * |
| * @details Helper API to achieve data transfer with memcpy |
| * through PCIe outbound memory |
| * |
| * @param dev Pointer to the device structure for the driver instance |
| * @param pcie_addr Host memory buffer address |
| * @param local_addr Local memory buffer address |
| * @param size Data transfer size (bytes) |
| * @param ob_mem_type Hint if lowmem/highmem outbound region has to be used |
| * (PCIE_OB_LOWMEM / PCIE_OB_HIGHMEM / PCIE_OB_ANYMEM), |
| * should be PCIE_OB_LOWMEM if bus master cannot generate |
| * more than 32-bit address |
| * @param dir Data transfer direction (HOST_TO_DEVICE / DEVICE_TO_HOST) |
| * |
| * @return 0 if successful, negative errno code if failure. |
| */ |
| int pcie_ep_xfer_data_memcpy(const struct device *dev, uint64_t pcie_addr, |
| uintptr_t *local_addr, uint32_t size, |
| enum pcie_ob_mem_type ob_mem_type, |
| enum xfer_direction dir); |
| |
| /** |
| * @brief Data transfer using system DMA |
| * |
| * @details Helper API to achieve data transfer with system DMA through PCIe |
| * outbound memory, this API is based off pcie_ep_xfer_data_memcpy, |
| * here we use "system dma" instead of memcpy |
| * |
| * @param dev Pointer to the device structure for the driver instance |
| * @param pcie_addr Host memory buffer address |
| * @param local_addr Local memory buffer address |
| * @param size Data transfer size (bytes) |
| * @param ob_mem_type Hint if lowmem/highmem outbound region has to be used |
| * (PCIE_OB_LOWMEM / PCIE_OB_HIGHMEM / PCIE_OB_ANYMEM) |
| * @param dir Data transfer direction (HOST_TO_DEVICE / DEVICE_TO_HOST) |
| * |
| * @return 0 if successful, negative errno code if failure. |
| */ |
| int pcie_ep_xfer_data_dma(const struct device *dev, uint64_t pcie_addr, |
| uintptr_t *local_addr, uint32_t size, |
| enum pcie_ob_mem_type ob_mem_type, |
| enum xfer_direction dir); |
| |
| #endif /* ZEPHYR_INCLUDE_DRIVERS_PCIE_EP_H_ */ |