uboot/drivers/net/mscc_eswitch/mscc_miim.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
   2/*
   3 * Copyright (c) 2018 Microsemi Corporation
   4 */
   5
   6#include <miiphy.h>
   7#include <wait_bit.h>
   8#include <linux/bitops.h>
   9#include "mscc_miim.h"
  10
  11#define MIIM_STATUS                     0x0
  12#define         MIIM_STAT_BUSY                  BIT(3)
  13#define MIIM_CMD                        0x8
  14#define         MIIM_CMD_SCAN           BIT(0)
  15#define         MIIM_CMD_OPR_WRITE      BIT(1)
  16#define         MIIM_CMD_OPR_READ       BIT(2)
  17#define         MIIM_CMD_SINGLE_SCAN    BIT(3)
  18#define         MIIM_CMD_WRDATA(x)      ((x) << 4)
  19#define         MIIM_CMD_REGAD(x)       ((x) << 20)
  20#define         MIIM_CMD_PHYAD(x)       ((x) << 25)
  21#define         MIIM_CMD_VLD            BIT(31)
  22#define MIIM_DATA                       0xC
  23#define         MIIM_DATA_ERROR         (0x2 << 16)
  24
  25static int mscc_miim_wait_ready(struct mscc_miim_dev *miim)
  26{
  27        return wait_for_bit_le32(miim->regs + MIIM_STATUS, MIIM_STAT_BUSY,
  28                                 false, 250, false);
  29}
  30
  31int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg)
  32{
  33        struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
  34        u32 val;
  35        int ret;
  36
  37        ret = mscc_miim_wait_ready(miim);
  38        if (ret)
  39                goto out;
  40
  41        writel(MIIM_CMD_VLD | MIIM_CMD_PHYAD(addr) |
  42               MIIM_CMD_REGAD(reg) | MIIM_CMD_OPR_READ,
  43               miim->regs + MIIM_CMD);
  44
  45        ret = mscc_miim_wait_ready(miim);
  46        if (ret)
  47                goto out;
  48
  49        val = readl(miim->regs + MIIM_DATA);
  50        if (val & MIIM_DATA_ERROR) {
  51                ret = -EIO;
  52                goto out;
  53        }
  54
  55        ret = val & 0xFFFF;
  56 out:
  57        return ret;
  58}
  59
  60int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg,
  61                    u16 val)
  62{
  63        struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
  64        int ret;
  65
  66        ret = mscc_miim_wait_ready(miim);
  67        if (ret < 0)
  68                goto out;
  69
  70        writel(MIIM_CMD_VLD | MIIM_CMD_PHYAD(addr) |
  71               MIIM_CMD_REGAD(reg) | MIIM_CMD_WRDATA(val) |
  72               MIIM_CMD_OPR_WRITE, miim->regs + MIIM_CMD);
  73 out:
  74        return ret;
  75}
  76
  77struct mii_dev *mscc_mdiobus_init(struct mscc_miim_dev *miim, int *miim_count,
  78                                  phys_addr_t miim_base,
  79                                  unsigned long miim_size)
  80{
  81        struct mii_dev *bus;
  82
  83        bus = mdio_alloc();
  84
  85        if (!bus)
  86                return NULL;
  87
  88        *miim_count += 1;
  89        sprintf(bus->name, "miim-bus%d", *miim_count);
  90
  91        miim[*miim_count].regs = ioremap(miim_base, miim_size);
  92        miim[*miim_count].miim_base = miim_base;
  93        miim[*miim_count].miim_size = miim_size;
  94        bus->priv = &miim[*miim_count];
  95        bus->read = mscc_miim_read;
  96        bus->write = mscc_miim_write;
  97
  98        if (mdio_register(bus))
  99                return NULL;
 100
 101        miim[*miim_count].bus = bus;
 102        return bus;
 103}
 104