uboot/drivers/net/aspeed_mdio.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Aspeed MDIO driver
   4 *
   5 * (C) Copyright 2021 Aspeed Technology Inc.
   6 *
   7 * This file is inspired from the Linux kernel driver drivers/net/phy/mdio-aspeed.c
   8 */
   9
  10#include <common.h>
  11#include <dm.h>
  12#include <log.h>
  13#include <miiphy.h>
  14#include <net.h>
  15#include <reset.h>
  16#include <linux/bitops.h>
  17#include <linux/bitfield.h>
  18#include <linux/io.h>
  19#include <linux/iopoll.h>
  20
  21#define ASPEED_MDIO_CTRL                0x0
  22#define   ASPEED_MDIO_CTRL_FIRE         BIT(31)
  23#define   ASPEED_MDIO_CTRL_ST           BIT(28)
  24#define     ASPEED_MDIO_CTRL_ST_C45     0
  25#define     ASPEED_MDIO_CTRL_ST_C22     1
  26#define   ASPEED_MDIO_CTRL_OP           GENMASK(27, 26)
  27#define     MDIO_C22_OP_WRITE           0b01
  28#define     MDIO_C22_OP_READ            0b10
  29#define   ASPEED_MDIO_CTRL_PHYAD        GENMASK(25, 21)
  30#define   ASPEED_MDIO_CTRL_REGAD        GENMASK(20, 16)
  31#define   ASPEED_MDIO_CTRL_MIIWDATA     GENMASK(15, 0)
  32
  33#define ASPEED_MDIO_DATA                0x4
  34#define   ASPEED_MDIO_DATA_MDC_THRES    GENMASK(31, 24)
  35#define   ASPEED_MDIO_DATA_MDIO_EDGE    BIT(23)
  36#define   ASPEED_MDIO_DATA_MDIO_LATCH   GENMASK(22, 20)
  37#define   ASPEED_MDIO_DATA_IDLE         BIT(16)
  38#define   ASPEED_MDIO_DATA_MIIRDATA     GENMASK(15, 0)
  39
  40#define ASPEED_MDIO_TIMEOUT_US          1000
  41
  42struct aspeed_mdio_priv {
  43        void *base;
  44};
  45
  46static int aspeed_mdio_read(struct udevice *mdio_dev, int addr, int devad, int reg)
  47{
  48        struct aspeed_mdio_priv *priv = dev_get_priv(mdio_dev);
  49        u32 ctrl;
  50        u32 data;
  51        int rc;
  52
  53        if (devad != MDIO_DEVAD_NONE)
  54                return -EOPNOTSUPP;
  55
  56        ctrl = ASPEED_MDIO_CTRL_FIRE
  57                | FIELD_PREP(ASPEED_MDIO_CTRL_ST, ASPEED_MDIO_CTRL_ST_C22)
  58                | FIELD_PREP(ASPEED_MDIO_CTRL_OP, MDIO_C22_OP_READ)
  59                | FIELD_PREP(ASPEED_MDIO_CTRL_PHYAD, addr)
  60                | FIELD_PREP(ASPEED_MDIO_CTRL_REGAD, reg);
  61
  62        writel(ctrl, priv->base + ASPEED_MDIO_CTRL);
  63
  64        rc = readl_poll_timeout(priv->base + ASPEED_MDIO_DATA, data,
  65                                data & ASPEED_MDIO_DATA_IDLE,
  66                                ASPEED_MDIO_TIMEOUT_US);
  67
  68        if (rc < 0)
  69                return rc;
  70
  71        return FIELD_GET(ASPEED_MDIO_DATA_MIIRDATA, data);
  72}
  73
  74static int aspeed_mdio_write(struct udevice *mdio_dev, int addr, int devad, int reg, u16 val)
  75{
  76        struct aspeed_mdio_priv *priv = dev_get_priv(mdio_dev);
  77        u32 ctrl;
  78
  79        if (devad != MDIO_DEVAD_NONE)
  80                return -EOPNOTSUPP;
  81
  82        ctrl = ASPEED_MDIO_CTRL_FIRE
  83                | FIELD_PREP(ASPEED_MDIO_CTRL_ST, ASPEED_MDIO_CTRL_ST_C22)
  84                | FIELD_PREP(ASPEED_MDIO_CTRL_OP, MDIO_C22_OP_WRITE)
  85                | FIELD_PREP(ASPEED_MDIO_CTRL_PHYAD, addr)
  86                | FIELD_PREP(ASPEED_MDIO_CTRL_REGAD, reg)
  87                | FIELD_PREP(ASPEED_MDIO_CTRL_MIIWDATA, val);
  88
  89        writel(ctrl, priv->base + ASPEED_MDIO_CTRL);
  90
  91        return readl_poll_timeout(priv->base + ASPEED_MDIO_CTRL, ctrl,
  92                                  !(ctrl & ASPEED_MDIO_CTRL_FIRE),
  93                                  ASPEED_MDIO_TIMEOUT_US);
  94}
  95
  96static const struct mdio_ops aspeed_mdio_ops = {
  97        .read = aspeed_mdio_read,
  98        .write = aspeed_mdio_write,
  99};
 100
 101static int aspeed_mdio_probe(struct udevice *dev)
 102{
 103        struct aspeed_mdio_priv *priv = dev_get_priv(dev);
 104        struct reset_ctl reset_ctl;
 105        int ret = 0;
 106
 107        priv->base = dev_read_addr_ptr(dev);
 108
 109        ret = reset_get_by_index(dev, 0, &reset_ctl);
 110        reset_deassert(&reset_ctl);
 111
 112        return 0;
 113}
 114
 115static const struct udevice_id aspeed_mdio_ids[] = {
 116        { .compatible = "aspeed,ast2600-mdio" },
 117        { }
 118};
 119
 120U_BOOT_DRIVER(aspeed_mdio) = {
 121        .name = "aspeed_mdio",
 122        .id = UCLASS_MDIO,
 123        .of_match = aspeed_mdio_ids,
 124        .probe = aspeed_mdio_probe,
 125        .ops = &aspeed_mdio_ops,
 126        .plat_auto = sizeof(struct mdio_perdev_priv),
 127        .priv_auto = sizeof(struct aspeed_mdio_priv),
 128};
 129