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 "mscc_miim.h" 9 10 #define MIIM_STATUS 0x0 11 #define MIIM_STAT_BUSY BIT(3) 12 #define MIIM_CMD 0x8 13 #define MIIM_CMD_SCAN BIT(0) 14 #define MIIM_CMD_OPR_WRITE BIT(1) 15 #define MIIM_CMD_OPR_READ BIT(2) 16 #define MIIM_CMD_SINGLE_SCAN BIT(3) 17 #define MIIM_CMD_WRDATA(x) ((x) << 4) 18 #define MIIM_CMD_REGAD(x) ((x) << 20) 19 #define MIIM_CMD_PHYAD(x) ((x) << 25) 20 #define MIIM_CMD_VLD BIT(31) 21 #define MIIM_DATA 0xC 22 #define MIIM_DATA_ERROR (0x2 << 16) 23 24 static int mscc_miim_wait_ready(struct mscc_miim_dev *miim) 25 { 26 return wait_for_bit_le32(miim->regs + MIIM_STATUS, MIIM_STAT_BUSY, 27 false, 250, false); 28 } 29 30 int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg) 31 { 32 struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv; 33 u32 val; 34 int ret; 35 36 ret = mscc_miim_wait_ready(miim); 37 if (ret) 38 goto out; 39 40 writel(MIIM_CMD_VLD | MIIM_CMD_PHYAD(addr) | 41 MIIM_CMD_REGAD(reg) | MIIM_CMD_OPR_READ, 42 miim->regs + MIIM_CMD); 43 44 ret = mscc_miim_wait_ready(miim); 45 if (ret) 46 goto out; 47 48 val = readl(miim->regs + MIIM_DATA); 49 if (val & MIIM_DATA_ERROR) { 50 ret = -EIO; 51 goto out; 52 } 53 54 ret = val & 0xFFFF; 55 out: 56 return ret; 57 } 58 59 int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg, 60 u16 val) 61 { 62 struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv; 63 int ret; 64 65 ret = mscc_miim_wait_ready(miim); 66 if (ret < 0) 67 goto out; 68 69 writel(MIIM_CMD_VLD | MIIM_CMD_PHYAD(addr) | 70 MIIM_CMD_REGAD(reg) | MIIM_CMD_WRDATA(val) | 71 MIIM_CMD_OPR_WRITE, miim->regs + MIIM_CMD); 72 out: 73 return ret; 74 } 75