diff options
author | Minghuan Lian <Minghuan.Lian@freescale.com> | 2015-07-10 11:35:09 +0800 |
---|---|---|
committer | York Sun <yorksun@freescale.com> | 2015-08-03 12:06:38 -0700 |
commit | 01cafcedbfbefef6c975d7bbe704994bf3357ebd (patch) | |
tree | 4a996b30e021a44fbc8474b3d645f39084b068ad /drivers/pci | |
parent | ed5b580b381307c522cb977dccd207a170ad9b13 (diff) | |
download | u-boot-imx-01cafcedbfbefef6c975d7bbe704994bf3357ebd.zip u-boot-imx-01cafcedbfbefef6c975d7bbe704994bf3357ebd.tar.gz u-boot-imx-01cafcedbfbefef6c975d7bbe704994bf3357ebd.tar.bz2 |
drivers/pci/layerscape: Add EP mode support
The patch will initialize PCIe controller on EP mode
1. Setup bar:
bar0 32bit 4K for specific configuration
bar1 32bit 8K for MSIX
bar2 64bit 4K for descriptor of memory
bar4 64bit 1M for DMA memory test
2. Setup iATU:
iATU inbound 0-3 to map bar transaction to memory address
started at CONFIG_SYS_PCI_EP_MEMORY_BASE
iATU outbound 0 to map 4G memory space
Signed-off-by: Minghuan Lian <Minghuan.Lian@freescale.com>
Reviewed-by: York Sun <yorksun@freescale.com>
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/pcie_layerscape.c | 137 |
1 files changed, 135 insertions, 2 deletions
diff --git a/drivers/pci/pcie_layerscape.c b/drivers/pci/pcie_layerscape.c index 3ef4975..95cfe8c 100644 --- a/drivers/pci/pcie_layerscape.c +++ b/drivers/pci/pcie_layerscape.c @@ -25,6 +25,10 @@ #define CONFIG_SYS_PCI_MEMORY_SIZE (2 * 1024 * 1024 * 1024UL) /* 2G */ #endif +#ifndef CONFIG_SYS_PCI_EP_MEMORY_BASE +#define CONFIG_SYS_PCI_EP_MEMORY_BASE CONFIG_SYS_LOAD_ADDR +#endif + /* iATU registers */ #define PCIE_ATU_VIEWPORT 0x900 #define PCIE_ATU_REGION_INBOUND (0x1 << 31) @@ -41,6 +45,7 @@ #define PCIE_ATU_CR2 0x908 #define PCIE_ATU_ENABLE (0x1 << 31) #define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30) +#define PCIE_ATU_BAR_NUM(bar) ((bar) << 8) #define PCIE_ATU_LOWER_BASE 0x90C #define PCIE_ATU_UPPER_BASE 0x910 #define PCIE_ATU_LIMIT 0x914 @@ -52,6 +57,7 @@ /* LUT registers */ #define PCIE_LUT_BASE 0x80000 +#define PCIE_LUT_LCTRL0 0x7F8 #define PCIE_LUT_DBG 0x7FC #define PCIE_DBI_RO_WR_EN 0x8bc @@ -65,6 +71,25 @@ #define PCIE_DBI_SIZE 0x100000 /* 1M */ +#define PCIE_LCTRL0_CFG2_ENABLE (1 << 31) +#define PCIE_LCTRL0_VF(vf) ((vf) << 22) +#define PCIE_LCTRL0_PF(pf) ((pf) << 16) +#define PCIE_LCTRL0_VF_ACTIVE (1 << 21) +#define PCIE_LCTRL0_VAL(pf, vf) (PCIE_LCTRL0_PF(pf) | \ + PCIE_LCTRL0_VF(vf) | \ + ((vf) == 0 ? 0 : PCIE_LCTRL0_VF_ACTIVE) | \ + PCIE_LCTRL0_CFG2_ENABLE) + +#define PCIE_NO_SRIOV_BAR_BASE 0x1000 + +#define PCIE_PF_NUM 2 +#define PCIE_VF_NUM 64 + +#define PCIE_BAR0_SIZE (4 * 1024) /* 4K */ +#define PCIE_BAR1_SIZE (8 * 1024) /* 8K for MSIX */ +#define PCIE_BAR2_SIZE (4 * 1024) /* 4K */ +#define PCIE_BAR4_SIZE (1 * 1024 * 1024) /* 1M */ + struct ls_pcie { int idx; void __iomem *dbi; @@ -76,6 +101,7 @@ struct ls_pcie { struct ls_pcie_info { unsigned long regs; int pci_num; + u64 phys_base; u64 cfg0_phys; u64 cfg0_size; u64 cfg1_phys; @@ -91,6 +117,7 @@ struct ls_pcie_info { #define SET_LS_PCIE_INFO(x, num) \ { \ x.regs = CONFIG_SYS_PCIE##num##_ADDR; \ + x.phys_base = CONFIG_SYS_PCIE##num##_PHYS_ADDR; \ x.cfg0_phys = CONFIG_SYS_PCIE_CFG0_PHYS_OFF + \ CONFIG_SYS_PCIE##num##_PHYS_ADDR; \ x.cfg0_size = CONFIG_SYS_PCIE_CFG0_SIZE; \ @@ -197,6 +224,18 @@ static void ls_pcie_iatu_outbound_set(struct ls_pcie *pcie, int idx, int type, writel(PCIE_ATU_ENABLE, pcie->dbi + PCIE_ATU_CR2); } +/* Use bar match mode and MEM type as default */ +static void ls_pcie_iatu_inbound_set(struct ls_pcie *pcie, int idx, + int bar, u64 phys) +{ + writel(PCIE_ATU_REGION_INBOUND | idx, pcie->dbi + PCIE_ATU_VIEWPORT); + writel((u32)phys, pcie->dbi + PCIE_ATU_LOWER_TARGET); + writel(phys >> 32, pcie->dbi + PCIE_ATU_UPPER_TARGET); + writel(PCIE_ATU_TYPE_MEM, pcie->dbi + PCIE_ATU_CR1); + writel(PCIE_ATU_ENABLE | PCIE_ATU_BAR_MODE_ENABLE | + PCIE_ATU_BAR_NUM(bar), pcie->dbi + PCIE_ATU_CR2); +} + static void ls_pcie_setup_atu(struct ls_pcie *pcie, struct ls_pcie_info *info) { #ifdef DEBUG @@ -350,6 +389,97 @@ static void ls_pcie_setup_ctrl(struct ls_pcie *pcie, #endif } +static void ls_pcie_ep_setup_atu(struct ls_pcie *pcie, + struct ls_pcie_info *info) +{ + u64 phys = CONFIG_SYS_PCI_EP_MEMORY_BASE; + + /* ATU 0 : INBOUND : map BAR0 */ + ls_pcie_iatu_inbound_set(pcie, PCIE_ATU_REGION_INDEX0, 0, phys); + /* ATU 1 : INBOUND : map BAR1 */ + phys += PCIE_BAR1_SIZE; + ls_pcie_iatu_inbound_set(pcie, PCIE_ATU_REGION_INDEX1, 1, phys); + /* ATU 2 : INBOUND : map BAR2 */ + phys += PCIE_BAR2_SIZE; + ls_pcie_iatu_inbound_set(pcie, PCIE_ATU_REGION_INDEX2, 2, phys); + /* ATU 3 : INBOUND : map BAR4 */ + phys = CONFIG_SYS_PCI_EP_MEMORY_BASE + PCIE_BAR4_SIZE; + ls_pcie_iatu_inbound_set(pcie, PCIE_ATU_REGION_INDEX3, 4, phys); + + /* ATU 0 : OUTBOUND : map 4G MEM */ + ls_pcie_iatu_outbound_set(pcie, PCIE_ATU_REGION_INDEX0, + PCIE_ATU_TYPE_MEM, + info->phys_base, + 0, + 4 * 1024 * 1024 * 1024ULL); +} + +/* BAR0 and BAR1 are 32bit BAR2 and BAR4 are 64bit */ +static void ls_pcie_ep_setup_bar(void *bar_base, int bar, u32 size) +{ + if (size < 4 * 1024) + return; + + switch (bar) { + case 0: + writel(size - 1, bar_base + PCI_BASE_ADDRESS_0); + break; + case 1: + writel(size - 1, bar_base + PCI_BASE_ADDRESS_1); + break; + case 2: + writel(size - 1, bar_base + PCI_BASE_ADDRESS_2); + writel(0, bar_base + PCI_BASE_ADDRESS_3); + break; + case 4: + writel(size - 1, bar_base + PCI_BASE_ADDRESS_4); + writel(0, bar_base + PCI_BASE_ADDRESS_5); + break; + default: + break; + } +} + +static void ls_pcie_ep_setup_bars(void *bar_base) +{ + /* BAR0 - 32bit - 4K configuration */ + ls_pcie_ep_setup_bar(bar_base, 0, PCIE_BAR0_SIZE); + /* BAR1 - 32bit - 8K MSIX*/ + ls_pcie_ep_setup_bar(bar_base, 1, PCIE_BAR1_SIZE); + /* BAR2 - 64bit - 4K MEM desciptor */ + ls_pcie_ep_setup_bar(bar_base, 2, PCIE_BAR2_SIZE); + /* BAR4 - 64bit - 1M MEM*/ + ls_pcie_ep_setup_bar(bar_base, 4, PCIE_BAR4_SIZE); +} + +static void ls_pcie_setup_ep(struct ls_pcie *pcie, struct ls_pcie_info *info) +{ + struct pci_controller *hose = &pcie->hose; + pci_dev_t dev = PCI_BDF(hose->first_busno, 0, 0); + int sriov; + + sriov = pci_hose_find_ext_capability(hose, dev, PCI_EXT_CAP_ID_SRIOV); + if (sriov) { + int pf, vf; + + for (pf = 0; pf < PCIE_PF_NUM; pf++) { + for (vf = 0; vf <= PCIE_VF_NUM; vf++) { + writel(PCIE_LCTRL0_VAL(pf, vf), + pcie->dbi + PCIE_LUT_BASE + + PCIE_LUT_LCTRL0); + ls_pcie_ep_setup_bars(pcie->dbi); + ls_pcie_ep_setup_atu(pcie, info); + } + } + + /* Disable CFG2 */ + writel(0, pcie->dbi + PCIE_LUT_BASE + PCIE_LUT_LCTRL0); + } else { + ls_pcie_ep_setup_bars(pcie->dbi + PCIE_NO_SRIOV_BAR_BASE); + ls_pcie_ep_setup_atu(pcie, info); + } +} + int ls_pcie_init_ctrl(int busno, enum srds_prtcl dev, struct ls_pcie_info *info) { struct ls_pcie *pcie; @@ -426,6 +556,11 @@ int ls_pcie_init_ctrl(int busno, enum srds_prtcl dev, struct ls_pcie_info *info) printf("PCIe%u: %s ", info->pci_num, ep_mode ? "Endpoint" : "Root Complex"); + if (ep_mode) + ls_pcie_setup_ep(pcie, info); + else + ls_pcie_setup_ctrl(pcie, info); + linkup = ls_pcie_link_up(pcie); if (!linkup) { @@ -443,8 +578,6 @@ int ls_pcie_init_ctrl(int busno, enum srds_prtcl dev, struct ls_pcie_info *info) if (ep_mode) return busno; - ls_pcie_setup_ctrl(pcie, info); - pci_register_hose(hose); hose->last_busno = pci_hose_scan(hose); |