Merge branch 'net-dsa-b53-mmap-add-bcm63xx-ephy-power-control'

Kyle Hendry says:

====================
net: dsa: b53: mmap: Add bcm63xx EPHY power control

The gpio controller on some bcm63xx SoCs has a register for
controlling functionality of the internal fast ethernet phys.
These patches allow the b53 driver to enable/disable phy
power.

The register also contains reset bits which will be set by
a reset driver in another patch series:
https://lore.kernel.org/all/20250715234605.36216-1-kylehendrydev@gmail.com/

v1: https://lore.kernel.org/20250716002922.230807-1-kylehendrydev@gmail.com
====================

Link: https://patch.msgid.link/20250724035300.20497-1-kylehendrydev@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2025-07-25 14:07:39 -07:00
commit cf51016ba8
4 changed files with 134 additions and 21 deletions

View File

@ -66,6 +66,12 @@ properties:
- brcm,bcm63268-switch
- const: brcm,bcm63xx-switch
brcm,gpio-ctrl:
description:
A phandle to the syscon node of the bcm63xx gpio controller
which contains phy control registers
$ref: /schemas/types.yaml#/definitions/phandle
required:
- compatible
- reg

View File

@ -689,6 +689,9 @@ int b53_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy)
cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
if (dev->ops->phy_enable)
dev->ops->phy_enable(dev, port);
if (dev->ops->irq_enable)
ret = dev->ops->irq_enable(dev, port);
if (ret)
@ -727,6 +730,9 @@ void b53_disable_port(struct dsa_switch *ds, int port)
reg |= PORT_CTRL_RX_DISABLE | PORT_CTRL_TX_DISABLE;
b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), reg);
if (dev->ops->phy_disable)
dev->ops->phy_disable(dev, port);
if (dev->ops->irq_disable)
dev->ops->irq_disable(dev, port);
}
@ -1404,7 +1410,7 @@ static void b53_adjust_63xx_rgmii(struct dsa_switch *ds, int port,
b53_read8(dev, B53_CTRL_PAGE, B53_RGMII_CTRL_P(port), &rgmii_ctrl);
rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC);
if (is63268(dev))
if (is6318_268(dev))
rgmii_ctrl |= RGMII_CTRL_MII_OVERRIDE;
rgmii_ctrl |= RGMII_CTRL_ENABLE_GMII;
@ -2768,19 +2774,6 @@ static const struct b53_chip_data b53_switch_chips[] = {
.jumbo_pm_reg = B53_JUMBO_PORT_MASK_63XX,
.jumbo_size_reg = B53_JUMBO_MAX_SIZE_63XX,
},
{
.chip_id = BCM63268_DEVICE_ID,
.dev_name = "BCM63268",
.vlans = 4096,
.enabled_ports = 0, /* pdata must provide them */
.arl_bins = 4,
.arl_buckets = 1024,
.imp_port = 8,
.vta_regs = B53_VTA_REGS_63XX,
.duplex_reg = B53_DUPLEX_STAT_63XX,
.jumbo_pm_reg = B53_JUMBO_PORT_MASK_63XX,
.jumbo_size_reg = B53_JUMBO_MAX_SIZE_63XX,
},
{
.chip_id = BCM53010_DEVICE_ID,
.dev_name = "BCM53010",
@ -2930,13 +2923,17 @@ static const struct b53_chip_data b53_switch_chips[] = {
static int b53_switch_init(struct b53_device *dev)
{
u32 chip_id = dev->chip_id;
unsigned int i;
int ret;
if (is63xx(dev))
chip_id = BCM63XX_DEVICE_ID;
for (i = 0; i < ARRAY_SIZE(b53_switch_chips); i++) {
const struct b53_chip_data *chip = &b53_switch_chips[i];
if (chip->chip_id == dev->chip_id) {
if (chip->chip_id == chip_id) {
if (!dev->enabled_ports)
dev->enabled_ports = chip->enabled_ports;
dev->name = chip->dev_name;

View File

@ -21,13 +21,54 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/io.h>
#include <linux/mfd/syscon.h>
#include <linux/platform_device.h>
#include <linux/platform_data/b53.h>
#include <linux/regmap.h>
#include "b53_priv.h"
#define BCM63XX_EPHY_REG 0x3C
struct b53_phy_info {
u32 ephy_enable_mask;
u32 ephy_port_mask;
u32 ephy_bias_bit;
const u32 *ephy_offset;
};
struct b53_mmap_priv {
void __iomem *regs;
struct regmap *gpio_ctrl;
const struct b53_phy_info *phy_info;
u32 phys_enabled;
};
static const u32 bcm6318_ephy_offsets[] = {4, 5, 6, 7};
static const struct b53_phy_info bcm6318_ephy_info = {
.ephy_enable_mask = BIT(0) | BIT(4) | BIT(8) | BIT(12) | BIT(16),
.ephy_port_mask = GENMASK((ARRAY_SIZE(bcm6318_ephy_offsets) - 1), 0),
.ephy_bias_bit = 24,
.ephy_offset = bcm6318_ephy_offsets,
};
static const u32 bcm6368_ephy_offsets[] = {2, 3, 4, 5};
static const struct b53_phy_info bcm6368_ephy_info = {
.ephy_enable_mask = BIT(0),
.ephy_port_mask = GENMASK((ARRAY_SIZE(bcm6368_ephy_offsets) - 1), 0),
.ephy_bias_bit = 0,
.ephy_offset = bcm6368_ephy_offsets,
};
static const u32 bcm63268_ephy_offsets[] = {4, 9, 14};
static const struct b53_phy_info bcm63268_ephy_info = {
.ephy_enable_mask = GENMASK(4, 0),
.ephy_port_mask = GENMASK((ARRAY_SIZE(bcm63268_ephy_offsets) - 1), 0),
.ephy_bias_bit = 24,
.ephy_offset = bcm63268_ephy_offsets,
};
static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
@ -229,6 +270,50 @@ static int b53_mmap_phy_write16(struct b53_device *dev, int addr, int reg,
return -EIO;
}
static int bcm63xx_ephy_set(struct b53_device *dev, int port, bool enable)
{
struct b53_mmap_priv *priv = dev->priv;
const struct b53_phy_info *info = priv->phy_info;
struct regmap *gpio_ctrl = priv->gpio_ctrl;
u32 mask, val;
if (enable) {
mask = (info->ephy_enable_mask << info->ephy_offset[port])
| BIT(info->ephy_bias_bit);
val = 0;
} else {
mask = (info->ephy_enable_mask << info->ephy_offset[port]);
if (!((priv->phys_enabled & ~BIT(port)) & info->ephy_port_mask))
mask |= BIT(info->ephy_bias_bit);
val = mask;
}
return regmap_update_bits(gpio_ctrl, BCM63XX_EPHY_REG, mask, val);
}
static void b53_mmap_phy_enable(struct b53_device *dev, int port)
{
struct b53_mmap_priv *priv = dev->priv;
int ret = 0;
if (priv->phy_info && (BIT(port) & priv->phy_info->ephy_port_mask))
ret = bcm63xx_ephy_set(dev, port, true);
if (!ret)
priv->phys_enabled |= BIT(port);
}
static void b53_mmap_phy_disable(struct b53_device *dev, int port)
{
struct b53_mmap_priv *priv = dev->priv;
int ret = 0;
if (priv->phy_info && (BIT(port) & priv->phy_info->ephy_port_mask))
ret = bcm63xx_ephy_set(dev, port, false);
if (!ret)
priv->phys_enabled &= ~BIT(port);
}
static const struct b53_io_ops b53_mmap_ops = {
.read8 = b53_mmap_read8,
.read16 = b53_mmap_read16,
@ -242,6 +327,8 @@ static const struct b53_io_ops b53_mmap_ops = {
.write64 = b53_mmap_write64,
.phy_read16 = b53_mmap_phy_read16,
.phy_write16 = b53_mmap_phy_write16,
.phy_enable = b53_mmap_phy_enable,
.phy_disable = b53_mmap_phy_disable,
};
static int b53_mmap_probe_of(struct platform_device *pdev,
@ -313,6 +400,18 @@ static int b53_mmap_probe(struct platform_device *pdev)
priv->regs = pdata->regs;
priv->gpio_ctrl = syscon_regmap_lookup_by_phandle(np, "brcm,gpio-ctrl");
if (!IS_ERR(priv->gpio_ctrl)) {
if (pdata->chip_id == BCM6318_DEVICE_ID ||
pdata->chip_id == BCM6328_DEVICE_ID ||
pdata->chip_id == BCM6362_DEVICE_ID)
priv->phy_info = &bcm6318_ephy_info;
else if (pdata->chip_id == BCM6368_DEVICE_ID)
priv->phy_info = &bcm6368_ephy_info;
else if (pdata->chip_id == BCM63268_DEVICE_ID)
priv->phy_info = &bcm63268_ephy_info;
}
dev = b53_switch_alloc(&pdev->dev, &b53_mmap_ops, priv);
if (!dev)
return -ENOMEM;
@ -348,16 +447,16 @@ static const struct of_device_id b53_mmap_of_table[] = {
.data = (void *)BCM63XX_DEVICE_ID,
}, {
.compatible = "brcm,bcm6318-switch",
.data = (void *)BCM63268_DEVICE_ID,
.data = (void *)BCM6318_DEVICE_ID,
}, {
.compatible = "brcm,bcm6328-switch",
.data = (void *)BCM63XX_DEVICE_ID,
.data = (void *)BCM6328_DEVICE_ID,
}, {
.compatible = "brcm,bcm6362-switch",
.data = (void *)BCM63XX_DEVICE_ID,
.data = (void *)BCM6362_DEVICE_ID,
}, {
.compatible = "brcm,bcm6368-switch",
.data = (void *)BCM63XX_DEVICE_ID,
.data = (void *)BCM6368_DEVICE_ID,
}, {
.compatible = "brcm,bcm63268-switch",
.data = (void *)BCM63268_DEVICE_ID,

View File

@ -45,6 +45,8 @@ struct b53_io_ops {
int (*phy_write16)(struct b53_device *dev, int addr, int reg, u16 value);
int (*irq_enable)(struct b53_device *dev, int port);
void (*irq_disable)(struct b53_device *dev, int port);
void (*phy_enable)(struct b53_device *dev, int port);
void (*phy_disable)(struct b53_device *dev, int port);
void (*phylink_get_caps)(struct b53_device *dev, int port,
struct phylink_config *config);
struct phylink_pcs *(*phylink_mac_select_pcs)(struct b53_device *dev,
@ -71,6 +73,10 @@ enum {
BCM53125_DEVICE_ID = 0x53125,
BCM53128_DEVICE_ID = 0x53128,
BCM63XX_DEVICE_ID = 0x6300,
BCM6318_DEVICE_ID = 0x6318,
BCM6328_DEVICE_ID = 0x6328,
BCM6362_DEVICE_ID = 0x6362,
BCM6368_DEVICE_ID = 0x6368,
BCM63268_DEVICE_ID = 0x63268,
BCM53010_DEVICE_ID = 0x53010,
BCM53011_DEVICE_ID = 0x53011,
@ -218,12 +224,17 @@ static inline int is531x5(struct b53_device *dev)
static inline int is63xx(struct b53_device *dev)
{
return dev->chip_id == BCM63XX_DEVICE_ID ||
dev->chip_id == BCM6318_DEVICE_ID ||
dev->chip_id == BCM6328_DEVICE_ID ||
dev->chip_id == BCM6362_DEVICE_ID ||
dev->chip_id == BCM6368_DEVICE_ID ||
dev->chip_id == BCM63268_DEVICE_ID;
}
static inline int is63268(struct b53_device *dev)
static inline int is6318_268(struct b53_device *dev)
{
return dev->chip_id == BCM63268_DEVICE_ID;
return dev->chip_id == BCM6318_DEVICE_ID ||
dev->chip_id == BCM63268_DEVICE_ID;
}
static inline int is5301x(struct b53_device *dev)