Merge Official Source

Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
Tianling Shen 2025-01-19 16:01:46 +08:00
commit 42afc4e64e
No known key found for this signature in database
GPG Key ID: 6850B6345C862176
13 changed files with 455 additions and 71 deletions

View File

@ -64,7 +64,7 @@ Signed-off-by: David Bauer <mail@david-bauer.net>
spin_unlock_irqrestore(&ath79_reset->lock, flags);
return 0;
@@ -79,8 +90,27 @@ static int ath79_reset_restart_handler(s
@@ -79,8 +90,28 @@ static int ath79_reset_restart_handler(s
{
struct ath79_reset *ath79_reset =
container_of(nb, struct ath79_reset, restart_nb);
@ -81,19 +81,20 @@ Signed-off-by: David Bauer <mail@david-bauer.net>
+ * full chip reset. See page 111 of the AR9344 datasheet.
+ */
+ __ath79_reset_update_unlocked(ath79_reset, ETH_SWITCH_RESET, true);
+ mdelay(10);
+ mdelay(1);
+ __ath79_reset_update_unlocked(ath79_reset, ETH_SWITCH_ARESET, true);
+ mdelay(1);
+ __ath79_reset_update_unlocked(ath79_reset, FULL_CHIP_RESET, true);
+ mdelay(10);
+ } else {
+ __ath79_reset_update_unlocked(ath79_reset, FULL_CHIP_RESET, true);
+ }
+
+ __ath79_reset_update_unlocked(ath79_reset, FULL_CHIP_RESET, true);
+ mdelay(10);
+
+ spin_unlock_irqrestore(&ath79_reset->lock, flags);
return NOTIFY_DONE;
}
@@ -95,6 +125,8 @@ static int ath79_reset_probe(struct plat
@@ -95,6 +126,8 @@ static int ath79_reset_probe(struct plat
if (!ath79_reset)
return -ENOMEM;

View File

@ -0,0 +1,42 @@
From a78794562fcb2659c976388b1285eddda97e9954 Mon Sep 17 00:00:00 2001
From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Date: Tue, 10 Oct 2023 21:29:13 +0530
Subject: [PATCH] PCI: dwc: Add host_post_init() callback
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This callback can be used by the platform drivers to do configuration
once all the devices are scanned. Like changing LNKCTL of all downstream
devices to enable ASPM etc...
Link: https://lore.kernel.org/linux-pci/20231010155914.9516-2-manivannan.sadhasivam@linaro.org
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
---
drivers/pci/controller/dwc/pcie-designware-host.c | 3 +++
drivers/pci/controller/dwc/pcie-designware.h | 1 +
2 files changed, 4 insertions(+)
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -502,6 +502,9 @@ int dw_pcie_host_init(struct dw_pcie_rp
if (ret)
goto err_stop_link;
+ if (pp->ops->host_post_init)
+ pp->ops->host_post_init(pp);
+
return 0;
err_stop_link:
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -301,6 +301,7 @@ enum dw_pcie_ltssm {
struct dw_pcie_host_ops {
int (*host_init)(struct dw_pcie_rp *pp);
void (*host_deinit)(struct dw_pcie_rp *pp);
+ void (*host_post_init)(struct dw_pcie_rp *pp);
int (*msi_host_init)(struct dw_pcie_rp *pp);
void (*pme_turn_off)(struct dw_pcie_rp *pp);
};

View File

@ -0,0 +1,102 @@
From 9f4f3dfad8cf08208fbb78b1b9cbf957c12618b9 Mon Sep 17 00:00:00 2001
From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Date: Tue, 10 Oct 2023 21:29:14 +0530
Subject: [PATCH] PCI: qcom: Enable ASPM for platforms supporting 1.9.0 ops
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
ASPM is supported by Qcom host controllers/bridges on most of the recent
platforms and so the devices tested so far. But for enabling ASPM by
default (without using Kconfig, kernel command-line or sysfs), BIOS has
to enable ASPM on both host bridge and downstream devices during boot.
Unfortunately, none of the BIOS available on Qcom platforms enables
ASPM. Due to this, the platforms making use of Qcom SoCs draw high power
during runtime.
To fix this power draw issue, users have to enable ASPM using Kconfig,
kernel command-line, sysfs or the BIOS has to start enabling ASPM.
The latter may happen in the future, but that won't address the issue on
current platforms. Also, asking users to enable a feature to get the power
management right would provide an unpleasant out-of-the-box experience.
So the apt solution is to enable ASPM in the controller driver itself. And
this is being accomplished by calling pci_enable_link_state() in the newly
introduced host_post_init() callback for all the devices connected to the
bus. This function enables all supported link low power states for both
host bridge and the downstream devices.
Due to limited testing, ASPM is only enabled for platforms making use of
ops_1_9_0 callbacks.
[kwilczynski: commit log]
Link: https://lore.kernel.org/linux-pci/20231010155914.9516-3-manivannan.sadhasivam@linaro.org
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
---
drivers/pci/controller/dwc/pcie-qcom.c | 28 ++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -222,6 +222,7 @@ struct qcom_pcie_ops {
int (*get_resources)(struct qcom_pcie *pcie);
int (*init)(struct qcom_pcie *pcie);
int (*post_init)(struct qcom_pcie *pcie);
+ void (*host_post_init)(struct qcom_pcie *pcie);
void (*deinit)(struct qcom_pcie *pcie);
void (*ltssm_enable)(struct qcom_pcie *pcie);
int (*config_sid)(struct qcom_pcie *pcie);
@@ -966,6 +967,22 @@ static int qcom_pcie_post_init_2_7_0(str
return 0;
}
+static int qcom_pcie_enable_aspm(struct pci_dev *pdev, void *userdata)
+{
+ /* Downstream devices need to be in D0 state before enabling PCI PM substates */
+ pci_set_power_state(pdev, PCI_D0);
+ pci_enable_link_state(pdev, PCIE_LINK_STATE_ALL);
+
+ return 0;
+}
+
+static void qcom_pcie_host_post_init_2_7_0(struct qcom_pcie *pcie)
+{
+ struct dw_pcie_rp *pp = &pcie->pci->pp;
+
+ pci_walk_bus(pp->bridge->bus, qcom_pcie_enable_aspm, NULL);
+}
+
static void qcom_pcie_deinit_2_7_0(struct qcom_pcie *pcie)
{
struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0;
@@ -1224,9 +1241,19 @@ static void qcom_pcie_host_deinit(struct
pcie->cfg->ops->deinit(pcie);
}
+static void qcom_pcie_host_post_init(struct dw_pcie_rp *pp)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct qcom_pcie *pcie = to_qcom_pcie(pci);
+
+ if (pcie->cfg->ops->host_post_init)
+ pcie->cfg->ops->host_post_init(pcie);
+}
+
static const struct dw_pcie_host_ops qcom_pcie_dw_ops = {
.host_init = qcom_pcie_host_init,
.host_deinit = qcom_pcie_host_deinit,
+ .host_post_init = qcom_pcie_host_post_init,
};
/* Qcom IP rev.: 2.1.0 Synopsys IP rev.: 4.01a */
@@ -1288,6 +1315,7 @@ static const struct qcom_pcie_ops ops_1_
.get_resources = qcom_pcie_get_resources_2_7_0,
.init = qcom_pcie_init_2_7_0,
.post_init = qcom_pcie_post_init_2_7_0,
+ .host_post_init = qcom_pcie_host_post_init_2_7_0,
.deinit = qcom_pcie_deinit_2_7_0,
.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
.config_sid = qcom_pcie_config_sid_1_9_0,

View File

@ -307,6 +307,7 @@
};
&pcie0 {
compatible = "qcom,pcie-ipq4019-lantiq-hack";
status = "okay";
perst-gpio = <&tlmm 38 GPIO_ACTIVE_LOW>;

View File

@ -0,0 +1,166 @@
From f4f03dca92b45616ef0325051fdc7627c16fdd62 Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Tue, 7 May 2024 20:21:17 +0200
Subject: [PATCH] PCI: qcom: add hack compatible for ipq4019 Lantiq DSL
Add hack compatible for ipq4019 Lantiq DSL
This change the PCIe vendor/device ID to the values from Lantiq
GRX500 SoCs. We also program the ATU to fake the CPU ID as a Lantiq CPU
by providing to the Lantiq firmware custom crafted value in the address
the firmware would expect the CPU ID to be readable.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
Signed-off-by: Florian Maurer <f.maurer@outlook.com>
---
drivers/pci/controller/dwc/pcie-qcom.c | 94 +++++++++++++++++++++++++-
1 file changed, 93 insertions(+), 1 deletion(-)
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -184,11 +184,24 @@ struct qcom_pcie_resources_2_3_3 {
#define QCOM_PCIE_2_4_0_MAX_CLOCKS 4
#define QCOM_PCIE_2_4_0_MAX_RESETS 12
+/*
+ * This value is the manufacturer ID of Lantiq. The address where
+ * it will be visible for the PCIe device matches the location of
+ * CPU ID registers on Lantiq SocS (MPS base address is 0x1f107000).
+ */
+#define QCOM_PCIE_2_4_0_CPU_ID_BASE_REG 0x1f107000
+#define QCOM_PCIE_2_4_0_CPU_ID_REG 0x340
+#define QCOM_PCIE_2_4_0_CPU_ID_REG_OFFSET (QCOM_PCIE_2_4_0_CPU_ID_REG / sizeof(u32))
+#define QCOM_PCIE_2_4_0_CPU_ID_REG_VAL (0x389 << 5)
+#define QCOM_PCIE_2_4_0_GRX500_VENDOR_ID 0x1bef
+#define QCOM_PCIE_2_4_0_GRX500_DEVICE_ID 0x0030
struct qcom_pcie_resources_2_4_0 {
struct clk_bulk_data clks[QCOM_PCIE_2_4_0_MAX_CLOCKS];
int num_clks;
struct reset_control_bulk_data resets[QCOM_PCIE_2_4_0_MAX_RESETS];
int num_resets;
+ void *lantiq_hack_virt;
+ dma_addr_t lantiq_hack_phys;
};
#define QCOM_PCIE_2_7_0_MAX_CLOCKS 15
@@ -629,12 +642,65 @@ static int qcom_pcie_post_init_2_3_2(str
return 0;
}
+static void qcom_pcie_host_post_init_2_3_2_lantiq_hack(struct qcom_pcie *pcie)
+{
+ struct qcom_pcie_resources_2_4_0 *res = &pcie->res.v2_4_0;
+ struct dw_pcie *pci = pcie->pci;
+ struct dw_pcie_rp *pp = &pci->pp;
+ struct device *dev = pci->dev;
+ struct resource_entry *entry;
+ int ret, index = 0;
+ u64 addr, phys;
+ u32 *val;
+
+ res->lantiq_hack_virt = dma_alloc_coherent(dev, SZ_4K,
+ &res->lantiq_hack_phys,
+ GFP_ATOMIC);
+ if (!res->lantiq_hack_virt) {
+ dev_err(dev, "failed to allocate DMA for lantiq hack\n");
+ return;
+ }
+
+ /* Fake Lantiq CPU ID register */
+ val = (u32 *)res->lantiq_hack_virt;
+ val[QCOM_PCIE_2_4_0_CPU_ID_REG_OFFSET] = QCOM_PCIE_2_4_0_CPU_ID_REG_VAL;
+
+ /* Increment index based on used iATU */
+ resource_list_for_each_entry(entry, &pp->bridge->dma_ranges)
+ if (resource_type(entry->res) == IORESOURCE_MEM)
+ index++;
+
+ /* Check if there is space for an additional iATU */
+ if (index >= pci->num_ib_windows) {
+ dev_err(dev, "No inbound iATU window available for magic\n");
+ return;
+ }
+
+ addr = QCOM_PCIE_2_4_0_CPU_ID_BASE_REG;
+ phys = res->lantiq_hack_phys;
+
+ /* Make it visible to PCIe devices using address translation unit */
+ ret = dw_pcie_prog_inbound_atu(pci, index, PCIE_ATU_TYPE_MEM,
+ phys, addr, SZ_4K);
+ if (ret) {
+ dev_err(dev, "timeout waiting for IATU for lantiq hack: %d\n", ret);
+ return;
+ }
+
+ /* Set vendor/device ID of GRX500 PCIe host */
+ dw_pcie_dbi_ro_wr_en(pci);
+ dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, QCOM_PCIE_2_4_0_GRX500_VENDOR_ID);
+ dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, QCOM_PCIE_2_4_0_GRX500_DEVICE_ID);
+ dw_pcie_dbi_ro_wr_dis(pci);
+}
+
static int qcom_pcie_get_resources_2_4_0(struct qcom_pcie *pcie)
{
struct qcom_pcie_resources_2_4_0 *res = &pcie->res.v2_4_0;
struct dw_pcie *pci = pcie->pci;
struct device *dev = pci->dev;
- bool is_ipq = of_device_is_compatible(dev->of_node, "qcom,pcie-ipq4019");
+ bool is_ipq = of_device_is_compatible(dev->of_node, "qcom,pcie-ipq4019") ||
+ of_device_is_compatible(dev->of_node, "qcom,pcie-ipq4019-lantiq-hack");
int ret;
res->clks[0].id = "aux";
@@ -679,6 +745,17 @@ static void qcom_pcie_deinit_2_4_0(struc
clk_bulk_disable_unprepare(res->num_clks, res->clks);
}
+static void qcom_pcie_deinit_2_4_0_lantiq_hack(struct qcom_pcie *pcie)
+{
+ struct qcom_pcie_resources_2_4_0 *res = &pcie->res.v2_4_0;
+ struct dw_pcie *pci = pcie->pci;
+ struct device *dev = pci->dev;
+
+ dma_free_coherent(dev, SZ_4K, res->lantiq_hack_virt, res->lantiq_hack_phys);
+
+ qcom_pcie_deinit_2_4_0(pcie);
+}
+
static int qcom_pcie_init_2_4_0(struct qcom_pcie *pcie)
{
struct qcom_pcie_resources_2_4_0 *res = &pcie->res.v2_4_0;
@@ -1292,6 +1369,16 @@ static const struct qcom_pcie_ops ops_2_
.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
};
+/* Qcom IP rev.: 2.4.0 Synopsys IP rev.: 4.20a Lantiq DSL Hack */
+static const struct qcom_pcie_ops ops_2_4_0_lantiq_hack = {
+ .get_resources = qcom_pcie_get_resources_2_4_0,
+ .init = qcom_pcie_init_2_4_0,
+ .post_init = qcom_pcie_post_init_2_3_2,
+ .host_post_init = qcom_pcie_host_post_init_2_3_2_lantiq_hack,
+ .deinit = qcom_pcie_deinit_2_4_0_lantiq_hack,
+ .ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
+};
+
/* Qcom IP rev.: 2.3.3 Synopsys IP rev.: 4.30a */
static const struct qcom_pcie_ops ops_2_3_3 = {
.get_resources = qcom_pcie_get_resources_2_3_3,
@@ -1354,6 +1441,10 @@ static const struct qcom_pcie_cfg cfg_2_
.ops = &ops_2_4_0,
};
+static const struct qcom_pcie_cfg cfg_2_4_0_lantiq_hack = {
+ .ops = &ops_2_4_0_lantiq_hack,
+};
+
static const struct qcom_pcie_cfg cfg_2_7_0 = {
.ops = &ops_2_7_0,
};
@@ -1641,6 +1732,7 @@ static const struct of_device_id qcom_pc
{ .compatible = "qcom,pcie-apq8064", .data = &cfg_2_1_0 },
{ .compatible = "qcom,pcie-apq8084", .data = &cfg_1_0_0 },
{ .compatible = "qcom,pcie-ipq4019", .data = &cfg_2_4_0 },
+ { .compatible = "qcom,pcie-ipq4019-lantiq-hack", .data = &cfg_2_4_0_lantiq_hack },
{ .compatible = "qcom,pcie-ipq6018", .data = &cfg_2_9_0 },
{ .compatible = "qcom,pcie-ipq8064", .data = &cfg_2_1_0 },
{ .compatible = "qcom,pcie-ipq8064-v2", .data = &cfg_2_1_0 },

View File

@ -67,6 +67,7 @@
wlan2g_blue {
gpios = <&pio 1 GPIO_ACTIVE_LOW>;
label = "blue:wlan2g";
linux,default-trigger = "phy0tpt";
};
lan_green {
@ -84,6 +85,7 @@
wlan5g_blue {
gpios = <&pio 2 GPIO_ACTIVE_LOW>;
label = "blue:wlan5g";
linux,default-trigger = "phy1tpt";
};
};
};

View File

@ -82,8 +82,6 @@ mercusys,mr90x-v1-ubi)
;;
netgear,wax220)
ucidef_set_led_netdev "eth0" "LAN" "green:lan" "eth0"
ucidef_set_led_netdev "wlan2g" "WLAN2G" "blue:wlan2g" "phy0-ap0"
ucidef_set_led_netdev "wlan5g" "WLAN5G" "blue:wlan5g" "phy1-ap0"
;;
nradio,c8-668gl)
ucidef_set_led_netdev "wifi" "WIFI" "blue:wlan" "phy1-ap0" "link"

View File

@ -793,7 +793,7 @@ define Device/cudy_wr3000h-v1
DEVICE_VARIANT := v1
DEVICE_DTS := mt7981b-cudy-wr3000h-v1
DEVICE_DTS_DIR := ../dts
SUPPORTED_DEVICES += R59
SUPPORTED_DEVICES += R63
UBINIZE_OPTS := -E 5
BLOCKSIZE := 128k
PAGESIZE := 2048

View File

@ -178,14 +178,15 @@
led@0 {
reg = <0>;
color = <LED_COLOR_ID_GREEN>;
color = <LED_COLOR_ID_YELLOW>;
function = LED_FUNCTION_WAN;
default-state = "keep";
active-low;
};
led@1 {
reg = <1>;
color = <LED_COLOR_ID_YELLOW>;
led@2 {
reg = <2>;
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_WAN;
default-state = "keep";
};

View File

@ -32,13 +32,6 @@
};
};
gpio1: rtl8231-gpio {
compatible = "realtek,rtl8231-gpio";
#gpio-cells = <2>;
indirect-access-bus-id = <3>;
gpio-controller;
};
keys {
compatible = "gpio-keys-polled";
poll-interval = <20>;
@ -90,6 +83,24 @@
};
};
&mdio_aux {
status = "okay";
gpio1: expander@3 {
compatible = "realtek,rtl8231";
reg = <3>;
gpio-controller;
#gpio-cells = <2>;
gpio-ranges = <&gpio1 0 0 37>;
led-controller {
compatible = "realtek,rtl8231-leds";
status = "disabled";
};
};
};
&spi0 {
status = "okay";
flash@0 {

View File

@ -258,6 +258,22 @@
};
switchcore@1b000000 {
compatible = "syscon", "simple-mfd";
reg = <0x1b000000 0x20000>;
mdio_aux: mdio-aux {
compatible = "realtek,rtl8390-aux-mdio";
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
pinctrl-names = "default";
pinctrl-0 = <&mdio_aux_mdx>;
};
};
pinmux@1b000004 {
compatible = "pinctrl-single";
reg = <0x1b000004 0x4>;
@ -290,6 +306,11 @@
pinmux_disable_sys_led: disable_sys_led {
pinctrl-single,bits = <0x0 0x0 0x4000>;
};
/* enable AUX MDC/MDIO */
mdio_aux_mdx: aux-mdx-pins {
pinctrl-single,bits = <0x0 0x100000 0x1c0000>;
};
};
ethernet0: ethernet@1b00a300 {

View File

@ -1,21 +1,21 @@
From c7ddb74c981c1a29bad82d555d08724aca93b687 Mon Sep 17 00:00:00 2001
From ffb7da9aa25765b2115e7ff3ee4f6dafa60f5421 Mon Sep 17 00:00:00 2001
From: Sander Vanheule <sander@svanheule.net>
Date: Fri, 27 Dec 2024 14:55:31 +0100
Subject: [PATCH] net: mdio: Add Realtek Otto auxiliary controller
SoCs in Realtek's Otto platform such as the RTL8380 and RTL8391 have a
simple auxiliary MDIO controller that is commonly used to manage RTL8231
GPIO expanders on switch devices.
SoCs in Realtek's Otto platform such as the RTL8380, RTL8391, and
RTL9302 have a simple auxiliary MDIO controller that is commonly used to
manage RTL8231 GPIO expanders on switch devices.
Add a new MDIO controller driver supporting the RTL838x (maple) and
RTL839x (cypress) SoCs.
Add a new MDIO controller driver supporting the RTL838x (maple), RTL839x
(cypress), and RTL930x (longan) SoCs.
Signed-off-by: Sander Vanheule <sander@svanheule.net>
---
drivers/net/mdio/Kconfig | 10 ++
drivers/net/mdio/Makefile | 1 +
drivers/net/mdio/mdio-realtek-otto-aux.c | 129 +++++++++++++++++++++++
3 files changed, 140 insertions(+)
drivers/net/mdio/mdio-realtek-otto-aux.c | 175 +++++++++++++++++++++++
3 files changed, 186 insertions(+)
create mode 100644 drivers/net/mdio/mdio-realtek-otto-aux.c
--- a/drivers/net/mdio/Kconfig
@ -49,7 +49,7 @@ Signed-off-by: Sander Vanheule <sander@svanheule.net>
obj-$(CONFIG_MDIO_THUNDER) += mdio-thunder.o
--- /dev/null
+++ b/drivers/net/mdio/mdio-realtek-otto-aux.c
@@ -0,0 +1,141 @@
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <linux/mfd/core.h>
@ -64,65 +64,95 @@ Signed-off-by: Sander Vanheule <sander@svanheule.net>
+
+#define RTL8380_EXT_GPIO_INDIRECT_ACCESS 0xA09C
+#define RTL8390_EXT_GPIO_INDIRECT_ACCESS 0x0224
+#define RTL9300_EXT_GPIO_INDIRECT_ACCESS 0xC620
+
+#define RTL83XX_AUX_MDIO_DATA GENMASK(31, 16)
+#define RTL83XX_AUX_MDIO_REG GENMASK(11, 7)
+#define RTL83XX_AUX_MDIO_PHY_ADDR GENMASK(6, 2)
+#define RTL83XX_AUX_MDIO_WRITE BIT(1)
+#define RTL83XX_AUX_MDIO_READ 0
+#define RTL83XX_AUX_MDIO_EXEC BIT(0)
+#define RTL83XX_AUX_MDIO_DATA_OFFSET 16
+#define RTL83XX_AUX_MDIO_RCMD_FAIL 0
+
+#define RTL93XX_AUX_MDIO_DATA_OFFSET 12
+#define RTL93XX_AUX_MDIO_RCMD_FAIL BIT(28)
+
+#define REALTEK_AUX_MDIO_REG GENMASK(11, 7)
+#define REALTEK_AUX_MDIO_PHY_ADDR GENMASK(6, 2)
+#define REALTEK_AUX_MDIO_WRITE BIT(1)
+#define REALTEK_AUX_MDIO_READ 0
+#define REALTEK_AUX_MDIO_EXEC BIT(0)
+
+struct realtek_aux_mdio_info {
+ unsigned int cmd_reg;
+ unsigned int data_offset;
+ unsigned int rcmd_fail_mask;
+ unsigned int timeout_us;
+};
+
+static const struct realtek_aux_mdio_info info_rtl838x = {
+ .cmd_reg = RTL8380_EXT_GPIO_INDIRECT_ACCESS,
+ .data_offset = RTL83XX_AUX_MDIO_DATA_OFFSET,
+ .rcmd_fail_mask = RTL83XX_AUX_MDIO_RCMD_FAIL,
+ .timeout_us = 1700,
+};
+
+static const struct realtek_aux_mdio_info info_rtl839x = {
+ .cmd_reg = RTL8390_EXT_GPIO_INDIRECT_ACCESS,
+ .data_offset = RTL83XX_AUX_MDIO_DATA_OFFSET,
+ .rcmd_fail_mask = RTL83XX_AUX_MDIO_RCMD_FAIL,
+ .timeout_us = 4120,
+};
+
+static const struct realtek_aux_mdio_info info_rtl930x = {
+ .cmd_reg = RTL9300_EXT_GPIO_INDIRECT_ACCESS,
+ .data_offset = RTL93XX_AUX_MDIO_DATA_OFFSET,
+ .rcmd_fail_mask = RTL93XX_AUX_MDIO_RCMD_FAIL,
+ .timeout_us = 19000,
+};
+
+struct realtek_aux_mdio_ctrl {
+ struct device *dev;
+ struct regmap *map;
+ unsigned int cmd_reg;
+ const struct realtek_aux_mdio_info *info;
+};
+
+#define mii_bus_to_ctrl(bus) ((struct realtek_aux_mdio_ctrl *) bus->priv)
+
+static int rtl83xx_aux_mdio_cmd(struct realtek_aux_mdio_ctrl *ctrl, int addr, int regnum,
+static int realtek_aux_mdio_cmd(struct realtek_aux_mdio_ctrl *ctrl, int addr, int regnum,
+ u32 rw_bit, u16 *data)
+{
+ unsigned int mask_volatile;
+ unsigned int cmd;
+ unsigned int run;
+ int err;
+
+ cmd = rw_bit | RTL83XX_AUX_MDIO_EXEC;
+ cmd |= FIELD_PREP(RTL83XX_AUX_MDIO_PHY_ADDR, addr);
+ cmd |= FIELD_PREP(RTL83XX_AUX_MDIO_REG, regnum);
+ cmd = rw_bit | REALTEK_AUX_MDIO_EXEC;
+ cmd |= FIELD_PREP(REALTEK_AUX_MDIO_PHY_ADDR, addr);
+ cmd |= FIELD_PREP(REALTEK_AUX_MDIO_REG, regnum);
+
+ mask_volatile = RTL83XX_AUX_MDIO_EXEC;
+ if (rw_bit == REALTEK_AUX_MDIO_WRITE)
+ cmd |= *data << ctrl->info->data_offset;
+
+ if (rw_bit == RTL83XX_AUX_MDIO_WRITE)
+ cmd |= FIELD_PREP(RTL83XX_AUX_MDIO_DATA, *data);
+ else
+ mask_volatile |= RTL83XX_AUX_MDIO_DATA;
+
+ err = regmap_write(ctrl->map, ctrl->cmd_reg, cmd);
+ err = regmap_write(ctrl->map, ctrl->info->cmd_reg, cmd);
+ if (err)
+ return err;
+
+ err = regmap_read_poll_timeout_atomic(ctrl->map, ctrl->cmd_reg, run, (run != cmd), 3, 100);
+ err = regmap_read_poll_timeout_atomic(ctrl->map, ctrl->info->cmd_reg, cmd,
+ !(cmd & REALTEK_AUX_MDIO_EXEC), 3, ctrl->info->timeout_us);
+ if (err)
+ return err;
+
+ if ((run & ~mask_volatile) != (cmd & ~mask_volatile)) {
+ dev_err(ctrl->dev, "Command modified. Is offloading still active?");
+ return -EIO;
+ if (rw_bit == REALTEK_AUX_MDIO_READ) {
+ if (cmd & ctrl->info->rcmd_fail_mask)
+ return -EIO;
+
+ *data = (cmd >> ctrl->info->data_offset) & GENMASK(15, 0);
+ }
+
+ if (!err && (rw_bit == RTL83XX_AUX_MDIO_READ))
+ *data = FIELD_GET(RTL83XX_AUX_MDIO_DATA, run);
+
+ return err;
+ return 0;
+}
+
+static int rtl83xx_aux_mdio_read(struct mii_bus *bus, int addr, int regnum)
+static int realtek_aux_mdio_read(struct mii_bus *bus, int addr, int regnum)
+{
+ struct realtek_aux_mdio_ctrl *ctrl = mii_bus_to_ctrl(bus);
+ u16 data;
+ int err;
+
+ err = rtl83xx_aux_mdio_cmd(ctrl, addr, regnum, RTL83XX_AUX_MDIO_READ, &data);
+ err = realtek_aux_mdio_cmd(ctrl, addr, regnum, REALTEK_AUX_MDIO_READ, &data);
+
+ if (err)
+ return err;
@ -130,11 +160,11 @@ Signed-off-by: Sander Vanheule <sander@svanheule.net>
+ return data;
+}
+
+static int rtl83xx_aux_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
+static int realtek_aux_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
+{
+ struct realtek_aux_mdio_ctrl *ctrl = mii_bus_to_ctrl(bus);
+
+ return rtl83xx_aux_mdio_cmd(ctrl, addr, regnum, RTL83XX_AUX_MDIO_WRITE, &val);
+ return realtek_aux_mdio_cmd(ctrl, addr, regnum, REALTEK_AUX_MDIO_WRITE, &val);
+}
+
+static int realtek_aux_mdio_probe(struct platform_device *pdev)
@ -149,16 +179,16 @@ Signed-off-by: Sander Vanheule <sander@svanheule.net>
+
+ ctrl = bus->priv;
+ ctrl->dev = &pdev->dev;
+ ctrl->cmd_reg = (unsigned int) device_get_match_data(ctrl->dev);
+ ctrl->info = (const struct realtek_aux_mdio_info *) device_get_match_data(ctrl->dev);
+ ctrl->map = syscon_node_to_regmap(np->parent);
+ if (IS_ERR(ctrl->map))
+ return PTR_ERR(ctrl->map);
+
+ bus->name = "RTL83xx auxiliary MDIO bus";
+ snprintf(bus->id, MII_BUS_ID_SIZE, "rtl83xx-aux-mdio") ;
+ bus->name = "Realtek auxiliary MDIO bus";
+ snprintf(bus->id, MII_BUS_ID_SIZE, "realtek-aux-mdio") ;
+ bus->parent = ctrl->dev;
+ bus->read = rtl83xx_aux_mdio_read;
+ bus->write = rtl83xx_aux_mdio_write;
+ bus->read = realtek_aux_mdio_read;
+ bus->write = realtek_aux_mdio_write;
+ /* Don't have interrupts */
+ for (unsigned int i = 0; i < PHY_MAX_ADDR; i++)
+ bus->irq[i] = PHY_POLL;
@ -169,11 +199,15 @@ Signed-off-by: Sander Vanheule <sander@svanheule.net>
+static const struct of_device_id realtek_aux_mdio_of_match[] = {
+ {
+ .compatible = "realtek,rtl8380-aux-mdio",
+ .data = (void *) RTL8380_EXT_GPIO_INDIRECT_ACCESS,
+ .data = &info_rtl838x,
+ },
+ {
+ .compatible = "realtek,rtl8390-aux-mdio",
+ .data = (void *) RTL8390_EXT_GPIO_INDIRECT_ACCESS,
+ .data = &info_rtl839x,
+ },
+ {
+ .compatible = "realtek,rtl9300-aux-mdio",
+ .data = &info_rtl930x,
+ },
+ { /* sentinel */ }
+};
@ -189,5 +223,5 @@ Signed-off-by: Sander Vanheule <sander@svanheule.net>
+module_platform_driver(realtek_aux_mdio_driver);
+
+MODULE_AUTHOR("Sander Vanheule <sander@svanheule.net>");
+MODULE_DESCRIPTION("Realtek RTL83xx auxiliary MDIO bus");
+MODULE_DESCRIPTION("Realtek otto auxiliary MDIO bus");
+MODULE_LICENSE("GPL v2");

View File

@ -96,6 +96,7 @@ CONFIG_GPIO_GENERIC=y
CONFIG_GPIO_PCA953X=y
CONFIG_GPIO_PCA953X_IRQ=y
CONFIG_GPIO_REALTEK_OTTO=y
CONFIG_GPIO_REGMAP=y
CONFIG_GPIO_RTL8231=y
CONFIG_GPIO_WATCHDOG=y
# CONFIG_GPIO_WATCHDOG_ARCH_INITCALL is not set
@ -122,6 +123,7 @@ CONFIG_IRQ_MIPS_CPU=y
CONFIG_IRQ_WORK=y
CONFIG_JFFS2_ZLIB=y
CONFIG_LEDS_GPIO=y
# CONFIG_LEDS_RTL8231 is not set
CONFIG_LIBFDT=y
CONFIG_LOCK_DEBUGGING_SUPPORT=y
CONFIG_MACH_REALTEK_RTL=y
@ -130,9 +132,10 @@ CONFIG_MDIO_BUS=y
CONFIG_MDIO_DEVICE=y
CONFIG_MDIO_DEVRES=y
CONFIG_MDIO_I2C=y
# CONFIG_MDIO_REALTEK_OTTO_AUX is not set
CONFIG_MDIO_REALTEK_OTTO_AUX=y
CONFIG_MDIO_SMBUS=y
# CONFIG_MFD_RTL8231 is not set
CONFIG_MFD_CORE=y
CONFIG_MFD_RTL8231=y
CONFIG_MFD_SYSCON=y
CONFIG_MIGRATION=y
CONFIG_MIPS=y
@ -201,6 +204,7 @@ CONFIG_PHYLIB=y
CONFIG_PHYLIB_LEDS=y
CONFIG_PHYLINK=y
CONFIG_PINCTRL=y
CONFIG_PINCTRL_RTL8231=y
CONFIG_PM_OPP=y
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_GPIO_RESTART=y
@ -217,6 +221,7 @@ CONFIG_REALTEK_PHY=y
CONFIG_REALTEK_SOC_PHY=y
CONFIG_REGMAP=y
CONFIG_REGMAP_I2C=y
CONFIG_REGMAP_MDIO=y
CONFIG_REGMAP_MMIO=y
CONFIG_RESET_CONTROLLER=y
CONFIG_RFS_ACCEL=y