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