common: Drop linux/delay.h from common header
[oweals/u-boot.git] / drivers / net / phy / mv88e6352.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2012
4  * Valentin Lontgchamp, Keymile AG, valentin.longchamp@keymile.com
5  */
6
7 #include <common.h>
8 #include <command.h>
9 #include <log.h>
10 #include <miiphy.h>
11 #include <linux/delay.h>
12 #include <linux/errno.h>
13 #include <mv88e6352.h>
14
15 #define SMI_HDR         ((0x8 | 0x1) << 12)
16 #define SMI_BUSY_MASK   (0x8000)
17 #define SMIRD_OP        (0x2 << 10)
18 #define SMIWR_OP        (0x1 << 10)
19 #define SMI_MASK        0x1f
20 #define PORT_SHIFT      5
21
22 #define COMMAND_REG     0
23 #define DATA_REG        1
24
25 /* global registers */
26 #define GLOBAL          0x1b
27
28 #define GLOBAL_STATUS   0x00
29 #define PPU_STATE       0x8000
30
31 #define GLOBAL_CTRL     0x04
32 #define SW_RESET        0x8000
33 #define PPU_ENABLE      0x4000
34
35 static int sw_wait_rdy(const char *devname, u8 phy_addr)
36 {
37         u16 command;
38         u32 timeout = 100;
39         int ret;
40
41         /* wait till the SMI is not busy */
42         do {
43                 /* read command register */
44                 ret = miiphy_read(devname, phy_addr, COMMAND_REG, &command);
45                 if (ret < 0) {
46                         printf("%s: Error reading command register\n",
47                                 __func__);
48                         return ret;
49                 }
50                 if (timeout-- == 0) {
51                         printf("Err..(%s) SMI busy timeout\n", __func__);
52                         return -EFAULT;
53                 }
54         } while (command & SMI_BUSY_MASK);
55
56         return 0;
57 }
58
59 static int sw_reg_read(const char *devname, u8 phy_addr, u8 port,
60         u8 reg, u16 *data)
61 {
62         int ret;
63         u16 command;
64
65         ret = sw_wait_rdy(devname, phy_addr);
66         if (ret)
67                 return ret;
68
69         command = SMI_HDR | SMIRD_OP | ((port&SMI_MASK) << PORT_SHIFT) |
70                         (reg & SMI_MASK);
71         debug("%s: write to command: %#x\n", __func__, command);
72         ret = miiphy_write(devname, phy_addr, COMMAND_REG, command);
73         if (ret)
74                 return ret;
75
76         ret = sw_wait_rdy(devname, phy_addr);
77         if (ret)
78                 return ret;
79
80         ret = miiphy_read(devname, phy_addr, DATA_REG, data);
81
82         return ret;
83 }
84
85 static int sw_reg_write(const char *devname, u8 phy_addr, u8 port,
86         u8 reg, u16 data)
87 {
88         int ret;
89         u16 value;
90
91         ret = sw_wait_rdy(devname, phy_addr);
92         if (ret)
93                 return ret;
94
95         debug("%s: write to data: %#x\n", __func__, data);
96         ret = miiphy_write(devname, phy_addr, DATA_REG, data);
97         if (ret)
98                 return ret;
99
100         value = SMI_HDR | SMIWR_OP | ((port & SMI_MASK) << PORT_SHIFT) |
101                         (reg & SMI_MASK);
102         debug("%s: write to command: %#x\n", __func__, value);
103         ret = miiphy_write(devname, phy_addr, COMMAND_REG, value);
104         if (ret)
105                 return ret;
106
107         ret = sw_wait_rdy(devname, phy_addr);
108         if (ret)
109                 return ret;
110
111         return 0;
112 }
113
114 static int ppu_enable(const char *devname, u8 phy_addr)
115 {
116         int i, ret = 0;
117         u16 reg;
118
119         ret = sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_CTRL, &reg);
120         if (ret) {
121                 printf("%s: Error reading global ctrl reg\n", __func__);
122                 return ret;
123         }
124
125         reg |= PPU_ENABLE;
126
127         ret = sw_reg_write(devname, phy_addr, GLOBAL, GLOBAL_CTRL, reg);
128         if (ret) {
129                 printf("%s: Error writing global ctrl reg\n", __func__);
130                 return ret;
131         }
132
133         for (i = 0; i < 1000; i++) {
134                 sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS,
135                         &reg);
136                 if ((reg & 0xc000) == 0xc000)
137                         return 0;
138                 udelay(1000);
139         }
140
141         return -ETIMEDOUT;
142 }
143
144 static int ppu_disable(const char *devname, u8 phy_addr)
145 {
146         int i, ret = 0;
147         u16 reg;
148
149         ret = sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_CTRL, &reg);
150         if (ret) {
151                 printf("%s: Error reading global ctrl reg\n", __func__);
152                 return ret;
153         }
154
155         reg &= ~PPU_ENABLE;
156
157         ret = sw_reg_write(devname, phy_addr, GLOBAL, GLOBAL_CTRL, reg);
158         if (ret) {
159                 printf("%s: Error writing global ctrl reg\n", __func__);
160                 return ret;
161         }
162
163         for (i = 0; i < 1000; i++) {
164                 sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS,
165                         &reg);
166                 if ((reg & 0xc000) != 0xc000)
167                         return 0;
168                 udelay(1000);
169         }
170
171         return -ETIMEDOUT;
172 }
173
174 int mv88e_sw_program(const char *devname, u8 phy_addr,
175         struct mv88e_sw_reg *regs, int regs_nb)
176 {
177         int i, ret = 0;
178
179         /* first we need to disable the PPU */
180         ret = ppu_disable(devname, phy_addr);
181         if (ret) {
182                 printf("%s: Error disabling PPU\n", __func__);
183                 return ret;
184         }
185
186         for (i = 0; i < regs_nb; i++) {
187                 ret = sw_reg_write(devname, phy_addr, regs[i].port,
188                         regs[i].reg, regs[i].value);
189                 if (ret) {
190                         printf("%s: Error configuring switch\n", __func__);
191                         ppu_enable(devname, phy_addr);
192                         return ret;
193                 }
194         }
195
196         /* re-enable the PPU */
197         ret = ppu_enable(devname, phy_addr);
198         if (ret) {
199                 printf("%s: Error enabling PPU\n", __func__);
200                 return ret;
201         }
202
203         return 0;
204 }
205
206 int mv88e_sw_reset(const char *devname, u8 phy_addr)
207 {
208         int i, ret = 0;
209         u16 reg;
210
211         ret = sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_CTRL, &reg);
212         if (ret) {
213                 printf("%s: Error reading global ctrl reg\n", __func__);
214                 return ret;
215         }
216
217         reg = SW_RESET | PPU_ENABLE | 0x0400;
218
219         ret = sw_reg_write(devname, phy_addr, GLOBAL, GLOBAL_CTRL, reg);
220         if (ret) {
221                 printf("%s: Error writing global ctrl reg\n", __func__);
222                 return ret;
223         }
224
225         for (i = 0; i < 1000; i++) {
226                 sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS,
227                         &reg);
228                 if ((reg & 0xc800) != 0xc800)
229                         return 0;
230                 udelay(1000);
231         }
232
233         return -ETIMEDOUT;
234 }
235
236 int do_mvsw_reg_read(const char *name, int argc, char *const argv[])
237 {
238         u16 value = 0, phyaddr, reg, port;
239         int ret;
240
241         phyaddr = simple_strtoul(argv[1], NULL, 10);
242         port = simple_strtoul(argv[2], NULL, 10);
243         reg = simple_strtoul(argv[3], NULL, 10);
244
245         ret = sw_reg_read(name, phyaddr, port, reg, &value);
246         printf("%#x\n", value);
247
248         return ret;
249 }
250
251 int do_mvsw_reg_write(const char *name, int argc, char *const argv[])
252 {
253         u16 value = 0, phyaddr, reg, port;
254         int ret;
255
256         phyaddr = simple_strtoul(argv[1], NULL, 10);
257         port = simple_strtoul(argv[2], NULL, 10);
258         reg = simple_strtoul(argv[3], NULL, 10);
259         value = simple_strtoul(argv[4], NULL, 16);
260
261         ret = sw_reg_write(name, phyaddr, port, reg, value);
262
263         return ret;
264 }
265
266
267 int do_mvsw_reg(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
268 {
269         int ret;
270         const char *cmd, *ethname;
271
272         if (argc < 2)
273                 return cmd_usage(cmdtp);
274
275         cmd = argv[1];
276         --argc;
277         ++argv;
278
279         if (strcmp(cmd, "read") == 0) {
280                 if (argc < 5)
281                         return cmd_usage(cmdtp);
282                 ethname = argv[1];
283                 --argc;
284                 ++argv;
285                 ret = do_mvsw_reg_read(ethname, argc, argv);
286         } else if (strcmp(cmd, "write") == 0) {
287                 if (argc < 6)
288                         return cmd_usage(cmdtp);
289                 ethname = argv[1];
290                 --argc;
291                 ++argv;
292                 ret = do_mvsw_reg_write(ethname, argc, argv);
293         } else
294                 return cmd_usage(cmdtp);
295
296         return ret;
297 }
298
299 U_BOOT_CMD(
300         mvsw_reg,       7,      1,      do_mvsw_reg,
301         "marvell 88e6352 switch register access",
302         "write ethname phyaddr port reg value\n"
303         "mvsw_reg read  ethname phyaddr port reg\n"
304         );