]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
econet: en7528: add PCIe and WiFi support 21326/head
authorAhmed Naseef <naseefkm@gmail.com>
Mon, 9 Feb 2026 13:57:35 +0000 (17:57 +0400)
committerHauke Mehrtens <hauke@hauke-m.de>
Sun, 15 Feb 2026 00:12:52 +0000 (01:12 +0100)
Add PCIe controller and PHY support for EN7528 SoC. This includes
a new PCIe PHY driver, EN7528-specific startup in the MediaTek PCIe
controller, and a fix for bogus prefetch window reads on bridges
that do not implement the registers.

Enable WiFi for the DASAN H660GM-A board with MT7603 (2.4 GHz) and
MT7615/MT7663 (5 GHz).

Signed-off-by: Ahmed Naseef <naseefkm@gmail.com>
Link: https://github.com/openwrt/openwrt/pull/21326
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
target/linux/econet/dts/en7528.dtsi
target/linux/econet/dts/en7528_dasan_h660gm-a.dts
target/linux/econet/dts/en7528_generic.dts
target/linux/econet/en751221/config-6.12
target/linux/econet/en7528/config-6.12
target/linux/econet/en7528/target.mk
target/linux/econet/image/en7528.mk
target/linux/econet/patches-6.12/912-pcie-add-en7528-pcie-and-phy-support.patch [new file with mode: 0644]
target/linux/econet/patches-6.12/913-pcie-fix-bogus-prefetch-window.patch [new file with mode: 0644]

index 66d302a739c690efd85a23e625561a06fcef02db..1ccc298d211506d0c6cde28f019edb1a70e36e85 100644 (file)
                interrupts = <2>;
        };
 
+       pcie_phy0: pcie-phy@1faf2000 {
+               compatible = "econet,en7528-pcie-phy0";
+               reg = <0x1faf2000 0x1000>;
+               #phy-cells = <0>;
+       };
+
+       pcie_phy1: pcie-phy@1fac0000 {
+               compatible = "econet,en7528-pcie-phy1";
+               reg = <0x1fac0000 0x1000>;
+               #phy-cells = <0>;
+       };
+
        gpio0: gpio@1fbf0200 {
                compatible = "airoha,en7523-gpio";
                reg = <0x1fbf0204 0x4>,
                clock-frequency = <7372800>;
        };
 
+       pciecfg: pciecfg@1fb80000 {
+               compatible = "mediatek,generic-pciecfg", "syscon";
+               reg = <0x1fb80000 0x1000>;
+       };
+
+       pcie0: pcie@1fb81000 {
+               compatible = "econet,en7528-pcie";
+               device_type = "pci";
+               reg = <0x1fb81000 0x1000>;
+               reg-names = "port0";
+               linux,pci-domain = <0>;
+               #address-cells = <3>;
+               #size-cells = <2>;
+               interrupt-parent = <&gic>;
+               interrupts = <GIC_SHARED 23 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "pcie_irq";
+               clocks = <&scu EN7523_CLK_PCIE>;
+               clock-names = "sys_ck0";
+               phys = <&pcie_phy0>;
+               phy-names = "pcie-phy0";
+               bus-range = <0x00 0xff>;
+               ranges = <0x01000000 0 0x00000000 0x1f600000 0 0x00010000>,
+                        <0x82000000 0 0x20000000 0x20000000 0 0x08000000>;
+               status = "disabled";
+
+               #interrupt-cells = <1>;
+               interrupt-map-mask = <0 0 0 7>;
+               interrupt-map = <0 0 0 1 &pcie_intc0 0>,
+                               <0 0 0 2 &pcie_intc0 1>,
+                               <0 0 0 3 &pcie_intc0 2>,
+                               <0 0 0 4 &pcie_intc0 3>;
+
+               pcie_intc0: interrupt-controller {
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <1>;
+               };
+
+               slot0: pcie@0,0 {
+                       reg = <0x0000 0 0 0 0>;
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       ranges;
+               };
+       };
+
+       pcie1: pcie@1fb83000 {
+               compatible = "econet,en7528-pcie";
+               device_type = "pci";
+               reg = <0x1fb83000 0x1000>;
+               reg-names = "port1";
+               linux,pci-domain = <1>;
+               #address-cells = <3>;
+               #size-cells = <2>;
+               interrupt-parent = <&gic>;
+               interrupts = <GIC_SHARED 24 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "pcie_irq";
+               clocks = <&scu EN7523_CLK_PCIE>;
+               clock-names = "sys_ck1";
+               phys = <&pcie_phy1>;
+               phy-names = "pcie-phy1";
+               bus-range = <0x00 0xff>;
+               ranges = <0x01000000 0 0x00000000 0x1f610000 0 0x00010000>,
+                        <0x82000000 0 0x28000000 0x28000000 0 0x08000000>;
+               status = "disabled";
+
+               #interrupt-cells = <1>;
+               interrupt-map-mask = <0 0 0 7>;
+               interrupt-map = <0 0 0 1 &pcie_intc1 0>,
+                               <0 0 0 2 &pcie_intc1 1>,
+                               <0 0 0 3 &pcie_intc1 2>,
+                               <0 0 0 4 &pcie_intc1 3>;
+
+               pcie_intc1: interrupt-controller {
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <1>;
+               };
+
+               slot1: pcie@1,0 {
+                       reg = <0x0800 0 0 0 0>;
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       ranges;
+               };
+       };
+
        ethernet: ethernet@1fb50000 {
                compatible = "econet,en7528-eth";
                reg = <0x1fb50000 0x10000>;
index 69fd912377f2ec93f962e6c9bb0a8cf9e14407fa..f14c1e29db6e78c05ba06efa903a9815361045d3 100644 (file)
        };
 };
 
+&pcie0 {
+       status = "okay";
+};
+
+&pcie1 {
+       status = "okay";
+};
+
+&slot0 {
+       status = "okay";
+
+       wifi@0,0 {
+               compatible = "mediatek,mt76";
+               reg = <0x0000 0 0 0 0>;
+               nvmem-cells = <&macaddr_dzs 8>, <&eeprom_reservearea_40000>;
+               nvmem-cell-names = "mac-address", "eeprom";
+               ieee80211-freq-limit = <2400000 2500000>;
+       };
+};
+
+&slot1 {
+       status = "okay";
+
+       wifi@0,0 {
+               compatible = "mediatek,mt76";
+               reg = <0x0000 0 0 0 0>;
+               nvmem-cells = <&macaddr_dzs 9>, <&eeprom_reservearea_1c0000>;
+               nvmem-cell-names = "mac-address", "eeprom";
+               ieee80211-freq-limit = <5000000 6000000>;
+       };
+};
+
 &gmac0 {
        status = "okay";
        nvmem-cells = <&macaddr_dzs 7>;
                partition@ddc0000 {
                        label = "reservearea";
                        reg = <0xddc0000 0x240000>;
+                       nvmem-layout {
+                               compatible = "fixed-layout";
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+
+                               eeprom_reservearea_40000: eeprom@40000 {
+                                       reg = <0x40000 0x400>;
+                               };
+
+                               eeprom_reservearea_1c0000: eeprom@1c0000 {
+                                       reg = <0x1c0000 0x1000>;
+                               };
+                       };
                };
        };
 };
index d4d25266e3481c625732924287b045a43c2e5071..086d0d36b4eb946c2e858c5110e879f6992c8bb9 100644 (file)
        };
 };
 
+&pcie0 {
+       status = "okay";
+};
+
+&pcie1 {
+       status = "okay";
+};
+
 &gmac0 {
        status = "okay";
 };
index 57f4208e2823adc03c1155ced1fd486bf7681878..dd80756777c691ab79969e8def07b0e968f1a9e5 100644 (file)
@@ -139,6 +139,7 @@ CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
 CONFIG_PCI_DRIVERS_LEGACY=y
 CONFIG_PERF_USE_VMALLOC=y
 CONFIG_PGTABLE_LEVELS=2
+# CONFIG_PHY_EN7528_PCIE is not set
 CONFIG_PTP_1588_CLOCK_OPTIONAL=y
 CONFIG_QUEUED_RWLOCKS=y
 CONFIG_QUEUED_SPINLOCKS=y
index 4dc701fe7708d0a04bdac1f8445686215d04fecf..49bcddb67c5b3b8ab14bb4199f41b779c4ccb16e 100644 (file)
@@ -4,6 +4,7 @@ CONFIG_ARCH_KEEP_MEMBLOCK=y
 CONFIG_ARCH_MMAP_RND_BITS_MAX=15
 CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_BLK_MQ_PCI=y
 CONFIG_BOARD_SCACHE=y
 CONFIG_CLKSRC_MMIO=y
 CONFIG_CLONE_BACKWARDS=y
@@ -73,7 +74,9 @@ CONFIG_GENERIC_LIB_ASHRDI3=y
 CONFIG_GENERIC_LIB_CMPDI2=y
 CONFIG_GENERIC_LIB_LSHRDI3=y
 CONFIG_GENERIC_LIB_UCMPDI2=y
+CONFIG_GENERIC_MSI_IRQ=y
 CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_PHY=y
 CONFIG_GENERIC_SCHED_CLOCK=y
 CONFIG_GENERIC_SMP_IDLE_THREAD=y
 CONFIG_GENERIC_TIME_VSYSCALL=y
@@ -100,6 +103,7 @@ CONFIG_LIBFDT=y
 CONFIG_LOCK_DEBUGGING_SUPPORT=y
 CONFIG_LZO_COMPRESS=y
 CONFIG_LZO_DECOMPRESS=y
+CONFIG_MFD_SYSCON=y
 CONFIG_MIGRATION=y
 CONFIG_MIPS=y
 CONFIG_MIPS_ASID_BITS=8
@@ -137,7 +141,6 @@ CONFIG_NET_EGRESS=y
 CONFIG_NET_FLOW_LIMIT=y
 CONFIG_NET_INGRESS=y
 CONFIG_NET_XGRESS=y
-CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
 CONFIG_NR_CPUS=4
 CONFIG_NVMEM=y
 CONFIG_NVMEM_LAYOUTS=y
@@ -153,9 +156,16 @@ CONFIG_PADATA=y
 CONFIG_PAGE_POOL=y
 CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
 CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
-CONFIG_PCI_DRIVERS_LEGACY=y
+CONFIG_PCI=y
+CONFIG_PCIE_MEDIATEK=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_DOMAINS_GENERIC=y
+CONFIG_PCI_DRIVERS_GENERIC=y
+CONFIG_PCI_MSI=y
+CONFIG_PCI_MSI_ARCH_FALLBACKS=y
 CONFIG_PERF_USE_VMALLOC=y
 CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHY_EN7528_PCIE=y
 CONFIG_PTP_1588_CLOCK_OPTIONAL=y
 CONFIG_QUEUED_RWLOCKS=y
 CONFIG_QUEUED_SPINLOCKS=y
index e5e29d915d23e77b26813138faf5a242f8bb1177..0cd6158b812fa4eb2d4d84409fe3296703d63312 100644 (file)
@@ -6,7 +6,7 @@ BOARDNAME:=EN7528 based boards
 CPU_TYPE:=24kc
 KERNELNAME:=vmlinuz.bin
 
-DEFAULT_PACKAGES += kmod-leds-gpio kmod-gpio-button-hotplug
+DEFAULT_PACKAGES += kmod-leds-gpio kmod-gpio-button-hotplug wpad-basic-mbedtls
 
 define Target/Description
        Build firmware images for EcoNet EN7528 based boards.
index d718bfdb620f7427dfd82256837e14d45cc91999..d608a28bc5204ddfdcfdb90e163673b11f1bed48 100644 (file)
@@ -11,6 +11,7 @@ define Device/dasan_h660gm-a
   DEVICE_VENDOR := DASAN
   DEVICE_MODEL := H660GM-A
   DEVICE_DTS := en7528_dasan_h660gm-a
+  DEVICE_PACKAGES := kmod-mt7603 kmod-mt7615e kmod-mt7663-firmware-ap
   TRX_MODEL := Dewberry
   IMAGES := tclinux.trx
   IMAGE/tclinux.trx := append-kernel | lzma | tclinux-trx
diff --git a/target/linux/econet/patches-6.12/912-pcie-add-en7528-pcie-and-phy-support.patch b/target/linux/econet/patches-6.12/912-pcie-add-en7528-pcie-and-phy-support.patch
new file mode 100644 (file)
index 0000000..e98bda7
--- /dev/null
@@ -0,0 +1,327 @@
+--- a/drivers/pci/controller/Kconfig
++++ b/drivers/pci/controller/Kconfig
+@@ -187,7 +187,7 @@ config PCI_MVEBU
+ config PCIE_MEDIATEK
+       tristate "MediaTek PCIe controller"
+-      depends on ARCH_AIROHA || ARCH_MEDIATEK || COMPILE_TEST
++      depends on ARCH_AIROHA || ARCH_MEDIATEK || ECONET || COMPILE_TEST
+       depends on OF
+       depends on PCI_MSI
+       help
+--- a/arch/mips/econet/Kconfig
++++ b/arch/mips/econet/Kconfig
+@@ -28,9 +28,11 @@ choice
+               bool "EN7528 family"
+               select COMMON_CLK
+               select CPU_LITTLE_ENDIAN
++              select HAVE_PCI
+               select IRQ_MIPS_CPU
+               select MIPS_CPU_SCACHE
+               select MIPS_GIC
++              select PCI_DRIVERS_GENERIC
+               select SMP
+               select SMP_UP
+               select SYS_SUPPORTS_HIGHMEM
+--- a/drivers/pci/controller/pcie-mediatek.c
++++ b/drivers/pci/controller/pcie-mediatek.c
+@@ -76,6 +76,7 @@
+ #define PCIE_CONF_VEND_ID     0x100
+ #define PCIE_CONF_DEVICE_ID   0x102
++#define PCIE_CONF_REV_CLASS   0x104
+ #define PCIE_CONF_CLASS_ID    0x106
+ #define PCIE_INT_MASK         0x420
+@@ -88,6 +89,11 @@
+ #define MSI_MASK              BIT(23)
+ #define MTK_MSI_IRQS_NUM      32
++#define EN7528_HOST_MODE      0x00804201
++#define EN7528_LINKUP_REG     0x50
++#define EN7528_RC0_LINKUP             BIT(1)
++#define EN7528_RC1_LINKUP             BIT(2)
++
+ #define PCIE_AHB_TRANS_BASE0_L        0x438
+ #define PCIE_AHB_TRANS_BASE0_H        0x43c
+ #define AHB2PCIE_SIZE(x)      ((x) & GENMASK(4, 0))
+@@ -748,6 +754,86 @@ static int mtk_pcie_startup_port_v2(stru
+       return 0;
+ }
++static int mtk_pcie_startup_port_en7528(struct mtk_pcie_port *port)
++{
++      struct mtk_pcie *pcie = port->pcie;
++      struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
++      struct resource *mem = NULL;
++      struct resource_entry *entry;
++      u32 val, link_mask;
++      int err;
++
++      entry = resource_list_first_type(&host->windows, IORESOURCE_MEM);
++      if (entry)
++              mem = entry->res;
++      if (!mem)
++              return -EINVAL;
++
++      if (!pcie->cfg) {
++              dev_err(pcie->dev, "EN7528: pciecfg syscon not available\n");
++              return -EINVAL;
++      }
++
++      /* Assert all reset signals */
++      writel(0, port->base + PCIE_RST_CTRL);
++
++      /*
++       * Enable PCIe link down reset, if link status changed from link up to
++       * link down, this will reset MAC control registers and configuration
++       * space.
++       */
++      writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL);
++
++      /*
++       * Described in PCIe CEM specification sections 2.2 (PERST# Signal) and
++       * 2.2.1 (Initial Power-Up (G3 to S0)). The deassertion of PERST#
++       * should be delayed 100ms (TPVPERL) for the power and clock to become
++       * stable.
++       */
++      msleep(100);
++
++      /* De-assert PHY, PE, PIPE, MAC and configuration reset */
++      val = readl(port->base + PCIE_RST_CTRL);
++      val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB |
++             PCIE_MAC_SRSTB | PCIE_CRSTB;
++      writel(val, port->base + PCIE_RST_CTRL);
++
++      writel(PCIE_CLASS_CODE | PCIE_REVISION_ID,
++             port->base + PCIE_CONF_REV_CLASS);
++      writel(EN7528_HOST_MODE, port->base);
++
++      link_mask = (port->slot == 0) ? EN7528_RC0_LINKUP : EN7528_RC1_LINKUP;
++
++      /* 100ms timeout value should be enough for Gen1/2 training */
++      err = regmap_read_poll_timeout(pcie->cfg, EN7528_LINKUP_REG, val,
++                                     !!(val & link_mask), 20,
++                                     100 * USEC_PER_MSEC);
++      if (err) {
++              dev_err(pcie->dev, "EN7528: port%d link timeout\n", port->slot);
++              return -ETIMEDOUT;
++      }
++
++      /* Set INTx mask */
++      val = readl(port->base + PCIE_INT_MASK);
++      val &= ~INTX_MASK;
++      writel(val, port->base + PCIE_INT_MASK);
++
++      if (IS_ENABLED(CONFIG_PCI_MSI))
++              mtk_pcie_enable_msi(port);
++
++      /* Set AHB to PCIe translation windows */
++      val = lower_32_bits(mem->start) |
++            AHB2PCIE_SIZE(fls(resource_size(mem)));
++      writel(val, port->base + PCIE_AHB_TRANS_BASE0_L);
++
++      val = upper_32_bits(mem->start);
++      writel(val, port->base + PCIE_AHB_TRANS_BASE0_H);
++
++      writel(WIN_ENABLE, port->base + PCIE_AXI_WINDOW0);
++
++      return 0;
++}
++
+ static void __iomem *mtk_pcie_map_bus(struct pci_bus *bus,
+                                     unsigned int devfn, int where)
+ {
+@@ -1114,6 +1200,20 @@ static int mtk_pcie_probe(struct platfor
+       if (err)
+               goto put_resources;
++      /* Retrain Gen1 links to reach Gen2 where supported */
++      if (pcie->soc->startup == mtk_pcie_startup_port_en7528) {
++              struct pci_bus *bus = host->bus;
++              struct pci_dev *rc = NULL;
++
++              while ((rc = pci_get_class(PCI_CLASS_BRIDGE_PCI << 8, rc))) {
++                      if (rc->bus != bus)
++                              continue;
++                      if (!pcie_retrain_link(rc, true))
++                              dev_info(dev, "port%d link retrained\n",
++                                       PCI_SLOT(rc->devfn));
++              }
++      }
++
+       return 0;
+ put_resources:
+@@ -1223,12 +1323,19 @@ static const struct mtk_pcie_soc mtk_pci
+       .setup_irq = mtk_pcie_setup_irq,
+ };
++static const struct mtk_pcie_soc mtk_pcie_soc_en7528 = {
++      .ops = &mtk_pcie_ops_v2,
++      .startup = mtk_pcie_startup_port_en7528,
++      .setup_irq = mtk_pcie_setup_irq,
++};
++
+ static const struct of_device_id mtk_pcie_ids[] = {
+       { .compatible = "mediatek,mt2701-pcie", .data = &mtk_pcie_soc_v1 },
+       { .compatible = "mediatek,mt7623-pcie", .data = &mtk_pcie_soc_v1 },
+       { .compatible = "mediatek,mt2712-pcie", .data = &mtk_pcie_soc_mt2712 },
+       { .compatible = "mediatek,mt7622-pcie", .data = &mtk_pcie_soc_mt7622 },
+       { .compatible = "mediatek,mt7629-pcie", .data = &mtk_pcie_soc_mt7629 },
++      { .compatible = "econet,en7528-pcie", .data = &mtk_pcie_soc_en7528 },
+       {},
+ };
+ MODULE_DEVICE_TABLE(of, mtk_pcie_ids);
+--- a/drivers/phy/Kconfig
++++ b/drivers/phy/Kconfig
+@@ -82,6 +82,17 @@ config PHY_AIROHA_PCIE
+         This driver create the basic PHY instance and provides initialize
+         callback for PCIe GEN3 port.
++config PHY_EN7528_PCIE
++      tristate "EcoNet EN7528 PCIe PHY Driver"
++      depends on ECONET || COMPILE_TEST
++      depends on OF
++      select GENERIC_PHY
++      select REGMAP_MMIO
++      help
++        Say Y here to add support for EcoNet EN7528 PCIe PHY driver.
++        This driver provides PHY initialization for the two PCIe ports
++        on EN7528 SoC.
++
+ source "drivers/phy/allwinner/Kconfig"
+ source "drivers/phy/amlogic/Kconfig"
+ source "drivers/phy/broadcom/Kconfig"
+--- a/drivers/phy/Makefile
++++ b/drivers/phy/Makefile
+@@ -11,6 +11,7 @@ obj-$(CONFIG_PHY_XGENE)                      += phy-xgene.o
+ obj-$(CONFIG_PHY_PISTACHIO_USB)               += phy-pistachio-usb.o
+ obj-$(CONFIG_USB_LGM_PHY)             += phy-lgm-usb.o
+ obj-$(CONFIG_PHY_AIROHA_PCIE)         += phy-airoha-pcie.o
++obj-$(CONFIG_PHY_EN7528_PCIE)         += phy-en7528-pcie.o
+ obj-y                                 += allwinner/   \
+                                          amlogic/     \
+                                          broadcom/    \
+--- /dev/null
++++ b/drivers/phy/phy-en7528-pcie.c
+@@ -0,0 +1,119 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright (C) 2026 Ahmed Naseef <naseefkm@gmail.com>
++ *
++ * EcoNet EN7528 PCIe PHY Driver
++ */
++
++#include <linux/bitops.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/phy/phy.h>
++#include <linux/platform_device.h>
++#include <linux/regmap.h>
++
++struct en7528_pcie_phy_data {
++      u32 reg;
++      u32 mask;
++      u32 val;
++      u32 max_reg;
++};
++
++struct en7528_pcie_phy {
++      struct regmap *regmap;
++      const struct en7528_pcie_phy_data *data;
++};
++
++/* Port 0 PHY: set LCDDS_CLK_PH_INV for PLL operation */
++static const struct en7528_pcie_phy_data en7528_phy_port0 = {
++      .reg = 0x4a0,
++      .mask = BIT(5),
++      .val = BIT(5),
++      .max_reg = 0x4a0,
++};
++
++/* Port 1 PHY: Rx impedance tuning, target R -5 Ohm */
++static const struct en7528_pcie_phy_data en7528_phy_port1 = {
++      .reg = 0xb2c,
++      .mask = GENMASK(13, 12),
++      .val = BIT(12),
++      .max_reg = 0xb2c,
++};
++
++static int en7528_pcie_phy_init(struct phy *phy)
++{
++      struct en7528_pcie_phy *ephy = phy_get_drvdata(phy);
++      const struct en7528_pcie_phy_data *data = ephy->data;
++
++      return regmap_update_bits(ephy->regmap, data->reg,
++                                data->mask, data->val);
++}
++
++static const struct phy_ops en7528_pcie_phy_ops = {
++      .init   = en7528_pcie_phy_init,
++      .owner  = THIS_MODULE,
++};
++
++static int en7528_pcie_phy_probe(struct platform_device *pdev)
++{
++      struct device *dev = &pdev->dev;
++      const struct en7528_pcie_phy_data *data;
++      struct regmap_config regmap_config = {
++              .reg_bits = 32,
++              .val_bits = 32,
++              .reg_stride = 4,
++      };
++      struct phy_provider *provider;
++      struct en7528_pcie_phy *ephy;
++      void __iomem *base;
++      struct phy *phy;
++
++      data = of_device_get_match_data(dev);
++      if (!data)
++              return -EINVAL;
++
++      ephy = devm_kzalloc(dev, sizeof(*ephy), GFP_KERNEL);
++      if (!ephy)
++              return -ENOMEM;
++
++      ephy->data = data;
++
++      base = devm_platform_ioremap_resource(pdev, 0);
++      if (IS_ERR(base))
++              return PTR_ERR(base);
++
++      regmap_config.max_register = data->max_reg;
++      ephy->regmap = devm_regmap_init_mmio(dev, base, &regmap_config);
++      if (IS_ERR(ephy->regmap))
++              return PTR_ERR(ephy->regmap);
++
++      phy = devm_phy_create(dev, dev->of_node, &en7528_pcie_phy_ops);
++      if (IS_ERR(phy))
++              return PTR_ERR(phy);
++
++      phy_set_drvdata(phy, ephy);
++
++      provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
++
++      return PTR_ERR_OR_ZERO(provider);
++}
++
++static const struct of_device_id en7528_pcie_phy_ids[] = {
++      { .compatible = "econet,en7528-pcie-phy0", .data = &en7528_phy_port0 },
++      { .compatible = "econet,en7528-pcie-phy1", .data = &en7528_phy_port1 },
++      { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, en7528_pcie_phy_ids);
++
++static struct platform_driver en7528_pcie_phy_driver = {
++      .probe = en7528_pcie_phy_probe,
++      .driver = {
++              .name = "en7528-pcie-phy",
++              .of_match_table = en7528_pcie_phy_ids,
++      },
++};
++module_platform_driver(en7528_pcie_phy_driver);
++
++MODULE_AUTHOR("Ahmed Naseef <naseefkm@gmail.com>");
++MODULE_DESCRIPTION("EcoNet EN7528 PCIe PHY driver");
++MODULE_LICENSE("GPL v2");
diff --git a/target/linux/econet/patches-6.12/913-pcie-fix-bogus-prefetch-window.patch b/target/linux/econet/patches-6.12/913-pcie-fix-bogus-prefetch-window.patch
new file mode 100644 (file)
index 0000000..a7ee7b7
--- /dev/null
@@ -0,0 +1,38 @@
+Subject: [PATCH] PCI: Skip bridge window reads when window is not supported
+
+pci_read_bridge_io() and pci_read_bridge_mmio_pref() read bridge window
+registers unconditionally. If the registers are hardwired to zero
+(not implemented), both base and limit will be 0. Since (0 <= 0) is
+true, a bogus window [mem 0x00000000-0x000fffff] or [io 0x0000-0x0fff]
+gets created.
+
+pci_read_bridge_windows() already detects unsupported windows by
+testing register writability and sets io_window/pref_window flags
+accordingly. Check these flags at the start of pci_read_bridge_io()
+and pci_read_bridge_mmio_pref() to skip reading registers when the
+window is not supported.
+
+Suggested-by: Bjorn Helgaas <helgaas@kernel.org>
+Signed-off-by: Ahmed Naseef <naseefkm@gmail.com>
+--- a/drivers/pci/probe.c
++++ b/drivers/pci/probe.c
+@@ -351,6 +351,9 @@ static void pci_read_bridge_io(struct pc
+       unsigned long io_mask, io_granularity, base, limit;
+       struct pci_bus_region region;
++      if (!dev->io_window)
++              return;
++
+       io_mask = PCI_IO_RANGE_MASK;
+       io_granularity = 0x1000;
+       if (dev->io_window_1k) {
+@@ -412,6 +415,9 @@ static void pci_read_bridge_mmio_pref(st
+       pci_bus_addr_t base, limit;
+       struct pci_bus_region region;
++      if (!dev->pref_window)
++              return;
++
+       pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
+       pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo);
+       base64 = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16;