Merge tag 'u-boot-imx-20190426' of git://git.denx.de/u-boot-imx
[oweals/u-boot.git] / drivers / net / mscc_eswitch / mscc_miim.c
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 }