blob: 343c5f3a38a7773037c16747a28a3e39959b0fe1 [file] [log] [blame]
Yang Xiwen6b5c8d92023-08-23 01:03:43 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Hisilicon Fast Ethernet MDIO Bus Driver
4 *
5 * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
6 */
7
8#include <dm.h>
9#include <clk.h>
10#include <miiphy.h>
11#include <linux/io.h>
12#include <linux/iopoll.h>
13
14#define MDIO_RWCTRL 0x00
15#define MDIO_RO_DATA 0x04
16#define MDIO_WRITE BIT(13)
17#define MDIO_RW_FINISH BIT(15)
18#define BIT_PHY_ADDR_OFFSET 8
19#define BIT_WR_DATA_OFFSET 16
20
21struct hisi_femac_mdio_data {
22 struct clk *clk;
23 void __iomem *membase;
24};
25
26static int hisi_femac_mdio_wait_ready(struct hisi_femac_mdio_data *data)
27{
28 u32 val;
29
30 return readl_poll_timeout(data->membase + MDIO_RWCTRL,
31 val, val & MDIO_RW_FINISH, 10000);
32}
33
34static int hisi_femac_mdio_read(struct udevice *dev, int addr, int devad, int reg)
35{
36 struct hisi_femac_mdio_data *data = dev_get_priv(dev);
37 int ret;
38
39 ret = hisi_femac_mdio_wait_ready(data);
40 if (ret)
41 return ret;
42
43 writel((addr << BIT_PHY_ADDR_OFFSET) | reg,
44 data->membase + MDIO_RWCTRL);
45
46 ret = hisi_femac_mdio_wait_ready(data);
47 if (ret)
48 return ret;
49
50 return readl(data->membase + MDIO_RO_DATA) & 0xFFFF;
51}
52
53static int hisi_femac_mdio_write(struct udevice *dev, int addr, int devad, int reg, u16 val)
54{
55 struct hisi_femac_mdio_data *data = dev_get_priv(dev);
56 int ret;
57
58 ret = hisi_femac_mdio_wait_ready(data);
59 if (ret)
60 return ret;
61
62 writel(MDIO_WRITE | (val << BIT_WR_DATA_OFFSET) |
63 (addr << BIT_PHY_ADDR_OFFSET) | reg,
64 data->membase + MDIO_RWCTRL);
65
66 return hisi_femac_mdio_wait_ready(data);
67}
68
69static int hisi_femac_mdio_of_to_plat(struct udevice *dev)
70{
71 struct hisi_femac_mdio_data *data = dev_get_priv(dev);
72 int ret;
73
74 data->membase = dev_remap_addr(dev);
75 if (IS_ERR(data->membase)) {
76 ret = PTR_ERR(data->membase);
77 return log_msg_ret("Failed to remap base addr", ret);
78 }
79
80 // clk is optional
81 data->clk = devm_clk_get_optional(dev, NULL);
82
83 return 0;
84}
85
86static int hisi_femac_mdio_probe(struct udevice *dev)
87{
88 struct hisi_femac_mdio_data *data = dev_get_priv(dev);
89 int ret;
90
91 ret = clk_prepare_enable(data->clk);
92 if (ret)
93 return log_msg_ret("Failed to enable clk", ret);
94
95 return 0;
96}
97
98static const struct mdio_ops hisi_femac_mdio_ops = {
99 .read = hisi_femac_mdio_read,
100 .write = hisi_femac_mdio_write,
101};
102
103static const struct udevice_id hisi_femac_mdio_dt_ids[] = {
104 { .compatible = "hisilicon,hisi-femac-mdio" },
105 { }
106};
107
108U_BOOT_DRIVER(hisi_femac_mdio_driver) = {
109 .name = "hisi-femac-mdio",
110 .id = UCLASS_MDIO,
111 .of_match = hisi_femac_mdio_dt_ids,
112 .of_to_plat = hisi_femac_mdio_of_to_plat,
113 .probe = hisi_femac_mdio_probe,
114 .ops = &hisi_femac_mdio_ops,
115 .priv_auto = sizeof(struct hisi_femac_mdio_data),
116};