diff --git a/arch/arm/boot/dts/am57xx-pcm-948-common.dtsi b/arch/arm/boot/dts/am57xx-pcm-948-common.dtsi index abc788769d7f..e3431293034a 100644 --- a/arch/arm/boot/dts/am57xx-pcm-948-common.dtsi +++ b/arch/arm/boot/dts/am57xx-pcm-948-common.dtsi @@ -788,7 +788,8 @@ }; &pcie1_rc { - status = "okay"; + //status = "okay"; + status = "disabled"; pinctrl-names = "default"; pinctrl-0 = <&pcie1_pins>; diff --git a/arch/arm/boot/dts/am57xx-phycore-common.dtsi b/arch/arm/boot/dts/am57xx-phycore-common.dtsi index 42d86989c56d..456d9ec6224a 100644 --- a/arch/arm/boot/dts/am57xx-phycore-common.dtsi +++ b/arch/arm/boot/dts/am57xx-phycore-common.dtsi @@ -569,7 +569,13 @@ * * pcie2_rc/ep are incompatible with PCM-948 */ + +&pcie2_phy{ + status = "okay"; +}; + &axi1 { + status = "okay"; pcie2_ep: pcie_ep@51800000 { compatible = "ti,dra7-pcie-ep"; reg = <0x51800000 0x28>, <0x51802000 0x14c>, @@ -581,7 +587,7 @@ num-ob-windows = <16>; ti,hwmods = "pcie2"; phys = <&pcie2_phy>; - phy-names = "pcie-phy1"; + phy-names = "pcie-phy0"; syscon-legacy-mode = <&scm_conf1 0x14 1>; status = "okay"; }; diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index 549319d419b2..b548dbbd443d 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -367,7 +367,7 @@ #address-cells = <1>; ranges = <0x51800000 0x51800000 0x3000 0x0 0x30000000 0x10000000>; - status = "disabled"; + //status = "disabled"; pcie2_rc: pcie@51800000 { reg = <0x51800000 0x2000>, <0x51802000 0x14c>, <0x1000 0x2000>; reg-names = "rc_dbics", "ti_conf", "config"; @@ -389,6 +389,7 @@ <0 0 0 2 &pcie2_intc 2>, <0 0 0 3 &pcie2_intc 3>, <0 0 0 4 &pcie2_intc 4>; + status = "disabled"; pcie2_intc: interrupt-controller { interrupt-controller; #address-cells = <0>; diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index 54f139b4d6ad..a56542d3c313 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -622,6 +622,8 @@ static const struct of_device_id of_dra7xx_pcie_match[] = { * * To avoid this issue set PCIE_SS1_AXI2OCP_LEGACY_MODE_ENABLE to 1. */ + + /* static int dra7xx_pcie_unaligned_memaccess(struct device *dev) { int ret; @@ -651,8 +653,8 @@ static int dra7xx_pcie_unaligned_memaccess(struct device *dev) of_node_put(args.np); return ret; -} - +}*/ +/* static int dra7xx_pcie_configure_two_lane(struct device *dev, u32 b1co_mode_sel_mask) { @@ -680,7 +682,8 @@ static int dra7xx_pcie_configure_two_lane(struct device *dev, return 0; } - +*/ +/* static int __init dra7xx_pcie_probe(struct platform_device *pdev) { u32 reg; @@ -768,7 +771,7 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) if (phy_count == 2) { ret = dra7xx_pcie_configure_two_lane(dev, b1co_mode_sel_mask); if (ret < 0) - dra7xx->phy_count = 1; /* Fallback to x1 lane mode */ + dra7xx->phy_count = 1; } ret = dra7xx_pcie_enable_phy(dra7xx); @@ -873,6 +876,245 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) return ret; } +*/ + +static int dra7xx_pcie_ep_legacy_mode(struct device *dev) +{ + int ret; + struct device_node *np = dev->of_node; + struct regmap *regmap; + unsigned int reg; + unsigned int field; + + regmap = syscon_regmap_lookup_by_phandle(np, "syscon-legacy-mode"); + if (IS_ERR(regmap)) { + dev_dbg(dev, "can't get syscon-legacy-mode\n"); + return -EINVAL; + } + + if (of_property_read_u32_index(np, "syscon-legacy-mode", 1, ®)) { + dev_err(dev, "couldn't get legacy mode register offset\n"); + return -EINVAL; + } + + if (of_property_read_u32_index(np, "syscon-legacy-mode", 2, &field)) { + dev_err(dev, "can't get bit field for setting legacy mode\n"); + return -EINVAL; + } + + ret = regmap_update_bits(regmap, reg, field, field); + if (ret) + dev_err(dev, "failed to set legacy mode\n"); + + return ret; +} + + +static int __init dra7xx_pcie_probe(struct platform_device *pdev) +{ + u32 reg; + u32 field; + int ret; + int irq; + int i; + int phy_count; + struct phy **phy; + struct device_link **link; + void __iomem *base; + struct resource *res; + struct dw_pcie *pci; + struct dra7xx_pcie *dra7xx; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct regmap *regmap; + char name[10]; + struct gpio_desc *reset, *clk_oe; + const struct of_device_id *match; + const struct dra7xx_pcie_of_data *data; + enum dw_pcie_device_mode mode; + + match = of_match_device(of_match_ptr(of_dra7xx_pcie_match), dev); + if (!match) + return -EINVAL; + + data = (struct dra7xx_pcie_of_data *)match->data; + mode = (enum dw_pcie_device_mode)data->mode; + + dra7xx = devm_kzalloc(dev, sizeof(*dra7xx), GFP_KERNEL); + if (!dra7xx) + return -ENOMEM; + + pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL); + if (!pci) + return -ENOMEM; + + pci->dev = dev; + pci->ops = &dw_pcie_ops; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "missing IRQ resource\n"); + return -EINVAL; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ti_conf"); + base = devm_ioremap_nocache(dev, res->start, resource_size(res)); + if (!base) + return -ENOMEM; + + phy_count = of_property_count_strings(np, "phy-names"); + if (phy_count < 0) { + dev_err(dev, "unable to find the strings\n"); + return phy_count; + } + + phy = devm_kzalloc(dev, sizeof(*phy) * phy_count, GFP_KERNEL); + if (!phy) + return -ENOMEM; + + link = devm_kzalloc(dev, sizeof(*link) * phy_count, GFP_KERNEL); + if (!link) + return -ENOMEM; + + if (phy_count > 1) { + regmap = syscon_regmap_lookup_by_phandle(np, + "syscon-dual-lane"); + if (IS_ERR(regmap)) { + dev_dbg(dev, "can't get syscon-dual-lane\n"); + return -EINVAL; + } + + if (of_property_read_u32_index(np, "syscon-dual-lane", 1, + ®)) { + dev_err(dev, + "couldn't get x2 lane mode register offset\n"); + return -EINVAL; + } + + if (of_property_read_u32_index(np, "syscon-dual-lane", 2, + &field)) { + dev_err(dev, + "can't get bit field for setting x2 lane mode\n"); + return -EINVAL; + } + + ret = regmap_update_bits(regmap, reg, field, field); + if (ret) { + dev_err(dev, "failed to set x2 lane mode\n"); + return ret; + } + } + + for (i = 0; i < phy_count; i++) { + snprintf(name, sizeof(name), "pcie-phy%d", i); + phy[i] = devm_phy_get(dev, name); + if (IS_ERR(phy[i])) + return PTR_ERR(phy[i]); + + link[i] = device_link_add(dev, &phy[i]->dev, DL_FLAG_STATELESS); + if (!link[i]) { + ret = -EINVAL; + goto err_link; + } + } + + dra7xx->base = base; + dra7xx->phy = phy; + dra7xx->pci = pci; + dra7xx->phy_count = phy_count; + + ret = dra7xx_pcie_enable_phy(dra7xx); + if (ret) { + dev_err(dev, "failed to enable phy\n"); + return ret; + } + + pm_runtime_enable(dev); + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + dev_err(dev, "pm_runtime_get_sync failed\n"); + goto err_get_sync; + } + + reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD); + reg &= ~LTSSM_EN; + dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg); + + platform_set_drvdata(pdev, dra7xx); + + clk_oe = devm_gpiod_get_optional(dev, "pcie-clk-oe", GPIOD_OUT_HIGH); + if (IS_ERR(clk_oe)) { + ret = PTR_ERR(clk_oe); + dev_err(&pdev->dev, "clk_oe gpio request failed, ret %d\n", ret); + goto err_gpio; + } + + if (of_property_read_bool(np, "pcie-reset-active-low")) + reset = devm_gpiod_get_optional(dev, "pcie-reset", GPIOD_OUT_LOW); + else + reset = devm_gpiod_get_optional(dev, "pcie-reset", GPIOD_OUT_HIGH); + if (IS_ERR(reset)) { + ret = PTR_ERR(reset); + dev_err(&pdev->dev, "gpio request failed, ret %d\n", ret); + goto err_gpio; + } + + reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD); + reg &= ~LTSSM_EN; + dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg); + + dra7xx->link_gen = of_pci_get_max_link_speed(np); + if (dra7xx->link_gen < 0 || dra7xx->link_gen > 2) + dra7xx->link_gen = 2; + + switch (mode) { + case DW_PCIE_RC_TYPE: + dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_DEVICE_TYPE, + DEVICE_TYPE_RC); + + ret = dra7xx_add_pcie_port(dra7xx, pdev); + if (ret < 0) + goto err_gpio; + break; + case DW_PCIE_EP_TYPE: + dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_DEVICE_TYPE, + DEVICE_TYPE_EP); + + ret = dra7xx_pcie_ep_legacy_mode(dev); + if (ret) + goto err_gpio; + + ret = dra7xx_add_pcie_ep(dra7xx, pdev); + if (ret < 0) + goto err_gpio; + break; + default: + dev_err(dev, "INVALID device type %d\n", mode); + } + dra7xx->mode = mode; + + ret = devm_request_irq(dev, irq, dra7xx_pcie_irq_handler, + IRQF_SHARED, "dra7xx-pcie-main", dra7xx); + if (ret) { + dev_err(dev, "failed to request irq\n"); + goto err_gpio; + } + + return 0; + +err_gpio: + pm_runtime_put(dev); + +err_get_sync: + pm_runtime_disable(dev); + dra7xx_pcie_disable_phy(dra7xx); + +err_link: + while (--i >= 0) + device_link_del(link[i]); + + return ret; +} #ifdef CONFIG_PM_SLEEP static int dra7xx_pcie_suspend(struct device *dev)