mirror of
https://git.openwrt.org/openwrt/openwrt.git
synced 2026-02-19 04:11:18 +01:00
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 <naseefkm@gmail.com> Link: https://github.com/openwrt/openwrt/pull/21326 Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
This commit is contained in:
parent
a14d81d465
commit
be24a13ad5
9 changed files with 532 additions and 3 deletions
|
|
@ -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 = <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>;
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -24,6 +24,14 @@
|
|||
};
|
||||
};
|
||||
|
||||
&pcie0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pcie1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gmac0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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, ®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 <naseefkm@gmail.com>");
|
||||
+MODULE_DESCRIPTION("EcoNet EN7528 PCIe PHY driver");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
|
|
@ -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;
|
||||
Loading…
Add table
Reference in a new issue