linux/drivers/net/ethernet/hisilicon/hns_mdio.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   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                    1000000
  27
  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                0x0
  45#define MDIO_ADDR_REG                   0x4
  46#define MDIO_WDATA_REG                  0x8
  47#define MDIO_RDATA_REG                  0xc
  48#define MDIO_STA_REG                    0x10
  49
  50/* cfg phy bit map */
  51#define MDIO_CMD_DEVAD_M        0x1f
  52#define MDIO_CMD_DEVAD_S        0
  53#define MDIO_CMD_PRTAD_M        0x1f
  54#define MDIO_CMD_PRTAD_S        5
  55#define MDIO_CMD_OP_S           10
  56#define MDIO_CMD_ST_S           12
  57#define MDIO_CMD_START_B        14
  58
  59#define MDIO_ADDR_DATA_M        0xffff
  60#define MDIO_ADDR_DATA_S        0
  61
  62#define MDIO_WDATA_DATA_M       0xffff
  63#define MDIO_WDATA_DATA_S       0
  64
  65#define MDIO_RDATA_DATA_M       0xffff
  66#define MDIO_RDATA_DATA_S       0
  67
  68#define MDIO_STATE_STA_B        0
  69
  70enum mdio_st_clause {
  71        MDIO_ST_CLAUSE_45 = 0,
  72        MDIO_ST_CLAUSE_22
  73};
  74
  75enum mdio_c22_op_seq {
  76        MDIO_C22_WRITE = 1,
  77        MDIO_C22_READ = 2
  78};
  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_READ
  85};
  86
  87/* peri subctrl reg */
  88#define MDIO_SC_CLK_EN          0x338
  89#define MDIO_SC_CLK_DIS         0x33C
  90#define MDIO_SC_RESET_REQ       0xA38
  91#define MDIO_SC_RESET_DREQ      0xA3C
  92#define MDIO_SC_CLK_ST          0x531C
  93#define MDIO_SC_RESET_ST        0x5A1C
  94
  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       1
 143#define MDIO_CHECK_CLR_ST       0
 144
 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, &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        /* waitting 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 - access phy register
 210 * @bus: mdio bus
 211 * @phy_id: phy id
 212 * @regnum: register num
 213 * @data: register value
 214 *
 215 * Return 0 on success, negative on failure
 216 */
 217static int hns_mdio_write(struct mii_bus *bus,
 218                          int phy_id, int regnum, u16 data)
 219{
 220        int ret;
 221        struct hns_mdio_device *mdio_dev = (struct hns_mdio_device *)bus->priv;
 222        u8 devad = ((regnum >> 16) & 0x1f);
 223        u8 is_c45 = !!(regnum & MII_ADDR_C45);
 224        u16 reg = (u16)(regnum & 0xffff);
 225        u8 op;
 226        u16 cmd_reg_cfg;
 227
 228        dev_dbg(&bus->dev, "mdio write %s,base is %p\n",
 229                bus->id, mdio_dev->vbase);
 230        dev_dbg(&bus->dev, "phy id=%d, is_c45=%d, devad=%d, reg=%#x, write data=%d\n",
 231                phy_id, is_c45, devad, reg, data);
 232
 233        /* wait for ready */
 234        ret = hns_mdio_wait_ready(bus);
 235        if (ret) {
 236                dev_err(&bus->dev, "MDIO bus is busy\n");
 237                return ret;
 238        }
 239
 240        if (!is_c45) {
 241                cmd_reg_cfg = reg;
 242                op = MDIO_C22_WRITE;
 243        } else {
 244                /* config the cmd-reg to write addr*/
 245                MDIO_SET_REG_FIELD(mdio_dev, MDIO_ADDR_REG, MDIO_ADDR_DATA_M,
 246                                   MDIO_ADDR_DATA_S, reg);
 247
 248                hns_mdio_cmd_write(mdio_dev, is_c45,
 249                                   MDIO_C45_WRITE_ADDR, phy_id, devad);
 250
 251                /* check for read or write opt is finished */
 252                ret = hns_mdio_wait_ready(bus);
 253                if (ret) {
 254                        dev_err(&bus->dev, "MDIO bus is busy\n");
 255                        return ret;
 256                }
 257
 258                /* config the data needed writing */
 259                cmd_reg_cfg = devad;
 260                op = MDIO_C45_WRITE_DATA;
 261        }
 262
 263        MDIO_SET_REG_FIELD(mdio_dev, MDIO_WDATA_REG, MDIO_WDATA_DATA_M,
 264                           MDIO_WDATA_DATA_S, data);
 265
 266        hns_mdio_cmd_write(mdio_dev, is_c45, op, phy_id, cmd_reg_cfg);
 267
 268        return 0;
 269}
 270
 271/**
 272 * hns_mdio_read - access phy register
 273 * @bus: mdio bus
 274 * @phy_id: phy id
 275 * @regnum: register num
 276 *
 277 * Return phy register value
 278 */
 279static int hns_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
 280{
 281        int ret;
 282        u16 reg_val;
 283        u8 devad = ((regnum >> 16) & 0x1f);
 284        u8 is_c45 = !!(regnum & MII_ADDR_C45);
 285        u16 reg = (u16)(regnum & 0xffff);
 286        struct hns_mdio_device *mdio_dev = (struct hns_mdio_device *)bus->priv;
 287
 288        dev_dbg(&bus->dev, "mdio read %s,base is %p\n",
 289                bus->id, mdio_dev->vbase);
 290        dev_dbg(&bus->dev, "phy id=%d, is_c45=%d, devad=%d, reg=%#x!\n",
 291                phy_id, is_c45, devad, reg);
 292
 293        /* Step 1: wait for ready */
 294        ret = hns_mdio_wait_ready(bus);
 295        if (ret) {
 296                dev_err(&bus->dev, "MDIO bus is busy\n");
 297                return ret;
 298        }
 299
 300        if (!is_c45) {
 301                hns_mdio_cmd_write(mdio_dev, is_c45,
 302                                   MDIO_C22_READ, phy_id, reg);
 303        } else {
 304                MDIO_SET_REG_FIELD(mdio_dev, MDIO_ADDR_REG, MDIO_ADDR_DATA_M,
 305                                   MDIO_ADDR_DATA_S, reg);
 306
 307                /* Step 2; config the cmd-reg to write addr*/
 308                hns_mdio_cmd_write(mdio_dev, is_c45,
 309                                   MDIO_C45_WRITE_ADDR, phy_id, devad);
 310
 311                /* Step 3: check for read or write opt is finished */
 312                ret = hns_mdio_wait_ready(bus);
 313                if (ret) {
 314                        dev_err(&bus->dev, "MDIO bus is busy\n");
 315                        return ret;
 316                }
 317
 318                hns_mdio_cmd_write(mdio_dev, is_c45,
 319                                   MDIO_C45_READ, phy_id, devad);
 320        }
 321
 322        /* Step 5: waitting for MDIO_COMMAND_REG 's mdio_start==0,*/
 323        /* check for read or write opt is finished */
 324        ret = hns_mdio_wait_ready(bus);
 325        if (ret) {
 326                dev_err(&bus->dev, "MDIO bus is busy\n");
 327                return ret;
 328        }
 329
 330        reg_val = MDIO_GET_REG_BIT(mdio_dev, MDIO_STA_REG, MDIO_STATE_STA_B);
 331        if (reg_val) {
 332                dev_err(&bus->dev, " ERROR! MDIO Read failed!\n");
 333                return -EBUSY;
 334        }
 335
 336        /* Step 6; get out data*/
 337        reg_val = (u16)MDIO_GET_REG_FIELD(mdio_dev, MDIO_RDATA_REG,
 338                                          MDIO_RDATA_DATA_M, MDIO_RDATA_DATA_S);
 339
 340        return reg_val;
 341}
 342
 343/**
 344 * hns_mdio_reset - reset mdio bus
 345 * @bus: mdio bus
 346 *
 347 * Return 0 on success, negative on failure
 348 */
 349static int hns_mdio_reset(struct mii_bus *bus)
 350{
 351        struct hns_mdio_device *mdio_dev = (struct hns_mdio_device *)bus->priv;
 352        const struct hns_mdio_sc_reg *sc_reg;
 353        int ret;
 354
 355        if (dev_of_node(bus->parent)) {
 356                if (!mdio_dev->subctrl_vbase) {
 357                        dev_err(&bus->dev, "mdio sys ctl reg has not mapped\n");
 358                        return -ENODEV;
 359                }
 360
 361                sc_reg = &mdio_dev->sc_reg;
 362                /* 1. reset req, and read reset st check */
 363                ret = mdio_sc_cfg_reg_write(mdio_dev, sc_reg->mdio_reset_req,
 364                                            0x1, sc_reg->mdio_reset_st, 0x1,
 365                                            MDIO_CHECK_SET_ST);
 366                if (ret) {
 367                        dev_err(&bus->dev, "MDIO reset fail\n");
 368                        return ret;
 369                }
 370
 371                /* 2. dis clk, and read clk st check */
 372                ret = mdio_sc_cfg_reg_write(mdio_dev, sc_reg->mdio_clk_dis,
 373                                            0x1, sc_reg->mdio_clk_st, 0x1,
 374                                            MDIO_CHECK_CLR_ST);
 375                if (ret) {
 376                        dev_err(&bus->dev, "MDIO dis clk fail\n");
 377                        return ret;
 378                }
 379
 380                /* 3. reset dreq, and read reset st check */
 381                ret = mdio_sc_cfg_reg_write(mdio_dev, sc_reg->mdio_reset_dreq,
 382                                            0x1, sc_reg->mdio_reset_st, 0x1,
 383                                            MDIO_CHECK_CLR_ST);
 384                if (ret) {
 385                        dev_err(&bus->dev, "MDIO dis clk fail\n");
 386                        return ret;
 387                }
 388
 389                /* 4. en clk, and read clk st check */
 390                ret = mdio_sc_cfg_reg_write(mdio_dev, sc_reg->mdio_clk_en,
 391                                            0x1, sc_reg->mdio_clk_st, 0x1,
 392                                            MDIO_CHECK_SET_ST);
 393                if (ret)
 394                        dev_err(&bus->dev, "MDIO en clk fail\n");
 395        } else if (is_acpi_node(bus->parent->fwnode)) {
 396                acpi_status s;
 397
 398                s = acpi_evaluate_object(ACPI_HANDLE(bus->parent),
 399                                         "_RST", NULL, NULL);
 400                if (ACPI_FAILURE(s)) {
 401                        dev_err(&bus->dev, "Reset failed, return:%#x\n", s);
 402                        ret = -EBUSY;
 403                } else {
 404                        ret = 0;
 405                }
 406        } else {
 407                dev_err(&bus->dev, "Can not get cfg data from DT or ACPI\n");
 408                ret = -ENXIO;
 409        }
 410        return ret;
 411}
 412
 413/**
 414 * hns_mdio_probe - probe mdio device
 415 * @pdev: mdio platform device
 416 *
 417 * Return 0 on success, negative on failure
 418 */
 419static int hns_mdio_probe(struct platform_device *pdev)
 420{
 421        struct hns_mdio_device *mdio_dev;
 422        struct mii_bus *new_bus;
 423        int ret;
 424
 425        if (!pdev) {
 426                dev_err(NULL, "pdev is NULL!\r\n");
 427                return -ENODEV;
 428        }
 429
 430        mdio_dev = devm_kzalloc(&pdev->dev, sizeof(*mdio_dev), GFP_KERNEL);
 431        if (!mdio_dev)
 432                return -ENOMEM;
 433
 434        new_bus = devm_mdiobus_alloc(&pdev->dev);
 435        if (!new_bus) {
 436                dev_err(&pdev->dev, "mdiobus_alloc fail!\n");
 437                return -ENOMEM;
 438        }
 439
 440        new_bus->name = MDIO_BUS_NAME;
 441        new_bus->read = hns_mdio_read;
 442        new_bus->write = hns_mdio_write;
 443        new_bus->reset = hns_mdio_reset;
 444        new_bus->priv = mdio_dev;
 445        new_bus->parent = &pdev->dev;
 446
 447        mdio_dev->vbase = devm_platform_ioremap_resource(pdev, 0);
 448        if (IS_ERR(mdio_dev->vbase)) {
 449                ret = PTR_ERR(mdio_dev->vbase);
 450                return ret;
 451        }
 452
 453        platform_set_drvdata(pdev, new_bus);
 454        snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%s", "Mii",
 455                 dev_name(&pdev->dev));
 456        if (dev_of_node(&pdev->dev)) {
 457                struct of_phandle_args reg_args;
 458
 459                ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
 460                                                       "subctrl-vbase",
 461                                                       4,
 462                                                       0,
 463                                                       &reg_args);
 464                if (!ret) {
 465                        mdio_dev->subctrl_vbase =
 466                                syscon_node_to_regmap(reg_args.np);
 467                        if (IS_ERR(mdio_dev->subctrl_vbase)) {
 468                                dev_warn(&pdev->dev, "syscon_node_to_regmap error\n");
 469                                mdio_dev->subctrl_vbase = NULL;
 470                        } else {
 471                                if (reg_args.args_count == 4) {
 472                                        mdio_dev->sc_reg.mdio_clk_en =
 473                                                (u16)reg_args.args[0];
 474                                        mdio_dev->sc_reg.mdio_clk_dis =
 475                                                (u16)reg_args.args[0] + 4;
 476                                        mdio_dev->sc_reg.mdio_reset_req =
 477                                                (u16)reg_args.args[1];
 478                                        mdio_dev->sc_reg.mdio_reset_dreq =
 479                                                (u16)reg_args.args[1] + 4;
 480                                        mdio_dev->sc_reg.mdio_clk_st =
 481                                                (u16)reg_args.args[2];
 482                                        mdio_dev->sc_reg.mdio_reset_st =
 483                                                (u16)reg_args.args[3];
 484                                } else {
 485                                        /* for compatible */
 486                                        mdio_dev->sc_reg.mdio_clk_en =
 487                                                MDIO_SC_CLK_EN;
 488                                        mdio_dev->sc_reg.mdio_clk_dis =
 489                                                MDIO_SC_CLK_DIS;
 490                                        mdio_dev->sc_reg.mdio_reset_req =
 491                                                MDIO_SC_RESET_REQ;
 492                                        mdio_dev->sc_reg.mdio_reset_dreq =
 493                                                MDIO_SC_RESET_DREQ;
 494                                        mdio_dev->sc_reg.mdio_clk_st =
 495                                                MDIO_SC_CLK_ST;
 496                                        mdio_dev->sc_reg.mdio_reset_st =
 497                                                MDIO_SC_RESET_ST;
 498                                }
 499                        }
 500                } else {
 501                        dev_warn(&pdev->dev, "find syscon ret = %#x\n", ret);
 502                        mdio_dev->subctrl_vbase = NULL;
 503                }
 504
 505                ret = of_mdiobus_register(new_bus, pdev->dev.of_node);
 506        } else if (is_acpi_node(pdev->dev.fwnode)) {
 507                /* Clear all the IRQ properties */
 508                memset(new_bus->irq, PHY_POLL, 4 * PHY_MAX_ADDR);
 509
 510                /* Mask out all PHYs from auto probing. */
 511                new_bus->phy_mask = ~0;
 512
 513                /* Register the MDIO bus */
 514                ret = mdiobus_register(new_bus);
 515        } else {
 516                dev_err(&pdev->dev, "Can not get cfg data from DT or ACPI\n");
 517                ret = -ENXIO;
 518        }
 519
 520        if (ret) {
 521                dev_err(&pdev->dev, "Cannot register as MDIO bus!\n");
 522                platform_set_drvdata(pdev, NULL);
 523                return ret;
 524        }
 525
 526        return 0;
 527}
 528
 529/**
 530 * hns_mdio_remove - remove mdio device
 531 * @pdev: mdio platform device
 532 *
 533 * Return 0 on success, negative on failure
 534 */
 535static int hns_mdio_remove(struct platform_device *pdev)
 536{
 537        struct mii_bus *bus;
 538
 539        bus = platform_get_drvdata(pdev);
 540
 541        mdiobus_unregister(bus);
 542        platform_set_drvdata(pdev, NULL);
 543        return 0;
 544}
 545
 546static const struct of_device_id hns_mdio_match[] = {
 547        {.compatible = "hisilicon,mdio"},
 548        {.compatible = "hisilicon,hns-mdio"},
 549        {}
 550};
 551MODULE_DEVICE_TABLE(of, hns_mdio_match);
 552
 553static const struct acpi_device_id hns_mdio_acpi_match[] = {
 554        { "HISI0141", 0 },
 555        { },
 556};
 557MODULE_DEVICE_TABLE(acpi, hns_mdio_acpi_match);
 558
 559static struct platform_driver hns_mdio_driver = {
 560        .probe = hns_mdio_probe,
 561        .remove = hns_mdio_remove,
 562        .driver = {
 563                   .name = MDIO_DRV_NAME,
 564                   .of_match_table = hns_mdio_match,
 565                   .acpi_match_table = ACPI_PTR(hns_mdio_acpi_match),
 566                   },
 567};
 568
 569module_platform_driver(hns_mdio_driver);
 570
 571MODULE_LICENSE("GPL");
 572MODULE_AUTHOR("Huawei Tech. Co., Ltd.");
 573MODULE_DESCRIPTION("Hisilicon HNS MDIO driver");
 574MODULE_ALIAS("platform:" MDIO_DRV_NAME);
 575