PCI: dwc: dra7xx: Invoke phy_set_mode() API to set PHY mode to PHY_MODE_PCIE
[linux-2.6-block.git] / drivers / pci / controller / dwc / pci-dra7xx.c
index a32d6dde7a579f6c21fe3daf79f10c566b48bb8d..5d5844fc143e8c2aa37d2ba3fd28325ecf3d6e78 100644 (file)
 #define MSI_REQ_GRANT                                  BIT(0)
 #define MSI_VECTOR_SHIFT                               7
 
+#define PCIE_1LANE_2LANE_SELECTION                     BIT(13)
+#define PCIE_B1C0_MODE_SEL                             BIT(2)
+#define PCIE_B0_B1_TSYNCEN                             BIT(0)
+
 struct dra7xx_pcie {
        struct dw_pcie          *pci;
        void __iomem            *base;          /* DT ti_conf */
@@ -93,6 +97,7 @@ struct dra7xx_pcie {
 
 struct dra7xx_pcie_of_data {
        enum dw_pcie_device_mode mode;
+       u32 b1co_mode_sel_mask;
 };
 
 #define to_dra7xx_pcie(x)      dev_get_drvdata((x)->dev)
@@ -499,6 +504,10 @@ static int dra7xx_pcie_enable_phy(struct dra7xx_pcie *dra7xx)
        int i;
 
        for (i = 0; i < phy_count; i++) {
+               ret = phy_set_mode(dra7xx->phy[i], PHY_MODE_PCIE);
+               if (ret < 0)
+                       goto err_phy;
+
                ret = phy_init(dra7xx->phy[i]);
                if (ret < 0)
                        goto err_phy;
@@ -529,6 +538,26 @@ static const struct dra7xx_pcie_of_data dra7xx_pcie_ep_of_data = {
        .mode = DW_PCIE_EP_TYPE,
 };
 
+static const struct dra7xx_pcie_of_data dra746_pcie_rc_of_data = {
+       .b1co_mode_sel_mask = BIT(2),
+       .mode = DW_PCIE_RC_TYPE,
+};
+
+static const struct dra7xx_pcie_of_data dra726_pcie_rc_of_data = {
+       .b1co_mode_sel_mask = GENMASK(3, 2),
+       .mode = DW_PCIE_RC_TYPE,
+};
+
+static const struct dra7xx_pcie_of_data dra746_pcie_ep_of_data = {
+       .b1co_mode_sel_mask = BIT(2),
+       .mode = DW_PCIE_EP_TYPE,
+};
+
+static const struct dra7xx_pcie_of_data dra726_pcie_ep_of_data = {
+       .b1co_mode_sel_mask = GENMASK(3, 2),
+       .mode = DW_PCIE_EP_TYPE,
+};
+
 static const struct of_device_id of_dra7xx_pcie_match[] = {
        {
                .compatible = "ti,dra7-pcie",
@@ -538,6 +567,22 @@ static const struct of_device_id of_dra7xx_pcie_match[] = {
                .compatible = "ti,dra7-pcie-ep",
                .data = &dra7xx_pcie_ep_of_data,
        },
+       {
+               .compatible = "ti,dra746-pcie-rc",
+               .data = &dra746_pcie_rc_of_data,
+       },
+       {
+               .compatible = "ti,dra726-pcie-rc",
+               .data = &dra726_pcie_rc_of_data,
+       },
+       {
+               .compatible = "ti,dra746-pcie-ep",
+               .data = &dra746_pcie_ep_of_data,
+       },
+       {
+               .compatible = "ti,dra726-pcie-ep",
+               .data = &dra726_pcie_ep_of_data,
+       },
        {},
 };
 
@@ -583,6 +628,34 @@ static int dra7xx_pcie_unaligned_memaccess(struct device *dev)
        return ret;
 }
 
+static int dra7xx_pcie_configure_two_lane(struct device *dev,
+                                         u32 b1co_mode_sel_mask)
+{
+       struct device_node *np = dev->of_node;
+       struct regmap *pcie_syscon;
+       unsigned int pcie_reg;
+       u32 mask;
+       u32 val;
+
+       pcie_syscon = syscon_regmap_lookup_by_phandle(np, "ti,syscon-lane-sel");
+       if (IS_ERR(pcie_syscon)) {
+               dev_err(dev, "unable to get ti,syscon-lane-sel\n");
+               return -EINVAL;
+       }
+
+       if (of_property_read_u32_index(np, "ti,syscon-lane-sel", 1,
+                                      &pcie_reg)) {
+               dev_err(dev, "couldn't get lane selection reg offset\n");
+               return -EINVAL;
+       }
+
+       mask = b1co_mode_sel_mask | PCIE_B0_B1_TSYNCEN;
+       val = PCIE_B1C0_MODE_SEL | PCIE_B0_B1_TSYNCEN;
+       regmap_update_bits(pcie_syscon, pcie_reg, mask, val);
+
+       return 0;
+}
+
 static int __init dra7xx_pcie_probe(struct platform_device *pdev)
 {
        u32 reg;
@@ -603,6 +676,7 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
        const struct of_device_id *match;
        const struct dra7xx_pcie_of_data *data;
        enum dw_pcie_device_mode mode;
+       u32 b1co_mode_sel_mask;
 
        match = of_match_device(of_match_ptr(of_dra7xx_pcie_match), dev);
        if (!match)
@@ -610,6 +684,7 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
 
        data = (struct dra7xx_pcie_of_data *)match->data;
        mode = (enum dw_pcie_device_mode)data->mode;
+       b1co_mode_sel_mask = data->b1co_mode_sel_mask;
 
        dra7xx = devm_kzalloc(dev, sizeof(*dra7xx), GFP_KERNEL);
        if (!dra7xx)
@@ -665,6 +740,12 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
        dra7xx->pci = pci;
        dra7xx->phy_count = phy_count;
 
+       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 */
+       }
+
        ret = dra7xx_pcie_enable_phy(dra7xx);
        if (ret) {
                dev_err(dev, "failed to enable phy\n");