1 // SPDX-License-Identifier: GPL-2.0+
3 * Hisilicon Fast Ethernet MDIO Bus Driver
5 * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
11 #include <dm/device_compat.h>
13 #include <linux/iopoll.h>
15 #define MDIO_RWCTRL 0x00
16 #define MDIO_RO_DATA 0x04
17 #define MDIO_WRITE BIT(13)
18 #define MDIO_RW_FINISH BIT(15)
19 #define BIT_PHY_ADDR_OFFSET 8
20 #define BIT_WR_DATA_OFFSET 16
22 struct hisi_femac_mdio_data
{
24 void __iomem
*membase
;
27 static int hisi_femac_mdio_wait_ready(struct hisi_femac_mdio_data
*data
)
31 return readl_poll_timeout(data
->membase
+ MDIO_RWCTRL
,
32 val
, val
& MDIO_RW_FINISH
, 10000);
35 static int hisi_femac_mdio_read(struct udevice
*dev
, int addr
, int devad
, int reg
)
37 struct hisi_femac_mdio_data
*data
= dev_get_priv(dev
);
40 ret
= hisi_femac_mdio_wait_ready(data
);
44 writel((addr
<< BIT_PHY_ADDR_OFFSET
) | reg
,
45 data
->membase
+ MDIO_RWCTRL
);
47 ret
= hisi_femac_mdio_wait_ready(data
);
51 return readl(data
->membase
+ MDIO_RO_DATA
) & 0xFFFF;
54 static int hisi_femac_mdio_write(struct udevice
*dev
, int addr
, int devad
, int reg
, u16 val
)
56 struct hisi_femac_mdio_data
*data
= dev_get_priv(dev
);
59 ret
= hisi_femac_mdio_wait_ready(data
);
63 writel(MDIO_WRITE
| (val
<< BIT_WR_DATA_OFFSET
) |
64 (addr
<< BIT_PHY_ADDR_OFFSET
) | reg
,
65 data
->membase
+ MDIO_RWCTRL
);
67 return hisi_femac_mdio_wait_ready(data
);
70 static int hisi_femac_mdio_of_to_plat(struct udevice
*dev
)
72 struct hisi_femac_mdio_data
*data
= dev_get_priv(dev
);
75 data
->membase
= dev_remap_addr(dev
);
76 if (IS_ERR(data
->membase
)) {
77 ret
= PTR_ERR(data
->membase
);
78 dev_err(dev
, "Failed to remap base addr %d\n", ret
);
79 return log_msg_ret("mdio", ret
);
83 data
->clk
= devm_clk_get_optional(dev
, NULL
);
88 static int hisi_femac_mdio_probe(struct udevice
*dev
)
90 struct hisi_femac_mdio_data
*data
= dev_get_priv(dev
);
93 ret
= clk_prepare_enable(data
->clk
);
95 dev_err(dev
, "Failed to enable clock: %d\n", ret
);
96 return log_msg_ret("clk", ret
);
102 static const struct mdio_ops hisi_femac_mdio_ops
= {
103 .read
= hisi_femac_mdio_read
,
104 .write
= hisi_femac_mdio_write
,
107 static const struct udevice_id hisi_femac_mdio_dt_ids
[] = {
108 { .compatible
= "hisilicon,hisi-femac-mdio" },
112 U_BOOT_DRIVER(hisi_femac_mdio_driver
) = {
113 .name
= "hisi-femac-mdio",
115 .of_match
= hisi_femac_mdio_dt_ids
,
116 .of_to_plat
= hisi_femac_mdio_of_to_plat
,
117 .probe
= hisi_femac_mdio_probe
,
118 .ops
= &hisi_femac_mdio_ops
,
119 .plat_auto
= sizeof(struct mdio_perdev_priv
),
120 .priv_auto
= sizeof(struct hisi_femac_mdio_data
),