123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
- /*
- * Copyright (c) 2018 Microsemi Corporation
- */
- #include <miiphy.h>
- #include <wait_bit.h>
- #include <linux/bitops.h>
- #include "mscc_miim.h"
- #define MIIM_STATUS 0x0
- #define MIIM_STAT_BUSY BIT(3)
- #define MIIM_CMD 0x8
- #define MIIM_CMD_SCAN BIT(0)
- #define MIIM_CMD_OPR_WRITE BIT(1)
- #define MIIM_CMD_OPR_READ BIT(2)
- #define MIIM_CMD_SINGLE_SCAN BIT(3)
- #define MIIM_CMD_WRDATA(x) ((x) << 4)
- #define MIIM_CMD_REGAD(x) ((x) << 20)
- #define MIIM_CMD_PHYAD(x) ((x) << 25)
- #define MIIM_CMD_VLD BIT(31)
- #define MIIM_DATA 0xC
- #define MIIM_DATA_ERROR (0x2 << 16)
- static int mscc_miim_wait_ready(struct mscc_miim_dev *miim)
- {
- return wait_for_bit_le32(miim->regs + MIIM_STATUS, MIIM_STAT_BUSY,
- false, 250, false);
- }
- int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg)
- {
- struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
- u32 val;
- int ret;
- ret = mscc_miim_wait_ready(miim);
- if (ret)
- goto out;
- writel(MIIM_CMD_VLD | MIIM_CMD_PHYAD(addr) |
- MIIM_CMD_REGAD(reg) | MIIM_CMD_OPR_READ,
- miim->regs + MIIM_CMD);
- ret = mscc_miim_wait_ready(miim);
- if (ret)
- goto out;
- val = readl(miim->regs + MIIM_DATA);
- if (val & MIIM_DATA_ERROR) {
- ret = -EIO;
- goto out;
- }
- ret = val & 0xFFFF;
- out:
- return ret;
- }
- int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg,
- u16 val)
- {
- struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
- int ret;
- ret = mscc_miim_wait_ready(miim);
- if (ret < 0)
- goto out;
- writel(MIIM_CMD_VLD | MIIM_CMD_PHYAD(addr) |
- MIIM_CMD_REGAD(reg) | MIIM_CMD_WRDATA(val) |
- MIIM_CMD_OPR_WRITE, miim->regs + MIIM_CMD);
- out:
- return ret;
- }
- struct mii_dev *mscc_mdiobus_init(struct mscc_miim_dev *miim, int *miim_count,
- phys_addr_t miim_base,
- unsigned long miim_size)
- {
- struct mii_dev *bus;
- bus = mdio_alloc();
- if (!bus)
- return NULL;
- *miim_count += 1;
- sprintf(bus->name, "miim-bus%d", *miim_count);
- miim[*miim_count].regs = ioremap(miim_base, miim_size);
- miim[*miim_count].miim_base = miim_base;
- miim[*miim_count].miim_size = miim_size;
- bus->priv = &miim[*miim_count];
- bus->read = mscc_miim_read;
- bus->write = mscc_miim_write;
- if (mdio_register(bus))
- return NULL;
- miim[*miim_count].bus = bus;
- return bus;
- }
|