1 /*
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Description: Hieth mdio operation
18 */
19
20 #define HIETH_SFV300
21
22 #include "hieth.h"
23 #include "mdio.h"
24
25 /* write mdio registers reset value */
mdio_reg_reset(struct hieth_netdev_local * ld)26 static void mdio_reg_reset(struct hieth_netdev_local *ld)
27 {
28 hieth_writel(ld, 0x00008000, MDIO_RWCTRL);
29 hieth_writel(ld, 0x00000001, U_MDIO_PHYADDR);
30 hieth_writel(ld, 0x00000001, D_MDIO_PHYADDR);
31 hieth_writel(ld, 0x04631EA9, U_MDIO_ANEG_CTRL);
32 hieth_writel(ld, 0x04631EA9, D_MDIO_ANEG_CTRL);
33 hieth_writel(ld, 0x00000000, U_MDIO_IRQENA);
34 hieth_writel(ld, 0x00000000, D_MDIO_IRQENA);
35 }
36
wait_mdio_ready(struct hieth_netdev_local * ld)37 static int wait_mdio_ready(struct hieth_netdev_local *ld)
38 {
39 int timeout_us = 5000;
40
41 while (--timeout_us && !test_mdio_ready(ld))
42 udelay(50); /* delay 50us */
43
44 return timeout_us;
45 }
46
hieth_mdio_read(struct hieth_netdev_local * ld,int phy_addr,unsigned int regnum)47 int hieth_mdio_read(struct hieth_netdev_local *ld, int phy_addr, unsigned int regnum)
48 {
49 int val = 0;
50 hieth_assert((!((unsigned int)phy_addr & (~0x1F))) && (!(regnum & (~0x1F))));
51
52 local_lock(ld);
53
54 if (!wait_mdio_ready(ld)) {
55 hieth_error("mdio busy");
56 goto error_exit;
57 }
58
59 mdio_start_phyread(ld, (unsigned int)phy_addr, regnum);
60
61 if (wait_mdio_ready(ld) != 0) {
62 val = mdio_get_phyread_val(ld);
63 } else {
64 hieth_error("read timeout");
65 }
66
67 error_exit:
68
69 local_unlock(ld);
70
71 hieth_trace(HIETH_TRACE_MDIO, "phy_addr = %d, regnum = %d, val = 0x%04x", phy_addr,
72 (int)regnum, val);
73
74 return val;
75 }
76
hieth_mdio_write(struct hieth_netdev_local * ld,int phy_addr,int regnum,int val)77 int hieth_mdio_write(struct hieth_netdev_local *ld, int phy_addr, int regnum, int val)
78 {
79 hieth_assert((!((unsigned int)phy_addr & (~0x1F))) && (!((unsigned int)regnum & (~0x1F))));
80
81 hieth_trace(HIETH_TRACE_MDIO, "phy_addr = %d, regnum = %d", phy_addr, regnum);
82
83 local_lock(ld);
84
85 if (!wait_mdio_ready(ld)) {
86 hieth_error("mdio busy");
87 val = -1;
88 goto error_exit;
89 }
90
91 mdio_phywrite(ld, (unsigned int)phy_addr, (unsigned int)regnum, (unsigned int)val);
92
93 error_exit:
94
95 local_unlock(ld);
96
97 return val;
98 }
99
hieth_mdio_reset(struct hieth_netdev_local * ld)100 int hieth_mdio_reset(struct hieth_netdev_local *ld)
101 {
102 mdio_reg_reset(ld);
103
104 return 0;
105 }
106
hieth_mdio_init(struct hieth_netdev_local * ld)107 int hieth_mdio_init(struct hieth_netdev_local *ld)
108 {
109 local_lock_init(ld);
110
111 hieth_mdio_reset(ld);
112
113 return 0;
114 }
115
hieth_mdio_exit(struct hieth_netdev_local * ld)116 void hieth_mdio_exit(struct hieth_netdev_local *ld)
117 {
118 local_lock_exit(ld);
119 }
120