blob: d8ee8df47b18b9245826b194fd5c14afcbc426ec [file] [log] [blame]
Horatiu Vultur236dabc2019-01-31 15:30:34 +01001// 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
24static 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
30int 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
59int 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}
Horatiu Vultur6fbf1612019-06-09 15:27:29 +020075
76struct mii_dev *mscc_mdiobus_init(struct mscc_miim_dev *miim, int *miim_count,
77 phys_addr_t miim_base,
78 unsigned long miim_size)
79{
80 struct mii_dev *bus;
81
82 bus = mdio_alloc();
83
84 if (!bus)
85 return NULL;
86
87 *miim_count += 1;
88 sprintf(bus->name, "miim-bus%d", *miim_count);
89
90 miim[*miim_count].regs = ioremap(miim_base, miim_size);
91 miim[*miim_count].miim_base = miim_base;
92 miim[*miim_count].miim_size = miim_size;
93 bus->priv = &miim[*miim_count];
94 bus->read = mscc_miim_read;
95 bus->write = mscc_miim_write;
96
97 if (mdio_register(bus))
98 return NULL;
99
100 miim[*miim_count].bus = bus;
101 return bus;
102}