653 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (c) 2014-2015 Hisilicon Limited.4 */5 6#include <linux/acpi.h>7#include <linux/errno.h>8#include <linux/etherdevice.h>9#include <linux/init.h>10#include <linux/kernel.h>11#include <linux/mfd/syscon.h>12#include <linux/module.h>13#include <linux/mutex.h>14#include <linux/netdevice.h>15#include <linux/of_address.h>16#include <linux/of.h>17#include <linux/of_mdio.h>18#include <linux/of_platform.h>19#include <linux/phy.h>20#include <linux/platform_device.h>21#include <linux/regmap.h>22 23#define MDIO_DRV_NAME "Hi-HNS_MDIO"24#define MDIO_BUS_NAME "Hisilicon MII Bus"25 26#define MDIO_TIMEOUT 100000027 28struct hns_mdio_sc_reg {29 u16 mdio_clk_en;30 u16 mdio_clk_dis;31 u16 mdio_reset_req;32 u16 mdio_reset_dreq;33 u16 mdio_clk_st;34 u16 mdio_reset_st;35};36 37struct hns_mdio_device {38 u8 __iomem *vbase; /* mdio reg base address */39 struct regmap *subctrl_vbase;40 struct hns_mdio_sc_reg sc_reg;41};42 43/* mdio reg */44#define MDIO_COMMAND_REG 0x045#define MDIO_ADDR_REG 0x446#define MDIO_WDATA_REG 0x847#define MDIO_RDATA_REG 0xc48#define MDIO_STA_REG 0x1049 50/* cfg phy bit map */51#define MDIO_CMD_DEVAD_M 0x1f52#define MDIO_CMD_DEVAD_S 053#define MDIO_CMD_PRTAD_M 0x1f54#define MDIO_CMD_PRTAD_S 555#define MDIO_CMD_OP_S 1056#define MDIO_CMD_ST_S 1257#define MDIO_CMD_START_B 1458 59#define MDIO_ADDR_DATA_M 0xffff60#define MDIO_ADDR_DATA_S 061 62#define MDIO_WDATA_DATA_M 0xffff63#define MDIO_WDATA_DATA_S 064 65#define MDIO_RDATA_DATA_M 0xffff66#define MDIO_RDATA_DATA_S 067 68#define MDIO_STATE_STA_B 069 70enum mdio_st_clause {71 MDIO_ST_CLAUSE_45 = 0,72 MDIO_ST_CLAUSE_2273};74 75enum mdio_c22_op_seq {76 MDIO_C22_WRITE = 1,77 MDIO_C22_READ = 278};79 80enum mdio_c45_op_seq {81 MDIO_C45_WRITE_ADDR = 0,82 MDIO_C45_WRITE_DATA,83 MDIO_C45_READ_INCREMENT,84 MDIO_C45_READ85};86 87/* peri subctrl reg */88#define MDIO_SC_CLK_EN 0x33889#define MDIO_SC_CLK_DIS 0x33C90#define MDIO_SC_RESET_REQ 0xA3891#define MDIO_SC_RESET_DREQ 0xA3C92#define MDIO_SC_CLK_ST 0x531C93#define MDIO_SC_RESET_ST 0x5A1C94 95static void mdio_write_reg(u8 __iomem *base, u32 reg, u32 value)96{97 writel_relaxed(value, base + reg);98}99 100#define MDIO_WRITE_REG(a, reg, value) \101 mdio_write_reg((a)->vbase, (reg), (value))102 103static u32 mdio_read_reg(u8 __iomem *base, u32 reg)104{105 return readl_relaxed(base + reg);106}107 108#define mdio_set_field(origin, mask, shift, val) \109 do { \110 (origin) &= (~((mask) << (shift))); \111 (origin) |= (((val) & (mask)) << (shift)); \112 } while (0)113 114#define mdio_get_field(origin, mask, shift) (((origin) >> (shift)) & (mask))115 116static void mdio_set_reg_field(u8 __iomem *base, u32 reg, u32 mask, u32 shift,117 u32 val)118{119 u32 origin = mdio_read_reg(base, reg);120 121 mdio_set_field(origin, mask, shift, val);122 mdio_write_reg(base, reg, origin);123}124 125#define MDIO_SET_REG_FIELD(dev, reg, mask, shift, val) \126 mdio_set_reg_field((dev)->vbase, (reg), (mask), (shift), (val))127 128static u32 mdio_get_reg_field(u8 __iomem *base, u32 reg, u32 mask, u32 shift)129{130 u32 origin;131 132 origin = mdio_read_reg(base, reg);133 return mdio_get_field(origin, mask, shift);134}135 136#define MDIO_GET_REG_FIELD(dev, reg, mask, shift) \137 mdio_get_reg_field((dev)->vbase, (reg), (mask), (shift))138 139#define MDIO_GET_REG_BIT(dev, reg, bit) \140 mdio_get_reg_field((dev)->vbase, (reg), 0x1ull, (bit))141 142#define MDIO_CHECK_SET_ST 1143#define MDIO_CHECK_CLR_ST 0144 145static int mdio_sc_cfg_reg_write(struct hns_mdio_device *mdio_dev,146 u32 cfg_reg, u32 set_val,147 u32 st_reg, u32 st_msk, u8 check_st)148{149 u32 time_cnt;150 u32 reg_value;151 int ret;152 153 regmap_write(mdio_dev->subctrl_vbase, cfg_reg, set_val);154 155 for (time_cnt = MDIO_TIMEOUT; time_cnt; time_cnt--) {156 ret = regmap_read(mdio_dev->subctrl_vbase, st_reg, ®_value);157 if (ret)158 return ret;159 160 reg_value &= st_msk;161 if ((!!check_st) == (!!reg_value))162 break;163 }164 165 if ((!!check_st) != (!!reg_value))166 return -EBUSY;167 168 return 0;169}170 171static int hns_mdio_wait_ready(struct mii_bus *bus)172{173 struct hns_mdio_device *mdio_dev = bus->priv;174 u32 cmd_reg_value;175 int i;176 177 /* waiting for MDIO_COMMAND_REG's mdio_start==0 */178 /* after that can do read or write*/179 for (i = 0; i < MDIO_TIMEOUT; i++) {180 cmd_reg_value = MDIO_GET_REG_BIT(mdio_dev,181 MDIO_COMMAND_REG,182 MDIO_CMD_START_B);183 if (!cmd_reg_value)184 break;185 }186 if ((i == MDIO_TIMEOUT) && cmd_reg_value)187 return -ETIMEDOUT;188 189 return 0;190}191 192static void hns_mdio_cmd_write(struct hns_mdio_device *mdio_dev,193 u8 is_c45, u8 op, u8 phy_id, u16 cmd)194{195 u32 cmd_reg_value;196 u8 st = is_c45 ? MDIO_ST_CLAUSE_45 : MDIO_ST_CLAUSE_22;197 198 cmd_reg_value = st << MDIO_CMD_ST_S;199 cmd_reg_value |= op << MDIO_CMD_OP_S;200 cmd_reg_value |=201 (phy_id & MDIO_CMD_PRTAD_M) << MDIO_CMD_PRTAD_S;202 cmd_reg_value |= (cmd & MDIO_CMD_DEVAD_M) << MDIO_CMD_DEVAD_S;203 cmd_reg_value |= 1 << MDIO_CMD_START_B;204 205 MDIO_WRITE_REG(mdio_dev, MDIO_COMMAND_REG, cmd_reg_value);206}207 208/**209 * hns_mdio_write_c22 - access phy register210 * @bus: mdio bus211 * @phy_id: phy id212 * @regnum: register num213 * @data: register value214 *215 * Return 0 on success, negative on failure216 */217static int hns_mdio_write_c22(struct mii_bus *bus,218 int phy_id, int regnum, u16 data)219{220 struct hns_mdio_device *mdio_dev = bus->priv;221 u16 reg = (u16)(regnum & 0xffff);222 u16 cmd_reg_cfg;223 int ret;224 u8 op;225 226 dev_dbg(&bus->dev, "mdio write %s,base is %p\n",227 bus->id, mdio_dev->vbase);228 dev_dbg(&bus->dev, "phy id=%d, reg=%#x, write data=%d\n",229 phy_id, reg, data);230 231 /* wait for ready */232 ret = hns_mdio_wait_ready(bus);233 if (ret) {234 dev_err(&bus->dev, "MDIO bus is busy\n");235 return ret;236 }237 238 cmd_reg_cfg = reg;239 op = MDIO_C22_WRITE;240 241 MDIO_SET_REG_FIELD(mdio_dev, MDIO_WDATA_REG, MDIO_WDATA_DATA_M,242 MDIO_WDATA_DATA_S, data);243 244 hns_mdio_cmd_write(mdio_dev, false, op, phy_id, cmd_reg_cfg);245 246 return 0;247}248 249/**250 * hns_mdio_write_c45 - access phy register251 * @bus: mdio bus252 * @phy_id: phy id253 * @devad: device address to read254 * @regnum: register num255 * @data: register value256 *257 * Return 0 on success, negative on failure258 */259static int hns_mdio_write_c45(struct mii_bus *bus, int phy_id, int devad,260 int regnum, u16 data)261{262 struct hns_mdio_device *mdio_dev = bus->priv;263 u16 reg = (u16)(regnum & 0xffff);264 u16 cmd_reg_cfg;265 int ret;266 u8 op;267 268 dev_dbg(&bus->dev, "mdio write %s,base is %p\n",269 bus->id, mdio_dev->vbase);270 dev_dbg(&bus->dev, "phy id=%d, devad=%d, reg=%#x, write data=%d\n",271 phy_id, devad, reg, data);272 273 /* wait for ready */274 ret = hns_mdio_wait_ready(bus);275 if (ret) {276 dev_err(&bus->dev, "MDIO bus is busy\n");277 return ret;278 }279 280 /* config the cmd-reg to write addr*/281 MDIO_SET_REG_FIELD(mdio_dev, MDIO_ADDR_REG, MDIO_ADDR_DATA_M,282 MDIO_ADDR_DATA_S, reg);283 284 hns_mdio_cmd_write(mdio_dev, true, MDIO_C45_WRITE_ADDR, phy_id, devad);285 286 /* check for read or write opt is finished */287 ret = hns_mdio_wait_ready(bus);288 if (ret) {289 dev_err(&bus->dev, "MDIO bus is busy\n");290 return ret;291 }292 293 /* config the data needed writing */294 cmd_reg_cfg = devad;295 op = MDIO_C45_WRITE_DATA;296 297 MDIO_SET_REG_FIELD(mdio_dev, MDIO_WDATA_REG, MDIO_WDATA_DATA_M,298 MDIO_WDATA_DATA_S, data);299 300 hns_mdio_cmd_write(mdio_dev, true, op, phy_id, cmd_reg_cfg);301 302 return 0;303}304 305/**306 * hns_mdio_read_c22 - access phy register307 * @bus: mdio bus308 * @phy_id: phy id309 * @regnum: register num310 *311 * Return phy register value312 */313static int hns_mdio_read_c22(struct mii_bus *bus, int phy_id, int regnum)314{315 struct hns_mdio_device *mdio_dev = bus->priv;316 u16 reg = (u16)(regnum & 0xffff);317 u16 reg_val;318 int ret;319 320 dev_dbg(&bus->dev, "mdio read %s,base is %p\n",321 bus->id, mdio_dev->vbase);322 dev_dbg(&bus->dev, "phy id=%d, reg=%#x!\n", phy_id, reg);323 324 /* Step 1: wait for ready */325 ret = hns_mdio_wait_ready(bus);326 if (ret) {327 dev_err(&bus->dev, "MDIO bus is busy\n");328 return ret;329 }330 331 hns_mdio_cmd_write(mdio_dev, false, MDIO_C22_READ, phy_id, reg);332 333 /* Step 2: waiting for MDIO_COMMAND_REG 's mdio_start==0,*/334 /* check for read or write opt is finished */335 ret = hns_mdio_wait_ready(bus);336 if (ret) {337 dev_err(&bus->dev, "MDIO bus is busy\n");338 return ret;339 }340 341 reg_val = MDIO_GET_REG_BIT(mdio_dev, MDIO_STA_REG, MDIO_STATE_STA_B);342 if (reg_val) {343 dev_err(&bus->dev, " ERROR! MDIO Read failed!\n");344 return -EBUSY;345 }346 347 /* Step 3; get out data*/348 reg_val = (u16)MDIO_GET_REG_FIELD(mdio_dev, MDIO_RDATA_REG,349 MDIO_RDATA_DATA_M, MDIO_RDATA_DATA_S);350 351 return reg_val;352}353 354/**355 * hns_mdio_read_c45 - access phy register356 * @bus: mdio bus357 * @phy_id: phy id358 * @devad: device address to read359 * @regnum: register num360 *361 * Return phy register value362 */363static int hns_mdio_read_c45(struct mii_bus *bus, int phy_id, int devad,364 int regnum)365{366 struct hns_mdio_device *mdio_dev = bus->priv;367 u16 reg = (u16)(regnum & 0xffff);368 u16 reg_val;369 int ret;370 371 dev_dbg(&bus->dev, "mdio read %s,base is %p\n",372 bus->id, mdio_dev->vbase);373 dev_dbg(&bus->dev, "phy id=%d, devad=%d, reg=%#x!\n",374 phy_id, devad, reg);375 376 /* Step 1: wait for ready */377 ret = hns_mdio_wait_ready(bus);378 if (ret) {379 dev_err(&bus->dev, "MDIO bus is busy\n");380 return ret;381 }382 383 MDIO_SET_REG_FIELD(mdio_dev, MDIO_ADDR_REG, MDIO_ADDR_DATA_M,384 MDIO_ADDR_DATA_S, reg);385 386 /* Step 2; config the cmd-reg to write addr*/387 hns_mdio_cmd_write(mdio_dev, true, MDIO_C45_WRITE_ADDR, phy_id, devad);388 389 /* Step 3: check for read or write opt is finished */390 ret = hns_mdio_wait_ready(bus);391 if (ret) {392 dev_err(&bus->dev, "MDIO bus is busy\n");393 return ret;394 }395 396 hns_mdio_cmd_write(mdio_dev, true, MDIO_C45_READ, phy_id, devad);397 398 /* Step 5: waiting for MDIO_COMMAND_REG 's mdio_start==0,*/399 /* check for read or write opt is finished */400 ret = hns_mdio_wait_ready(bus);401 if (ret) {402 dev_err(&bus->dev, "MDIO bus is busy\n");403 return ret;404 }405 406 reg_val = MDIO_GET_REG_BIT(mdio_dev, MDIO_STA_REG, MDIO_STATE_STA_B);407 if (reg_val) {408 dev_err(&bus->dev, " ERROR! MDIO Read failed!\n");409 return -EBUSY;410 }411 412 /* Step 6; get out data*/413 reg_val = (u16)MDIO_GET_REG_FIELD(mdio_dev, MDIO_RDATA_REG,414 MDIO_RDATA_DATA_M, MDIO_RDATA_DATA_S);415 416 return reg_val;417}418 419/**420 * hns_mdio_reset - reset mdio bus421 * @bus: mdio bus422 *423 * Return 0 on success, negative on failure424 */425static int hns_mdio_reset(struct mii_bus *bus)426{427 struct hns_mdio_device *mdio_dev = bus->priv;428 const struct hns_mdio_sc_reg *sc_reg;429 int ret;430 431 if (dev_of_node(bus->parent)) {432 if (!mdio_dev->subctrl_vbase) {433 dev_err(&bus->dev, "mdio sys ctl reg has not mapped\n");434 return -ENODEV;435 }436 437 sc_reg = &mdio_dev->sc_reg;438 /* 1. reset req, and read reset st check */439 ret = mdio_sc_cfg_reg_write(mdio_dev, sc_reg->mdio_reset_req,440 0x1, sc_reg->mdio_reset_st, 0x1,441 MDIO_CHECK_SET_ST);442 if (ret) {443 dev_err(&bus->dev, "MDIO reset fail\n");444 return ret;445 }446 447 /* 2. dis clk, and read clk st check */448 ret = mdio_sc_cfg_reg_write(mdio_dev, sc_reg->mdio_clk_dis,449 0x1, sc_reg->mdio_clk_st, 0x1,450 MDIO_CHECK_CLR_ST);451 if (ret) {452 dev_err(&bus->dev, "MDIO dis clk fail\n");453 return ret;454 }455 456 /* 3. reset dreq, and read reset st check */457 ret = mdio_sc_cfg_reg_write(mdio_dev, sc_reg->mdio_reset_dreq,458 0x1, sc_reg->mdio_reset_st, 0x1,459 MDIO_CHECK_CLR_ST);460 if (ret) {461 dev_err(&bus->dev, "MDIO dis clk fail\n");462 return ret;463 }464 465 /* 4. en clk, and read clk st check */466 ret = mdio_sc_cfg_reg_write(mdio_dev, sc_reg->mdio_clk_en,467 0x1, sc_reg->mdio_clk_st, 0x1,468 MDIO_CHECK_SET_ST);469 if (ret)470 dev_err(&bus->dev, "MDIO en clk fail\n");471 } else if (is_acpi_node(bus->parent->fwnode)) {472 acpi_status s;473 474 s = acpi_evaluate_object(ACPI_HANDLE(bus->parent),475 "_RST", NULL, NULL);476 if (ACPI_FAILURE(s)) {477 dev_err(&bus->dev, "Reset failed, return:%#x\n", s);478 ret = -EBUSY;479 } else {480 ret = 0;481 }482 } else {483 dev_err(&bus->dev, "Can not get cfg data from DT or ACPI\n");484 ret = -ENXIO;485 }486 return ret;487}488 489/**490 * hns_mdio_probe - probe mdio device491 * @pdev: mdio platform device492 *493 * Return 0 on success, negative on failure494 */495static int hns_mdio_probe(struct platform_device *pdev)496{497 struct hns_mdio_device *mdio_dev;498 struct mii_bus *new_bus;499 int ret;500 501 if (!pdev) {502 dev_err(NULL, "pdev is NULL!\r\n");503 return -ENODEV;504 }505 506 mdio_dev = devm_kzalloc(&pdev->dev, sizeof(*mdio_dev), GFP_KERNEL);507 if (!mdio_dev)508 return -ENOMEM;509 510 new_bus = devm_mdiobus_alloc(&pdev->dev);511 if (!new_bus) {512 dev_err(&pdev->dev, "mdiobus_alloc fail!\n");513 return -ENOMEM;514 }515 516 new_bus->name = MDIO_BUS_NAME;517 new_bus->read = hns_mdio_read_c22;518 new_bus->write = hns_mdio_write_c22;519 new_bus->read_c45 = hns_mdio_read_c45;520 new_bus->write_c45 = hns_mdio_write_c45;521 new_bus->reset = hns_mdio_reset;522 new_bus->priv = mdio_dev;523 new_bus->parent = &pdev->dev;524 525 mdio_dev->vbase = devm_platform_ioremap_resource(pdev, 0);526 if (IS_ERR(mdio_dev->vbase)) {527 ret = PTR_ERR(mdio_dev->vbase);528 return ret;529 }530 531 platform_set_drvdata(pdev, new_bus);532 snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%s", "Mii",533 dev_name(&pdev->dev));534 if (dev_of_node(&pdev->dev)) {535 struct of_phandle_args reg_args;536 537 ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,538 "subctrl-vbase",539 4,540 0,541 ®_args);542 if (!ret) {543 mdio_dev->subctrl_vbase =544 syscon_node_to_regmap(reg_args.np);545 if (IS_ERR(mdio_dev->subctrl_vbase)) {546 dev_warn(&pdev->dev, "syscon_node_to_regmap error\n");547 mdio_dev->subctrl_vbase = NULL;548 } else {549 if (reg_args.args_count == 4) {550 mdio_dev->sc_reg.mdio_clk_en =551 (u16)reg_args.args[0];552 mdio_dev->sc_reg.mdio_clk_dis =553 (u16)reg_args.args[0] + 4;554 mdio_dev->sc_reg.mdio_reset_req =555 (u16)reg_args.args[1];556 mdio_dev->sc_reg.mdio_reset_dreq =557 (u16)reg_args.args[1] + 4;558 mdio_dev->sc_reg.mdio_clk_st =559 (u16)reg_args.args[2];560 mdio_dev->sc_reg.mdio_reset_st =561 (u16)reg_args.args[3];562 } else {563 /* for compatible */564 mdio_dev->sc_reg.mdio_clk_en =565 MDIO_SC_CLK_EN;566 mdio_dev->sc_reg.mdio_clk_dis =567 MDIO_SC_CLK_DIS;568 mdio_dev->sc_reg.mdio_reset_req =569 MDIO_SC_RESET_REQ;570 mdio_dev->sc_reg.mdio_reset_dreq =571 MDIO_SC_RESET_DREQ;572 mdio_dev->sc_reg.mdio_clk_st =573 MDIO_SC_CLK_ST;574 mdio_dev->sc_reg.mdio_reset_st =575 MDIO_SC_RESET_ST;576 }577 }578 of_node_put(reg_args.np);579 } else {580 dev_warn(&pdev->dev, "find syscon ret = %#x\n", ret);581 mdio_dev->subctrl_vbase = NULL;582 }583 584 ret = of_mdiobus_register(new_bus, pdev->dev.of_node);585 } else if (is_acpi_node(pdev->dev.fwnode)) {586 /* Clear all the IRQ properties */587 memset(new_bus->irq, PHY_POLL, 4 * PHY_MAX_ADDR);588 589 /* Mask out all PHYs from auto probing. */590 new_bus->phy_mask = ~0;591 592 /* Register the MDIO bus */593 ret = mdiobus_register(new_bus);594 } else {595 dev_err(&pdev->dev, "Can not get cfg data from DT or ACPI\n");596 ret = -ENXIO;597 }598 599 if (ret) {600 dev_err(&pdev->dev, "Cannot register as MDIO bus!\n");601 platform_set_drvdata(pdev, NULL);602 return ret;603 }604 605 return 0;606}607 608/**609 * hns_mdio_remove - remove mdio device610 * @pdev: mdio platform device611 *612 * Return 0 on success, negative on failure613 */614static void hns_mdio_remove(struct platform_device *pdev)615{616 struct mii_bus *bus;617 618 bus = platform_get_drvdata(pdev);619 620 mdiobus_unregister(bus);621 platform_set_drvdata(pdev, NULL);622}623 624static const struct of_device_id hns_mdio_match[] = {625 {.compatible = "hisilicon,mdio"},626 {.compatible = "hisilicon,hns-mdio"},627 {}628};629MODULE_DEVICE_TABLE(of, hns_mdio_match);630 631static const struct acpi_device_id hns_mdio_acpi_match[] = {632 { "HISI0141", 0 },633 { },634};635MODULE_DEVICE_TABLE(acpi, hns_mdio_acpi_match);636 637static struct platform_driver hns_mdio_driver = {638 .probe = hns_mdio_probe,639 .remove_new = hns_mdio_remove,640 .driver = {641 .name = MDIO_DRV_NAME,642 .of_match_table = hns_mdio_match,643 .acpi_match_table = ACPI_PTR(hns_mdio_acpi_match),644 },645};646 647module_platform_driver(hns_mdio_driver);648 649MODULE_LICENSE("GPL");650MODULE_AUTHOR("Huawei Tech. Co., Ltd.");651MODULE_DESCRIPTION("Hisilicon HNS MDIO driver");652MODULE_ALIAS("platform:" MDIO_DRV_NAME);653