PCI: dwc: Add const qualifier to struct dw_pcie_ep_ops
[linux-2.6-block.git] / drivers / pci / controller / dwc / pci-dra7xx.c
index a32d6dde7a579f6c21fe3daf79f10c566b48bb8d..b287dbf6914cb61167532facddfce2995fd046b3 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)
@@ -389,9 +394,22 @@ static int dra7xx_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
        return 0;
 }
 
-static struct dw_pcie_ep_ops pcie_ep_ops = {
+static const struct pci_epc_features dra7xx_pcie_epc_features = {
+       .linkup_notifier = true,
+       .msi_capable = true,
+       .msix_capable = false,
+};
+
+static const struct pci_epc_features*
+dra7xx_pcie_get_features(struct dw_pcie_ep *ep)
+{
+       return &dra7xx_pcie_epc_features;
+}
+
+static const struct dw_pcie_ep_ops pcie_ep_ops = {
        .ep_init = dra7xx_pcie_ep_init,
        .raise_irq = dra7xx_pcie_raise_irq,
+       .get_features = dra7xx_pcie_get_features,
 };
 
 static int __init dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx,
@@ -499,6 +517,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 +551,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 +580,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 +641,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 +689,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 +697,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 +753,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");