Commit aa80511a authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'net-mscc-miim-add-integrated-phy-reset-support'

Michael Walle says:

====================
net: mscc-miim: add integrated PHY reset support

The MDIO driver has support to release the integrated PHYs from reset.
This was implemented for the SparX-5 for now. Now add support for the
LAN966x, too.
====================

Link: https://lore.kernel.org/r/20220318201324.1647416-1-michael@walle.ccSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents c050f5e9 74529db3
...@@ -2,7 +2,7 @@ Microsemi MII Management Controller (MIIM) / MDIO ...@@ -2,7 +2,7 @@ Microsemi MII Management Controller (MIIM) / MDIO
================================================= =================================================
Properties: Properties:
- compatible: must be "mscc,ocelot-miim" - compatible: must be "mscc,ocelot-miim" or "microchip,lan966x-miim"
- reg: The base address of the MDIO bus controller register bank. Optionally, a - reg: The base address of the MDIO bus controller register bank. Optionally, a
second register bank can be defined if there is an associated reset register second register bank can be defined if there is an associated reset register
for internal PHYs for internal PHYs
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/of_mdio.h> #include <linux/of_mdio.h>
#include <linux/phy.h> #include <linux/phy.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#define MSCC_MIIM_REG_STATUS 0x0 #define MSCC_MIIM_REG_STATUS 0x0
...@@ -36,11 +37,19 @@ ...@@ -36,11 +37,19 @@
#define PHY_CFG_PHY_RESET (BIT(5) | BIT(6) | BIT(7) | BIT(8)) #define PHY_CFG_PHY_RESET (BIT(5) | BIT(6) | BIT(7) | BIT(8))
#define MSCC_PHY_REG_PHY_STATUS 0x4 #define MSCC_PHY_REG_PHY_STATUS 0x4
#define LAN966X_CUPHY_COMMON_CFG 0x0
#define CUPHY_COMMON_CFG_RESET_N BIT(0)
struct mscc_miim_info {
unsigned int phy_reset_offset;
unsigned int phy_reset_bits;
};
struct mscc_miim_dev { struct mscc_miim_dev {
struct regmap *regs; struct regmap *regs;
int mii_status_offset; int mii_status_offset;
struct regmap *phy_regs; struct regmap *phy_regs;
int phy_reset_offset; const struct mscc_miim_info *info;
}; };
/* When high resolution timers aren't built-in: we can't use usleep_range() as /* When high resolution timers aren't built-in: we can't use usleep_range() as
...@@ -157,27 +166,29 @@ static int mscc_miim_write(struct mii_bus *bus, int mii_id, ...@@ -157,27 +166,29 @@ static int mscc_miim_write(struct mii_bus *bus, int mii_id,
static int mscc_miim_reset(struct mii_bus *bus) static int mscc_miim_reset(struct mii_bus *bus)
{ {
struct mscc_miim_dev *miim = bus->priv; struct mscc_miim_dev *miim = bus->priv;
int offset = miim->phy_reset_offset; unsigned int offset, bits;
int ret; int ret;
if (miim->phy_regs) { if (!miim->phy_regs)
ret = regmap_write(miim->phy_regs, return 0;
MSCC_PHY_REG_PHY_CFG + offset, 0);
if (ret < 0) {
WARN_ONCE(1, "mscc reset set error %d\n", ret);
return ret;
}
ret = regmap_write(miim->phy_regs, offset = miim->info->phy_reset_offset;
MSCC_PHY_REG_PHY_CFG + offset, 0x1ff); bits = miim->info->phy_reset_bits;
if (ret < 0) {
WARN_ONCE(1, "mscc reset clear error %d\n", ret); ret = regmap_update_bits(miim->phy_regs, offset, bits, 0);
return ret; if (ret < 0) {
} WARN_ONCE(1, "mscc reset set error %d\n", ret);
return ret;
}
mdelay(500); ret = regmap_update_bits(miim->phy_regs, offset, bits, bits);
if (ret < 0) {
WARN_ONCE(1, "mscc reset clear error %d\n", ret);
return ret;
} }
mdelay(500);
return 0; return 0;
} }
...@@ -272,7 +283,10 @@ static int mscc_miim_probe(struct platform_device *pdev) ...@@ -272,7 +283,10 @@ static int mscc_miim_probe(struct platform_device *pdev)
miim = bus->priv; miim = bus->priv;
miim->phy_regs = phy_regmap; miim->phy_regs = phy_regmap;
miim->phy_reset_offset = 0;
miim->info = device_get_match_data(&pdev->dev);
if (!miim->info)
return -EINVAL;
ret = of_mdiobus_register(bus, pdev->dev.of_node); ret = of_mdiobus_register(bus, pdev->dev.of_node);
if (ret < 0) { if (ret < 0) {
...@@ -294,8 +308,25 @@ static int mscc_miim_remove(struct platform_device *pdev) ...@@ -294,8 +308,25 @@ static int mscc_miim_remove(struct platform_device *pdev)
return 0; return 0;
} }
static const struct mscc_miim_info mscc_ocelot_miim_info = {
.phy_reset_offset = MSCC_PHY_REG_PHY_CFG,
.phy_reset_bits = PHY_CFG_PHY_ENA | PHY_CFG_PHY_COMMON_RESET |
PHY_CFG_PHY_RESET,
};
static const struct mscc_miim_info microchip_lan966x_miim_info = {
.phy_reset_offset = LAN966X_CUPHY_COMMON_CFG,
.phy_reset_bits = CUPHY_COMMON_CFG_RESET_N,
};
static const struct of_device_id mscc_miim_match[] = { static const struct of_device_id mscc_miim_match[] = {
{ .compatible = "mscc,ocelot-miim" }, {
.compatible = "mscc,ocelot-miim",
.data = &mscc_ocelot_miim_info
}, {
.compatible = "microchip,lan966x-miim",
.data = &microchip_lan966x_miim_info
},
{ } { }
}; };
MODULE_DEVICE_TABLE(of, mscc_miim_match); MODULE_DEVICE_TABLE(of, mscc_miim_match);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment