Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

+134 -21
+6
Documentation/devicetree/bindings/net/dsa/brcm,b53.yaml
··· 66 66 - brcm,bcm63268-switch 67 67 - const: brcm,bcm63xx-switch 68 68 69 + brcm,gpio-ctrl: 70 + description: 71 + A phandle to the syscon node of the bcm63xx gpio controller 72 + which contains phy control registers 73 + $ref: /schemas/types.yaml#/definitions/phandle 74 + 69 75 required: 70 76 - compatible 71 77 - reg
+12 -15
drivers/net/dsa/b53/b53_common.c
··· 689 689 690 690 cpu_port = dsa_to_port(ds, port)->cpu_dp->index; 691 691 692 + if (dev->ops->phy_enable) 693 + dev->ops->phy_enable(dev, port); 694 + 692 695 if (dev->ops->irq_enable) 693 696 ret = dev->ops->irq_enable(dev, port); 694 697 if (ret) ··· 729 726 b53_read8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), &reg); 730 727 reg |= PORT_CTRL_RX_DISABLE | PORT_CTRL_TX_DISABLE; 731 728 b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), reg); 729 + 730 + if (dev->ops->phy_disable) 731 + dev->ops->phy_disable(dev, port); 732 732 733 733 if (dev->ops->irq_disable) 734 734 dev->ops->irq_disable(dev, port); ··· 1410 1404 b53_read8(dev, B53_CTRL_PAGE, B53_RGMII_CTRL_P(port), &rgmii_ctrl); 1411 1405 rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC); 1412 1406 1413 - if (is63268(dev)) 1407 + if (is6318_268(dev)) 1414 1408 rgmii_ctrl |= RGMII_CTRL_MII_OVERRIDE; 1415 1409 1416 1410 rgmii_ctrl |= RGMII_CTRL_ENABLE_GMII; ··· 2775 2769 .jumbo_size_reg = B53_JUMBO_MAX_SIZE_63XX, 2776 2770 }, 2777 2771 { 2778 - .chip_id = BCM63268_DEVICE_ID, 2779 - .dev_name = "BCM63268", 2780 - .vlans = 4096, 2781 - .enabled_ports = 0, /* pdata must provide them */ 2782 - .arl_bins = 4, 2783 - .arl_buckets = 1024, 2784 - .imp_port = 8, 2785 - .vta_regs = B53_VTA_REGS_63XX, 2786 - .duplex_reg = B53_DUPLEX_STAT_63XX, 2787 - .jumbo_pm_reg = B53_JUMBO_PORT_MASK_63XX, 2788 - .jumbo_size_reg = B53_JUMBO_MAX_SIZE_63XX, 2789 - }, 2790 - { 2791 2772 .chip_id = BCM53010_DEVICE_ID, 2792 2773 .dev_name = "BCM53010", 2793 2774 .vlans = 4096, ··· 2923 2930 2924 2931 static int b53_switch_init(struct b53_device *dev) 2925 2932 { 2933 + u32 chip_id = dev->chip_id; 2926 2934 unsigned int i; 2927 2935 int ret; 2936 + 2937 + if (is63xx(dev)) 2938 + chip_id = BCM63XX_DEVICE_ID; 2928 2939 2929 2940 for (i = 0; i < ARRAY_SIZE(b53_switch_chips); i++) { 2930 2941 const struct b53_chip_data *chip = &b53_switch_chips[i]; 2931 2942 2932 - if (chip->chip_id == dev->chip_id) { 2943 + if (chip->chip_id == chip_id) { 2933 2944 if (!dev->enabled_ports) 2934 2945 dev->enabled_ports = chip->enabled_ports; 2935 2946 dev->name = chip->dev_name;
+103 -4
drivers/net/dsa/b53/b53_mmap.c
··· 21 21 #include <linux/module.h> 22 22 #include <linux/of.h> 23 23 #include <linux/io.h> 24 + #include <linux/mfd/syscon.h> 24 25 #include <linux/platform_device.h> 25 26 #include <linux/platform_data/b53.h> 27 + #include <linux/regmap.h> 26 28 27 29 #include "b53_priv.h" 28 30 31 + #define BCM63XX_EPHY_REG 0x3C 32 + 33 + struct b53_phy_info { 34 + u32 ephy_enable_mask; 35 + u32 ephy_port_mask; 36 + u32 ephy_bias_bit; 37 + const u32 *ephy_offset; 38 + }; 39 + 29 40 struct b53_mmap_priv { 30 41 void __iomem *regs; 42 + struct regmap *gpio_ctrl; 43 + const struct b53_phy_info *phy_info; 44 + u32 phys_enabled; 45 + }; 46 + 47 + static const u32 bcm6318_ephy_offsets[] = {4, 5, 6, 7}; 48 + 49 + static const struct b53_phy_info bcm6318_ephy_info = { 50 + .ephy_enable_mask = BIT(0) | BIT(4) | BIT(8) | BIT(12) | BIT(16), 51 + .ephy_port_mask = GENMASK((ARRAY_SIZE(bcm6318_ephy_offsets) - 1), 0), 52 + .ephy_bias_bit = 24, 53 + .ephy_offset = bcm6318_ephy_offsets, 54 + }; 55 + 56 + static const u32 bcm6368_ephy_offsets[] = {2, 3, 4, 5}; 57 + 58 + static const struct b53_phy_info bcm6368_ephy_info = { 59 + .ephy_enable_mask = BIT(0), 60 + .ephy_port_mask = GENMASK((ARRAY_SIZE(bcm6368_ephy_offsets) - 1), 0), 61 + .ephy_bias_bit = 0, 62 + .ephy_offset = bcm6368_ephy_offsets, 63 + }; 64 + 65 + static const u32 bcm63268_ephy_offsets[] = {4, 9, 14}; 66 + 67 + static const struct b53_phy_info bcm63268_ephy_info = { 68 + .ephy_enable_mask = GENMASK(4, 0), 69 + .ephy_port_mask = GENMASK((ARRAY_SIZE(bcm63268_ephy_offsets) - 1), 0), 70 + .ephy_bias_bit = 24, 71 + .ephy_offset = bcm63268_ephy_offsets, 31 72 }; 32 73 33 74 static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) ··· 270 229 return -EIO; 271 230 } 272 231 232 + static int bcm63xx_ephy_set(struct b53_device *dev, int port, bool enable) 233 + { 234 + struct b53_mmap_priv *priv = dev->priv; 235 + const struct b53_phy_info *info = priv->phy_info; 236 + struct regmap *gpio_ctrl = priv->gpio_ctrl; 237 + u32 mask, val; 238 + 239 + if (enable) { 240 + mask = (info->ephy_enable_mask << info->ephy_offset[port]) 241 + | BIT(info->ephy_bias_bit); 242 + val = 0; 243 + } else { 244 + mask = (info->ephy_enable_mask << info->ephy_offset[port]); 245 + if (!((priv->phys_enabled & ~BIT(port)) & info->ephy_port_mask)) 246 + mask |= BIT(info->ephy_bias_bit); 247 + val = mask; 248 + } 249 + return regmap_update_bits(gpio_ctrl, BCM63XX_EPHY_REG, mask, val); 250 + } 251 + 252 + static void b53_mmap_phy_enable(struct b53_device *dev, int port) 253 + { 254 + struct b53_mmap_priv *priv = dev->priv; 255 + int ret = 0; 256 + 257 + if (priv->phy_info && (BIT(port) & priv->phy_info->ephy_port_mask)) 258 + ret = bcm63xx_ephy_set(dev, port, true); 259 + 260 + if (!ret) 261 + priv->phys_enabled |= BIT(port); 262 + } 263 + 264 + static void b53_mmap_phy_disable(struct b53_device *dev, int port) 265 + { 266 + struct b53_mmap_priv *priv = dev->priv; 267 + int ret = 0; 268 + 269 + if (priv->phy_info && (BIT(port) & priv->phy_info->ephy_port_mask)) 270 + ret = bcm63xx_ephy_set(dev, port, false); 271 + 272 + if (!ret) 273 + priv->phys_enabled &= ~BIT(port); 274 + } 275 + 273 276 static const struct b53_io_ops b53_mmap_ops = { 274 277 .read8 = b53_mmap_read8, 275 278 .read16 = b53_mmap_read16, ··· 327 242 .write64 = b53_mmap_write64, 328 243 .phy_read16 = b53_mmap_phy_read16, 329 244 .phy_write16 = b53_mmap_phy_write16, 245 + .phy_enable = b53_mmap_phy_enable, 246 + .phy_disable = b53_mmap_phy_disable, 330 247 }; 331 248 332 249 static int b53_mmap_probe_of(struct platform_device *pdev, ··· 400 313 401 314 priv->regs = pdata->regs; 402 315 316 + priv->gpio_ctrl = syscon_regmap_lookup_by_phandle(np, "brcm,gpio-ctrl"); 317 + if (!IS_ERR(priv->gpio_ctrl)) { 318 + if (pdata->chip_id == BCM6318_DEVICE_ID || 319 + pdata->chip_id == BCM6328_DEVICE_ID || 320 + pdata->chip_id == BCM6362_DEVICE_ID) 321 + priv->phy_info = &bcm6318_ephy_info; 322 + else if (pdata->chip_id == BCM6368_DEVICE_ID) 323 + priv->phy_info = &bcm6368_ephy_info; 324 + else if (pdata->chip_id == BCM63268_DEVICE_ID) 325 + priv->phy_info = &bcm63268_ephy_info; 326 + } 327 + 403 328 dev = b53_switch_alloc(&pdev->dev, &b53_mmap_ops, priv); 404 329 if (!dev) 405 330 return -ENOMEM; ··· 447 348 .data = (void *)BCM63XX_DEVICE_ID, 448 349 }, { 449 350 .compatible = "brcm,bcm6318-switch", 450 - .data = (void *)BCM63268_DEVICE_ID, 351 + .data = (void *)BCM6318_DEVICE_ID, 451 352 }, { 452 353 .compatible = "brcm,bcm6328-switch", 453 - .data = (void *)BCM63XX_DEVICE_ID, 354 + .data = (void *)BCM6328_DEVICE_ID, 454 355 }, { 455 356 .compatible = "brcm,bcm6362-switch", 456 - .data = (void *)BCM63XX_DEVICE_ID, 357 + .data = (void *)BCM6362_DEVICE_ID, 457 358 }, { 458 359 .compatible = "brcm,bcm6368-switch", 459 - .data = (void *)BCM63XX_DEVICE_ID, 360 + .data = (void *)BCM6368_DEVICE_ID, 460 361 }, { 461 362 .compatible = "brcm,bcm63268-switch", 462 363 .data = (void *)BCM63268_DEVICE_ID,
+13 -2
drivers/net/dsa/b53/b53_priv.h
··· 45 45 int (*phy_write16)(struct b53_device *dev, int addr, int reg, u16 value); 46 46 int (*irq_enable)(struct b53_device *dev, int port); 47 47 void (*irq_disable)(struct b53_device *dev, int port); 48 + void (*phy_enable)(struct b53_device *dev, int port); 49 + void (*phy_disable)(struct b53_device *dev, int port); 48 50 void (*phylink_get_caps)(struct b53_device *dev, int port, 49 51 struct phylink_config *config); 50 52 struct phylink_pcs *(*phylink_mac_select_pcs)(struct b53_device *dev, ··· 73 71 BCM53125_DEVICE_ID = 0x53125, 74 72 BCM53128_DEVICE_ID = 0x53128, 75 73 BCM63XX_DEVICE_ID = 0x6300, 74 + BCM6318_DEVICE_ID = 0x6318, 75 + BCM6328_DEVICE_ID = 0x6328, 76 + BCM6362_DEVICE_ID = 0x6362, 77 + BCM6368_DEVICE_ID = 0x6368, 76 78 BCM63268_DEVICE_ID = 0x63268, 77 79 BCM53010_DEVICE_ID = 0x53010, 78 80 BCM53011_DEVICE_ID = 0x53011, ··· 224 218 static inline int is63xx(struct b53_device *dev) 225 219 { 226 220 return dev->chip_id == BCM63XX_DEVICE_ID || 221 + dev->chip_id == BCM6318_DEVICE_ID || 222 + dev->chip_id == BCM6328_DEVICE_ID || 223 + dev->chip_id == BCM6362_DEVICE_ID || 224 + dev->chip_id == BCM6368_DEVICE_ID || 227 225 dev->chip_id == BCM63268_DEVICE_ID; 228 226 } 229 227 230 - static inline int is63268(struct b53_device *dev) 228 + static inline int is6318_268(struct b53_device *dev) 231 229 { 232 - return dev->chip_id == BCM63268_DEVICE_ID; 230 + return dev->chip_id == BCM6318_DEVICE_ID || 231 + dev->chip_id == BCM63268_DEVICE_ID; 233 232 } 234 233 235 234 static inline int is5301x(struct b53_device *dev)