diff options
Diffstat (limited to 'drivers/pci/controller/dwc/pci-keystone.c')
| -rw-r--r-- | drivers/pci/controller/dwc/pci-keystone.c | 249 |
1 files changed, 63 insertions, 186 deletions
diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index af677254a072..865258d8c53c 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -3,7 +3,7 @@ * PCIe host controller driver for Texas Instruments Keystone SoCs * * Copyright (C) 2013-2014 Texas Instruments., Ltd. - * http://www.ti.com + * https://www.ti.com * * Author: Murali Karicheri <[email protected]> * Implementation based on pci-exynos.c and pcie-designware.c @@ -96,8 +96,6 @@ #define LEG_EP 0x1 #define RC 0x2 -#define EXP_CAP_ID_OFFSET 0x70 - #define KS_PCIE_SYSCLOCKOUTEN BIT(0) #define AM654_PCIE_DEV_TYPE_MASK 0x3 @@ -261,28 +259,18 @@ static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, struct dw_pcie *pci = ks_pcie->pci; struct device *dev = pci->dev; u32 pending; - int virq; pending = ks_pcie_app_readl(ks_pcie, IRQ_STATUS(offset)); if (BIT(0) & pending) { - virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, offset); - dev_dbg(dev, ": irq: irq_offset %d, virq %d\n", offset, virq); - generic_handle_irq(virq); + dev_dbg(dev, ": irq: irq_offset %d", offset); + generic_handle_domain_irq(ks_pcie->legacy_irq_domain, offset); } /* EOI the INTx interrupt */ ks_pcie_app_writel(ks_pcie, IRQ_EOI, offset); } -/* - * Dummy function so that DW core doesn't configure MSI - */ -static int ks_pcie_am654_msi_host_init(struct pcie_port *pp) -{ - return 0; -} - static void ks_pcie_enable_error_irq(struct keystone_pcie *ks_pcie) { ks_pcie_app_writel(ks_pcie, ERR_IRQ_ENABLE_SET, ERR_IRQ_ALL); @@ -356,8 +344,9 @@ static const struct irq_domain_ops ks_pcie_legacy_irq_domain_ops = { }; /** - * ks_pcie_set_dbi_mode() - Set DBI mode to access overlaid BAR mask - * registers + * ks_pcie_set_dbi_mode() - Set DBI mode to access overlaid BAR mask registers + * @ks_pcie: A pointer to the keystone_pcie structure which holds the KeyStone + * PCIe host controller driver information. * * Since modification of dbi_cs2 involves different clock domain, read the * status back to ensure the transition is complete. @@ -377,6 +366,8 @@ static void ks_pcie_set_dbi_mode(struct keystone_pcie *ks_pcie) /** * ks_pcie_clear_dbi_mode() - Disable DBI mode + * @ks_pcie: A pointer to the keystone_pcie structure which holds the KeyStone + * PCIe host controller driver information. * * Since modification of dbi_cs2 involves different clock domain, read the * status back to ensure the transition is complete. @@ -400,10 +391,14 @@ static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie) u32 num_viewport = ks_pcie->num_viewport; struct dw_pcie *pci = ks_pcie->pci; struct pcie_port *pp = &pci->pp; - u64 start = pp->mem->start; - u64 end = pp->mem->end; + u64 start, end; + struct resource *mem; int i; + mem = resource_list_first_type(&pp->bridge->windows, IORESOURCE_MEM)->res; + start = mem->start; + end = mem->end; + /* Disable BARs for inbound access */ ks_pcie_set_dbi_mode(ks_pcie); dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0); @@ -422,7 +417,7 @@ static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie) lower_32_bits(start) | OB_ENABLEN); ks_pcie_app_writel(ks_pcie, OB_OFFSET_HI(i), upper_32_bits(start)); - start += OB_WIN_SIZE; + start += OB_WIN_SIZE * SZ_1M; } val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); @@ -430,50 +425,44 @@ static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie) ks_pcie_app_writel(ks_pcie, CMD_STATUS, val); } -static int ks_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus, - unsigned int devfn, int where, int size, - u32 *val) +static void __iomem *ks_pcie_other_map_bus(struct pci_bus *bus, + unsigned int devfn, int where) { + struct pcie_port *pp = bus->sysdata; struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); u32 reg; reg = CFG_BUS(bus->number) | CFG_DEVICE(PCI_SLOT(devfn)) | CFG_FUNC(PCI_FUNC(devfn)); - if (bus->parent->number != pp->root_bus_nr) + if (!pci_is_root_bus(bus->parent)) reg |= CFG_TYPE1; ks_pcie_app_writel(ks_pcie, CFG_SETUP, reg); - return dw_pcie_read(pp->va_cfg0_base + where, size, val); + return pp->va_cfg0_base + where; } -static int ks_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus, - unsigned int devfn, int where, int size, - u32 val) -{ - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); - u32 reg; - - reg = CFG_BUS(bus->number) | CFG_DEVICE(PCI_SLOT(devfn)) | - CFG_FUNC(PCI_FUNC(devfn)); - if (bus->parent->number != pp->root_bus_nr) - reg |= CFG_TYPE1; - ks_pcie_app_writel(ks_pcie, CFG_SETUP, reg); - - return dw_pcie_write(pp->va_cfg0_base + where, size, val); -} +static struct pci_ops ks_child_pcie_ops = { + .map_bus = ks_pcie_other_map_bus, + .read = pci_generic_config_read, + .write = pci_generic_config_write, +}; /** - * ks_pcie_v3_65_scan_bus() - keystone scan_bus post initialization + * ks_pcie_v3_65_add_bus() - keystone add_bus post initialization + * @bus: A pointer to the PCI bus structure. * * This sets BAR0 to enable inbound access for MSI_IRQ register */ -static void ks_pcie_v3_65_scan_bus(struct pcie_port *pp) +static int ks_pcie_v3_65_add_bus(struct pci_bus *bus) { + struct pcie_port *pp = bus->sysdata; struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); + if (!pci_is_root_bus(bus)) + return 0; + /* Configure and set up BAR0 */ ks_pcie_set_dbi_mode(ks_pcie); @@ -488,10 +477,21 @@ static void ks_pcie_v3_65_scan_bus(struct pcie_port *pp) * be sufficient. Use physical address to avoid any conflicts. */ dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, ks_pcie->app.start); + + return 0; } +static struct pci_ops ks_pcie_ops = { + .map_bus = dw_pcie_own_conf_map_bus, + .read = pci_generic_config_read, + .write = pci_generic_config_write, + .add_bus = ks_pcie_v3_65_add_bus, +}; + /** * ks_pcie_link_up() - Check if link up + * @pci: A pointer to the dw_pcie structure which holds the DesignWare PCIe host + * controller driver information. */ static int ks_pcie_link_up(struct dw_pcie *pci) { @@ -510,20 +510,14 @@ static void ks_pcie_stop_link(struct dw_pcie *pci) /* Disable Link training */ val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); val &= ~LTSSM_EN_VAL; - ks_pcie_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val); + ks_pcie_app_writel(ks_pcie, CMD_STATUS, val); } static int ks_pcie_start_link(struct dw_pcie *pci) { struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); - struct device *dev = pci->dev; u32 val; - if (dw_pcie_link_up(pci)) { - dev_dbg(dev, "link is already up\n"); - return 0; - } - /* Initiate Link Training */ val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); ks_pcie_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val); @@ -583,7 +577,7 @@ static void ks_pcie_msi_irq_handler(struct irq_desc *desc) struct pcie_port *pp = &pci->pp; struct device *dev = pci->dev; struct irq_chip *chip = irq_desc_get_chip(desc); - u32 vector, virq, reg, pos; + u32 vector, reg, pos; dev_dbg(dev, "%s, irq %d\n", __func__, irq); @@ -604,10 +598,8 @@ static void ks_pcie_msi_irq_handler(struct irq_desc *desc) continue; vector = offset + (pos << 3); - virq = irq_linear_revmap(pp->irq_domain, vector); - dev_dbg(dev, "irq: bit %d, vector %d, virq %d\n", pos, vector, - virq); - generic_handle_irq(virq); + dev_dbg(dev, "irq: bit %d, vector %d\n", pos, vector); + generic_handle_domain_irq(pp->irq_domain, vector); } chained_irq_exit(chip, desc); @@ -615,7 +607,6 @@ static void ks_pcie_msi_irq_handler(struct irq_desc *desc) /** * ks_pcie_legacy_irq_handler() - Handle legacy interrupt - * @irq: IRQ line for legacy interrupts * @desc: Pointer to irq descriptor * * Traverse through pending legacy interrupts and invoke handler for each. Also @@ -807,6 +798,10 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); int ret; + pp->bridge->ops = &ks_pcie_ops; + if (!ks_pcie->is_am6) + pp->bridge->child_ops = &ks_child_pcie_ops; + ret = ks_pcie_config_legacy_irq(ks_pcie); if (ret) return ret; @@ -815,8 +810,6 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) if (ret) return ret; - dw_pcie_setup_rc(pp); - ks_pcie_stop_link(pci); ks_pcie_setup_rc_app_regs(ks_pcie); writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8), @@ -835,23 +828,16 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) "Asynchronous external abort"); #endif - ks_pcie_start_link(pci); - dw_pcie_wait_for_link(pci); - return 0; } static const struct dw_pcie_host_ops ks_pcie_host_ops = { - .rd_other_conf = ks_pcie_rd_other_conf, - .wr_other_conf = ks_pcie_wr_other_conf, .host_init = ks_pcie_host_init, .msi_host_init = ks_pcie_msi_host_init, - .scan_bus = ks_pcie_v3_65_scan_bus, }; static const struct dw_pcie_host_ops ks_pcie_am654_host_ops = { .host_init = ks_pcie_host_init, - .msi_host_init = ks_pcie_am654_msi_host_init, }; static irqreturn_t ks_pcie_err_irq_handler(int irq, void *priv) @@ -861,43 +847,6 @@ static irqreturn_t ks_pcie_err_irq_handler(int irq, void *priv) return ks_pcie_handle_error_irq(ks_pcie); } -static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie, - struct platform_device *pdev) -{ - struct dw_pcie *pci = ks_pcie->pci; - struct pcie_port *pp = &pci->pp; - struct device *dev = &pdev->dev; - struct resource *res; - int ret; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config"); - pp->va_cfg0_base = devm_pci_remap_cfg_resource(dev, res); - if (IS_ERR(pp->va_cfg0_base)) - return PTR_ERR(pp->va_cfg0_base); - - pp->va_cfg1_base = pp->va_cfg0_base; - - ret = dw_pcie_host_init(pp); - if (ret) { - dev_err(dev, "failed to initialize host\n"); - return ret; - } - - return 0; -} - -static u32 ks_pcie_am654_read_dbi2(struct dw_pcie *pci, void __iomem *base, - u32 reg, size_t size) -{ - struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); - u32 val; - - ks_pcie_set_dbi_mode(ks_pcie); - dw_pcie_read(base + reg, size, &val); - ks_pcie_clear_dbi_mode(ks_pcie); - return val; -} - static void ks_pcie_am654_write_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg, size_t size, u32 val) { @@ -912,7 +861,6 @@ static const struct dw_pcie_ops ks_pcie_dw_pcie_ops = { .start_link = ks_pcie_start_link, .stop_link = ks_pcie_stop_link, .link_up = ks_pcie_link_up, - .read_dbi2 = ks_pcie_am654_read_dbi2, .write_dbi2 = ks_pcie_am654_write_dbi2, }; @@ -959,6 +907,9 @@ static int ks_pcie_am654_raise_irq(struct dw_pcie_ep *ep, u8 func_no, case PCI_EPC_IRQ_MSI: dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num); break; + case PCI_EPC_IRQ_MSIX: + dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num); + break; default: dev_err(pci->dev, "UNKNOWN IRQ type\n"); return -EINVAL; @@ -970,7 +921,7 @@ static int ks_pcie_am654_raise_irq(struct dw_pcie_ep *ep, u8 func_no, static const struct pci_epc_features ks_pcie_am654_epc_features = { .linkup_notifier = false, .msi_capable = true, - .msix_capable = false, + .msix_capable = true, .reserved_bar = 1 << BAR_0 | 1 << BAR_1, .bar_fixed_64bit = 1 << BAR_0, .bar_fixed_size[2] = SZ_1M, @@ -992,33 +943,6 @@ static const struct dw_pcie_ep_ops ks_pcie_am654_ep_ops = { .get_features = &ks_pcie_am654_get_features, }; -static int __init ks_pcie_add_pcie_ep(struct keystone_pcie *ks_pcie, - struct platform_device *pdev) -{ - int ret; - struct dw_pcie_ep *ep; - struct resource *res; - struct device *dev = &pdev->dev; - struct dw_pcie *pci = ks_pcie->pci; - - ep = &pci->ep; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); - if (!res) - return -EINVAL; - - ep->phys_base = res->start; - ep->addr_size = resource_size(res); - - ret = dw_pcie_ep_init(ep); - if (ret) { - dev_err(dev, "failed to initialize endpoint\n"); - return ret; - } - - return 0; -} - static void ks_pcie_disable_phy(struct keystone_pcie *ks_pcie) { int num_lanes = ks_pcie->num_lanes; @@ -1122,31 +1046,6 @@ static int ks_pcie_am654_set_mode(struct device *dev, return 0; } -static void ks_pcie_set_link_speed(struct dw_pcie *pci, int link_speed) -{ - u32 val; - - dw_pcie_dbi_ro_wr_en(pci); - - val = dw_pcie_readl_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCAP); - if ((val & PCI_EXP_LNKCAP_SLS) != link_speed) { - val &= ~((u32)PCI_EXP_LNKCAP_SLS); - val |= link_speed; - dw_pcie_writel_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCAP, - val); - } - - val = dw_pcie_readl_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCTL2); - if ((val & PCI_EXP_LNKCAP_SLS) != link_speed) { - val &= ~((u32)PCI_EXP_LNKCAP_SLS); - val |= link_speed; - dw_pcie_writel_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCTL2, - val); - } - - dw_pcie_dbi_ro_wr_dis(pci); -} - static const struct ks_pcie_of_data ks_pcie_rc_of_data = { .host_ops = &ks_pcie_host_ops, .version = 0x365A, @@ -1194,13 +1093,11 @@ static int __init ks_pcie_probe(struct platform_device *pdev) struct keystone_pcie *ks_pcie; struct device_link **link; struct gpio_desc *gpiod; - void __iomem *atu_base; struct resource *res; unsigned int version; void __iomem *base; u32 num_viewport; struct phy **phy; - int link_speed; u32 num_lanes; char name[10]; int ret; @@ -1247,10 +1144,8 @@ static int __init ks_pcie_probe(struct platform_device *pdev) pci->version = version; irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "missing IRQ resource: %d\n", irq); + if (irq < 0) return irq; - } ret = request_irq(irq, ks_pcie_err_irq_handler, IRQF_SHARED, "ks-pcie-error-irq", ks_pcie); @@ -1319,30 +1214,12 @@ static int __init ks_pcie_probe(struct platform_device *pdev) goto err_get_sync; } - if (pci->version >= 0x480A) { - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "atu"); - atu_base = devm_ioremap_resource(dev, res); - if (IS_ERR(atu_base)) { - ret = PTR_ERR(atu_base); - goto err_get_sync; - } - - pci->atu_base = atu_base; - + if (pci->version >= 0x480A) ret = ks_pcie_am654_set_mode(dev, mode); - if (ret < 0) - goto err_get_sync; - } else { + else ret = ks_pcie_set_mode(dev); - if (ret < 0) - goto err_get_sync; - } - - link_speed = of_pci_get_max_link_speed(np); - if (link_speed < 0) - link_speed = 2; - - ks_pcie_set_link_speed(pci, link_speed); + if (ret < 0) + goto err_get_sync; switch (mode) { case DW_PCIE_RC_TYPE: @@ -1354,7 +1231,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev) ret = of_property_read_u32(np, "num-viewport", &num_viewport); if (ret < 0) { dev_err(dev, "unable to read *num-viewport* property\n"); - return ret; + goto err_get_sync; } /* @@ -1372,7 +1249,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev) ks_pcie->num_viewport = num_viewport; pci->pp.ops = host_ops; - ret = ks_pcie_add_pcie_port(ks_pcie, pdev); + ret = dw_pcie_host_init(&pci->pp); if (ret < 0) goto err_get_sync; break; @@ -1383,7 +1260,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev) } pci->ep.ops = ep_ops; - ret = ks_pcie_add_pcie_ep(ks_pcie, pdev); + ret = dw_pcie_ep_init(&pci->ep); if (ret < 0) goto err_get_sync; break; |