1 // SPDX-License-Identifier: GPL-2.0 2 /* Renesas Ethernet SERDES device driver 3 * 4 * Copyright (C) 2022 Renesas Electronics Corporation 5 */ 6 7 #include <linux/delay.h> 8 #include <linux/err.h> 9 #include <linux/iopoll.h> 10 #include <linux/kernel.h> 11 #include <linux/of.h> 12 #include <linux/phy.h> 13 #include <linux/phy/phy.h> 14 #include <linux/platform_device.h> 15 #include <linux/reset.h> 16 17 #define R8A779F0_ETH_SERDES_NUM 3 18 #define R8A779F0_ETH_SERDES_OFFSET 0x0400 19 #define R8A779F0_ETH_SERDES_BANK_SELECT 0x03fc 20 #define R8A779F0_ETH_SERDES_TIMEOUT_US 100000 21 #define R8A779F0_ETH_SERDES_NUM_RETRY_LINKUP 3 22 23 struct r8a779f0_eth_serdes_drv_data; 24 struct r8a779f0_eth_serdes_channel { 25 struct r8a779f0_eth_serdes_drv_data *dd; 26 struct phy *phy; 27 void __iomem *addr; 28 phy_interface_t phy_interface; 29 int speed; 30 int index; 31 }; 32 33 struct r8a779f0_eth_serdes_drv_data { 34 void __iomem *addr; 35 struct platform_device *pdev; 36 struct reset_control *reset; 37 struct r8a779f0_eth_serdes_channel channel[R8A779F0_ETH_SERDES_NUM]; 38 bool initialized; 39 }; 40 41 /* 42 * The datasheet describes initialization procedure without any information 43 * about registers' name/bits. So, this is all black magic to initialize 44 * the hardware. 45 */ 46 static void r8a779f0_eth_serdes_write32(void __iomem *addr, u32 offs, u32 bank, u32 data) 47 { 48 iowrite32(bank, addr + R8A779F0_ETH_SERDES_BANK_SELECT); 49 iowrite32(data, addr + offs); 50 } 51 52 static int 53 r8a779f0_eth_serdes_reg_wait(struct r8a779f0_eth_serdes_channel *channel, 54 u32 offs, u32 bank, u32 mask, u32 expected) 55 { 56 int ret; 57 u32 val; 58 59 iowrite32(bank, channel->addr + R8A779F0_ETH_SERDES_BANK_SELECT); 60 61 ret = readl_poll_timeout_atomic(channel->addr + offs, val, 62 (val & mask) == expected, 63 1, R8A779F0_ETH_SERDES_TIMEOUT_US); 64 if (ret) 65 dev_dbg(&channel->phy->dev, 66 "%s: index %d, offs %x, bank %x, mask %x, expected %x\n", 67 __func__, channel->index, offs, bank, mask, expected); 68 69 return ret; 70 } 71 72 static int 73 r8a779f0_eth_serdes_common_init_ram(struct r8a779f0_eth_serdes_drv_data *dd) 74 { 75 struct r8a779f0_eth_serdes_channel *channel; 76 int i, ret; 77 78 for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) { 79 channel = &dd->channel[i]; 80 ret = r8a779f0_eth_serdes_reg_wait(channel, 0x026c, 0x180, BIT(0), 0x01); 81 if (ret) 82 return ret; 83 } 84 85 r8a779f0_eth_serdes_write32(dd->addr, 0x026c, 0x180, 0x03); 86 87 return ret; 88 } 89 90 static int 91 r8a779f0_eth_serdes_common_setting(struct r8a779f0_eth_serdes_channel *channel) 92 { 93 struct r8a779f0_eth_serdes_drv_data *dd = channel->dd; 94 95 switch (channel->phy_interface) { 96 case PHY_INTERFACE_MODE_SGMII: 97 r8a779f0_eth_serdes_write32(dd->addr, 0x0244, 0x180, 0x0097); 98 r8a779f0_eth_serdes_write32(dd->addr, 0x01d0, 0x180, 0x0060); 99 r8a779f0_eth_serdes_write32(dd->addr, 0x01d8, 0x180, 0x2200); 100 r8a779f0_eth_serdes_write32(dd->addr, 0x01d4, 0x180, 0x0000); 101 r8a779f0_eth_serdes_write32(dd->addr, 0x01e0, 0x180, 0x003d); 102 return 0; 103 default: 104 return -EOPNOTSUPP; 105 } 106 } 107 108 static int 109 r8a779f0_eth_serdes_chan_setting(struct r8a779f0_eth_serdes_channel *channel) 110 { 111 int ret; 112 113 switch (channel->phy_interface) { 114 case PHY_INTERFACE_MODE_SGMII: 115 r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x380, 0x2000); 116 r8a779f0_eth_serdes_write32(channel->addr, 0x01c0, 0x180, 0x0011); 117 r8a779f0_eth_serdes_write32(channel->addr, 0x0248, 0x180, 0x0540); 118 r8a779f0_eth_serdes_write32(channel->addr, 0x0258, 0x180, 0x0015); 119 r8a779f0_eth_serdes_write32(channel->addr, 0x0144, 0x180, 0x0100); 120 r8a779f0_eth_serdes_write32(channel->addr, 0x01a0, 0x180, 0x0000); 121 r8a779f0_eth_serdes_write32(channel->addr, 0x00d0, 0x180, 0x0002); 122 r8a779f0_eth_serdes_write32(channel->addr, 0x0150, 0x180, 0x0003); 123 r8a779f0_eth_serdes_write32(channel->addr, 0x00c8, 0x180, 0x0100); 124 r8a779f0_eth_serdes_write32(channel->addr, 0x0148, 0x180, 0x0100); 125 r8a779f0_eth_serdes_write32(channel->addr, 0x0174, 0x180, 0x0000); 126 r8a779f0_eth_serdes_write32(channel->addr, 0x0160, 0x180, 0x0007); 127 r8a779f0_eth_serdes_write32(channel->addr, 0x01ac, 0x180, 0x0000); 128 r8a779f0_eth_serdes_write32(channel->addr, 0x00c4, 0x180, 0x0310); 129 r8a779f0_eth_serdes_write32(channel->addr, 0x00c8, 0x180, 0x0101); 130 ret = r8a779f0_eth_serdes_reg_wait(channel, 0x00c8, 0x0180, BIT(0), 0); 131 if (ret) 132 return ret; 133 134 r8a779f0_eth_serdes_write32(channel->addr, 0x0148, 0x180, 0x0101); 135 ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0148, 0x0180, BIT(0), 0); 136 if (ret) 137 return ret; 138 139 r8a779f0_eth_serdes_write32(channel->addr, 0x00c4, 0x180, 0x1310); 140 r8a779f0_eth_serdes_write32(channel->addr, 0x00d8, 0x180, 0x1800); 141 r8a779f0_eth_serdes_write32(channel->addr, 0x00dc, 0x180, 0x0000); 142 r8a779f0_eth_serdes_write32(channel->addr, 0x001c, 0x300, 0x0001); 143 r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x380, 0x2100); 144 ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0000, 0x0380, BIT(8), 0); 145 if (ret) 146 return ret; 147 148 if (channel->speed == 1000) 149 r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x1f00, 0x0140); 150 else if (channel->speed == 100) 151 r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x1f00, 0x2100); 152 153 /* For AN_ON */ 154 r8a779f0_eth_serdes_write32(channel->addr, 0x0004, 0x1f80, 0x0005); 155 r8a779f0_eth_serdes_write32(channel->addr, 0x0028, 0x1f80, 0x07a1); 156 r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x1f80, 0x0208); 157 break; 158 default: 159 return -EOPNOTSUPP; 160 } 161 162 return 0; 163 } 164 165 static int 166 r8a779f0_eth_serdes_chan_speed(struct r8a779f0_eth_serdes_channel *channel) 167 { 168 int ret; 169 170 switch (channel->phy_interface) { 171 case PHY_INTERFACE_MODE_SGMII: 172 /* For AN_ON */ 173 if (channel->speed == 1000) 174 r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x1f00, 0x1140); 175 else if (channel->speed == 100) 176 r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x1f00, 0x3100); 177 ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0008, 0x1f80, BIT(0), 1); 178 if (ret) 179 return ret; 180 r8a779f0_eth_serdes_write32(channel->addr, 0x0008, 0x1f80, 0x0000); 181 break; 182 default: 183 return -EOPNOTSUPP; 184 } 185 186 return 0; 187 } 188 189 190 static int r8a779f0_eth_serdes_monitor_linkup(struct r8a779f0_eth_serdes_channel *channel) 191 { 192 int i, ret; 193 194 for (i = 0; i < R8A779F0_ETH_SERDES_NUM_RETRY_LINKUP; i++) { 195 ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0004, 0x300, 196 BIT(2), BIT(2)); 197 if (!ret) 198 break; 199 200 /* restart */ 201 r8a779f0_eth_serdes_write32(channel->addr, 0x0144, 0x180, 0x0100); 202 udelay(1); 203 r8a779f0_eth_serdes_write32(channel->addr, 0x0144, 0x180, 0x0000); 204 } 205 206 return ret; 207 } 208 209 static int r8a779f0_eth_serdes_hw_init(struct r8a779f0_eth_serdes_channel *channel) 210 { 211 struct r8a779f0_eth_serdes_drv_data *dd = channel->dd; 212 int i, ret; 213 214 if (dd->initialized) 215 return 0; 216 217 ret = r8a779f0_eth_serdes_common_init_ram(dd); 218 if (ret) 219 return ret; 220 221 for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) { 222 ret = r8a779f0_eth_serdes_reg_wait(&dd->channel[i], 0x0000, 223 0x300, BIT(15), 0); 224 if (ret) 225 return ret; 226 } 227 228 for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) 229 r8a779f0_eth_serdes_write32(dd->channel[i].addr, 0x03d4, 0x380, 0x0443); 230 231 ret = r8a779f0_eth_serdes_common_setting(channel); 232 if (ret) 233 return ret; 234 235 for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) 236 r8a779f0_eth_serdes_write32(dd->channel[i].addr, 0x03d0, 0x380, 0x0001); 237 238 239 r8a779f0_eth_serdes_write32(dd->addr, 0x0000, 0x380, 0x8000); 240 241 ret = r8a779f0_eth_serdes_common_init_ram(dd); 242 if (ret) 243 return ret; 244 245 return r8a779f0_eth_serdes_reg_wait(&dd->channel[0], 0x0000, 0x380, BIT(15), 0); 246 } 247 248 static int r8a779f0_eth_serdes_init(struct phy *p) 249 { 250 struct r8a779f0_eth_serdes_channel *channel = phy_get_drvdata(p); 251 int ret; 252 253 ret = r8a779f0_eth_serdes_hw_init(channel); 254 if (!ret) 255 channel->dd->initialized = true; 256 257 return ret; 258 } 259 260 static int r8a779f0_eth_serdes_hw_init_late(struct r8a779f0_eth_serdes_channel 261 *channel) 262 { 263 int ret; 264 265 ret = r8a779f0_eth_serdes_chan_setting(channel); 266 if (ret) 267 return ret; 268 269 ret = r8a779f0_eth_serdes_chan_speed(channel); 270 if (ret) 271 return ret; 272 273 r8a779f0_eth_serdes_write32(channel->addr, 0x03c0, 0x380, 0x0000); 274 275 r8a779f0_eth_serdes_write32(channel->addr, 0x03d0, 0x380, 0x0000); 276 277 return r8a779f0_eth_serdes_monitor_linkup(channel); 278 } 279 280 static int r8a779f0_eth_serdes_power_on(struct phy *p) 281 { 282 struct r8a779f0_eth_serdes_channel *channel = phy_get_drvdata(p); 283 284 return r8a779f0_eth_serdes_hw_init_late(channel); 285 } 286 287 static int r8a779f0_eth_serdes_set_mode(struct phy *p, enum phy_mode mode, 288 int submode) 289 { 290 struct r8a779f0_eth_serdes_channel *channel = phy_get_drvdata(p); 291 292 if (mode != PHY_MODE_ETHERNET) 293 return -EOPNOTSUPP; 294 295 switch (submode) { 296 case PHY_INTERFACE_MODE_GMII: 297 case PHY_INTERFACE_MODE_SGMII: 298 case PHY_INTERFACE_MODE_USXGMII: 299 channel->phy_interface = submode; 300 return 0; 301 default: 302 return -EOPNOTSUPP; 303 } 304 } 305 306 static int r8a779f0_eth_serdes_set_speed(struct phy *p, int speed) 307 { 308 struct r8a779f0_eth_serdes_channel *channel = phy_get_drvdata(p); 309 310 channel->speed = speed; 311 312 return 0; 313 } 314 315 static const struct phy_ops r8a779f0_eth_serdes_ops = { 316 .init = r8a779f0_eth_serdes_init, 317 .power_on = r8a779f0_eth_serdes_power_on, 318 .set_mode = r8a779f0_eth_serdes_set_mode, 319 .set_speed = r8a779f0_eth_serdes_set_speed, 320 }; 321 322 static struct phy *r8a779f0_eth_serdes_xlate(struct device *dev, 323 struct of_phandle_args *args) 324 { 325 struct r8a779f0_eth_serdes_drv_data *dd = dev_get_drvdata(dev); 326 327 if (args->args[0] >= R8A779F0_ETH_SERDES_NUM) 328 return ERR_PTR(-ENODEV); 329 330 return dd->channel[args->args[0]].phy; 331 } 332 333 static const struct of_device_id r8a779f0_eth_serdes_of_table[] = { 334 { .compatible = "renesas,r8a779f0-ether-serdes", }, 335 { } 336 }; 337 MODULE_DEVICE_TABLE(of, r8a779f0_eth_serdes_of_table); 338 339 static int r8a779f0_eth_serdes_probe(struct platform_device *pdev) 340 { 341 struct r8a779f0_eth_serdes_drv_data *dd; 342 struct phy_provider *provider; 343 int i; 344 345 dd = devm_kzalloc(&pdev->dev, sizeof(*dd), GFP_KERNEL); 346 if (!dd) 347 return -ENOMEM; 348 349 platform_set_drvdata(pdev, dd); 350 dd->pdev = pdev; 351 dd->addr = devm_platform_ioremap_resource(pdev, 0); 352 if (IS_ERR(dd->addr)) 353 return PTR_ERR(dd->addr); 354 355 dd->reset = devm_reset_control_get(&pdev->dev, NULL); 356 if (IS_ERR(dd->reset)) 357 return PTR_ERR(dd->reset); 358 359 reset_control_reset(dd->reset); 360 361 for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) { 362 struct r8a779f0_eth_serdes_channel *channel = &dd->channel[i]; 363 364 channel->phy = devm_phy_create(&pdev->dev, NULL, 365 &r8a779f0_eth_serdes_ops); 366 if (IS_ERR(channel->phy)) 367 return PTR_ERR(channel->phy); 368 channel->addr = dd->addr + R8A779F0_ETH_SERDES_OFFSET * i; 369 channel->dd = dd; 370 channel->index = i; 371 phy_set_drvdata(channel->phy, channel); 372 } 373 374 provider = devm_of_phy_provider_register(&pdev->dev, 375 r8a779f0_eth_serdes_xlate); 376 if (IS_ERR(provider)) 377 return PTR_ERR(provider); 378 379 pm_runtime_enable(&pdev->dev); 380 pm_runtime_get_sync(&pdev->dev); 381 382 return 0; 383 } 384 385 static void r8a779f0_eth_serdes_remove(struct platform_device *pdev) 386 { 387 pm_runtime_put(&pdev->dev); 388 pm_runtime_disable(&pdev->dev); 389 390 platform_set_drvdata(pdev, NULL); 391 } 392 393 static struct platform_driver r8a779f0_eth_serdes_driver_platform = { 394 .probe = r8a779f0_eth_serdes_probe, 395 .remove_new = r8a779f0_eth_serdes_remove, 396 .driver = { 397 .name = "r8a779f0_eth_serdes", 398 .of_match_table = r8a779f0_eth_serdes_of_table, 399 } 400 }; 401 module_platform_driver(r8a779f0_eth_serdes_driver_platform); 402 MODULE_AUTHOR("Yoshihiro Shimoda"); 403 MODULE_DESCRIPTION("Renesas Ethernet SERDES device driver"); 404 MODULE_LICENSE("GPL"); 405