// SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* * Copyright (c) 2018 Microsemi Corporation */ #include #include #include #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; }