1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (c) 2026 David Yang 4 */ 5 6 #include <linux/of_mdio.h> 7 8 #include "chip.h" 9 #include "mdio_bus.h" 10 #include "smi.h" 11 12 static int yt921x_intif_wait(struct yt921x_priv *priv) 13 { 14 u32 val = 0; 15 16 return yt921x_reg_wait(priv, YT921X_INT_MBUS_OP, YT921X_MBUS_OP_START, 17 &val); 18 } 19 20 int yt921x_intif_read(struct yt921x_priv *priv, int port, int reg, u16 *valp) 21 { 22 struct device *dev = yt921x_priv_to_device(priv); 23 u32 mask; 24 u32 ctrl; 25 u32 val; 26 int res; 27 28 res = yt921x_intif_wait(priv); 29 if (res) 30 return res; 31 32 mask = YT921X_MBUS_CTRL_PORT_M | YT921X_MBUS_CTRL_REG_M | 33 YT921X_MBUS_CTRL_OP_M; 34 ctrl = YT921X_MBUS_CTRL_PORT(port) | YT921X_MBUS_CTRL_REG(reg) | 35 YT921X_MBUS_CTRL_READ; 36 res = yt921x_reg_update_bits(priv, YT921X_INT_MBUS_CTRL, mask, ctrl); 37 if (res) 38 return res; 39 res = yt921x_reg_write(priv, YT921X_INT_MBUS_OP, YT921X_MBUS_OP_START); 40 if (res) 41 return res; 42 43 res = yt921x_intif_wait(priv); 44 if (res) 45 return res; 46 res = yt921x_reg_read(priv, YT921X_INT_MBUS_DIN, &val); 47 if (res) 48 return res; 49 50 if ((u16)val != val) 51 dev_info(dev, 52 "%s: port %d, reg 0x%x: Expected u16, got 0x%08x\n", 53 __func__, port, reg, val); 54 *valp = (u16)val; 55 return 0; 56 } 57 58 int yt921x_intif_write(struct yt921x_priv *priv, int port, int reg, u16 val) 59 { 60 u32 mask; 61 u32 ctrl; 62 int res; 63 64 res = yt921x_intif_wait(priv); 65 if (res) 66 return res; 67 68 mask = YT921X_MBUS_CTRL_PORT_M | YT921X_MBUS_CTRL_REG_M | 69 YT921X_MBUS_CTRL_OP_M; 70 ctrl = YT921X_MBUS_CTRL_PORT(port) | YT921X_MBUS_CTRL_REG(reg) | 71 YT921X_MBUS_CTRL_WRITE; 72 res = yt921x_reg_update_bits(priv, YT921X_INT_MBUS_CTRL, mask, ctrl); 73 if (res) 74 return res; 75 res = yt921x_reg_write(priv, YT921X_INT_MBUS_DOUT, val); 76 if (res) 77 return res; 78 res = yt921x_reg_write(priv, YT921X_INT_MBUS_OP, YT921X_MBUS_OP_START); 79 if (res) 80 return res; 81 82 return yt921x_intif_wait(priv); 83 } 84 85 int 86 yt921x_intif_modify_changed(struct yt921x_priv *priv, int port, int reg, 87 u16 mask, u16 val) 88 { 89 int res; 90 u16 v; 91 u16 u; 92 93 res = yt921x_intif_read(priv, port, reg, &v); 94 if (res) 95 return res; 96 97 u = v; 98 u &= ~mask; 99 u |= val; 100 if (u == v) 101 return 0; 102 103 res = yt921x_intif_write(priv, port, reg, u); 104 if (res) 105 return res; 106 107 return 1; 108 } 109 110 static int yt921x_mbus_int_read(struct mii_bus *mbus, int port, int reg) 111 { 112 struct yt921x_priv *priv = mbus->priv; 113 u16 val; 114 int res; 115 116 if (port >= YT921X_PORT_NUM) 117 return U16_MAX; 118 119 mutex_lock(&priv->reg_lock); 120 res = yt921x_intif_read(priv, port, reg, &val); 121 mutex_unlock(&priv->reg_lock); 122 123 if (res) 124 return res; 125 return val; 126 } 127 128 static int 129 yt921x_mbus_int_write(struct mii_bus *mbus, int port, int reg, u16 data) 130 { 131 struct yt921x_priv *priv = mbus->priv; 132 int res; 133 134 if (port >= YT921X_PORT_NUM) 135 return -ENODEV; 136 137 mutex_lock(&priv->reg_lock); 138 res = yt921x_intif_write(priv, port, reg, data); 139 mutex_unlock(&priv->reg_lock); 140 141 return res; 142 } 143 144 int yt921x_mbus_int_init(struct yt921x_priv *priv, struct device_node *mnp) 145 { 146 struct device *dev = yt921x_priv_to_device(priv); 147 struct mii_bus *mbus; 148 int res; 149 150 mbus = devm_mdiobus_alloc(dev); 151 if (!mbus) 152 return -ENOMEM; 153 154 mbus->name = "YT921x internal MDIO bus"; 155 snprintf(mbus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev)); 156 mbus->priv = priv; 157 mbus->read = yt921x_mbus_int_read; 158 mbus->write = yt921x_mbus_int_write; 159 mbus->parent = dev; 160 mbus->phy_mask = (u32)~GENMASK(YT921X_PORT_NUM - 1, 0); 161 162 res = devm_of_mdiobus_register(dev, mbus, mnp); 163 if (res) 164 return res; 165 166 priv->mbus_int = mbus; 167 168 return 0; 169 } 170 171 static int yt921x_extif_wait(struct yt921x_priv *priv) 172 { 173 u32 val = 0; 174 175 return yt921x_reg_wait(priv, YT921X_EXT_MBUS_OP, YT921X_MBUS_OP_START, 176 &val); 177 } 178 179 static int 180 yt921x_extif_read(struct yt921x_priv *priv, int port, int reg, u16 *valp) 181 { 182 struct device *dev = yt921x_priv_to_device(priv); 183 u32 mask; 184 u32 ctrl; 185 u32 val; 186 int res; 187 188 res = yt921x_extif_wait(priv); 189 if (res) 190 return res; 191 192 mask = YT921X_MBUS_CTRL_PORT_M | YT921X_MBUS_CTRL_REG_M | 193 YT921X_MBUS_CTRL_TYPE_M | YT921X_MBUS_CTRL_OP_M; 194 ctrl = YT921X_MBUS_CTRL_PORT(port) | YT921X_MBUS_CTRL_REG(reg) | 195 YT921X_MBUS_CTRL_TYPE_C22 | YT921X_MBUS_CTRL_READ; 196 res = yt921x_reg_update_bits(priv, YT921X_EXT_MBUS_CTRL, mask, ctrl); 197 if (res) 198 return res; 199 res = yt921x_reg_write(priv, YT921X_EXT_MBUS_OP, YT921X_MBUS_OP_START); 200 if (res) 201 return res; 202 203 res = yt921x_extif_wait(priv); 204 if (res) 205 return res; 206 res = yt921x_reg_read(priv, YT921X_EXT_MBUS_DIN, &val); 207 if (res) 208 return res; 209 210 if ((u16)val != val) 211 dev_info(dev, 212 "%s: port %d, reg 0x%x: Expected u16, got 0x%08x\n", 213 __func__, port, reg, val); 214 *valp = (u16)val; 215 return 0; 216 } 217 218 static int 219 yt921x_extif_write(struct yt921x_priv *priv, int port, int reg, u16 val) 220 { 221 u32 mask; 222 u32 ctrl; 223 int res; 224 225 res = yt921x_extif_wait(priv); 226 if (res) 227 return res; 228 229 mask = YT921X_MBUS_CTRL_PORT_M | YT921X_MBUS_CTRL_REG_M | 230 YT921X_MBUS_CTRL_TYPE_M | YT921X_MBUS_CTRL_OP_M; 231 ctrl = YT921X_MBUS_CTRL_PORT(port) | YT921X_MBUS_CTRL_REG(reg) | 232 YT921X_MBUS_CTRL_TYPE_C22 | YT921X_MBUS_CTRL_WRITE; 233 res = yt921x_reg_update_bits(priv, YT921X_EXT_MBUS_CTRL, mask, ctrl); 234 if (res) 235 return res; 236 res = yt921x_reg_write(priv, YT921X_EXT_MBUS_DOUT, val); 237 if (res) 238 return res; 239 res = yt921x_reg_write(priv, YT921X_EXT_MBUS_OP, YT921X_MBUS_OP_START); 240 if (res) 241 return res; 242 243 return yt921x_extif_wait(priv); 244 } 245 246 static int yt921x_mbus_ext_read(struct mii_bus *mbus, int port, int reg) 247 { 248 struct yt921x_priv *priv = mbus->priv; 249 u16 val; 250 int res; 251 252 mutex_lock(&priv->reg_lock); 253 res = yt921x_extif_read(priv, port, reg, &val); 254 mutex_unlock(&priv->reg_lock); 255 256 if (res) 257 return res; 258 return val; 259 } 260 261 static int 262 yt921x_mbus_ext_write(struct mii_bus *mbus, int port, int reg, u16 data) 263 { 264 struct yt921x_priv *priv = mbus->priv; 265 int res; 266 267 mutex_lock(&priv->reg_lock); 268 res = yt921x_extif_write(priv, port, reg, data); 269 mutex_unlock(&priv->reg_lock); 270 271 return res; 272 } 273 274 int yt921x_mbus_ext_init(struct yt921x_priv *priv, struct device_node *mnp) 275 { 276 struct device *dev = yt921x_priv_to_device(priv); 277 struct mii_bus *mbus; 278 int res; 279 280 mbus = devm_mdiobus_alloc(dev); 281 if (!mbus) 282 return -ENOMEM; 283 284 mbus->name = "YT921x external MDIO bus"; 285 snprintf(mbus->id, MII_BUS_ID_SIZE, "%s@ext", dev_name(dev)); 286 mbus->priv = priv; 287 /* TODO: c45? */ 288 mbus->read = yt921x_mbus_ext_read; 289 mbus->write = yt921x_mbus_ext_write; 290 mbus->parent = dev; 291 292 res = devm_of_mdiobus_register(dev, mbus, mnp); 293 if (res) 294 return res; 295 296 priv->mbus_ext = mbus; 297 298 return 0; 299 } 300