PCI: iproc: Add support for the next-gen PAXB controller
authorRay Jui <ray.jui@broadcom.com>
Tue, 1 Nov 2016 00:38:41 +0000 (17:38 -0700)
committerBjorn Helgaas <bhelgaas@google.com>
Wed, 23 Nov 2016 22:51:14 +0000 (16:51 -0600)
Add support for the next generation of the iProc PAXB host controller, used
in Stingray.

Signed-off-by: Oza Oza <oza.oza@broadcom.com>
Signed-off-by: Ray Jui <ray.jui@broadcom.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Scott Branden <scott.branden@broadcom.com>
drivers/pci/host/pcie-iproc-platform.c
drivers/pci/host/pcie-iproc.c
drivers/pci/host/pcie-iproc.h

index 47329d34267c7be6c5826e51ea10da4fc6c68698..fd3ed9bccaff68de28997860dd45db4308d54863 100644 (file)
@@ -30,6 +30,9 @@ static const struct of_device_id iproc_pcie_of_match_table[] = {
        {
                .compatible = "brcm,iproc-pcie",
                .data = (int *)IPROC_PCIE_PAXB,
+       }, {
+               .compatible = "brcm,iproc-pcie-paxb-v2",
+               .data = (int *)IPROC_PCIE_PAXB_V2,
        }, {
                .compatible = "brcm,iproc-pcie-paxc",
                .data = (int *)IPROC_PCIE_PAXC,
index cbbbeaa46dad5d025ee4ac0c28cfdea5a98a4a69..3d02ad261761c0cb6db4481516cb96202a0f3016 100644 (file)
@@ -118,6 +118,29 @@ static const struct iproc_pcie_ob_map paxb_ob_map[] = {
        },
 };
 
+static const struct iproc_pcie_ob_map paxb_v2_ob_map[] = {
+       {
+               /* OARR0/OMAP0 */
+               .window_sizes = { 128, 256 },
+               .nr_sizes = 2,
+       },
+       {
+               /* OARR1/OMAP1 */
+               .window_sizes = { 128, 256 },
+               .nr_sizes = 2,
+       },
+       {
+               /* OARR2/OMAP2 */
+               .window_sizes = { 128, 256, 512, 1024 },
+               .nr_sizes = 4,
+       },
+       {
+               /* OARR3/OMAP3 */
+               .window_sizes = { 128, 256, 512, 1024 },
+               .nr_sizes = 4,
+       },
+};
+
 /**
  * iProc PCIe inbound mapping type
  */
@@ -156,6 +179,54 @@ struct iproc_pcie_ib_map {
        u16 imap_window_offset;
 };
 
+static const struct iproc_pcie_ib_map paxb_v2_ib_map[] = {
+       {
+               /* IARR0/IMAP0 */
+               .type = IPROC_PCIE_IB_MAP_IO,
+               .size_unit = SZ_1K,
+               .region_sizes = { 32 },
+               .nr_sizes = 1,
+               .nr_windows = 8,
+               .imap_addr_offset = 0x40,
+               .imap_window_offset = 0x4,
+       },
+       {
+               /* IARR1/IMAP1 (currently unused) */
+               .type = IPROC_PCIE_IB_MAP_INVALID,
+       },
+       {
+               /* IARR2/IMAP2 */
+               .type = IPROC_PCIE_IB_MAP_MEM,
+               .size_unit = SZ_1M,
+               .region_sizes = { 64, 128, 256, 512, 1024, 2048, 4096, 8192,
+                                 16384 },
+               .nr_sizes = 9,
+               .nr_windows = 1,
+               .imap_addr_offset = 0x4,
+               .imap_window_offset = 0x8,
+       },
+       {
+               /* IARR3/IMAP3 */
+               .type = IPROC_PCIE_IB_MAP_MEM,
+               .size_unit = SZ_1G,
+               .region_sizes = { 1, 2, 4, 8, 16, 32 },
+               .nr_sizes = 6,
+               .nr_windows = 8,
+               .imap_addr_offset = 0x4,
+               .imap_window_offset = 0x8,
+       },
+       {
+               /* IARR4/IMAP4 */
+               .type = IPROC_PCIE_IB_MAP_MEM,
+               .size_unit = SZ_1G,
+               .region_sizes = { 32, 64, 128, 256, 512 },
+               .nr_sizes = 5,
+               .nr_windows = 8,
+               .imap_addr_offset = 0x4,
+               .imap_window_offset = 0x8,
+       },
+};
+
 /*
  * iProc PCIe host registers
  */
@@ -258,6 +329,34 @@ static const u16 iproc_pcie_reg_paxb[] = {
        [IPROC_PCIE_APB_ERR_EN]       = 0xf40,
 };
 
+/* iProc PCIe PAXB v2 registers */
+static const u16 iproc_pcie_reg_paxb_v2[] = {
+       [IPROC_PCIE_CLK_CTRL]         = 0x000,
+       [IPROC_PCIE_CFG_IND_ADDR]     = 0x120,
+       [IPROC_PCIE_CFG_IND_DATA]     = 0x124,
+       [IPROC_PCIE_CFG_ADDR]         = 0x1f8,
+       [IPROC_PCIE_CFG_DATA]         = 0x1fc,
+       [IPROC_PCIE_INTX_EN]          = 0x330,
+       [IPROC_PCIE_OARR0]            = 0xd20,
+       [IPROC_PCIE_OMAP0]            = 0xd40,
+       [IPROC_PCIE_OARR1]            = 0xd28,
+       [IPROC_PCIE_OMAP1]            = 0xd48,
+       [IPROC_PCIE_OARR2]            = 0xd60,
+       [IPROC_PCIE_OMAP2]            = 0xd68,
+       [IPROC_PCIE_OARR3]            = 0xdf0,
+       [IPROC_PCIE_OMAP3]            = 0xdf8,
+       [IPROC_PCIE_IARR0]            = 0xd00,
+       [IPROC_PCIE_IMAP0]            = 0xc00,
+       [IPROC_PCIE_IARR2]            = 0xd10,
+       [IPROC_PCIE_IMAP2]            = 0xcc0,
+       [IPROC_PCIE_IARR3]            = 0xe00,
+       [IPROC_PCIE_IMAP3]            = 0xe08,
+       [IPROC_PCIE_IARR4]            = 0xe68,
+       [IPROC_PCIE_IMAP4]            = 0xe70,
+       [IPROC_PCIE_LINK_STATUS]      = 0xf0c,
+       [IPROC_PCIE_APB_ERR_EN]       = 0xf40,
+};
+
 /* iProc PCIe PAXC v1 registers */
 static const u16 iproc_pcie_reg_paxc[] = {
        [IPROC_PCIE_CLK_CTRL]         = 0x000,
@@ -914,6 +1013,19 @@ static int iproce_pcie_get_msi(struct iproc_pcie *pcie,
        return 0;
 }
 
+static int iproc_pcie_paxb_v2_msi_steer(struct iproc_pcie *pcie, u64 msi_addr)
+{
+       int ret;
+       struct of_pci_range range;
+
+       memset(&range, 0, sizeof(range));
+       range.size = SZ_32K;
+       range.pci_addr = range.cpu_addr = ALIGN(msi_addr, range.size);
+
+       ret = iproc_pcie_setup_ib(pcie, &range, IPROC_PCIE_IB_MAP_IO);
+       return ret;
+}
+
 static void iproc_pcie_paxc_v2_msi_steer(struct iproc_pcie *pcie, u64 msi_addr)
 {
        u32 val;
@@ -965,6 +1077,11 @@ static int iproc_pcie_msi_steer(struct iproc_pcie *pcie,
        }
 
        switch (pcie->type) {
+       case IPROC_PCIE_PAXB_V2:
+               ret = iproc_pcie_paxb_v2_msi_steer(pcie, msi_addr);
+               if (ret)
+                       return ret;
+               break;
        case IPROC_PCIE_PAXC_V2:
                iproc_pcie_paxc_v2_msi_steer(pcie, msi_addr);
                break;
@@ -1042,6 +1159,17 @@ static int iproc_pcie_rev_init(struct iproc_pcie *pcie)
                        pcie->ob.nr_windows = ARRAY_SIZE(paxb_ob_map);
                }
                break;
+       case IPROC_PCIE_PAXB_V2:
+               regs = iproc_pcie_reg_paxb_v2;
+               pcie->has_apb_err_disable = true;
+               if (pcie->need_ob_cfg) {
+                       pcie->ob_map = paxb_v2_ob_map;
+                       pcie->ob.nr_windows = ARRAY_SIZE(paxb_v2_ob_map);
+               }
+               pcie->ib.nr_regions = ARRAY_SIZE(paxb_v2_ib_map);
+               pcie->ib_map = paxb_v2_ib_map;
+               pcie->need_msi_steer = true;
+               break;
        case IPROC_PCIE_PAXC:
                regs = iproc_pcie_reg_paxc;
                pcie->ep_is_internal = true;
index 3f2709af1a5072ff0f92cb0458f45fdf9b40595f..04fed8e907f12b602b5fb1f11ff59971ebd0b87f 100644 (file)
@@ -26,6 +26,7 @@
 enum iproc_pcie_type {
        IPROC_PCIE_PAXB_BCMA = 0,
        IPROC_PCIE_PAXB,
+       IPROC_PCIE_PAXB_V2,
        IPROC_PCIE_PAXC,
        IPROC_PCIE_PAXC_V2,
 };