// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
#include <dt-bindings/reset/econet,en751221-scu.h>
+#include <dt-bindings/clock/econet,en751221-scu.h>
/dts-v1/;
reg = <0x1fa20000 0x388>;
};
+ pcie_phy1: pcie-phy@1fac0000 {
+ compatible = "econet,en751221-pcie-phy1";
+ reg = <0x1fac0000 0x1000>;
+ #phy-cells = <0>;
+ };
+
+ pcie_phy0: pcie-phy@1faf2000 {
+ compatible = "econet,en751221-pcie-phy0";
+ reg = <0x1faf2000 0x1000>;
+ #phy-cells = <0>;
+ };
+
intc: interrupt-controller@1fb40000 {
compatible = "econet,en751221-intc";
reg = <0x1fb40000 0x100>;
};
};
+ 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 = <&intc>;
+ interrupts = <23>;
+ interrupt-names = "pcie_irq";
+ clocks = <&scuclk EN751221_CLK_PCIE>;
+ clock-names = "sys_ck0";
+ phys = <&pcie_phy0>;
+ phy-names = "pcie-phy0";
+ bus-range = <0x00 0xff>;
+ ranges = <0x01000000 0 0x00000000 0x1f600000 0 0x00008000>,
+ <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>;
+ device_type = "pci";
+ #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 = <&intc>;
+ interrupts = <24>;
+ interrupt-names = "pcie_irq";
+ clocks = <&scuclk EN751221_CLK_PCIE>;
+ clock-names = "sys_ck1";
+ phys = <&pcie_phy1>;
+ phy-names = "pcie-phy1";
+ bus-range = <0x00 0xff>;
+ ranges = <0x81000000 0 0x00000000 0x1f608000 0 0x00008000>,
+ <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;
+ };
+ };
+
usb: usb@1fb90000 {
compatible = "mediatek,mt8173-xhci", "mediatek,mtk-xhci";
reg = <0x1fb90000 0x4000>,
nvmem-cells = <&macaddr_bootloader_ff48 0>;
nvmem-cell-names = "mac-address";
};
+
+&pcie0 {
+ status = "okay";
+};
+&slot0 {
+ wifi@0,0 {
+ /* MT7612E */
+ compatible = "mediatek,mt76";
+ reg = <0x0000 0 0 0 0>;
+ nvmem-cells = <&eeprom_reserve_180040>, <&macaddr_bootloader_ff48 1>;
+ nvmem-cell-names = "eeprom", "mac-address";
+ };
+};
+&pcie1 {
+ status = "okay";
+};
+&slot1 {
+ wifi@0,0 {
+ /* MT7592 */
+ compatible = "mediatek,mt76";
+ reg = <0x0000 0 0 0 0>;
+ nvmem-cells = <&eeprom_reserve_140000>, <&macaddr_bootloader_ff48 2>;
+ nvmem-cell-names = "eeprom", "mac-address";
+ };
+};
nvmem-cells = <&macaddr_misc_8f100 0>;
nvmem-cell-names = "mac-address";
};
+
+&pcie0 {
+ status = "okay";
+};
+&slot0 {
+ wifi@0,0 {
+ /* MT7592 */
+ compatible = "mediatek,mt76";
+ reg = <0x0000 0 0 0 0>;
+ nvmem-cells = <&eeprom_misc_80000>, <&macaddr_misc_8f100 1>;
+ nvmem-cell-names = "eeprom", "mac-address";
+ };
+};
+&pcie1 {
+ status = "okay";
+};
+&slot1 {
+ wifi@0,0 {
+ /* MT7613BE */
+ compatible = "mediatek,mt76";
+ reg = <0x0000 0 0 0 0>;
+ nvmem-cells = <&eeprom_misc_a0000>, <&macaddr_misc_8f100 2>;
+ nvmem-cell-names = "eeprom", "mac-address";
+ };
+};
partition@7540000 {
label = "reservearea";
reg = <0x007540000 0x000080000>;
+ nvmem-layout {
+ compatible = "fixed-layout";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ eeprom_reserve_60000: eeprom@60000 {
+ /* MT7592 */
+ /* This overlaps the MT7612E EEPROM, but MT7603E demands
+ * 1024 bytes of EEPROM even though only 512 bytes are used.
+ */
+ reg = <0x60000 0x400>;
+ };
+
+ eeprom_reserve_60200: eeprom@60200 {
+ /* MT7612E */
+ reg = <0x60200 0x200>;
+ };
+ };
};
};
};
+
+&pcie0 {
+ status = "okay";
+};
+&slot0 {
+ wifi@0,0 {
+ /* MT7592 */
+ compatible = "mediatek,mt76";
+ reg = <0x0000 0 0 0 0>;
+ nvmem-cells = <&eeprom_reserve_60000>;
+ nvmem-cell-names = "eeprom";
+ };
+};
+&pcie1 {
+ status = "okay";
+};
+&slot1 {
+ wifi@0,0 {
+ /* MT7612E */
+ compatible = "mediatek,mt76";
+ reg = <0x0000 0 0 0 0>;
+ nvmem-cells = <&eeprom_reserve_60200>;
+ nvmem-cell-names = "eeprom";
+ };
+};
CONFIG_ARCH_KEEP_MEMBLOCK=y
CONFIG_ARCH_MMAP_RND_BITS_MAX=15
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15
+CONFIG_BLK_MQ_PCI=y
CONFIG_CLKSRC_MMIO=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_COMMON_CLK=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
CONFIG_INITRAMFS_SOURCE=""
CONFIG_IRQCHIP=y
CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_IRQ_MIPS_CPU=y
CONFIG_IRQ_WORK=y
CONFIG_NET_FLOW_LIMIT=y
CONFIG_NET_INGRESS=y
CONFIG_NET_XGRESS=y
-CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
CONFIG_NR_CPUS=2
CONFIG_NVMEM=y
CONFIG_NVMEM_LAYOUTS=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_PCIEAER=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIE_MEDIATEK=y
+CONFIG_PCI_DISABLE_COMMON_QUIRKS=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 is not set
+CONFIG_PHY_EN7528_PCIE=y
CONFIG_PTP_1588_CLOCK_OPTIONAL=y
CONFIG_QUEUED_RWLOCKS=y
CONFIG_QUEUED_SPINLOCKS=y
CONFIG_RANDSTRUCT_NONE=y
+CONFIG_RAS=y
CONFIG_RATIONAL=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_MMIO=y
CONFIG_RESET_CONTROLLER=y
CONFIG_RFS_ACCEL=y
CONFIG_RPS=y
DEVICE_DTS := en751221_smartfiber_xp8421-b
IMAGES := tclinux.trx
IMAGE/tclinux.trx := append-kernel | lzma | tclinux-trx
- DEVICE_PACKAGES := kmod-usb3
+ DEVICE_PACKAGES := kmod-usb3 kmod-mt7603 kmod-mt76x2
endef
TARGET_DEVICES += smartfiber_xp8421-b
TPLINK_HWREVADD := 0x0
TPLINK_HVERSION := 3
DEVICE_DTS := en751221_tplink_archer-vr1200v-v2
+ DEVICE_PACKAGES := kmod-mt7603 kmod-mt7615e kmod-mt7663-firmware-ap
IMAGES := sysupgrade.bin
IMAGE/sysupgrade.bin := append-kernel | lzma | pad-to 4193792 | append-rootfs | \
tplink-v2-header -R 0x400000
DEVICE_DTS := en751221_zyxel_pmg5617ga
IMAGES := tclinux.trx
IMAGE/tclinux.trx := append-kernel | lzma | tclinux-trx
- DEVICE_PACKAGES := kmod-usb3
+ DEVICE_PACKAGES := kmod-usb3 kmod-mt7603 kmod-mt76x2
endef
TARGET_DEVICES += zyxel_pmg5617ga
help
--- a/arch/mips/econet/Kconfig
+++ b/arch/mips/econet/Kconfig
-@@ -28,9 +28,11 @@ choice
+@@ -14,7 +14,9 @@ choice
+ select COMMON_CLK
+ select CPU_BIG_ENDIAN
+ select ECONET_EN751221_INTC
++ select HAVE_PCI
+ select IRQ_MIPS_CPU
++ select PCI_DRIVERS_GENERIC
+ select SMP
+ select SMP_UP
+ select SYS_SUPPORTS_SMP
+@@ -28,9 +30,11 @@ choice
bool "EN7528 family"
select COMMON_CLK
select CPU_LITTLE_ENDIAN
broadcom/ \
--- /dev/null
+++ b/drivers/phy/phy-en7528-pcie.c
-@@ -0,0 +1,119 @@
+@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2026 Ahmed Naseef <naseefkm@gmail.com>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
-+struct en7528_pcie_phy_data {
++struct en7528_pcie_phy_op {
+ u32 reg;
+ u32 mask;
+ u32 val;
-+ u32 max_reg;
+};
+
+struct en7528_pcie_phy {
+ struct regmap *regmap;
-+ const struct en7528_pcie_phy_data *data;
++ const struct en7528_pcie_phy_op *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,
++static const struct en7528_pcie_phy_op en7528_phy_port0[] = {
++ {
++ .reg = 0x4a0,
++ .mask = BIT(5),
++ .val = BIT(5),
++ },
++ { /* sentinel */ }
+};
+
+/* 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 const struct en7528_pcie_phy_op en7528_phy_port1[] = {
++ {
++ .reg = 0xb2c,
++ .mask = GENMASK(13, 12),
++ .val = BIT(12),
++ },
++ { /* sentinel */ }
++};
++
++/* EN751221 Port 1 PHY */
++static const struct en7528_pcie_phy_op en751221_phy_port1[] = {
++ /* Rx Detection Timing for 7512 E1, 16*8 clock cycles */
++ {
++ .reg = 0xa28,
++ .mask = GENMASK(17, 9),
++ .val = 16 << 9,
++ },
++ /* Same for different power mode */
++ {
++ .reg = 0xa2c,
++ .mask = GENMASK(8, 0),
++ .val = 16,
++ },
++ { /* sentinel */ }
+};
+
+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;
++ const struct en7528_pcie_phy_op *data = ephy->data;
++ int i, ret;
+
-+ return regmap_update_bits(ephy->regmap, data->reg,
-+ data->mask, data->val);
++ for (i = 0; data[i].mask || data[i].val; i++) {
++ if (i)
++ usleep_range(1000, 2000);
++
++ ret = regmap_update_bits(ephy->regmap, data[i].reg,
++ data[i].mask, data[i].val);
++ if (ret)
++ return ret;
++ }
++
++ return 0;
+}
+
+static const struct phy_ops en7528_pcie_phy_ops = {
+static int en7528_pcie_phy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
-+ const struct en7528_pcie_phy_data *data;
++ const struct en7528_pcie_phy_op *data;
+ struct regmap_config regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ struct en7528_pcie_phy *ephy;
+ void __iomem *base;
+ struct phy *phy;
++ int i;
+
+ data = of_device_get_match_data(dev);
+ if (!data)
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
-+ regmap_config.max_register = data->max_reg;
++ for (i = 0; data[i].mask || data[i].val; i++)
++ if (data[i].reg > regmap_config.max_register)
++ regmap_config.max_register = data[i].reg;
++
+ ephy->regmap = devm_regmap_init_mmio(dev, base, ®map_config);
+ if (IS_ERR(ephy->regmap))
+ return PTR_ERR(ephy->regmap);
+}
+
+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 },
++ { .compatible = "econet,en7528-pcie-phy0", .data = en7528_phy_port0 },
++ { .compatible = "econet,en7528-pcie-phy1", .data = en7528_phy_port1 },
++ { .compatible = "econet,en751221-pcie-phy0", .data = en7528_phy_port0 },
++ { .compatible = "econet,en751221-pcie-phy1", .data = en751221_phy_port1 },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, en7528_pcie_phy_ids);