enetc_mdio.c (4388B)
1// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 2/* Copyright 2019 NXP */ 3 4#include <linux/fsl/enetc_mdio.h> 5#include <linux/mdio.h> 6#include <linux/of_mdio.h> 7#include <linux/iopoll.h> 8#include <linux/of.h> 9 10#include "enetc_pf.h" 11 12#define ENETC_MDIO_CFG 0x0 /* MDIO configuration and status */ 13#define ENETC_MDIO_CTL 0x4 /* MDIO control */ 14#define ENETC_MDIO_DATA 0x8 /* MDIO data */ 15#define ENETC_MDIO_ADDR 0xc /* MDIO address */ 16 17#define MDIO_CFG_CLKDIV(x) ((((x) >> 1) & 0xff) << 8) 18#define MDIO_CFG_BSY BIT(0) 19#define MDIO_CFG_RD_ER BIT(1) 20#define MDIO_CFG_HOLD(x) (((x) << 2) & GENMASK(4, 2)) 21#define MDIO_CFG_ENC45 BIT(6) 22 /* external MDIO only - driven on neg MDC edge */ 23#define MDIO_CFG_NEG BIT(23) 24 25#define ENETC_EMDIO_CFG \ 26 (MDIO_CFG_HOLD(2) | \ 27 MDIO_CFG_CLKDIV(258) | \ 28 MDIO_CFG_NEG) 29 30#define MDIO_CTL_DEV_ADDR(x) ((x) & 0x1f) 31#define MDIO_CTL_PORT_ADDR(x) (((x) & 0x1f) << 5) 32#define MDIO_CTL_READ BIT(15) 33 34static inline u32 enetc_mdio_rd(struct enetc_mdio_priv *mdio_priv, int off) 35{ 36 return enetc_port_rd_mdio(mdio_priv->hw, mdio_priv->mdio_base + off); 37} 38 39static inline void enetc_mdio_wr(struct enetc_mdio_priv *mdio_priv, int off, 40 u32 val) 41{ 42 enetc_port_wr_mdio(mdio_priv->hw, mdio_priv->mdio_base + off, val); 43} 44 45static bool enetc_mdio_is_busy(struct enetc_mdio_priv *mdio_priv) 46{ 47 return enetc_mdio_rd(mdio_priv, ENETC_MDIO_CFG) & MDIO_CFG_BSY; 48} 49 50static int enetc_mdio_wait_complete(struct enetc_mdio_priv *mdio_priv) 51{ 52 bool is_busy; 53 54 return readx_poll_timeout(enetc_mdio_is_busy, mdio_priv, 55 is_busy, !is_busy, 10, 10 * 1000); 56} 57 58int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value) 59{ 60 struct enetc_mdio_priv *mdio_priv = bus->priv; 61 u32 mdio_ctl, mdio_cfg; 62 u16 dev_addr; 63 int ret; 64 65 mdio_cfg = ENETC_EMDIO_CFG; 66 if (regnum & MII_ADDR_C45) { 67 dev_addr = (regnum >> 16) & 0x1f; 68 mdio_cfg |= MDIO_CFG_ENC45; 69 } else { 70 /* clause 22 (ie 1G) */ 71 dev_addr = regnum & 0x1f; 72 mdio_cfg &= ~MDIO_CFG_ENC45; 73 } 74 75 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg); 76 77 ret = enetc_mdio_wait_complete(mdio_priv); 78 if (ret) 79 return ret; 80 81 /* set port and dev addr */ 82 mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); 83 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl); 84 85 /* set the register address */ 86 if (regnum & MII_ADDR_C45) { 87 enetc_mdio_wr(mdio_priv, ENETC_MDIO_ADDR, regnum & 0xffff); 88 89 ret = enetc_mdio_wait_complete(mdio_priv); 90 if (ret) 91 return ret; 92 } 93 94 /* write the value */ 95 enetc_mdio_wr(mdio_priv, ENETC_MDIO_DATA, value); 96 97 ret = enetc_mdio_wait_complete(mdio_priv); 98 if (ret) 99 return ret; 100 101 return 0; 102} 103EXPORT_SYMBOL_GPL(enetc_mdio_write); 104 105int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum) 106{ 107 struct enetc_mdio_priv *mdio_priv = bus->priv; 108 u32 mdio_ctl, mdio_cfg; 109 u16 dev_addr, value; 110 int ret; 111 112 mdio_cfg = ENETC_EMDIO_CFG; 113 if (regnum & MII_ADDR_C45) { 114 dev_addr = (regnum >> 16) & 0x1f; 115 mdio_cfg |= MDIO_CFG_ENC45; 116 } else { 117 dev_addr = regnum & 0x1f; 118 mdio_cfg &= ~MDIO_CFG_ENC45; 119 } 120 121 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg); 122 123 ret = enetc_mdio_wait_complete(mdio_priv); 124 if (ret) 125 return ret; 126 127 /* set port and device addr */ 128 mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); 129 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl); 130 131 /* set the register address */ 132 if (regnum & MII_ADDR_C45) { 133 enetc_mdio_wr(mdio_priv, ENETC_MDIO_ADDR, regnum & 0xffff); 134 135 ret = enetc_mdio_wait_complete(mdio_priv); 136 if (ret) 137 return ret; 138 } 139 140 /* initiate the read */ 141 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl | MDIO_CTL_READ); 142 143 ret = enetc_mdio_wait_complete(mdio_priv); 144 if (ret) 145 return ret; 146 147 /* return all Fs if nothing was there */ 148 if (enetc_mdio_rd(mdio_priv, ENETC_MDIO_CFG) & MDIO_CFG_RD_ER) { 149 dev_dbg(&bus->dev, 150 "Error while reading PHY%d reg at %d.%d\n", 151 phy_id, dev_addr, regnum); 152 return 0xffff; 153 } 154 155 value = enetc_mdio_rd(mdio_priv, ENETC_MDIO_DATA) & 0xffff; 156 157 return value; 158} 159EXPORT_SYMBOL_GPL(enetc_mdio_read); 160 161struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs) 162{ 163 struct enetc_hw *hw; 164 165 hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); 166 if (!hw) 167 return ERR_PTR(-ENOMEM); 168 169 hw->port = port_regs; 170 171 return hw; 172} 173EXPORT_SYMBOL_GPL(enetc_hw_alloc); 174 175/* Lock for MDIO access errata on LS1028A */ 176DEFINE_RWLOCK(enetc_mdio_lock); 177EXPORT_SYMBOL_GPL(enetc_mdio_lock);