diff options
Diffstat (limited to 'target/linux/ramips/patches-5.15/100-v5.16-PCI-mt7621-Add-MediaTek-MT7621-PCIe-host-controller-.patch')
-rw-r--r-- | target/linux/ramips/patches-5.15/100-v5.16-PCI-mt7621-Add-MediaTek-MT7621-PCIe-host-controller-.patch | 1418 |
1 files changed, 1418 insertions, 0 deletions
diff --git a/target/linux/ramips/patches-5.15/100-v5.16-PCI-mt7621-Add-MediaTek-MT7621-PCIe-host-controller-.patch b/target/linux/ramips/patches-5.15/100-v5.16-PCI-mt7621-Add-MediaTek-MT7621-PCIe-host-controller-.patch new file mode 100644 index 0000000000..1c8c7cd3d0 --- /dev/null +++ b/target/linux/ramips/patches-5.15/100-v5.16-PCI-mt7621-Add-MediaTek-MT7621-PCIe-host-controller-.patch @@ -0,0 +1,1418 @@ +From: Sergio Paracuellos <sergio.paracuellos@gmail.com> +Date: Wed, 22 Sep 2021 07:00:34 +0200 +Subject: [PATCH] PCI: mt7621: Add MediaTek MT7621 PCIe host controller driver + +Add driver for the PCIe controller of the MT7621 SoC. + +[bhelgaas: rename from pci-mt7621.c to pcie-mt7621.c; also rename Kconfig +symbol from PCI_MT7621 to PCIE_MT7621] +Link: https://lore.kernel.org/r/20210922050035.18162-3-sergio.paracuellos@gmail.com +Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com> +Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> +Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> +Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + rename drivers/{staging/mt7621-pci/pci-mt7621.c => pci/controller/pcie-mt7621.c} (95%) + delete mode 100644 drivers/staging/mt7621-pci/Kconfig + delete mode 100644 drivers/staging/mt7621-pci/Makefile + delete mode 100644 drivers/staging/mt7621-pci/TODO + delete mode 100644 drivers/staging/mt7621-pci/mediatek,mt7621-pci.txt + +--- a/arch/mips/ralink/Kconfig ++++ b/arch/mips/ralink/Kconfig +@@ -51,7 +51,8 @@ choice + select SYS_SUPPORTS_HIGHMEM + select MIPS_GIC + select CLKSRC_MIPS_GIC +- select HAVE_PCI if PCI_MT7621 ++ select HAVE_PCI ++ select PCI_DRIVERS_GENERIC + select SOC_BUS + endchoice + +--- a/drivers/pci/controller/Kconfig ++++ b/drivers/pci/controller/Kconfig +@@ -312,6 +312,14 @@ config PCIE_HISI_ERR + Say Y here if you want error handling support + for the PCIe controller's errors on HiSilicon HIP SoCs + ++config PCIE_MT7621 ++ tristate "MediaTek MT7621 PCIe Controller" ++ depends on (RALINK && SOC_MT7621) || (MIPS && COMPILE_TEST) ++ select PHY_MT7621_PCI ++ default SOC_MT7621 ++ help ++ This selects a driver for the MediaTek MT7621 PCIe Controller. ++ + source "drivers/pci/controller/dwc/Kconfig" + source "drivers/pci/controller/mobiveil/Kconfig" + source "drivers/pci/controller/cadence/Kconfig" +--- a/drivers/pci/controller/Makefile ++++ b/drivers/pci/controller/Makefile +@@ -37,6 +37,8 @@ obj-$(CONFIG_VMD) += vmd.o + obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o + obj-$(CONFIG_PCI_LOONGSON) += pci-loongson.o + obj-$(CONFIG_PCIE_HISI_ERR) += pcie-hisi-error.o ++obj-$(CONFIG_PCIE_MT7621) += pcie-mt7621.o ++ + # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW + obj-y += dwc/ + obj-y += mobiveil/ +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -86,8 +86,6 @@ source "drivers/staging/vc04_services/Kc + + source "drivers/staging/pi433/Kconfig" + +-source "drivers/staging/mt7621-pci/Kconfig" +- + source "drivers/staging/mt7621-dma/Kconfig" + + source "drivers/staging/ralink-gdma/Kconfig" +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -33,7 +33,6 @@ obj-$(CONFIG_KS7010) += ks7010/ + obj-$(CONFIG_GREYBUS) += greybus/ + obj-$(CONFIG_BCM2835_VCHIQ) += vc04_services/ + obj-$(CONFIG_PI433) += pi433/ +-obj-$(CONFIG_PCI_MT7621) += mt7621-pci/ + obj-$(CONFIG_SOC_MT7621) += mt7621-dma/ + obj-$(CONFIG_DMA_RALINK) += ralink-gdma/ + obj-$(CONFIG_SOC_MT7621) += mt7621-dts/ +--- a/drivers/staging/mt7621-pci/Kconfig ++++ /dev/null +@@ -1,8 +0,0 @@ +-# SPDX-License-Identifier: GPL-2.0 +-config PCI_MT7621 +- tristate "MediaTek MT7621 PCI Controller" +- depends on RALINK +- select PCI_DRIVERS_GENERIC +- help +- This selects a driver for the MediaTek MT7621 PCI Controller. +- +--- a/drivers/staging/mt7621-pci/Makefile ++++ /dev/null +@@ -1,2 +0,0 @@ +-# SPDX-License-Identifier: GPL-2.0 +-obj-$(CONFIG_PCI_MT7621) += pci-mt7621.o +--- a/drivers/staging/mt7621-pci/TODO ++++ /dev/null +@@ -1,4 +0,0 @@ +- +-- general code review and cleanup +- +-Cc: NeilBrown <neil@brown.name> +--- a/drivers/staging/mt7621-pci/mediatek,mt7621-pci.txt ++++ /dev/null +@@ -1,104 +0,0 @@ +-MediaTek MT7621 PCIe controller +- +-Required properties: +-- compatible: "mediatek,mt7621-pci" +-- device_type: Must be "pci" +-- reg: Base addresses and lengths of the PCIe subsys and root ports. +-- bus-range: Range of bus numbers associated with this controller. +-- #address-cells: Address representation for root ports (must be 3) +-- pinctrl-names : The pin control state names. +-- pinctrl-0: The "default" pinctrl state. +-- #size-cells: Size representation for root ports (must be 2) +-- ranges: Ranges for the PCI memory and I/O regions. +-- #interrupt-cells: Must be 1 +-- interrupt-map-mask and interrupt-map: Standard PCI IRQ mapping properties. +- Please refer to the standard PCI bus binding document for a more detailed +- explanation. +-- status: either "disabled" or "okay". +-- resets: Must contain an entry for each entry in reset-names. +- See ../reset/reset.txt for details. +-- reset-names: Must be "pcie0", "pcie1", "pcieN"... based on the number of +- root ports. +-- clocks: Must contain an entry for each entry in clock-names. +- See ../clocks/clock-bindings.txt for details. +-- clock-names: Must be "pcie0", "pcie1", "pcieN"... based on the number of +- root ports. +-- reset-gpios: GPIO specs for the reset pins. +- +-In addition, the device tree node must have sub-nodes describing each PCIe port +-interface, having the following mandatory properties: +- +-Required properties: +-- reg: Only the first four bytes are used to refer to the correct bus number +- and device number. +-- #address-cells: Must be 3 +-- #size-cells: Must be 2 +-- ranges: Sub-ranges distributed from the PCIe controller node. An empty +- property is sufficient. +-- bus-range: Range of bus numbers associated with this port. +- +-Example for MT7621: +- +- pcie: pcie@1e140000 { +- compatible = "mediatek,mt7621-pci"; +- reg = <0x1e140000 0x100 /* host-pci bridge registers */ +- 0x1e142000 0x100 /* pcie port 0 RC control registers */ +- 0x1e143000 0x100 /* pcie port 1 RC control registers */ +- 0x1e144000 0x100>; /* pcie port 2 RC control registers */ +- +- #address-cells = <3>; +- #size-cells = <2>; +- +- pinctrl-names = "default"; +- pinctrl-0 = <&pcie_pins>; +- +- device_type = "pci"; +- +- bus-range = <0 255>; +- ranges = < +- 0x02000000 0 0x00000000 0x60000000 0 0x10000000 /* pci memory */ +- 0x01000000 0 0x00000000 0x1e160000 0 0x00010000 /* io space */ +- >; +- +- #interrupt-cells = <1>; +- interrupt-map-mask = <0xF0000 0 0 1>; +- interrupt-map = <0x10000 0 0 1 &gic GIC_SHARED 4 IRQ_TYPE_LEVEL_HIGH>, +- <0x20000 0 0 1 &gic GIC_SHARED 24 IRQ_TYPE_LEVEL_HIGH>, +- <0x30000 0 0 1 &gic GIC_SHARED 25 IRQ_TYPE_LEVEL_HIGH>; +- +- status = "disabled"; +- +- resets = <&rstctrl 24 &rstctrl 25 &rstctrl 26>; +- reset-names = "pcie0", "pcie1", "pcie2"; +- clocks = <&clkctrl 24 &clkctrl 25 &clkctrl 26>; +- clock-names = "pcie0", "pcie1", "pcie2"; +- +- reset-gpios = <&gpio 19 GPIO_ACTIVE_LOW>, +- <&gpio 8 GPIO_ACTIVE_LOW>, +- <&gpio 7 GPIO_ACTIVE_LOW>; +- +- pcie@0,0 { +- reg = <0x0000 0 0 0 0>; +- #address-cells = <3>; +- #size-cells = <2>; +- ranges; +- bus-range = <0x00 0xff>; +- }; +- +- pcie@1,0 { +- reg = <0x0800 0 0 0 0>; +- #address-cells = <3>; +- #size-cells = <2>; +- ranges; +- bus-range = <0x00 0xff>; +- }; +- +- pcie@2,0 { +- reg = <0x1000 0 0 0 0>; +- #address-cells = <3>; +- #size-cells = <2>; +- ranges; +- bus-range = <0x00 0xff>; +- }; +- }; +- +--- a/drivers/staging/mt7621-pci/pci-mt7621.c ++++ /dev/null +@@ -1,601 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0+ +-/* +- * BRIEF MODULE DESCRIPTION +- * PCI init for Ralink RT2880 solution +- * +- * Copyright 2007 Ralink Inc. (bruce_chang@ralinktech.com.tw) +- * +- * May 2007 Bruce Chang +- * Initial Release +- * +- * May 2009 Bruce Chang +- * support RT2880/RT3883 PCIe +- * +- * May 2011 Bruce Chang +- * support RT6855/MT7620 PCIe +- */ +- +-#include <linux/bitops.h> +-#include <linux/clk.h> +-#include <linux/delay.h> +-#include <linux/gpio/consumer.h> +-#include <linux/module.h> +-#include <linux/of.h> +-#include <linux/of_address.h> +-#include <linux/of_pci.h> +-#include <linux/of_platform.h> +-#include <linux/pci.h> +-#include <linux/phy/phy.h> +-#include <linux/platform_device.h> +-#include <linux/reset.h> +-#include <linux/sys_soc.h> +- +-/* MediaTek specific configuration registers */ +-#define PCIE_FTS_NUM 0x70c +-#define PCIE_FTS_NUM_MASK GENMASK(15, 8) +-#define PCIE_FTS_NUM_L0(x) (((x) & 0xff) << 8) +- +-/* Host-PCI bridge registers */ +-#define RALINK_PCI_PCICFG_ADDR 0x0000 +-#define RALINK_PCI_PCIMSK_ADDR 0x000C +-#define RALINK_PCI_CONFIG_ADDR 0x0020 +-#define RALINK_PCI_CONFIG_DATA 0x0024 +-#define RALINK_PCI_MEMBASE 0x0028 +-#define RALINK_PCI_IOBASE 0x002C +- +-/* PCIe RC control registers */ +-#define RALINK_PCI_ID 0x0030 +-#define RALINK_PCI_CLASS 0x0034 +-#define RALINK_PCI_SUBID 0x0038 +-#define RALINK_PCI_STATUS 0x0050 +- +-/* Some definition values */ +-#define PCIE_REVISION_ID BIT(0) +-#define PCIE_CLASS_CODE (0x60400 << 8) +-#define PCIE_BAR_MAP_MAX GENMASK(30, 16) +-#define PCIE_BAR_ENABLE BIT(0) +-#define PCIE_PORT_INT_EN(x) BIT(20 + (x)) +-#define PCIE_PORT_LINKUP BIT(0) +-#define PCIE_PORT_CNT 3 +- +-#define PERST_DELAY_MS 100 +- +-/** +- * struct mt7621_pcie_port - PCIe port information +- * @base: I/O mapped register base +- * @list: port list +- * @pcie: pointer to PCIe host info +- * @clk: pointer to the port clock gate +- * @phy: pointer to PHY control block +- * @pcie_rst: pointer to port reset control +- * @gpio_rst: gpio reset +- * @slot: port slot +- * @enabled: indicates if port is enabled +- */ +-struct mt7621_pcie_port { +- void __iomem *base; +- struct list_head list; +- struct mt7621_pcie *pcie; +- struct clk *clk; +- struct phy *phy; +- struct reset_control *pcie_rst; +- struct gpio_desc *gpio_rst; +- u32 slot; +- bool enabled; +-}; +- +-/** +- * struct mt7621_pcie - PCIe host information +- * @base: IO Mapped Register Base +- * @dev: Pointer to PCIe device +- * @ports: pointer to PCIe port information +- * @resets_inverted: depends on chip revision +- * reset lines are inverted. +- */ +-struct mt7621_pcie { +- struct device *dev; +- void __iomem *base; +- struct list_head ports; +- bool resets_inverted; +-}; +- +-static inline u32 pcie_read(struct mt7621_pcie *pcie, u32 reg) +-{ +- return readl_relaxed(pcie->base + reg); +-} +- +-static inline void pcie_write(struct mt7621_pcie *pcie, u32 val, u32 reg) +-{ +- writel_relaxed(val, pcie->base + reg); +-} +- +-static inline void pcie_rmw(struct mt7621_pcie *pcie, u32 reg, u32 clr, u32 set) +-{ +- u32 val = readl_relaxed(pcie->base + reg); +- +- val &= ~clr; +- val |= set; +- writel_relaxed(val, pcie->base + reg); +-} +- +-static inline u32 pcie_port_read(struct mt7621_pcie_port *port, u32 reg) +-{ +- return readl_relaxed(port->base + reg); +-} +- +-static inline void pcie_port_write(struct mt7621_pcie_port *port, +- u32 val, u32 reg) +-{ +- writel_relaxed(val, port->base + reg); +-} +- +-static inline u32 mt7621_pcie_get_cfgaddr(unsigned int bus, unsigned int slot, +- unsigned int func, unsigned int where) +-{ +- return (((where & 0xF00) >> 8) << 24) | (bus << 16) | (slot << 11) | +- (func << 8) | (where & 0xfc) | 0x80000000; +-} +- +-static void __iomem *mt7621_pcie_map_bus(struct pci_bus *bus, +- unsigned int devfn, int where) +-{ +- struct mt7621_pcie *pcie = bus->sysdata; +- u32 address = mt7621_pcie_get_cfgaddr(bus->number, PCI_SLOT(devfn), +- PCI_FUNC(devfn), where); +- +- writel_relaxed(address, pcie->base + RALINK_PCI_CONFIG_ADDR); +- +- return pcie->base + RALINK_PCI_CONFIG_DATA + (where & 3); +-} +- +-struct pci_ops mt7621_pcie_ops = { +- .map_bus = mt7621_pcie_map_bus, +- .read = pci_generic_config_read, +- .write = pci_generic_config_write, +-}; +- +-static u32 read_config(struct mt7621_pcie *pcie, unsigned int dev, u32 reg) +-{ +- u32 address = mt7621_pcie_get_cfgaddr(0, dev, 0, reg); +- +- pcie_write(pcie, address, RALINK_PCI_CONFIG_ADDR); +- return pcie_read(pcie, RALINK_PCI_CONFIG_DATA); +-} +- +-static void write_config(struct mt7621_pcie *pcie, unsigned int dev, +- u32 reg, u32 val) +-{ +- u32 address = mt7621_pcie_get_cfgaddr(0, dev, 0, reg); +- +- pcie_write(pcie, address, RALINK_PCI_CONFIG_ADDR); +- pcie_write(pcie, val, RALINK_PCI_CONFIG_DATA); +-} +- +-static inline void mt7621_rst_gpio_pcie_assert(struct mt7621_pcie_port *port) +-{ +- if (port->gpio_rst) +- gpiod_set_value(port->gpio_rst, 1); +-} +- +-static inline void mt7621_rst_gpio_pcie_deassert(struct mt7621_pcie_port *port) +-{ +- if (port->gpio_rst) +- gpiod_set_value(port->gpio_rst, 0); +-} +- +-static inline bool mt7621_pcie_port_is_linkup(struct mt7621_pcie_port *port) +-{ +- return (pcie_port_read(port, RALINK_PCI_STATUS) & PCIE_PORT_LINKUP) != 0; +-} +- +-static inline void mt7621_control_assert(struct mt7621_pcie_port *port) +-{ +- struct mt7621_pcie *pcie = port->pcie; +- +- if (pcie->resets_inverted) +- reset_control_assert(port->pcie_rst); +- else +- reset_control_deassert(port->pcie_rst); +-} +- +-static inline void mt7621_control_deassert(struct mt7621_pcie_port *port) +-{ +- struct mt7621_pcie *pcie = port->pcie; +- +- if (pcie->resets_inverted) +- reset_control_deassert(port->pcie_rst); +- else +- reset_control_assert(port->pcie_rst); +-} +- +-static int setup_cm_memory_region(struct pci_host_bridge *host) +-{ +- struct mt7621_pcie *pcie = pci_host_bridge_priv(host); +- struct device *dev = pcie->dev; +- struct resource_entry *entry; +- resource_size_t mask; +- +- entry = resource_list_first_type(&host->windows, IORESOURCE_MEM); +- if (!entry) { +- dev_err(dev, "Cannot get memory resource\n"); +- return -EINVAL; +- } +- +- if (mips_cps_numiocu(0)) { +- /* +- * FIXME: hardware doesn't accept mask values with 1s after +- * 0s (e.g. 0xffef), so it would be great to warn if that's +- * about to happen +- */ +- mask = ~(entry->res->end - entry->res->start); +- +- write_gcr_reg1_base(entry->res->start); +- write_gcr_reg1_mask(mask | CM_GCR_REGn_MASK_CMTGT_IOCU0); +- dev_info(dev, "PCI coherence region base: 0x%08llx, mask/settings: 0x%08llx\n", +- (unsigned long long)read_gcr_reg1_base(), +- (unsigned long long)read_gcr_reg1_mask()); +- } +- +- return 0; +-} +- +-static int mt7621_pcie_parse_port(struct mt7621_pcie *pcie, +- struct device_node *node, +- int slot) +-{ +- struct mt7621_pcie_port *port; +- struct device *dev = pcie->dev; +- struct platform_device *pdev = to_platform_device(dev); +- char name[10]; +- int err; +- +- port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); +- if (!port) +- return -ENOMEM; +- +- port->base = devm_platform_ioremap_resource(pdev, slot + 1); +- if (IS_ERR(port->base)) +- return PTR_ERR(port->base); +- +- port->clk = devm_get_clk_from_child(dev, node, NULL); +- if (IS_ERR(port->clk)) { +- dev_err(dev, "failed to get pcie%d clock\n", slot); +- return PTR_ERR(port->clk); +- } +- +- port->pcie_rst = of_reset_control_get_exclusive(node, NULL); +- if (PTR_ERR(port->pcie_rst) == -EPROBE_DEFER) { +- dev_err(dev, "failed to get pcie%d reset control\n", slot); +- return PTR_ERR(port->pcie_rst); +- } +- +- snprintf(name, sizeof(name), "pcie-phy%d", slot); +- port->phy = devm_of_phy_get(dev, node, name); +- if (IS_ERR(port->phy)) { +- dev_err(dev, "failed to get pcie-phy%d\n", slot); +- err = PTR_ERR(port->phy); +- goto remove_reset; +- } +- +- port->gpio_rst = devm_gpiod_get_index_optional(dev, "reset", slot, +- GPIOD_OUT_LOW); +- if (IS_ERR(port->gpio_rst)) { +- dev_err(dev, "Failed to get GPIO for PCIe%d\n", slot); +- err = PTR_ERR(port->gpio_rst); +- goto remove_reset; +- } +- +- port->slot = slot; +- port->pcie = pcie; +- +- INIT_LIST_HEAD(&port->list); +- list_add_tail(&port->list, &pcie->ports); +- +- return 0; +- +-remove_reset: +- reset_control_put(port->pcie_rst); +- return err; +-} +- +-static int mt7621_pcie_parse_dt(struct mt7621_pcie *pcie) +-{ +- struct device *dev = pcie->dev; +- struct platform_device *pdev = to_platform_device(dev); +- struct device_node *node = dev->of_node, *child; +- int err; +- +- pcie->base = devm_platform_ioremap_resource(pdev, 0); +- if (IS_ERR(pcie->base)) +- return PTR_ERR(pcie->base); +- +- for_each_available_child_of_node(node, child) { +- int slot; +- +- err = of_pci_get_devfn(child); +- if (err < 0) { +- of_node_put(child); +- dev_err(dev, "failed to parse devfn: %d\n", err); +- return err; +- } +- +- slot = PCI_SLOT(err); +- +- err = mt7621_pcie_parse_port(pcie, child, slot); +- if (err) { +- of_node_put(child); +- return err; +- } +- } +- +- return 0; +-} +- +-static int mt7621_pcie_init_port(struct mt7621_pcie_port *port) +-{ +- struct mt7621_pcie *pcie = port->pcie; +- struct device *dev = pcie->dev; +- u32 slot = port->slot; +- int err; +- +- err = phy_init(port->phy); +- if (err) { +- dev_err(dev, "failed to initialize port%d phy\n", slot); +- return err; +- } +- +- err = phy_power_on(port->phy); +- if (err) { +- dev_err(dev, "failed to power on port%d phy\n", slot); +- phy_exit(port->phy); +- return err; +- } +- +- port->enabled = true; +- +- return 0; +-} +- +-static void mt7621_pcie_reset_assert(struct mt7621_pcie *pcie) +-{ +- struct mt7621_pcie_port *port; +- +- list_for_each_entry(port, &pcie->ports, list) { +- /* PCIe RC reset assert */ +- mt7621_control_assert(port); +- +- /* PCIe EP reset assert */ +- mt7621_rst_gpio_pcie_assert(port); +- } +- +- msleep(PERST_DELAY_MS); +-} +- +-static void mt7621_pcie_reset_rc_deassert(struct mt7621_pcie *pcie) +-{ +- struct mt7621_pcie_port *port; +- +- list_for_each_entry(port, &pcie->ports, list) +- mt7621_control_deassert(port); +-} +- +-static void mt7621_pcie_reset_ep_deassert(struct mt7621_pcie *pcie) +-{ +- struct mt7621_pcie_port *port; +- +- list_for_each_entry(port, &pcie->ports, list) +- mt7621_rst_gpio_pcie_deassert(port); +- +- msleep(PERST_DELAY_MS); +-} +- +-static int mt7621_pcie_init_ports(struct mt7621_pcie *pcie) +-{ +- struct device *dev = pcie->dev; +- struct mt7621_pcie_port *port, *tmp; +- u8 num_disabled = 0; +- int err; +- +- mt7621_pcie_reset_assert(pcie); +- mt7621_pcie_reset_rc_deassert(pcie); +- +- list_for_each_entry_safe(port, tmp, &pcie->ports, list) { +- u32 slot = port->slot; +- +- if (slot == 1) { +- port->enabled = true; +- continue; +- } +- +- err = mt7621_pcie_init_port(port); +- if (err) { +- dev_err(dev, "Initiating port %d failed\n", slot); +- list_del(&port->list); +- } +- } +- +- mt7621_pcie_reset_ep_deassert(pcie); +- +- tmp = NULL; +- list_for_each_entry(port, &pcie->ports, list) { +- u32 slot = port->slot; +- +- if (!mt7621_pcie_port_is_linkup(port)) { +- dev_err(dev, "pcie%d no card, disable it (RST & CLK)\n", +- slot); +- mt7621_control_assert(port); +- port->enabled = false; +- num_disabled++; +- +- if (slot == 0) { +- tmp = port; +- continue; +- } +- +- if (slot == 1 && tmp && !tmp->enabled) +- phy_power_off(tmp->phy); +- } +- } +- +- return (num_disabled != PCIE_PORT_CNT) ? 0 : -ENODEV; +-} +- +-static void mt7621_pcie_enable_port(struct mt7621_pcie_port *port) +-{ +- struct mt7621_pcie *pcie = port->pcie; +- u32 slot = port->slot; +- u32 val; +- +- /* enable pcie interrupt */ +- val = pcie_read(pcie, RALINK_PCI_PCIMSK_ADDR); +- val |= PCIE_PORT_INT_EN(slot); +- pcie_write(pcie, val, RALINK_PCI_PCIMSK_ADDR); +- +- /* map 2G DDR region */ +- pcie_port_write(port, PCIE_BAR_MAP_MAX | PCIE_BAR_ENABLE, +- PCI_BASE_ADDRESS_0); +- +- /* configure class code and revision ID */ +- pcie_port_write(port, PCIE_CLASS_CODE | PCIE_REVISION_ID, +- RALINK_PCI_CLASS); +- +- /* configure RC FTS number to 250 when it leaves L0s */ +- val = read_config(pcie, slot, PCIE_FTS_NUM); +- val &= ~PCIE_FTS_NUM_MASK; +- val |= PCIE_FTS_NUM_L0(0x50); +- write_config(pcie, slot, PCIE_FTS_NUM, val); +-} +- +-static int mt7621_pcie_enable_ports(struct pci_host_bridge *host) +-{ +- struct mt7621_pcie *pcie = pci_host_bridge_priv(host); +- struct device *dev = pcie->dev; +- struct mt7621_pcie_port *port; +- struct resource_entry *entry; +- int err; +- +- entry = resource_list_first_type(&host->windows, IORESOURCE_IO); +- if (!entry) { +- dev_err(dev, "Cannot get io resource\n"); +- return -EINVAL; +- } +- +- /* Setup MEMWIN and IOWIN */ +- pcie_write(pcie, 0xffffffff, RALINK_PCI_MEMBASE); +- pcie_write(pcie, entry->res->start, RALINK_PCI_IOBASE); +- +- list_for_each_entry(port, &pcie->ports, list) { +- if (port->enabled) { +- err = clk_prepare_enable(port->clk); +- if (err) { +- dev_err(dev, "enabling clk pcie%d\n", +- port->slot); +- return err; +- } +- +- mt7621_pcie_enable_port(port); +- dev_info(dev, "PCIE%d enabled\n", port->slot); +- } +- } +- +- return 0; +-} +- +-static int mt7621_pcie_register_host(struct pci_host_bridge *host) +-{ +- struct mt7621_pcie *pcie = pci_host_bridge_priv(host); +- +- host->ops = &mt7621_pcie_ops; +- host->sysdata = pcie; +- return pci_host_probe(host); +-} +- +-static const struct soc_device_attribute mt7621_pcie_quirks_match[] = { +- { .soc_id = "mt7621", .revision = "E2" }, +- { /* sentinel */ } +-}; +- +-static int mt7621_pcie_probe(struct platform_device *pdev) +-{ +- struct device *dev = &pdev->dev; +- const struct soc_device_attribute *attr; +- struct mt7621_pcie_port *port; +- struct mt7621_pcie *pcie; +- struct pci_host_bridge *bridge; +- int err; +- +- if (!dev->of_node) +- return -ENODEV; +- +- bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie)); +- if (!bridge) +- return -ENOMEM; +- +- pcie = pci_host_bridge_priv(bridge); +- pcie->dev = dev; +- platform_set_drvdata(pdev, pcie); +- INIT_LIST_HEAD(&pcie->ports); +- +- attr = soc_device_match(mt7621_pcie_quirks_match); +- if (attr) +- pcie->resets_inverted = true; +- +- err = mt7621_pcie_parse_dt(pcie); +- if (err) { +- dev_err(dev, "Parsing DT failed\n"); +- return err; +- } +- +- err = mt7621_pcie_init_ports(pcie); +- if (err) { +- dev_err(dev, "Nothing connected in virtual bridges\n"); +- return 0; +- } +- +- err = mt7621_pcie_enable_ports(bridge); +- if (err) { +- dev_err(dev, "Error enabling pcie ports\n"); +- goto remove_resets; +- } +- +- err = setup_cm_memory_region(bridge); +- if (err) { +- dev_err(dev, "Error setting up iocu mem regions\n"); +- goto remove_resets; +- } +- +- return mt7621_pcie_register_host(bridge); +- +-remove_resets: +- list_for_each_entry(port, &pcie->ports, list) +- reset_control_put(port->pcie_rst); +- +- return err; +-} +- +-static int mt7621_pcie_remove(struct platform_device *pdev) +-{ +- struct mt7621_pcie *pcie = platform_get_drvdata(pdev); +- struct mt7621_pcie_port *port; +- +- list_for_each_entry(port, &pcie->ports, list) +- reset_control_put(port->pcie_rst); +- +- return 0; +-} +- +-static const struct of_device_id mt7621_pcie_ids[] = { +- { .compatible = "mediatek,mt7621-pci" }, +- {}, +-}; +-MODULE_DEVICE_TABLE(of, mt7621_pcie_ids); +- +-static struct platform_driver mt7621_pcie_driver = { +- .probe = mt7621_pcie_probe, +- .remove = mt7621_pcie_remove, +- .driver = { +- .name = "mt7621-pci", +- .of_match_table = of_match_ptr(mt7621_pcie_ids), +- }, +-}; +-builtin_platform_driver(mt7621_pcie_driver); +--- /dev/null ++++ b/drivers/pci/controller/pcie-mt7621.c +@@ -0,0 +1,600 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * BRIEF MODULE DESCRIPTION ++ * PCI init for Ralink RT2880 solution ++ * ++ * Copyright 2007 Ralink Inc. (bruce_chang@ralinktech.com.tw) ++ * ++ * May 2007 Bruce Chang ++ * Initial Release ++ * ++ * May 2009 Bruce Chang ++ * support RT2880/RT3883 PCIe ++ * ++ * May 2011 Bruce Chang ++ * support RT6855/MT7620 PCIe ++ */ ++ ++#include <linux/bitops.h> ++#include <linux/clk.h> ++#include <linux/delay.h> ++#include <linux/gpio/consumer.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_address.h> ++#include <linux/of_pci.h> ++#include <linux/of_platform.h> ++#include <linux/pci.h> ++#include <linux/phy/phy.h> ++#include <linux/platform_device.h> ++#include <linux/reset.h> ++#include <linux/sys_soc.h> ++ ++/* MediaTek-specific configuration registers */ ++#define PCIE_FTS_NUM 0x70c ++#define PCIE_FTS_NUM_MASK GENMASK(15, 8) ++#define PCIE_FTS_NUM_L0(x) (((x) & 0xff) << 8) ++ ++/* Host-PCI bridge registers */ ++#define RALINK_PCI_PCICFG_ADDR 0x0000 ++#define RALINK_PCI_PCIMSK_ADDR 0x000c ++#define RALINK_PCI_CONFIG_ADDR 0x0020 ++#define RALINK_PCI_CONFIG_DATA 0x0024 ++#define RALINK_PCI_MEMBASE 0x0028 ++#define RALINK_PCI_IOBASE 0x002c ++ ++/* PCIe RC control registers */ ++#define RALINK_PCI_ID 0x0030 ++#define RALINK_PCI_CLASS 0x0034 ++#define RALINK_PCI_SUBID 0x0038 ++#define RALINK_PCI_STATUS 0x0050 ++ ++/* Some definition values */ ++#define PCIE_REVISION_ID BIT(0) ++#define PCIE_CLASS_CODE (0x60400 << 8) ++#define PCIE_BAR_MAP_MAX GENMASK(30, 16) ++#define PCIE_BAR_ENABLE BIT(0) ++#define PCIE_PORT_INT_EN(x) BIT(20 + (x)) ++#define PCIE_PORT_LINKUP BIT(0) ++#define PCIE_PORT_CNT 3 ++ ++#define PERST_DELAY_MS 100 ++ ++/** ++ * struct mt7621_pcie_port - PCIe port information ++ * @base: I/O mapped register base ++ * @list: port list ++ * @pcie: pointer to PCIe host info ++ * @clk: pointer to the port clock gate ++ * @phy: pointer to PHY control block ++ * @pcie_rst: pointer to port reset control ++ * @gpio_rst: gpio reset ++ * @slot: port slot ++ * @enabled: indicates if port is enabled ++ */ ++struct mt7621_pcie_port { ++ void __iomem *base; ++ struct list_head list; ++ struct mt7621_pcie *pcie; ++ struct clk *clk; ++ struct phy *phy; ++ struct reset_control *pcie_rst; ++ struct gpio_desc *gpio_rst; ++ u32 slot; ++ bool enabled; ++}; ++ ++/** ++ * struct mt7621_pcie - PCIe host information ++ * @base: IO Mapped Register Base ++ * @dev: Pointer to PCIe device ++ * @ports: pointer to PCIe port information ++ * @resets_inverted: depends on chip revision ++ * reset lines are inverted. ++ */ ++struct mt7621_pcie { ++ void __iomem *base; ++ struct device *dev; ++ struct list_head ports; ++ bool resets_inverted; ++}; ++ ++static inline u32 pcie_read(struct mt7621_pcie *pcie, u32 reg) ++{ ++ return readl_relaxed(pcie->base + reg); ++} ++ ++static inline void pcie_write(struct mt7621_pcie *pcie, u32 val, u32 reg) ++{ ++ writel_relaxed(val, pcie->base + reg); ++} ++ ++static inline void pcie_rmw(struct mt7621_pcie *pcie, u32 reg, u32 clr, u32 set) ++{ ++ u32 val = readl_relaxed(pcie->base + reg); ++ ++ val &= ~clr; ++ val |= set; ++ writel_relaxed(val, pcie->base + reg); ++} ++ ++static inline u32 pcie_port_read(struct mt7621_pcie_port *port, u32 reg) ++{ ++ return readl_relaxed(port->base + reg); ++} ++ ++static inline void pcie_port_write(struct mt7621_pcie_port *port, ++ u32 val, u32 reg) ++{ ++ writel_relaxed(val, port->base + reg); ++} ++ ++static inline u32 mt7621_pci_get_cfgaddr(unsigned int bus, unsigned int slot, ++ unsigned int func, unsigned int where) ++{ ++ return (((where & 0xf00) >> 8) << 24) | (bus << 16) | (slot << 11) | ++ (func << 8) | (where & 0xfc) | 0x80000000; ++} ++ ++static void __iomem *mt7621_pcie_map_bus(struct pci_bus *bus, ++ unsigned int devfn, int where) ++{ ++ struct mt7621_pcie *pcie = bus->sysdata; ++ u32 address = mt7621_pci_get_cfgaddr(bus->number, PCI_SLOT(devfn), ++ PCI_FUNC(devfn), where); ++ ++ writel_relaxed(address, pcie->base + RALINK_PCI_CONFIG_ADDR); ++ ++ return pcie->base + RALINK_PCI_CONFIG_DATA + (where & 3); ++} ++ ++struct pci_ops mt7621_pci_ops = { ++ .map_bus = mt7621_pcie_map_bus, ++ .read = pci_generic_config_read, ++ .write = pci_generic_config_write, ++}; ++ ++static u32 read_config(struct mt7621_pcie *pcie, unsigned int dev, u32 reg) ++{ ++ u32 address = mt7621_pci_get_cfgaddr(0, dev, 0, reg); ++ ++ pcie_write(pcie, address, RALINK_PCI_CONFIG_ADDR); ++ return pcie_read(pcie, RALINK_PCI_CONFIG_DATA); ++} ++ ++static void write_config(struct mt7621_pcie *pcie, unsigned int dev, ++ u32 reg, u32 val) ++{ ++ u32 address = mt7621_pci_get_cfgaddr(0, dev, 0, reg); ++ ++ pcie_write(pcie, address, RALINK_PCI_CONFIG_ADDR); ++ pcie_write(pcie, val, RALINK_PCI_CONFIG_DATA); ++} ++ ++static inline void mt7621_rst_gpio_pcie_assert(struct mt7621_pcie_port *port) ++{ ++ if (port->gpio_rst) ++ gpiod_set_value(port->gpio_rst, 1); ++} ++ ++static inline void mt7621_rst_gpio_pcie_deassert(struct mt7621_pcie_port *port) ++{ ++ if (port->gpio_rst) ++ gpiod_set_value(port->gpio_rst, 0); ++} ++ ++static inline bool mt7621_pcie_port_is_linkup(struct mt7621_pcie_port *port) ++{ ++ return (pcie_port_read(port, RALINK_PCI_STATUS) & PCIE_PORT_LINKUP) != 0; ++} ++ ++static inline void mt7621_control_assert(struct mt7621_pcie_port *port) ++{ ++ struct mt7621_pcie *pcie = port->pcie; ++ ++ if (pcie->resets_inverted) ++ reset_control_assert(port->pcie_rst); ++ else ++ reset_control_deassert(port->pcie_rst); ++} ++ ++static inline void mt7621_control_deassert(struct mt7621_pcie_port *port) ++{ ++ struct mt7621_pcie *pcie = port->pcie; ++ ++ if (pcie->resets_inverted) ++ reset_control_deassert(port->pcie_rst); ++ else ++ reset_control_assert(port->pcie_rst); ++} ++ ++static int setup_cm_memory_region(struct pci_host_bridge *host) ++{ ++ struct mt7621_pcie *pcie = pci_host_bridge_priv(host); ++ struct device *dev = pcie->dev; ++ struct resource_entry *entry; ++ resource_size_t mask; ++ ++ entry = resource_list_first_type(&host->windows, IORESOURCE_MEM); ++ if (!entry) { ++ dev_err(dev, "cannot get memory resource\n"); ++ return -EINVAL; ++ } ++ ++ if (mips_cps_numiocu(0)) { ++ /* ++ * FIXME: hardware doesn't accept mask values with 1s after ++ * 0s (e.g. 0xffef), so it would be great to warn if that's ++ * about to happen ++ */ ++ mask = ~(entry->res->end - entry->res->start); ++ ++ write_gcr_reg1_base(entry->res->start); ++ write_gcr_reg1_mask(mask | CM_GCR_REGn_MASK_CMTGT_IOCU0); ++ dev_info(dev, "PCI coherence region base: 0x%08llx, mask/settings: 0x%08llx\n", ++ (unsigned long long)read_gcr_reg1_base(), ++ (unsigned long long)read_gcr_reg1_mask()); ++ } ++ ++ return 0; ++} ++ ++static int mt7621_pcie_parse_port(struct mt7621_pcie *pcie, ++ struct device_node *node, ++ int slot) ++{ ++ struct mt7621_pcie_port *port; ++ struct device *dev = pcie->dev; ++ struct platform_device *pdev = to_platform_device(dev); ++ char name[10]; ++ int err; ++ ++ port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); ++ if (!port) ++ return -ENOMEM; ++ ++ port->base = devm_platform_ioremap_resource(pdev, slot + 1); ++ if (IS_ERR(port->base)) ++ return PTR_ERR(port->base); ++ ++ port->clk = devm_get_clk_from_child(dev, node, NULL); ++ if (IS_ERR(port->clk)) { ++ dev_err(dev, "failed to get pcie%d clock\n", slot); ++ return PTR_ERR(port->clk); ++ } ++ ++ port->pcie_rst = of_reset_control_get_exclusive(node, NULL); ++ if (PTR_ERR(port->pcie_rst) == -EPROBE_DEFER) { ++ dev_err(dev, "failed to get pcie%d reset control\n", slot); ++ return PTR_ERR(port->pcie_rst); ++ } ++ ++ snprintf(name, sizeof(name), "pcie-phy%d", slot); ++ port->phy = devm_of_phy_get(dev, node, name); ++ if (IS_ERR(port->phy)) { ++ dev_err(dev, "failed to get pcie-phy%d\n", slot); ++ err = PTR_ERR(port->phy); ++ goto remove_reset; ++ } ++ ++ port->gpio_rst = devm_gpiod_get_index_optional(dev, "reset", slot, ++ GPIOD_OUT_LOW); ++ if (IS_ERR(port->gpio_rst)) { ++ dev_err(dev, "failed to get GPIO for PCIe%d\n", slot); ++ err = PTR_ERR(port->gpio_rst); ++ goto remove_reset; ++ } ++ ++ port->slot = slot; ++ port->pcie = pcie; ++ ++ INIT_LIST_HEAD(&port->list); ++ list_add_tail(&port->list, &pcie->ports); ++ ++ return 0; ++ ++remove_reset: ++ reset_control_put(port->pcie_rst); ++ return err; ++} ++ ++static int mt7621_pcie_parse_dt(struct mt7621_pcie *pcie) ++{ ++ struct device *dev = pcie->dev; ++ struct platform_device *pdev = to_platform_device(dev); ++ struct device_node *node = dev->of_node, *child; ++ int err; ++ ++ pcie->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(pcie->base)) ++ return PTR_ERR(pcie->base); ++ ++ for_each_available_child_of_node(node, child) { ++ int slot; ++ ++ err = of_pci_get_devfn(child); ++ if (err < 0) { ++ of_node_put(child); ++ dev_err(dev, "failed to parse devfn: %d\n", err); ++ return err; ++ } ++ ++ slot = PCI_SLOT(err); ++ ++ err = mt7621_pcie_parse_port(pcie, child, slot); ++ if (err) { ++ of_node_put(child); ++ return err; ++ } ++ } ++ ++ return 0; ++} ++ ++static int mt7621_pcie_init_port(struct mt7621_pcie_port *port) ++{ ++ struct mt7621_pcie *pcie = port->pcie; ++ struct device *dev = pcie->dev; ++ u32 slot = port->slot; ++ int err; ++ ++ err = phy_init(port->phy); ++ if (err) { ++ dev_err(dev, "failed to initialize port%d phy\n", slot); ++ return err; ++ } ++ ++ err = phy_power_on(port->phy); ++ if (err) { ++ dev_err(dev, "failed to power on port%d phy\n", slot); ++ phy_exit(port->phy); ++ return err; ++ } ++ ++ port->enabled = true; ++ ++ return 0; ++} ++ ++static void mt7621_pcie_reset_assert(struct mt7621_pcie *pcie) ++{ ++ struct mt7621_pcie_port *port; ++ ++ list_for_each_entry(port, &pcie->ports, list) { ++ /* PCIe RC reset assert */ ++ mt7621_control_assert(port); ++ ++ /* PCIe EP reset assert */ ++ mt7621_rst_gpio_pcie_assert(port); ++ } ++ ++ msleep(PERST_DELAY_MS); ++} ++ ++static void mt7621_pcie_reset_rc_deassert(struct mt7621_pcie *pcie) ++{ ++ struct mt7621_pcie_port *port; ++ ++ list_for_each_entry(port, &pcie->ports, list) ++ mt7621_control_deassert(port); ++} ++ ++static void mt7621_pcie_reset_ep_deassert(struct mt7621_pcie *pcie) ++{ ++ struct mt7621_pcie_port *port; ++ ++ list_for_each_entry(port, &pcie->ports, list) ++ mt7621_rst_gpio_pcie_deassert(port); ++ ++ msleep(PERST_DELAY_MS); ++} ++ ++static int mt7621_pcie_init_ports(struct mt7621_pcie *pcie) ++{ ++ struct device *dev = pcie->dev; ++ struct mt7621_pcie_port *port, *tmp; ++ u8 num_disabled = 0; ++ int err; ++ ++ mt7621_pcie_reset_assert(pcie); ++ mt7621_pcie_reset_rc_deassert(pcie); ++ ++ list_for_each_entry_safe(port, tmp, &pcie->ports, list) { ++ u32 slot = port->slot; ++ ++ if (slot == 1) { ++ port->enabled = true; ++ continue; ++ } ++ ++ err = mt7621_pcie_init_port(port); ++ if (err) { ++ dev_err(dev, "initializing port %d failed\n", slot); ++ list_del(&port->list); ++ } ++ } ++ ++ mt7621_pcie_reset_ep_deassert(pcie); ++ ++ tmp = NULL; ++ list_for_each_entry(port, &pcie->ports, list) { ++ u32 slot = port->slot; ++ ++ if (!mt7621_pcie_port_is_linkup(port)) { ++ dev_err(dev, "pcie%d no card, disable it (RST & CLK)\n", ++ slot); ++ mt7621_control_assert(port); ++ port->enabled = false; ++ num_disabled++; ++ ++ if (slot == 0) { ++ tmp = port; ++ continue; ++ } ++ ++ if (slot == 1 && tmp && !tmp->enabled) ++ phy_power_off(tmp->phy); ++ } ++ } ++ ++ return (num_disabled != PCIE_PORT_CNT) ? 0 : -ENODEV; ++} ++ ++static void mt7621_pcie_enable_port(struct mt7621_pcie_port *port) ++{ ++ struct mt7621_pcie *pcie = port->pcie; ++ u32 slot = port->slot; ++ u32 val; ++ ++ /* enable pcie interrupt */ ++ val = pcie_read(pcie, RALINK_PCI_PCIMSK_ADDR); ++ val |= PCIE_PORT_INT_EN(slot); ++ pcie_write(pcie, val, RALINK_PCI_PCIMSK_ADDR); ++ ++ /* map 2G DDR region */ ++ pcie_port_write(port, PCIE_BAR_MAP_MAX | PCIE_BAR_ENABLE, ++ PCI_BASE_ADDRESS_0); ++ ++ /* configure class code and revision ID */ ++ pcie_port_write(port, PCIE_CLASS_CODE | PCIE_REVISION_ID, ++ RALINK_PCI_CLASS); ++ ++ /* configure RC FTS number to 250 when it leaves L0s */ ++ val = read_config(pcie, slot, PCIE_FTS_NUM); ++ val &= ~PCIE_FTS_NUM_MASK; ++ val |= PCIE_FTS_NUM_L0(0x50); ++ write_config(pcie, slot, PCIE_FTS_NUM, val); ++} ++ ++static int mt7621_pcie_enable_ports(struct pci_host_bridge *host) ++{ ++ struct mt7621_pcie *pcie = pci_host_bridge_priv(host); ++ struct device *dev = pcie->dev; ++ struct mt7621_pcie_port *port; ++ struct resource_entry *entry; ++ int err; ++ ++ entry = resource_list_first_type(&host->windows, IORESOURCE_IO); ++ if (!entry) { ++ dev_err(dev, "cannot get io resource\n"); ++ return -EINVAL; ++ } ++ ++ /* Setup MEMWIN and IOWIN */ ++ pcie_write(pcie, 0xffffffff, RALINK_PCI_MEMBASE); ++ pcie_write(pcie, entry->res->start, RALINK_PCI_IOBASE); ++ ++ list_for_each_entry(port, &pcie->ports, list) { ++ if (port->enabled) { ++ err = clk_prepare_enable(port->clk); ++ if (err) { ++ dev_err(dev, "enabling clk pcie%d\n", ++ port->slot); ++ return err; ++ } ++ ++ mt7621_pcie_enable_port(port); ++ dev_info(dev, "PCIE%d enabled\n", port->slot); ++ } ++ } ++ ++ return 0; ++} ++ ++static int mt7621_pcie_register_host(struct pci_host_bridge *host) ++{ ++ struct mt7621_pcie *pcie = pci_host_bridge_priv(host); ++ ++ host->ops = &mt7621_pci_ops; ++ host->sysdata = pcie; ++ return pci_host_probe(host); ++} ++ ++static const struct soc_device_attribute mt7621_pci_quirks_match[] = { ++ { .soc_id = "mt7621", .revision = "E2" } ++}; ++ ++static int mt7621_pci_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ const struct soc_device_attribute *attr; ++ struct mt7621_pcie_port *port; ++ struct mt7621_pcie *pcie; ++ struct pci_host_bridge *bridge; ++ int err; ++ ++ if (!dev->of_node) ++ return -ENODEV; ++ ++ bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie)); ++ if (!bridge) ++ return -ENOMEM; ++ ++ pcie = pci_host_bridge_priv(bridge); ++ pcie->dev = dev; ++ platform_set_drvdata(pdev, pcie); ++ INIT_LIST_HEAD(&pcie->ports); ++ ++ attr = soc_device_match(mt7621_pci_quirks_match); ++ if (attr) ++ pcie->resets_inverted = true; ++ ++ err = mt7621_pcie_parse_dt(pcie); ++ if (err) { ++ dev_err(dev, "parsing DT failed\n"); ++ return err; ++ } ++ ++ err = mt7621_pcie_init_ports(pcie); ++ if (err) { ++ dev_err(dev, "nothing connected in virtual bridges\n"); ++ return 0; ++ } ++ ++ err = mt7621_pcie_enable_ports(bridge); ++ if (err) { ++ dev_err(dev, "error enabling pcie ports\n"); ++ goto remove_resets; ++ } ++ ++ err = setup_cm_memory_region(bridge); ++ if (err) { ++ dev_err(dev, "error setting up iocu mem regions\n"); ++ goto remove_resets; ++ } ++ ++ return mt7621_pcie_register_host(bridge); ++ ++remove_resets: ++ list_for_each_entry(port, &pcie->ports, list) ++ reset_control_put(port->pcie_rst); ++ ++ return err; ++} ++ ++static int mt7621_pci_remove(struct platform_device *pdev) ++{ ++ struct mt7621_pcie *pcie = platform_get_drvdata(pdev); ++ struct mt7621_pcie_port *port; ++ ++ list_for_each_entry(port, &pcie->ports, list) ++ reset_control_put(port->pcie_rst); ++ ++ return 0; ++} ++ ++static const struct of_device_id mt7621_pci_ids[] = { ++ { .compatible = "mediatek,mt7621-pci" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, mt7621_pci_ids); ++ ++static struct platform_driver mt7621_pci_driver = { ++ .probe = mt7621_pci_probe, ++ .remove = mt7621_pci_remove, ++ .driver = { ++ .name = "mt7621-pci", ++ .of_match_table = of_match_ptr(mt7621_pci_ids), ++ }, ++}; ++builtin_platform_driver(mt7621_pci_driver); |