All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFT v2 0/4] pci: add common Designware PCIe functions and support Amlogic Meson PCIe controller
@ 2021-03-25 14:49 ` Neil Armstrong
  0 siblings, 0 replies; 26+ messages in thread
From: Neil Armstrong @ 2021-03-25 14:49 UTC (permalink / raw)
  To: u-boot

With the introduction of pcie_dw_rockchip, and need to support the DW PCIe in the
Amlogic AXG & G12 SoCs, most of the DW PCIe helpers would be duplicated.

This introduce a "common" DW PCIe helpers file with common code merged from the
dw_ti and dw_rockchip drivers and adapted to fit with the upcoming dw_meson.

The following changes will switch the dw_ti and dw_rockchip, and introduce a new
driver to support the Amlogic AXG & G12 SoCs using these new common helpers.

The dw_meson has been validated, but the dw_ti and dw_rockchip would need testing
on hardware to validate nothing has been broken.

Changes since v1:
- added prefetch memory region support
- switched to __iomem
- fixed circular dependency for PCI_KEYSTONE

Neil Armstrong (4):
  pci: add common Designware PCIe functions
  pci: pcie_dw_ti: migrate to common Designware PCIe functions
  pci: pcie_dw_rockchip: migrate to common Designware PCIe functions
  pci: add Amlogic Meson Designware PCIe controller

 drivers/pci/Kconfig            |  16 +-
 drivers/pci/Makefile           |   2 +
 drivers/pci/pcie_dw_common.c   | 366 +++++++++++++++++++++++++
 drivers/pci/pcie_dw_common.h   | 155 +++++++++++
 drivers/pci/pcie_dw_meson.c    | 459 ++++++++++++++++++++++++++++++++
 drivers/pci/pcie_dw_rockchip.c | 472 ++-------------------------------
 drivers/pci/pcie_dw_ti.c       | 444 +++----------------------------
 7 files changed, 1062 insertions(+), 852 deletions(-)
 create mode 100644 drivers/pci/pcie_dw_common.c
 create mode 100644 drivers/pci/pcie_dw_common.h
 create mode 100644 drivers/pci/pcie_dw_meson.c

-- 
2.25.1

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH RFT v2 0/4] pci: add common Designware PCIe functions and support Amlogic Meson PCIe controller
@ 2021-03-25 14:49 ` Neil Armstrong
  0 siblings, 0 replies; 26+ messages in thread
From: Neil Armstrong @ 2021-03-25 14:49 UTC (permalink / raw)
  To: lokeshvutla, nsekhar, shawn.lin, bmeng.cn, green.wan
  Cc: u-boot, u-boot-amlogic, Neil Armstrong

With the introduction of pcie_dw_rockchip, and need to support the DW PCIe in the
Amlogic AXG & G12 SoCs, most of the DW PCIe helpers would be duplicated.

This introduce a "common" DW PCIe helpers file with common code merged from the
dw_ti and dw_rockchip drivers and adapted to fit with the upcoming dw_meson.

The following changes will switch the dw_ti and dw_rockchip, and introduce a new
driver to support the Amlogic AXG & G12 SoCs using these new common helpers.

The dw_meson has been validated, but the dw_ti and dw_rockchip would need testing
on hardware to validate nothing has been broken.

Changes since v1:
- added prefetch memory region support
- switched to __iomem
- fixed circular dependency for PCI_KEYSTONE

Neil Armstrong (4):
  pci: add common Designware PCIe functions
  pci: pcie_dw_ti: migrate to common Designware PCIe functions
  pci: pcie_dw_rockchip: migrate to common Designware PCIe functions
  pci: add Amlogic Meson Designware PCIe controller

 drivers/pci/Kconfig            |  16 +-
 drivers/pci/Makefile           |   2 +
 drivers/pci/pcie_dw_common.c   | 366 +++++++++++++++++++++++++
 drivers/pci/pcie_dw_common.h   | 155 +++++++++++
 drivers/pci/pcie_dw_meson.c    | 459 ++++++++++++++++++++++++++++++++
 drivers/pci/pcie_dw_rockchip.c | 472 ++-------------------------------
 drivers/pci/pcie_dw_ti.c       | 444 +++----------------------------
 7 files changed, 1062 insertions(+), 852 deletions(-)
 create mode 100644 drivers/pci/pcie_dw_common.c
 create mode 100644 drivers/pci/pcie_dw_common.h
 create mode 100644 drivers/pci/pcie_dw_meson.c

-- 
2.25.1


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH RFT v2 1/4] pci: add common Designware PCIe functions
  2021-03-25 14:49 ` Neil Armstrong
@ 2021-03-25 14:49   ` Neil Armstrong
  -1 siblings, 0 replies; 26+ messages in thread
From: Neil Armstrong @ 2021-03-25 14:49 UTC (permalink / raw)
  To: u-boot

With the introduction of pcie_dw_rockchip, and need to support the DW PCIe in the
Amlogic AXG & G12 SoCs, most of the DW PCIe helpers would be duplicated.

This introduce a "common" DW PCIe helpers file with common code merged from the
dw_ti and dw_rockchip drivers and adapted to fit with the upcoming dw_meson.

The following changes will switch the dw_ti and dw_rockchip to use these helpers.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/pci/Kconfig          |   4 +
 drivers/pci/Makefile         |   1 +
 drivers/pci/pcie_dw_common.c | 366 +++++++++++++++++++++++++++++++++++
 drivers/pci/pcie_dw_common.h | 155 +++++++++++++++
 4 files changed, 526 insertions(+)
 create mode 100644 drivers/pci/pcie_dw_common.c
 create mode 100644 drivers/pci/pcie_dw_common.h

diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index ba41787f64..ab5a5e7ed6 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -258,6 +258,10 @@ config PCI_MVEBU
 	  Say Y here if you want to enable PCIe controller support on
 	  Armada XP/38x SoCs.
 
+config PCIE_DW_COMMON
+	bool
+	select DM_PCI
+
 config PCI_KEYSTONE
 	bool "TI Keystone PCIe controller"
 	depends on DM_PCI
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 5ed94bc95c..e3ca8b27e4 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o \
 obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o
 obj-$(CONFIG_PCI_PHYTIUM) += pcie_phytium.o
 obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o
+obj-$(CONFIG_PCIE_DW_COMMON) += pcie_dw_common.o
 obj-$(CONFIG_PCI_KEYSTONE) += pcie_dw_ti.o
 obj-$(CONFIG_PCIE_MEDIATEK) += pcie_mediatek.o
 obj-$(CONFIG_PCIE_ROCKCHIP) += pcie_rockchip.o
diff --git a/drivers/pci/pcie_dw_common.c b/drivers/pci/pcie_dw_common.c
new file mode 100644
index 0000000000..7c92b7b754
--- /dev/null
+++ b/drivers/pci/pcie_dw_common.c
@@ -0,0 +1,366 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2021 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * Copyright (c) 2021 Rockchip, Inc.
+ *
+ * Copyright (C) 2018 Texas Instruments, Inc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <pci.h>
+#include <dm/device_compat.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include "pcie_dw_common.h"
+
+int pcie_dw_get_link_speed(struct pcie_dw *pci)
+{
+	return (readl(pci->dbi_base + PCIE_LINK_STATUS_REG) &
+		PCIE_LINK_STATUS_SPEED_MASK) >> PCIE_LINK_STATUS_SPEED_OFF;
+}
+
+int pcie_dw_get_link_width(struct pcie_dw *pci)
+{
+	return (readl(pci->dbi_base + PCIE_LINK_STATUS_REG) &
+		PCIE_LINK_STATUS_WIDTH_MASK) >> PCIE_LINK_STATUS_WIDTH_OFF;
+}
+
+static void dw_pcie_writel_ob_unroll(struct pcie_dw *pci, u32 index, u32 reg,
+				     u32 val)
+{
+	u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
+	void __iomem *base = pci->atu_base;
+
+	writel(val, base + offset + reg);
+}
+
+static u32 dw_pcie_readl_ob_unroll(struct pcie_dw *pci, u32 index, u32 reg)
+{
+	u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
+	void __iomem *base = pci->atu_base;
+
+	return readl(base + offset + reg);
+}
+
+/**
+ * pcie_dw_prog_outbound_atu_unroll() - Configure ATU for outbound accesses
+ *
+ * @pcie: Pointer to the PCI controller state
+ * @index: ATU region index
+ * @type: ATU accsess type
+ * @cpu_addr: the physical address for the translation entry
+ * @pci_addr: the pcie bus address for the translation entry
+ * @size: the size of the translation entry
+ *
+ * Return: 0 is successful and -1 is failure
+ */
+int pcie_dw_prog_outbound_atu_unroll(struct pcie_dw *pci, int index,
+				     int type, u64 cpu_addr,
+					     u64 pci_addr, u32 size)
+{
+	u32 retries, val;
+
+	dev_dbg(pci->dev, "ATU programmed with: index: %d, type: %d, cpu addr: %8llx, pci addr: %8llx, size: %8x\n",
+		index, type, cpu_addr, pci_addr, size);
+
+	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE,
+				 lower_32_bits(cpu_addr));
+	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE,
+				 upper_32_bits(cpu_addr));
+	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LIMIT,
+				 lower_32_bits(cpu_addr + size - 1));
+	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
+				 lower_32_bits(pci_addr));
+	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
+				 upper_32_bits(pci_addr));
+	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
+				 type);
+	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
+				 PCIE_ATU_ENABLE);
+
+	/*
+	 * Make sure ATU enable takes effect before any subsequent config
+	 * and I/O accesses.
+	 */
+	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
+		val = dw_pcie_readl_ob_unroll(pci, index,
+					      PCIE_ATU_UNR_REGION_CTRL2);
+		if (val & PCIE_ATU_ENABLE)
+			return 0;
+
+		udelay(LINK_WAIT_IATU);
+	}
+	dev_err(pci->dev, "outbound iATU is not being enabled\n");
+
+	return -1;
+}
+
+/**
+ * set_cfg_address() - Configure the PCIe controller config space access
+ *
+ * @pcie: Pointer to the PCI controller state
+ * @d: PCI device to access
+ * @where: Offset in the configuration space
+ *
+ * Configures the PCIe controller to access the configuration space of
+ * a specific PCIe device and returns the address to use for this
+ * access.
+ *
+ * Return: Address that can be used to access the configation space
+ *         of the requested device / offset
+ */
+static uintptr_t set_cfg_address(struct pcie_dw *pcie,
+				 pci_dev_t d, uint where)
+{
+	int bus = PCI_BUS(d) - pcie->first_busno;
+	uintptr_t va_address;
+	u32 atu_type;
+	int ret;
+
+	/* Use dbi_base for own configuration read and write */
+	if (!bus) {
+		va_address = (uintptr_t)pcie->dbi_base;
+		goto out;
+	}
+
+	if (bus == 1)
+		/*
+		 * For local bus whose primary bus number is root bridge,
+		 * change TLP Type field to 4.
+		 */
+		atu_type = PCIE_ATU_TYPE_CFG0;
+	else
+		/* Otherwise, change TLP Type field to 5. */
+		atu_type = PCIE_ATU_TYPE_CFG1;
+
+	/*
+	 * Not accessing root port configuration space?
+	 * Region #0 is used for Outbound CFG space access.
+	 * Direction = Outbound
+	 * Region Index = 0
+	 */
+	d = PCI_MASK_BUS(d);
+	d = PCI_ADD_BUS(bus, d);
+	ret = pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
+					       atu_type, (u64)pcie->cfg_base,
+						d << 8, pcie->cfg_size);
+	if (ret)
+		return (uintptr_t)ret;
+
+	va_address = (uintptr_t)pcie->cfg_base;
+
+out:
+	va_address += where & ~0x3;
+
+	return va_address;
+}
+
+/**
+ * pcie_dw_addr_valid() - Check for valid bus address
+ *
+ * @d: The PCI device to access
+ * @first_busno: Bus number of the PCIe controller root complex
+ *
+ * Return 1 (true) if the PCI device can be accessed by this controller.
+ *
+ * Return: 1 on valid, 0 on invalid
+ */
+static int pcie_dw_addr_valid(pci_dev_t d, int first_busno)
+{
+	if ((PCI_BUS(d) == first_busno) && (PCI_DEV(d) > 0))
+		return 0;
+	if ((PCI_BUS(d) == first_busno + 1) && (PCI_DEV(d) > 0))
+		return 0;
+
+	return 1;
+}
+
+/**
+ * pcie_dw_read_config() - Read from configuration space
+ *
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @valuep: A pointer at which to store the read value
+ * @size: Indicates the size of access to perform
+ *
+ * Read a value of size @size from offset @offset within the configuration
+ * space of the device identified by the bus, device & function numbers in @bdf
+ * on the PCI bus @bus.
+ *
+ * Return: 0 on success
+ */
+int pcie_dw_read_config(const struct udevice *bus, pci_dev_t bdf,
+			uint offset, ulong *valuep,
+			enum pci_size_t size)
+{
+	struct pcie_dw *pcie = dev_get_priv(bus);
+	uintptr_t va_address;
+	ulong value;
+
+	dev_dbg(pcie->dev, "PCIE CFG read: bdf=%2x:%2x:%2x ",
+		PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+
+	if (!pcie_dw_addr_valid(bdf, pcie->first_busno)) {
+		debug("- out of range\n");
+		*valuep = pci_get_ff(size);
+		return 0;
+	}
+
+	va_address = set_cfg_address(pcie, bdf, offset);
+
+	value = readl(va_address);
+
+	debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
+	*valuep = pci_conv_32_to_size(value, offset, size);
+
+	return pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
+						 PCIE_ATU_TYPE_IO, pcie->io.phys_start,
+						 pcie->io.bus_start, pcie->io.size);
+}
+
+/**
+ * pcie_dw_write_config() - Write to configuration space
+ *
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @value: The value to write
+ * @size: Indicates the size of access to perform
+ *
+ * Write the value @value of size @size from offset @offset within the
+ * configuration space of the device identified by the bus, device & function
+ * numbers in @bdf on the PCI bus @bus.
+ *
+ * Return: 0 on success
+ */
+int pcie_dw_write_config(struct udevice *bus, pci_dev_t bdf,
+			 uint offset, ulong value,
+			 enum pci_size_t size)
+{
+	struct pcie_dw *pcie = dev_get_priv(bus);
+	uintptr_t va_address;
+	ulong old;
+
+	dev_dbg(pcie->dev, "PCIE CFG write: (b,d,f)=(%2d,%2d,%2d) ",
+		PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+	dev_dbg(pcie->dev, "(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
+
+	if (!pcie_dw_addr_valid(bdf, pcie->first_busno)) {
+		debug("- out of range\n");
+		return 0;
+	}
+
+	va_address = set_cfg_address(pcie, bdf, offset);
+
+	old = readl(va_address);
+	value = pci_conv_size_to_32(old, value, offset, size);
+	writel(value, va_address);
+
+	return pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
+						 PCIE_ATU_TYPE_IO, pcie->io.phys_start,
+						 pcie->io.bus_start, pcie->io.size);
+}
+
+/**
+ * pcie_dw_setup_host() - Setup the PCIe controller for RC opertaion
+ *
+ * @pcie: Pointer to the PCI controller state
+ *
+ * Configure the host BARs of the PCIe controller root port so that
+ * PCI(e) devices may access the system memory.
+ */
+void pcie_dw_setup_host(struct pcie_dw *pci)
+{
+	struct udevice *ctlr = pci_get_controller(pci->dev);
+	struct pci_controller *hose = dev_get_uclass_priv(ctlr);
+	u32 ret;
+
+	if (!pci->atu_base)
+		pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
+
+	/* setup RC BARs */
+	writel(PCI_BASE_ADDRESS_MEM_TYPE_64,
+	       pci->dbi_base + PCI_BASE_ADDRESS_0);
+	writel(0x0, pci->dbi_base + PCI_BASE_ADDRESS_1);
+
+	/* setup interrupt pins */
+	clrsetbits_le32(pci->dbi_base + PCI_INTERRUPT_LINE,
+			0xff00, 0x100);
+
+	/* setup bus numbers */
+	clrsetbits_le32(pci->dbi_base + PCI_PRIMARY_BUS,
+			0xffffff, 0x00ff0100);
+
+	/* setup command register */
+	clrsetbits_le32(pci->dbi_base + PCI_PRIMARY_BUS,
+			0xffff,
+			PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+			PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
+
+	/* Enable write permission for the DBI read-only register */
+	dw_pcie_dbi_write_enable(pci, true);
+	/* program correct class for RC */
+	writew(PCI_CLASS_BRIDGE_PCI, pci->dbi_base + PCI_CLASS_DEVICE);
+	/* Better disable write permission right after the update */
+	dw_pcie_dbi_write_enable(pci, false);
+
+	setbits_le32(pci->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL,
+		     PORT_LOGIC_SPEED_CHANGE);
+
+	for (ret = 0; ret < hose->region_count; ret++) {
+		if (hose->regions[ret].flags == PCI_REGION_IO) {
+			pci->io.phys_start = hose->regions[ret].phys_start; /* IO base */
+			pci->io.bus_start = hose->regions[ret].bus_start;  /* IO_bus_addr */
+			pci->io.size = hose->regions[ret].size;      /* IO size */
+		} else if (hose->regions[ret].flags == PCI_REGION_MEM) {
+			pci->mem.phys_start = hose->regions[ret].phys_start; /* MEM base */
+			pci->mem.bus_start = hose->regions[ret].bus_start;  /* MEM_bus_addr */
+			pci->mem.size = hose->regions[ret].size;	    /* MEM size */
+		} else if (hose->regions[ret].flags == PCI_REGION_PREFETCH) {
+			pci->prefetch.phys_start = hose->regions[ret].phys_start; /* PREFETCH base */
+			pci->prefetch.bus_start = hose->regions[ret].bus_start;  /* PREFETCH_bus_addr */
+			pci->prefetch.size = hose->regions[ret].size;	    /* PREFETCH size */
+		} else if (hose->regions[ret].flags == PCI_REGION_SYS_MEMORY) {
+			pci->cfg_base = (void *)(pci->io.phys_start - pci->io.size);
+			pci->cfg_size = pci->io.size;
+		} else {
+			dev_err(pci->dev, "invalid flags type!\n");
+		}
+	}
+
+	dev_dbg(pci->dev, "Config space: [0x%p - 0x%p, size 0x%llx]\n",
+		pci->cfg_base, pci->cfg_base + pci->cfg_size,
+		pci->cfg_size);
+
+	dev_dbg(pci->dev, "IO space: [0x%llx - 0x%llx, size 0x%lx]\n",
+		pci->io.phys_start, pci->io.phys_start + pci->io.size,
+		pci->io.size);
+
+	dev_dbg(pci->dev, "IO bus:   [0x%lx - 0x%lx, size 0x%lx]\n",
+		pci->io.bus_start, pci->io.bus_start + pci->io.size,
+		pci->io.size);
+
+	dev_dbg(pci->dev, "MEM space: [0x%llx - 0x%llx, size 0x%lx]\n",
+		pci->mem.phys_start, pci->mem.phys_start + pci->mem.size,
+		pci->mem.size);
+
+	dev_dbg(pci->dev, "MEM bus:   [0x%lx - 0x%lx, size 0x%lx]\n",
+		pci->mem.bus_start, pci->mem.bus_start + pci->mem.size,
+		pci->mem.size);
+
+	if (pci->prefetch.size) {
+		dev_dbg(pci->dev, "PREFETCH space: [0x%llx - 0x%llx, size 0x%lx]\n",
+			pci->prefetch.phys_start, pci->prefetch.phys_start + pci->prefetch.size,
+			pci->prefetch.size);
+
+		dev_dbg(pci->dev, "PREFETCH bus:   [0x%lx - 0x%lx, size 0x%lx]\n",
+			pci->prefetch.bus_start, pci->prefetch.bus_start + pci->prefetch.size,
+			pci->prefetch.size);
+	}
+}
+
diff --git a/drivers/pci/pcie_dw_common.h b/drivers/pci/pcie_dw_common.h
new file mode 100644
index 0000000000..6b701645af
--- /dev/null
+++ b/drivers/pci/pcie_dw_common.h
@@ -0,0 +1,155 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2021 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * Copyright (c) 2021 Rockchip, Inc.
+ *
+ * Copyright (C) 2018 Texas Instruments, Inc
+ */
+
+#ifndef PCIE_DW_COMMON_H
+#define PCIE_DW_COMMON_H
+
+#define DEFAULT_DBI_ATU_OFFSET (0x3 << 20)
+
+/* PCI DBICS registers */
+#define PCIE_LINK_STATUS_REG		0x80
+#define PCIE_LINK_STATUS_SPEED_OFF	16
+#define PCIE_LINK_STATUS_SPEED_MASK	(0xf << PCIE_LINK_STATUS_SPEED_OFF)
+#define PCIE_LINK_STATUS_WIDTH_OFF	20
+#define PCIE_LINK_STATUS_WIDTH_MASK	(0xf << PCIE_LINK_STATUS_WIDTH_OFF)
+
+/*
+ * iATU Unroll-specific register definitions
+ * From 4.80 core version the address translation will be made by unroll.
+ * The registers are offset from atu_base
+ */
+#define PCIE_ATU_UNR_REGION_CTRL1	0x00
+#define PCIE_ATU_UNR_REGION_CTRL2	0x04
+#define PCIE_ATU_UNR_LOWER_BASE		0x08
+#define PCIE_ATU_UNR_UPPER_BASE		0x0c
+#define PCIE_ATU_UNR_LIMIT		0x10
+#define PCIE_ATU_UNR_LOWER_TARGET	0x14
+#define PCIE_ATU_UNR_UPPER_TARGET	0x18
+
+#define PCIE_ATU_REGION_INDEX1		(0x1 << 0)
+#define PCIE_ATU_REGION_INDEX0		(0x0 << 0)
+#define PCIE_ATU_TYPE_MEM		(0x0 << 0)
+#define PCIE_ATU_TYPE_IO		(0x2 << 0)
+#define PCIE_ATU_TYPE_CFG0		(0x4 << 0)
+#define PCIE_ATU_TYPE_CFG1		(0x5 << 0)
+#define PCIE_ATU_ENABLE			(0x1 << 31)
+#define PCIE_ATU_BAR_MODE_ENABLE	(0x1 << 30)
+#define PCIE_ATU_BUS(x)			(((x) & 0xff) << 24)
+#define PCIE_ATU_DEV(x)			(((x) & 0x1f) << 19)
+#define PCIE_ATU_FUNC(x)		(((x) & 0x7) << 16)
+
+/* Register address builder */
+#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region)	((region) << 9)
+
+/* Parameters for the waiting for iATU enabled routine */
+#define LINK_WAIT_MAX_IATU_RETRIES	5
+#define LINK_WAIT_IATU_US		10000
+
+/* PCI DBICS registers */
+#define PCIE_LINK_STATUS_REG		0x80
+#define PCIE_LINK_STATUS_SPEED_OFF	16
+#define PCIE_LINK_STATUS_SPEED_MASK	(0xf << PCIE_LINK_STATUS_SPEED_OFF)
+#define PCIE_LINK_STATUS_WIDTH_OFF	20
+#define PCIE_LINK_STATUS_WIDTH_MASK	(0xf << PCIE_LINK_STATUS_WIDTH_OFF)
+
+#define PCIE_LINK_CAPABILITY		0x7c
+#define PCIE_LINK_CTL_2			0xa0
+#define TARGET_LINK_SPEED_MASK		0xf
+#define LINK_SPEED_GEN_1		0x1
+#define LINK_SPEED_GEN_2		0x2
+#define LINK_SPEED_GEN_3		0x3
+
+/* Synopsys-specific PCIe configuration registers */
+#define PCIE_PORT_LINK_CONTROL		0x710
+#define PORT_LINK_DLL_LINK_EN		BIT(5)
+#define PORT_LINK_FAST_LINK_MODE	BIT(7)
+#define PORT_LINK_MODE_MASK		GENMASK(21, 16)
+#define PORT_LINK_MODE(n)		FIELD_PREP(PORT_LINK_MODE_MASK, n)
+#define PORT_LINK_MODE_1_LANES		PORT_LINK_MODE(0x1)
+#define PORT_LINK_MODE_2_LANES		PORT_LINK_MODE(0x3)
+#define PORT_LINK_MODE_4_LANES		PORT_LINK_MODE(0x7)
+#define PORT_LINK_MODE_8_LANES		PORT_LINK_MODE(0xf)
+
+#define PCIE_LINK_WIDTH_SPEED_CONTROL	0x80C
+#define PORT_LOGIC_N_FTS_MASK		GENMASK(7, 0)
+#define PORT_LOGIC_SPEED_CHANGE		BIT(17)
+#define PORT_LOGIC_LINK_WIDTH_MASK	GENMASK(12, 8)
+#define PORT_LOGIC_LINK_WIDTH(n)	FIELD_PREP(PORT_LOGIC_LINK_WIDTH_MASK, n)
+#define PORT_LOGIC_LINK_WIDTH_1_LANES	PORT_LOGIC_LINK_WIDTH(0x1)
+#define PORT_LOGIC_LINK_WIDTH_2_LANES	PORT_LOGIC_LINK_WIDTH(0x2)
+#define PORT_LOGIC_LINK_WIDTH_4_LANES	PORT_LOGIC_LINK_WIDTH(0x4)
+#define PORT_LOGIC_LINK_WIDTH_8_LANES	PORT_LOGIC_LINK_WIDTH(0x8)
+
+#define PCIE_MISC_CONTROL_1_OFF		0x8bc
+#define PCIE_DBI_RO_WR_EN		BIT(0)
+
+/* Parameters for the waiting for iATU enabled routine */
+#define LINK_WAIT_MAX_IATU_RETRIES	5
+#define LINK_WAIT_IATU			10000
+
+/**
+ * struct pcie_dw - DW PCIe controller state
+ *
+ * @dbi_base: The base address of dbi register space
+ * @cfg_base: The base address of configuration space
+ * @atu_base: The base address of ATU space
+ * @cfg_size: The size of the configuration space which is needed
+ *            as it gets written into the PCIE_ATU_LIMIT register
+ * @first_busno: This driver supports multiple PCIe controllers.
+ *               first_busno stores the bus number of the PCIe root-port
+ *               number which may vary depending on the PCIe setup
+ *               (PEX switches etc).
+ * @io: The IO space for EP's BAR
+ * @mem: The memory space for EP's BAR
+ * @prefetch: The prefetch space for EP's BAR
+ */
+struct pcie_dw {
+	struct udevice	*dev;
+	void __iomem *dbi_base;
+	void __iomem *cfg_base;
+	void __iomem *atu_base;
+	fdt_size_t cfg_size;
+
+	int first_busno;
+
+	/* IO, MEM & PREFETCH PCI regions */
+	struct pci_region io;
+	struct pci_region mem;
+	struct pci_region prefetch;
+};
+
+int pcie_dw_get_link_speed(struct pcie_dw *pci);
+
+int pcie_dw_get_link_width(struct pcie_dw *pci);
+
+int pcie_dw_prog_outbound_atu_unroll(struct pcie_dw *pci, int index, int type, u64 cpu_addr,
+				     u64 pci_addr, u32 size);
+
+int pcie_dw_read_config(const struct udevice *bus, pci_dev_t bdf, uint offset, ulong *valuep,
+			enum pci_size_t size);
+
+int pcie_dw_write_config(struct udevice *bus, pci_dev_t bdf, uint offset, ulong value,
+			 enum pci_size_t size);
+
+static inline void dw_pcie_dbi_write_enable(struct pcie_dw *pci, bool en)
+{
+	u32 val;
+
+	val = readl(pci->dbi_base + PCIE_MISC_CONTROL_1_OFF);
+	if (en)
+		val |= PCIE_DBI_RO_WR_EN;
+	else
+		val &= ~PCIE_DBI_RO_WR_EN;
+	writel(val, pci->dbi_base + PCIE_MISC_CONTROL_1_OFF);
+}
+
+void pcie_dw_setup_host(struct pcie_dw *pci);
+
+#endif
-- 
2.25.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH RFT v2 1/4] pci: add common Designware PCIe functions
@ 2021-03-25 14:49   ` Neil Armstrong
  0 siblings, 0 replies; 26+ messages in thread
From: Neil Armstrong @ 2021-03-25 14:49 UTC (permalink / raw)
  To: lokeshvutla, nsekhar, shawn.lin, bmeng.cn, green.wan
  Cc: u-boot, u-boot-amlogic, Neil Armstrong

With the introduction of pcie_dw_rockchip, and need to support the DW PCIe in the
Amlogic AXG & G12 SoCs, most of the DW PCIe helpers would be duplicated.

This introduce a "common" DW PCIe helpers file with common code merged from the
dw_ti and dw_rockchip drivers and adapted to fit with the upcoming dw_meson.

The following changes will switch the dw_ti and dw_rockchip to use these helpers.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/pci/Kconfig          |   4 +
 drivers/pci/Makefile         |   1 +
 drivers/pci/pcie_dw_common.c | 366 +++++++++++++++++++++++++++++++++++
 drivers/pci/pcie_dw_common.h | 155 +++++++++++++++
 4 files changed, 526 insertions(+)
 create mode 100644 drivers/pci/pcie_dw_common.c
 create mode 100644 drivers/pci/pcie_dw_common.h

diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index ba41787f64..ab5a5e7ed6 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -258,6 +258,10 @@ config PCI_MVEBU
 	  Say Y here if you want to enable PCIe controller support on
 	  Armada XP/38x SoCs.
 
+config PCIE_DW_COMMON
+	bool
+	select DM_PCI
+
 config PCI_KEYSTONE
 	bool "TI Keystone PCIe controller"
 	depends on DM_PCI
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 5ed94bc95c..e3ca8b27e4 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o \
 obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o
 obj-$(CONFIG_PCI_PHYTIUM) += pcie_phytium.o
 obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o
+obj-$(CONFIG_PCIE_DW_COMMON) += pcie_dw_common.o
 obj-$(CONFIG_PCI_KEYSTONE) += pcie_dw_ti.o
 obj-$(CONFIG_PCIE_MEDIATEK) += pcie_mediatek.o
 obj-$(CONFIG_PCIE_ROCKCHIP) += pcie_rockchip.o
diff --git a/drivers/pci/pcie_dw_common.c b/drivers/pci/pcie_dw_common.c
new file mode 100644
index 0000000000..7c92b7b754
--- /dev/null
+++ b/drivers/pci/pcie_dw_common.c
@@ -0,0 +1,366 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2021 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * Copyright (c) 2021 Rockchip, Inc.
+ *
+ * Copyright (C) 2018 Texas Instruments, Inc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <pci.h>
+#include <dm/device_compat.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include "pcie_dw_common.h"
+
+int pcie_dw_get_link_speed(struct pcie_dw *pci)
+{
+	return (readl(pci->dbi_base + PCIE_LINK_STATUS_REG) &
+		PCIE_LINK_STATUS_SPEED_MASK) >> PCIE_LINK_STATUS_SPEED_OFF;
+}
+
+int pcie_dw_get_link_width(struct pcie_dw *pci)
+{
+	return (readl(pci->dbi_base + PCIE_LINK_STATUS_REG) &
+		PCIE_LINK_STATUS_WIDTH_MASK) >> PCIE_LINK_STATUS_WIDTH_OFF;
+}
+
+static void dw_pcie_writel_ob_unroll(struct pcie_dw *pci, u32 index, u32 reg,
+				     u32 val)
+{
+	u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
+	void __iomem *base = pci->atu_base;
+
+	writel(val, base + offset + reg);
+}
+
+static u32 dw_pcie_readl_ob_unroll(struct pcie_dw *pci, u32 index, u32 reg)
+{
+	u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
+	void __iomem *base = pci->atu_base;
+
+	return readl(base + offset + reg);
+}
+
+/**
+ * pcie_dw_prog_outbound_atu_unroll() - Configure ATU for outbound accesses
+ *
+ * @pcie: Pointer to the PCI controller state
+ * @index: ATU region index
+ * @type: ATU accsess type
+ * @cpu_addr: the physical address for the translation entry
+ * @pci_addr: the pcie bus address for the translation entry
+ * @size: the size of the translation entry
+ *
+ * Return: 0 is successful and -1 is failure
+ */
+int pcie_dw_prog_outbound_atu_unroll(struct pcie_dw *pci, int index,
+				     int type, u64 cpu_addr,
+					     u64 pci_addr, u32 size)
+{
+	u32 retries, val;
+
+	dev_dbg(pci->dev, "ATU programmed with: index: %d, type: %d, cpu addr: %8llx, pci addr: %8llx, size: %8x\n",
+		index, type, cpu_addr, pci_addr, size);
+
+	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE,
+				 lower_32_bits(cpu_addr));
+	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE,
+				 upper_32_bits(cpu_addr));
+	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LIMIT,
+				 lower_32_bits(cpu_addr + size - 1));
+	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
+				 lower_32_bits(pci_addr));
+	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
+				 upper_32_bits(pci_addr));
+	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
+				 type);
+	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
+				 PCIE_ATU_ENABLE);
+
+	/*
+	 * Make sure ATU enable takes effect before any subsequent config
+	 * and I/O accesses.
+	 */
+	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
+		val = dw_pcie_readl_ob_unroll(pci, index,
+					      PCIE_ATU_UNR_REGION_CTRL2);
+		if (val & PCIE_ATU_ENABLE)
+			return 0;
+
+		udelay(LINK_WAIT_IATU);
+	}
+	dev_err(pci->dev, "outbound iATU is not being enabled\n");
+
+	return -1;
+}
+
+/**
+ * set_cfg_address() - Configure the PCIe controller config space access
+ *
+ * @pcie: Pointer to the PCI controller state
+ * @d: PCI device to access
+ * @where: Offset in the configuration space
+ *
+ * Configures the PCIe controller to access the configuration space of
+ * a specific PCIe device and returns the address to use for this
+ * access.
+ *
+ * Return: Address that can be used to access the configation space
+ *         of the requested device / offset
+ */
+static uintptr_t set_cfg_address(struct pcie_dw *pcie,
+				 pci_dev_t d, uint where)
+{
+	int bus = PCI_BUS(d) - pcie->first_busno;
+	uintptr_t va_address;
+	u32 atu_type;
+	int ret;
+
+	/* Use dbi_base for own configuration read and write */
+	if (!bus) {
+		va_address = (uintptr_t)pcie->dbi_base;
+		goto out;
+	}
+
+	if (bus == 1)
+		/*
+		 * For local bus whose primary bus number is root bridge,
+		 * change TLP Type field to 4.
+		 */
+		atu_type = PCIE_ATU_TYPE_CFG0;
+	else
+		/* Otherwise, change TLP Type field to 5. */
+		atu_type = PCIE_ATU_TYPE_CFG1;
+
+	/*
+	 * Not accessing root port configuration space?
+	 * Region #0 is used for Outbound CFG space access.
+	 * Direction = Outbound
+	 * Region Index = 0
+	 */
+	d = PCI_MASK_BUS(d);
+	d = PCI_ADD_BUS(bus, d);
+	ret = pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
+					       atu_type, (u64)pcie->cfg_base,
+						d << 8, pcie->cfg_size);
+	if (ret)
+		return (uintptr_t)ret;
+
+	va_address = (uintptr_t)pcie->cfg_base;
+
+out:
+	va_address += where & ~0x3;
+
+	return va_address;
+}
+
+/**
+ * pcie_dw_addr_valid() - Check for valid bus address
+ *
+ * @d: The PCI device to access
+ * @first_busno: Bus number of the PCIe controller root complex
+ *
+ * Return 1 (true) if the PCI device can be accessed by this controller.
+ *
+ * Return: 1 on valid, 0 on invalid
+ */
+static int pcie_dw_addr_valid(pci_dev_t d, int first_busno)
+{
+	if ((PCI_BUS(d) == first_busno) && (PCI_DEV(d) > 0))
+		return 0;
+	if ((PCI_BUS(d) == first_busno + 1) && (PCI_DEV(d) > 0))
+		return 0;
+
+	return 1;
+}
+
+/**
+ * pcie_dw_read_config() - Read from configuration space
+ *
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @valuep: A pointer at which to store the read value
+ * @size: Indicates the size of access to perform
+ *
+ * Read a value of size @size from offset @offset within the configuration
+ * space of the device identified by the bus, device & function numbers in @bdf
+ * on the PCI bus @bus.
+ *
+ * Return: 0 on success
+ */
+int pcie_dw_read_config(const struct udevice *bus, pci_dev_t bdf,
+			uint offset, ulong *valuep,
+			enum pci_size_t size)
+{
+	struct pcie_dw *pcie = dev_get_priv(bus);
+	uintptr_t va_address;
+	ulong value;
+
+	dev_dbg(pcie->dev, "PCIE CFG read: bdf=%2x:%2x:%2x ",
+		PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+
+	if (!pcie_dw_addr_valid(bdf, pcie->first_busno)) {
+		debug("- out of range\n");
+		*valuep = pci_get_ff(size);
+		return 0;
+	}
+
+	va_address = set_cfg_address(pcie, bdf, offset);
+
+	value = readl(va_address);
+
+	debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
+	*valuep = pci_conv_32_to_size(value, offset, size);
+
+	return pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
+						 PCIE_ATU_TYPE_IO, pcie->io.phys_start,
+						 pcie->io.bus_start, pcie->io.size);
+}
+
+/**
+ * pcie_dw_write_config() - Write to configuration space
+ *
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @value: The value to write
+ * @size: Indicates the size of access to perform
+ *
+ * Write the value @value of size @size from offset @offset within the
+ * configuration space of the device identified by the bus, device & function
+ * numbers in @bdf on the PCI bus @bus.
+ *
+ * Return: 0 on success
+ */
+int pcie_dw_write_config(struct udevice *bus, pci_dev_t bdf,
+			 uint offset, ulong value,
+			 enum pci_size_t size)
+{
+	struct pcie_dw *pcie = dev_get_priv(bus);
+	uintptr_t va_address;
+	ulong old;
+
+	dev_dbg(pcie->dev, "PCIE CFG write: (b,d,f)=(%2d,%2d,%2d) ",
+		PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+	dev_dbg(pcie->dev, "(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
+
+	if (!pcie_dw_addr_valid(bdf, pcie->first_busno)) {
+		debug("- out of range\n");
+		return 0;
+	}
+
+	va_address = set_cfg_address(pcie, bdf, offset);
+
+	old = readl(va_address);
+	value = pci_conv_size_to_32(old, value, offset, size);
+	writel(value, va_address);
+
+	return pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
+						 PCIE_ATU_TYPE_IO, pcie->io.phys_start,
+						 pcie->io.bus_start, pcie->io.size);
+}
+
+/**
+ * pcie_dw_setup_host() - Setup the PCIe controller for RC opertaion
+ *
+ * @pcie: Pointer to the PCI controller state
+ *
+ * Configure the host BARs of the PCIe controller root port so that
+ * PCI(e) devices may access the system memory.
+ */
+void pcie_dw_setup_host(struct pcie_dw *pci)
+{
+	struct udevice *ctlr = pci_get_controller(pci->dev);
+	struct pci_controller *hose = dev_get_uclass_priv(ctlr);
+	u32 ret;
+
+	if (!pci->atu_base)
+		pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
+
+	/* setup RC BARs */
+	writel(PCI_BASE_ADDRESS_MEM_TYPE_64,
+	       pci->dbi_base + PCI_BASE_ADDRESS_0);
+	writel(0x0, pci->dbi_base + PCI_BASE_ADDRESS_1);
+
+	/* setup interrupt pins */
+	clrsetbits_le32(pci->dbi_base + PCI_INTERRUPT_LINE,
+			0xff00, 0x100);
+
+	/* setup bus numbers */
+	clrsetbits_le32(pci->dbi_base + PCI_PRIMARY_BUS,
+			0xffffff, 0x00ff0100);
+
+	/* setup command register */
+	clrsetbits_le32(pci->dbi_base + PCI_PRIMARY_BUS,
+			0xffff,
+			PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+			PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
+
+	/* Enable write permission for the DBI read-only register */
+	dw_pcie_dbi_write_enable(pci, true);
+	/* program correct class for RC */
+	writew(PCI_CLASS_BRIDGE_PCI, pci->dbi_base + PCI_CLASS_DEVICE);
+	/* Better disable write permission right after the update */
+	dw_pcie_dbi_write_enable(pci, false);
+
+	setbits_le32(pci->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL,
+		     PORT_LOGIC_SPEED_CHANGE);
+
+	for (ret = 0; ret < hose->region_count; ret++) {
+		if (hose->regions[ret].flags == PCI_REGION_IO) {
+			pci->io.phys_start = hose->regions[ret].phys_start; /* IO base */
+			pci->io.bus_start = hose->regions[ret].bus_start;  /* IO_bus_addr */
+			pci->io.size = hose->regions[ret].size;      /* IO size */
+		} else if (hose->regions[ret].flags == PCI_REGION_MEM) {
+			pci->mem.phys_start = hose->regions[ret].phys_start; /* MEM base */
+			pci->mem.bus_start = hose->regions[ret].bus_start;  /* MEM_bus_addr */
+			pci->mem.size = hose->regions[ret].size;	    /* MEM size */
+		} else if (hose->regions[ret].flags == PCI_REGION_PREFETCH) {
+			pci->prefetch.phys_start = hose->regions[ret].phys_start; /* PREFETCH base */
+			pci->prefetch.bus_start = hose->regions[ret].bus_start;  /* PREFETCH_bus_addr */
+			pci->prefetch.size = hose->regions[ret].size;	    /* PREFETCH size */
+		} else if (hose->regions[ret].flags == PCI_REGION_SYS_MEMORY) {
+			pci->cfg_base = (void *)(pci->io.phys_start - pci->io.size);
+			pci->cfg_size = pci->io.size;
+		} else {
+			dev_err(pci->dev, "invalid flags type!\n");
+		}
+	}
+
+	dev_dbg(pci->dev, "Config space: [0x%p - 0x%p, size 0x%llx]\n",
+		pci->cfg_base, pci->cfg_base + pci->cfg_size,
+		pci->cfg_size);
+
+	dev_dbg(pci->dev, "IO space: [0x%llx - 0x%llx, size 0x%lx]\n",
+		pci->io.phys_start, pci->io.phys_start + pci->io.size,
+		pci->io.size);
+
+	dev_dbg(pci->dev, "IO bus:   [0x%lx - 0x%lx, size 0x%lx]\n",
+		pci->io.bus_start, pci->io.bus_start + pci->io.size,
+		pci->io.size);
+
+	dev_dbg(pci->dev, "MEM space: [0x%llx - 0x%llx, size 0x%lx]\n",
+		pci->mem.phys_start, pci->mem.phys_start + pci->mem.size,
+		pci->mem.size);
+
+	dev_dbg(pci->dev, "MEM bus:   [0x%lx - 0x%lx, size 0x%lx]\n",
+		pci->mem.bus_start, pci->mem.bus_start + pci->mem.size,
+		pci->mem.size);
+
+	if (pci->prefetch.size) {
+		dev_dbg(pci->dev, "PREFETCH space: [0x%llx - 0x%llx, size 0x%lx]\n",
+			pci->prefetch.phys_start, pci->prefetch.phys_start + pci->prefetch.size,
+			pci->prefetch.size);
+
+		dev_dbg(pci->dev, "PREFETCH bus:   [0x%lx - 0x%lx, size 0x%lx]\n",
+			pci->prefetch.bus_start, pci->prefetch.bus_start + pci->prefetch.size,
+			pci->prefetch.size);
+	}
+}
+
diff --git a/drivers/pci/pcie_dw_common.h b/drivers/pci/pcie_dw_common.h
new file mode 100644
index 0000000000..6b701645af
--- /dev/null
+++ b/drivers/pci/pcie_dw_common.h
@@ -0,0 +1,155 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2021 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * Copyright (c) 2021 Rockchip, Inc.
+ *
+ * Copyright (C) 2018 Texas Instruments, Inc
+ */
+
+#ifndef PCIE_DW_COMMON_H
+#define PCIE_DW_COMMON_H
+
+#define DEFAULT_DBI_ATU_OFFSET (0x3 << 20)
+
+/* PCI DBICS registers */
+#define PCIE_LINK_STATUS_REG		0x80
+#define PCIE_LINK_STATUS_SPEED_OFF	16
+#define PCIE_LINK_STATUS_SPEED_MASK	(0xf << PCIE_LINK_STATUS_SPEED_OFF)
+#define PCIE_LINK_STATUS_WIDTH_OFF	20
+#define PCIE_LINK_STATUS_WIDTH_MASK	(0xf << PCIE_LINK_STATUS_WIDTH_OFF)
+
+/*
+ * iATU Unroll-specific register definitions
+ * From 4.80 core version the address translation will be made by unroll.
+ * The registers are offset from atu_base
+ */
+#define PCIE_ATU_UNR_REGION_CTRL1	0x00
+#define PCIE_ATU_UNR_REGION_CTRL2	0x04
+#define PCIE_ATU_UNR_LOWER_BASE		0x08
+#define PCIE_ATU_UNR_UPPER_BASE		0x0c
+#define PCIE_ATU_UNR_LIMIT		0x10
+#define PCIE_ATU_UNR_LOWER_TARGET	0x14
+#define PCIE_ATU_UNR_UPPER_TARGET	0x18
+
+#define PCIE_ATU_REGION_INDEX1		(0x1 << 0)
+#define PCIE_ATU_REGION_INDEX0		(0x0 << 0)
+#define PCIE_ATU_TYPE_MEM		(0x0 << 0)
+#define PCIE_ATU_TYPE_IO		(0x2 << 0)
+#define PCIE_ATU_TYPE_CFG0		(0x4 << 0)
+#define PCIE_ATU_TYPE_CFG1		(0x5 << 0)
+#define PCIE_ATU_ENABLE			(0x1 << 31)
+#define PCIE_ATU_BAR_MODE_ENABLE	(0x1 << 30)
+#define PCIE_ATU_BUS(x)			(((x) & 0xff) << 24)
+#define PCIE_ATU_DEV(x)			(((x) & 0x1f) << 19)
+#define PCIE_ATU_FUNC(x)		(((x) & 0x7) << 16)
+
+/* Register address builder */
+#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region)	((region) << 9)
+
+/* Parameters for the waiting for iATU enabled routine */
+#define LINK_WAIT_MAX_IATU_RETRIES	5
+#define LINK_WAIT_IATU_US		10000
+
+/* PCI DBICS registers */
+#define PCIE_LINK_STATUS_REG		0x80
+#define PCIE_LINK_STATUS_SPEED_OFF	16
+#define PCIE_LINK_STATUS_SPEED_MASK	(0xf << PCIE_LINK_STATUS_SPEED_OFF)
+#define PCIE_LINK_STATUS_WIDTH_OFF	20
+#define PCIE_LINK_STATUS_WIDTH_MASK	(0xf << PCIE_LINK_STATUS_WIDTH_OFF)
+
+#define PCIE_LINK_CAPABILITY		0x7c
+#define PCIE_LINK_CTL_2			0xa0
+#define TARGET_LINK_SPEED_MASK		0xf
+#define LINK_SPEED_GEN_1		0x1
+#define LINK_SPEED_GEN_2		0x2
+#define LINK_SPEED_GEN_3		0x3
+
+/* Synopsys-specific PCIe configuration registers */
+#define PCIE_PORT_LINK_CONTROL		0x710
+#define PORT_LINK_DLL_LINK_EN		BIT(5)
+#define PORT_LINK_FAST_LINK_MODE	BIT(7)
+#define PORT_LINK_MODE_MASK		GENMASK(21, 16)
+#define PORT_LINK_MODE(n)		FIELD_PREP(PORT_LINK_MODE_MASK, n)
+#define PORT_LINK_MODE_1_LANES		PORT_LINK_MODE(0x1)
+#define PORT_LINK_MODE_2_LANES		PORT_LINK_MODE(0x3)
+#define PORT_LINK_MODE_4_LANES		PORT_LINK_MODE(0x7)
+#define PORT_LINK_MODE_8_LANES		PORT_LINK_MODE(0xf)
+
+#define PCIE_LINK_WIDTH_SPEED_CONTROL	0x80C
+#define PORT_LOGIC_N_FTS_MASK		GENMASK(7, 0)
+#define PORT_LOGIC_SPEED_CHANGE		BIT(17)
+#define PORT_LOGIC_LINK_WIDTH_MASK	GENMASK(12, 8)
+#define PORT_LOGIC_LINK_WIDTH(n)	FIELD_PREP(PORT_LOGIC_LINK_WIDTH_MASK, n)
+#define PORT_LOGIC_LINK_WIDTH_1_LANES	PORT_LOGIC_LINK_WIDTH(0x1)
+#define PORT_LOGIC_LINK_WIDTH_2_LANES	PORT_LOGIC_LINK_WIDTH(0x2)
+#define PORT_LOGIC_LINK_WIDTH_4_LANES	PORT_LOGIC_LINK_WIDTH(0x4)
+#define PORT_LOGIC_LINK_WIDTH_8_LANES	PORT_LOGIC_LINK_WIDTH(0x8)
+
+#define PCIE_MISC_CONTROL_1_OFF		0x8bc
+#define PCIE_DBI_RO_WR_EN		BIT(0)
+
+/* Parameters for the waiting for iATU enabled routine */
+#define LINK_WAIT_MAX_IATU_RETRIES	5
+#define LINK_WAIT_IATU			10000
+
+/**
+ * struct pcie_dw - DW PCIe controller state
+ *
+ * @dbi_base: The base address of dbi register space
+ * @cfg_base: The base address of configuration space
+ * @atu_base: The base address of ATU space
+ * @cfg_size: The size of the configuration space which is needed
+ *            as it gets written into the PCIE_ATU_LIMIT register
+ * @first_busno: This driver supports multiple PCIe controllers.
+ *               first_busno stores the bus number of the PCIe root-port
+ *               number which may vary depending on the PCIe setup
+ *               (PEX switches etc).
+ * @io: The IO space for EP's BAR
+ * @mem: The memory space for EP's BAR
+ * @prefetch: The prefetch space for EP's BAR
+ */
+struct pcie_dw {
+	struct udevice	*dev;
+	void __iomem *dbi_base;
+	void __iomem *cfg_base;
+	void __iomem *atu_base;
+	fdt_size_t cfg_size;
+
+	int first_busno;
+
+	/* IO, MEM & PREFETCH PCI regions */
+	struct pci_region io;
+	struct pci_region mem;
+	struct pci_region prefetch;
+};
+
+int pcie_dw_get_link_speed(struct pcie_dw *pci);
+
+int pcie_dw_get_link_width(struct pcie_dw *pci);
+
+int pcie_dw_prog_outbound_atu_unroll(struct pcie_dw *pci, int index, int type, u64 cpu_addr,
+				     u64 pci_addr, u32 size);
+
+int pcie_dw_read_config(const struct udevice *bus, pci_dev_t bdf, uint offset, ulong *valuep,
+			enum pci_size_t size);
+
+int pcie_dw_write_config(struct udevice *bus, pci_dev_t bdf, uint offset, ulong value,
+			 enum pci_size_t size);
+
+static inline void dw_pcie_dbi_write_enable(struct pcie_dw *pci, bool en)
+{
+	u32 val;
+
+	val = readl(pci->dbi_base + PCIE_MISC_CONTROL_1_OFF);
+	if (en)
+		val |= PCIE_DBI_RO_WR_EN;
+	else
+		val &= ~PCIE_DBI_RO_WR_EN;
+	writel(val, pci->dbi_base + PCIE_MISC_CONTROL_1_OFF);
+}
+
+void pcie_dw_setup_host(struct pcie_dw *pci);
+
+#endif
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH RFT v2 2/4] pci: pcie_dw_ti: migrate to common Designware PCIe functions
  2021-03-25 14:49 ` Neil Armstrong
@ 2021-03-25 14:49   ` Neil Armstrong
  -1 siblings, 0 replies; 26+ messages in thread
From: Neil Armstrong @ 2021-03-25 14:49 UTC (permalink / raw)
  To: u-boot

Migrate the dw_ti driver to use the common DW PCIe helpers.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/pci/Kconfig      |   2 +-
 drivers/pci/pcie_dw_ti.c | 444 ++++-----------------------------------
 2 files changed, 38 insertions(+), 408 deletions(-)

diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index ab5a5e7ed6..318d8fa37d 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -264,7 +264,7 @@ config PCIE_DW_COMMON
 
 config PCI_KEYSTONE
 	bool "TI Keystone PCIe controller"
-	depends on DM_PCI
+	select PCIE_DW_COMMON
 	help
 	  Say Y here if you want to enable PCI controller support on AM654 SoC.
 
diff --git a/drivers/pci/pcie_dw_ti.c b/drivers/pci/pcie_dw_ti.c
index 33a5c3cc20..4195a02de3 100644
--- a/drivers/pci/pcie_dw_ti.c
+++ b/drivers/pci/pcie_dw_ti.c
@@ -19,19 +19,13 @@
 #include <linux/delay.h>
 #include <linux/err.h>
 
+#include "pcie_dw_common.h"
+
 DECLARE_GLOBAL_DATA_PTR;
 
 #define PCIE_VENDORID_MASK	GENMASK(15, 0)
 #define PCIE_DEVICEID_SHIFT	16
 
-/* PCI DBICS registers */
-#define PCIE_CONFIG_BAR0		0x10
-#define PCIE_LINK_STATUS_REG		0x80
-#define PCIE_LINK_STATUS_SPEED_OFF	16
-#define PCIE_LINK_STATUS_SPEED_MASK	(0xf << PCIE_LINK_STATUS_SPEED_OFF)
-#define PCIE_LINK_STATUS_WIDTH_OFF	20
-#define PCIE_LINK_STATUS_WIDTH_MASK	(0xf << PCIE_LINK_STATUS_WIDTH_OFF)
-
 #define PCIE_LINK_CAPABILITY		0x7c
 #define PCIE_LINK_CTL_2			0xa0
 #define TARGET_LINK_SPEED_MASK		0xf
@@ -47,46 +41,12 @@ DECLARE_GLOBAL_DATA_PTR;
 #define PORT_LOGIC_LTSSM_STATE_MASK	0x1f
 #define PORT_LOGIC_LTSSM_STATE_L0	0x11
 
-#define PCIE_LINK_WIDTH_SPEED_CONTROL	0x80c
-#define PORT_LOGIC_SPEED_CHANGE		(0x1 << 17)
-
 #define PCIE_LINK_UP_TIMEOUT_MS		100
 
-/*
- * iATU Unroll-specific register definitions
- * From 4.80 core version the address translation will be made by unroll.
- * The registers are offset from atu_base
- */
-#define PCIE_ATU_UNR_REGION_CTRL1	0x00
-#define PCIE_ATU_UNR_REGION_CTRL2	0x04
-#define PCIE_ATU_UNR_LOWER_BASE		0x08
-#define PCIE_ATU_UNR_UPPER_BASE		0x0c
-#define PCIE_ATU_UNR_LIMIT		0x10
-#define PCIE_ATU_UNR_LOWER_TARGET	0x14
-#define PCIE_ATU_UNR_UPPER_TARGET	0x18
-
-#define PCIE_ATU_REGION_INDEX1		(0x1 << 0)
-#define PCIE_ATU_REGION_INDEX0		(0x0 << 0)
-#define PCIE_ATU_TYPE_MEM		(0x0 << 0)
-#define PCIE_ATU_TYPE_IO		(0x2 << 0)
-#define PCIE_ATU_TYPE_CFG0		(0x4 << 0)
-#define PCIE_ATU_TYPE_CFG1		(0x5 << 0)
-#define PCIE_ATU_ENABLE			(0x1 << 31)
-#define PCIE_ATU_BAR_MODE_ENABLE	(0x1 << 30)
-#define PCIE_ATU_BUS(x)			(((x) & 0xff) << 24)
-#define PCIE_ATU_DEV(x)			(((x) & 0x1f) << 19)
-#define PCIE_ATU_FUNC(x)		(((x) & 0x7) << 16)
-
-/* Register address builder */
-#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region)	((region) << 9)
-
 /* Offsets from App base */
 #define PCIE_CMD_STATUS			0x04
 #define LTSSM_EN_VAL			BIT(0)
 
-/* Parameters for the waiting for iATU enabled routine */
-#define LINK_WAIT_MAX_IATU_RETRIES	5
-#define LINK_WAIT_IATU			10000
 
 #define AM654_PCIE_DEV_TYPE_MASK	0x3
 #define EP				0x0
@@ -96,29 +56,13 @@ DECLARE_GLOBAL_DATA_PTR;
 /**
  * struct pcie_dw_ti - TI DW PCIe controller state
  *
+ * @pci: The common PCIe DW structure
  * @app_base: The base address of application register space
- * @dbics_base: The base address of dbics register space
- * @cfg_base: The base address of configuration space
- * @atu_base: The base address of ATU space
- * @cfg_size: The size of the configuration space which is needed
- *            as it gets written into the PCIE_ATU_LIMIT register
- * @first_busno: This driver supports multiple PCIe controllers.
- *               first_busno stores the bus number of the PCIe root-port
- *               number which may vary depending on the PCIe setup
- *               (PEX switches etc).
  */
 struct pcie_dw_ti {
+	/* Must be first member of the struct */
+	struct pcie_dw dw;
 	void *app_base;
-	void *dbi_base;
-	void *cfg_base;
-	void *atu_base;
-	fdt_size_t cfg_size;
-	int first_busno;
-	struct udevice *dev;
-
-	/* IO and MEM PCI regions */
-	struct pci_region io;
-	struct pci_region mem;
 };
 
 enum dw_pcie_device_mode {
@@ -128,261 +72,6 @@ enum dw_pcie_device_mode {
 	DW_PCIE_RC_TYPE,
 };
 
-static int pcie_dw_get_link_speed(struct pcie_dw_ti *pci)
-{
-	return (readl(pci->dbi_base + PCIE_LINK_STATUS_REG) &
-		PCIE_LINK_STATUS_SPEED_MASK) >> PCIE_LINK_STATUS_SPEED_OFF;
-}
-
-static int pcie_dw_get_link_width(struct pcie_dw_ti *pci)
-{
-	return (readl(pci->dbi_base + PCIE_LINK_STATUS_REG) &
-		PCIE_LINK_STATUS_WIDTH_MASK) >> PCIE_LINK_STATUS_WIDTH_OFF;
-}
-
-static void dw_pcie_writel_ob_unroll(struct pcie_dw_ti *pci, u32 index, u32 reg,
-				     u32 val)
-{
-	u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
-	void __iomem *base = pci->atu_base;
-
-	writel(val, base + offset + reg);
-}
-
-static u32 dw_pcie_readl_ob_unroll(struct pcie_dw_ti *pci, u32 index, u32 reg)
-{
-	u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
-	void __iomem *base = pci->atu_base;
-
-	return readl(base + offset + reg);
-}
-
-/**
- * pcie_dw_prog_outbound_atu_unroll() - Configure ATU for outbound accesses
- *
- * @pcie: Pointer to the PCI controller state
- * @index: ATU region index
- * @type: ATU accsess type
- * @cpu_addr: the physical address for the translation entry
- * @pci_addr: the pcie bus address for the translation entry
- * @size: the size of the translation entry
- */
-static void pcie_dw_prog_outbound_atu_unroll(struct pcie_dw_ti *pci, int index,
-					     int type, u64 cpu_addr,
-					     u64 pci_addr, u32 size)
-{
-	u32 retries, val;
-
-	debug("ATU programmed with: index: %d, type: %d, cpu addr: %8llx, pci addr: %8llx, size: %8x\n",
-	      index, type, cpu_addr, pci_addr, size);
-
-	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE,
-				 lower_32_bits(cpu_addr));
-	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE,
-				 upper_32_bits(cpu_addr));
-	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LIMIT,
-				 lower_32_bits(cpu_addr + size - 1));
-	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
-				 lower_32_bits(pci_addr));
-	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
-				 upper_32_bits(pci_addr));
-	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
-				 type);
-	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
-				 PCIE_ATU_ENABLE);
-
-	/*
-	 * Make sure ATU enable takes effect before any subsequent config
-	 * and I/O accesses.
-	 */
-	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
-		val = dw_pcie_readl_ob_unroll(pci, index,
-					      PCIE_ATU_UNR_REGION_CTRL2);
-		if (val & PCIE_ATU_ENABLE)
-			return;
-
-		udelay(LINK_WAIT_IATU);
-	}
-	dev_err(pci->dev, "outbound iATU is not being enabled\n");
-}
-
-/**
- * set_cfg_address() - Configure the PCIe controller config space access
- *
- * @pcie: Pointer to the PCI controller state
- * @d: PCI device to access
- * @where: Offset in the configuration space
- *
- * Configures the PCIe controller to access the configuration space of
- * a specific PCIe device and returns the address to use for this
- * access.
- *
- * Return: Address that can be used to access the configation space
- *         of the requested device / offset
- */
-static uintptr_t set_cfg_address(struct pcie_dw_ti *pcie,
-				 pci_dev_t d, uint where)
-{
-	int bus = PCI_BUS(d) - pcie->first_busno;
-	uintptr_t va_address;
-	u32 atu_type;
-
-	/* Use dbi_base for own configuration read and write */
-	if (!bus) {
-		va_address = (uintptr_t)pcie->dbi_base;
-		goto out;
-	}
-
-	if (bus == 1)
-		/* For local bus, change TLP Type field to 4. */
-		atu_type = PCIE_ATU_TYPE_CFG0;
-	else
-		/* Otherwise, change TLP Type field to 5. */
-		atu_type = PCIE_ATU_TYPE_CFG1;
-
-	/*
-	 * Not accessing root port configuration space?
-	 * Region #0 is used for Outbound CFG space access.
-	 * Direction = Outbound
-	 * Region Index = 0
-	 */
-	d = PCI_MASK_BUS(d);
-	d = PCI_ADD_BUS(bus, d);
-	pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
-					 atu_type, (u64)pcie->cfg_base,
-					 d << 8, pcie->cfg_size);
-
-	va_address = (uintptr_t)pcie->cfg_base;
-
-out:
-	va_address += where & ~0x3;
-
-	return va_address;
-}
-
-/**
- * pcie_dw_addr_valid() - Check for valid bus address
- *
- * @d: The PCI device to access
- * @first_busno: Bus number of the PCIe controller root complex
- *
- * Return 1 (true) if the PCI device can be accessed by this controller.
- *
- * Return: 1 on valid, 0 on invalid
- */
-static int pcie_dw_addr_valid(pci_dev_t d, int first_busno)
-{
-	if ((PCI_BUS(d) == first_busno) && (PCI_DEV(d) > 0))
-		return 0;
-	if ((PCI_BUS(d) == first_busno + 1) && (PCI_DEV(d) > 0))
-		return 0;
-
-	return 1;
-}
-
-/**
- * pcie_dw_ti_read_config() - Read from configuration space
- *
- * @bus: Pointer to the PCI bus
- * @bdf: Identifies the PCIe device to access
- * @offset: The offset into the device's configuration space
- * @valuep: A pointer at which to store the read value
- * @size: Indicates the size of access to perform
- *
- * Read a value of size @size from offset @offset within the configuration
- * space of the device identified by the bus, device & function numbers in @bdf
- * on the PCI bus @bus.
- *
- * Return: 0 on success
- */
-static int pcie_dw_ti_read_config(const struct udevice *bus, pci_dev_t bdf,
-				  uint offset, ulong *valuep,
-				  enum pci_size_t size)
-{
-	struct pcie_dw_ti *pcie = dev_get_priv(bus);
-	uintptr_t va_address;
-	ulong value;
-
-	debug("PCIE CFG read: bdf=%2x:%2x:%2x ",
-	      PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
-
-	if (!pcie_dw_addr_valid(bdf, pcie->first_busno)) {
-		debug("- out of range\n");
-		*valuep = pci_get_ff(size);
-		return 0;
-	}
-
-	va_address = set_cfg_address(pcie, bdf, offset);
-
-	value = readl(va_address);
-
-	debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
-	*valuep = pci_conv_32_to_size(value, offset, size);
-
-	pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
-					 PCIE_ATU_TYPE_IO, pcie->io.phys_start,
-					 pcie->io.bus_start, pcie->io.size);
-
-	return 0;
-}
-
-/**
- * pcie_dw_ti_write_config() - Write to configuration space
- *
- * @bus: Pointer to the PCI bus
- * @bdf: Identifies the PCIe device to access
- * @offset: The offset into the device's configuration space
- * @value: The value to write
- * @size: Indicates the size of access to perform
- *
- * Write the value @value of size @size from offset @offset within the
- * configuration space of the device identified by the bus, device & function
- * numbers in @bdf on the PCI bus @bus.
- *
- * Return: 0 on success
- */
-static int pcie_dw_ti_write_config(struct udevice *bus, pci_dev_t bdf,
-				   uint offset, ulong value,
-				   enum pci_size_t size)
-{
-	struct pcie_dw_ti *pcie = dev_get_priv(bus);
-	uintptr_t va_address;
-	ulong old;
-
-	debug("PCIE CFG write: (b,d,f)=(%2d,%2d,%2d) ",
-	      PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
-	debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
-
-	if (!pcie_dw_addr_valid(bdf, pcie->first_busno)) {
-		debug("- out of range\n");
-		return 0;
-	}
-
-	va_address = set_cfg_address(pcie, bdf, offset);
-
-	old = readl(va_address);
-	value = pci_conv_size_to_32(old, value, offset, size);
-	writel(value, va_address);
-
-	pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
-					 PCIE_ATU_TYPE_IO, pcie->io.phys_start,
-					 pcie->io.bus_start, pcie->io.size);
-
-	return 0;
-}
-
-static inline void dw_pcie_dbi_write_enable(struct pcie_dw_ti *pci, bool en)
-{
-	u32 val;
-
-	val = readl(pci->dbi_base + PCIE_MISC_CONTROL_1_OFF);
-	if (en)
-		val |= PCIE_DBI_RO_WR_EN;
-	else
-		val &= ~PCIE_DBI_RO_WR_EN;
-	writel(val, pci->dbi_base + PCIE_MISC_CONTROL_1_OFF);
-}
-
 /**
  * pcie_dw_configure() - Configure link capabilities and speed
  *
@@ -395,19 +84,19 @@ static void pcie_dw_configure(struct pcie_dw_ti *pci, u32 cap_speed)
 {
 	u32 val;
 
-	dw_pcie_dbi_write_enable(pci, true);
+	dw_pcie_dbi_write_enable(&pci->dw, true);
 
-	val = readl(pci->dbi_base + PCIE_LINK_CAPABILITY);
+	val = readl(pci->dw.dbi_base + PCIE_LINK_CAPABILITY);
 	val &= ~TARGET_LINK_SPEED_MASK;
 	val |= cap_speed;
-	writel(val, pci->dbi_base + PCIE_LINK_CAPABILITY);
+	writel(val, pci->dw.dbi_base + PCIE_LINK_CAPABILITY);
 
-	val = readl(pci->dbi_base + PCIE_LINK_CTL_2);
+	val = readl(pci->dw.dbi_base + PCIE_LINK_CTL_2);
 	val &= ~TARGET_LINK_SPEED_MASK;
 	val |= cap_speed;
-	writel(val, pci->dbi_base + PCIE_LINK_CTL_2);
+	writel(val, pci->dw.dbi_base + PCIE_LINK_CTL_2);
 
-	dw_pcie_dbi_write_enable(pci, false);
+	dw_pcie_dbi_write_enable(&pci->dw, false);
 }
 
 /**
@@ -421,7 +110,7 @@ static int is_link_up(struct pcie_dw_ti *pci)
 {
 	u32 val;
 
-	val = readl(pci->dbi_base + PCIE_PORT_DEBUG0);
+	val = readl(pci->dw.dbi_base + PCIE_PORT_DEBUG0);
 	val &= PORT_LOGIC_LTSSM_STATE_MASK;
 
 	return (val == PORT_LOGIC_LTSSM_STATE_L0);
@@ -477,56 +166,6 @@ static int pcie_dw_ti_pcie_link_up(struct pcie_dw_ti *pci, u32 cap_speed)
 	return 1;
 }
 
-/**
- * pcie_dw_setup_host() - Setup the PCIe controller for RC opertaion
- *
- * @pcie: Pointer to the PCI controller state
- *
- * Configure the host BARs of the PCIe controller root port so that
- * PCI(e) devices may access the system memory.
- */
-static void pcie_dw_setup_host(struct pcie_dw_ti *pci)
-{
-	u32 val;
-
-	/* setup RC BARs */
-	writel(PCI_BASE_ADDRESS_MEM_TYPE_64,
-	       pci->dbi_base + PCI_BASE_ADDRESS_0);
-	writel(0x0, pci->dbi_base + PCI_BASE_ADDRESS_1);
-
-	/* setup interrupt pins */
-	dw_pcie_dbi_write_enable(pci, true);
-	val = readl(pci->dbi_base + PCI_INTERRUPT_LINE);
-	val &= 0xffff00ff;
-	val |= 0x00000100;
-	writel(val, pci->dbi_base + PCI_INTERRUPT_LINE);
-	dw_pcie_dbi_write_enable(pci, false);
-
-	/* setup bus numbers */
-	val = readl(pci->dbi_base + PCI_PRIMARY_BUS);
-	val &= 0xff000000;
-	val |= 0x00ff0100;
-	writel(val, pci->dbi_base + PCI_PRIMARY_BUS);
-
-	/* setup command register */
-	val = readl(pci->dbi_base + PCI_COMMAND);
-	val &= 0xffff0000;
-	val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
-		PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
-	writel(val, pci->dbi_base + PCI_COMMAND);
-
-	/* Enable write permission for the DBI read-only register */
-	dw_pcie_dbi_write_enable(pci, true);
-	/* program correct class for RC */
-	writew(PCI_CLASS_BRIDGE_PCI, pci->dbi_base + PCI_CLASS_DEVICE);
-	/* Better disable write permission right after the update */
-	dw_pcie_dbi_write_enable(pci, false);
-
-	val = readl(pci->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
-	val |= PORT_LOGIC_SPEED_CHANGE;
-	writel(val, pci->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
-}
-
 static int pcie_am654_set_mode(struct pcie_dw_ti *pci,
 			       enum dw_pcie_device_mode mode)
 {
@@ -535,7 +174,7 @@ static int pcie_am654_set_mode(struct pcie_dw_ti *pci,
 	u32 mask;
 	int ret;
 
-	syscon = syscon_regmap_lookup_by_phandle(pci->dev,
+	syscon = syscon_regmap_lookup_by_phandle(pci->dw.dev,
 						 "ti,syscon-pcie-mode");
 	if (IS_ERR(syscon))
 		return 0;
@@ -550,13 +189,13 @@ static int pcie_am654_set_mode(struct pcie_dw_ti *pci,
 		val = EP;
 		break;
 	default:
-		dev_err(pci->dev, "INVALID device type %d\n", mode);
+		dev_err(pci->dw.dev, "INVALID device type %d\n", mode);
 		return -EINVAL;
 	}
 
 	ret = regmap_update_bits(syscon, 0, mask, val);
 	if (ret) {
-		dev_err(pci->dev, "failed to set pcie mode\n");
+		dev_err(pci->dw.dev, "failed to set pcie mode\n");
 		return ret;
 	}
 
@@ -569,7 +208,7 @@ static int pcie_dw_init_id(struct pcie_dw_ti *pci)
 	unsigned int id;
 	int ret;
 
-	devctrl_regs = syscon_regmap_lookup_by_phandle(pci->dev,
+	devctrl_regs = syscon_regmap_lookup_by_phandle(pci->dw.dev,
 						       "ti,syscon-pcie-id");
 	if (IS_ERR(devctrl_regs))
 		return PTR_ERR(devctrl_regs);
@@ -578,10 +217,10 @@ static int pcie_dw_init_id(struct pcie_dw_ti *pci)
 	if (ret)
 		return ret;
 
-	dw_pcie_dbi_write_enable(pci, true);
-	writew(id & PCIE_VENDORID_MASK, pci->dbi_base + PCI_VENDOR_ID);
-	writew(id >> PCIE_DEVICEID_SHIFT, pci->dbi_base + PCI_DEVICE_ID);
-	dw_pcie_dbi_write_enable(pci, false);
+	dw_pcie_dbi_write_enable(&pci->dw, true);
+	writew(id & PCIE_VENDORID_MASK, pci->dw.dbi_base + PCI_VENDOR_ID);
+	writew(id >> PCIE_DEVICEID_SHIFT, pci->dw.dbi_base + PCI_DEVICE_ID);
+	dw_pcie_dbi_write_enable(&pci->dw, false);
 
 	return 0;
 }
@@ -635,10 +274,10 @@ static int pcie_dw_ti_probe(struct udevice *dev)
 	generic_phy_init(&phy1);
 	generic_phy_power_on(&phy1);
 
-	pci->first_busno = dev_seq(dev);
-	pci->dev = dev;
+	pci->dw.first_busno = dev_seq(dev);
+	pci->dw.dev = dev;
 
-	pcie_dw_setup_host(pci);
+	pcie_dw_setup_host(&pci->dw);
 	pcie_dw_init_id(pci);
 
 	if (device_is_compatible(dev, "ti,am654-pcie-rc"))
@@ -650,23 +289,14 @@ static int pcie_dw_ti_probe(struct udevice *dev)
 	}
 
 	printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n", dev_seq(dev),
-	       pcie_dw_get_link_speed(pci),
-	       pcie_dw_get_link_width(pci),
+	       pcie_dw_get_link_speed(&pci->dw),
+	       pcie_dw_get_link_width(&pci->dw),
 	       hose->first_busno);
 
-	/* Store the IO and MEM windows settings for future use by the ATU */
-	pci->io.phys_start = hose->regions[0].phys_start; /* IO base */
-	pci->io.bus_start  = hose->regions[0].bus_start;  /* IO_bus_addr */
-	pci->io.size	    = hose->regions[0].size;	   /* IO size */
-
-	pci->mem.phys_start = hose->regions[1].phys_start; /* MEM base */
-	pci->mem.bus_start  = hose->regions[1].bus_start;  /* MEM_bus_addr */
-	pci->mem.size	     = hose->regions[1].size;	    /* MEM size */
-
-	pcie_dw_prog_outbound_atu_unroll(pci, PCIE_ATU_REGION_INDEX0,
+	pcie_dw_prog_outbound_atu_unroll(&pci->dw, PCIE_ATU_REGION_INDEX0,
 					 PCIE_ATU_TYPE_MEM,
-					 pci->mem.phys_start,
-					 pci->mem.bus_start, pci->mem.size);
+					 pci->dw.mem.phys_start,
+					 pci->dw.mem.bus_start, pci->dw.mem.size);
 
 	return 0;
 }
@@ -687,19 +317,19 @@ static int pcie_dw_ti_of_to_plat(struct udevice *dev)
 	struct pcie_dw_ti *pcie = dev_get_priv(dev);
 
 	/* Get the controller base address */
-	pcie->dbi_base = (void *)dev_read_addr_name(dev, "dbics");
-	if ((fdt_addr_t)pcie->dbi_base == FDT_ADDR_T_NONE)
+	pcie->dw.dbi_base = (void *)dev_read_addr_name(dev, "dbics");
+	if ((fdt_addr_t)pcie->dw.dbi_base == FDT_ADDR_T_NONE)
 		return -EINVAL;
 
 	/* Get the config space base address and size */
-	pcie->cfg_base = (void *)dev_read_addr_size_name(dev, "config",
-							 &pcie->cfg_size);
-	if ((fdt_addr_t)pcie->cfg_base == FDT_ADDR_T_NONE)
+	pcie->dw.cfg_base = (void *)dev_read_addr_size_name(dev, "config",
+							 &pcie->dw.cfg_size);
+	if ((fdt_addr_t)pcie->dw.cfg_base == FDT_ADDR_T_NONE)
 		return -EINVAL;
 
 	/* Get the iATU base address and size */
-	pcie->atu_base = (void *)dev_read_addr_name(dev, "atu");
-	if ((fdt_addr_t)pcie->atu_base == FDT_ADDR_T_NONE)
+	pcie->dw.atu_base = (void *)dev_read_addr_name(dev, "atu");
+	if ((fdt_addr_t)pcie->dw.atu_base == FDT_ADDR_T_NONE)
 		return -EINVAL;
 
 	/* Get the app base address and size */
@@ -711,8 +341,8 @@ static int pcie_dw_ti_of_to_plat(struct udevice *dev)
 }
 
 static const struct dm_pci_ops pcie_dw_ti_ops = {
-	.read_config	= pcie_dw_ti_read_config,
-	.write_config	= pcie_dw_ti_write_config,
+	.read_config	= pcie_dw_read_config,
+	.write_config	= pcie_dw_write_config,
 };
 
 static const struct udevice_id pcie_dw_ti_ids[] = {
-- 
2.25.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH RFT v2 2/4] pci: pcie_dw_ti: migrate to common Designware PCIe functions
@ 2021-03-25 14:49   ` Neil Armstrong
  0 siblings, 0 replies; 26+ messages in thread
From: Neil Armstrong @ 2021-03-25 14:49 UTC (permalink / raw)
  To: lokeshvutla, nsekhar, shawn.lin, bmeng.cn, green.wan
  Cc: u-boot, u-boot-amlogic, Neil Armstrong

Migrate the dw_ti driver to use the common DW PCIe helpers.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/pci/Kconfig      |   2 +-
 drivers/pci/pcie_dw_ti.c | 444 ++++-----------------------------------
 2 files changed, 38 insertions(+), 408 deletions(-)

diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index ab5a5e7ed6..318d8fa37d 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -264,7 +264,7 @@ config PCIE_DW_COMMON
 
 config PCI_KEYSTONE
 	bool "TI Keystone PCIe controller"
-	depends on DM_PCI
+	select PCIE_DW_COMMON
 	help
 	  Say Y here if you want to enable PCI controller support on AM654 SoC.
 
diff --git a/drivers/pci/pcie_dw_ti.c b/drivers/pci/pcie_dw_ti.c
index 33a5c3cc20..4195a02de3 100644
--- a/drivers/pci/pcie_dw_ti.c
+++ b/drivers/pci/pcie_dw_ti.c
@@ -19,19 +19,13 @@
 #include <linux/delay.h>
 #include <linux/err.h>
 
+#include "pcie_dw_common.h"
+
 DECLARE_GLOBAL_DATA_PTR;
 
 #define PCIE_VENDORID_MASK	GENMASK(15, 0)
 #define PCIE_DEVICEID_SHIFT	16
 
-/* PCI DBICS registers */
-#define PCIE_CONFIG_BAR0		0x10
-#define PCIE_LINK_STATUS_REG		0x80
-#define PCIE_LINK_STATUS_SPEED_OFF	16
-#define PCIE_LINK_STATUS_SPEED_MASK	(0xf << PCIE_LINK_STATUS_SPEED_OFF)
-#define PCIE_LINK_STATUS_WIDTH_OFF	20
-#define PCIE_LINK_STATUS_WIDTH_MASK	(0xf << PCIE_LINK_STATUS_WIDTH_OFF)
-
 #define PCIE_LINK_CAPABILITY		0x7c
 #define PCIE_LINK_CTL_2			0xa0
 #define TARGET_LINK_SPEED_MASK		0xf
@@ -47,46 +41,12 @@ DECLARE_GLOBAL_DATA_PTR;
 #define PORT_LOGIC_LTSSM_STATE_MASK	0x1f
 #define PORT_LOGIC_LTSSM_STATE_L0	0x11
 
-#define PCIE_LINK_WIDTH_SPEED_CONTROL	0x80c
-#define PORT_LOGIC_SPEED_CHANGE		(0x1 << 17)
-
 #define PCIE_LINK_UP_TIMEOUT_MS		100
 
-/*
- * iATU Unroll-specific register definitions
- * From 4.80 core version the address translation will be made by unroll.
- * The registers are offset from atu_base
- */
-#define PCIE_ATU_UNR_REGION_CTRL1	0x00
-#define PCIE_ATU_UNR_REGION_CTRL2	0x04
-#define PCIE_ATU_UNR_LOWER_BASE		0x08
-#define PCIE_ATU_UNR_UPPER_BASE		0x0c
-#define PCIE_ATU_UNR_LIMIT		0x10
-#define PCIE_ATU_UNR_LOWER_TARGET	0x14
-#define PCIE_ATU_UNR_UPPER_TARGET	0x18
-
-#define PCIE_ATU_REGION_INDEX1		(0x1 << 0)
-#define PCIE_ATU_REGION_INDEX0		(0x0 << 0)
-#define PCIE_ATU_TYPE_MEM		(0x0 << 0)
-#define PCIE_ATU_TYPE_IO		(0x2 << 0)
-#define PCIE_ATU_TYPE_CFG0		(0x4 << 0)
-#define PCIE_ATU_TYPE_CFG1		(0x5 << 0)
-#define PCIE_ATU_ENABLE			(0x1 << 31)
-#define PCIE_ATU_BAR_MODE_ENABLE	(0x1 << 30)
-#define PCIE_ATU_BUS(x)			(((x) & 0xff) << 24)
-#define PCIE_ATU_DEV(x)			(((x) & 0x1f) << 19)
-#define PCIE_ATU_FUNC(x)		(((x) & 0x7) << 16)
-
-/* Register address builder */
-#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region)	((region) << 9)
-
 /* Offsets from App base */
 #define PCIE_CMD_STATUS			0x04
 #define LTSSM_EN_VAL			BIT(0)
 
-/* Parameters for the waiting for iATU enabled routine */
-#define LINK_WAIT_MAX_IATU_RETRIES	5
-#define LINK_WAIT_IATU			10000
 
 #define AM654_PCIE_DEV_TYPE_MASK	0x3
 #define EP				0x0
@@ -96,29 +56,13 @@ DECLARE_GLOBAL_DATA_PTR;
 /**
  * struct pcie_dw_ti - TI DW PCIe controller state
  *
+ * @pci: The common PCIe DW structure
  * @app_base: The base address of application register space
- * @dbics_base: The base address of dbics register space
- * @cfg_base: The base address of configuration space
- * @atu_base: The base address of ATU space
- * @cfg_size: The size of the configuration space which is needed
- *            as it gets written into the PCIE_ATU_LIMIT register
- * @first_busno: This driver supports multiple PCIe controllers.
- *               first_busno stores the bus number of the PCIe root-port
- *               number which may vary depending on the PCIe setup
- *               (PEX switches etc).
  */
 struct pcie_dw_ti {
+	/* Must be first member of the struct */
+	struct pcie_dw dw;
 	void *app_base;
-	void *dbi_base;
-	void *cfg_base;
-	void *atu_base;
-	fdt_size_t cfg_size;
-	int first_busno;
-	struct udevice *dev;
-
-	/* IO and MEM PCI regions */
-	struct pci_region io;
-	struct pci_region mem;
 };
 
 enum dw_pcie_device_mode {
@@ -128,261 +72,6 @@ enum dw_pcie_device_mode {
 	DW_PCIE_RC_TYPE,
 };
 
-static int pcie_dw_get_link_speed(struct pcie_dw_ti *pci)
-{
-	return (readl(pci->dbi_base + PCIE_LINK_STATUS_REG) &
-		PCIE_LINK_STATUS_SPEED_MASK) >> PCIE_LINK_STATUS_SPEED_OFF;
-}
-
-static int pcie_dw_get_link_width(struct pcie_dw_ti *pci)
-{
-	return (readl(pci->dbi_base + PCIE_LINK_STATUS_REG) &
-		PCIE_LINK_STATUS_WIDTH_MASK) >> PCIE_LINK_STATUS_WIDTH_OFF;
-}
-
-static void dw_pcie_writel_ob_unroll(struct pcie_dw_ti *pci, u32 index, u32 reg,
-				     u32 val)
-{
-	u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
-	void __iomem *base = pci->atu_base;
-
-	writel(val, base + offset + reg);
-}
-
-static u32 dw_pcie_readl_ob_unroll(struct pcie_dw_ti *pci, u32 index, u32 reg)
-{
-	u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
-	void __iomem *base = pci->atu_base;
-
-	return readl(base + offset + reg);
-}
-
-/**
- * pcie_dw_prog_outbound_atu_unroll() - Configure ATU for outbound accesses
- *
- * @pcie: Pointer to the PCI controller state
- * @index: ATU region index
- * @type: ATU accsess type
- * @cpu_addr: the physical address for the translation entry
- * @pci_addr: the pcie bus address for the translation entry
- * @size: the size of the translation entry
- */
-static void pcie_dw_prog_outbound_atu_unroll(struct pcie_dw_ti *pci, int index,
-					     int type, u64 cpu_addr,
-					     u64 pci_addr, u32 size)
-{
-	u32 retries, val;
-
-	debug("ATU programmed with: index: %d, type: %d, cpu addr: %8llx, pci addr: %8llx, size: %8x\n",
-	      index, type, cpu_addr, pci_addr, size);
-
-	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE,
-				 lower_32_bits(cpu_addr));
-	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE,
-				 upper_32_bits(cpu_addr));
-	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LIMIT,
-				 lower_32_bits(cpu_addr + size - 1));
-	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
-				 lower_32_bits(pci_addr));
-	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
-				 upper_32_bits(pci_addr));
-	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
-				 type);
-	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
-				 PCIE_ATU_ENABLE);
-
-	/*
-	 * Make sure ATU enable takes effect before any subsequent config
-	 * and I/O accesses.
-	 */
-	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
-		val = dw_pcie_readl_ob_unroll(pci, index,
-					      PCIE_ATU_UNR_REGION_CTRL2);
-		if (val & PCIE_ATU_ENABLE)
-			return;
-
-		udelay(LINK_WAIT_IATU);
-	}
-	dev_err(pci->dev, "outbound iATU is not being enabled\n");
-}
-
-/**
- * set_cfg_address() - Configure the PCIe controller config space access
- *
- * @pcie: Pointer to the PCI controller state
- * @d: PCI device to access
- * @where: Offset in the configuration space
- *
- * Configures the PCIe controller to access the configuration space of
- * a specific PCIe device and returns the address to use for this
- * access.
- *
- * Return: Address that can be used to access the configation space
- *         of the requested device / offset
- */
-static uintptr_t set_cfg_address(struct pcie_dw_ti *pcie,
-				 pci_dev_t d, uint where)
-{
-	int bus = PCI_BUS(d) - pcie->first_busno;
-	uintptr_t va_address;
-	u32 atu_type;
-
-	/* Use dbi_base for own configuration read and write */
-	if (!bus) {
-		va_address = (uintptr_t)pcie->dbi_base;
-		goto out;
-	}
-
-	if (bus == 1)
-		/* For local bus, change TLP Type field to 4. */
-		atu_type = PCIE_ATU_TYPE_CFG0;
-	else
-		/* Otherwise, change TLP Type field to 5. */
-		atu_type = PCIE_ATU_TYPE_CFG1;
-
-	/*
-	 * Not accessing root port configuration space?
-	 * Region #0 is used for Outbound CFG space access.
-	 * Direction = Outbound
-	 * Region Index = 0
-	 */
-	d = PCI_MASK_BUS(d);
-	d = PCI_ADD_BUS(bus, d);
-	pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
-					 atu_type, (u64)pcie->cfg_base,
-					 d << 8, pcie->cfg_size);
-
-	va_address = (uintptr_t)pcie->cfg_base;
-
-out:
-	va_address += where & ~0x3;
-
-	return va_address;
-}
-
-/**
- * pcie_dw_addr_valid() - Check for valid bus address
- *
- * @d: The PCI device to access
- * @first_busno: Bus number of the PCIe controller root complex
- *
- * Return 1 (true) if the PCI device can be accessed by this controller.
- *
- * Return: 1 on valid, 0 on invalid
- */
-static int pcie_dw_addr_valid(pci_dev_t d, int first_busno)
-{
-	if ((PCI_BUS(d) == first_busno) && (PCI_DEV(d) > 0))
-		return 0;
-	if ((PCI_BUS(d) == first_busno + 1) && (PCI_DEV(d) > 0))
-		return 0;
-
-	return 1;
-}
-
-/**
- * pcie_dw_ti_read_config() - Read from configuration space
- *
- * @bus: Pointer to the PCI bus
- * @bdf: Identifies the PCIe device to access
- * @offset: The offset into the device's configuration space
- * @valuep: A pointer at which to store the read value
- * @size: Indicates the size of access to perform
- *
- * Read a value of size @size from offset @offset within the configuration
- * space of the device identified by the bus, device & function numbers in @bdf
- * on the PCI bus @bus.
- *
- * Return: 0 on success
- */
-static int pcie_dw_ti_read_config(const struct udevice *bus, pci_dev_t bdf,
-				  uint offset, ulong *valuep,
-				  enum pci_size_t size)
-{
-	struct pcie_dw_ti *pcie = dev_get_priv(bus);
-	uintptr_t va_address;
-	ulong value;
-
-	debug("PCIE CFG read: bdf=%2x:%2x:%2x ",
-	      PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
-
-	if (!pcie_dw_addr_valid(bdf, pcie->first_busno)) {
-		debug("- out of range\n");
-		*valuep = pci_get_ff(size);
-		return 0;
-	}
-
-	va_address = set_cfg_address(pcie, bdf, offset);
-
-	value = readl(va_address);
-
-	debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
-	*valuep = pci_conv_32_to_size(value, offset, size);
-
-	pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
-					 PCIE_ATU_TYPE_IO, pcie->io.phys_start,
-					 pcie->io.bus_start, pcie->io.size);
-
-	return 0;
-}
-
-/**
- * pcie_dw_ti_write_config() - Write to configuration space
- *
- * @bus: Pointer to the PCI bus
- * @bdf: Identifies the PCIe device to access
- * @offset: The offset into the device's configuration space
- * @value: The value to write
- * @size: Indicates the size of access to perform
- *
- * Write the value @value of size @size from offset @offset within the
- * configuration space of the device identified by the bus, device & function
- * numbers in @bdf on the PCI bus @bus.
- *
- * Return: 0 on success
- */
-static int pcie_dw_ti_write_config(struct udevice *bus, pci_dev_t bdf,
-				   uint offset, ulong value,
-				   enum pci_size_t size)
-{
-	struct pcie_dw_ti *pcie = dev_get_priv(bus);
-	uintptr_t va_address;
-	ulong old;
-
-	debug("PCIE CFG write: (b,d,f)=(%2d,%2d,%2d) ",
-	      PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
-	debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
-
-	if (!pcie_dw_addr_valid(bdf, pcie->first_busno)) {
-		debug("- out of range\n");
-		return 0;
-	}
-
-	va_address = set_cfg_address(pcie, bdf, offset);
-
-	old = readl(va_address);
-	value = pci_conv_size_to_32(old, value, offset, size);
-	writel(value, va_address);
-
-	pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
-					 PCIE_ATU_TYPE_IO, pcie->io.phys_start,
-					 pcie->io.bus_start, pcie->io.size);
-
-	return 0;
-}
-
-static inline void dw_pcie_dbi_write_enable(struct pcie_dw_ti *pci, bool en)
-{
-	u32 val;
-
-	val = readl(pci->dbi_base + PCIE_MISC_CONTROL_1_OFF);
-	if (en)
-		val |= PCIE_DBI_RO_WR_EN;
-	else
-		val &= ~PCIE_DBI_RO_WR_EN;
-	writel(val, pci->dbi_base + PCIE_MISC_CONTROL_1_OFF);
-}
-
 /**
  * pcie_dw_configure() - Configure link capabilities and speed
  *
@@ -395,19 +84,19 @@ static void pcie_dw_configure(struct pcie_dw_ti *pci, u32 cap_speed)
 {
 	u32 val;
 
-	dw_pcie_dbi_write_enable(pci, true);
+	dw_pcie_dbi_write_enable(&pci->dw, true);
 
-	val = readl(pci->dbi_base + PCIE_LINK_CAPABILITY);
+	val = readl(pci->dw.dbi_base + PCIE_LINK_CAPABILITY);
 	val &= ~TARGET_LINK_SPEED_MASK;
 	val |= cap_speed;
-	writel(val, pci->dbi_base + PCIE_LINK_CAPABILITY);
+	writel(val, pci->dw.dbi_base + PCIE_LINK_CAPABILITY);
 
-	val = readl(pci->dbi_base + PCIE_LINK_CTL_2);
+	val = readl(pci->dw.dbi_base + PCIE_LINK_CTL_2);
 	val &= ~TARGET_LINK_SPEED_MASK;
 	val |= cap_speed;
-	writel(val, pci->dbi_base + PCIE_LINK_CTL_2);
+	writel(val, pci->dw.dbi_base + PCIE_LINK_CTL_2);
 
-	dw_pcie_dbi_write_enable(pci, false);
+	dw_pcie_dbi_write_enable(&pci->dw, false);
 }
 
 /**
@@ -421,7 +110,7 @@ static int is_link_up(struct pcie_dw_ti *pci)
 {
 	u32 val;
 
-	val = readl(pci->dbi_base + PCIE_PORT_DEBUG0);
+	val = readl(pci->dw.dbi_base + PCIE_PORT_DEBUG0);
 	val &= PORT_LOGIC_LTSSM_STATE_MASK;
 
 	return (val == PORT_LOGIC_LTSSM_STATE_L0);
@@ -477,56 +166,6 @@ static int pcie_dw_ti_pcie_link_up(struct pcie_dw_ti *pci, u32 cap_speed)
 	return 1;
 }
 
-/**
- * pcie_dw_setup_host() - Setup the PCIe controller for RC opertaion
- *
- * @pcie: Pointer to the PCI controller state
- *
- * Configure the host BARs of the PCIe controller root port so that
- * PCI(e) devices may access the system memory.
- */
-static void pcie_dw_setup_host(struct pcie_dw_ti *pci)
-{
-	u32 val;
-
-	/* setup RC BARs */
-	writel(PCI_BASE_ADDRESS_MEM_TYPE_64,
-	       pci->dbi_base + PCI_BASE_ADDRESS_0);
-	writel(0x0, pci->dbi_base + PCI_BASE_ADDRESS_1);
-
-	/* setup interrupt pins */
-	dw_pcie_dbi_write_enable(pci, true);
-	val = readl(pci->dbi_base + PCI_INTERRUPT_LINE);
-	val &= 0xffff00ff;
-	val |= 0x00000100;
-	writel(val, pci->dbi_base + PCI_INTERRUPT_LINE);
-	dw_pcie_dbi_write_enable(pci, false);
-
-	/* setup bus numbers */
-	val = readl(pci->dbi_base + PCI_PRIMARY_BUS);
-	val &= 0xff000000;
-	val |= 0x00ff0100;
-	writel(val, pci->dbi_base + PCI_PRIMARY_BUS);
-
-	/* setup command register */
-	val = readl(pci->dbi_base + PCI_COMMAND);
-	val &= 0xffff0000;
-	val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
-		PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
-	writel(val, pci->dbi_base + PCI_COMMAND);
-
-	/* Enable write permission for the DBI read-only register */
-	dw_pcie_dbi_write_enable(pci, true);
-	/* program correct class for RC */
-	writew(PCI_CLASS_BRIDGE_PCI, pci->dbi_base + PCI_CLASS_DEVICE);
-	/* Better disable write permission right after the update */
-	dw_pcie_dbi_write_enable(pci, false);
-
-	val = readl(pci->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
-	val |= PORT_LOGIC_SPEED_CHANGE;
-	writel(val, pci->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
-}
-
 static int pcie_am654_set_mode(struct pcie_dw_ti *pci,
 			       enum dw_pcie_device_mode mode)
 {
@@ -535,7 +174,7 @@ static int pcie_am654_set_mode(struct pcie_dw_ti *pci,
 	u32 mask;
 	int ret;
 
-	syscon = syscon_regmap_lookup_by_phandle(pci->dev,
+	syscon = syscon_regmap_lookup_by_phandle(pci->dw.dev,
 						 "ti,syscon-pcie-mode");
 	if (IS_ERR(syscon))
 		return 0;
@@ -550,13 +189,13 @@ static int pcie_am654_set_mode(struct pcie_dw_ti *pci,
 		val = EP;
 		break;
 	default:
-		dev_err(pci->dev, "INVALID device type %d\n", mode);
+		dev_err(pci->dw.dev, "INVALID device type %d\n", mode);
 		return -EINVAL;
 	}
 
 	ret = regmap_update_bits(syscon, 0, mask, val);
 	if (ret) {
-		dev_err(pci->dev, "failed to set pcie mode\n");
+		dev_err(pci->dw.dev, "failed to set pcie mode\n");
 		return ret;
 	}
 
@@ -569,7 +208,7 @@ static int pcie_dw_init_id(struct pcie_dw_ti *pci)
 	unsigned int id;
 	int ret;
 
-	devctrl_regs = syscon_regmap_lookup_by_phandle(pci->dev,
+	devctrl_regs = syscon_regmap_lookup_by_phandle(pci->dw.dev,
 						       "ti,syscon-pcie-id");
 	if (IS_ERR(devctrl_regs))
 		return PTR_ERR(devctrl_regs);
@@ -578,10 +217,10 @@ static int pcie_dw_init_id(struct pcie_dw_ti *pci)
 	if (ret)
 		return ret;
 
-	dw_pcie_dbi_write_enable(pci, true);
-	writew(id & PCIE_VENDORID_MASK, pci->dbi_base + PCI_VENDOR_ID);
-	writew(id >> PCIE_DEVICEID_SHIFT, pci->dbi_base + PCI_DEVICE_ID);
-	dw_pcie_dbi_write_enable(pci, false);
+	dw_pcie_dbi_write_enable(&pci->dw, true);
+	writew(id & PCIE_VENDORID_MASK, pci->dw.dbi_base + PCI_VENDOR_ID);
+	writew(id >> PCIE_DEVICEID_SHIFT, pci->dw.dbi_base + PCI_DEVICE_ID);
+	dw_pcie_dbi_write_enable(&pci->dw, false);
 
 	return 0;
 }
@@ -635,10 +274,10 @@ static int pcie_dw_ti_probe(struct udevice *dev)
 	generic_phy_init(&phy1);
 	generic_phy_power_on(&phy1);
 
-	pci->first_busno = dev_seq(dev);
-	pci->dev = dev;
+	pci->dw.first_busno = dev_seq(dev);
+	pci->dw.dev = dev;
 
-	pcie_dw_setup_host(pci);
+	pcie_dw_setup_host(&pci->dw);
 	pcie_dw_init_id(pci);
 
 	if (device_is_compatible(dev, "ti,am654-pcie-rc"))
@@ -650,23 +289,14 @@ static int pcie_dw_ti_probe(struct udevice *dev)
 	}
 
 	printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n", dev_seq(dev),
-	       pcie_dw_get_link_speed(pci),
-	       pcie_dw_get_link_width(pci),
+	       pcie_dw_get_link_speed(&pci->dw),
+	       pcie_dw_get_link_width(&pci->dw),
 	       hose->first_busno);
 
-	/* Store the IO and MEM windows settings for future use by the ATU */
-	pci->io.phys_start = hose->regions[0].phys_start; /* IO base */
-	pci->io.bus_start  = hose->regions[0].bus_start;  /* IO_bus_addr */
-	pci->io.size	    = hose->regions[0].size;	   /* IO size */
-
-	pci->mem.phys_start = hose->regions[1].phys_start; /* MEM base */
-	pci->mem.bus_start  = hose->regions[1].bus_start;  /* MEM_bus_addr */
-	pci->mem.size	     = hose->regions[1].size;	    /* MEM size */
-
-	pcie_dw_prog_outbound_atu_unroll(pci, PCIE_ATU_REGION_INDEX0,
+	pcie_dw_prog_outbound_atu_unroll(&pci->dw, PCIE_ATU_REGION_INDEX0,
 					 PCIE_ATU_TYPE_MEM,
-					 pci->mem.phys_start,
-					 pci->mem.bus_start, pci->mem.size);
+					 pci->dw.mem.phys_start,
+					 pci->dw.mem.bus_start, pci->dw.mem.size);
 
 	return 0;
 }
@@ -687,19 +317,19 @@ static int pcie_dw_ti_of_to_plat(struct udevice *dev)
 	struct pcie_dw_ti *pcie = dev_get_priv(dev);
 
 	/* Get the controller base address */
-	pcie->dbi_base = (void *)dev_read_addr_name(dev, "dbics");
-	if ((fdt_addr_t)pcie->dbi_base == FDT_ADDR_T_NONE)
+	pcie->dw.dbi_base = (void *)dev_read_addr_name(dev, "dbics");
+	if ((fdt_addr_t)pcie->dw.dbi_base == FDT_ADDR_T_NONE)
 		return -EINVAL;
 
 	/* Get the config space base address and size */
-	pcie->cfg_base = (void *)dev_read_addr_size_name(dev, "config",
-							 &pcie->cfg_size);
-	if ((fdt_addr_t)pcie->cfg_base == FDT_ADDR_T_NONE)
+	pcie->dw.cfg_base = (void *)dev_read_addr_size_name(dev, "config",
+							 &pcie->dw.cfg_size);
+	if ((fdt_addr_t)pcie->dw.cfg_base == FDT_ADDR_T_NONE)
 		return -EINVAL;
 
 	/* Get the iATU base address and size */
-	pcie->atu_base = (void *)dev_read_addr_name(dev, "atu");
-	if ((fdt_addr_t)pcie->atu_base == FDT_ADDR_T_NONE)
+	pcie->dw.atu_base = (void *)dev_read_addr_name(dev, "atu");
+	if ((fdt_addr_t)pcie->dw.atu_base == FDT_ADDR_T_NONE)
 		return -EINVAL;
 
 	/* Get the app base address and size */
@@ -711,8 +341,8 @@ static int pcie_dw_ti_of_to_plat(struct udevice *dev)
 }
 
 static const struct dm_pci_ops pcie_dw_ti_ops = {
-	.read_config	= pcie_dw_ti_read_config,
-	.write_config	= pcie_dw_ti_write_config,
+	.read_config	= pcie_dw_read_config,
+	.write_config	= pcie_dw_write_config,
 };
 
 static const struct udevice_id pcie_dw_ti_ids[] = {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH RFT v2 3/4] pci: pcie_dw_rockchip: migrate to common Designware PCIe functions
  2021-03-25 14:49 ` Neil Armstrong
@ 2021-03-25 14:49   ` Neil Armstrong
  -1 siblings, 0 replies; 26+ messages in thread
From: Neil Armstrong @ 2021-03-25 14:49 UTC (permalink / raw)
  To: u-boot

Migrate the dw_rockchip driver to use the common DW PCIe helpers.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/pci/Kconfig            |   2 +-
 drivers/pci/pcie_dw_rockchip.c | 472 ++-------------------------------
 2 files changed, 30 insertions(+), 444 deletions(-)

diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 318d8fa37d..cacfc4bd25 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -289,7 +289,7 @@ config PCIE_ROCKCHIP
 config PCIE_DW_ROCKCHIP
 	bool "Rockchip DesignWare based PCIe controller"
 	depends on ARCH_ROCKCHIP
-	select DM_PCI
+	select PCIE_DW_COMMON
 	select PHY_ROCKCHIP_SNPS_PCIE3
 	help
 	  Say Y here if you want to enable DW PCIe controller support on
diff --git a/drivers/pci/pcie_dw_rockchip.c b/drivers/pci/pcie_dw_rockchip.c
index 77f1a1b48f..bc22af4230 100644
--- a/drivers/pci/pcie_dw_rockchip.c
+++ b/drivers/pci/pcie_dw_rockchip.c
@@ -22,39 +22,26 @@
 #include <linux/delay.h>
 #include <power/regulator.h>
 
+#include "pcie_dw_common.h"
+
 DECLARE_GLOBAL_DATA_PTR;
 
 /**
  * struct rk_pcie - RK DW PCIe controller state
  *
  * @vpcie3v3: The 3.3v power supply for slot
- * @dbi_base: The base address of dwc core regs
  * @apb_base: The base address of vendor regs
- * @cfg_base: The base address of config header space
- * @cfg_size: The size of the configuration space which is needed
- *            as it gets written into the PCIE_ATU_LIMIT register
- * @first_busno: This driver supports multiple PCIe controllers.
- *               first_busno stores the bus number of the PCIe root-port
- *               number which may vary depending on the PCIe setup
- *               (PEX switches etc).
  * @rst_gpio: The #PERST signal for slot
- * @io:	The IO space for EP's BAR
- * @mem: The memory space for EP's BAR
  */
 struct rk_pcie {
-	struct udevice	*dev;
+	/* Must be first member of the struct */
+	struct pcie_dw  dw;
 	struct udevice  *vpcie3v3;
-	void		*dbi_base;
 	void		*apb_base;
-	void		*cfg_base;
-	fdt_size_t	cfg_size;
 	struct phy	phy;
 	struct clk_bulk	clks;
-	int		first_busno;
 	struct reset_ctl_bulk	rsts;
 	struct gpio_desc	rst_gpio;
-	struct pci_region	io;
-	struct pci_region	mem;
 };
 
 /* Parameters for the waiting for iATU enabled routine */
@@ -73,59 +60,6 @@ struct rk_pcie {
 #define PCIE_CLIENT_DBG_TRANSITION_DATA	0xffff0000
 #define PCIE_CLIENT_DBF_EN		0xffff0003
 
-/* PCI DBICS registers */
-#define PCIE_LINK_STATUS_REG		0x80
-#define PCIE_LINK_STATUS_SPEED_OFF	16
-#define PCIE_LINK_STATUS_SPEED_MASK	(0xf << PCIE_LINK_STATUS_SPEED_OFF)
-#define PCIE_LINK_STATUS_WIDTH_OFF	20
-#define PCIE_LINK_STATUS_WIDTH_MASK	(0xf << PCIE_LINK_STATUS_WIDTH_OFF)
-
-#define PCIE_LINK_CAPABILITY		0x7c
-#define PCIE_LINK_CTL_2			0xa0
-#define TARGET_LINK_SPEED_MASK		0xf
-#define LINK_SPEED_GEN_1		0x1
-#define LINK_SPEED_GEN_2		0x2
-#define LINK_SPEED_GEN_3		0x3
-
-#define PCIE_MISC_CONTROL_1_OFF		0x8bc
-#define PCIE_DBI_RO_WR_EN		BIT(0)
-
-#define PCIE_LINK_WIDTH_SPEED_CONTROL	0x80c
-#define PORT_LOGIC_SPEED_CHANGE		BIT(17)
-
-/*
- * iATU Unroll-specific register definitions
- * From 4.80 core version the address translation will be made by unroll.
- * The registers are offset from atu_base
- */
-#define PCIE_ATU_UNR_REGION_CTRL1	0x00
-#define PCIE_ATU_UNR_REGION_CTRL2	0x04
-#define PCIE_ATU_UNR_LOWER_BASE		0x08
-#define PCIE_ATU_UNR_UPPER_BASE		0x0c
-#define PCIE_ATU_UNR_LIMIT		0x10
-#define PCIE_ATU_UNR_LOWER_TARGET	0x14
-#define PCIE_ATU_UNR_UPPER_TARGET	0x18
-
-#define PCIE_ATU_REGION_INDEX1		(0x1 << 0)
-#define PCIE_ATU_REGION_INDEX0		(0x0 << 0)
-#define PCIE_ATU_TYPE_MEM		(0x0 << 0)
-#define PCIE_ATU_TYPE_IO		(0x2 << 0)
-#define PCIE_ATU_TYPE_CFG0		(0x4 << 0)
-#define PCIE_ATU_TYPE_CFG1		(0x5 << 0)
-#define PCIE_ATU_ENABLE			(0x1 << 31)
-#define PCIE_ATU_BAR_MODE_ENABLE	(0x1 << 30)
-#define PCIE_ATU_BUS(x)			(((x) & 0xff) << 24)
-#define PCIE_ATU_DEV(x)			(((x) & 0x1f) << 19)
-#define PCIE_ATU_FUNC(x)		(((x) & 0x7) << 16)
-
-/* Register address builder */
-#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region)        \
-	((0x3 << 20) | ((region) << 9))
-
-/* Parameters for the waiting for iATU enabled routine */
-#define LINK_WAIT_MAX_IATU_RETRIES	5
-#define LINK_WAIT_IATU_US		10000
-
 /* Parameters for the waiting for #perst signal */
 #define PERST_WAIT_MS			1000
 
@@ -175,7 +109,7 @@ static u32 __rk_pcie_read_apb(struct rk_pcie *rk_pcie, void __iomem *base,
 
 	ret = rk_pcie_read(base + reg, size, &val);
 	if (ret)
-		dev_err(rk_pcie->dev, "Read APB address failed\n");
+		dev_err(rk_pcie->dw.dev, "Read APB address failed\n");
 
 	return val;
 }
@@ -187,7 +121,7 @@ static void __rk_pcie_write_apb(struct rk_pcie *rk_pcie, void __iomem *base,
 
 	ret = rk_pcie_write(base + reg, size, val);
 	if (ret)
-		dev_err(rk_pcie->dev, "Write APB address failed\n");
+		dev_err(rk_pcie->dw.dev, "Write APB address failed\n");
 }
 
 /**
@@ -214,91 +148,6 @@ static inline void rk_pcie_writel_apb(struct rk_pcie *rk_pcie, u32 reg,
 	__rk_pcie_write_apb(rk_pcie, rk_pcie->apb_base, reg, 0x4, val);
 }
 
-static int rk_pcie_get_link_speed(struct rk_pcie *rk_pcie)
-{
-	return (readl(rk_pcie->dbi_base + PCIE_LINK_STATUS_REG) &
-		PCIE_LINK_STATUS_SPEED_MASK) >> PCIE_LINK_STATUS_SPEED_OFF;
-}
-
-static int rk_pcie_get_link_width(struct rk_pcie *rk_pcie)
-{
-	return (readl(rk_pcie->dbi_base + PCIE_LINK_STATUS_REG) &
-		PCIE_LINK_STATUS_WIDTH_MASK) >> PCIE_LINK_STATUS_WIDTH_OFF;
-}
-
-static void rk_pcie_writel_ob_unroll(struct rk_pcie *rk_pcie, u32 index,
-				     u32 reg, u32 val)
-{
-	u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
-	void __iomem *base = rk_pcie->dbi_base;
-
-	writel(val, base + offset + reg);
-}
-
-static u32 rk_pcie_readl_ob_unroll(struct rk_pcie *rk_pcie, u32 index, u32 reg)
-{
-	u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
-	void __iomem *base = rk_pcie->dbi_base;
-
-	return readl(base + offset + reg);
-}
-
-static inline void rk_pcie_dbi_write_enable(struct rk_pcie *rk_pcie, bool en)
-{
-	u32 val;
-
-	val = readl(rk_pcie->dbi_base + PCIE_MISC_CONTROL_1_OFF);
-
-	if (en)
-		val |= PCIE_DBI_RO_WR_EN;
-	else
-		val &= ~PCIE_DBI_RO_WR_EN;
-	writel(val, rk_pcie->dbi_base + PCIE_MISC_CONTROL_1_OFF);
-}
-
-/**
- * rockchip_pcie_setup_host() - Setup the PCIe controller for RC opertaion
- *
- * @rk_pcie: Pointer to the PCI controller state
- *
- * Configure the host BARs of the PCIe controller root port so that
- * PCI(e) devices may access the system memory.
- */
-static void rk_pcie_setup_host(struct rk_pcie *rk_pcie)
-{
-	u32 val;
-
-	rk_pcie_dbi_write_enable(rk_pcie, true);
-
-	/* setup RC BARs */
-	writel(PCI_BASE_ADDRESS_MEM_TYPE_64,
-	       rk_pcie->dbi_base + PCI_BASE_ADDRESS_0);
-	writel(0x0, rk_pcie->dbi_base + PCI_BASE_ADDRESS_1);
-
-	/* setup interrupt pins */
-	clrsetbits_le32(rk_pcie->dbi_base + PCI_INTERRUPT_LINE,
-			0xff00, 0x100);
-
-	/* setup bus numbers */
-	clrsetbits_le32(rk_pcie->dbi_base + PCI_PRIMARY_BUS,
-			0xffffff, 0x00ff0100);
-
-	/* setup command register */
-	clrsetbits_le32(rk_pcie->dbi_base + PCI_PRIMARY_BUS,
-			0xffff,
-			PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
-			PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
-
-	/* program correct class for RC */
-	writew(PCI_CLASS_BRIDGE_PCI, rk_pcie->dbi_base + PCI_CLASS_DEVICE);
-	/* Better disable write permission right after the update */
-
-	setbits_le32(rk_pcie->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL,
-		     PORT_LOGIC_SPEED_CHANGE)
-
-	rk_pcie_dbi_write_enable(rk_pcie, false);
-}
-
 /**
  * rk_pcie_configure() - Configure link capabilities and speed
  *
@@ -311,242 +160,15 @@ static void rk_pcie_configure(struct rk_pcie *pci, u32 cap_speed)
 {
 	u32 val;
 
-	rk_pcie_dbi_write_enable(pci, true);
+	dw_pcie_dbi_write_enable(&pci->dw, true);
 
-	clrsetbits_le32(pci->dbi_base + PCIE_LINK_CAPABILITY,
+	clrsetbits_le32(pci->dw.dbi_base + PCIE_LINK_CAPABILITY,
 			TARGET_LINK_SPEED_MASK, cap_speed);
 
-	clrsetbits_le32(pci->dbi_base + PCIE_LINK_CTL_2,
+	clrsetbits_le32(pci->dw.dbi_base + PCIE_LINK_CTL_2,
 			TARGET_LINK_SPEED_MASK, cap_speed);
 
-	rk_pcie_dbi_write_enable(pci, false);
-}
-
-/**
- * rk_pcie_dw_prog_outbound_atu_unroll() - Configure ATU for outbound accesses
- *
- * @rk_pcie: Pointer to the PCI controller state
- * @index: ATU region index
- * @type: ATU accsess type
- * @cpu_addr: the physical address for the translation entry
- * @pci_addr: the pcie bus address for the translation entry
- * @size: the size of the translation entry
- *
- * Return: 0 is successful and -1 is failure
- */
-static int rk_pcie_prog_outbound_atu_unroll(struct rk_pcie *pci, int index,
-					    int type, u64 cpu_addr,
-					    u64 pci_addr, u32 size)
-{
-	u32 retries, val;
-
-	dev_dbg(pci->dev, "ATU programmed with: index: %d, type: %d, cpu addr: %8llx, pci addr: %8llx, size: %8x\n",
-		index, type, cpu_addr, pci_addr, size);
-
-	rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE,
-				 lower_32_bits(cpu_addr));
-	rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE,
-				 upper_32_bits(cpu_addr));
-	rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LIMIT,
-				 lower_32_bits(cpu_addr + size - 1));
-	rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
-				 lower_32_bits(pci_addr));
-	rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
-				 upper_32_bits(pci_addr));
-	rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
-				 type);
-	rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
-				 PCIE_ATU_ENABLE);
-
-	/*
-	 * Make sure ATU enable takes effect before any subsequent config
-	 * and I/O accesses.
-	 */
-	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
-		val = rk_pcie_readl_ob_unroll(pci, index,
-					      PCIE_ATU_UNR_REGION_CTRL2);
-		if (val & PCIE_ATU_ENABLE)
-			return 0;
-
-		udelay(LINK_WAIT_IATU_US);
-	}
-	dev_err(pci->dev, "outbound iATU is not being enabled\n");
-
-	return -1;
-}
-
-/**
- * rk_pcie_dw_addr_valid() - Check for valid bus address
- *
- * @d: The PCI device to access
- * @first_busno: Bus number of the PCIe controller root complex
- *
- * Return 1 (true) if the PCI device can be accessed by this controller.
- *
- * Return: 1 on valid, 0 on invalid
- */
-static int rk_pcie_addr_valid(pci_dev_t d, int first_busno)
-{
-	if ((PCI_BUS(d) == first_busno) && (PCI_DEV(d) > 0))
-		return 0;
-	if ((PCI_BUS(d) == first_busno + 1) && (PCI_DEV(d) > 0))
-		return 0;
-
-	return 1;
-}
-
-/**
- * set_cfg_address() - Configure the PCIe controller config space access
- *
- * @rk_pcie: Pointer to the PCI controller state
- * @d: PCI device to access
- * @where: Offset in the configuration space
- *
- * Configures the PCIe controller to access the configuration space of
- * a specific PCIe device and returns the address to use for this
- * access.
- *
- * Return: Address that can be used to access the configation space
- *         of the requested device / offset
- */
-static uintptr_t set_cfg_address(struct rk_pcie *pcie,
-				 pci_dev_t d, uint where)
-{
-	int rel_bus = PCI_BUS(d) - pcie->first_busno;
-	uintptr_t va_address;
-	u32 atu_type;
-	int ret;
-
-	/* Use dbi_base for own configuration read and write */
-	if (!rel_bus) {
-		va_address = (uintptr_t)pcie->dbi_base;
-		goto out;
-	}
-
-	if (rel_bus == 1)
-		/*
-		 * For local bus whose primary bus number is root bridge,
-		 * change TLP Type field to 4.
-		 */
-		atu_type = PCIE_ATU_TYPE_CFG0;
-	else
-		/* Otherwise, change TLP Type field to 5. */
-		atu_type = PCIE_ATU_TYPE_CFG1;
-
-	/*
-	 * Not accessing root port configuration space?
-	 * Region #0 is used for Outbound CFG space access.
-	 * Direction = Outbound
-	 * Region Index = 0
-	 */
-	d = PCI_MASK_BUS(d);
-	d = PCI_ADD_BUS(rel_bus, d);
-	ret = rk_pcie_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
-					       atu_type, (u64)pcie->cfg_base,
-					       d << 8, pcie->cfg_size);
-	if (ret)
-		return (uintptr_t)ret;
-
-	va_address = (uintptr_t)pcie->cfg_base;
-
-out:
-	va_address += where & ~0x3;
-
-	return va_address;
-}
-
-/**
- * rockchip_pcie_rd_conf() - Read from configuration space
- *
- * @bus: Pointer to the PCI bus
- * @bdf: Identifies the PCIe device to access
- * @offset: The offset into the device's configuration space
- * @valuep: A pointer at which to store the read value
- * @size: Indicates the size of access to perform
- *
- * Read a value of size @size from offset @offset within the configuration
- * space of the device identified by the bus, device & function numbers in @bdf
- * on the PCI bus @bus.
- *
- * Return: 0 on success
- */
-static int rockchip_pcie_rd_conf(const struct udevice *bus, pci_dev_t bdf,
-				 uint offset, ulong *valuep,
-				 enum pci_size_t size)
-{
-	struct rk_pcie *pcie = dev_get_priv(bus);
-	uintptr_t va_address;
-	ulong value;
-
-	debug("PCIE CFG read: bdf=%2x:%2x:%2x\n",
-	      PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
-
-	if (!rk_pcie_addr_valid(bdf, pcie->first_busno)) {
-		debug("- out of range\n");
-		*valuep = pci_get_ff(size);
-		return 0;
-	}
-
-	va_address = set_cfg_address(pcie, bdf, offset);
-
-	value = readl(va_address);
-
-	debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
-	*valuep = pci_conv_32_to_size(value, offset, size);
-
-	return rk_pcie_prog_outbound_atu_unroll(pcie,
-						PCIE_ATU_REGION_INDEX1,
-						PCIE_ATU_TYPE_IO,
-						pcie->io.phys_start,
-						pcie->io.bus_start,
-						pcie->io.size);
-}
-
-/**
- * rockchip_pcie_wr_conf() - Write to configuration space
- *
- * @bus: Pointer to the PCI bus
- * @bdf: Identifies the PCIe device to access
- * @offset: The offset into the device's configuration space
- * @value: The value to write
- * @size: Indicates the size of access to perform
- *
- * Write the value @value of size @size from offset @offset within the
- * configuration space of the device identified by the bus, device & function
- * numbers in @bdf on the PCI bus @bus.
- *
- * Return: 0 on success
- */
-static int rockchip_pcie_wr_conf(struct udevice *bus, pci_dev_t bdf,
-				 uint offset, ulong value,
-				 enum pci_size_t size)
-{
-	struct rk_pcie *pcie = dev_get_priv(bus);
-	uintptr_t va_address;
-	ulong old;
-
-	debug("PCIE CFG write: (b,d,f)=(%2d,%2d,%2d)\n",
-	      PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
-	debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
-
-	if (!rk_pcie_addr_valid(bdf, pcie->first_busno)) {
-		debug("- out of range\n");
-		return 0;
-	}
-
-	va_address = set_cfg_address(pcie, bdf, offset);
-
-	old = readl(va_address);
-	value = pci_conv_size_to_32(old, value, offset, size);
-	writel(value, va_address);
-
-	return rk_pcie_prog_outbound_atu_unroll(pcie,
-						PCIE_ATU_REGION_INDEX1,
-						PCIE_ATU_TYPE_IO,
-						pcie->io.phys_start,
-						pcie->io.bus_start,
-						pcie->io.size);
-
+	dw_pcie_dbi_write_enable(&pci->dw, false);
 }
 
 static void rk_pcie_enable_debug(struct rk_pcie *rk_pcie)
@@ -642,19 +264,19 @@ static int rk_pcie_link_up(struct rk_pcie *priv, u32 cap_speed)
 
 	for (retries = 0; retries < 5; retries++) {
 		if (is_link_up(priv)) {
-			dev_info(priv->dev, "PCIe Link up, LTSSM is 0x%x\n",
+			dev_info(priv->dw.dev, "PCIe Link up, LTSSM is 0x%x\n",
 				 rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS));
 			rk_pcie_debug_dump(priv);
 			return 0;
 		}
 
-		dev_info(priv->dev, "PCIe Linking... LTSSM is 0x%x\n",
+		dev_info(priv->dw.dev, "PCIe Linking... LTSSM is 0x%x\n",
 			 rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS));
 		rk_pcie_debug_dump(priv);
 		msleep(1000);
 	}
 
-	dev_err(priv->dev, "PCIe-%d Link Fail\n", dev_seq(priv->dev));
+	dev_err(priv->dw.dev, "PCIe-%d Link Fail\n", dev_seq(priv->dw.dev));
 	/* Link maybe in Gen switch recovery but we need to wait more 1s */
 	msleep(1000);
 	return -EIO;
@@ -670,7 +292,7 @@ static int rockchip_pcie_init_port(struct udevice *dev)
 	if (priv->vpcie3v3) {
 		ret = regulator_set_value(priv->vpcie3v3, 3300000);
 		if (ret) {
-			dev_err(priv->dev, "failed to enable vpcie3v3 (ret=%d)\n",
+			dev_err(priv->dw.dev, "failed to enable vpcie3v3 (ret=%d)\n",
 				ret);
 			return ret;
 		}
@@ -709,7 +331,7 @@ static int rockchip_pcie_init_port(struct udevice *dev)
 
 	/* Set RC mode */
 	rk_pcie_writel_apb(priv, 0x0, 0xf00040);
-	rk_pcie_setup_host(priv);
+	pcie_dw_setup_host(&priv->dw);
 
 	ret = rk_pcie_link_up(priv, LINK_SPEED_GEN_3);
 	if (ret < 0)
@@ -733,11 +355,11 @@ static int rockchip_pcie_parse_dt(struct udevice *dev)
 	struct rk_pcie *priv = dev_get_priv(dev);
 	int ret;
 
-	priv->dbi_base = (void *)dev_read_addr_index(dev, 0);
-	if (!priv->dbi_base)
+	priv->dw.dbi_base = (void *)dev_read_addr_index(dev, 0);
+	if (!priv->dw.dbi_base)
 		return -ENODEV;
 
-	dev_dbg(dev, "DBI address is 0x%p\n", priv->dbi_base);
+	dev_dbg(dev, "DBI address is 0x%p\n", priv->dw.dbi_base);
 
 	priv->apb_base = (void *)dev_read_addr_index(dev, 1);
 	if (!priv->apb_base)
@@ -795,10 +417,10 @@ static int rockchip_pcie_probe(struct udevice *dev)
 	struct rk_pcie *priv = dev_get_priv(dev);
 	struct udevice *ctlr = pci_get_controller(dev);
 	struct pci_controller *hose = dev_get_uclass_priv(ctlr);
-	int reti = 0;
+	int ret = 0;
 
-	priv->first_busno = dev_seq(dev);
-	priv->dev = dev;
+	priv->dw.first_busno = dev_seq(dev);
+	priv->dw.dev = dev;
 
 	ret = rockchip_pcie_parse_dt(dev);
 	if (ret)
@@ -809,58 +431,22 @@ static int rockchip_pcie_probe(struct udevice *dev)
 		return ret;
 
 	dev_info(dev, "PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n",
-		 dev_seq(dev), rk_pcie_get_link_speed(priv),
-		 rk_pcie_get_link_width(priv),
+		 dev_seq(dev), pcie_dw_get_link_speed(&priv->dw),
+		 pcie_dw_get_link_width(&priv->dw),
 		 hose->first_busno);
 
-	for (ret = 0; ret < hose->region_count; ret++) {
-		if (hose->regions[ret].flags == PCI_REGION_IO) {
-			priv->io.phys_start = hose->regions[ret].phys_start; /* IO base */
-			priv->io.bus_start  = hose->regions[ret].bus_start;  /* IO_bus_addr */
-			priv->io.size       = hose->regions[ret].size;      /* IO size */
-		} else if (hose->regions[ret].flags == PCI_REGION_MEM) {
-			priv->mem.phys_start = hose->regions[ret].phys_start; /* MEM base */
-			priv->mem.bus_start  = hose->regions[ret].bus_start;  /* MEM_bus_addr */
-			priv->mem.size	     = hose->regions[ret].size;	    /* MEM size */
-		} else if (hose->regions[ret].flags == PCI_REGION_SYS_MEMORY) {
-			priv->cfg_base = (void *)(priv->io.phys_start - priv->io.size);
-			priv->cfg_size = priv->io.size;
-		} else {
-			dev_err(dev, "invalid flags type!\n");
-		}
-	}
-
-	dev_dbg(dev, "Config space: [0x%p - 0x%p, size 0x%llx]\n",
-		priv->cfg_base, priv->cfg_base + priv->cfg_size,
-		priv->cfg_size);
-
-	dev_dbg(dev, "IO space: [0x%llx - 0x%llx, size 0x%lx]\n",
-		priv->io.phys_start, priv->io.phys_start + priv->io.size,
-		priv->io.size);
-
-	dev_dbg(dev, "IO bus:   [0x%lx - 0x%lx, size 0x%lx]\n",
-		priv->io.bus_start, priv->io.bus_start + priv->io.size,
-		priv->io.size);
-
-	dev_dbg(dev, "MEM space: [0x%llx - 0x%llx, size 0x%lx]\n",
-		priv->mem.phys_start, priv->mem.phys_start + priv->mem.size,
-		priv->mem.size);
-
-	dev_dbg(dev, "MEM bus:   [0x%lx - 0x%lx, size 0x%lx]\n",
-		priv->mem.bus_start, priv->mem.bus_start + priv->mem.size,
-		priv->mem.size);
 
-	return rk_pcie_prog_outbound_atu_unroll(priv,
+	return pcie_dw_prog_outbound_atu_unroll(&priv->dw,
 						PCIE_ATU_REGION_INDEX0,
 						PCIE_ATU_TYPE_MEM,
-						priv->mem.phys_start,
-						priv->mem.bus_start,
-						priv->mem.size);
+						priv->dw.mem.phys_start,
+						priv->dw.mem.bus_start,
+						priv->dw.mem.size);
 }
 
 static const struct dm_pci_ops rockchip_pcie_ops = {
-	.read_config	= rockchip_pcie_rd_conf,
-	.write_config	= rockchip_pcie_wr_conf,
+	.read_config	= pcie_dw_read_config,
+	.write_config	= pcie_dw_write_config,
 };
 
 static const struct udevice_id rockchip_pcie_ids[] = {
-- 
2.25.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH RFT v2 3/4] pci: pcie_dw_rockchip: migrate to common Designware PCIe functions
@ 2021-03-25 14:49   ` Neil Armstrong
  0 siblings, 0 replies; 26+ messages in thread
From: Neil Armstrong @ 2021-03-25 14:49 UTC (permalink / raw)
  To: lokeshvutla, nsekhar, shawn.lin, bmeng.cn, green.wan
  Cc: u-boot, u-boot-amlogic, Neil Armstrong

Migrate the dw_rockchip driver to use the common DW PCIe helpers.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/pci/Kconfig            |   2 +-
 drivers/pci/pcie_dw_rockchip.c | 472 ++-------------------------------
 2 files changed, 30 insertions(+), 444 deletions(-)

diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 318d8fa37d..cacfc4bd25 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -289,7 +289,7 @@ config PCIE_ROCKCHIP
 config PCIE_DW_ROCKCHIP
 	bool "Rockchip DesignWare based PCIe controller"
 	depends on ARCH_ROCKCHIP
-	select DM_PCI
+	select PCIE_DW_COMMON
 	select PHY_ROCKCHIP_SNPS_PCIE3
 	help
 	  Say Y here if you want to enable DW PCIe controller support on
diff --git a/drivers/pci/pcie_dw_rockchip.c b/drivers/pci/pcie_dw_rockchip.c
index 77f1a1b48f..bc22af4230 100644
--- a/drivers/pci/pcie_dw_rockchip.c
+++ b/drivers/pci/pcie_dw_rockchip.c
@@ -22,39 +22,26 @@
 #include <linux/delay.h>
 #include <power/regulator.h>
 
+#include "pcie_dw_common.h"
+
 DECLARE_GLOBAL_DATA_PTR;
 
 /**
  * struct rk_pcie - RK DW PCIe controller state
  *
  * @vpcie3v3: The 3.3v power supply for slot
- * @dbi_base: The base address of dwc core regs
  * @apb_base: The base address of vendor regs
- * @cfg_base: The base address of config header space
- * @cfg_size: The size of the configuration space which is needed
- *            as it gets written into the PCIE_ATU_LIMIT register
- * @first_busno: This driver supports multiple PCIe controllers.
- *               first_busno stores the bus number of the PCIe root-port
- *               number which may vary depending on the PCIe setup
- *               (PEX switches etc).
  * @rst_gpio: The #PERST signal for slot
- * @io:	The IO space for EP's BAR
- * @mem: The memory space for EP's BAR
  */
 struct rk_pcie {
-	struct udevice	*dev;
+	/* Must be first member of the struct */
+	struct pcie_dw  dw;
 	struct udevice  *vpcie3v3;
-	void		*dbi_base;
 	void		*apb_base;
-	void		*cfg_base;
-	fdt_size_t	cfg_size;
 	struct phy	phy;
 	struct clk_bulk	clks;
-	int		first_busno;
 	struct reset_ctl_bulk	rsts;
 	struct gpio_desc	rst_gpio;
-	struct pci_region	io;
-	struct pci_region	mem;
 };
 
 /* Parameters for the waiting for iATU enabled routine */
@@ -73,59 +60,6 @@ struct rk_pcie {
 #define PCIE_CLIENT_DBG_TRANSITION_DATA	0xffff0000
 #define PCIE_CLIENT_DBF_EN		0xffff0003
 
-/* PCI DBICS registers */
-#define PCIE_LINK_STATUS_REG		0x80
-#define PCIE_LINK_STATUS_SPEED_OFF	16
-#define PCIE_LINK_STATUS_SPEED_MASK	(0xf << PCIE_LINK_STATUS_SPEED_OFF)
-#define PCIE_LINK_STATUS_WIDTH_OFF	20
-#define PCIE_LINK_STATUS_WIDTH_MASK	(0xf << PCIE_LINK_STATUS_WIDTH_OFF)
-
-#define PCIE_LINK_CAPABILITY		0x7c
-#define PCIE_LINK_CTL_2			0xa0
-#define TARGET_LINK_SPEED_MASK		0xf
-#define LINK_SPEED_GEN_1		0x1
-#define LINK_SPEED_GEN_2		0x2
-#define LINK_SPEED_GEN_3		0x3
-
-#define PCIE_MISC_CONTROL_1_OFF		0x8bc
-#define PCIE_DBI_RO_WR_EN		BIT(0)
-
-#define PCIE_LINK_WIDTH_SPEED_CONTROL	0x80c
-#define PORT_LOGIC_SPEED_CHANGE		BIT(17)
-
-/*
- * iATU Unroll-specific register definitions
- * From 4.80 core version the address translation will be made by unroll.
- * The registers are offset from atu_base
- */
-#define PCIE_ATU_UNR_REGION_CTRL1	0x00
-#define PCIE_ATU_UNR_REGION_CTRL2	0x04
-#define PCIE_ATU_UNR_LOWER_BASE		0x08
-#define PCIE_ATU_UNR_UPPER_BASE		0x0c
-#define PCIE_ATU_UNR_LIMIT		0x10
-#define PCIE_ATU_UNR_LOWER_TARGET	0x14
-#define PCIE_ATU_UNR_UPPER_TARGET	0x18
-
-#define PCIE_ATU_REGION_INDEX1		(0x1 << 0)
-#define PCIE_ATU_REGION_INDEX0		(0x0 << 0)
-#define PCIE_ATU_TYPE_MEM		(0x0 << 0)
-#define PCIE_ATU_TYPE_IO		(0x2 << 0)
-#define PCIE_ATU_TYPE_CFG0		(0x4 << 0)
-#define PCIE_ATU_TYPE_CFG1		(0x5 << 0)
-#define PCIE_ATU_ENABLE			(0x1 << 31)
-#define PCIE_ATU_BAR_MODE_ENABLE	(0x1 << 30)
-#define PCIE_ATU_BUS(x)			(((x) & 0xff) << 24)
-#define PCIE_ATU_DEV(x)			(((x) & 0x1f) << 19)
-#define PCIE_ATU_FUNC(x)		(((x) & 0x7) << 16)
-
-/* Register address builder */
-#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region)        \
-	((0x3 << 20) | ((region) << 9))
-
-/* Parameters for the waiting for iATU enabled routine */
-#define LINK_WAIT_MAX_IATU_RETRIES	5
-#define LINK_WAIT_IATU_US		10000
-
 /* Parameters for the waiting for #perst signal */
 #define PERST_WAIT_MS			1000
 
@@ -175,7 +109,7 @@ static u32 __rk_pcie_read_apb(struct rk_pcie *rk_pcie, void __iomem *base,
 
 	ret = rk_pcie_read(base + reg, size, &val);
 	if (ret)
-		dev_err(rk_pcie->dev, "Read APB address failed\n");
+		dev_err(rk_pcie->dw.dev, "Read APB address failed\n");
 
 	return val;
 }
@@ -187,7 +121,7 @@ static void __rk_pcie_write_apb(struct rk_pcie *rk_pcie, void __iomem *base,
 
 	ret = rk_pcie_write(base + reg, size, val);
 	if (ret)
-		dev_err(rk_pcie->dev, "Write APB address failed\n");
+		dev_err(rk_pcie->dw.dev, "Write APB address failed\n");
 }
 
 /**
@@ -214,91 +148,6 @@ static inline void rk_pcie_writel_apb(struct rk_pcie *rk_pcie, u32 reg,
 	__rk_pcie_write_apb(rk_pcie, rk_pcie->apb_base, reg, 0x4, val);
 }
 
-static int rk_pcie_get_link_speed(struct rk_pcie *rk_pcie)
-{
-	return (readl(rk_pcie->dbi_base + PCIE_LINK_STATUS_REG) &
-		PCIE_LINK_STATUS_SPEED_MASK) >> PCIE_LINK_STATUS_SPEED_OFF;
-}
-
-static int rk_pcie_get_link_width(struct rk_pcie *rk_pcie)
-{
-	return (readl(rk_pcie->dbi_base + PCIE_LINK_STATUS_REG) &
-		PCIE_LINK_STATUS_WIDTH_MASK) >> PCIE_LINK_STATUS_WIDTH_OFF;
-}
-
-static void rk_pcie_writel_ob_unroll(struct rk_pcie *rk_pcie, u32 index,
-				     u32 reg, u32 val)
-{
-	u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
-	void __iomem *base = rk_pcie->dbi_base;
-
-	writel(val, base + offset + reg);
-}
-
-static u32 rk_pcie_readl_ob_unroll(struct rk_pcie *rk_pcie, u32 index, u32 reg)
-{
-	u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
-	void __iomem *base = rk_pcie->dbi_base;
-
-	return readl(base + offset + reg);
-}
-
-static inline void rk_pcie_dbi_write_enable(struct rk_pcie *rk_pcie, bool en)
-{
-	u32 val;
-
-	val = readl(rk_pcie->dbi_base + PCIE_MISC_CONTROL_1_OFF);
-
-	if (en)
-		val |= PCIE_DBI_RO_WR_EN;
-	else
-		val &= ~PCIE_DBI_RO_WR_EN;
-	writel(val, rk_pcie->dbi_base + PCIE_MISC_CONTROL_1_OFF);
-}
-
-/**
- * rockchip_pcie_setup_host() - Setup the PCIe controller for RC opertaion
- *
- * @rk_pcie: Pointer to the PCI controller state
- *
- * Configure the host BARs of the PCIe controller root port so that
- * PCI(e) devices may access the system memory.
- */
-static void rk_pcie_setup_host(struct rk_pcie *rk_pcie)
-{
-	u32 val;
-
-	rk_pcie_dbi_write_enable(rk_pcie, true);
-
-	/* setup RC BARs */
-	writel(PCI_BASE_ADDRESS_MEM_TYPE_64,
-	       rk_pcie->dbi_base + PCI_BASE_ADDRESS_0);
-	writel(0x0, rk_pcie->dbi_base + PCI_BASE_ADDRESS_1);
-
-	/* setup interrupt pins */
-	clrsetbits_le32(rk_pcie->dbi_base + PCI_INTERRUPT_LINE,
-			0xff00, 0x100);
-
-	/* setup bus numbers */
-	clrsetbits_le32(rk_pcie->dbi_base + PCI_PRIMARY_BUS,
-			0xffffff, 0x00ff0100);
-
-	/* setup command register */
-	clrsetbits_le32(rk_pcie->dbi_base + PCI_PRIMARY_BUS,
-			0xffff,
-			PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
-			PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
-
-	/* program correct class for RC */
-	writew(PCI_CLASS_BRIDGE_PCI, rk_pcie->dbi_base + PCI_CLASS_DEVICE);
-	/* Better disable write permission right after the update */
-
-	setbits_le32(rk_pcie->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL,
-		     PORT_LOGIC_SPEED_CHANGE)
-
-	rk_pcie_dbi_write_enable(rk_pcie, false);
-}
-
 /**
  * rk_pcie_configure() - Configure link capabilities and speed
  *
@@ -311,242 +160,15 @@ static void rk_pcie_configure(struct rk_pcie *pci, u32 cap_speed)
 {
 	u32 val;
 
-	rk_pcie_dbi_write_enable(pci, true);
+	dw_pcie_dbi_write_enable(&pci->dw, true);
 
-	clrsetbits_le32(pci->dbi_base + PCIE_LINK_CAPABILITY,
+	clrsetbits_le32(pci->dw.dbi_base + PCIE_LINK_CAPABILITY,
 			TARGET_LINK_SPEED_MASK, cap_speed);
 
-	clrsetbits_le32(pci->dbi_base + PCIE_LINK_CTL_2,
+	clrsetbits_le32(pci->dw.dbi_base + PCIE_LINK_CTL_2,
 			TARGET_LINK_SPEED_MASK, cap_speed);
 
-	rk_pcie_dbi_write_enable(pci, false);
-}
-
-/**
- * rk_pcie_dw_prog_outbound_atu_unroll() - Configure ATU for outbound accesses
- *
- * @rk_pcie: Pointer to the PCI controller state
- * @index: ATU region index
- * @type: ATU accsess type
- * @cpu_addr: the physical address for the translation entry
- * @pci_addr: the pcie bus address for the translation entry
- * @size: the size of the translation entry
- *
- * Return: 0 is successful and -1 is failure
- */
-static int rk_pcie_prog_outbound_atu_unroll(struct rk_pcie *pci, int index,
-					    int type, u64 cpu_addr,
-					    u64 pci_addr, u32 size)
-{
-	u32 retries, val;
-
-	dev_dbg(pci->dev, "ATU programmed with: index: %d, type: %d, cpu addr: %8llx, pci addr: %8llx, size: %8x\n",
-		index, type, cpu_addr, pci_addr, size);
-
-	rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE,
-				 lower_32_bits(cpu_addr));
-	rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE,
-				 upper_32_bits(cpu_addr));
-	rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LIMIT,
-				 lower_32_bits(cpu_addr + size - 1));
-	rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
-				 lower_32_bits(pci_addr));
-	rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
-				 upper_32_bits(pci_addr));
-	rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
-				 type);
-	rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
-				 PCIE_ATU_ENABLE);
-
-	/*
-	 * Make sure ATU enable takes effect before any subsequent config
-	 * and I/O accesses.
-	 */
-	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
-		val = rk_pcie_readl_ob_unroll(pci, index,
-					      PCIE_ATU_UNR_REGION_CTRL2);
-		if (val & PCIE_ATU_ENABLE)
-			return 0;
-
-		udelay(LINK_WAIT_IATU_US);
-	}
-	dev_err(pci->dev, "outbound iATU is not being enabled\n");
-
-	return -1;
-}
-
-/**
- * rk_pcie_dw_addr_valid() - Check for valid bus address
- *
- * @d: The PCI device to access
- * @first_busno: Bus number of the PCIe controller root complex
- *
- * Return 1 (true) if the PCI device can be accessed by this controller.
- *
- * Return: 1 on valid, 0 on invalid
- */
-static int rk_pcie_addr_valid(pci_dev_t d, int first_busno)
-{
-	if ((PCI_BUS(d) == first_busno) && (PCI_DEV(d) > 0))
-		return 0;
-	if ((PCI_BUS(d) == first_busno + 1) && (PCI_DEV(d) > 0))
-		return 0;
-
-	return 1;
-}
-
-/**
- * set_cfg_address() - Configure the PCIe controller config space access
- *
- * @rk_pcie: Pointer to the PCI controller state
- * @d: PCI device to access
- * @where: Offset in the configuration space
- *
- * Configures the PCIe controller to access the configuration space of
- * a specific PCIe device and returns the address to use for this
- * access.
- *
- * Return: Address that can be used to access the configation space
- *         of the requested device / offset
- */
-static uintptr_t set_cfg_address(struct rk_pcie *pcie,
-				 pci_dev_t d, uint where)
-{
-	int rel_bus = PCI_BUS(d) - pcie->first_busno;
-	uintptr_t va_address;
-	u32 atu_type;
-	int ret;
-
-	/* Use dbi_base for own configuration read and write */
-	if (!rel_bus) {
-		va_address = (uintptr_t)pcie->dbi_base;
-		goto out;
-	}
-
-	if (rel_bus == 1)
-		/*
-		 * For local bus whose primary bus number is root bridge,
-		 * change TLP Type field to 4.
-		 */
-		atu_type = PCIE_ATU_TYPE_CFG0;
-	else
-		/* Otherwise, change TLP Type field to 5. */
-		atu_type = PCIE_ATU_TYPE_CFG1;
-
-	/*
-	 * Not accessing root port configuration space?
-	 * Region #0 is used for Outbound CFG space access.
-	 * Direction = Outbound
-	 * Region Index = 0
-	 */
-	d = PCI_MASK_BUS(d);
-	d = PCI_ADD_BUS(rel_bus, d);
-	ret = rk_pcie_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
-					       atu_type, (u64)pcie->cfg_base,
-					       d << 8, pcie->cfg_size);
-	if (ret)
-		return (uintptr_t)ret;
-
-	va_address = (uintptr_t)pcie->cfg_base;
-
-out:
-	va_address += where & ~0x3;
-
-	return va_address;
-}
-
-/**
- * rockchip_pcie_rd_conf() - Read from configuration space
- *
- * @bus: Pointer to the PCI bus
- * @bdf: Identifies the PCIe device to access
- * @offset: The offset into the device's configuration space
- * @valuep: A pointer at which to store the read value
- * @size: Indicates the size of access to perform
- *
- * Read a value of size @size from offset @offset within the configuration
- * space of the device identified by the bus, device & function numbers in @bdf
- * on the PCI bus @bus.
- *
- * Return: 0 on success
- */
-static int rockchip_pcie_rd_conf(const struct udevice *bus, pci_dev_t bdf,
-				 uint offset, ulong *valuep,
-				 enum pci_size_t size)
-{
-	struct rk_pcie *pcie = dev_get_priv(bus);
-	uintptr_t va_address;
-	ulong value;
-
-	debug("PCIE CFG read: bdf=%2x:%2x:%2x\n",
-	      PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
-
-	if (!rk_pcie_addr_valid(bdf, pcie->first_busno)) {
-		debug("- out of range\n");
-		*valuep = pci_get_ff(size);
-		return 0;
-	}
-
-	va_address = set_cfg_address(pcie, bdf, offset);
-
-	value = readl(va_address);
-
-	debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
-	*valuep = pci_conv_32_to_size(value, offset, size);
-
-	return rk_pcie_prog_outbound_atu_unroll(pcie,
-						PCIE_ATU_REGION_INDEX1,
-						PCIE_ATU_TYPE_IO,
-						pcie->io.phys_start,
-						pcie->io.bus_start,
-						pcie->io.size);
-}
-
-/**
- * rockchip_pcie_wr_conf() - Write to configuration space
- *
- * @bus: Pointer to the PCI bus
- * @bdf: Identifies the PCIe device to access
- * @offset: The offset into the device's configuration space
- * @value: The value to write
- * @size: Indicates the size of access to perform
- *
- * Write the value @value of size @size from offset @offset within the
- * configuration space of the device identified by the bus, device & function
- * numbers in @bdf on the PCI bus @bus.
- *
- * Return: 0 on success
- */
-static int rockchip_pcie_wr_conf(struct udevice *bus, pci_dev_t bdf,
-				 uint offset, ulong value,
-				 enum pci_size_t size)
-{
-	struct rk_pcie *pcie = dev_get_priv(bus);
-	uintptr_t va_address;
-	ulong old;
-
-	debug("PCIE CFG write: (b,d,f)=(%2d,%2d,%2d)\n",
-	      PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
-	debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
-
-	if (!rk_pcie_addr_valid(bdf, pcie->first_busno)) {
-		debug("- out of range\n");
-		return 0;
-	}
-
-	va_address = set_cfg_address(pcie, bdf, offset);
-
-	old = readl(va_address);
-	value = pci_conv_size_to_32(old, value, offset, size);
-	writel(value, va_address);
-
-	return rk_pcie_prog_outbound_atu_unroll(pcie,
-						PCIE_ATU_REGION_INDEX1,
-						PCIE_ATU_TYPE_IO,
-						pcie->io.phys_start,
-						pcie->io.bus_start,
-						pcie->io.size);
-
+	dw_pcie_dbi_write_enable(&pci->dw, false);
 }
 
 static void rk_pcie_enable_debug(struct rk_pcie *rk_pcie)
@@ -642,19 +264,19 @@ static int rk_pcie_link_up(struct rk_pcie *priv, u32 cap_speed)
 
 	for (retries = 0; retries < 5; retries++) {
 		if (is_link_up(priv)) {
-			dev_info(priv->dev, "PCIe Link up, LTSSM is 0x%x\n",
+			dev_info(priv->dw.dev, "PCIe Link up, LTSSM is 0x%x\n",
 				 rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS));
 			rk_pcie_debug_dump(priv);
 			return 0;
 		}
 
-		dev_info(priv->dev, "PCIe Linking... LTSSM is 0x%x\n",
+		dev_info(priv->dw.dev, "PCIe Linking... LTSSM is 0x%x\n",
 			 rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS));
 		rk_pcie_debug_dump(priv);
 		msleep(1000);
 	}
 
-	dev_err(priv->dev, "PCIe-%d Link Fail\n", dev_seq(priv->dev));
+	dev_err(priv->dw.dev, "PCIe-%d Link Fail\n", dev_seq(priv->dw.dev));
 	/* Link maybe in Gen switch recovery but we need to wait more 1s */
 	msleep(1000);
 	return -EIO;
@@ -670,7 +292,7 @@ static int rockchip_pcie_init_port(struct udevice *dev)
 	if (priv->vpcie3v3) {
 		ret = regulator_set_value(priv->vpcie3v3, 3300000);
 		if (ret) {
-			dev_err(priv->dev, "failed to enable vpcie3v3 (ret=%d)\n",
+			dev_err(priv->dw.dev, "failed to enable vpcie3v3 (ret=%d)\n",
 				ret);
 			return ret;
 		}
@@ -709,7 +331,7 @@ static int rockchip_pcie_init_port(struct udevice *dev)
 
 	/* Set RC mode */
 	rk_pcie_writel_apb(priv, 0x0, 0xf00040);
-	rk_pcie_setup_host(priv);
+	pcie_dw_setup_host(&priv->dw);
 
 	ret = rk_pcie_link_up(priv, LINK_SPEED_GEN_3);
 	if (ret < 0)
@@ -733,11 +355,11 @@ static int rockchip_pcie_parse_dt(struct udevice *dev)
 	struct rk_pcie *priv = dev_get_priv(dev);
 	int ret;
 
-	priv->dbi_base = (void *)dev_read_addr_index(dev, 0);
-	if (!priv->dbi_base)
+	priv->dw.dbi_base = (void *)dev_read_addr_index(dev, 0);
+	if (!priv->dw.dbi_base)
 		return -ENODEV;
 
-	dev_dbg(dev, "DBI address is 0x%p\n", priv->dbi_base);
+	dev_dbg(dev, "DBI address is 0x%p\n", priv->dw.dbi_base);
 
 	priv->apb_base = (void *)dev_read_addr_index(dev, 1);
 	if (!priv->apb_base)
@@ -795,10 +417,10 @@ static int rockchip_pcie_probe(struct udevice *dev)
 	struct rk_pcie *priv = dev_get_priv(dev);
 	struct udevice *ctlr = pci_get_controller(dev);
 	struct pci_controller *hose = dev_get_uclass_priv(ctlr);
-	int reti = 0;
+	int ret = 0;
 
-	priv->first_busno = dev_seq(dev);
-	priv->dev = dev;
+	priv->dw.first_busno = dev_seq(dev);
+	priv->dw.dev = dev;
 
 	ret = rockchip_pcie_parse_dt(dev);
 	if (ret)
@@ -809,58 +431,22 @@ static int rockchip_pcie_probe(struct udevice *dev)
 		return ret;
 
 	dev_info(dev, "PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n",
-		 dev_seq(dev), rk_pcie_get_link_speed(priv),
-		 rk_pcie_get_link_width(priv),
+		 dev_seq(dev), pcie_dw_get_link_speed(&priv->dw),
+		 pcie_dw_get_link_width(&priv->dw),
 		 hose->first_busno);
 
-	for (ret = 0; ret < hose->region_count; ret++) {
-		if (hose->regions[ret].flags == PCI_REGION_IO) {
-			priv->io.phys_start = hose->regions[ret].phys_start; /* IO base */
-			priv->io.bus_start  = hose->regions[ret].bus_start;  /* IO_bus_addr */
-			priv->io.size       = hose->regions[ret].size;      /* IO size */
-		} else if (hose->regions[ret].flags == PCI_REGION_MEM) {
-			priv->mem.phys_start = hose->regions[ret].phys_start; /* MEM base */
-			priv->mem.bus_start  = hose->regions[ret].bus_start;  /* MEM_bus_addr */
-			priv->mem.size	     = hose->regions[ret].size;	    /* MEM size */
-		} else if (hose->regions[ret].flags == PCI_REGION_SYS_MEMORY) {
-			priv->cfg_base = (void *)(priv->io.phys_start - priv->io.size);
-			priv->cfg_size = priv->io.size;
-		} else {
-			dev_err(dev, "invalid flags type!\n");
-		}
-	}
-
-	dev_dbg(dev, "Config space: [0x%p - 0x%p, size 0x%llx]\n",
-		priv->cfg_base, priv->cfg_base + priv->cfg_size,
-		priv->cfg_size);
-
-	dev_dbg(dev, "IO space: [0x%llx - 0x%llx, size 0x%lx]\n",
-		priv->io.phys_start, priv->io.phys_start + priv->io.size,
-		priv->io.size);
-
-	dev_dbg(dev, "IO bus:   [0x%lx - 0x%lx, size 0x%lx]\n",
-		priv->io.bus_start, priv->io.bus_start + priv->io.size,
-		priv->io.size);
-
-	dev_dbg(dev, "MEM space: [0x%llx - 0x%llx, size 0x%lx]\n",
-		priv->mem.phys_start, priv->mem.phys_start + priv->mem.size,
-		priv->mem.size);
-
-	dev_dbg(dev, "MEM bus:   [0x%lx - 0x%lx, size 0x%lx]\n",
-		priv->mem.bus_start, priv->mem.bus_start + priv->mem.size,
-		priv->mem.size);
 
-	return rk_pcie_prog_outbound_atu_unroll(priv,
+	return pcie_dw_prog_outbound_atu_unroll(&priv->dw,
 						PCIE_ATU_REGION_INDEX0,
 						PCIE_ATU_TYPE_MEM,
-						priv->mem.phys_start,
-						priv->mem.bus_start,
-						priv->mem.size);
+						priv->dw.mem.phys_start,
+						priv->dw.mem.bus_start,
+						priv->dw.mem.size);
 }
 
 static const struct dm_pci_ops rockchip_pcie_ops = {
-	.read_config	= rockchip_pcie_rd_conf,
-	.write_config	= rockchip_pcie_wr_conf,
+	.read_config	= pcie_dw_read_config,
+	.write_config	= pcie_dw_write_config,
 };
 
 static const struct udevice_id rockchip_pcie_ids[] = {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH RFT v2 4/4] pci: add Amlogic Meson Designware PCIe controller
  2021-03-25 14:49 ` Neil Armstrong
@ 2021-03-25 14:49   ` Neil Armstrong
  -1 siblings, 0 replies; 26+ messages in thread
From: Neil Armstrong @ 2021-03-25 14:49 UTC (permalink / raw)
  To: u-boot

Add support for the DW PCIe controller found in the Amlogic Meson AXG and
G12 (G12A, G12B, SM1) SoCs.
This uses the common DW PCIe helpers introducted previously.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/pci/Kconfig         |   8 +
 drivers/pci/Makefile        |   1 +
 drivers/pci/pcie_dw_meson.c | 459 ++++++++++++++++++++++++++++++++++++
 3 files changed, 468 insertions(+)
 create mode 100644 drivers/pci/pcie_dw_meson.c

diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index cacfc4bd25..cdcdd8f456 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -276,6 +276,14 @@ config PCIE_MEDIATEK
 	  Say Y here if you want to enable Gen2 PCIe controller,
 	  which could be found on MT7623 SoC family.
 
+config PCIE_DW_MESON
+	bool "Amlogic Meson DesignWare based PCIe controller"
+	depends on ARCH_MESON
+	select PCIE_DW_COMMON
+	help
+	  Say Y here if you want to enable DW PCIe controller support on
+	  Amlogic SoCs.
+
 config PCIE_ROCKCHIP
 	bool "Enable Rockchip PCIe driver"
 	depends on ARCH_ROCKCHIP
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index e3ca8b27e4..96d61821fe 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -50,5 +50,6 @@ obj-$(CONFIG_PCI_KEYSTONE) += pcie_dw_ti.o
 obj-$(CONFIG_PCIE_MEDIATEK) += pcie_mediatek.o
 obj-$(CONFIG_PCIE_ROCKCHIP) += pcie_rockchip.o
 obj-$(CONFIG_PCIE_DW_ROCKCHIP) += pcie_dw_rockchip.o
+obj-$(CONFIG_PCIE_DW_MESON) += pcie_dw_meson.o
 obj-$(CONFIG_PCI_BRCMSTB) += pcie_brcmstb.o
 obj-$(CONFIG_PCI_OCTEONTX) += pci_octeontx.o
diff --git a/drivers/pci/pcie_dw_meson.c b/drivers/pci/pcie_dw_meson.c
new file mode 100644
index 0000000000..0525ecbea6
--- /dev/null
+++ b/drivers/pci/pcie_dw_meson.c
@@ -0,0 +1,459 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Amlogic DesignWare based PCIe host controller driver
+ *
+ * Copyright (c) 2021 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * Based on pcie_dw_rockchip.c
+ * Copyright (c) 2021 Rockchip, Inc.
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <pci.h>
+#include <power-domain.h>
+#include <reset.h>
+#include <syscon.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+#include <dm/device_compat.h>
+#include <linux/iopoll.h>
+#include <linux/delay.h>
+#include <linux/log2.h>
+#include <linux/bitfield.h>
+
+#include "pcie_dw_common.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * struct meson_pcie - Amlogic Meson DW PCIe controller state
+ *
+ * @pci: The common PCIe DW structure
+ * @meson_cfg_base: The base address of vendor regs
+ * @phy
+ * @clk_port
+ * @clk_general
+ * @clk_pclk
+ * @rsts
+ * @rst_gpio: The #PERST signal for slot
+ */
+struct meson_pcie {
+	/* Must be first member of the struct */
+	struct pcie_dw dw;
+	void *meson_cfg_base;
+	struct phy phy;
+	struct clk clk_port;
+	struct clk clk_general;
+	struct clk clk_pclk;
+	struct reset_ctl_bulk rsts;
+	struct gpio_desc rst_gpio;
+};
+
+#define PCI_EXP_DEVCTL_PAYLOAD	0x00e0	/* Max_Payload_Size */
+
+#define PCIE_CAP_MAX_PAYLOAD_SIZE(x)	((x) << 5)
+#define PCIE_CAP_MAX_READ_REQ_SIZE(x)	((x) << 12)
+
+/* PCIe specific config registers */
+#define PCIE_CFG0			0x0
+#define APP_LTSSM_ENABLE		BIT(7)
+
+#define PCIE_CFG_STATUS12		0x30
+#define IS_SMLH_LINK_UP(x)		((x) & (1 << 6))
+#define IS_RDLH_LINK_UP(x)		((x) & (1 << 16))
+#define IS_LTSSM_UP(x)			((((x) >> 10) & 0x1f) == 0x11)
+
+#define PCIE_CFG_STATUS17		0x44
+#define PM_CURRENT_STATE(x)		(((x) >> 7) & 0x1)
+
+#define WAIT_LINKUP_TIMEOUT		4000
+#define PORT_CLK_RATE			100000000UL
+#define MAX_PAYLOAD_SIZE		256
+#define MAX_READ_REQ_SIZE		256
+#define PCIE_RESET_DELAY		500
+#define PCIE_SHARED_RESET		1
+#define PCIE_NORMAL_RESET		0
+
+enum pcie_data_rate {
+	PCIE_GEN1,
+	PCIE_GEN2,
+	PCIE_GEN3,
+	PCIE_GEN4
+};
+
+/* Parameters for the waiting for #perst signal */
+#define PERST_WAIT_US			1000000
+
+static inline u32 meson_cfg_readl(struct meson_pcie *priv, u32 reg)
+{
+	return readl(priv->meson_cfg_base + reg);
+}
+
+static inline void meson_cfg_writel(struct meson_pcie *priv, u32 val, u32 reg)
+{
+	writel(val, priv->meson_cfg_base + reg);
+}
+
+/**
+ * meson_pcie_configure() - Configure link
+ *
+ * @meson_pcie: Pointer to the PCI controller state
+ *
+ * Configure the link mode and width
+ */
+static void meson_pcie_configure(struct meson_pcie *priv)
+{
+	u32 val;
+
+	dw_pcie_dbi_write_enable(&priv->dw, true);
+
+	val = readl(priv->dw.dbi_base + PCIE_PORT_LINK_CONTROL);
+	val &= ~PORT_LINK_FAST_LINK_MODE;
+	val |= PORT_LINK_DLL_LINK_EN;
+	val &= ~PORT_LINK_MODE_MASK;
+	val |= PORT_LINK_MODE_1_LANES;
+	writel(val, priv->dw.dbi_base + PCIE_PORT_LINK_CONTROL);
+
+	val = readl(priv->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
+	val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
+	val |= PORT_LOGIC_LINK_WIDTH_1_LANES;
+	writel(val, priv->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
+
+	dw_pcie_dbi_write_enable(&priv->dw, false);
+}
+
+static inline void meson_pcie_enable_ltssm(struct meson_pcie *priv)
+{
+	u32 val;
+
+	val = meson_cfg_readl(priv, PCIE_CFG0);
+	val |= APP_LTSSM_ENABLE;
+	meson_cfg_writel(priv, val, PCIE_CFG0);
+}
+
+static int meson_pcie_wait_link_up(struct meson_pcie *priv)
+{
+	u32 speed_okay = 0;
+	u32 cnt = 0;
+	u32 state12, state17, smlh_up, ltssm_up, rdlh_up;
+
+	do {
+		state12 = meson_cfg_readl(priv, PCIE_CFG_STATUS12);
+		state17 = meson_cfg_readl(priv, PCIE_CFG_STATUS17);
+		smlh_up = IS_SMLH_LINK_UP(state12);
+		rdlh_up = IS_RDLH_LINK_UP(state12);
+		ltssm_up = IS_LTSSM_UP(state12);
+
+		if (PM_CURRENT_STATE(state17) < PCIE_GEN3)
+			speed_okay = 1;
+
+		if (smlh_up)
+			debug("%s: smlh_link_up is on\n", __func__);
+		if (rdlh_up)
+			debug("%s: rdlh_link_up is on\n", __func__);
+		if (ltssm_up)
+			debug("%s: ltssm_up is on\n", __func__);
+		if (speed_okay)
+			debug("%s: speed_okay\n", __func__);
+
+		if (smlh_up && rdlh_up && ltssm_up && speed_okay)
+			return 0;
+
+		cnt++;
+
+		udelay(10);
+	} while (cnt < WAIT_LINKUP_TIMEOUT);
+
+	printf("%s: error: wait linkup timeout\n", __func__);
+	return -EIO;
+}
+
+/**
+ * meson_pcie_link_up() - Wait for the link to come up
+ *
+ * @meson_pcie: Pointer to the PCI controller state
+ * @cap_speed: Desired link speed
+ *
+ * Return: 1 (true) for active line and negative (false) for no link (timeout)
+ */
+static int meson_pcie_link_up(struct meson_pcie *priv, u32 cap_speed)
+{
+	/* DW link configurations */
+	meson_pcie_configure(priv);
+
+	/* Reset the device */
+	if (dm_gpio_is_valid(&priv->rst_gpio)) {
+		dm_gpio_set_value(&priv->rst_gpio, 1);
+		/*
+		 * Minimal is 100ms from spec but we see
+		 * some wired devices need much more, such as 600ms.
+		 * Add a enough delay to cover all cases.
+		 */
+		udelay(PERST_WAIT_US);
+		dm_gpio_set_value(&priv->rst_gpio, 0);
+	}
+
+	/* Enable LTSSM */
+	meson_pcie_enable_ltssm(priv);
+
+	return meson_pcie_wait_link_up(priv);
+}
+
+static int meson_size_to_payload(int size)
+{
+	/*
+	 * dwc supports 2^(val+7) payload size, which val is 0~5 default to 1.
+	 * So if input size is not 2^order alignment or less than 2^7 or bigger
+	 * than 2^12, just set to default size 2^(1+7).
+	 */
+	if (!is_power_of_2(size) || size < 128 || size > 4096) {
+		debug("%s: payload size %d, set to default 256\n", __func__, size);
+		return 1;
+	}
+
+	return fls(size) - 8;
+}
+
+static void meson_set_max_payload(struct meson_pcie *priv, int size)
+{
+	u32 val;
+	u16 offset = dm_pci_find_capability(priv->dw.dev, PCI_CAP_ID_EXP);
+	int max_payload_size = meson_size_to_payload(size);
+
+	dw_pcie_dbi_write_enable(&priv->dw, true);
+
+	val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
+	val &= ~PCI_EXP_DEVCTL_PAYLOAD;
+	writel(val, priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
+
+	val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
+	val |= PCIE_CAP_MAX_PAYLOAD_SIZE(max_payload_size);
+	writel(val, priv->dw.dbi_base + PCI_EXP_DEVCTL);
+
+	dw_pcie_dbi_write_enable(&priv->dw, false);
+}
+
+static void meson_set_max_rd_req_size(struct meson_pcie *priv, int size)
+{
+	u32 val;
+	u16 offset = dm_pci_find_capability(priv->dw.dev, PCI_CAP_ID_EXP);
+	int max_rd_req_size = meson_size_to_payload(size);
+
+	dw_pcie_dbi_write_enable(&priv->dw, true);
+
+	val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
+	val &= ~PCI_EXP_DEVCTL_PAYLOAD;
+	writel(val, priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
+
+	val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
+	val |= PCIE_CAP_MAX_READ_REQ_SIZE(max_rd_req_size);
+	writel(val, priv->dw.dbi_base + PCI_EXP_DEVCTL);
+
+	dw_pcie_dbi_write_enable(&priv->dw, false);
+}
+
+static int meson_pcie_init_port(struct udevice *dev)
+{
+	int ret;
+	struct meson_pcie *priv = dev_get_priv(dev);
+
+	ret = generic_phy_init(&priv->phy);
+	if (ret) {
+		dev_err(dev, "failed to init phy (ret=%d)\n", ret);
+		return ret;
+	}
+
+	ret = generic_phy_power_on(&priv->phy);
+	if (ret) {
+		dev_err(dev, "failed to power on phy (ret=%d)\n", ret);
+		goto err_exit_phy;
+	}
+
+	ret = generic_phy_reset(&priv->phy);
+	if (ret) {
+		dev_err(dev, "failed to reset phy (ret=%d)\n", ret);
+		goto err_exit_phy;
+	}
+
+	ret = reset_assert_bulk(&priv->rsts);
+	if (ret) {
+		dev_err(dev, "failed to assert resets (ret=%d)\n", ret);
+		goto err_power_off_phy;
+	}
+
+	udelay(PCIE_RESET_DELAY);
+
+	ret = reset_deassert_bulk(&priv->rsts);
+	if (ret) {
+		dev_err(dev, "failed to deassert resets (ret=%d)\n", ret);
+		goto err_power_off_phy;
+	}
+
+	udelay(PCIE_RESET_DELAY);
+
+	ret = clk_set_rate(&priv->clk_port, PORT_CLK_RATE);
+	if (ret) {
+		dev_err(dev, "failed to set port clk rate (ret=%d)\n", ret);
+		goto err_deassert_bulk;
+	}
+
+	ret = clk_enable(&priv->clk_general);
+	if (ret) {
+		dev_err(dev, "failed to enable clk general (ret=%d)\n", ret);
+		goto err_deassert_bulk;
+	}
+
+	ret = clk_enable(&priv->clk_pclk);
+	if (ret) {
+		dev_err(dev, "failed to enable pclk (ret=%d)\n", ret);
+		goto err_deassert_bulk;
+	}
+
+	meson_set_max_payload(priv, MAX_PAYLOAD_SIZE);
+	meson_set_max_rd_req_size(priv, MAX_READ_REQ_SIZE);
+
+	pcie_dw_setup_host(&priv->dw);
+
+	ret = meson_pcie_link_up(priv, LINK_SPEED_GEN_2);
+	if (ret < 0)
+		goto err_link_up;
+
+	return 0;
+err_link_up:
+	clk_disable(&priv->clk_port);
+	clk_disable(&priv->clk_general);
+	clk_disable(&priv->clk_pclk);
+err_deassert_bulk:
+	reset_assert_bulk(&priv->rsts);
+err_power_off_phy:
+	generic_phy_power_off(&priv->phy);
+err_exit_phy:
+	generic_phy_exit(&priv->phy);
+
+	return ret;
+}
+
+static int meson_pcie_parse_dt(struct udevice *dev)
+{
+	struct meson_pcie *priv = dev_get_priv(dev);
+	int ret;
+
+	priv->dw.dbi_base = (void *)dev_read_addr_index(dev, 0);
+	if (!priv->dw.dbi_base)
+		return -ENODEV;
+
+	dev_dbg(dev, "ELBI address is 0x%p\n", priv->dw.dbi_base);
+
+	priv->meson_cfg_base = (void *)dev_read_addr_index(dev, 1);
+	if (!priv->meson_cfg_base)
+		return -ENODEV;
+
+	dev_dbg(dev, "CFG address is 0x%p\n", priv->meson_cfg_base);
+
+	ret = gpio_request_by_name(dev, "reset-gpios", 0,
+				   &priv->rst_gpio, GPIOD_IS_OUT);
+	if (ret) {
+		dev_err(dev, "failed to find reset-gpios property\n");
+		return ret;
+	}
+
+	ret = reset_get_bulk(dev, &priv->rsts);
+	if (ret) {
+		dev_err(dev, "Can't get reset: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_get_by_name(dev, "port", &priv->clk_port);
+	if (ret) {
+		dev_err(dev, "Can't get port clock: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_get_by_name(dev, "general", &priv->clk_general);
+	if (ret) {
+		dev_err(dev, "Can't get port clock: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_get_by_name(dev, "pclk", &priv->clk_pclk);
+	if (ret) {
+		dev_err(dev, "Can't get port clock: %d\n", ret);
+		return ret;
+	}
+
+	ret = generic_phy_get_by_index(dev, 0, &priv->phy);
+	if (ret) {
+		dev_err(dev, "failed to get pcie phy (ret=%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * meson_pcie_probe() - Probe the PCIe bus for active link
+ *
+ * @dev: A pointer to the device being operated on
+ *
+ * Probe for an active link on the PCIe bus and configure the controller
+ * to enable this port.
+ *
+ * Return: 0 on success, else -ENODEV
+ */
+static int meson_pcie_probe(struct udevice *dev)
+{
+	struct meson_pcie *priv = dev_get_priv(dev);
+	struct udevice *ctlr = pci_get_controller(dev);
+	struct pci_controller *hose = dev_get_uclass_priv(ctlr);
+	int ret = 0;
+
+	priv->dw.first_busno = dev_seq(dev);
+	priv->dw.dev = dev;
+
+	ret = meson_pcie_parse_dt(dev);
+	if (ret)
+		return ret;
+
+	ret = meson_pcie_init_port(dev);
+	if (ret) {
+		dm_gpio_free(dev, &priv->rst_gpio);
+		return ret;
+	}
+
+	printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n",
+	       dev_seq(dev), pcie_dw_get_link_speed(&priv->dw),
+	       pcie_dw_get_link_width(&priv->dw),
+	       hose->first_busno);
+
+	return pcie_dw_prog_outbound_atu_unroll(&priv->dw,
+						PCIE_ATU_REGION_INDEX0,
+						PCIE_ATU_TYPE_MEM,
+						priv->dw.mem.phys_start,
+						priv->dw.mem.bus_start,
+						priv->dw.mem.size);
+}
+
+static const struct dm_pci_ops meson_pcie_ops = {
+	.read_config	= pcie_dw_read_config,
+	.write_config	= pcie_dw_write_config,
+};
+
+static const struct udevice_id meson_pcie_ids[] = {
+	{ .compatible = "amlogic,axg-pcie" },
+	{ .compatible = "amlogic,g12a-pcie" },
+	{ }
+};
+
+U_BOOT_DRIVER(meson_dw_pcie) = {
+	.name			= "pcie_dw_meson",
+	.id			= UCLASS_PCI,
+	.of_match		= meson_pcie_ids,
+	.ops			= &meson_pcie_ops,
+	.probe			= meson_pcie_probe,
+	.priv_auto		= sizeof(struct meson_pcie),
+};
-- 
2.25.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH RFT v2 4/4] pci: add Amlogic Meson Designware PCIe controller
@ 2021-03-25 14:49   ` Neil Armstrong
  0 siblings, 0 replies; 26+ messages in thread
From: Neil Armstrong @ 2021-03-25 14:49 UTC (permalink / raw)
  To: lokeshvutla, nsekhar, shawn.lin, bmeng.cn, green.wan
  Cc: u-boot, u-boot-amlogic, Neil Armstrong

Add support for the DW PCIe controller found in the Amlogic Meson AXG and
G12 (G12A, G12B, SM1) SoCs.
This uses the common DW PCIe helpers introducted previously.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/pci/Kconfig         |   8 +
 drivers/pci/Makefile        |   1 +
 drivers/pci/pcie_dw_meson.c | 459 ++++++++++++++++++++++++++++++++++++
 3 files changed, 468 insertions(+)
 create mode 100644 drivers/pci/pcie_dw_meson.c

diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index cacfc4bd25..cdcdd8f456 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -276,6 +276,14 @@ config PCIE_MEDIATEK
 	  Say Y here if you want to enable Gen2 PCIe controller,
 	  which could be found on MT7623 SoC family.
 
+config PCIE_DW_MESON
+	bool "Amlogic Meson DesignWare based PCIe controller"
+	depends on ARCH_MESON
+	select PCIE_DW_COMMON
+	help
+	  Say Y here if you want to enable DW PCIe controller support on
+	  Amlogic SoCs.
+
 config PCIE_ROCKCHIP
 	bool "Enable Rockchip PCIe driver"
 	depends on ARCH_ROCKCHIP
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index e3ca8b27e4..96d61821fe 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -50,5 +50,6 @@ obj-$(CONFIG_PCI_KEYSTONE) += pcie_dw_ti.o
 obj-$(CONFIG_PCIE_MEDIATEK) += pcie_mediatek.o
 obj-$(CONFIG_PCIE_ROCKCHIP) += pcie_rockchip.o
 obj-$(CONFIG_PCIE_DW_ROCKCHIP) += pcie_dw_rockchip.o
+obj-$(CONFIG_PCIE_DW_MESON) += pcie_dw_meson.o
 obj-$(CONFIG_PCI_BRCMSTB) += pcie_brcmstb.o
 obj-$(CONFIG_PCI_OCTEONTX) += pci_octeontx.o
diff --git a/drivers/pci/pcie_dw_meson.c b/drivers/pci/pcie_dw_meson.c
new file mode 100644
index 0000000000..0525ecbea6
--- /dev/null
+++ b/drivers/pci/pcie_dw_meson.c
@@ -0,0 +1,459 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Amlogic DesignWare based PCIe host controller driver
+ *
+ * Copyright (c) 2021 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * Based on pcie_dw_rockchip.c
+ * Copyright (c) 2021 Rockchip, Inc.
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <pci.h>
+#include <power-domain.h>
+#include <reset.h>
+#include <syscon.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+#include <dm/device_compat.h>
+#include <linux/iopoll.h>
+#include <linux/delay.h>
+#include <linux/log2.h>
+#include <linux/bitfield.h>
+
+#include "pcie_dw_common.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * struct meson_pcie - Amlogic Meson DW PCIe controller state
+ *
+ * @pci: The common PCIe DW structure
+ * @meson_cfg_base: The base address of vendor regs
+ * @phy
+ * @clk_port
+ * @clk_general
+ * @clk_pclk
+ * @rsts
+ * @rst_gpio: The #PERST signal for slot
+ */
+struct meson_pcie {
+	/* Must be first member of the struct */
+	struct pcie_dw dw;
+	void *meson_cfg_base;
+	struct phy phy;
+	struct clk clk_port;
+	struct clk clk_general;
+	struct clk clk_pclk;
+	struct reset_ctl_bulk rsts;
+	struct gpio_desc rst_gpio;
+};
+
+#define PCI_EXP_DEVCTL_PAYLOAD	0x00e0	/* Max_Payload_Size */
+
+#define PCIE_CAP_MAX_PAYLOAD_SIZE(x)	((x) << 5)
+#define PCIE_CAP_MAX_READ_REQ_SIZE(x)	((x) << 12)
+
+/* PCIe specific config registers */
+#define PCIE_CFG0			0x0
+#define APP_LTSSM_ENABLE		BIT(7)
+
+#define PCIE_CFG_STATUS12		0x30
+#define IS_SMLH_LINK_UP(x)		((x) & (1 << 6))
+#define IS_RDLH_LINK_UP(x)		((x) & (1 << 16))
+#define IS_LTSSM_UP(x)			((((x) >> 10) & 0x1f) == 0x11)
+
+#define PCIE_CFG_STATUS17		0x44
+#define PM_CURRENT_STATE(x)		(((x) >> 7) & 0x1)
+
+#define WAIT_LINKUP_TIMEOUT		4000
+#define PORT_CLK_RATE			100000000UL
+#define MAX_PAYLOAD_SIZE		256
+#define MAX_READ_REQ_SIZE		256
+#define PCIE_RESET_DELAY		500
+#define PCIE_SHARED_RESET		1
+#define PCIE_NORMAL_RESET		0
+
+enum pcie_data_rate {
+	PCIE_GEN1,
+	PCIE_GEN2,
+	PCIE_GEN3,
+	PCIE_GEN4
+};
+
+/* Parameters for the waiting for #perst signal */
+#define PERST_WAIT_US			1000000
+
+static inline u32 meson_cfg_readl(struct meson_pcie *priv, u32 reg)
+{
+	return readl(priv->meson_cfg_base + reg);
+}
+
+static inline void meson_cfg_writel(struct meson_pcie *priv, u32 val, u32 reg)
+{
+	writel(val, priv->meson_cfg_base + reg);
+}
+
+/**
+ * meson_pcie_configure() - Configure link
+ *
+ * @meson_pcie: Pointer to the PCI controller state
+ *
+ * Configure the link mode and width
+ */
+static void meson_pcie_configure(struct meson_pcie *priv)
+{
+	u32 val;
+
+	dw_pcie_dbi_write_enable(&priv->dw, true);
+
+	val = readl(priv->dw.dbi_base + PCIE_PORT_LINK_CONTROL);
+	val &= ~PORT_LINK_FAST_LINK_MODE;
+	val |= PORT_LINK_DLL_LINK_EN;
+	val &= ~PORT_LINK_MODE_MASK;
+	val |= PORT_LINK_MODE_1_LANES;
+	writel(val, priv->dw.dbi_base + PCIE_PORT_LINK_CONTROL);
+
+	val = readl(priv->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
+	val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
+	val |= PORT_LOGIC_LINK_WIDTH_1_LANES;
+	writel(val, priv->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
+
+	dw_pcie_dbi_write_enable(&priv->dw, false);
+}
+
+static inline void meson_pcie_enable_ltssm(struct meson_pcie *priv)
+{
+	u32 val;
+
+	val = meson_cfg_readl(priv, PCIE_CFG0);
+	val |= APP_LTSSM_ENABLE;
+	meson_cfg_writel(priv, val, PCIE_CFG0);
+}
+
+static int meson_pcie_wait_link_up(struct meson_pcie *priv)
+{
+	u32 speed_okay = 0;
+	u32 cnt = 0;
+	u32 state12, state17, smlh_up, ltssm_up, rdlh_up;
+
+	do {
+		state12 = meson_cfg_readl(priv, PCIE_CFG_STATUS12);
+		state17 = meson_cfg_readl(priv, PCIE_CFG_STATUS17);
+		smlh_up = IS_SMLH_LINK_UP(state12);
+		rdlh_up = IS_RDLH_LINK_UP(state12);
+		ltssm_up = IS_LTSSM_UP(state12);
+
+		if (PM_CURRENT_STATE(state17) < PCIE_GEN3)
+			speed_okay = 1;
+
+		if (smlh_up)
+			debug("%s: smlh_link_up is on\n", __func__);
+		if (rdlh_up)
+			debug("%s: rdlh_link_up is on\n", __func__);
+		if (ltssm_up)
+			debug("%s: ltssm_up is on\n", __func__);
+		if (speed_okay)
+			debug("%s: speed_okay\n", __func__);
+
+		if (smlh_up && rdlh_up && ltssm_up && speed_okay)
+			return 0;
+
+		cnt++;
+
+		udelay(10);
+	} while (cnt < WAIT_LINKUP_TIMEOUT);
+
+	printf("%s: error: wait linkup timeout\n", __func__);
+	return -EIO;
+}
+
+/**
+ * meson_pcie_link_up() - Wait for the link to come up
+ *
+ * @meson_pcie: Pointer to the PCI controller state
+ * @cap_speed: Desired link speed
+ *
+ * Return: 1 (true) for active line and negative (false) for no link (timeout)
+ */
+static int meson_pcie_link_up(struct meson_pcie *priv, u32 cap_speed)
+{
+	/* DW link configurations */
+	meson_pcie_configure(priv);
+
+	/* Reset the device */
+	if (dm_gpio_is_valid(&priv->rst_gpio)) {
+		dm_gpio_set_value(&priv->rst_gpio, 1);
+		/*
+		 * Minimal is 100ms from spec but we see
+		 * some wired devices need much more, such as 600ms.
+		 * Add a enough delay to cover all cases.
+		 */
+		udelay(PERST_WAIT_US);
+		dm_gpio_set_value(&priv->rst_gpio, 0);
+	}
+
+	/* Enable LTSSM */
+	meson_pcie_enable_ltssm(priv);
+
+	return meson_pcie_wait_link_up(priv);
+}
+
+static int meson_size_to_payload(int size)
+{
+	/*
+	 * dwc supports 2^(val+7) payload size, which val is 0~5 default to 1.
+	 * So if input size is not 2^order alignment or less than 2^7 or bigger
+	 * than 2^12, just set to default size 2^(1+7).
+	 */
+	if (!is_power_of_2(size) || size < 128 || size > 4096) {
+		debug("%s: payload size %d, set to default 256\n", __func__, size);
+		return 1;
+	}
+
+	return fls(size) - 8;
+}
+
+static void meson_set_max_payload(struct meson_pcie *priv, int size)
+{
+	u32 val;
+	u16 offset = dm_pci_find_capability(priv->dw.dev, PCI_CAP_ID_EXP);
+	int max_payload_size = meson_size_to_payload(size);
+
+	dw_pcie_dbi_write_enable(&priv->dw, true);
+
+	val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
+	val &= ~PCI_EXP_DEVCTL_PAYLOAD;
+	writel(val, priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
+
+	val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
+	val |= PCIE_CAP_MAX_PAYLOAD_SIZE(max_payload_size);
+	writel(val, priv->dw.dbi_base + PCI_EXP_DEVCTL);
+
+	dw_pcie_dbi_write_enable(&priv->dw, false);
+}
+
+static void meson_set_max_rd_req_size(struct meson_pcie *priv, int size)
+{
+	u32 val;
+	u16 offset = dm_pci_find_capability(priv->dw.dev, PCI_CAP_ID_EXP);
+	int max_rd_req_size = meson_size_to_payload(size);
+
+	dw_pcie_dbi_write_enable(&priv->dw, true);
+
+	val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
+	val &= ~PCI_EXP_DEVCTL_PAYLOAD;
+	writel(val, priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
+
+	val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
+	val |= PCIE_CAP_MAX_READ_REQ_SIZE(max_rd_req_size);
+	writel(val, priv->dw.dbi_base + PCI_EXP_DEVCTL);
+
+	dw_pcie_dbi_write_enable(&priv->dw, false);
+}
+
+static int meson_pcie_init_port(struct udevice *dev)
+{
+	int ret;
+	struct meson_pcie *priv = dev_get_priv(dev);
+
+	ret = generic_phy_init(&priv->phy);
+	if (ret) {
+		dev_err(dev, "failed to init phy (ret=%d)\n", ret);
+		return ret;
+	}
+
+	ret = generic_phy_power_on(&priv->phy);
+	if (ret) {
+		dev_err(dev, "failed to power on phy (ret=%d)\n", ret);
+		goto err_exit_phy;
+	}
+
+	ret = generic_phy_reset(&priv->phy);
+	if (ret) {
+		dev_err(dev, "failed to reset phy (ret=%d)\n", ret);
+		goto err_exit_phy;
+	}
+
+	ret = reset_assert_bulk(&priv->rsts);
+	if (ret) {
+		dev_err(dev, "failed to assert resets (ret=%d)\n", ret);
+		goto err_power_off_phy;
+	}
+
+	udelay(PCIE_RESET_DELAY);
+
+	ret = reset_deassert_bulk(&priv->rsts);
+	if (ret) {
+		dev_err(dev, "failed to deassert resets (ret=%d)\n", ret);
+		goto err_power_off_phy;
+	}
+
+	udelay(PCIE_RESET_DELAY);
+
+	ret = clk_set_rate(&priv->clk_port, PORT_CLK_RATE);
+	if (ret) {
+		dev_err(dev, "failed to set port clk rate (ret=%d)\n", ret);
+		goto err_deassert_bulk;
+	}
+
+	ret = clk_enable(&priv->clk_general);
+	if (ret) {
+		dev_err(dev, "failed to enable clk general (ret=%d)\n", ret);
+		goto err_deassert_bulk;
+	}
+
+	ret = clk_enable(&priv->clk_pclk);
+	if (ret) {
+		dev_err(dev, "failed to enable pclk (ret=%d)\n", ret);
+		goto err_deassert_bulk;
+	}
+
+	meson_set_max_payload(priv, MAX_PAYLOAD_SIZE);
+	meson_set_max_rd_req_size(priv, MAX_READ_REQ_SIZE);
+
+	pcie_dw_setup_host(&priv->dw);
+
+	ret = meson_pcie_link_up(priv, LINK_SPEED_GEN_2);
+	if (ret < 0)
+		goto err_link_up;
+
+	return 0;
+err_link_up:
+	clk_disable(&priv->clk_port);
+	clk_disable(&priv->clk_general);
+	clk_disable(&priv->clk_pclk);
+err_deassert_bulk:
+	reset_assert_bulk(&priv->rsts);
+err_power_off_phy:
+	generic_phy_power_off(&priv->phy);
+err_exit_phy:
+	generic_phy_exit(&priv->phy);
+
+	return ret;
+}
+
+static int meson_pcie_parse_dt(struct udevice *dev)
+{
+	struct meson_pcie *priv = dev_get_priv(dev);
+	int ret;
+
+	priv->dw.dbi_base = (void *)dev_read_addr_index(dev, 0);
+	if (!priv->dw.dbi_base)
+		return -ENODEV;
+
+	dev_dbg(dev, "ELBI address is 0x%p\n", priv->dw.dbi_base);
+
+	priv->meson_cfg_base = (void *)dev_read_addr_index(dev, 1);
+	if (!priv->meson_cfg_base)
+		return -ENODEV;
+
+	dev_dbg(dev, "CFG address is 0x%p\n", priv->meson_cfg_base);
+
+	ret = gpio_request_by_name(dev, "reset-gpios", 0,
+				   &priv->rst_gpio, GPIOD_IS_OUT);
+	if (ret) {
+		dev_err(dev, "failed to find reset-gpios property\n");
+		return ret;
+	}
+
+	ret = reset_get_bulk(dev, &priv->rsts);
+	if (ret) {
+		dev_err(dev, "Can't get reset: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_get_by_name(dev, "port", &priv->clk_port);
+	if (ret) {
+		dev_err(dev, "Can't get port clock: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_get_by_name(dev, "general", &priv->clk_general);
+	if (ret) {
+		dev_err(dev, "Can't get port clock: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_get_by_name(dev, "pclk", &priv->clk_pclk);
+	if (ret) {
+		dev_err(dev, "Can't get port clock: %d\n", ret);
+		return ret;
+	}
+
+	ret = generic_phy_get_by_index(dev, 0, &priv->phy);
+	if (ret) {
+		dev_err(dev, "failed to get pcie phy (ret=%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * meson_pcie_probe() - Probe the PCIe bus for active link
+ *
+ * @dev: A pointer to the device being operated on
+ *
+ * Probe for an active link on the PCIe bus and configure the controller
+ * to enable this port.
+ *
+ * Return: 0 on success, else -ENODEV
+ */
+static int meson_pcie_probe(struct udevice *dev)
+{
+	struct meson_pcie *priv = dev_get_priv(dev);
+	struct udevice *ctlr = pci_get_controller(dev);
+	struct pci_controller *hose = dev_get_uclass_priv(ctlr);
+	int ret = 0;
+
+	priv->dw.first_busno = dev_seq(dev);
+	priv->dw.dev = dev;
+
+	ret = meson_pcie_parse_dt(dev);
+	if (ret)
+		return ret;
+
+	ret = meson_pcie_init_port(dev);
+	if (ret) {
+		dm_gpio_free(dev, &priv->rst_gpio);
+		return ret;
+	}
+
+	printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n",
+	       dev_seq(dev), pcie_dw_get_link_speed(&priv->dw),
+	       pcie_dw_get_link_width(&priv->dw),
+	       hose->first_busno);
+
+	return pcie_dw_prog_outbound_atu_unroll(&priv->dw,
+						PCIE_ATU_REGION_INDEX0,
+						PCIE_ATU_TYPE_MEM,
+						priv->dw.mem.phys_start,
+						priv->dw.mem.bus_start,
+						priv->dw.mem.size);
+}
+
+static const struct dm_pci_ops meson_pcie_ops = {
+	.read_config	= pcie_dw_read_config,
+	.write_config	= pcie_dw_write_config,
+};
+
+static const struct udevice_id meson_pcie_ids[] = {
+	{ .compatible = "amlogic,axg-pcie" },
+	{ .compatible = "amlogic,g12a-pcie" },
+	{ }
+};
+
+U_BOOT_DRIVER(meson_dw_pcie) = {
+	.name			= "pcie_dw_meson",
+	.id			= UCLASS_PCI,
+	.of_match		= meson_pcie_ids,
+	.ops			= &meson_pcie_ops,
+	.probe			= meson_pcie_probe,
+	.priv_auto		= sizeof(struct meson_pcie),
+};
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH RFT v2 1/4] pci: add common Designware PCIe functions
  2021-03-25 14:49   ` Neil Armstrong
@ 2021-03-26  9:21     ` Green Wan
  -1 siblings, 0 replies; 26+ messages in thread
From: Green Wan @ 2021-03-26  9:21 UTC (permalink / raw)
  To: u-boot

Hi Neil,

I rebased my driver and gave it a try today. Add my tested-by.
Tested-by: Green Wan <green.wan@sifive.com>

Thanks,

Hi Bin,

Since fu740 support patches include the designware-based driver and
also in reviewing, do you prefer me to create the patch based on
Neil's pcie_dw_common.c or create a separated PCIE patch after both
fu740 and Neil's patches are merged?

Thanks,
-- Green



On Thu, Mar 25, 2021 at 10:49 PM Neil Armstrong <narmstrong@baylibre.com> wrote:
>
> With the introduction of pcie_dw_rockchip, and need to support the DW PCIe in the
> Amlogic AXG & G12 SoCs, most of the DW PCIe helpers would be duplicated.
>
> This introduce a "common" DW PCIe helpers file with common code merged from the
> dw_ti and dw_rockchip drivers and adapted to fit with the upcoming dw_meson.
>
> The following changes will switch the dw_ti and dw_rockchip to use these helpers.
>
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
>  drivers/pci/Kconfig          |   4 +
>  drivers/pci/Makefile         |   1 +
>  drivers/pci/pcie_dw_common.c | 366 +++++++++++++++++++++++++++++++++++
>  drivers/pci/pcie_dw_common.h | 155 +++++++++++++++
>  4 files changed, 526 insertions(+)
>  create mode 100644 drivers/pci/pcie_dw_common.c
>  create mode 100644 drivers/pci/pcie_dw_common.h
>
> diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
> index ba41787f64..ab5a5e7ed6 100644
> --- a/drivers/pci/Kconfig
> +++ b/drivers/pci/Kconfig
> @@ -258,6 +258,10 @@ config PCI_MVEBU
>           Say Y here if you want to enable PCIe controller support on
>           Armada XP/38x SoCs.
>
> +config PCIE_DW_COMMON
> +       bool
> +       select DM_PCI
> +
>  config PCI_KEYSTONE
>         bool "TI Keystone PCIe controller"
>         depends on DM_PCI
> diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
> index 5ed94bc95c..e3ca8b27e4 100644
> --- a/drivers/pci/Makefile
> +++ b/drivers/pci/Makefile
> @@ -45,6 +45,7 @@ obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o \
>  obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o
>  obj-$(CONFIG_PCI_PHYTIUM) += pcie_phytium.o
>  obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o
> +obj-$(CONFIG_PCIE_DW_COMMON) += pcie_dw_common.o
>  obj-$(CONFIG_PCI_KEYSTONE) += pcie_dw_ti.o
>  obj-$(CONFIG_PCIE_MEDIATEK) += pcie_mediatek.o
>  obj-$(CONFIG_PCIE_ROCKCHIP) += pcie_rockchip.o
> diff --git a/drivers/pci/pcie_dw_common.c b/drivers/pci/pcie_dw_common.c
> new file mode 100644
> index 0000000000..7c92b7b754
> --- /dev/null
> +++ b/drivers/pci/pcie_dw_common.c
> @@ -0,0 +1,366 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (c) 2021 BayLibre, SAS
> + * Author: Neil Armstrong <narmstrong@baylibre.com>
> + *
> + * Copyright (c) 2021 Rockchip, Inc.
> + *
> + * Copyright (C) 2018 Texas Instruments, Inc
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <log.h>
> +#include <pci.h>
> +#include <dm/device_compat.h>
> +#include <asm/io.h>
> +#include <linux/delay.h>
> +#include "pcie_dw_common.h"
> +
> +int pcie_dw_get_link_speed(struct pcie_dw *pci)
> +{
> +       return (readl(pci->dbi_base + PCIE_LINK_STATUS_REG) &
> +               PCIE_LINK_STATUS_SPEED_MASK) >> PCIE_LINK_STATUS_SPEED_OFF;
> +}
> +
> +int pcie_dw_get_link_width(struct pcie_dw *pci)
> +{
> +       return (readl(pci->dbi_base + PCIE_LINK_STATUS_REG) &
> +               PCIE_LINK_STATUS_WIDTH_MASK) >> PCIE_LINK_STATUS_WIDTH_OFF;
> +}
> +
> +static void dw_pcie_writel_ob_unroll(struct pcie_dw *pci, u32 index, u32 reg,
> +                                    u32 val)
> +{
> +       u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
> +       void __iomem *base = pci->atu_base;
> +
> +       writel(val, base + offset + reg);
> +}
> +
> +static u32 dw_pcie_readl_ob_unroll(struct pcie_dw *pci, u32 index, u32 reg)
> +{
> +       u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
> +       void __iomem *base = pci->atu_base;
> +
> +       return readl(base + offset + reg);
> +}
> +
> +/**
> + * pcie_dw_prog_outbound_atu_unroll() - Configure ATU for outbound accesses
> + *
> + * @pcie: Pointer to the PCI controller state
> + * @index: ATU region index
> + * @type: ATU accsess type
> + * @cpu_addr: the physical address for the translation entry
> + * @pci_addr: the pcie bus address for the translation entry
> + * @size: the size of the translation entry
> + *
> + * Return: 0 is successful and -1 is failure
> + */
> +int pcie_dw_prog_outbound_atu_unroll(struct pcie_dw *pci, int index,
> +                                    int type, u64 cpu_addr,
> +                                            u64 pci_addr, u32 size)
> +{
> +       u32 retries, val;
> +
> +       dev_dbg(pci->dev, "ATU programmed with: index: %d, type: %d, cpu addr: %8llx, pci addr: %8llx, size: %8x\n",
> +               index, type, cpu_addr, pci_addr, size);
> +
> +       dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE,
> +                                lower_32_bits(cpu_addr));
> +       dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE,
> +                                upper_32_bits(cpu_addr));
> +       dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LIMIT,
> +                                lower_32_bits(cpu_addr + size - 1));
> +       dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
> +                                lower_32_bits(pci_addr));
> +       dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
> +                                upper_32_bits(pci_addr));
> +       dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
> +                                type);
> +       dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
> +                                PCIE_ATU_ENABLE);
> +
> +       /*
> +        * Make sure ATU enable takes effect before any subsequent config
> +        * and I/O accesses.
> +        */
> +       for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
> +               val = dw_pcie_readl_ob_unroll(pci, index,
> +                                             PCIE_ATU_UNR_REGION_CTRL2);
> +               if (val & PCIE_ATU_ENABLE)
> +                       return 0;
> +
> +               udelay(LINK_WAIT_IATU);
> +       }
> +       dev_err(pci->dev, "outbound iATU is not being enabled\n");
> +
> +       return -1;
> +}
> +
> +/**
> + * set_cfg_address() - Configure the PCIe controller config space access
> + *
> + * @pcie: Pointer to the PCI controller state
> + * @d: PCI device to access
> + * @where: Offset in the configuration space
> + *
> + * Configures the PCIe controller to access the configuration space of
> + * a specific PCIe device and returns the address to use for this
> + * access.
> + *
> + * Return: Address that can be used to access the configation space
> + *         of the requested device / offset
> + */
> +static uintptr_t set_cfg_address(struct pcie_dw *pcie,
> +                                pci_dev_t d, uint where)
> +{
> +       int bus = PCI_BUS(d) - pcie->first_busno;
> +       uintptr_t va_address;
> +       u32 atu_type;
> +       int ret;
> +
> +       /* Use dbi_base for own configuration read and write */
> +       if (!bus) {
> +               va_address = (uintptr_t)pcie->dbi_base;
> +               goto out;
> +       }
> +
> +       if (bus == 1)
> +               /*
> +                * For local bus whose primary bus number is root bridge,
> +                * change TLP Type field to 4.
> +                */
> +               atu_type = PCIE_ATU_TYPE_CFG0;
> +       else
> +               /* Otherwise, change TLP Type field to 5. */
> +               atu_type = PCIE_ATU_TYPE_CFG1;
> +
> +       /*
> +        * Not accessing root port configuration space?
> +        * Region #0 is used for Outbound CFG space access.
> +        * Direction = Outbound
> +        * Region Index = 0
> +        */
> +       d = PCI_MASK_BUS(d);
> +       d = PCI_ADD_BUS(bus, d);
> +       ret = pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
> +                                              atu_type, (u64)pcie->cfg_base,
> +                                               d << 8, pcie->cfg_size);
> +       if (ret)
> +               return (uintptr_t)ret;
> +
> +       va_address = (uintptr_t)pcie->cfg_base;
> +
> +out:
> +       va_address += where & ~0x3;
> +
> +       return va_address;
> +}
> +
> +/**
> + * pcie_dw_addr_valid() - Check for valid bus address
> + *
> + * @d: The PCI device to access
> + * @first_busno: Bus number of the PCIe controller root complex
> + *
> + * Return 1 (true) if the PCI device can be accessed by this controller.
> + *
> + * Return: 1 on valid, 0 on invalid
> + */
> +static int pcie_dw_addr_valid(pci_dev_t d, int first_busno)
> +{
> +       if ((PCI_BUS(d) == first_busno) && (PCI_DEV(d) > 0))
> +               return 0;
> +       if ((PCI_BUS(d) == first_busno + 1) && (PCI_DEV(d) > 0))
> +               return 0;
> +
> +       return 1;
> +}
> +
> +/**
> + * pcie_dw_read_config() - Read from configuration space
> + *
> + * @bus: Pointer to the PCI bus
> + * @bdf: Identifies the PCIe device to access
> + * @offset: The offset into the device's configuration space
> + * @valuep: A pointer at which to store the read value
> + * @size: Indicates the size of access to perform
> + *
> + * Read a value of size @size from offset @offset within the configuration
> + * space of the device identified by the bus, device & function numbers in @bdf
> + * on the PCI bus @bus.
> + *
> + * Return: 0 on success
> + */
> +int pcie_dw_read_config(const struct udevice *bus, pci_dev_t bdf,
> +                       uint offset, ulong *valuep,
> +                       enum pci_size_t size)
> +{
> +       struct pcie_dw *pcie = dev_get_priv(bus);
> +       uintptr_t va_address;
> +       ulong value;
> +
> +       dev_dbg(pcie->dev, "PCIE CFG read: bdf=%2x:%2x:%2x ",
> +               PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
> +
> +       if (!pcie_dw_addr_valid(bdf, pcie->first_busno)) {
> +               debug("- out of range\n");
> +               *valuep = pci_get_ff(size);
> +               return 0;
> +       }
> +
> +       va_address = set_cfg_address(pcie, bdf, offset);
> +
> +       value = readl(va_address);
> +
> +       debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
> +       *valuep = pci_conv_32_to_size(value, offset, size);
> +
> +       return pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
> +                                                PCIE_ATU_TYPE_IO, pcie->io.phys_start,
> +                                                pcie->io.bus_start, pcie->io.size);
> +}
> +
> +/**
> + * pcie_dw_write_config() - Write to configuration space
> + *
> + * @bus: Pointer to the PCI bus
> + * @bdf: Identifies the PCIe device to access
> + * @offset: The offset into the device's configuration space
> + * @value: The value to write
> + * @size: Indicates the size of access to perform
> + *
> + * Write the value @value of size @size from offset @offset within the
> + * configuration space of the device identified by the bus, device & function
> + * numbers in @bdf on the PCI bus @bus.
> + *
> + * Return: 0 on success
> + */
> +int pcie_dw_write_config(struct udevice *bus, pci_dev_t bdf,
> +                        uint offset, ulong value,
> +                        enum pci_size_t size)
> +{
> +       struct pcie_dw *pcie = dev_get_priv(bus);
> +       uintptr_t va_address;
> +       ulong old;
> +
> +       dev_dbg(pcie->dev, "PCIE CFG write: (b,d,f)=(%2d,%2d,%2d) ",
> +               PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
> +       dev_dbg(pcie->dev, "(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
> +
> +       if (!pcie_dw_addr_valid(bdf, pcie->first_busno)) {
> +               debug("- out of range\n");
> +               return 0;
> +       }
> +
> +       va_address = set_cfg_address(pcie, bdf, offset);
> +
> +       old = readl(va_address);
> +       value = pci_conv_size_to_32(old, value, offset, size);
> +       writel(value, va_address);
> +
> +       return pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
> +                                                PCIE_ATU_TYPE_IO, pcie->io.phys_start,
> +                                                pcie->io.bus_start, pcie->io.size);
> +}
> +
> +/**
> + * pcie_dw_setup_host() - Setup the PCIe controller for RC opertaion
> + *
> + * @pcie: Pointer to the PCI controller state
> + *
> + * Configure the host BARs of the PCIe controller root port so that
> + * PCI(e) devices may access the system memory.
> + */
> +void pcie_dw_setup_host(struct pcie_dw *pci)
> +{
> +       struct udevice *ctlr = pci_get_controller(pci->dev);
> +       struct pci_controller *hose = dev_get_uclass_priv(ctlr);
> +       u32 ret;
> +
> +       if (!pci->atu_base)
> +               pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
> +
> +       /* setup RC BARs */
> +       writel(PCI_BASE_ADDRESS_MEM_TYPE_64,
> +              pci->dbi_base + PCI_BASE_ADDRESS_0);
> +       writel(0x0, pci->dbi_base + PCI_BASE_ADDRESS_1);
> +
> +       /* setup interrupt pins */
> +       clrsetbits_le32(pci->dbi_base + PCI_INTERRUPT_LINE,
> +                       0xff00, 0x100);
> +
> +       /* setup bus numbers */
> +       clrsetbits_le32(pci->dbi_base + PCI_PRIMARY_BUS,
> +                       0xffffff, 0x00ff0100);
> +
> +       /* setup command register */
> +       clrsetbits_le32(pci->dbi_base + PCI_PRIMARY_BUS,
> +                       0xffff,
> +                       PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
> +                       PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
> +
> +       /* Enable write permission for the DBI read-only register */
> +       dw_pcie_dbi_write_enable(pci, true);
> +       /* program correct class for RC */
> +       writew(PCI_CLASS_BRIDGE_PCI, pci->dbi_base + PCI_CLASS_DEVICE);
> +       /* Better disable write permission right after the update */
> +       dw_pcie_dbi_write_enable(pci, false);
> +
> +       setbits_le32(pci->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL,
> +                    PORT_LOGIC_SPEED_CHANGE);
> +
> +       for (ret = 0; ret < hose->region_count; ret++) {
> +               if (hose->regions[ret].flags == PCI_REGION_IO) {
> +                       pci->io.phys_start = hose->regions[ret].phys_start; /* IO base */
> +                       pci->io.bus_start = hose->regions[ret].bus_start;  /* IO_bus_addr */
> +                       pci->io.size = hose->regions[ret].size;      /* IO size */
> +               } else if (hose->regions[ret].flags == PCI_REGION_MEM) {
> +                       pci->mem.phys_start = hose->regions[ret].phys_start; /* MEM base */
> +                       pci->mem.bus_start = hose->regions[ret].bus_start;  /* MEM_bus_addr */
> +                       pci->mem.size = hose->regions[ret].size;            /* MEM size */
> +               } else if (hose->regions[ret].flags == PCI_REGION_PREFETCH) {
> +                       pci->prefetch.phys_start = hose->regions[ret].phys_start; /* PREFETCH base */
> +                       pci->prefetch.bus_start = hose->regions[ret].bus_start;  /* PREFETCH_bus_addr */
> +                       pci->prefetch.size = hose->regions[ret].size;       /* PREFETCH size */
> +               } else if (hose->regions[ret].flags == PCI_REGION_SYS_MEMORY) {
> +                       pci->cfg_base = (void *)(pci->io.phys_start - pci->io.size);
> +                       pci->cfg_size = pci->io.size;
> +               } else {
> +                       dev_err(pci->dev, "invalid flags type!\n");
> +               }
> +       }
> +
> +       dev_dbg(pci->dev, "Config space: [0x%p - 0x%p, size 0x%llx]\n",
> +               pci->cfg_base, pci->cfg_base + pci->cfg_size,
> +               pci->cfg_size);
> +
> +       dev_dbg(pci->dev, "IO space: [0x%llx - 0x%llx, size 0x%lx]\n",
> +               pci->io.phys_start, pci->io.phys_start + pci->io.size,
> +               pci->io.size);
> +
> +       dev_dbg(pci->dev, "IO bus:   [0x%lx - 0x%lx, size 0x%lx]\n",
> +               pci->io.bus_start, pci->io.bus_start + pci->io.size,
> +               pci->io.size);
> +
> +       dev_dbg(pci->dev, "MEM space: [0x%llx - 0x%llx, size 0x%lx]\n",
> +               pci->mem.phys_start, pci->mem.phys_start + pci->mem.size,
> +               pci->mem.size);
> +
> +       dev_dbg(pci->dev, "MEM bus:   [0x%lx - 0x%lx, size 0x%lx]\n",
> +               pci->mem.bus_start, pci->mem.bus_start + pci->mem.size,
> +               pci->mem.size);
> +
> +       if (pci->prefetch.size) {
> +               dev_dbg(pci->dev, "PREFETCH space: [0x%llx - 0x%llx, size 0x%lx]\n",
> +                       pci->prefetch.phys_start, pci->prefetch.phys_start + pci->prefetch.size,
> +                       pci->prefetch.size);
> +
> +               dev_dbg(pci->dev, "PREFETCH bus:   [0x%lx - 0x%lx, size 0x%lx]\n",
> +                       pci->prefetch.bus_start, pci->prefetch.bus_start + pci->prefetch.size,
> +                       pci->prefetch.size);
> +       }
> +}
> +
> diff --git a/drivers/pci/pcie_dw_common.h b/drivers/pci/pcie_dw_common.h
> new file mode 100644
> index 0000000000..6b701645af
> --- /dev/null
> +++ b/drivers/pci/pcie_dw_common.h
> @@ -0,0 +1,155 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (c) 2021 BayLibre, SAS
> + * Author: Neil Armstrong <narmstrong@baylibre.com>
> + *
> + * Copyright (c) 2021 Rockchip, Inc.
> + *
> + * Copyright (C) 2018 Texas Instruments, Inc
> + */
> +
> +#ifndef PCIE_DW_COMMON_H
> +#define PCIE_DW_COMMON_H
> +
> +#define DEFAULT_DBI_ATU_OFFSET (0x3 << 20)
> +
> +/* PCI DBICS registers */
> +#define PCIE_LINK_STATUS_REG           0x80
> +#define PCIE_LINK_STATUS_SPEED_OFF     16
> +#define PCIE_LINK_STATUS_SPEED_MASK    (0xf << PCIE_LINK_STATUS_SPEED_OFF)
> +#define PCIE_LINK_STATUS_WIDTH_OFF     20
> +#define PCIE_LINK_STATUS_WIDTH_MASK    (0xf << PCIE_LINK_STATUS_WIDTH_OFF)
> +
> +/*
> + * iATU Unroll-specific register definitions
> + * From 4.80 core version the address translation will be made by unroll.
> + * The registers are offset from atu_base
> + */
> +#define PCIE_ATU_UNR_REGION_CTRL1      0x00
> +#define PCIE_ATU_UNR_REGION_CTRL2      0x04
> +#define PCIE_ATU_UNR_LOWER_BASE                0x08
> +#define PCIE_ATU_UNR_UPPER_BASE                0x0c
> +#define PCIE_ATU_UNR_LIMIT             0x10
> +#define PCIE_ATU_UNR_LOWER_TARGET      0x14
> +#define PCIE_ATU_UNR_UPPER_TARGET      0x18
> +
> +#define PCIE_ATU_REGION_INDEX1         (0x1 << 0)
> +#define PCIE_ATU_REGION_INDEX0         (0x0 << 0)
> +#define PCIE_ATU_TYPE_MEM              (0x0 << 0)
> +#define PCIE_ATU_TYPE_IO               (0x2 << 0)
> +#define PCIE_ATU_TYPE_CFG0             (0x4 << 0)
> +#define PCIE_ATU_TYPE_CFG1             (0x5 << 0)
> +#define PCIE_ATU_ENABLE                        (0x1 << 31)
> +#define PCIE_ATU_BAR_MODE_ENABLE       (0x1 << 30)
> +#define PCIE_ATU_BUS(x)                        (((x) & 0xff) << 24)
> +#define PCIE_ATU_DEV(x)                        (((x) & 0x1f) << 19)
> +#define PCIE_ATU_FUNC(x)               (((x) & 0x7) << 16)
> +
> +/* Register address builder */
> +#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region)       ((region) << 9)
> +
> +/* Parameters for the waiting for iATU enabled routine */
> +#define LINK_WAIT_MAX_IATU_RETRIES     5
> +#define LINK_WAIT_IATU_US              10000
> +
> +/* PCI DBICS registers */
> +#define PCIE_LINK_STATUS_REG           0x80
> +#define PCIE_LINK_STATUS_SPEED_OFF     16
> +#define PCIE_LINK_STATUS_SPEED_MASK    (0xf << PCIE_LINK_STATUS_SPEED_OFF)
> +#define PCIE_LINK_STATUS_WIDTH_OFF     20
> +#define PCIE_LINK_STATUS_WIDTH_MASK    (0xf << PCIE_LINK_STATUS_WIDTH_OFF)
> +
> +#define PCIE_LINK_CAPABILITY           0x7c
> +#define PCIE_LINK_CTL_2                        0xa0
> +#define TARGET_LINK_SPEED_MASK         0xf
> +#define LINK_SPEED_GEN_1               0x1
> +#define LINK_SPEED_GEN_2               0x2
> +#define LINK_SPEED_GEN_3               0x3
> +
> +/* Synopsys-specific PCIe configuration registers */
> +#define PCIE_PORT_LINK_CONTROL         0x710
> +#define PORT_LINK_DLL_LINK_EN          BIT(5)
> +#define PORT_LINK_FAST_LINK_MODE       BIT(7)
> +#define PORT_LINK_MODE_MASK            GENMASK(21, 16)
> +#define PORT_LINK_MODE(n)              FIELD_PREP(PORT_LINK_MODE_MASK, n)
> +#define PORT_LINK_MODE_1_LANES         PORT_LINK_MODE(0x1)
> +#define PORT_LINK_MODE_2_LANES         PORT_LINK_MODE(0x3)
> +#define PORT_LINK_MODE_4_LANES         PORT_LINK_MODE(0x7)
> +#define PORT_LINK_MODE_8_LANES         PORT_LINK_MODE(0xf)
> +
> +#define PCIE_LINK_WIDTH_SPEED_CONTROL  0x80C
> +#define PORT_LOGIC_N_FTS_MASK          GENMASK(7, 0)
> +#define PORT_LOGIC_SPEED_CHANGE                BIT(17)
> +#define PORT_LOGIC_LINK_WIDTH_MASK     GENMASK(12, 8)
> +#define PORT_LOGIC_LINK_WIDTH(n)       FIELD_PREP(PORT_LOGIC_LINK_WIDTH_MASK, n)
> +#define PORT_LOGIC_LINK_WIDTH_1_LANES  PORT_LOGIC_LINK_WIDTH(0x1)
> +#define PORT_LOGIC_LINK_WIDTH_2_LANES  PORT_LOGIC_LINK_WIDTH(0x2)
> +#define PORT_LOGIC_LINK_WIDTH_4_LANES  PORT_LOGIC_LINK_WIDTH(0x4)
> +#define PORT_LOGIC_LINK_WIDTH_8_LANES  PORT_LOGIC_LINK_WIDTH(0x8)
> +
> +#define PCIE_MISC_CONTROL_1_OFF                0x8bc
> +#define PCIE_DBI_RO_WR_EN              BIT(0)
> +
> +/* Parameters for the waiting for iATU enabled routine */
> +#define LINK_WAIT_MAX_IATU_RETRIES     5
> +#define LINK_WAIT_IATU                 10000
> +
> +/**
> + * struct pcie_dw - DW PCIe controller state
> + *
> + * @dbi_base: The base address of dbi register space
> + * @cfg_base: The base address of configuration space
> + * @atu_base: The base address of ATU space
> + * @cfg_size: The size of the configuration space which is needed
> + *            as it gets written into the PCIE_ATU_LIMIT register
> + * @first_busno: This driver supports multiple PCIe controllers.
> + *               first_busno stores the bus number of the PCIe root-port
> + *               number which may vary depending on the PCIe setup
> + *               (PEX switches etc).
> + * @io: The IO space for EP's BAR
> + * @mem: The memory space for EP's BAR
> + * @prefetch: The prefetch space for EP's BAR
> + */
> +struct pcie_dw {
> +       struct udevice  *dev;
> +       void __iomem *dbi_base;
> +       void __iomem *cfg_base;
> +       void __iomem *atu_base;
> +       fdt_size_t cfg_size;
> +
> +       int first_busno;
> +
> +       /* IO, MEM & PREFETCH PCI regions */
> +       struct pci_region io;
> +       struct pci_region mem;
> +       struct pci_region prefetch;
> +};
> +
> +int pcie_dw_get_link_speed(struct pcie_dw *pci);
> +
> +int pcie_dw_get_link_width(struct pcie_dw *pci);
> +
> +int pcie_dw_prog_outbound_atu_unroll(struct pcie_dw *pci, int index, int type, u64 cpu_addr,
> +                                    u64 pci_addr, u32 size);
> +
> +int pcie_dw_read_config(const struct udevice *bus, pci_dev_t bdf, uint offset, ulong *valuep,
> +                       enum pci_size_t size);
> +
> +int pcie_dw_write_config(struct udevice *bus, pci_dev_t bdf, uint offset, ulong value,
> +                        enum pci_size_t size);
> +
> +static inline void dw_pcie_dbi_write_enable(struct pcie_dw *pci, bool en)
> +{
> +       u32 val;
> +
> +       val = readl(pci->dbi_base + PCIE_MISC_CONTROL_1_OFF);
> +       if (en)
> +               val |= PCIE_DBI_RO_WR_EN;
> +       else
> +               val &= ~PCIE_DBI_RO_WR_EN;
> +       writel(val, pci->dbi_base + PCIE_MISC_CONTROL_1_OFF);
> +}
> +
> +void pcie_dw_setup_host(struct pcie_dw *pci);
> +
> +#endif
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH RFT v2 1/4] pci: add common Designware PCIe functions
@ 2021-03-26  9:21     ` Green Wan
  0 siblings, 0 replies; 26+ messages in thread
From: Green Wan @ 2021-03-26  9:21 UTC (permalink / raw)
  To: Neil Armstrong, Bin Meng
  Cc: cc: Lokesh Vutla, Sekhar Nori, shawn.lin, U-Boot Mailing List,
	u-boot-amlogic

Hi Neil,

I rebased my driver and gave it a try today. Add my tested-by.
Tested-by: Green Wan <green.wan@sifive.com>

Thanks,

Hi Bin,

Since fu740 support patches include the designware-based driver and
also in reviewing, do you prefer me to create the patch based on
Neil's pcie_dw_common.c or create a separated PCIE patch after both
fu740 and Neil's patches are merged?

Thanks,
-- Green



On Thu, Mar 25, 2021 at 10:49 PM Neil Armstrong <narmstrong@baylibre.com> wrote:
>
> With the introduction of pcie_dw_rockchip, and need to support the DW PCIe in the
> Amlogic AXG & G12 SoCs, most of the DW PCIe helpers would be duplicated.
>
> This introduce a "common" DW PCIe helpers file with common code merged from the
> dw_ti and dw_rockchip drivers and adapted to fit with the upcoming dw_meson.
>
> The following changes will switch the dw_ti and dw_rockchip to use these helpers.
>
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
>  drivers/pci/Kconfig          |   4 +
>  drivers/pci/Makefile         |   1 +
>  drivers/pci/pcie_dw_common.c | 366 +++++++++++++++++++++++++++++++++++
>  drivers/pci/pcie_dw_common.h | 155 +++++++++++++++
>  4 files changed, 526 insertions(+)
>  create mode 100644 drivers/pci/pcie_dw_common.c
>  create mode 100644 drivers/pci/pcie_dw_common.h
>
> diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
> index ba41787f64..ab5a5e7ed6 100644
> --- a/drivers/pci/Kconfig
> +++ b/drivers/pci/Kconfig
> @@ -258,6 +258,10 @@ config PCI_MVEBU
>           Say Y here if you want to enable PCIe controller support on
>           Armada XP/38x SoCs.
>
> +config PCIE_DW_COMMON
> +       bool
> +       select DM_PCI
> +
>  config PCI_KEYSTONE
>         bool "TI Keystone PCIe controller"
>         depends on DM_PCI
> diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
> index 5ed94bc95c..e3ca8b27e4 100644
> --- a/drivers/pci/Makefile
> +++ b/drivers/pci/Makefile
> @@ -45,6 +45,7 @@ obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o \
>  obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o
>  obj-$(CONFIG_PCI_PHYTIUM) += pcie_phytium.o
>  obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o
> +obj-$(CONFIG_PCIE_DW_COMMON) += pcie_dw_common.o
>  obj-$(CONFIG_PCI_KEYSTONE) += pcie_dw_ti.o
>  obj-$(CONFIG_PCIE_MEDIATEK) += pcie_mediatek.o
>  obj-$(CONFIG_PCIE_ROCKCHIP) += pcie_rockchip.o
> diff --git a/drivers/pci/pcie_dw_common.c b/drivers/pci/pcie_dw_common.c
> new file mode 100644
> index 0000000000..7c92b7b754
> --- /dev/null
> +++ b/drivers/pci/pcie_dw_common.c
> @@ -0,0 +1,366 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (c) 2021 BayLibre, SAS
> + * Author: Neil Armstrong <narmstrong@baylibre.com>
> + *
> + * Copyright (c) 2021 Rockchip, Inc.
> + *
> + * Copyright (C) 2018 Texas Instruments, Inc
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <log.h>
> +#include <pci.h>
> +#include <dm/device_compat.h>
> +#include <asm/io.h>
> +#include <linux/delay.h>
> +#include "pcie_dw_common.h"
> +
> +int pcie_dw_get_link_speed(struct pcie_dw *pci)
> +{
> +       return (readl(pci->dbi_base + PCIE_LINK_STATUS_REG) &
> +               PCIE_LINK_STATUS_SPEED_MASK) >> PCIE_LINK_STATUS_SPEED_OFF;
> +}
> +
> +int pcie_dw_get_link_width(struct pcie_dw *pci)
> +{
> +       return (readl(pci->dbi_base + PCIE_LINK_STATUS_REG) &
> +               PCIE_LINK_STATUS_WIDTH_MASK) >> PCIE_LINK_STATUS_WIDTH_OFF;
> +}
> +
> +static void dw_pcie_writel_ob_unroll(struct pcie_dw *pci, u32 index, u32 reg,
> +                                    u32 val)
> +{
> +       u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
> +       void __iomem *base = pci->atu_base;
> +
> +       writel(val, base + offset + reg);
> +}
> +
> +static u32 dw_pcie_readl_ob_unroll(struct pcie_dw *pci, u32 index, u32 reg)
> +{
> +       u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
> +       void __iomem *base = pci->atu_base;
> +
> +       return readl(base + offset + reg);
> +}
> +
> +/**
> + * pcie_dw_prog_outbound_atu_unroll() - Configure ATU for outbound accesses
> + *
> + * @pcie: Pointer to the PCI controller state
> + * @index: ATU region index
> + * @type: ATU accsess type
> + * @cpu_addr: the physical address for the translation entry
> + * @pci_addr: the pcie bus address for the translation entry
> + * @size: the size of the translation entry
> + *
> + * Return: 0 is successful and -1 is failure
> + */
> +int pcie_dw_prog_outbound_atu_unroll(struct pcie_dw *pci, int index,
> +                                    int type, u64 cpu_addr,
> +                                            u64 pci_addr, u32 size)
> +{
> +       u32 retries, val;
> +
> +       dev_dbg(pci->dev, "ATU programmed with: index: %d, type: %d, cpu addr: %8llx, pci addr: %8llx, size: %8x\n",
> +               index, type, cpu_addr, pci_addr, size);
> +
> +       dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE,
> +                                lower_32_bits(cpu_addr));
> +       dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE,
> +                                upper_32_bits(cpu_addr));
> +       dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LIMIT,
> +                                lower_32_bits(cpu_addr + size - 1));
> +       dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
> +                                lower_32_bits(pci_addr));
> +       dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
> +                                upper_32_bits(pci_addr));
> +       dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
> +                                type);
> +       dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
> +                                PCIE_ATU_ENABLE);
> +
> +       /*
> +        * Make sure ATU enable takes effect before any subsequent config
> +        * and I/O accesses.
> +        */
> +       for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
> +               val = dw_pcie_readl_ob_unroll(pci, index,
> +                                             PCIE_ATU_UNR_REGION_CTRL2);
> +               if (val & PCIE_ATU_ENABLE)
> +                       return 0;
> +
> +               udelay(LINK_WAIT_IATU);
> +       }
> +       dev_err(pci->dev, "outbound iATU is not being enabled\n");
> +
> +       return -1;
> +}
> +
> +/**
> + * set_cfg_address() - Configure the PCIe controller config space access
> + *
> + * @pcie: Pointer to the PCI controller state
> + * @d: PCI device to access
> + * @where: Offset in the configuration space
> + *
> + * Configures the PCIe controller to access the configuration space of
> + * a specific PCIe device and returns the address to use for this
> + * access.
> + *
> + * Return: Address that can be used to access the configation space
> + *         of the requested device / offset
> + */
> +static uintptr_t set_cfg_address(struct pcie_dw *pcie,
> +                                pci_dev_t d, uint where)
> +{
> +       int bus = PCI_BUS(d) - pcie->first_busno;
> +       uintptr_t va_address;
> +       u32 atu_type;
> +       int ret;
> +
> +       /* Use dbi_base for own configuration read and write */
> +       if (!bus) {
> +               va_address = (uintptr_t)pcie->dbi_base;
> +               goto out;
> +       }
> +
> +       if (bus == 1)
> +               /*
> +                * For local bus whose primary bus number is root bridge,
> +                * change TLP Type field to 4.
> +                */
> +               atu_type = PCIE_ATU_TYPE_CFG0;
> +       else
> +               /* Otherwise, change TLP Type field to 5. */
> +               atu_type = PCIE_ATU_TYPE_CFG1;
> +
> +       /*
> +        * Not accessing root port configuration space?
> +        * Region #0 is used for Outbound CFG space access.
> +        * Direction = Outbound
> +        * Region Index = 0
> +        */
> +       d = PCI_MASK_BUS(d);
> +       d = PCI_ADD_BUS(bus, d);
> +       ret = pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
> +                                              atu_type, (u64)pcie->cfg_base,
> +                                               d << 8, pcie->cfg_size);
> +       if (ret)
> +               return (uintptr_t)ret;
> +
> +       va_address = (uintptr_t)pcie->cfg_base;
> +
> +out:
> +       va_address += where & ~0x3;
> +
> +       return va_address;
> +}
> +
> +/**
> + * pcie_dw_addr_valid() - Check for valid bus address
> + *
> + * @d: The PCI device to access
> + * @first_busno: Bus number of the PCIe controller root complex
> + *
> + * Return 1 (true) if the PCI device can be accessed by this controller.
> + *
> + * Return: 1 on valid, 0 on invalid
> + */
> +static int pcie_dw_addr_valid(pci_dev_t d, int first_busno)
> +{
> +       if ((PCI_BUS(d) == first_busno) && (PCI_DEV(d) > 0))
> +               return 0;
> +       if ((PCI_BUS(d) == first_busno + 1) && (PCI_DEV(d) > 0))
> +               return 0;
> +
> +       return 1;
> +}
> +
> +/**
> + * pcie_dw_read_config() - Read from configuration space
> + *
> + * @bus: Pointer to the PCI bus
> + * @bdf: Identifies the PCIe device to access
> + * @offset: The offset into the device's configuration space
> + * @valuep: A pointer at which to store the read value
> + * @size: Indicates the size of access to perform
> + *
> + * Read a value of size @size from offset @offset within the configuration
> + * space of the device identified by the bus, device & function numbers in @bdf
> + * on the PCI bus @bus.
> + *
> + * Return: 0 on success
> + */
> +int pcie_dw_read_config(const struct udevice *bus, pci_dev_t bdf,
> +                       uint offset, ulong *valuep,
> +                       enum pci_size_t size)
> +{
> +       struct pcie_dw *pcie = dev_get_priv(bus);
> +       uintptr_t va_address;
> +       ulong value;
> +
> +       dev_dbg(pcie->dev, "PCIE CFG read: bdf=%2x:%2x:%2x ",
> +               PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
> +
> +       if (!pcie_dw_addr_valid(bdf, pcie->first_busno)) {
> +               debug("- out of range\n");
> +               *valuep = pci_get_ff(size);
> +               return 0;
> +       }
> +
> +       va_address = set_cfg_address(pcie, bdf, offset);
> +
> +       value = readl(va_address);
> +
> +       debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
> +       *valuep = pci_conv_32_to_size(value, offset, size);
> +
> +       return pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
> +                                                PCIE_ATU_TYPE_IO, pcie->io.phys_start,
> +                                                pcie->io.bus_start, pcie->io.size);
> +}
> +
> +/**
> + * pcie_dw_write_config() - Write to configuration space
> + *
> + * @bus: Pointer to the PCI bus
> + * @bdf: Identifies the PCIe device to access
> + * @offset: The offset into the device's configuration space
> + * @value: The value to write
> + * @size: Indicates the size of access to perform
> + *
> + * Write the value @value of size @size from offset @offset within the
> + * configuration space of the device identified by the bus, device & function
> + * numbers in @bdf on the PCI bus @bus.
> + *
> + * Return: 0 on success
> + */
> +int pcie_dw_write_config(struct udevice *bus, pci_dev_t bdf,
> +                        uint offset, ulong value,
> +                        enum pci_size_t size)
> +{
> +       struct pcie_dw *pcie = dev_get_priv(bus);
> +       uintptr_t va_address;
> +       ulong old;
> +
> +       dev_dbg(pcie->dev, "PCIE CFG write: (b,d,f)=(%2d,%2d,%2d) ",
> +               PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
> +       dev_dbg(pcie->dev, "(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
> +
> +       if (!pcie_dw_addr_valid(bdf, pcie->first_busno)) {
> +               debug("- out of range\n");
> +               return 0;
> +       }
> +
> +       va_address = set_cfg_address(pcie, bdf, offset);
> +
> +       old = readl(va_address);
> +       value = pci_conv_size_to_32(old, value, offset, size);
> +       writel(value, va_address);
> +
> +       return pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
> +                                                PCIE_ATU_TYPE_IO, pcie->io.phys_start,
> +                                                pcie->io.bus_start, pcie->io.size);
> +}
> +
> +/**
> + * pcie_dw_setup_host() - Setup the PCIe controller for RC opertaion
> + *
> + * @pcie: Pointer to the PCI controller state
> + *
> + * Configure the host BARs of the PCIe controller root port so that
> + * PCI(e) devices may access the system memory.
> + */
> +void pcie_dw_setup_host(struct pcie_dw *pci)
> +{
> +       struct udevice *ctlr = pci_get_controller(pci->dev);
> +       struct pci_controller *hose = dev_get_uclass_priv(ctlr);
> +       u32 ret;
> +
> +       if (!pci->atu_base)
> +               pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
> +
> +       /* setup RC BARs */
> +       writel(PCI_BASE_ADDRESS_MEM_TYPE_64,
> +              pci->dbi_base + PCI_BASE_ADDRESS_0);
> +       writel(0x0, pci->dbi_base + PCI_BASE_ADDRESS_1);
> +
> +       /* setup interrupt pins */
> +       clrsetbits_le32(pci->dbi_base + PCI_INTERRUPT_LINE,
> +                       0xff00, 0x100);
> +
> +       /* setup bus numbers */
> +       clrsetbits_le32(pci->dbi_base + PCI_PRIMARY_BUS,
> +                       0xffffff, 0x00ff0100);
> +
> +       /* setup command register */
> +       clrsetbits_le32(pci->dbi_base + PCI_PRIMARY_BUS,
> +                       0xffff,
> +                       PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
> +                       PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
> +
> +       /* Enable write permission for the DBI read-only register */
> +       dw_pcie_dbi_write_enable(pci, true);
> +       /* program correct class for RC */
> +       writew(PCI_CLASS_BRIDGE_PCI, pci->dbi_base + PCI_CLASS_DEVICE);
> +       /* Better disable write permission right after the update */
> +       dw_pcie_dbi_write_enable(pci, false);
> +
> +       setbits_le32(pci->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL,
> +                    PORT_LOGIC_SPEED_CHANGE);
> +
> +       for (ret = 0; ret < hose->region_count; ret++) {
> +               if (hose->regions[ret].flags == PCI_REGION_IO) {
> +                       pci->io.phys_start = hose->regions[ret].phys_start; /* IO base */
> +                       pci->io.bus_start = hose->regions[ret].bus_start;  /* IO_bus_addr */
> +                       pci->io.size = hose->regions[ret].size;      /* IO size */
> +               } else if (hose->regions[ret].flags == PCI_REGION_MEM) {
> +                       pci->mem.phys_start = hose->regions[ret].phys_start; /* MEM base */
> +                       pci->mem.bus_start = hose->regions[ret].bus_start;  /* MEM_bus_addr */
> +                       pci->mem.size = hose->regions[ret].size;            /* MEM size */
> +               } else if (hose->regions[ret].flags == PCI_REGION_PREFETCH) {
> +                       pci->prefetch.phys_start = hose->regions[ret].phys_start; /* PREFETCH base */
> +                       pci->prefetch.bus_start = hose->regions[ret].bus_start;  /* PREFETCH_bus_addr */
> +                       pci->prefetch.size = hose->regions[ret].size;       /* PREFETCH size */
> +               } else if (hose->regions[ret].flags == PCI_REGION_SYS_MEMORY) {
> +                       pci->cfg_base = (void *)(pci->io.phys_start - pci->io.size);
> +                       pci->cfg_size = pci->io.size;
> +               } else {
> +                       dev_err(pci->dev, "invalid flags type!\n");
> +               }
> +       }
> +
> +       dev_dbg(pci->dev, "Config space: [0x%p - 0x%p, size 0x%llx]\n",
> +               pci->cfg_base, pci->cfg_base + pci->cfg_size,
> +               pci->cfg_size);
> +
> +       dev_dbg(pci->dev, "IO space: [0x%llx - 0x%llx, size 0x%lx]\n",
> +               pci->io.phys_start, pci->io.phys_start + pci->io.size,
> +               pci->io.size);
> +
> +       dev_dbg(pci->dev, "IO bus:   [0x%lx - 0x%lx, size 0x%lx]\n",
> +               pci->io.bus_start, pci->io.bus_start + pci->io.size,
> +               pci->io.size);
> +
> +       dev_dbg(pci->dev, "MEM space: [0x%llx - 0x%llx, size 0x%lx]\n",
> +               pci->mem.phys_start, pci->mem.phys_start + pci->mem.size,
> +               pci->mem.size);
> +
> +       dev_dbg(pci->dev, "MEM bus:   [0x%lx - 0x%lx, size 0x%lx]\n",
> +               pci->mem.bus_start, pci->mem.bus_start + pci->mem.size,
> +               pci->mem.size);
> +
> +       if (pci->prefetch.size) {
> +               dev_dbg(pci->dev, "PREFETCH space: [0x%llx - 0x%llx, size 0x%lx]\n",
> +                       pci->prefetch.phys_start, pci->prefetch.phys_start + pci->prefetch.size,
> +                       pci->prefetch.size);
> +
> +               dev_dbg(pci->dev, "PREFETCH bus:   [0x%lx - 0x%lx, size 0x%lx]\n",
> +                       pci->prefetch.bus_start, pci->prefetch.bus_start + pci->prefetch.size,
> +                       pci->prefetch.size);
> +       }
> +}
> +
> diff --git a/drivers/pci/pcie_dw_common.h b/drivers/pci/pcie_dw_common.h
> new file mode 100644
> index 0000000000..6b701645af
> --- /dev/null
> +++ b/drivers/pci/pcie_dw_common.h
> @@ -0,0 +1,155 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (c) 2021 BayLibre, SAS
> + * Author: Neil Armstrong <narmstrong@baylibre.com>
> + *
> + * Copyright (c) 2021 Rockchip, Inc.
> + *
> + * Copyright (C) 2018 Texas Instruments, Inc
> + */
> +
> +#ifndef PCIE_DW_COMMON_H
> +#define PCIE_DW_COMMON_H
> +
> +#define DEFAULT_DBI_ATU_OFFSET (0x3 << 20)
> +
> +/* PCI DBICS registers */
> +#define PCIE_LINK_STATUS_REG           0x80
> +#define PCIE_LINK_STATUS_SPEED_OFF     16
> +#define PCIE_LINK_STATUS_SPEED_MASK    (0xf << PCIE_LINK_STATUS_SPEED_OFF)
> +#define PCIE_LINK_STATUS_WIDTH_OFF     20
> +#define PCIE_LINK_STATUS_WIDTH_MASK    (0xf << PCIE_LINK_STATUS_WIDTH_OFF)
> +
> +/*
> + * iATU Unroll-specific register definitions
> + * From 4.80 core version the address translation will be made by unroll.
> + * The registers are offset from atu_base
> + */
> +#define PCIE_ATU_UNR_REGION_CTRL1      0x00
> +#define PCIE_ATU_UNR_REGION_CTRL2      0x04
> +#define PCIE_ATU_UNR_LOWER_BASE                0x08
> +#define PCIE_ATU_UNR_UPPER_BASE                0x0c
> +#define PCIE_ATU_UNR_LIMIT             0x10
> +#define PCIE_ATU_UNR_LOWER_TARGET      0x14
> +#define PCIE_ATU_UNR_UPPER_TARGET      0x18
> +
> +#define PCIE_ATU_REGION_INDEX1         (0x1 << 0)
> +#define PCIE_ATU_REGION_INDEX0         (0x0 << 0)
> +#define PCIE_ATU_TYPE_MEM              (0x0 << 0)
> +#define PCIE_ATU_TYPE_IO               (0x2 << 0)
> +#define PCIE_ATU_TYPE_CFG0             (0x4 << 0)
> +#define PCIE_ATU_TYPE_CFG1             (0x5 << 0)
> +#define PCIE_ATU_ENABLE                        (0x1 << 31)
> +#define PCIE_ATU_BAR_MODE_ENABLE       (0x1 << 30)
> +#define PCIE_ATU_BUS(x)                        (((x) & 0xff) << 24)
> +#define PCIE_ATU_DEV(x)                        (((x) & 0x1f) << 19)
> +#define PCIE_ATU_FUNC(x)               (((x) & 0x7) << 16)
> +
> +/* Register address builder */
> +#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region)       ((region) << 9)
> +
> +/* Parameters for the waiting for iATU enabled routine */
> +#define LINK_WAIT_MAX_IATU_RETRIES     5
> +#define LINK_WAIT_IATU_US              10000
> +
> +/* PCI DBICS registers */
> +#define PCIE_LINK_STATUS_REG           0x80
> +#define PCIE_LINK_STATUS_SPEED_OFF     16
> +#define PCIE_LINK_STATUS_SPEED_MASK    (0xf << PCIE_LINK_STATUS_SPEED_OFF)
> +#define PCIE_LINK_STATUS_WIDTH_OFF     20
> +#define PCIE_LINK_STATUS_WIDTH_MASK    (0xf << PCIE_LINK_STATUS_WIDTH_OFF)
> +
> +#define PCIE_LINK_CAPABILITY           0x7c
> +#define PCIE_LINK_CTL_2                        0xa0
> +#define TARGET_LINK_SPEED_MASK         0xf
> +#define LINK_SPEED_GEN_1               0x1
> +#define LINK_SPEED_GEN_2               0x2
> +#define LINK_SPEED_GEN_3               0x3
> +
> +/* Synopsys-specific PCIe configuration registers */
> +#define PCIE_PORT_LINK_CONTROL         0x710
> +#define PORT_LINK_DLL_LINK_EN          BIT(5)
> +#define PORT_LINK_FAST_LINK_MODE       BIT(7)
> +#define PORT_LINK_MODE_MASK            GENMASK(21, 16)
> +#define PORT_LINK_MODE(n)              FIELD_PREP(PORT_LINK_MODE_MASK, n)
> +#define PORT_LINK_MODE_1_LANES         PORT_LINK_MODE(0x1)
> +#define PORT_LINK_MODE_2_LANES         PORT_LINK_MODE(0x3)
> +#define PORT_LINK_MODE_4_LANES         PORT_LINK_MODE(0x7)
> +#define PORT_LINK_MODE_8_LANES         PORT_LINK_MODE(0xf)
> +
> +#define PCIE_LINK_WIDTH_SPEED_CONTROL  0x80C
> +#define PORT_LOGIC_N_FTS_MASK          GENMASK(7, 0)
> +#define PORT_LOGIC_SPEED_CHANGE                BIT(17)
> +#define PORT_LOGIC_LINK_WIDTH_MASK     GENMASK(12, 8)
> +#define PORT_LOGIC_LINK_WIDTH(n)       FIELD_PREP(PORT_LOGIC_LINK_WIDTH_MASK, n)
> +#define PORT_LOGIC_LINK_WIDTH_1_LANES  PORT_LOGIC_LINK_WIDTH(0x1)
> +#define PORT_LOGIC_LINK_WIDTH_2_LANES  PORT_LOGIC_LINK_WIDTH(0x2)
> +#define PORT_LOGIC_LINK_WIDTH_4_LANES  PORT_LOGIC_LINK_WIDTH(0x4)
> +#define PORT_LOGIC_LINK_WIDTH_8_LANES  PORT_LOGIC_LINK_WIDTH(0x8)
> +
> +#define PCIE_MISC_CONTROL_1_OFF                0x8bc
> +#define PCIE_DBI_RO_WR_EN              BIT(0)
> +
> +/* Parameters for the waiting for iATU enabled routine */
> +#define LINK_WAIT_MAX_IATU_RETRIES     5
> +#define LINK_WAIT_IATU                 10000
> +
> +/**
> + * struct pcie_dw - DW PCIe controller state
> + *
> + * @dbi_base: The base address of dbi register space
> + * @cfg_base: The base address of configuration space
> + * @atu_base: The base address of ATU space
> + * @cfg_size: The size of the configuration space which is needed
> + *            as it gets written into the PCIE_ATU_LIMIT register
> + * @first_busno: This driver supports multiple PCIe controllers.
> + *               first_busno stores the bus number of the PCIe root-port
> + *               number which may vary depending on the PCIe setup
> + *               (PEX switches etc).
> + * @io: The IO space for EP's BAR
> + * @mem: The memory space for EP's BAR
> + * @prefetch: The prefetch space for EP's BAR
> + */
> +struct pcie_dw {
> +       struct udevice  *dev;
> +       void __iomem *dbi_base;
> +       void __iomem *cfg_base;
> +       void __iomem *atu_base;
> +       fdt_size_t cfg_size;
> +
> +       int first_busno;
> +
> +       /* IO, MEM & PREFETCH PCI regions */
> +       struct pci_region io;
> +       struct pci_region mem;
> +       struct pci_region prefetch;
> +};
> +
> +int pcie_dw_get_link_speed(struct pcie_dw *pci);
> +
> +int pcie_dw_get_link_width(struct pcie_dw *pci);
> +
> +int pcie_dw_prog_outbound_atu_unroll(struct pcie_dw *pci, int index, int type, u64 cpu_addr,
> +                                    u64 pci_addr, u32 size);
> +
> +int pcie_dw_read_config(const struct udevice *bus, pci_dev_t bdf, uint offset, ulong *valuep,
> +                       enum pci_size_t size);
> +
> +int pcie_dw_write_config(struct udevice *bus, pci_dev_t bdf, uint offset, ulong value,
> +                        enum pci_size_t size);
> +
> +static inline void dw_pcie_dbi_write_enable(struct pcie_dw *pci, bool en)
> +{
> +       u32 val;
> +
> +       val = readl(pci->dbi_base + PCIE_MISC_CONTROL_1_OFF);
> +       if (en)
> +               val |= PCIE_DBI_RO_WR_EN;
> +       else
> +               val &= ~PCIE_DBI_RO_WR_EN;
> +       writel(val, pci->dbi_base + PCIE_MISC_CONTROL_1_OFF);
> +}
> +
> +void pcie_dw_setup_host(struct pcie_dw *pci);
> +
> +#endif
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH RFT v2 1/4] pci: add common Designware PCIe functions
  2021-03-26  9:21     ` Green Wan
@ 2021-03-26 11:48       ` Bin Meng
  -1 siblings, 0 replies; 26+ messages in thread
From: Bin Meng @ 2021-03-26 11:48 UTC (permalink / raw)
  To: u-boot

Hi Green,

On Fri, Mar 26, 2021 at 5:21 PM Green Wan <green.wan@sifive.com> wrote:
>
> Hi Neil,
>
> I rebased my driver and gave it a try today. Add my tested-by.
> Tested-by: Green Wan <green.wan@sifive.com>
>
> Thanks,
>
> Hi Bin,
>
> Since fu740 support patches include the designware-based driver and
> also in reviewing, do you prefer me to create the patch based on
> Neil's pcie_dw_common.c or create a separated PCIE patch after both
> fu740 and Neil's patches are merged?

There are two options:

1. Go with the current fu740 series with PCIe, but do a follow-up
patch to convert the fu740 PCIe driver against Neil's
2. Split the PCIe driver out of the fu740 series, and do a follow-up
patch to add the fu740 PCIe driver based on Neil's

I am fine with either approach.

Regards,
Bin

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH RFT v2 1/4] pci: add common Designware PCIe functions
@ 2021-03-26 11:48       ` Bin Meng
  0 siblings, 0 replies; 26+ messages in thread
From: Bin Meng @ 2021-03-26 11:48 UTC (permalink / raw)
  To: Green Wan
  Cc: Neil Armstrong, cc: Lokesh Vutla, Sekhar Nori, shawn.lin,
	U-Boot Mailing List, u-boot-amlogic

Hi Green,

On Fri, Mar 26, 2021 at 5:21 PM Green Wan <green.wan@sifive.com> wrote:
>
> Hi Neil,
>
> I rebased my driver and gave it a try today. Add my tested-by.
> Tested-by: Green Wan <green.wan@sifive.com>
>
> Thanks,
>
> Hi Bin,
>
> Since fu740 support patches include the designware-based driver and
> also in reviewing, do you prefer me to create the patch based on
> Neil's pcie_dw_common.c or create a separated PCIE patch after both
> fu740 and Neil's patches are merged?

There are two options:

1. Go with the current fu740 series with PCIe, but do a follow-up
patch to convert the fu740 PCIe driver against Neil's
2. Split the PCIe driver out of the fu740 series, and do a follow-up
patch to add the fu740 PCIe driver based on Neil's

I am fine with either approach.

Regards,
Bin

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH RFT v2 1/4] pci: add common Designware PCIe functions
  2021-03-26 11:48       ` Bin Meng
@ 2021-03-26 14:23         ` Green Wan
  -1 siblings, 0 replies; 26+ messages in thread
From: Green Wan @ 2021-03-26 14:23 UTC (permalink / raw)
  To: u-boot

On Fri, Mar 26, 2021 at 7:48 PM Bin Meng <bmeng.cn@gmail.com> wrote:
>
> Hi Green,
>
> On Fri, Mar 26, 2021 at 5:21 PM Green Wan <green.wan@sifive.com> wrote:
> >
> > Hi Neil,
> >
> > I rebased my driver and gave it a try today. Add my tested-by.
> > Tested-by: Green Wan <green.wan@sifive.com>
> >
> > Thanks,
> >
> > Hi Bin,
> >
> > Since fu740 support patches include the designware-based driver and
> > also in reviewing, do you prefer me to create the patch based on
> > Neil's pcie_dw_common.c or create a separated PCIE patch after both
> > fu740 and Neil's patches are merged?
>
> There are two options:
>
> 1. Go with the current fu740 series with PCIe, but do a follow-up
> patch to convert the fu740 PCIe driver against Neil's
> 2. Split the PCIe driver out of the fu740 series, and do a follow-up
> patch to add the fu740 PCIe driver based on Neil's
>

Okay, thanks. I'd like to create a fu740 series v4 patch and go with approach 1.
And the follow-up patch will be posted afterward soon as well.

Regards,
Green

> I am fine with either approach.
>
> Regards,
> Bin

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH RFT v2 1/4] pci: add common Designware PCIe functions
@ 2021-03-26 14:23         ` Green Wan
  0 siblings, 0 replies; 26+ messages in thread
From: Green Wan @ 2021-03-26 14:23 UTC (permalink / raw)
  To: Bin Meng
  Cc: Neil Armstrong, cc: Lokesh Vutla, Sekhar Nori, shawn.lin,
	U-Boot Mailing List, u-boot-amlogic

On Fri, Mar 26, 2021 at 7:48 PM Bin Meng <bmeng.cn@gmail.com> wrote:
>
> Hi Green,
>
> On Fri, Mar 26, 2021 at 5:21 PM Green Wan <green.wan@sifive.com> wrote:
> >
> > Hi Neil,
> >
> > I rebased my driver and gave it a try today. Add my tested-by.
> > Tested-by: Green Wan <green.wan@sifive.com>
> >
> > Thanks,
> >
> > Hi Bin,
> >
> > Since fu740 support patches include the designware-based driver and
> > also in reviewing, do you prefer me to create the patch based on
> > Neil's pcie_dw_common.c or create a separated PCIE patch after both
> > fu740 and Neil's patches are merged?
>
> There are two options:
>
> 1. Go with the current fu740 series with PCIe, but do a follow-up
> patch to convert the fu740 PCIe driver against Neil's
> 2. Split the PCIe driver out of the fu740 series, and do a follow-up
> patch to add the fu740 PCIe driver based on Neil's
>

Okay, thanks. I'd like to create a fu740 series v4 patch and go with approach 1.
And the follow-up patch will be posted afterward soon as well.

Regards,
Green

> I am fine with either approach.
>
> Regards,
> Bin

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH RFT v2 0/4] pci: add common Designware PCIe functions and support Amlogic Meson PCIe controller
  2021-03-25 14:49 ` Neil Armstrong
@ 2021-04-06 12:21   ` Neil Armstrong
  -1 siblings, 0 replies; 26+ messages in thread
From: Neil Armstrong @ 2021-04-06 12:21 UTC (permalink / raw)
  To: u-boot

Hi Bin,

On 25/03/2021 15:49, Neil Armstrong wrote:
> With the introduction of pcie_dw_rockchip, and need to support the DW PCIe in the
> Amlogic AXG & G12 SoCs, most of the DW PCIe helpers would be duplicated.
> 
> This introduce a "common" DW PCIe helpers file with common code merged from the
> dw_ti and dw_rockchip drivers and adapted to fit with the upcoming dw_meson.
> 
> The following changes will switch the dw_ti and dw_rockchip, and introduce a new
> driver to support the Amlogic AXG & G12 SoCs using these new common helpers.
> 
> The dw_meson has been validated, but the dw_ti and dw_rockchip would need testing
> on hardware to validate nothing has been broken.

How should be proceed ? I can't possibly test patches 2 & 3, but Green has tested it
on Sifive, should patch 1 & 4 be merged then we should wait feedback from the Ti & Rockchip
owners ?

Neil

> 
> Changes since v1:
> - added prefetch memory region support
> - switched to __iomem
> - fixed circular dependency for PCI_KEYSTONE
> 
> Neil Armstrong (4):
>   pci: add common Designware PCIe functions
>   pci: pcie_dw_ti: migrate to common Designware PCIe functions
>   pci: pcie_dw_rockchip: migrate to common Designware PCIe functions
>   pci: add Amlogic Meson Designware PCIe controller
> 
>  drivers/pci/Kconfig            |  16 +-
>  drivers/pci/Makefile           |   2 +
>  drivers/pci/pcie_dw_common.c   | 366 +++++++++++++++++++++++++
>  drivers/pci/pcie_dw_common.h   | 155 +++++++++++
>  drivers/pci/pcie_dw_meson.c    | 459 ++++++++++++++++++++++++++++++++
>  drivers/pci/pcie_dw_rockchip.c | 472 ++-------------------------------
>  drivers/pci/pcie_dw_ti.c       | 444 +++----------------------------
>  7 files changed, 1062 insertions(+), 852 deletions(-)
>  create mode 100644 drivers/pci/pcie_dw_common.c
>  create mode 100644 drivers/pci/pcie_dw_common.h
>  create mode 100644 drivers/pci/pcie_dw_meson.c
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH RFT v2 0/4] pci: add common Designware PCIe functions and support Amlogic Meson PCIe controller
@ 2021-04-06 12:21   ` Neil Armstrong
  0 siblings, 0 replies; 26+ messages in thread
From: Neil Armstrong @ 2021-04-06 12:21 UTC (permalink / raw)
  To: bmeng.cn
  Cc: u-boot, u-boot-amlogic, lokeshvutla, nsekhar, shawn.lin, green.wan

Hi Bin,

On 25/03/2021 15:49, Neil Armstrong wrote:
> With the introduction of pcie_dw_rockchip, and need to support the DW PCIe in the
> Amlogic AXG & G12 SoCs, most of the DW PCIe helpers would be duplicated.
> 
> This introduce a "common" DW PCIe helpers file with common code merged from the
> dw_ti and dw_rockchip drivers and adapted to fit with the upcoming dw_meson.
> 
> The following changes will switch the dw_ti and dw_rockchip, and introduce a new
> driver to support the Amlogic AXG & G12 SoCs using these new common helpers.
> 
> The dw_meson has been validated, but the dw_ti and dw_rockchip would need testing
> on hardware to validate nothing has been broken.

How should be proceed ? I can't possibly test patches 2 & 3, but Green has tested it
on Sifive, should patch 1 & 4 be merged then we should wait feedback from the Ti & Rockchip
owners ?

Neil

> 
> Changes since v1:
> - added prefetch memory region support
> - switched to __iomem
> - fixed circular dependency for PCI_KEYSTONE
> 
> Neil Armstrong (4):
>   pci: add common Designware PCIe functions
>   pci: pcie_dw_ti: migrate to common Designware PCIe functions
>   pci: pcie_dw_rockchip: migrate to common Designware PCIe functions
>   pci: add Amlogic Meson Designware PCIe controller
> 
>  drivers/pci/Kconfig            |  16 +-
>  drivers/pci/Makefile           |   2 +
>  drivers/pci/pcie_dw_common.c   | 366 +++++++++++++++++++++++++
>  drivers/pci/pcie_dw_common.h   | 155 +++++++++++
>  drivers/pci/pcie_dw_meson.c    | 459 ++++++++++++++++++++++++++++++++
>  drivers/pci/pcie_dw_rockchip.c | 472 ++-------------------------------
>  drivers/pci/pcie_dw_ti.c       | 444 +++----------------------------
>  7 files changed, 1062 insertions(+), 852 deletions(-)
>  create mode 100644 drivers/pci/pcie_dw_common.c
>  create mode 100644 drivers/pci/pcie_dw_common.h
>  create mode 100644 drivers/pci/pcie_dw_meson.c
> 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH RFT v2 0/4] pci: add common Designware PCIe functions and support Amlogic Meson PCIe controller
  2021-04-06 12:21   ` Neil Armstrong
@ 2021-04-08  5:29     ` Bin Meng
  -1 siblings, 0 replies; 26+ messages in thread
From: Bin Meng @ 2021-04-08  5:29 UTC (permalink / raw)
  To: u-boot

Hi Neil,

On Tue, Apr 6, 2021 at 8:22 PM Neil Armstrong <narmstrong@baylibre.com> wrote:
>
> Hi Bin,
>
> On 25/03/2021 15:49, Neil Armstrong wrote:
> > With the introduction of pcie_dw_rockchip, and need to support the DW PCIe in the
> > Amlogic AXG & G12 SoCs, most of the DW PCIe helpers would be duplicated.
> >
> > This introduce a "common" DW PCIe helpers file with common code merged from the
> > dw_ti and dw_rockchip drivers and adapted to fit with the upcoming dw_meson.
> >
> > The following changes will switch the dw_ti and dw_rockchip, and introduce a new
> > driver to support the Amlogic AXG & G12 SoCs using these new common helpers.
> >
> > The dw_meson has been validated, but the dw_ti and dw_rockchip would need testing
> > on hardware to validate nothing has been broken.
>
> How should be proceed ? I can't possibly test patches 2 & 3, but Green has tested it
> on Sifive, should patch 1 & 4 be merged then we should wait feedback from the Ti & Rockchip
> owners ?

This series is not assigned to me in patchwork so I cannot decide anything :)

But my opinion was that let's wait for some more time, and if nobody
jumps out let's merge this series.

Regards,
Bin

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH RFT v2 0/4] pci: add common Designware PCIe functions and support Amlogic Meson PCIe controller
@ 2021-04-08  5:29     ` Bin Meng
  0 siblings, 0 replies; 26+ messages in thread
From: Bin Meng @ 2021-04-08  5:29 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: U-Boot Mailing List, u-boot-amlogic, Lokesh Vutla, Sekhar Nori,
	shawn.lin, Green Wan

Hi Neil,

On Tue, Apr 6, 2021 at 8:22 PM Neil Armstrong <narmstrong@baylibre.com> wrote:
>
> Hi Bin,
>
> On 25/03/2021 15:49, Neil Armstrong wrote:
> > With the introduction of pcie_dw_rockchip, and need to support the DW PCIe in the
> > Amlogic AXG & G12 SoCs, most of the DW PCIe helpers would be duplicated.
> >
> > This introduce a "common" DW PCIe helpers file with common code merged from the
> > dw_ti and dw_rockchip drivers and adapted to fit with the upcoming dw_meson.
> >
> > The following changes will switch the dw_ti and dw_rockchip, and introduce a new
> > driver to support the Amlogic AXG & G12 SoCs using these new common helpers.
> >
> > The dw_meson has been validated, but the dw_ti and dw_rockchip would need testing
> > on hardware to validate nothing has been broken.
>
> How should be proceed ? I can't possibly test patches 2 & 3, but Green has tested it
> on Sifive, should patch 1 & 4 be merged then we should wait feedback from the Ti & Rockchip
> owners ?

This series is not assigned to me in patchwork so I cannot decide anything :)

But my opinion was that let's wait for some more time, and if nobody
jumps out let's merge this series.

Regards,
Bin

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH RFT v2 0/4] pci: add common Designware PCIe functions and support Amlogic Meson PCIe controller
  2021-04-08  5:29     ` Bin Meng
@ 2021-04-08  7:41       ` Neil Armstrong
  -1 siblings, 0 replies; 26+ messages in thread
From: Neil Armstrong @ 2021-04-08  7:41 UTC (permalink / raw)
  To: u-boot

On 08/04/2021 07:29, Bin Meng wrote:
> Hi Neil,
> 
> On Tue, Apr 6, 2021 at 8:22 PM Neil Armstrong <narmstrong@baylibre.com> wrote:
>>
>> Hi Bin,
>>
>> On 25/03/2021 15:49, Neil Armstrong wrote:
>>> With the introduction of pcie_dw_rockchip, and need to support the DW PCIe in the
>>> Amlogic AXG & G12 SoCs, most of the DW PCIe helpers would be duplicated.
>>>
>>> This introduce a "common" DW PCIe helpers file with common code merged from the
>>> dw_ti and dw_rockchip drivers and adapted to fit with the upcoming dw_meson.
>>>
>>> The following changes will switch the dw_ti and dw_rockchip, and introduce a new
>>> driver to support the Amlogic AXG & G12 SoCs using these new common helpers.
>>>
>>> The dw_meson has been validated, but the dw_ti and dw_rockchip would need testing
>>> on hardware to validate nothing has been broken.
>>
>> How should be proceed ? I can't possibly test patches 2 & 3, but Green has tested it
>> on Sifive, should patch 1 & 4 be merged then we should wait feedback from the Ti & Rockchip
>> owners ?
> 
> This series is not assigned to me in patchwork so I cannot decide anything :)

I can switch them to you, but I never know who to assign for these multi-vendor series...

> 
> But my opinion was that let's wait for some more time, and if nobody
> jumps out let's merge this series.

Fine fore me !

Thanks,
Neil

> 
> Regards,
> Bin
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH RFT v2 0/4] pci: add common Designware PCIe functions and support Amlogic Meson PCIe controller
@ 2021-04-08  7:41       ` Neil Armstrong
  0 siblings, 0 replies; 26+ messages in thread
From: Neil Armstrong @ 2021-04-08  7:41 UTC (permalink / raw)
  To: Bin Meng
  Cc: U-Boot Mailing List, u-boot-amlogic, Lokesh Vutla, Sekhar Nori,
	shawn.lin, Green Wan

On 08/04/2021 07:29, Bin Meng wrote:
> Hi Neil,
> 
> On Tue, Apr 6, 2021 at 8:22 PM Neil Armstrong <narmstrong@baylibre.com> wrote:
>>
>> Hi Bin,
>>
>> On 25/03/2021 15:49, Neil Armstrong wrote:
>>> With the introduction of pcie_dw_rockchip, and need to support the DW PCIe in the
>>> Amlogic AXG & G12 SoCs, most of the DW PCIe helpers would be duplicated.
>>>
>>> This introduce a "common" DW PCIe helpers file with common code merged from the
>>> dw_ti and dw_rockchip drivers and adapted to fit with the upcoming dw_meson.
>>>
>>> The following changes will switch the dw_ti and dw_rockchip, and introduce a new
>>> driver to support the Amlogic AXG & G12 SoCs using these new common helpers.
>>>
>>> The dw_meson has been validated, but the dw_ti and dw_rockchip would need testing
>>> on hardware to validate nothing has been broken.
>>
>> How should be proceed ? I can't possibly test patches 2 & 3, but Green has tested it
>> on Sifive, should patch 1 & 4 be merged then we should wait feedback from the Ti & Rockchip
>> owners ?
> 
> This series is not assigned to me in patchwork so I cannot decide anything :)

I can switch them to you, but I never know who to assign for these multi-vendor series...

> 
> But my opinion was that let's wait for some more time, and if nobody
> jumps out let's merge this series.

Fine fore me !

Thanks,
Neil

> 
> Regards,
> Bin
> 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH RFT v2 0/4] pci: add common Designware PCIe functions and support Amlogic Meson PCIe controller
  2021-04-08  7:41       ` Neil Armstrong
@ 2021-04-14 22:24         ` Bin Meng
  -1 siblings, 0 replies; 26+ messages in thread
From: Bin Meng @ 2021-04-14 22:24 UTC (permalink / raw)
  To: u-boot

Hi,

On Thu, Apr 8, 2021 at 3:41 PM Neil Armstrong <narmstrong@baylibre.com> wrote:
>
> On 08/04/2021 07:29, Bin Meng wrote:
> > Hi Neil,
> >
> > On Tue, Apr 6, 2021 at 8:22 PM Neil Armstrong <narmstrong@baylibre.com> wrote:
> >>
> >> Hi Bin,
> >>
> >> On 25/03/2021 15:49, Neil Armstrong wrote:
> >>> With the introduction of pcie_dw_rockchip, and need to support the DW PCIe in the
> >>> Amlogic AXG & G12 SoCs, most of the DW PCIe helpers would be duplicated.
> >>>
> >>> This introduce a "common" DW PCIe helpers file with common code merged from the
> >>> dw_ti and dw_rockchip drivers and adapted to fit with the upcoming dw_meson.
> >>>
> >>> The following changes will switch the dw_ti and dw_rockchip, and introduce a new
> >>> driver to support the Amlogic AXG & G12 SoCs using these new common helpers.
> >>>
> >>> The dw_meson has been validated, but the dw_ti and dw_rockchip would need testing
> >>> on hardware to validate nothing has been broken.
> >>
> >> How should be proceed ? I can't possibly test patches 2 & 3, but Green has tested it
> >> on Sifive, should patch 1 & 4 be merged then we should wait feedback from the Ti & Rockchip
> >> owners ?
> >
> > This series is not assigned to me in patchwork so I cannot decide anything :)
>
> I can switch them to you, but I never know who to assign for these multi-vendor series...
>
> >
> > But my opinion was that let's wait for some more time, and if nobody
> > jumps out let's merge this series.
>
> Fine fore me !

I am going to apply this series via the x86 tree if there are no
further comments.

Regards,
Bin

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH RFT v2 0/4] pci: add common Designware PCIe functions and support Amlogic Meson PCIe controller
@ 2021-04-14 22:24         ` Bin Meng
  0 siblings, 0 replies; 26+ messages in thread
From: Bin Meng @ 2021-04-14 22:24 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: U-Boot Mailing List, u-boot-amlogic, Lokesh Vutla, Sekhar Nori,
	shawn.lin, Green Wan

Hi,

On Thu, Apr 8, 2021 at 3:41 PM Neil Armstrong <narmstrong@baylibre.com> wrote:
>
> On 08/04/2021 07:29, Bin Meng wrote:
> > Hi Neil,
> >
> > On Tue, Apr 6, 2021 at 8:22 PM Neil Armstrong <narmstrong@baylibre.com> wrote:
> >>
> >> Hi Bin,
> >>
> >> On 25/03/2021 15:49, Neil Armstrong wrote:
> >>> With the introduction of pcie_dw_rockchip, and need to support the DW PCIe in the
> >>> Amlogic AXG & G12 SoCs, most of the DW PCIe helpers would be duplicated.
> >>>
> >>> This introduce a "common" DW PCIe helpers file with common code merged from the
> >>> dw_ti and dw_rockchip drivers and adapted to fit with the upcoming dw_meson.
> >>>
> >>> The following changes will switch the dw_ti and dw_rockchip, and introduce a new
> >>> driver to support the Amlogic AXG & G12 SoCs using these new common helpers.
> >>>
> >>> The dw_meson has been validated, but the dw_ti and dw_rockchip would need testing
> >>> on hardware to validate nothing has been broken.
> >>
> >> How should be proceed ? I can't possibly test patches 2 & 3, but Green has tested it
> >> on Sifive, should patch 1 & 4 be merged then we should wait feedback from the Ti & Rockchip
> >> owners ?
> >
> > This series is not assigned to me in patchwork so I cannot decide anything :)
>
> I can switch them to you, but I never know who to assign for these multi-vendor series...
>
> >
> > But my opinion was that let's wait for some more time, and if nobody
> > jumps out let's merge this series.
>
> Fine fore me !

I am going to apply this series via the x86 tree if there are no
further comments.

Regards,
Bin

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH RFT v2 0/4] pci: add common Designware PCIe functions and support Amlogic Meson PCIe controller
  2021-04-14 22:24         ` Bin Meng
@ 2021-04-15  4:20           ` Bin Meng
  -1 siblings, 0 replies; 26+ messages in thread
From: Bin Meng @ 2021-04-15  4:20 UTC (permalink / raw)
  To: u-boot

On Thu, Apr 15, 2021 at 6:24 AM Bin Meng <bmeng.cn@gmail.com> wrote:
>
> Hi,
>
> On Thu, Apr 8, 2021 at 3:41 PM Neil Armstrong <narmstrong@baylibre.com> wrote:
> >
> > On 08/04/2021 07:29, Bin Meng wrote:
> > > Hi Neil,
> > >
> > > On Tue, Apr 6, 2021 at 8:22 PM Neil Armstrong <narmstrong@baylibre.com> wrote:
> > >>
> > >> Hi Bin,
> > >>
> > >> On 25/03/2021 15:49, Neil Armstrong wrote:
> > >>> With the introduction of pcie_dw_rockchip, and need to support the DW PCIe in the
> > >>> Amlogic AXG & G12 SoCs, most of the DW PCIe helpers would be duplicated.
> > >>>
> > >>> This introduce a "common" DW PCIe helpers file with common code merged from the
> > >>> dw_ti and dw_rockchip drivers and adapted to fit with the upcoming dw_meson.
> > >>>
> > >>> The following changes will switch the dw_ti and dw_rockchip, and introduce a new
> > >>> driver to support the Amlogic AXG & G12 SoCs using these new common helpers.
> > >>>
> > >>> The dw_meson has been validated, but the dw_ti and dw_rockchip would need testing
> > >>> on hardware to validate nothing has been broken.
> > >>
> > >> How should be proceed ? I can't possibly test patches 2 & 3, but Green has tested it
> > >> on Sifive, should patch 1 & 4 be merged then we should wait feedback from the Ti & Rockchip
> > >> owners ?
> > >
> > > This series is not assigned to me in patchwork so I cannot decide anything :)
> >
> > I can switch them to you, but I never know who to assign for these multi-vendor series...
> >
> > >
> > > But my opinion was that let's wait for some more time, and if nobody
> > > jumps out let's merge this series.
> >
> > Fine fore me !
>
> I am going to apply this series via the x86 tree if there are no
> further comments.

series applied to u-boot-x86, thanks!

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH RFT v2 0/4] pci: add common Designware PCIe functions and support Amlogic Meson PCIe controller
@ 2021-04-15  4:20           ` Bin Meng
  0 siblings, 0 replies; 26+ messages in thread
From: Bin Meng @ 2021-04-15  4:20 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: U-Boot Mailing List, u-boot-amlogic, Lokesh Vutla, Sekhar Nori,
	shawn.lin, Green Wan

On Thu, Apr 15, 2021 at 6:24 AM Bin Meng <bmeng.cn@gmail.com> wrote:
>
> Hi,
>
> On Thu, Apr 8, 2021 at 3:41 PM Neil Armstrong <narmstrong@baylibre.com> wrote:
> >
> > On 08/04/2021 07:29, Bin Meng wrote:
> > > Hi Neil,
> > >
> > > On Tue, Apr 6, 2021 at 8:22 PM Neil Armstrong <narmstrong@baylibre.com> wrote:
> > >>
> > >> Hi Bin,
> > >>
> > >> On 25/03/2021 15:49, Neil Armstrong wrote:
> > >>> With the introduction of pcie_dw_rockchip, and need to support the DW PCIe in the
> > >>> Amlogic AXG & G12 SoCs, most of the DW PCIe helpers would be duplicated.
> > >>>
> > >>> This introduce a "common" DW PCIe helpers file with common code merged from the
> > >>> dw_ti and dw_rockchip drivers and adapted to fit with the upcoming dw_meson.
> > >>>
> > >>> The following changes will switch the dw_ti and dw_rockchip, and introduce a new
> > >>> driver to support the Amlogic AXG & G12 SoCs using these new common helpers.
> > >>>
> > >>> The dw_meson has been validated, but the dw_ti and dw_rockchip would need testing
> > >>> on hardware to validate nothing has been broken.
> > >>
> > >> How should be proceed ? I can't possibly test patches 2 & 3, but Green has tested it
> > >> on Sifive, should patch 1 & 4 be merged then we should wait feedback from the Ti & Rockchip
> > >> owners ?
> > >
> > > This series is not assigned to me in patchwork so I cannot decide anything :)
> >
> > I can switch them to you, but I never know who to assign for these multi-vendor series...
> >
> > >
> > > But my opinion was that let's wait for some more time, and if nobody
> > > jumps out let's merge this series.
> >
> > Fine fore me !
>
> I am going to apply this series via the x86 tree if there are no
> further comments.

series applied to u-boot-x86, thanks!

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2021-04-15  4:20 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-25 14:49 [PATCH RFT v2 0/4] pci: add common Designware PCIe functions and support Amlogic Meson PCIe controller Neil Armstrong
2021-03-25 14:49 ` Neil Armstrong
2021-03-25 14:49 ` [PATCH RFT v2 1/4] pci: add common Designware PCIe functions Neil Armstrong
2021-03-25 14:49   ` Neil Armstrong
2021-03-26  9:21   ` Green Wan
2021-03-26  9:21     ` Green Wan
2021-03-26 11:48     ` Bin Meng
2021-03-26 11:48       ` Bin Meng
2021-03-26 14:23       ` Green Wan
2021-03-26 14:23         ` Green Wan
2021-03-25 14:49 ` [PATCH RFT v2 2/4] pci: pcie_dw_ti: migrate to " Neil Armstrong
2021-03-25 14:49   ` Neil Armstrong
2021-03-25 14:49 ` [PATCH RFT v2 3/4] pci: pcie_dw_rockchip: " Neil Armstrong
2021-03-25 14:49   ` Neil Armstrong
2021-03-25 14:49 ` [PATCH RFT v2 4/4] pci: add Amlogic Meson Designware PCIe controller Neil Armstrong
2021-03-25 14:49   ` Neil Armstrong
2021-04-06 12:21 ` [PATCH RFT v2 0/4] pci: add common Designware PCIe functions and support Amlogic Meson " Neil Armstrong
2021-04-06 12:21   ` Neil Armstrong
2021-04-08  5:29   ` Bin Meng
2021-04-08  5:29     ` Bin Meng
2021-04-08  7:41     ` Neil Armstrong
2021-04-08  7:41       ` Neil Armstrong
2021-04-14 22:24       ` Bin Meng
2021-04-14 22:24         ` Bin Meng
2021-04-15  4:20         ` Bin Meng
2021-04-15  4:20           ` Bin Meng

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.