/***************************************************************************** * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire and PolarFire SoC PCIe subsystem software driver implementation. * */ #include "pf_pcie.h" #ifdef __cplusplus extern "C" { #endif /**************************************************************************/ /* Preprocessor Macros */ /**************************************************************************/ /* PCIe enumeration values */ /* At Present PCIe supports one Root Port and End Point */ #define PCIE_CFG_MAX_NUM_OF_BUS 8u #define PCIE_CFG_MAX_NUM_OF_DEV 2u #define PCIE_CFG_MAX_NUM_OF_FUN 8u #define PCIE_CFG_FUN_NOT_IMP_MASK 0xFFFFu #define PCIE_CFG_HEADER_TYPE_MASK 0x00EF0000u #define PCIE_CFG_MUL_FUN_DEV_MASK 0x00800000u #define PCIE_CFG_HEADER_O_TYPE 0x00000000u #define PCIE_CFG_CATCHE_SIZE 0x10u /* ECAM Address Register bitmaps and masks */ /* Mask of all valid bits */ #define PCIE_ECAM_MASK 0x0FFFFFFFu /* Bus Number Mask */ #define PCIE_ECAM_BUS_MASK 0x0FF00000u /* Device Number Mask */ #define PCIE_ECAM_DEV_MASK 0x000F8000u /* Function Number Mask */ #define PCIE_ECAM_FUN_MASK 0x00007000u /* Bus Number Shift Value */ #define PCIE_ECAM_BUS_SHIFT 20u /* Device Number Shift Value */ #define PCIE_ECAM_DEV_SHIFT 15u /* Function Number Shift Value */ #define PCIE_ECAM_FUN_SHIFT 12u #define BAR_MASK 0xFFFFFFFFu #define BAR_SIZE_MASK 0xFFFFFFF0u #define BAR_LSB_MASK 0x0000000Fu #define VENDOR_ID_MASK 0xFFFFu /* 64-bit Address space of BAR */ #define ADDR_SPACE_64BIT 0x00000004u /* Translated ID */ #define PCIE_TX_RX_INTERFACE 0x00000000u #define PCIE_CONFIG_INTERFACE 0x00000001u #define AXI4_MASTER_0_INTERFACE 0x00000004u /* Translation table size 256MB */ #define SIZE_256MB_TRANSLATE_TABLE_EN 0x00000037u /* PCIe Root Port Control & Status Register: enable I/O, memory access, bus master,Parity Error Response and SERR# */ #define RP_CFG_PRMSCR_DATA 0x00000147u /* PCIe EndPoint Control & Status Register: enable Memory access, bus master */ #define EP_CFG_PRMSCR_DATA 0x00000006u /* device conrol status register: maxrdreq=512, maxpayloadsize=256 */ #define RP_DEVICE_CTRL_STATUS_DATA 0x0000202Fu #define EP_DEVICE_CTRL_STATUS_DATA 0x00FF2830u /* PCIe Sub bus:FF, sec bus:0, prim bus:0 */ #define PRIM_SEC_SUB_BUS_DEFAULT 0x00FF0000u /* Non-prefetchable Limit, Non-prefetchable Base */ #define RP_MEM_LIMIT_BASE_DATA 0xEEE0EEE0u /* Prefetchable Limit, Prefetchable Base */ #define RP_PREF_MEM_LIMIT_BASE_DATA 0xFFF1FFF1u /* Prefetchable Base upper */ #define RP_PREF_BASE_UPPER_DATA 0xFFFFFFFFu /* Prefetchable upper limit*/ #define RP_PREF_LIMIT_UPPER_DATA 0x00000000u /* PCIe Config space MSI capability structure */ #define PCIE_ENABLE_MSI 0x00010000u #define PCIE_CAPB_ID_MSI 0x05u #define PCIE_CAPB_ID_MASK 0xFFu #define PCIE_CONFIG_CAPB_ID_MASK 0xFFFFFFFFFFFFFF00u #define PCIE_MSI_64BIT_CAPB_ADDR 0x00800000u #define PCIE_MSI_MULTI_VECTOR_SHIFT 17u #define PCIE_MSI_MULTI_VECTOR_MASK 7u #define PCIE_MSI_MULTI_ENABLE_SHIFT 20u /* PCI Express Capability structure ID */ #define PCIE_CAPB_ID_STRUCT 0x10u /****************************************************************************/ /* PCIe AXI master table init defines */ #define ATR0_PCIE_WIN0_OFFSET 0x600u #define ATR_WIN_REG_TABLE_SIZE 0x20u #define WIN0_SRCADDR_PARAM 0x00u #define WIN0_SRC_ADDR 0x01u #define WIN0_TRSL_ADDR_LSB 0x02u #define WIN0_TRSL_ADDR_UDW 0x03u #define WIN0_TRSL_PARAM 0x04u #define ATR_ADDR_MASK 0xFFFFF000u #define TLP_SHIFT 16u #define BAR_01_DW0 0xE4u /****************************************************************************/ /* PCIe AXI slave table init defines */ #define ATR0_AXI4_SLV0_OFFSET 0x800u #define ATR_SLV_REG_TABLE_SIZE 0x20u #define SLV0_SRCADDR_PARAM 0x00u #define SLV0_SRC_ADDR 0x01u #define SLV0_TRSL_ADDR_LSB 0x02u #define SLV0_TRSL_ADDR_UDW 0x03u #define SLV0_TRSL_PARAM 0x04u /****************************************************************************/ /* DMA */ #define EP_DMA_START_DATA 0x00002321u #define EP_DMA_INTERFACE_AXI 0x00000004u #define EP_DMA_INTERFACE_PCIE 0x00000000u /* EP DMA interrupt and error status */ #define DMA_INT_STATUS 0x00000003u #define DMA_ERR_STATUS 0x00000300u /* Enable PCIe Host MSI, INTx DMAx interrupts */ #define PCIE_HOST_INT_ENABLE 0x1F000FFFu /* Enable PCIe local DMAx, DMA error interrupts */ #define PCIE_LOCAL_INT_ENABLE 0x1F0000FFu /****************************************************************************/ /* Clear PCIe interrupt events */ #define PCIE_EVENT_INT_DATA 0x00070007u #define PCIE_ECC_DISABLE 0x0F000000u #define PCIE_SEC_ERROR_INT_CLEAR 0x0000FFFFu #define PCIE_DED_ERROR_INT_CLEAR 0x0000FFFFu #define PCIE_ISTATUS_CLEAR 0xFFFFFFFFu #define PCIE_CLEAR 0x00000000u #define PCIE_SET 0x00000001u #define ROOT_PORT_ENABLE 0x00000001u #define NULL_POINTER ((void *)0) #define MASK_32BIT 0xFFFFFFFFu #define SHIFT_32BIT 32u struct pcie_dma_instance_t { volatile pf_pcie_ep_dma_status_t state; pf_pcie_write_callback_t tx_complete_handler; pf_pcie_read_callback_t rx_complete_handler; }; /* EP dma struct variable */ static struct pcie_dma_instance_t g_pcie_dma; /* RP and EP bridge and controller structure variable */ static PCIE_BRIDGE * g_rp_pcie_bridge = PCIE_CLEAR; static PCIE_BRIDGE * g_ep_bridge_reg = PCIE_CLEAR; static PCIE_CTRL * g_ep_ctrl_reg = PCIE_CLEAR; static PCIE_CTRL * g_rp_pcie_ctrl = PCIE_CLEAR; /* Enumeration and BAR structure variable */ pf_pcie_ebuff_t g_pcie_enumeration; pf_pcie_bar_info_t g_pcie_bar_allocate; /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * * This function is valid only when IP is configured as a root complex. * */ pf_pcie_ebuff_t * PF_PCIE_enumeration ( uint64_t apb_addr, uint8_t pcie_ctrl_num, uint64_t ecam_addr ) { PCIE_BRIDGE * p_pcie_bridge; PCIE_END_CONF * p_pcie_config_space; PCIE_ROOT_CONF * p_pcie_root_config; PCIE_CTRL * p_pcie_ctrl; uint32_t * p_pcie_ep_config_space = PCIE_CLEAR; uint32_t pcie_header_type; uint32_t pcie_multi_fun; uint8_t pcie_bus_num; uint8_t pcie_dev_num; uint8_t pcie_fun_num; uint16_t pcie_vendor_id; uint64_t src_ecam_addr; uint32_t addr_inc; uint32_t p_reg; uint32_t ecam_addr_low; uint32_t ecam_addr_high; /* Default attached bridges and devices are 0 */ uint8_t bridges_attached = PCIE_CLEAR; uint8_t devices_attached = PCIE_CLEAR; uint32_t prim_sec_num = PRIM_SEC_SUB_BUS_DEFAULT; /* Default bridge and device enumeration number is 0 */ g_pcie_enumeration.no_of_bridges_attached = PCIE_CLEAR; g_pcie_enumeration.no_of_devices_attached = PCIE_CLEAR; /* Check PCIe Controller is 0 or 1 */ if (PF_PCIE_CTRL_0 == pcie_ctrl_num) { /* PCIe Bridge Controller 0 */ p_pcie_bridge = ((PCIE_BRIDGE *)((uintptr_t)(apb_addr + PCIE0_BRIDGE_PHY_ADDR_OFFSET))); p_pcie_ctrl = ((PCIE_CTRL *)((uintptr_t)(apb_addr + PCIE0_CRTL_PHY_ADDR_OFFSET))); } else if (PF_PCIE_CTRL_1 == pcie_ctrl_num) { /* PCIe Bridge Controller 1 */ p_pcie_bridge = ((PCIE_BRIDGE *)((uintptr_t)(apb_addr + PCIE1_BRIDGE_PHY_ADDR_OFFSET))); p_pcie_ctrl = ((PCIE_CTRL *)((uintptr_t)(apb_addr + PCIE1_CRTL_PHY_ADDR_OFFSET))); } else { /* Not supports PCIe Bridge Controller */ p_pcie_bridge = PCIE_CLEAR; } /* Check Root Port is enabled or not */ if ((NULL_POINTER != p_pcie_bridge) && (ROOT_PORT_ENABLE == ((p_pcie_bridge->GEN_SETTINGS) & ROOT_PORT_ENABLE))) { g_rp_pcie_bridge = p_pcie_bridge; g_rp_pcie_ctrl = p_pcie_ctrl; /* Clear interrupts on PCIe RootPort */ p_pcie_ctrl->ECC_CONTROL = PCIE_ECC_DISABLE; p_pcie_ctrl->PCIE_EVENT_INT = PCIE_EVENT_INT_DATA; p_pcie_ctrl->SEC_ERROR_INT = PCIE_SEC_ERROR_INT_CLEAR; p_pcie_ctrl->DED_ERROR_INT = PCIE_DED_ERROR_INT_CLEAR; p_pcie_bridge->ISTATUS_LOCAL = PCIE_ISTATUS_CLEAR; p_pcie_bridge->IMASK_LOCAL = PCIE_CLEAR; p_pcie_bridge->ISTATUS_HOST = PCIE_ISTATUS_CLEAR; p_pcie_bridge->IMASK_HOST = PCIE_CLEAR; ecam_addr_low = (uint32_t)(ecam_addr & MASK_32BIT); ecam_addr_high = (uint32_t)((ecam_addr >> SHIFT_32BIT) & MASK_32BIT); /* Select PCIe Config space */ p_pcie_bridge->ATR0_AXI4_SLV0_TRSL_PARAM = PCIE_CONFIG_INTERFACE; /* Address Translation table setup */ p_pcie_bridge->ATR0_AXI4_SLV0_SRCADDR_PARAM = ecam_addr_low | SIZE_256MB_TRANSLATE_TABLE_EN; p_pcie_bridge->ATR0_AXI4_SLV0_SRC_ADDR = ecam_addr_high; p_pcie_bridge->ATR0_AXI4_SLV0_TRSL_ADDR_LSB = ecam_addr_low; p_pcie_bridge->ATR0_AXI4_SLV0_TRSL_ADDR_UDW = ecam_addr_high; /* Enumeration starts here */ for (pcie_bus_num = PCIE_CLEAR; pcie_bus_num < PCIE_CFG_MAX_NUM_OF_BUS; pcie_bus_num++) { for (pcie_dev_num = PCIE_CLEAR; pcie_dev_num < PCIE_CFG_MAX_NUM_OF_DEV; pcie_dev_num++) { for (pcie_fun_num = PCIE_CLEAR; pcie_fun_num < PCIE_CFG_MAX_NUM_OF_FUN; pcie_fun_num++) { /* Calculate ECAM address based on AXI slave base address and bus, device and fun num */ src_ecam_addr = ecam_address_calc(ecam_addr, pcie_bus_num, pcie_dev_num, pcie_fun_num); p_pcie_config_space = (PCIE_END_CONF *)((uintptr_t)src_ecam_addr); /* Read Vendor ID of PCIe RP or EP */ pcie_vendor_id = ((uint16_t)((p_pcie_config_space->VID_DEVID) & VENDOR_ID_MASK)); /* Check Vendor ID is 0xFFFF then no need search */ if (PCIE_CFG_FUN_NOT_IMP_MASK == pcie_vendor_id) { if (PCIE_CLEAR == pcie_fun_num) { /* * don't need to search * further on this device. */ break; } } else { /* Header Type */ pcie_header_type = p_pcie_config_space->BIST_HEADER & PCIE_CFG_HEADER_TYPE_MASK; pcie_multi_fun = p_pcie_config_space->BIST_HEADER & PCIE_CFG_MUL_FUN_DEV_MASK; /* Check header type is type0 for PCIe EndPoint */ if (PCIE_CFG_HEADER_O_TYPE == pcie_header_type) { g_pcie_enumeration.devices[devices_attached].bus_num = pcie_bus_num; g_pcie_enumeration.devices[devices_attached].dev_num = pcie_dev_num; g_pcie_enumeration.devices[devices_attached].fun_num = pcie_fun_num; g_pcie_enumeration.devices[devices_attached].vendor_id = pcie_vendor_id; ++devices_attached; g_pcie_enumeration.no_of_devices_attached = devices_attached; /* Enable config space memory access bus master and cache size */ p_pcie_config_space->CFG_PRMSCR |= (EP_CFG_PRMSCR_DATA); p_pcie_config_space->BIST_HEADER = PCIE_CFG_CATCHE_SIZE; p_pcie_ep_config_space = (uint32_t *)((uintptr_t)src_ecam_addr); /* PCIe configuration header starts after standard size - 0x40/4 = 0x10 */ p_pcie_ep_config_space = p_pcie_ep_config_space + 0x10u; for (addr_inc = PCIE_CLEAR; addr_inc < 48u; ++addr_inc) { /* Read Capability ID 10h for PCI Express Capability structure */ p_reg = *(p_pcie_ep_config_space + addr_inc); if (PCIE_CAPB_ID_STRUCT == (p_reg & PCIE_CAPB_ID_MASK)) { break; } } if (addr_inc < 48u) { /* Device control and status offset */ addr_inc = addr_inc + 2u; /* End Point control and status configure */ *(p_pcie_ep_config_space + addr_inc) = EP_DEVICE_CTRL_STATUS_DATA; } } else { /* Header type is Type1 * This is a bridge or Root Port */ /* Check bus num is '0' for Root Port*/ if (PCIE_CLEAR == pcie_bus_num) { p_pcie_root_config = (PCIE_ROOT_CONF *)((uintptr_t)src_ecam_addr); prim_sec_num |= (uint32_t)(((((uint32_t)pcie_bus_num) + PCIE_SET) << 8u) | pcie_bus_num); /* Sub bus num 0xFF, sec bus num 1, and prime bus num 0 */ p_pcie_root_config->PRIM_SEC_BUS_NUM = prim_sec_num; /* Control & Status Register: enable bus master, * Parity Error Response and SERR# */ p_pcie_root_config->CFG_PRMSCR = RP_CFG_PRMSCR_DATA; /* Non-prefetchable Limit, Non-prefetchable Base */ p_pcie_root_config->MEM_LIMIT_BASE = RP_MEM_LIMIT_BASE_DATA; /* Prefetchable Limit, Prefetchable Base */ p_pcie_root_config->PREF_MEM_LIMIT_BASE = RP_PREF_MEM_LIMIT_BASE_DATA; /* Prefetchable Base upper */ p_pcie_root_config->PREF_BASE_UPPER = RP_PREF_BASE_UPPER_DATA; /* Prefetchable upper limit*/ p_pcie_root_config->PREF_LIMIT_UPPER = RP_PREF_LIMIT_UPPER_DATA; p_pcie_root_config->DEVICE_CTRL_STAT = RP_DEVICE_CTRL_STATUS_DATA; } else { /* The PCIe bridge primary and secondary bus setup */ prim_sec_num |= (uint32_t)(((((uint32_t)pcie_bus_num) + PCIE_SET) << 8u) | pcie_bus_num); p_pcie_root_config = (PCIE_ROOT_CONF *)((uintptr_t)src_ecam_addr); p_pcie_root_config->PRIM_SEC_BUS_NUM = prim_sec_num; p_pcie_root_config->CFG_PRMSCR = RP_CFG_PRMSCR_DATA; } g_pcie_enumeration.bridges[bridges_attached].bus_num = pcie_bus_num; g_pcie_enumeration.bridges[bridges_attached].dev_num = pcie_dev_num; g_pcie_enumeration.bridges[bridges_attached].fun_num = pcie_fun_num; g_pcie_enumeration.bridges[bridges_attached].vendor_id = pcie_vendor_id; ++bridges_attached; g_pcie_enumeration.no_of_bridges_attached = bridges_attached; } if ((PCIE_CLEAR == pcie_fun_num) && (PCIE_CLEAR == pcie_multi_fun)) { /* * If it is function 0 and it is not a * multi function device, don't need * to search further on this device */ break; } } } } } /* Selects PCIe Tx/RxInterface */ p_pcie_bridge->ATR0_AXI4_SLV0_TRSL_PARAM = PCIE_TX_RX_INTERFACE; } return &g_pcie_enumeration; } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ pf_pcie_bar_info_t * PF_PCIE_allocate_memory ( uint64_t ecam_addr, uint64_t allocate_addr ) { PCIE_END_CONF * p_pcie_config_space; uint32_t pcie_header_type; uint64_t axi_trns_base_addr = allocate_addr; uint32_t axi_trns_base_addr_low; uint32_t axi_trns_base_addr_high; uint32_t read_bar, lsb4bits_bar; axi_trns_base_addr_low = (uint32_t)(allocate_addr & MASK_32BIT); axi_trns_base_addr_high = (uint32_t)((allocate_addr >> SHIFT_32BIT) & MASK_32BIT); /* Default BAR and BAR size is 0 */ g_pcie_bar_allocate.bar0_address = PCIE_CLEAR; g_pcie_bar_allocate.bar0_size = PCIE_CLEAR; g_pcie_bar_allocate.bar1_address = PCIE_CLEAR; g_pcie_bar_allocate.bar1_size = PCIE_CLEAR; g_pcie_bar_allocate.bar2_address = PCIE_CLEAR; g_pcie_bar_allocate.bar2_size = PCIE_CLEAR; g_pcie_bar_allocate.bar3_address = PCIE_CLEAR; g_pcie_bar_allocate.bar3_size = PCIE_CLEAR; g_pcie_bar_allocate.bar4_address = PCIE_CLEAR; g_pcie_bar_allocate.bar4_size = PCIE_CLEAR; g_pcie_bar_allocate.bar5_address = PCIE_CLEAR; g_pcie_bar_allocate.bar5_size = PCIE_CLEAR; /* Check PCIe bridge is enabled */ if (NULL_POINTER != g_rp_pcie_bridge) { /* Select PCIe Config space */ g_rp_pcie_bridge->ATR0_AXI4_SLV0_TRSL_PARAM = PCIE_CONFIG_INTERFACE; p_pcie_config_space = (PCIE_END_CONF *)((uintptr_t)ecam_addr); pcie_header_type = PCIE_CLEAR; /* Header Type */ pcie_header_type = p_pcie_config_space->BIST_HEADER & PCIE_CFG_HEADER_TYPE_MASK; /* Write 0xFFFFFFFF to read PCIe BAR0 */ p_pcie_config_space->BAR0 = BAR_MASK; /* Read BAR0 */ read_bar = p_pcie_config_space->BAR0; /* Lower 4-bits of BAR0 */ lsb4bits_bar = read_bar & BAR_LSB_MASK; /* Calculate BAR0 size */ read_bar &= BAR_SIZE_MASK; read_bar = ~(read_bar) + PCIE_SET; if (read_bar != PCIE_CLEAR) { /* Write Translation address in EP BAR0 */ p_pcie_config_space->BAR0 = axi_trns_base_addr_low | lsb4bits_bar; if (ADDR_SPACE_64BIT == (lsb4bits_bar & ADDR_SPACE_64BIT)) { p_pcie_config_space->BAR1 = axi_trns_base_addr_high; g_pcie_bar_allocate.bar1_address = axi_trns_base_addr_high; } g_pcie_bar_allocate.bar0_address = axi_trns_base_addr_low; g_pcie_bar_allocate.bar0_size = read_bar; axi_trns_base_addr = axi_trns_base_addr + read_bar; } /* Check BAR0 is not 64-bit address space */ if (ADDR_SPACE_64BIT != (lsb4bits_bar & ADDR_SPACE_64BIT)) { axi_trns_base_addr_low = (uint32_t)(axi_trns_base_addr & MASK_32BIT); axi_trns_base_addr_high = (uint32_t)((axi_trns_base_addr >> SHIFT_32BIT) & MASK_32BIT); /* Write 0xFFFFFFFF to read PCIe BAR1 */ p_pcie_config_space->BAR1 = BAR_MASK; /* Read BAR1 */ read_bar = p_pcie_config_space->BAR1; lsb4bits_bar = read_bar & BAR_LSB_MASK; /* Calculate BAR1 size */ read_bar &= BAR_SIZE_MASK; read_bar = ~(read_bar) + PCIE_SET; if (read_bar != PCIE_CLEAR) { /* Write Translation address in EP BAR1 */ p_pcie_config_space->BAR1 = axi_trns_base_addr_low | lsb4bits_bar; g_pcie_bar_allocate.bar1_address = axi_trns_base_addr_low; g_pcie_bar_allocate.bar1_size = read_bar; axi_trns_base_addr = axi_trns_base_addr + read_bar; } } if (PCIE_CFG_HEADER_O_TYPE == pcie_header_type) { axi_trns_base_addr_low = (uint32_t)(axi_trns_base_addr & MASK_32BIT); axi_trns_base_addr_high = (uint32_t)((axi_trns_base_addr >> SHIFT_32BIT) & MASK_32BIT); /* Write 0xFFFFFFFF to read PCIe BAR2 */ p_pcie_config_space->BAR2 = BAR_MASK; /* Read BAR2 */ read_bar = p_pcie_config_space->BAR2; lsb4bits_bar = read_bar & BAR_LSB_MASK; /* Calculate BAR2 size */ read_bar &= BAR_SIZE_MASK; read_bar = ~(read_bar) + PCIE_SET; if (read_bar != PCIE_CLEAR) { /* Write Translation address in EP BAR2 */ p_pcie_config_space->BAR2 = axi_trns_base_addr_low | lsb4bits_bar; if (ADDR_SPACE_64BIT == (lsb4bits_bar & ADDR_SPACE_64BIT)) { p_pcie_config_space->BAR3 = axi_trns_base_addr_high; g_pcie_bar_allocate.bar3_address = axi_trns_base_addr_high; } g_pcie_bar_allocate.bar2_address = axi_trns_base_addr_low; g_pcie_bar_allocate.bar2_size = read_bar; axi_trns_base_addr = axi_trns_base_addr + read_bar; } /* Check BAR2 is not 64-bit address space */ if (ADDR_SPACE_64BIT != (lsb4bits_bar & ADDR_SPACE_64BIT)) { axi_trns_base_addr_low = (uint32_t)(axi_trns_base_addr & MASK_32BIT); axi_trns_base_addr_high = (uint32_t)((axi_trns_base_addr >> SHIFT_32BIT) & MASK_32BIT); /* Write 0xFFFFFFFF to read PCIe BAR3 */ p_pcie_config_space->BAR3 = BAR_MASK; /* Read BAR3 */ read_bar = p_pcie_config_space->BAR3; lsb4bits_bar = read_bar & BAR_LSB_MASK; /* Calculate BAR3 size */ read_bar &= BAR_SIZE_MASK; read_bar = ~(read_bar) + PCIE_SET; if (read_bar != PCIE_CLEAR) { /* Write Translation address in EP BAR3 */ p_pcie_config_space->BAR3 = axi_trns_base_addr_low | lsb4bits_bar; g_pcie_bar_allocate.bar3_address = axi_trns_base_addr_low; g_pcie_bar_allocate.bar3_size = read_bar; axi_trns_base_addr = axi_trns_base_addr + read_bar; } } axi_trns_base_addr_low = (uint32_t)(axi_trns_base_addr & MASK_32BIT); axi_trns_base_addr_high = (uint32_t)((axi_trns_base_addr >> SHIFT_32BIT) & MASK_32BIT); /* Write 0xFFFFFFFF to read PCIe BAR4 */ p_pcie_config_space->BAR4 = BAR_MASK; /* Read BAR4 */ read_bar = p_pcie_config_space->BAR4; lsb4bits_bar = read_bar & BAR_LSB_MASK; /* Calculate BAR4 size */ read_bar &= BAR_SIZE_MASK; read_bar = ~(read_bar) + PCIE_SET; if (read_bar != PCIE_CLEAR) { /* Write Translation address in EP BAR4 */ p_pcie_config_space->BAR4 = axi_trns_base_addr_low | lsb4bits_bar; if (ADDR_SPACE_64BIT == (lsb4bits_bar & ADDR_SPACE_64BIT)) { p_pcie_config_space->BAR5 = axi_trns_base_addr_high; g_pcie_bar_allocate.bar5_address = axi_trns_base_addr_high; } g_pcie_bar_allocate.bar4_address = axi_trns_base_addr_low; g_pcie_bar_allocate.bar4_size = read_bar; axi_trns_base_addr = axi_trns_base_addr + read_bar; } /* Check BAR4 is not 64-bit address space */ if (ADDR_SPACE_64BIT != (lsb4bits_bar & ADDR_SPACE_64BIT)) { axi_trns_base_addr_low = (uint32_t)(axi_trns_base_addr & MASK_32BIT); axi_trns_base_addr_high = (uint32_t)((axi_trns_base_addr >> SHIFT_32BIT) & MASK_32BIT); /* Write 0xFFFFFFFF to read PCIe BAR5 */ p_pcie_config_space->BAR5 = BAR_MASK; /* Read BAR5 */ read_bar = p_pcie_config_space->BAR5; lsb4bits_bar = read_bar & BAR_LSB_MASK; /* Calculate BAR5 size */ read_bar &= BAR_SIZE_MASK; read_bar = ~(read_bar) + PCIE_SET; if (read_bar != PCIE_CLEAR) { /* Write Translation address in EP BAR5 */ p_pcie_config_space->BAR5 = axi_trns_base_addr_low | lsb4bits_bar; g_pcie_bar_allocate.bar5_address = axi_trns_base_addr_low; g_pcie_bar_allocate.bar5_size = read_bar; axi_trns_base_addr = axi_trns_base_addr + read_bar; } } } /* Selects PCIe Tx/RxInterface */ g_rp_pcie_bridge->ATR0_AXI4_SLV0_TRSL_PARAM = PCIE_TX_RX_INTERFACE; } return &g_pcie_bar_allocate; } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ void PF_PCIE_enable_config_space_msi ( uint64_t ecam_addr, uint64_t msi_addr, uint16_t msi_data ) { uint32_t * p_pcie_config_space; uint32_t addr_inc; uint32_t p_reg; uint32_t msi_addr_low; uint32_t msi_addr_high; if (NULL_POINTER != g_rp_pcie_bridge) { msi_addr_low = (uint32_t)(msi_addr & MASK_32BIT); msi_addr_high = (uint32_t)((msi_addr >> SHIFT_32BIT) & MASK_32BIT); /* Select PCIe Config space */ g_rp_pcie_bridge->ATR0_AXI4_SLV0_TRSL_PARAM = PCIE_CONFIG_INTERFACE; p_pcie_config_space = (uint32_t *)((uintptr_t)(ecam_addr & PCIE_CONFIG_CAPB_ID_MASK)); /* PCIe configuration header starts after standard size - 0x40/4 = 0x10*/ p_pcie_config_space = p_pcie_config_space + 0x10u; for (addr_inc = PCIE_CLEAR; addr_inc < 48u; ++addr_inc) { /* Read Capability ID 05h for MSI */ p_reg = *(p_pcie_config_space + addr_inc); if (PCIE_CAPB_ID_MSI == (p_reg & PCIE_CAPB_ID_MASK)) { break; } } if (addr_inc < 48u) { p_reg = *(p_pcie_config_space + addr_inc); /* Read number of requested vectors(multiple messages capable) */ p_reg = (p_reg >> PCIE_MSI_MULTI_VECTOR_SHIFT) & PCIE_MSI_MULTI_VECTOR_MASK; /* Numbers of allocated vectors (multiple messages enable) */ p_reg = p_reg << PCIE_MSI_MULTI_ENABLE_SHIFT; /* Enable MSI */ *(p_pcie_config_space + addr_inc) |= (p_reg | PCIE_ENABLE_MSI); p_reg = *(p_pcie_config_space + addr_inc); ++addr_inc; /* MSI message lower address */ *(p_pcie_config_space + addr_inc) = msi_addr_low; ++addr_inc; /* MSI mesage upper address */ if (PCIE_MSI_64BIT_CAPB_ADDR == (p_reg & PCIE_MSI_64BIT_CAPB_ADDR)) { *(p_pcie_config_space + addr_inc) = msi_addr_high; ++addr_inc; } /* MSI message data */ *(p_pcie_config_space + addr_inc) = msi_data; } /* Selects PCIe Tx/RxInterface */ g_rp_pcie_bridge->ATR0_AXI4_SLV0_TRSL_PARAM = PCIE_TX_RX_INTERFACE; } } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * PCIe reads type1 configuration space of pcie bridge or switch. */ void PF_PCIE_type1_header_read ( uint64_t apb_addr, uint8_t pcie_ctrl_num, uint64_t ecam_addr, PCIE_ROOT_CONF * p_type1_header ) { PCIE_BRIDGE * p_pcie_bridge; PCIE_ROOT_CONF * p_pcie_type1_header; uint32_t pcie_header_type; uint32_t ecam_addr_low; uint32_t ecam_addr_high; if (PF_PCIE_CTRL_0 == pcie_ctrl_num) { p_pcie_bridge = ((PCIE_BRIDGE *)((uintptr_t)(apb_addr + PCIE0_BRIDGE_PHY_ADDR_OFFSET))); } else if (PF_PCIE_CTRL_1 == pcie_ctrl_num) { p_pcie_bridge = ((PCIE_BRIDGE *)((uintptr_t)(apb_addr + PCIE1_BRIDGE_PHY_ADDR_OFFSET))); } else { p_pcie_bridge = NULL_POINTER; } /* Check Root Port */ if ((NULL_POINTER != p_pcie_bridge) && (ROOT_PORT_ENABLE == (p_pcie_bridge->GEN_SETTINGS & ROOT_PORT_ENABLE))) { ecam_addr_low = (uint32_t)(ecam_addr & MASK_32BIT); ecam_addr_high = (uint32_t)((ecam_addr >> SHIFT_32BIT) & MASK_32BIT); /* Selects PCIe Config space */ p_pcie_bridge->ATR0_AXI4_SLV0_TRSL_PARAM = PCIE_CONFIG_INTERFACE; p_pcie_bridge->ATR0_AXI4_SLV0_SRCADDR_PARAM = ecam_addr_low | SIZE_256MB_TRANSLATE_TABLE_EN ; p_pcie_bridge->ATR0_AXI4_SLV0_SRC_ADDR = ecam_addr_high; p_pcie_bridge->ATR0_AXI4_SLV0_TRSL_ADDR_LSB = ecam_addr_low; p_pcie_bridge->ATR0_AXI4_SLV0_TRSL_ADDR_UDW = ecam_addr_high; p_pcie_type1_header = (PCIE_ROOT_CONF *)((uintptr_t)ecam_addr); /* Header Type */ pcie_header_type = p_pcie_type1_header->BIST_HEADER & PCIE_CFG_HEADER_TYPE_MASK; if (PCIE_CFG_HEADER_O_TYPE != pcie_header_type) { p_type1_header->VID_DEVID = p_pcie_type1_header->VID_DEVID; p_type1_header->CFG_PRMSCR = p_pcie_type1_header->CFG_PRMSCR; p_type1_header->CLASS_CODE = p_pcie_type1_header->CLASS_CODE; p_type1_header->BIST_HEADER = p_pcie_type1_header->BIST_HEADER; p_type1_header->BAR0 = p_pcie_type1_header->BAR0; p_type1_header->BAR1 = p_pcie_type1_header->BAR1; p_type1_header->PRIM_SEC_BUS_NUM = p_pcie_type1_header->PRIM_SEC_BUS_NUM; p_type1_header->IO_LIMIT_BASE = p_pcie_type1_header->IO_LIMIT_BASE; p_type1_header->MEM_LIMIT_BASE = p_pcie_type1_header->MEM_LIMIT_BASE; p_type1_header->PREF_MEM_LIMIT_BASE = p_pcie_type1_header->PREF_MEM_LIMIT_BASE; p_type1_header->PREF_BASE_UPPER = p_pcie_type1_header->PREF_BASE_UPPER; p_type1_header->PREF_LIMIT_UPPER = p_pcie_type1_header->PREF_LIMIT_UPPER; p_type1_header->IO_LIMIT_BASE_UPPER = p_pcie_type1_header->IO_LIMIT_BASE_UPPER; p_type1_header->CAPAB_POINTER = p_pcie_type1_header->CAPAB_POINTER; p_type1_header->EXPAN_ROM_BASE = p_pcie_type1_header->EXPAN_ROM_BASE; p_type1_header->INT_LINE_PIN = p_pcie_type1_header->INT_LINE_PIN; } /* Selects PCIe Tx/RxInterface */ p_pcie_bridge->ATR0_AXI4_SLV0_TRSL_PARAM = PCIE_TX_RX_INTERFACE; } } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ uint8_t PF_PCIE_config_space_atr_table_init ( uint64_t apb_addr, uint8_t pcie_ctrl_num, uint64_t ecam_addr ) { uint8_t returnval = PF_PCIE_ATR_TABLE_INIT_SUCCESS; uint32_t ecam_addr_low; uint32_t ecam_addr_high; if (NULL_POINTER == g_rp_pcie_bridge) { if (PF_PCIE_CTRL_0 == pcie_ctrl_num) { g_rp_pcie_bridge = ((PCIE_BRIDGE *)((uintptr_t)(apb_addr + PCIE0_BRIDGE_PHY_ADDR_OFFSET))); g_rp_pcie_ctrl = ((PCIE_CTRL *)((uintptr_t)(apb_addr + PCIE0_CRTL_PHY_ADDR_OFFSET))); } else if (PF_PCIE_CTRL_1 == pcie_ctrl_num) { g_rp_pcie_bridge = ((PCIE_BRIDGE *)((uintptr_t)(apb_addr + PCIE1_BRIDGE_PHY_ADDR_OFFSET))); g_rp_pcie_ctrl = ((PCIE_CTRL *)((uintptr_t)(apb_addr + PCIE1_CRTL_PHY_ADDR_OFFSET))); } else { g_rp_pcie_bridge = NULL_POINTER; returnval = PF_PCIE_ATR_TABLE_INIT_FAILURE; } if (NULL_POINTER != g_rp_pcie_bridge) { /* Clear interrupts on PCIe RootPort */ g_rp_pcie_ctrl->ECC_CONTROL = PCIE_ECC_DISABLE; g_rp_pcie_ctrl->PCIE_EVENT_INT = PCIE_EVENT_INT_DATA; g_rp_pcie_ctrl->SEC_ERROR_INT = PCIE_SEC_ERROR_INT_CLEAR; g_rp_pcie_ctrl->DED_ERROR_INT = PCIE_DED_ERROR_INT_CLEAR; g_rp_pcie_bridge->ISTATUS_LOCAL = PCIE_ISTATUS_CLEAR; g_rp_pcie_bridge->IMASK_LOCAL = PCIE_CLEAR; g_rp_pcie_bridge->ISTATUS_HOST = PCIE_ISTATUS_CLEAR; g_rp_pcie_bridge->IMASK_HOST = PCIE_CLEAR; } } if (NULL_POINTER != g_rp_pcie_bridge) { /* Check Root Port */ if (ROOT_PORT_ENABLE == (g_rp_pcie_bridge->GEN_SETTINGS & ROOT_PORT_ENABLE)) { ecam_addr_low = (uint32_t)(ecam_addr & MASK_32BIT); ecam_addr_high = (uint32_t)((ecam_addr >> SHIFT_32BIT) & MASK_32BIT); /* Selects PCIe Config space */ g_rp_pcie_bridge->ATR0_AXI4_SLV0_TRSL_PARAM = PCIE_CONFIG_INTERFACE; g_rp_pcie_bridge->ATR0_AXI4_SLV0_SRCADDR_PARAM = ecam_addr_low | SIZE_256MB_TRANSLATE_TABLE_EN; g_rp_pcie_bridge->ATR0_AXI4_SLV0_SRC_ADDR = ecam_addr_high; g_rp_pcie_bridge->ATR0_AXI4_SLV0_TRSL_ADDR_LSB = ecam_addr_low; g_rp_pcie_bridge->ATR0_AXI4_SLV0_TRSL_ADDR_UDW = ecam_addr_high; } else { returnval = PF_PCIE_ATR_TABLE_INIT_FAILURE; } } return returnval; } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ void PF_PCIE_config_space_atr_table_terminate(void) { if (NULL_POINTER != g_rp_pcie_bridge) { /* Selects PCIe Tx/Rx Interface, disable PCIe Config space */ g_rp_pcie_bridge->ATR0_AXI4_SLV0_TRSL_PARAM = PCIE_TX_RX_INTERFACE; } } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * PCIe reads configuration space of end point or root port. */ void PF_PCIE_config_space_read ( uint64_t ecam_addr, uint16_t config_space_offset, uint32_t * value ) { volatile uint32_t * cfg_reg = (uint32_t *)((uintptr_t)(ecam_addr + config_space_offset)); *value = *(cfg_reg); } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * PCIe writes configuration space of end point or root port. */ void PF_PCIE_config_space_write ( uint64_t ecam_addr, uint16_t config_space_offset, uint32_t value ) { volatile uint32_t * cfg_reg = (uint32_t *)((uintptr_t)(ecam_addr + config_space_offset)); *(cfg_reg) = value; } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ uint8_t PF_PCIE_master_atr_table_init ( uint64_t apb_addr, uint8_t pcie_ctrl_num, pf_pcie_master_atr_cfg_t * cfg, uint8_t master_table_num, uint8_t tlp_type ) { uint32_t * p_pcie_master_table; uint32_t * p_pcie_bar; PCIE_BRIDGE * p_pcie_bridge; uint32_t phy_reg; uint8_t returnval = PF_PCIE_ATR_TABLE_INIT_SUCCESS; /* Set pcie bridge base address for ATR master table based on pcie controller 0/1 */ if (PF_PCIE_CTRL_0 == pcie_ctrl_num) { p_pcie_bridge = ((PCIE_BRIDGE *)((uintptr_t)(apb_addr + PCIE0_BRIDGE_PHY_ADDR_OFFSET))); p_pcie_master_table = ((uint32_t *)((uintptr_t)(apb_addr + PCIE0_BRIDGE_PHY_ADDR_OFFSET + ATR0_PCIE_WIN0_OFFSET + (master_table_num * ATR_WIN_REG_TABLE_SIZE)))); if (cfg->bar_type == PF_PCIE_BAR_TYPE_64BIT_PREFET_MEM) { p_pcie_bar = ((uint32_t *)((uintptr_t)(apb_addr + PCIE0_BRIDGE_PHY_ADDR_OFFSET + BAR_01_DW0 + (master_table_num * 8u)))); } else { p_pcie_bar = ((uint32_t *)((uintptr_t)(apb_addr + PCIE0_BRIDGE_PHY_ADDR_OFFSET + BAR_01_DW0 + (master_table_num * 4u)))); } } else if (PF_PCIE_CTRL_1 == pcie_ctrl_num) { p_pcie_bridge = ((PCIE_BRIDGE *)((uintptr_t)(apb_addr + PCIE1_BRIDGE_PHY_ADDR_OFFSET))); p_pcie_master_table = ((uint32_t *)((uintptr_t)(apb_addr + PCIE1_BRIDGE_PHY_ADDR_OFFSET + ATR0_PCIE_WIN0_OFFSET + (master_table_num * ATR_WIN_REG_TABLE_SIZE)))); if (cfg->bar_type == PF_PCIE_BAR_TYPE_64BIT_PREFET_MEM) { p_pcie_bar = ((uint32_t *)((uintptr_t)(apb_addr + PCIE1_BRIDGE_PHY_ADDR_OFFSET + BAR_01_DW0 + (master_table_num * 8u)))); } else { p_pcie_bar = ((uint32_t *)((uintptr_t)(apb_addr + PCIE1_BRIDGE_PHY_ADDR_OFFSET + BAR_01_DW0 + (master_table_num * 4u)))); } } else { p_pcie_bridge = NULL_POINTER; } /* Check for pcie bridge controller base address */ if (NULL_POINTER != p_pcie_bridge) { /* Check for PCIe Root Port */ if (ROOT_PORT_ENABLE == (p_pcie_bridge->GEN_SETTINGS & ROOT_PORT_ENABLE)) { if (master_table_num < 2u) { /* Write BAR_01 or BAR_23 size and bar type */ phy_reg = ~((1u << (cfg->bar_size + 1u)) -1u); *p_pcie_bar = (phy_reg | cfg->bar_type); if (cfg->bar_type == PF_PCIE_BAR_TYPE_64BIT_PREFET_MEM) { /* Bar size mask in BAR_01/23_DW1 [64:32] bit */ *(p_pcie_bar + 1u) = BAR_MASK; } } else { returnval = PF_PCIE_ATR_TABLE_INIT_FAILURE; } } else /* End Point */ { if (master_table_num < 6u) { /* Write BAR_01 or BAR_23 or BAR_45 size and bar type */ phy_reg = ~((1u << (cfg->bar_size + 1u)) -1u); *p_pcie_bar = (phy_reg | cfg->bar_type); if (cfg->bar_type == PF_PCIE_BAR_TYPE_64BIT_PREFET_MEM) { /* Bar size mask in BAR_01/23/45_DW1 [64:32] bit */ *(p_pcie_bar + 1u) = BAR_MASK; } } else { returnval = PF_PCIE_ATR_TABLE_INIT_FAILURE; } } if (PF_PCIE_ATR_TABLE_INIT_SUCCESS == returnval) { phy_reg = (uint32_t)(cfg->src_addr & ATR_ADDR_MASK); phy_reg |= (uint32_t)((cfg->table_size) << PCIE_SET); phy_reg |= (uint32_t)(cfg->state); /* Set ATR Master SRC LSB address */ *(p_pcie_master_table + WIN0_SRCADDR_PARAM) = phy_reg; /* Set ATR Master SRC MSB address */ *(p_pcie_master_table + WIN0_SRC_ADDR) = (cfg->src_addr_msb); /* Set ATR Master TRNSL LSB address */ *(p_pcie_master_table + WIN0_TRSL_ADDR_LSB) = (cfg->trns_addr & ATR_ADDR_MASK); /* Set ATR Master TRNSL MSB address */ *(p_pcie_master_table + WIN0_TRSL_ADDR_UDW) = (cfg->trns_addr_msb); /* Set TLP type and TRSL_ID value */ *(p_pcie_master_table + WIN0_TRSL_PARAM) = ((uint32_t)tlp_type << TLP_SHIFT) | AXI4_MASTER_0_INTERFACE; } } else { returnval = PF_PCIE_ATR_TABLE_INIT_FAILURE; } return returnval; } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ uint8_t PF_PCIE_slave_atr_table_init ( uint64_t apb_addr, uint8_t pcie_ctrl_num, pf_pcie_slave_atr_cfg_t * cfg, uint8_t slave_table_num, uint8_t tlp_type ) { uint32_t * p_pcie_slave; uint32_t phy_reg = PCIE_CLEAR; uint8_t returnval = PF_PCIE_ATR_TABLE_INIT_SUCCESS; /* Set pcie bridge base address for ATR slave table based on pcie controlle 0/1 */ if (PF_PCIE_CTRL_0 == pcie_ctrl_num) { p_pcie_slave = ((uint32_t * )((uintptr_t)(apb_addr + PCIE0_BRIDGE_PHY_ADDR_OFFSET + ATR0_AXI4_SLV0_OFFSET + (slave_table_num * ATR_SLV_REG_TABLE_SIZE)))); } else if (PF_PCIE_CTRL_1 == pcie_ctrl_num) { p_pcie_slave = ((uint32_t * )((uintptr_t)(apb_addr + PCIE1_BRIDGE_PHY_ADDR_OFFSET + ATR0_AXI4_SLV0_OFFSET + (slave_table_num * ATR_SLV_REG_TABLE_SIZE)))); } else { p_pcie_slave = NULL_POINTER; } /* Check for pcie bridge controller base address */ if (NULL_POINTER != p_pcie_slave) { phy_reg = (uint32_t)(cfg->src_addr & ATR_ADDR_MASK); phy_reg |= (uint32_t)((cfg->size) << PCIE_SET); phy_reg |= (uint32_t)(cfg->state); /* Set ATR slave SRC LSB address */ *(p_pcie_slave + SLV0_SRCADDR_PARAM) = phy_reg; /* Set ATR slave SRC MSB address */ *(p_pcie_slave + SLV0_SRC_ADDR) = (cfg->src_addr_msb); /* Set ATR slave TRNSL LSB address */ phy_reg = (cfg->trns_addr & ATR_ADDR_MASK); *(p_pcie_slave + SLV0_TRSL_ADDR_LSB) = phy_reg; /* Set ATR slave TRNSL LSB address */ *(p_pcie_slave + SLV0_TRSL_ADDR_UDW) = (cfg->trns_addr_msb); /* Set TLP type */ *(p_pcie_slave + SLV0_TRSL_PARAM) = ((uint32_t)tlp_type << TLP_SHIFT) | PCIE_TX_RX_INTERFACE; } else { returnval = PF_PCIE_ATR_TABLE_INIT_FAILURE; } return returnval; } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ void PF_PCIE_dma_init(uint64_t allocated_addr) { g_ep_bridge_reg = (PCIE_BRIDGE *)((uintptr_t)allocated_addr); g_ep_ctrl_reg = (PCIE_CTRL *)((uintptr_t)(allocated_addr + 0x2000u)); /* Disable EP ECC interrupts and clear status bits */ g_ep_ctrl_reg->ECC_CONTROL = PCIE_ECC_DISABLE; g_ep_ctrl_reg->PCIE_EVENT_INT = PCIE_EVENT_INT_DATA; g_ep_ctrl_reg->SEC_ERROR_INT = PCIE_SEC_ERROR_INT_CLEAR; g_ep_ctrl_reg->DED_ERROR_INT = PCIE_DED_ERROR_INT_CLEAR; /* Disable and clear Local and Host interrupts on EP */ g_ep_bridge_reg->IMASK_LOCAL = PCIE_CLEAR; g_ep_bridge_reg->ISTATUS_LOCAL = PCIE_ISTATUS_CLEAR; g_ep_bridge_reg->IMASK_HOST = PCIE_CLEAR; g_ep_bridge_reg->ISTATUS_HOST = PCIE_ISTATUS_CLEAR; /* Enable PCIe Host MSI, INTx DMAx interrupts on EP */ g_ep_bridge_reg->IMASK_HOST= PCIE_HOST_INT_ENABLE; g_ep_bridge_reg->ISTATUS_HOST = PCIE_ISTATUS_CLEAR; /* initialize default interrupt handlers */ g_pcie_dma.tx_complete_handler = NULL_POINTER; g_pcie_dma.rx_complete_handler = NULL_POINTER; g_pcie_dma.state = PF_PCIE_EP_DMA_COMPLETED; } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ void PF_PCIE_set_dma_write_callback ( pf_pcie_write_callback_t write_callback ) { g_pcie_dma.tx_complete_handler = write_callback; } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ void PF_PCIE_set_dma_read_callback ( pf_pcie_read_callback_t rx_callback ) { g_pcie_dma.rx_complete_handler = rx_callback; } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ void PF_PCIE_dma_abort(void) { if(NULL_POINTER != g_ep_bridge_reg) { g_ep_bridge_reg->DMA0_CONTROL = PCIE_CLEAR; g_ep_bridge_reg->DMA1_CONTROL = PCIE_CLEAR; } g_pcie_dma.state = PF_PCIE_EP_DMA_COMPLETED; } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ void PF_PCIE_dma_read ( uint64_t src_address, uint64_t dest_address, uint32_t rx_lenth ) { /* Check EP bridge access enabled with DMA */ if (NULL_POINTER != g_ep_bridge_reg) { if ((PF_PCIE_EP_DMA_IN_PROGRESS != g_pcie_dma.state) && (rx_lenth > 0u)) { g_ep_bridge_reg->DMA1_CONTROL = PCIE_CLEAR; /* DMA from EP to RP - source EP AXI-Master, destination PCIe - DMA1 */ /* AXI4-Master Interface for Source*/ g_ep_bridge_reg->DMA1_SRC_PARAM = EP_DMA_INTERFACE_AXI; /* PCIe Interface for Destination */ g_ep_bridge_reg->DMA1_DESTPARAM = EP_DMA_INTERFACE_PCIE; /* Set source address */ g_ep_bridge_reg->DMA1_SRCADDR_LDW = (uint32_t)(src_address & MASK_32BIT); g_ep_bridge_reg->DMA1_SRCADDR_UDW = (uint32_t)((src_address >> SHIFT_32BIT) & MASK_32BIT); /* Set destination address*/ g_ep_bridge_reg->DMA1_DESTADDR_LDW = (uint32_t)(dest_address & MASK_32BIT); g_ep_bridge_reg->DMA1_DESTADDR_UDW = (uint32_t)((dest_address >> SHIFT_32BIT) & MASK_32BIT); /* Set dma size */ g_ep_bridge_reg->DMA1_LENGTH = rx_lenth; /*Start dma transaction */ g_ep_bridge_reg->DMA1_CONTROL = EP_DMA_START_DATA; g_pcie_dma.state = PF_PCIE_EP_DMA_IN_PROGRESS; } } else { g_pcie_dma.state = PF_PCIE_EP_DMA_NOT_INITIALIZED; } } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ void PF_PCIE_dma_write ( uint64_t src_address, uint64_t dest_address, uint32_t tx_lenth ) { /* Check EP bridge access enabled with DMA */ if (NULL_POINTER != g_ep_bridge_reg) { if ((PF_PCIE_EP_DMA_IN_PROGRESS != g_pcie_dma.state) && (tx_lenth > 0u)) { g_ep_bridge_reg->DMA0_CONTROL = PCIE_CLEAR; /* DMA from RP to EP - source RP-PCIe, destination AXI-Master - DMA0 */ /* PCIe Interface for Source */ g_ep_bridge_reg->DMA0_SRC_PARAM = EP_DMA_INTERFACE_PCIE; /*AXI4-Master Interface for Destination*/ g_ep_bridge_reg->DMA0_DESTPARAM = EP_DMA_INTERFACE_AXI; /* Set source address */ g_ep_bridge_reg->DMA0_SRCADDR_LDW = (uint32_t)(src_address & MASK_32BIT); g_ep_bridge_reg->DMA0_SRCADDR_UDW = (uint32_t)((src_address >> SHIFT_32BIT) & MASK_32BIT); /* Set destination address*/ g_ep_bridge_reg->DMA0_DESTADDR_LDW = (uint32_t)(dest_address & MASK_32BIT); g_ep_bridge_reg->DMA0_DESTADDR_UDW = (uint32_t)((dest_address >> SHIFT_32BIT) & MASK_32BIT); /* Set dma size */ g_ep_bridge_reg->DMA0_LENGTH = tx_lenth; /*Start dma transaction */ g_ep_bridge_reg->DMA0_CONTROL = EP_DMA_START_DATA; g_pcie_dma.state = PF_PCIE_EP_DMA_IN_PROGRESS; } } else { g_pcie_dma.state = PF_PCIE_EP_DMA_NOT_INITIALIZED; } } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ pf_pcie_ep_dma_status_t PF_PCIE_dma_get_transfer_status ( void ) { return g_pcie_dma.state; } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ void PF_PCIE_enable_interrupts(void) { /* Check RP bridge access enabled */ if (NULL_POINTER != g_rp_pcie_bridge) { g_rp_pcie_bridge->IMASK_LOCAL = PCIE_LOCAL_INT_ENABLE; g_rp_pcie_bridge->ISTATUS_LOCAL = PCIE_ISTATUS_CLEAR; g_rp_pcie_bridge->ISTATUS_MSI = PCIE_ISTATUS_CLEAR; } } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ void PF_PCIE_disable_interrupts(void) { /* Check RP bridge access enabled */ if (NULL_POINTER != g_rp_pcie_bridge) { g_rp_pcie_bridge->ISTATUS_LOCAL = PCIE_ISTATUS_CLEAR; g_rp_pcie_bridge->IMASK_LOCAL= PCIE_CLEAR; } } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ void PF_PCIE_isr(void) { uint32_t phy_reg; /* Check RP bridge access enabled */ if (NULL_POINTER != g_rp_pcie_bridge) { phy_reg = g_rp_pcie_bridge->ISTATUS_LOCAL; phy_reg = g_rp_pcie_bridge->ISTATUS_MSI; /* Check EP bridge access enabled with DMA */ if (NULL_POINTER != g_ep_bridge_reg) { phy_reg = g_ep_bridge_reg->ISTATUS_HOST; /* Check EP DMA0/1 interrupt occurred */ if (PCIE_CLEAR != (phy_reg & DMA_INT_STATUS)) { g_ep_bridge_reg->ISTATUS_HOST = DMA_INT_STATUS; g_pcie_dma.state = PF_PCIE_EP_DMA_COMPLETED; if (NULL_POINTER != g_pcie_dma.tx_complete_handler) { g_pcie_dma.tx_complete_handler(PF_PCIE_EP_DMA_COMPLETED); } } else if (PCIE_CLEAR != (phy_reg & DMA_ERR_STATUS)) { g_ep_bridge_reg->ISTATUS_HOST = DMA_ERR_STATUS; g_pcie_dma.state = PF_PCIE_EP_DMA_ERROR; if (NULL_POINTER != g_pcie_dma.rx_complete_handler) { g_pcie_dma.rx_complete_handler(PF_PCIE_EP_DMA_ERROR); } } else { g_ep_bridge_reg->ISTATUS_HOST = PCIE_ISTATUS_CLEAR; } } g_rp_pcie_bridge->ISTATUS_MSI = PCIE_ISTATUS_CLEAR; g_rp_pcie_bridge->ISTATUS_LOCAL = PCIE_ISTATUS_CLEAR; } } /**************************************************************************** Compose an address to be written to configuration address port @param Bus is the external PCIe function's Bus number. @param Device is the external PCIe function's Device number. @param Function is the external PCIe function's Function number. @return 32 bit composed value (address). */ uint64_t ecam_address_calc ( uint64_t axi_addr, uint8_t bus, uint8_t device, uint8_t function ) { uint64_t location = PCIE_CLEAR; location |= ((((uint64_t)bus) << PCIE_ECAM_BUS_SHIFT) & PCIE_ECAM_BUS_MASK); location |= ((((uint64_t)device) << PCIE_ECAM_DEV_SHIFT) & PCIE_ECAM_DEV_MASK); location |= ((((uint64_t)function) << PCIE_ECAM_FUN_SHIFT) & PCIE_ECAM_FUN_MASK); location &= PCIE_ECAM_MASK; axi_addr = axi_addr + location; return axi_addr; } #ifdef __cplusplus } #endif