From: Ahmed Naseef Date: Mon, 9 Feb 2026 13:57:35 +0000 (+0400) Subject: econet: en7528: add PCIe and WiFi support X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=be24a13ad5b2948e01cead1c93d45582d704f40c;p=thirdparty%2Fopenwrt.git econet: en7528: add PCIe and WiFi support 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 Link: https://github.com/openwrt/openwrt/pull/21326 Signed-off-by: Hauke Mehrtens --- diff --git a/target/linux/econet/dts/en7528.dtsi b/target/linux/econet/dts/en7528.dtsi index 66d302a739c..1ccc298d211 100644 --- a/target/linux/econet/dts/en7528.dtsi +++ b/target/linux/econet/dts/en7528.dtsi @@ -57,6 +57,18 @@ 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>, @@ -131,6 +143,93 @@ 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 = ; + 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 = ; + 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>; diff --git a/target/linux/econet/dts/en7528_dasan_h660gm-a.dts b/target/linux/econet/dts/en7528_dasan_h660gm-a.dts index 69fd912377f..f14c1e29db6 100644 --- a/target/linux/econet/dts/en7528_dasan_h660gm-a.dts +++ b/target/linux/econet/dts/en7528_dasan_h660gm-a.dts @@ -143,6 +143,38 @@ }; }; +&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>; @@ -216,6 +248,19 @@ 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>; + }; + }; }; }; }; diff --git a/target/linux/econet/dts/en7528_generic.dts b/target/linux/econet/dts/en7528_generic.dts index d4d25266e34..086d0d36b4e 100644 --- a/target/linux/econet/dts/en7528_generic.dts +++ b/target/linux/econet/dts/en7528_generic.dts @@ -24,6 +24,14 @@ }; }; +&pcie0 { + status = "okay"; +}; + +&pcie1 { + status = "okay"; +}; + &gmac0 { status = "okay"; }; diff --git a/target/linux/econet/en751221/config-6.12 b/target/linux/econet/en751221/config-6.12 index 57f4208e282..dd80756777c 100644 --- a/target/linux/econet/en751221/config-6.12 +++ b/target/linux/econet/en751221/config-6.12 @@ -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 diff --git a/target/linux/econet/en7528/config-6.12 b/target/linux/econet/en7528/config-6.12 index 4dc701fe770..49bcddb67c5 100644 --- a/target/linux/econet/en7528/config-6.12 +++ b/target/linux/econet/en7528/config-6.12 @@ -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 diff --git a/target/linux/econet/en7528/target.mk b/target/linux/econet/en7528/target.mk index e5e29d915d2..0cd6158b812 100644 --- a/target/linux/econet/en7528/target.mk +++ b/target/linux/econet/en7528/target.mk @@ -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. diff --git a/target/linux/econet/image/en7528.mk b/target/linux/econet/image/en7528.mk index d718bfdb620..d608a28bc52 100644 --- a/target/linux/econet/image/en7528.mk +++ b/target/linux/econet/image/en7528.mk @@ -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 index 00000000000..e98bda7d619 --- /dev/null +++ b/target/linux/econet/patches-6.12/912-pcie-add-en7528-pcie-and-phy-support.patch @@ -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 ++ * ++ * EcoNet EN7528 PCIe PHY Driver ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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, ®map_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 "); ++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 index 00000000000..a7ee7b7b6c7 --- /dev/null +++ b/target/linux/econet/patches-6.12/913-pcie-fix-bogus-prefetch-window.patch @@ -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 +Signed-off-by: Ahmed Naseef +--- 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;