Przeglądaj źródła

PCI: keystone: Add support for PCIe EP in K2G

Add PCIe EP support for K2G in pci-keystone.c

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
Kishon Vijay Abraham I 6 lat temu
rodzic
commit
5286a95f0c
1 zmienionych plików z 214 dodań i 6 usunięć
  1. 214 6
      drivers/pci/controller/dwc/pci-keystone.c

+ 214 - 6
drivers/pci/controller/dwc/pci-keystone.c

@@ -38,6 +38,7 @@
 #define CMD_STATUS			0x004
 #define CMD_STATUS			0x004
 #define LTSSM_EN_VAL		        BIT(0)
 #define LTSSM_EN_VAL		        BIT(0)
 #define OB_XLAT_EN_VAL		        BIT(1)
 #define OB_XLAT_EN_VAL		        BIT(1)
+#define IB_XLAT_EN_VAL			BIT(2)
 #define DBI_CS2				BIT(5)
 #define DBI_CS2				BIT(5)
 
 
 #define CFG_SETUP			0x008
 #define CFG_SETUP			0x008
@@ -105,6 +106,15 @@
 
 
 #define EXP_CAP_ID_OFFSET		0x70
 #define EXP_CAP_ID_OFFSET		0x70
 
 
+#define IB_BAR(n)			(0x300 + (0x10 * (n)))
+#define IB_START_LO(n)			(0x304 + (0x10 * (n)))
+#define IB_START_HI(n)			(0x308 + (0x10 * (n)))
+#define IB_OFFSET(n)			(0x30c + (0x10 * (n)))
+
+#define KS_PCIE_WIN_SIZE		SZ_1M
+#define KS_PCIE_WIN_INDEX_MASK		0x1f
+#define KS_PCIE_WIN_INDEX_SHIFT		20
+
 #define to_keystone_pcie(x)		dev_get_drvdata((x)->dev)
 #define to_keystone_pcie(x)		dev_get_drvdata((x)->dev)
 
 
 #define PCI_DEVICE_ID_TI_AM654X		0xb00c
 #define PCI_DEVICE_ID_TI_AM654X		0xb00c
@@ -116,6 +126,11 @@ struct ks_pcie_of_data {
 	unsigned int version;
 	unsigned int version;
 };
 };
 
 
+struct ks_pcie_outbound_win {
+	u64	cpu_addr;
+	u8	no_of_regions;
+};
+
 struct keystone_pcie {
 struct keystone_pcie {
 	struct dw_pcie		*pci;
 	struct dw_pcie		*pci;
 	/* PCI Device ID */
 	/* PCI Device ID */
@@ -135,6 +150,8 @@ struct keystone_pcie {
 	void __iomem		*va_app_base;	/* DT 1st resource */
 	void __iomem		*va_app_base;	/* DT 1st resource */
 	struct resource		app;
 	struct resource		app;
 	bool			is_am6;
 	bool			is_am6;
+	unsigned long		ob_window_map;
+	struct ks_pcie_outbound_win *ob_win;
 };
 };
 
 
 static u32 ks_pcie_app_readl(struct keystone_pcie *ks_pcie, u32 offset)
 static u32 ks_pcie_app_readl(struct keystone_pcie *ks_pcie, u32 offset)
@@ -1046,7 +1063,7 @@ static void ks_pcie_am654_write_dbi2(struct dw_pcie *pci, void __iomem *base,
 	ks_pcie_clear_dbi_mode(ks_pcie);
 	ks_pcie_clear_dbi_mode(ks_pcie);
 }
 }
 
 
-static const struct dw_pcie_ops ks_pcie_dw_pcie_ops = {
+static const struct dw_pcie_ops ks_pcie_am654_dw_pcie_ops = {
 	.start_link = ks_pcie_start_link,
 	.start_link = ks_pcie_start_link,
 	.stop_link = ks_pcie_stop_link,
 	.stop_link = ks_pcie_stop_link,
 	.link_up = ks_pcie_link_up,
 	.link_up = ks_pcie_link_up,
@@ -1130,6 +1147,157 @@ static const struct dw_pcie_ep_ops ks_pcie_am654_ep_ops = {
 	.get_features = &ks_pcie_am654_get_features,
 	.get_features = &ks_pcie_am654_get_features,
 };
 };
 
 
+static void ks_pcie_disable_outbound_atu(struct keystone_pcie *ks_pcie,
+					 phys_addr_t addr)
+{
+	u8 index;
+	u8 regions;
+	u64 cpu_addr;
+
+	index = (addr >> KS_PCIE_WIN_INDEX_SHIFT) & KS_PCIE_WIN_INDEX_MASK;
+	regions = ks_pcie->ob_win[index].no_of_regions;
+	cpu_addr = ks_pcie->ob_win[index].cpu_addr;
+
+	WARN_ON(cpu_addr != addr);
+
+	while (regions--) {
+		ks_pcie_app_writel(ks_pcie, OB_OFFSET_INDEX(index), 0x0);
+		clear_bit(index++, &ks_pcie->ob_window_map);
+	}
+}
+
+static void ks_pcie_disable_inbound_atu(struct keystone_pcie *ks_pcie,
+					int index)
+{
+	ks_pcie_app_writel(ks_pcie, IB_BAR(index), 0x0);
+	ks_pcie_app_writel(ks_pcie, IB_START_LO(index), 0x0);
+	ks_pcie_app_writel(ks_pcie, IB_START_HI(index), 0x0);
+	ks_pcie_app_writel(ks_pcie, IB_OFFSET(index), 0x0);
+}
+
+static void ks_pcie_disable_atu(struct dw_pcie *pci, phys_addr_t addr,
+				int index, enum dw_pcie_region_type type)
+{
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
+
+	switch (type) {
+	case DW_PCIE_REGION_INBOUND:
+		ks_pcie_disable_inbound_atu(ks_pcie, index);
+		break;
+	case DW_PCIE_REGION_OUTBOUND:
+		ks_pcie_disable_outbound_atu(ks_pcie, addr);
+		break;
+	default:
+		return;
+	}
+}
+
+static int ks_pcie_inbound_atu(struct dw_pcie *pci, u32 index,
+			       enum pci_barno bar, dma_addr_t cpu_addr)
+{
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
+	struct device *dev = pci->dev;
+
+	if (bar == BAR_0) {
+		dev_err(dev, "BAR_0 is reserved\n");
+		return -EINVAL;
+	}
+
+	ks_pcie_app_writel(ks_pcie, IB_BAR(index), bar);
+	ks_pcie_app_writel(ks_pcie, IB_OFFSET(index), lower_32_bits(cpu_addr));
+
+	return 0;
+}
+
+static int ks_pcie_check_free(struct keystone_pcie *ks_pcie, u8 index,
+			      u8 regions)
+{
+	while (regions--) {
+		if (test_bit(index++, &ks_pcie->ob_window_map))
+			return false;
+	}
+
+	return true;
+}
+
+static int ks_pcie_outbound_atu(struct dw_pcie *pci, u64 cpu_addr, u64 pci_addr,
+				size_t size)
+{
+	u8 index;
+	u8 regions;
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
+
+	index = (cpu_addr >> KS_PCIE_WIN_INDEX_SHIFT) & KS_PCIE_WIN_INDEX_MASK;
+	regions = ((size - 1) >> KS_PCIE_WIN_INDEX_SHIFT) + 1;
+
+	if (!ks_pcie_check_free(ks_pcie, index, regions))
+		return -ENOMEM;
+	if (index + regions > ks_pcie->num_viewport)
+		return -ENOMEM;
+
+	ks_pcie->ob_win[index].cpu_addr = cpu_addr;
+	ks_pcie->ob_win[index].no_of_regions = regions;
+
+	while (regions--) {
+		ks_pcie_app_writel(ks_pcie, OB_OFFSET_INDEX(index),
+				   lower_32_bits(pci_addr) | OB_ENABLEN);
+		ks_pcie_app_writel(ks_pcie, OB_OFFSET_HI(index),
+				   upper_32_bits(pci_addr));
+		set_bit(index++, &ks_pcie->ob_window_map);
+		pci_addr += KS_PCIE_WIN_SIZE;
+	}
+
+	return 0;
+}
+
+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,
+	.inbound_atu = ks_pcie_inbound_atu,
+	.outbound_atu = ks_pcie_outbound_atu,
+	.disable_atu = ks_pcie_disable_atu,
+};
+
+static void ks_pcie_ep_init(struct dw_pcie_ep *ep)
+{
+	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
+	int flags;
+	u32 val;
+
+	ep->page_size = KS_PCIE_WIN_SIZE;
+	flags = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_32;
+	dw_pcie_writel_dbi2(pci, PCI_BASE_ADDRESS_0, APP_ADDR_SPACE_0 - 1);
+	dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, flags);
+
+	ks_pcie_app_writel(ks_pcie, OB_SIZE, 0x0);
+	val = ks_pcie_app_readl(ks_pcie, CMD_STATUS);
+	ks_pcie_app_writel(ks_pcie, CMD_STATUS, val | OB_XLAT_EN_VAL |
+			   IB_XLAT_EN_VAL);
+}
+
+static const struct pci_epc_features ks_pcie_epc_features = {
+	.linkup_notifier = false,
+	.msi_capable = true,
+	.msix_capable = false,
+	.reserved_bar = 1 << BAR_0,
+};
+
+static const struct pci_epc_features*
+ks_pcie_get_features(struct dw_pcie_ep *ep)
+{
+	return &ks_pcie_epc_features;
+}
+
+static const struct dw_pcie_ep_ops ks_pcie_ep_ops = {
+	.ep_init = ks_pcie_ep_init,
+	.raise_irq = ks_pcie_am654_raise_irq,
+	.get_features = &ks_pcie_get_features,
+};
+
 static int __init ks_pcie_add_pcie_ep(struct keystone_pcie *ks_pcie,
 static int __init ks_pcie_add_pcie_ep(struct keystone_pcie *ks_pcie,
 				      struct platform_device *pdev)
 				      struct platform_device *pdev)
 {
 {
@@ -1148,6 +1316,14 @@ static int __init ks_pcie_add_pcie_ep(struct keystone_pcie *ks_pcie,
 	ep->phys_base = res->start;
 	ep->phys_base = res->start;
 	ep->addr_size = resource_size(res);
 	ep->addr_size = resource_size(res);
 
 
+	if (!ks_pcie->is_am6) {
+		ks_pcie->ob_win = devm_kzalloc(dev, sizeof(*ks_pcie->ob_win) *
+					       ks_pcie->num_viewport,
+					       GFP_KERNEL);
+		if (!ks_pcie->ob_win)
+			return -ENOMEM;
+	}
+
 	ret = dw_pcie_ep_init(ep);
 	ret = dw_pcie_ep_init(ep);
 	if (ret) {
 	if (ret) {
 		dev_err(dev, "failed to initialize endpoint\n");
 		dev_err(dev, "failed to initialize endpoint\n");
@@ -1200,7 +1376,7 @@ err_phy:
 	return ret;
 	return ret;
 }
 }
 
 
-static int ks_pcie_set_mode(struct device *dev)
+static int ks_pcie_set_mode(struct device *dev, enum dw_pcie_device_mode mode)
 {
 {
 	struct device_node *np = dev->of_node;
 	struct device_node *np = dev->of_node;
 	struct regmap *syscon;
 	struct regmap *syscon;
@@ -1213,7 +1389,18 @@ static int ks_pcie_set_mode(struct device *dev)
 		return 0;
 		return 0;
 
 
 	mask = KS_PCIE_DEV_TYPE_MASK | KS_PCIE_SYSCLOCKOUTEN;
 	mask = KS_PCIE_DEV_TYPE_MASK | KS_PCIE_SYSCLOCKOUTEN;
-	val = KS_PCIE_DEV_TYPE(RC) | KS_PCIE_SYSCLOCKOUTEN;
+
+	switch (mode) {
+	case DW_PCIE_RC_TYPE:
+		val = KS_PCIE_DEV_TYPE(RC) | KS_PCIE_SYSCLOCKOUTEN;
+		break;
+	case DW_PCIE_EP_TYPE:
+		val = KS_PCIE_DEV_TYPE(EP);
+		break;
+	default:
+		dev_err(dev, "INVALID device type %d\n", mode);
+		return -EINVAL;
+	}
 
 
 	ret = regmap_update_bits(syscon, 0, mask, val);
 	ret = regmap_update_bits(syscon, 0, mask, val);
 	if (ret) {
 	if (ret) {
@@ -1291,6 +1478,12 @@ static const struct ks_pcie_of_data ks_pcie_rc_of_data = {
 	.version = 0x365A,
 	.version = 0x365A,
 };
 };
 
 
+static const struct ks_pcie_of_data ks_pcie_ep_of_data = {
+	.ep_ops = &ks_pcie_ep_ops,
+	.mode = DW_PCIE_EP_TYPE,
+	.version = 0x365A,
+};
+
 static const struct ks_pcie_of_data ks_pcie_am654_rc_of_data = {
 static const struct ks_pcie_of_data ks_pcie_am654_rc_of_data = {
 	.host_ops = &ks_pcie_am654_host_ops,
 	.host_ops = &ks_pcie_am654_host_ops,
 	.mode = DW_PCIE_RC_TYPE,
 	.mode = DW_PCIE_RC_TYPE,
@@ -1309,6 +1502,10 @@ static const struct of_device_id ks_pcie_of_match[] = {
 		.data = &ks_pcie_rc_of_data,
 		.data = &ks_pcie_rc_of_data,
 		.compatible = "ti,keystone-pcie",
 		.compatible = "ti,keystone-pcie",
 	},
 	},
+	{
+		.data = &ks_pcie_ep_of_data,
+		.compatible = "ti,keystone-pcie-ep",
+	},
 	{
 	{
 		.data = &ks_pcie_am654_rc_of_data,
 		.data = &ks_pcie_am654_rc_of_data,
 		.compatible = "ti,am654-pcie-rc",
 		.compatible = "ti,am654-pcie-rc",
@@ -1376,13 +1573,17 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
 	if (IS_ERR(base))
 	if (IS_ERR(base))
 		return PTR_ERR(base);
 		return PTR_ERR(base);
 
 
-	if (of_device_is_compatible(np, "ti,am654-pcie-rc"))
+	if (of_device_is_compatible(np, "ti,am654-pcie-rc") ||
+	    of_device_is_compatible(np, "ti,am654-pcie-ep"))
 		ks_pcie->is_am6 = true;
 		ks_pcie->is_am6 = true;
 
 
 	pci->dbi_base = base;
 	pci->dbi_base = base;
 	pci->dbi_base2 = base;
 	pci->dbi_base2 = base;
 	pci->dev = dev;
 	pci->dev = dev;
-	pci->ops = &ks_pcie_dw_pcie_ops;
+	if (ks_pcie->is_am6)
+		pci->ops = &ks_pcie_am654_dw_pcie_ops;
+	else
+		pci->ops = &ks_pcie_dw_pcie_ops;
 	pci->version = version;
 	pci->version = version;
 
 
 	irq = platform_get_irq(pdev, 0);
 	irq = platform_get_irq(pdev, 0);
@@ -1472,7 +1673,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
 		if (ret < 0)
 		if (ret < 0)
 			goto err_get_sync;
 			goto err_get_sync;
 	} else {
 	} else {
-		ret = ks_pcie_set_mode(dev);
+		ret = ks_pcie_set_mode(dev, mode);
 		if (ret < 0)
 		if (ret < 0)
 			goto err_get_sync;
 			goto err_get_sync;
 	}
 	}
@@ -1521,6 +1722,13 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
 			goto err_get_sync;
 			goto err_get_sync;
 		}
 		}
 
 
+		ret = of_property_read_u32(np, "num-ob-windows", &num_viewport);
+		if (ret < 0) {
+			dev_err(dev, "unable to read *num-viewport* property\n");
+			goto err_get_sync;
+		}
+
+		ks_pcie->num_viewport = num_viewport;
 		pci->ep.ops = ep_ops;
 		pci->ep.ops = ep_ops;
 		ret = ks_pcie_add_pcie_ep(ks_pcie, pdev);
 		ret = ks_pcie_add_pcie_ep(ks_pcie, pdev);
 		if (ret < 0)
 		if (ret < 0)