diff options
Diffstat (limited to 'drivers/pci/pcie_intel_fpga.c')
-rw-r--r-- | drivers/pci/pcie_intel_fpga.c | 434 |
1 files changed, 0 insertions, 434 deletions
diff --git a/drivers/pci/pcie_intel_fpga.c b/drivers/pci/pcie_intel_fpga.c deleted file mode 100644 index 959fd369086..00000000000 --- a/drivers/pci/pcie_intel_fpga.c +++ /dev/null @@ -1,434 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Intel FPGA PCIe host controller driver - * - * Copyright (C) 2013-2018 Intel Corporation. All rights reserved - * - */ - -#include <dm.h> -#include <pci.h> -#include <asm/global_data.h> -#include <asm/io.h> -#include <dm/device_compat.h> -#include <linux/bitops.h> -#include <linux/delay.h> - -#define RP_TX_REG0 0x2000 -#define RP_TX_CNTRL 0x2004 -#define RP_TX_SOP BIT(0) -#define RP_TX_EOP BIT(1) -#define RP_RXCPL_STATUS 0x200C -#define RP_RXCPL_SOP BIT(0) -#define RP_RXCPL_EOP BIT(1) -#define RP_RXCPL_REG 0x2008 -#define P2A_INT_STATUS 0x3060 -#define P2A_INT_STS_ALL 0xf -#define P2A_INT_ENABLE 0x3070 -#define RP_CAP_OFFSET 0x70 - -/* TLP configuration type 0 and 1 */ -#define TLP_FMTTYPE_CFGRD0 0x04 /* Configuration Read Type 0 */ -#define TLP_FMTTYPE_CFGWR0 0x44 /* Configuration Write Type 0 */ -#define TLP_FMTTYPE_CFGRD1 0x05 /* Configuration Read Type 1 */ -#define TLP_FMTTYPE_CFGWR1 0x45 /* Configuration Write Type 1 */ -#define TLP_PAYLOAD_SIZE 0x01 -#define TLP_READ_TAG 0x1d -#define TLP_WRITE_TAG 0x10 -#define RP_DEVFN 0 - -#define RP_CFG_ADDR(pcie, reg) \ - ((pcie->hip_base) + (reg) + (1 << 20)) -#define RP_SECONDARY(pcie) \ - readb(RP_CFG_ADDR(pcie, PCI_SECONDARY_BUS)) -#define TLP_REQ_ID(bus, devfn) (((bus) << 8) | (devfn)) - -#define TLP_CFGRD_DW0(pcie, bus) \ - ((((bus > RP_SECONDARY(pcie)) ? TLP_FMTTYPE_CFGRD1 \ - : TLP_FMTTYPE_CFGRD0) << 24) | \ - TLP_PAYLOAD_SIZE) - -#define TLP_CFGWR_DW0(pcie, bus) \ - ((((bus > RP_SECONDARY(pcie)) ? TLP_FMTTYPE_CFGWR1 \ - : TLP_FMTTYPE_CFGWR0) << 24) | \ - TLP_PAYLOAD_SIZE) - -#define TLP_CFG_DW1(pcie, tag, be) \ - (((TLP_REQ_ID(pcie->first_busno, RP_DEVFN)) << 16) | (tag << 8) | (be)) -#define TLP_CFG_DW2(bus, dev, fn, offset) \ - (((bus) << 24) | ((dev) << 19) | ((fn) << 16) | (offset)) - -#define TLP_COMP_STATUS(s) (((s) >> 13) & 7) -#define TLP_BYTE_COUNT(s) (((s) >> 0) & 0xfff) -#define TLP_HDR_SIZE 3 -#define TLP_LOOP 20000 -#define DWORD_MASK 3 - -#define IS_ROOT_PORT(pcie, bdf) \ - ((PCI_BUS(bdf) == pcie->first_busno) ? true : false) - -/** - * struct intel_fpga_pcie - Intel FPGA PCIe controller state - * @bus: Pointer to the PCI bus - * @cra_base: The base address of CRA register space - * @hip_base: The base address of Rootport configuration space - * @first_busno: This driver supports multiple PCIe controllers. - * first_busno stores the bus number of the PCIe root-port - * number which may vary depending on the PCIe setup. - */ -struct intel_fpga_pcie { - struct udevice *bus; - void __iomem *cra_base; - void __iomem *hip_base; - int first_busno; -}; - -/** - * Intel FPGA PCIe port uses BAR0 of RC's configuration space as the - * translation from PCI bus to native BUS. Entire DDR region is mapped - * into PCIe space using these registers, so it can be reached by DMA from - * EP devices. - * The BAR0 of bridge should be hidden during enumeration to avoid the - * sizing and resource allocation by PCIe core. - */ -static bool intel_fpga_pcie_hide_rc_bar(struct intel_fpga_pcie *pcie, - pci_dev_t bdf, int offset) -{ - if (IS_ROOT_PORT(pcie, bdf) && PCI_DEV(bdf) == 0 && - PCI_FUNC(bdf) == 0 && offset == PCI_BASE_ADDRESS_0) - return true; - - return false; -} - -static inline void cra_writel(struct intel_fpga_pcie *pcie, const u32 value, - const u32 reg) -{ - writel(value, pcie->cra_base + reg); -} - -static inline u32 cra_readl(struct intel_fpga_pcie *pcie, const u32 reg) -{ - return readl(pcie->cra_base + reg); -} - -static bool intel_fpga_pcie_link_up(struct intel_fpga_pcie *pcie) -{ - return !!(readw(RP_CFG_ADDR(pcie, RP_CAP_OFFSET + PCI_EXP_LNKSTA)) - & PCI_EXP_LNKSTA_DLLLA); -} - -static bool intel_fpga_pcie_addr_valid(struct intel_fpga_pcie *pcie, - pci_dev_t bdf) -{ - /* If there is no link, then there is no device */ - if (!IS_ROOT_PORT(pcie, bdf) && !intel_fpga_pcie_link_up(pcie)) - return false; - - /* access only one slot on each root port */ - if (IS_ROOT_PORT(pcie, bdf) && PCI_DEV(bdf) > 0) - return false; - - if ((PCI_BUS(bdf) == pcie->first_busno + 1) && PCI_DEV(bdf) > 0) - return false; - - return true; -} - -static void tlp_write_tx(struct intel_fpga_pcie *pcie, u32 reg0, u32 ctrl) -{ - cra_writel(pcie, reg0, RP_TX_REG0); - cra_writel(pcie, ctrl, RP_TX_CNTRL); -} - -static int tlp_read_packet(struct intel_fpga_pcie *pcie, u32 *value) -{ - int i; - u32 ctrl; - u32 comp_status; - u32 dw[4]; - u32 count = 0; - - for (i = 0; i < TLP_LOOP; i++) { - ctrl = cra_readl(pcie, RP_RXCPL_STATUS); - if (!(ctrl & RP_RXCPL_SOP)) - continue; - - /* read first DW */ - dw[count++] = cra_readl(pcie, RP_RXCPL_REG); - - /* Poll for EOP */ - for (i = 0; i < TLP_LOOP; i++) { - ctrl = cra_readl(pcie, RP_RXCPL_STATUS); - dw[count++] = cra_readl(pcie, RP_RXCPL_REG); - if (ctrl & RP_RXCPL_EOP) { - comp_status = TLP_COMP_STATUS(dw[1]); - if (comp_status) { - *value = pci_get_ff(PCI_SIZE_32); - return 0; - } - - if (value && - TLP_BYTE_COUNT(dw[1]) == sizeof(u32) && - count >= 3) - *value = dw[3]; - - return 0; - } - } - - udelay(5); - } - - dev_err(pcie->dev, "read TLP packet timed out\n"); - return -ENODEV; -} - -static void tlp_write_packet(struct intel_fpga_pcie *pcie, u32 *headers, - u32 data) -{ - tlp_write_tx(pcie, headers[0], RP_TX_SOP); - - tlp_write_tx(pcie, headers[1], 0); - - tlp_write_tx(pcie, headers[2], 0); - - tlp_write_tx(pcie, data, RP_TX_EOP); -} - -static int tlp_cfg_dword_read(struct intel_fpga_pcie *pcie, pci_dev_t bdf, - int offset, u8 byte_en, u32 *value) -{ - u32 headers[TLP_HDR_SIZE]; - u8 busno = PCI_BUS(bdf); - - headers[0] = TLP_CFGRD_DW0(pcie, busno); - headers[1] = TLP_CFG_DW1(pcie, TLP_READ_TAG, byte_en); - headers[2] = TLP_CFG_DW2(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset); - - tlp_write_packet(pcie, headers, 0); - - return tlp_read_packet(pcie, value); -} - -static int tlp_cfg_dword_write(struct intel_fpga_pcie *pcie, pci_dev_t bdf, - int offset, u8 byte_en, u32 value) -{ - u32 headers[TLP_HDR_SIZE]; - u8 busno = PCI_BUS(bdf); - - headers[0] = TLP_CFGWR_DW0(pcie, busno); - headers[1] = TLP_CFG_DW1(pcie, TLP_WRITE_TAG, byte_en); - headers[2] = TLP_CFG_DW2(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset); - - tlp_write_packet(pcie, headers, value); - - return tlp_read_packet(pcie, NULL); -} - -int intel_fpga_rp_conf_addr(const struct udevice *bus, pci_dev_t bdf, - uint offset, void **paddress) -{ - struct intel_fpga_pcie *pcie = dev_get_priv(bus); - - *paddress = RP_CFG_ADDR(pcie, offset); - - return 0; -} - -static int intel_fpga_pcie_rp_rd_conf(struct udevice *bus, pci_dev_t bdf, - uint offset, ulong *valuep, - enum pci_size_t size) -{ - return pci_generic_mmap_read_config(bus, intel_fpga_rp_conf_addr, - bdf, offset, valuep, size); -} - -static int intel_fpga_pcie_rp_wr_conf(struct udevice *bus, pci_dev_t bdf, - uint offset, ulong value, - enum pci_size_t size) -{ - int ret; - struct intel_fpga_pcie *pcie = dev_get_priv(bus); - - ret = pci_generic_mmap_write_config(bus, intel_fpga_rp_conf_addr, - bdf, offset, value, size); - if (!ret) { - /* Monitor changes to PCI_PRIMARY_BUS register on root port - * and update local copy of root bus number accordingly. - */ - if (offset == PCI_PRIMARY_BUS) - pcie->first_busno = (u8)(value); - } - - return ret; -} - -static u8 pcie_get_byte_en(uint offset, enum pci_size_t size) -{ - switch (size) { - case PCI_SIZE_8: - return 1 << (offset & 3); - case PCI_SIZE_16: - return 3 << (offset & 3); - default: - return 0xf; - } -} - -static int _pcie_intel_fpga_read_config(struct intel_fpga_pcie *pcie, - pci_dev_t bdf, uint offset, - ulong *valuep, enum pci_size_t size) -{ - int ret; - u32 data; - u8 byte_en; - - /* Uses memory mapped method to read rootport config registers */ - if (IS_ROOT_PORT(pcie, bdf)) - return intel_fpga_pcie_rp_rd_conf(pcie->bus, bdf, - offset, valuep, size); - - byte_en = pcie_get_byte_en(offset, size); - ret = tlp_cfg_dword_read(pcie, bdf, offset & ~DWORD_MASK, - byte_en, &data); - if (ret) - return ret; - - dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08x)\n", - offset, size, data); - *valuep = pci_conv_32_to_size(data, offset, size); - - return 0; -} - -static int _pcie_intel_fpga_write_config(struct intel_fpga_pcie *pcie, - pci_dev_t bdf, uint offset, - ulong value, enum pci_size_t size) -{ - u32 data; - u8 byte_en; - - dev_dbg(pcie->dev, "PCIE CFG write: (b.d.f)=(%02d.%02d.%02d)\n", - PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); - dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08lx)\n", - offset, size, value); - - /* Uses memory mapped method to read rootport config registers */ - if (IS_ROOT_PORT(pcie, bdf)) - return intel_fpga_pcie_rp_wr_conf(pcie->bus, bdf, offset, - value, size); - - byte_en = pcie_get_byte_en(offset, size); - data = pci_conv_size_to_32(0, value, offset, size); - - return tlp_cfg_dword_write(pcie, bdf, offset & ~DWORD_MASK, - byte_en, data); -} - -static int pcie_intel_fpga_read_config(const struct udevice *bus, pci_dev_t bdf, - uint offset, ulong *valuep, - enum pci_size_t size) -{ - struct intel_fpga_pcie *pcie = dev_get_priv(bus); - - dev_dbg(pcie->dev, "PCIE CFG read: (b.d.f)=(%02d.%02d.%02d)\n", - PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); - - if (intel_fpga_pcie_hide_rc_bar(pcie, bdf, offset)) { - *valuep = (u32)pci_get_ff(size); - return 0; - } - - if (!intel_fpga_pcie_addr_valid(pcie, bdf)) { - *valuep = (u32)pci_get_ff(size); - return 0; - } - - return _pcie_intel_fpga_read_config(pcie, bdf, offset, valuep, size); -} - -static int pcie_intel_fpga_write_config(struct udevice *bus, pci_dev_t bdf, - uint offset, ulong value, - enum pci_size_t size) -{ - struct intel_fpga_pcie *pcie = dev_get_priv(bus); - - if (intel_fpga_pcie_hide_rc_bar(pcie, bdf, offset)) - return 0; - - if (!intel_fpga_pcie_addr_valid(pcie, bdf)) - return 0; - - return _pcie_intel_fpga_write_config(pcie, bdf, offset, value, - size); -} - -static int pcie_intel_fpga_probe(struct udevice *dev) -{ - struct intel_fpga_pcie *pcie = dev_get_priv(dev); - - pcie->bus = pci_get_controller(dev); - pcie->first_busno = dev_seq(dev); - - /* clear all interrupts */ - cra_writel(pcie, P2A_INT_STS_ALL, P2A_INT_STATUS); - /* disable all interrupts */ - cra_writel(pcie, 0, P2A_INT_ENABLE); - - return 0; -} - -static int pcie_intel_fpga_of_to_plat(struct udevice *dev) -{ - struct intel_fpga_pcie *pcie = dev_get_priv(dev); - struct fdt_resource reg_res; - int node = dev_of_offset(dev); - int ret; - - DECLARE_GLOBAL_DATA_PTR; - - ret = fdt_get_named_resource(gd->fdt_blob, node, "reg", "reg-names", - "Cra", ®_res); - if (ret) { - dev_err(dev, "resource \"Cra\" not found\n"); - return ret; - } - - pcie->cra_base = map_physmem(reg_res.start, - fdt_resource_size(®_res), - MAP_NOCACHE); - - ret = fdt_get_named_resource(gd->fdt_blob, node, "reg", "reg-names", - "Hip", ®_res); - if (ret) { - dev_err(dev, "resource \"Hip\" not found\n"); - return ret; - } - - pcie->hip_base = map_physmem(reg_res.start, - fdt_resource_size(®_res), - MAP_NOCACHE); - - return 0; -} - -static const struct dm_pci_ops pcie_intel_fpga_ops = { - .read_config = pcie_intel_fpga_read_config, - .write_config = pcie_intel_fpga_write_config, -}; - -static const struct udevice_id pcie_intel_fpga_ids[] = { - { .compatible = "altr,pcie-root-port-2.0" }, - {}, -}; - -U_BOOT_DRIVER(pcie_intel_fpga) = { - .name = "pcie_intel_fpga", - .id = UCLASS_PCI, - .of_match = pcie_intel_fpga_ids, - .ops = &pcie_intel_fpga_ops, - .of_to_plat = pcie_intel_fpga_of_to_plat, - .probe = pcie_intel_fpga_probe, - .priv_auto = sizeof(struct intel_fpga_pcie), -}; |