linux/drivers/net/ethernet/hisilicon/hns_mdio.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2014-2015 Hisilicon Limited.
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License as published by
   6 * the Free Software Foundation; either version 2 of the License, or
   7 * (at your option) any later version.
   8 */
   9
  10#include <linux/errno.h>
  11#include <linux/etherdevice.h>
  12#include <linux/init.h>
  13#include <linux/kernel.h>
  14#include <linux/mfd/syscon.h>
  15#include <linux/module.h>
  16#include <linux/mutex.h>
  17#include <linux/netdevice.h>
  18#include <linux/of_address.h>
  19#include <linux/of.h>
  20#include <linux/of_mdio.h>
  21#include <linux/of_platform.h>
  22#include <linux/phy.h>
  23#include <linux/platform_device.h>
  24#include <linux/regmap.h>
  25#include <linux/spinlock_types.h>
  26
  27#define MDIO_DRV_NAME "Hi-HNS_MDIO"
  28#define MDIO_BUS_NAME "Hisilicon MII Bus"
  29#define MDIO_DRV_VERSION "1.3.0"
  30#define MDIO_COPYRIGHT "Copyright(c) 2015 Huawei Corporation."
  31#define MDIO_DRV_STRING MDIO_BUS_NAME
  32#define MDIO_DEFAULT_DEVICE_DESCR MDIO_BUS_NAME
  33
  34#define MDIO_CTL_DEV_ADDR(x)    (x & 0x1f)
  35#define MDIO_CTL_PORT_ADDR(x)   ((x & 0x1f) << 5)
  36
  37#define MDIO_TIMEOUT                    1000000
  38
  39struct hns_mdio_device {
  40        void *vbase;            /* mdio reg base address */
  41        struct regmap *subctrl_vbase;
  42};
  43
  44/* mdio reg */
  45#define MDIO_COMMAND_REG                0x0
  46#define MDIO_ADDR_REG                   0x4
  47#define MDIO_WDATA_REG                  0x8
  48#define MDIO_RDATA_REG                  0xc
  49#define MDIO_STA_REG                    0x10
  50
  51/* cfg phy bit map */
  52#define MDIO_CMD_DEVAD_M        0x1f
  53#define MDIO_CMD_DEVAD_S        0
  54#define MDIO_CMD_PRTAD_M        0x1f
  55#define MDIO_CMD_PRTAD_S        5
  56#define MDIO_CMD_OP_M           0x3
  57#define MDIO_CMD_OP_S           10
  58#define MDIO_CMD_ST_M           0x3
  59#define MDIO_CMD_ST_S           12
  60#define MDIO_CMD_START_B        14
  61
  62#define MDIO_ADDR_DATA_M        0xffff
  63#define MDIO_ADDR_DATA_S        0
  64
  65#define MDIO_WDATA_DATA_M       0xffff
  66#define MDIO_WDATA_DATA_S       0
  67
  68#define MDIO_RDATA_DATA_M       0xffff
  69#define MDIO_RDATA_DATA_S       0
  70
  71#define MDIO_STATE_STA_B        0
  72
  73enum mdio_st_clause {
  74        MDIO_ST_CLAUSE_45 = 0,
  75        MDIO_ST_CLAUSE_22
  76};
  77
  78enum mdio_c22_op_seq {
  79        MDIO_C22_WRITE = 1,
  80        MDIO_C22_READ = 2
  81};
  82
  83enum mdio_c45_op_seq {
  84        MDIO_C45_WRITE_ADDR = 0,
  85        MDIO_C45_WRITE_DATA,
  86        MDIO_C45_READ_INCREMENT,
  87        MDIO_C45_READ
  88};
  89
  90/* peri subctrl reg */
  91#define MDIO_SC_CLK_EN          0x338
  92#define MDIO_SC_CLK_DIS         0x33C
  93#define MDIO_SC_RESET_REQ       0xA38
  94#define MDIO_SC_RESET_DREQ      0xA3C
  95#define MDIO_SC_CTRL            0x2010
  96#define MDIO_SC_CLK_ST          0x531C
  97#define MDIO_SC_RESET_ST        0x5A1C
  98
  99static void mdio_write_reg(void *base, u32 reg, u32 value)
 100{
 101        u8 __iomem *reg_addr = (u8 __iomem *)base;
 102
 103        writel_relaxed(value, reg_addr + reg);
 104}
 105
 106#define MDIO_WRITE_REG(a, reg, value) \
 107        mdio_write_reg((a)->vbase, (reg), (value))
 108
 109static u32 mdio_read_reg(void *base, u32 reg)
 110{
 111        u8 __iomem *reg_addr = (u8 __iomem *)base;
 112
 113        return readl_relaxed(reg_addr + reg);
 114}
 115
 116#define mdio_set_field(origin, mask, shift, val) \
 117        do { \
 118                (origin) &= (~((mask) << (shift))); \
 119                (origin) |= (((val) & (mask)) << (shift)); \
 120        } while (0)
 121
 122#define mdio_get_field(origin, mask, shift) (((origin) >> (shift)) & (mask))
 123
 124static void mdio_set_reg_field(void *base, u32 reg, u32 mask, u32 shift,
 125                               u32 val)
 126{
 127        u32 origin = mdio_read_reg(base, reg);
 128
 129        mdio_set_field(origin, mask, shift, val);
 130        mdio_write_reg(base, reg, origin);
 131}
 132
 133#define MDIO_SET_REG_FIELD(dev, reg, mask, shift, val) \
 134        mdio_set_reg_field((dev)->vbase, (reg), (mask), (shift), (val))
 135
 136static u32 mdio_get_reg_field(void *base, u32 reg, u32 mask, u32 shift)
 137{
 138        u32 origin;
 139
 140        origin = mdio_read_reg(base, reg);
 141        return mdio_get_field(origin, mask, shift);
 142}
 143
 144#define MDIO_GET_REG_FIELD(dev, reg, mask, shift) \
 145                mdio_get_reg_field((dev)->vbase, (reg), (mask), (shift))
 146
 147#define MDIO_GET_REG_BIT(dev, reg, bit) \
 148                mdio_get_reg_field((dev)->vbase, (reg), 0x1ull, (bit))
 149
 150#define MDIO_CHECK_SET_ST       1
 151#define MDIO_CHECK_CLR_ST       0
 152
 153static int mdio_sc_cfg_reg_write(struct hns_mdio_device *mdio_dev,
 154                                 u32 cfg_reg, u32 set_val,
 155                                 u32 st_reg, u32 st_msk, u8 check_st)
 156{
 157        u32 time_cnt;
 158        u32 reg_value;
 159
 160        regmap_write(mdio_dev->subctrl_vbase, cfg_reg, set_val);
 161
 162        for (time_cnt = MDIO_TIMEOUT; time_cnt; time_cnt--) {
 163                regmap_read(mdio_dev->subctrl_vbase, st_reg, &reg_value);
 164                reg_value &= st_msk;
 165                if ((!!check_st) == (!!reg_value))
 166                        break;
 167        }
 168
 169        if ((!!check_st) != (!!reg_value))
 170                return -EBUSY;
 171
 172        return 0;
 173}
 174
 175static int hns_mdio_wait_ready(struct mii_bus *bus)
 176{
 177        struct hns_mdio_device *mdio_dev = bus->priv;
 178        int i;
 179        u32 cmd_reg_value = 1;
 180
 181        /* waitting for MDIO_COMMAND_REG 's mdio_start==0 */
 182        /* after that can do read or write*/
 183        for (i = 0; cmd_reg_value; i++) {
 184                cmd_reg_value = MDIO_GET_REG_BIT(mdio_dev,
 185                                                 MDIO_COMMAND_REG,
 186                                                 MDIO_CMD_START_B);
 187                if (i == MDIO_TIMEOUT)
 188                        return -ETIMEDOUT;
 189        }
 190
 191        return 0;
 192}
 193
 194static void hns_mdio_cmd_write(struct hns_mdio_device *mdio_dev,
 195                               u8 is_c45, u8 op, u8 phy_id, u16 cmd)
 196{
 197        u32 cmd_reg_value;
 198        u8 st = is_c45 ? MDIO_ST_CLAUSE_45 : MDIO_ST_CLAUSE_22;
 199
 200        cmd_reg_value = st << MDIO_CMD_ST_S;
 201        cmd_reg_value |= op << MDIO_CMD_OP_S;
 202        cmd_reg_value |=
 203                (phy_id & MDIO_CMD_PRTAD_M) << MDIO_CMD_PRTAD_S;
 204        cmd_reg_value |= (cmd & MDIO_CMD_DEVAD_M) << MDIO_CMD_DEVAD_S;
 205        cmd_reg_value |= 1 << MDIO_CMD_START_B;
 206
 207        MDIO_WRITE_REG(mdio_dev, MDIO_COMMAND_REG, cmd_reg_value);
 208}
 209
 210/**
 211 * hns_mdio_write - access phy register
 212 * @bus: mdio bus
 213 * @phy_id: phy id
 214 * @regnum: register num
 215 * @value: register value
 216 *
 217 * Return 0 on success, negative on failure
 218 */
 219static int hns_mdio_write(struct mii_bus *bus,
 220                          int phy_id, int regnum, u16 data)
 221{
 222        int ret;
 223        struct hns_mdio_device *mdio_dev = (struct hns_mdio_device *)bus->priv;
 224        u8 devad = ((regnum >> 16) & 0x1f);
 225        u8 is_c45 = !!(regnum & MII_ADDR_C45);
 226        u16 reg = (u16)(regnum & 0xffff);
 227        u8 op;
 228        u16 cmd_reg_cfg;
 229
 230        dev_dbg(&bus->dev, "mdio write %s,base is %p\n",
 231                bus->id, mdio_dev->vbase);
 232        dev_dbg(&bus->dev, "phy id=%d, is_c45=%d, devad=%d, reg=%#x, write data=%d\n",
 233                phy_id, is_c45, devad, reg, data);
 234
 235        /* wait for ready */
 236        ret = hns_mdio_wait_ready(bus);
 237        if (ret) {
 238                dev_err(&bus->dev, "MDIO bus is busy\n");
 239                return ret;
 240        }
 241
 242        if (!is_c45) {
 243                cmd_reg_cfg = reg;
 244                op = MDIO_C22_WRITE;
 245        } else {
 246                /* config the cmd-reg to write addr*/
 247                MDIO_SET_REG_FIELD(mdio_dev, MDIO_ADDR_REG, MDIO_ADDR_DATA_M,
 248                                   MDIO_ADDR_DATA_S, reg);
 249
 250                hns_mdio_cmd_write(mdio_dev, is_c45,
 251                                   MDIO_C45_WRITE_ADDR, phy_id, devad);
 252
 253                /* check for read or write opt is finished */
 254                ret = hns_mdio_wait_ready(bus);
 255                if (ret) {
 256                        dev_err(&bus->dev, "MDIO bus is busy\n");
 257                        return ret;
 258                }
 259
 260                /* config the data needed writing */
 261                cmd_reg_cfg = devad;
 262                op = MDIO_C45_WRITE_ADDR;
 263        }
 264
 265        MDIO_SET_REG_FIELD(mdio_dev, MDIO_WDATA_REG, MDIO_WDATA_DATA_M,
 266                           MDIO_WDATA_DATA_S, data);
 267
 268        hns_mdio_cmd_write(mdio_dev, is_c45, op, phy_id, cmd_reg_cfg);
 269
 270        return 0;
 271}
 272
 273/**
 274 * hns_mdio_read - access phy register
 275 * @bus: mdio bus
 276 * @phy_id: phy id
 277 * @regnum: register num
 278 * @value: register value
 279 *
 280 * Return phy register value
 281 */
 282static int hns_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
 283{
 284        int ret;
 285        u16 reg_val = 0;
 286        u8 devad = ((regnum >> 16) & 0x1f);
 287        u8 is_c45 = !!(regnum & MII_ADDR_C45);
 288        u16 reg = (u16)(regnum & 0xffff);
 289        struct hns_mdio_device *mdio_dev = (struct hns_mdio_device *)bus->priv;
 290
 291        dev_dbg(&bus->dev, "mdio read %s,base is %p\n",
 292                bus->id, mdio_dev->vbase);
 293        dev_dbg(&bus->dev, "phy id=%d, is_c45=%d, devad=%d, reg=%#x!\n",
 294                phy_id, is_c45, devad, reg);
 295
 296        /* Step 1: wait for ready */
 297        ret = hns_mdio_wait_ready(bus);
 298        if (ret) {
 299                dev_err(&bus->dev, "MDIO bus is busy\n");
 300                return ret;
 301        }
 302
 303        if (!is_c45) {
 304                hns_mdio_cmd_write(mdio_dev, is_c45,
 305                                   MDIO_C22_READ, phy_id, reg);
 306        } else {
 307                MDIO_SET_REG_FIELD(mdio_dev, MDIO_ADDR_REG, MDIO_ADDR_DATA_M,
 308                                   MDIO_ADDR_DATA_S, reg);
 309
 310                /* Step 2; config the cmd-reg to write addr*/
 311                hns_mdio_cmd_write(mdio_dev, is_c45,
 312                                   MDIO_C45_WRITE_ADDR, phy_id, devad);
 313
 314                /* Step 3: check for read or write opt is finished */
 315                ret = hns_mdio_wait_ready(bus);
 316                if (ret) {
 317                        dev_err(&bus->dev, "MDIO bus is busy\n");
 318                        return ret;
 319                }
 320
 321                hns_mdio_cmd_write(mdio_dev, is_c45,
 322                                   MDIO_C45_WRITE_ADDR, phy_id, devad);
 323        }
 324
 325        /* Step 5: waitting for MDIO_COMMAND_REG 's mdio_start==0,*/
 326        /* check for read or write opt is finished */
 327        ret = hns_mdio_wait_ready(bus);
 328        if (ret) {
 329                dev_err(&bus->dev, "MDIO bus is busy\n");
 330                return ret;
 331        }
 332
 333        reg_val = MDIO_GET_REG_BIT(mdio_dev, MDIO_STA_REG, MDIO_STATE_STA_B);
 334        if (reg_val) {
 335                dev_err(&bus->dev, " ERROR! MDIO Read failed!\n");
 336                return -EBUSY;
 337        }
 338
 339        /* Step 6; get out data*/
 340        reg_val = (u16)MDIO_GET_REG_FIELD(mdio_dev, MDIO_RDATA_REG,
 341                                          MDIO_RDATA_DATA_M, MDIO_RDATA_DATA_S);
 342
 343        return reg_val;
 344}
 345
 346/**
 347 * hns_mdio_reset - reset mdio bus
 348 * @bus: mdio bus
 349 *
 350 * Return 0 on success, negative on failure
 351 */
 352static int hns_mdio_reset(struct mii_bus *bus)
 353{
 354        struct hns_mdio_device *mdio_dev = (struct hns_mdio_device *)bus->priv;
 355        int ret;
 356
 357        if (!mdio_dev->subctrl_vbase) {
 358                dev_err(&bus->dev, "mdio sys ctl reg has not maped\n");
 359                return -ENODEV;
 360        }
 361
 362        /*1. reset req, and read reset st check*/
 363        ret = mdio_sc_cfg_reg_write(mdio_dev, MDIO_SC_RESET_REQ, 0x1,
 364                                    MDIO_SC_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, MDIO_SC_CLK_DIS,
 373                                    0x1, MDIO_SC_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, MDIO_SC_RESET_DREQ, 0x1,
 382                                    MDIO_SC_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, MDIO_SC_CLK_EN,
 391                                    0x1, MDIO_SC_CLK_ST, 0x1,
 392                                    MDIO_CHECK_SET_ST);
 393        if (ret)
 394                dev_err(&bus->dev, "MDIO en clk fail\n");
 395
 396        return ret;
 397}
 398
 399/**
 400 * hns_mdio_bus_name - get mdio bus name
 401 * @name: mdio bus name
 402 * @np: mdio device node pointer
 403 */
 404static void hns_mdio_bus_name(char *name, struct device_node *np)
 405{
 406        const u32 *addr;
 407        u64 taddr = OF_BAD_ADDR;
 408
 409        addr = of_get_address(np, 0, NULL, NULL);
 410        if (addr)
 411                taddr = of_translate_address(np, addr);
 412
 413        snprintf(name, MII_BUS_ID_SIZE, "%s@%llx", np->name,
 414                 (unsigned long long)taddr);
 415}
 416
 417/**
 418 * hns_mdio_probe - probe mdio device
 419 * @pdev: mdio platform device
 420 *
 421 * Return 0 on success, negative on failure
 422 */
 423static int hns_mdio_probe(struct platform_device *pdev)
 424{
 425        struct device_node *np;
 426        struct hns_mdio_device *mdio_dev;
 427        struct mii_bus *new_bus;
 428        struct resource *res;
 429        int ret;
 430
 431        if (!pdev) {
 432                dev_err(NULL, "pdev is NULL!\r\n");
 433                return -ENODEV;
 434        }
 435        np = pdev->dev.of_node;
 436        mdio_dev = devm_kzalloc(&pdev->dev, sizeof(*mdio_dev), GFP_KERNEL);
 437        if (!mdio_dev)
 438                return -ENOMEM;
 439
 440        new_bus = devm_mdiobus_alloc(&pdev->dev);
 441        if (!new_bus) {
 442                dev_err(&pdev->dev, "mdiobus_alloc fail!\n");
 443                return -ENOMEM;
 444        }
 445
 446        new_bus->name = MDIO_BUS_NAME;
 447        new_bus->read = hns_mdio_read;
 448        new_bus->write = hns_mdio_write;
 449        new_bus->reset = hns_mdio_reset;
 450        new_bus->priv = mdio_dev;
 451        hns_mdio_bus_name(new_bus->id, np);
 452
 453        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 454        mdio_dev->vbase = devm_ioremap_resource(&pdev->dev, res);
 455        if (IS_ERR(mdio_dev->vbase)) {
 456                ret = PTR_ERR(mdio_dev->vbase);
 457                return ret;
 458        }
 459
 460        mdio_dev->subctrl_vbase =
 461                syscon_node_to_regmap(of_parse_phandle(np, "subctrl-vbase", 0));
 462        if (IS_ERR(mdio_dev->subctrl_vbase)) {
 463                dev_warn(&pdev->dev, "no syscon hisilicon,peri-c-subctrl\n");
 464                mdio_dev->subctrl_vbase = NULL;
 465        }
 466        new_bus->parent = &pdev->dev;
 467        platform_set_drvdata(pdev, new_bus);
 468
 469        ret = of_mdiobus_register(new_bus, np);
 470        if (ret) {
 471                dev_err(&pdev->dev, "Cannot register as MDIO bus!\n");
 472                platform_set_drvdata(pdev, NULL);
 473                return ret;
 474        }
 475
 476        return 0;
 477}
 478
 479/**
 480 * hns_mdio_remove - remove mdio device
 481 * @pdev: mdio platform device
 482 *
 483 * Return 0 on success, negative on failure
 484 */
 485static int hns_mdio_remove(struct platform_device *pdev)
 486{
 487        struct mii_bus *bus;
 488
 489        bus = platform_get_drvdata(pdev);
 490
 491        mdiobus_unregister(bus);
 492        platform_set_drvdata(pdev, NULL);
 493        return 0;
 494}
 495
 496static const struct of_device_id hns_mdio_match[] = {
 497        {.compatible = "hisilicon,mdio"},
 498        {.compatible = "hisilicon,hns-mdio"},
 499        {}
 500};
 501
 502static struct platform_driver hns_mdio_driver = {
 503        .probe = hns_mdio_probe,
 504        .remove = hns_mdio_remove,
 505        .driver = {
 506                   .name = MDIO_DRV_NAME,
 507                   .of_match_table = hns_mdio_match,
 508                   },
 509};
 510
 511module_platform_driver(hns_mdio_driver);
 512
 513MODULE_LICENSE("GPL");
 514MODULE_AUTHOR("Huawei Tech. Co., Ltd.");
 515MODULE_DESCRIPTION("Hisilicon HNS MDIO driver");
 516MODULE_ALIAS("platform:" MDIO_DRV_NAME);
 517