mirror of
https://github.com/armbian/build.git
synced 2025-09-15 02:31:05 +02:00
369 lines
10 KiB
Diff
369 lines
10 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: John Doe <john.doe@somewhere.on.planet>
|
|
Date: Sat, 15 Mar 2025 00:57:55 -0300
|
|
Subject: [PATCH] Add Maxio MAE0621A PHY driver
|
|
|
|
Signed-off-by: John Doe <john.doe@somewhere.on.planet>
|
|
---
|
|
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 5 +
|
|
drivers/net/phy/Kconfig | 5 +
|
|
drivers/net/phy/Makefile | 1 +
|
|
drivers/net/phy/maxio.c | 254 ++++++++++
|
|
drivers/net/phy/phy_device.c | 9 +
|
|
5 files changed, 274 insertions(+)
|
|
|
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
|
index d04543e5697b..c8cf84fa4091 100644
|
|
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
|
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
|
@@ -7826,10 +7826,11 @@ int stmmac_suspend(struct device *dev)
|
|
|
|
priv->speed = SPEED_UNKNOWN;
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(stmmac_suspend);
|
|
+#define MAXIO_PHY_MAE0621A_ID 0x7b744411
|
|
|
|
static void stmmac_reset_rx_queue(struct stmmac_priv *priv, u32 queue)
|
|
{
|
|
struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue];
|
|
|
|
@@ -7922,10 +7923,14 @@ int stmmac_resume(struct device *dev)
|
|
|
|
stmmac_reset_queues_param(priv);
|
|
|
|
stmmac_free_tx_skbufs(priv);
|
|
stmmac_clear_descriptors(priv, &priv->dma_conf);
|
|
+ if (ndev->phydev->drv->config_init) {
|
|
+ if (ndev->phydev->phy_id == MAXIO_PHY_MAE0621A_ID)
|
|
+ ndev->phydev->drv->config_init(ndev->phydev);
|
|
+ }
|
|
|
|
stmmac_hw_setup(ndev, false);
|
|
stmmac_init_coalesce(priv);
|
|
stmmac_set_rx_mode(ndev);
|
|
|
|
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
|
|
index 41c15a2c2037..6a5de0ce5723 100644
|
|
--- a/drivers/net/phy/Kconfig
|
|
+++ b/drivers/net/phy/Kconfig
|
|
@@ -360,10 +360,15 @@ config RENESAS_PHY
|
|
config ROCKCHIP_PHY
|
|
tristate "Rockchip Ethernet PHYs"
|
|
help
|
|
Currently supports the integrated Ethernet PHY.
|
|
|
|
+config MAXIO_PHY
|
|
+ tristate "Maxio PHYs"
|
|
+ help
|
|
+ Supports the Maxio MAExxxx PHY.
|
|
+
|
|
config SMSC_PHY
|
|
tristate "SMSC PHYs"
|
|
select CRC16
|
|
help
|
|
Currently supports the LAN83C185, LAN8187 and LAN8700 PHYs
|
|
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
|
|
index c8dac6e92278..2bdde53a3885 100644
|
|
--- a/drivers/net/phy/Makefile
|
|
+++ b/drivers/net/phy/Makefile
|
|
@@ -94,10 +94,11 @@ obj-$(CONFIG_NXP_C45_TJA11XX_PHY) += nxp-c45-tja.o
|
|
obj-$(CONFIG_NXP_CBTX_PHY) += nxp-cbtx.o
|
|
obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o
|
|
obj-y += qcom/
|
|
obj-$(CONFIG_QSEMI_PHY) += qsemi.o
|
|
obj-$(CONFIG_REALTEK_PHY) += realtek/
|
|
+obj-$(CONFIG_MAXIO_PHY) += maxio.o
|
|
obj-$(CONFIG_RENESAS_PHY) += uPD60620.o
|
|
obj-$(CONFIG_ROCKCHIP_PHY) += rockchip.o
|
|
obj-$(CONFIG_SMSC_PHY) += smsc.o
|
|
obj-$(CONFIG_STE10XP) += ste10Xp.o
|
|
obj-$(CONFIG_TERANETICS_PHY) += teranetics.o
|
|
diff --git a/drivers/net/phy/maxio.c b/drivers/net/phy/maxio.c
|
|
new file mode 100644
|
|
index 000000000000..fd227e86794f
|
|
--- /dev/null
|
|
+++ b/drivers/net/phy/maxio.c
|
|
@@ -0,0 +1,254 @@
|
|
+/*
|
|
+ * drivers/net/phy/maxio.c
|
|
+ *
|
|
+ * Driver for maxio PHYs
|
|
+ *
|
|
+ * Author: zhao yang <yang_zhao@maxio-tech.com>
|
|
+ *
|
|
+ * Copyright (c) 2004 maxio technology, Inc.
|
|
+ */
|
|
+#include <linux/bitops.h>
|
|
+#include <linux/phy.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/device.h>
|
|
+#include <linux/timer.h>
|
|
+#include <linux/netdevice.h>
|
|
+
|
|
+#define MAXIO_PAGE_SELECT 0x1f
|
|
+#define MAXIO_MAE0621A_INER 0x12
|
|
+#define MAXIO_MAE0621A_INER_LINK_STATUS BIT(4)
|
|
+#define MAXIO_MAE0621A_INSR 0x1d
|
|
+#define MAXIO_MAE0621A_TX_DELAY (BIT(6)|BIT(7))
|
|
+#define MAXIO_MAE0621A_RX_DELAY (BIT(4)|BIT(5))
|
|
+#define MAXIO_MAE0621A_CLK_MODE_REG 0x02
|
|
+#define MAXIO_MAE0621A_WORK_STATUS_REG 0x1d
|
|
+
|
|
+
|
|
+static int maxio_read_paged(struct phy_device *phydev, int page, u32 regnum)
|
|
+{
|
|
+ int ret = 0, oldpage;
|
|
+
|
|
+ oldpage = phy_read(phydev, MAXIO_PAGE_SELECT);
|
|
+ if (oldpage >= 0) {
|
|
+ phy_write(phydev, MAXIO_PAGE_SELECT, page);
|
|
+ ret = phy_read(phydev, regnum);
|
|
+ }
|
|
+ phy_write(phydev, MAXIO_PAGE_SELECT, oldpage);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int maxio_write_paged(struct phy_device *phydev, int page, u32 regnum, u16 val)
|
|
+{
|
|
+ int ret = 0, oldpage;
|
|
+
|
|
+ oldpage = phy_read(phydev, MAXIO_PAGE_SELECT);
|
|
+ if (oldpage >= 0) {
|
|
+ phy_write(phydev, MAXIO_PAGE_SELECT, page);
|
|
+ ret = phy_write(phydev, regnum, val);
|
|
+ }
|
|
+ phy_write(phydev, MAXIO_PAGE_SELECT, oldpage);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int maxio_mae0621a_clk_init(struct phy_device *phydev)
|
|
+{
|
|
+ u32 workmode,clkmode,oldpage;
|
|
+
|
|
+ oldpage = phy_read(phydev, MAXIO_PAGE_SELECT);
|
|
+ if (oldpage == 0xFFFF) {
|
|
+ oldpage = phy_read(phydev, MAXIO_PAGE_SELECT);
|
|
+ }
|
|
+
|
|
+ //soft reset
|
|
+ phy_write(phydev, MAXIO_PAGE_SELECT, 0x0);
|
|
+ phy_write(phydev, MII_BMCR, BMCR_RESET | phy_read(phydev, MII_BMCR));
|
|
+
|
|
+ //get workmode
|
|
+ phy_write(phydev, MAXIO_PAGE_SELECT, 0xa43);
|
|
+ workmode = phy_read(phydev, MAXIO_MAE0621A_WORK_STATUS_REG);
|
|
+
|
|
+ //get clkmode
|
|
+ phy_write( phydev, MAXIO_PAGE_SELECT, 0xd92 );
|
|
+ clkmode = phy_read( phydev, MAXIO_MAE0621A_CLK_MODE_REG );
|
|
+
|
|
+ //abnormal
|
|
+ if (0 == (workmode&BIT(5))) {
|
|
+ if (0 == (clkmode&BIT(8))) {
|
|
+ //oscillator
|
|
+ phy_write(phydev, 0x02, clkmode | BIT(8));
|
|
+ printk("****maxio_mae0621a_clk_init**clkmode**0x210a: 0x%x\n", phydev->phy_id);
|
|
+ } else {
|
|
+ //crystal
|
|
+ printk("****maxio_mae0621a_clk_init**clkmode**0x200a: 0x%x\n", phydev->phy_id);
|
|
+ phy_write(phydev, 0x02, clkmode &(~ BIT(8)));
|
|
+ }
|
|
+ }
|
|
+ phy_write(phydev, MAXIO_PAGE_SELECT, 0x0);
|
|
+
|
|
+ phy_write(phydev, MAXIO_PAGE_SELECT, oldpage);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int maxio_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
|
|
+{
|
|
+ int ret = 0, oldpage;
|
|
+ oldpage = phy_read(phydev, MAXIO_PAGE_SELECT);
|
|
+
|
|
+ if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) {// eee info
|
|
+ phy_write(phydev, MAXIO_PAGE_SELECT ,0);
|
|
+ phy_write(phydev, 0xd, MDIO_MMD_AN);
|
|
+ phy_write(phydev, 0xe, MDIO_AN_EEE_ADV);
|
|
+ phy_write(phydev, 0xd, 0x4000 | MDIO_MMD_AN);
|
|
+ ret = phy_read(phydev, 0x0e);
|
|
+ } else {
|
|
+ ret = -EOPNOTSUPP;
|
|
+ }
|
|
+ phy_write(phydev, MAXIO_PAGE_SELECT, oldpage);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int maxio_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, u16 val)
|
|
+{
|
|
+ int ret = 0, oldpage;
|
|
+ oldpage = phy_read(phydev, MAXIO_PAGE_SELECT);
|
|
+
|
|
+ if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { // eee info
|
|
+ phy_write(phydev, MAXIO_PAGE_SELECT ,0);
|
|
+ ret |= phy_write(phydev, 0xd, MDIO_MMD_AN);
|
|
+ ret |= phy_write(phydev, 0xe, MDIO_AN_EEE_ADV);
|
|
+ ret |= phy_write(phydev, 0xd, 0x4000 | MDIO_MMD_AN);
|
|
+ ret |= phy_write(phydev, 0xe, val);
|
|
+ msleep(100);
|
|
+ ret |= genphy_restart_aneg(phydev);
|
|
+ } else {
|
|
+ ret = -EOPNOTSUPP;
|
|
+ }
|
|
+ phy_write(phydev, MAXIO_PAGE_SELECT, oldpage);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int maxio_mae0621a_config_aneg(struct phy_device *phydev)
|
|
+{
|
|
+ return genphy_config_aneg(phydev);
|
|
+}
|
|
+
|
|
+
|
|
+static int maxio_mae0621a_config_init(struct phy_device *phydev)
|
|
+{
|
|
+ struct device *dev = &phydev->mdio.dev;
|
|
+ u16 val;
|
|
+ int ret;
|
|
+ u32 broken = 0;
|
|
+
|
|
+ maxio_mae0621a_clk_init(phydev);
|
|
+
|
|
+ //disable eee
|
|
+ printk("eee value: 0x%x \n",maxio_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV));
|
|
+ maxio_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0);
|
|
+ printk("eee value: 0x%x \n",maxio_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV));
|
|
+ broken |= MDIO_EEE_100TX;
|
|
+ broken |= MDIO_EEE_1000T;
|
|
+ memcpy(phydev->eee_broken_modes, broken, sizeof(phydev->eee_broken_modes));
|
|
+
|
|
+ //enable auto_speed_down
|
|
+ ret = maxio_write_paged(phydev, 0xd8f, 0x0, 0x300 );
|
|
+
|
|
+ //adjust TX/RX delay
|
|
+ switch (phydev->interface) {
|
|
+ case PHY_INTERFACE_MODE_RGMII:
|
|
+ val = 0x0;
|
|
+ break;
|
|
+ case PHY_INTERFACE_MODE_RGMII_ID:
|
|
+ val = MAXIO_MAE0621A_TX_DELAY | MAXIO_MAE0621A_RX_DELAY;
|
|
+ break;
|
|
+ case PHY_INTERFACE_MODE_RGMII_RXID:
|
|
+ val = MAXIO_MAE0621A_RX_DELAY;
|
|
+ break;
|
|
+ case PHY_INTERFACE_MODE_RGMII_TXID:
|
|
+ val = MAXIO_MAE0621A_TX_DELAY;
|
|
+ break;
|
|
+ default: /* the rest of the modes imply leaving delays as is. */
|
|
+ goto delay_skip;
|
|
+ }
|
|
+
|
|
+ ret = maxio_read_paged(phydev, 0xd96, 0x0);
|
|
+ if (ret < 0) {
|
|
+ dev_err(dev, "Failed to update the TX delay register\n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret =maxio_write_paged(phydev, 0xd96, 0x0, val|ret );
|
|
+ if (ret < 0) {
|
|
+ dev_err(dev, "Failed to update the TX delay register\n");
|
|
+ return ret;
|
|
+ } else if (ret == 0) {
|
|
+ dev_dbg(dev,
|
|
+ "2ns delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n",
|
|
+ val ? "enabled" : "disabled");
|
|
+ }
|
|
+delay_skip:
|
|
+
|
|
+ phy_write(phydev, MII_BMCR, BMCR_RESET | phy_read(phydev, MII_BMCR));
|
|
+ msleep(1);
|
|
+ phy_write(phydev, MAXIO_PAGE_SELECT, 0x0);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+static int maxio_mae0621a_resume(struct phy_device *phydev)
|
|
+{
|
|
+ int ret = genphy_resume(phydev);
|
|
+
|
|
+ ret |= phy_write(phydev, MII_BMCR, BMCR_RESET | phy_read(phydev, MII_BMCR));
|
|
+
|
|
+ msleep(20);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int maxio_mae0621a_suspend(struct phy_device *phydev)
|
|
+{
|
|
+ genphy_suspend(phydev);
|
|
+ phy_write(phydev, MAXIO_PAGE_SELECT ,0);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int maxio_mae0621a_status(struct phy_device *phydev)
|
|
+{
|
|
+ return genphy_read_status(phydev);
|
|
+}
|
|
+
|
|
+static int maxio_mae0621a_probe(struct phy_device *phydev)
|
|
+{
|
|
+ int ret = maxio_mae0621a_clk_init(phydev);
|
|
+ mdelay(100);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static struct phy_driver maxio_nc_drvs[] = {
|
|
+ {
|
|
+ .phy_id = 0x7b744411,
|
|
+ .phy_id_mask = 0x7fffffff,
|
|
+ .name = "MAE0621A Gigabit Ethernet",
|
|
+ .features = PHY_GBIT_FEATURES,
|
|
+ .probe = maxio_mae0621a_probe,
|
|
+ .config_init = maxio_mae0621a_config_init,
|
|
+ .config_aneg = maxio_mae0621a_config_aneg,
|
|
+ .read_status = maxio_mae0621a_status,
|
|
+ .suspend = maxio_mae0621a_suspend,
|
|
+ .resume = maxio_mae0621a_resume,
|
|
+ },
|
|
+};
|
|
+module_phy_driver(maxio_nc_drvs);
|
|
+
|
|
+MODULE_DESCRIPTION("Maxio PHY driver");
|
|
+MODULE_AUTHOR("Zhao Yang");
|
|
+MODULE_LICENSE("GPL");
|
|
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
|
|
index 46713d27412b..1a9514360673 100644
|
|
--- a/drivers/net/phy/phy_device.c
|
|
+++ b/drivers/net/phy/phy_device.c
|
|
@@ -858,10 +858,19 @@ static int get_phy_c45_ids(struct mii_bus *bus, int addr,
|
|
*/
|
|
static int get_phy_c22_id(struct mii_bus *bus, int addr, u32 *phy_id)
|
|
{
|
|
int phy_reg;
|
|
|
|
+#ifdef CONFIG_MAXIO_PHY
|
|
+ /*
|
|
+ *An MDIO connects to multiple PHYs requiring write before read.
|
|
+ *This operation does not affect one MDIO connected to a single PHY
|
|
+ *MII_PHYSID2 is a read-only register and writine to it has no effect
|
|
+ */
|
|
+ mdiobus_write(bus,addr,MII_PHYSID2,0);
|
|
+#endif
|
|
+
|
|
/* Grab the bits from PHYIR1, and put them in the upper half */
|
|
phy_reg = mdiobus_read(bus, addr, MII_PHYSID1);
|
|
if (phy_reg < 0) {
|
|
/* returning -ENODEV doesn't stop bus scanning */
|
|
return (phy_reg == -EIO || phy_reg == -ENODEV) ? -ENODEV : -EIO;
|
|
--
|
|
Created with Armbian build tools https://github.com/armbian/build
|
|
|