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