1 // SPDX-License-Identifier: GPL-2.0+
4 * Valentin Lontgchamp, Keymile AG, valentin.longchamp@keymile.com
11 #include <linux/delay.h>
12 #include <linux/errno.h>
13 #include <mv88e6352.h>
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)
25 /* global registers */
28 #define GLOBAL_STATUS 0x00
29 #define PPU_STATE 0x8000
31 #define GLOBAL_CTRL 0x04
32 #define SW_RESET 0x8000
33 #define PPU_ENABLE 0x4000
35 static int sw_wait_rdy(const char *devname, u8 phy_addr)
41 /* wait till the SMI is not busy */
43 /* read command register */
44 ret = miiphy_read(devname, phy_addr, COMMAND_REG, &command);
46 printf("%s: Error reading command register\n",
51 printf("Err..(%s) SMI busy timeout\n", __func__);
54 } while (command & SMI_BUSY_MASK);
59 static int sw_reg_read(const char *devname, u8 phy_addr, u8 port,
65 ret = sw_wait_rdy(devname, phy_addr);
69 command = SMI_HDR | SMIRD_OP | ((port&SMI_MASK) << PORT_SHIFT) |
71 debug("%s: write to command: %#x\n", __func__, command);
72 ret = miiphy_write(devname, phy_addr, COMMAND_REG, command);
76 ret = sw_wait_rdy(devname, phy_addr);
80 ret = miiphy_read(devname, phy_addr, DATA_REG, data);
85 static int sw_reg_write(const char *devname, u8 phy_addr, u8 port,
91 ret = sw_wait_rdy(devname, phy_addr);
95 debug("%s: write to data: %#x\n", __func__, data);
96 ret = miiphy_write(devname, phy_addr, DATA_REG, data);
100 value = SMI_HDR | SMIWR_OP | ((port & SMI_MASK) << PORT_SHIFT) |
102 debug("%s: write to command: %#x\n", __func__, value);
103 ret = miiphy_write(devname, phy_addr, COMMAND_REG, value);
107 ret = sw_wait_rdy(devname, phy_addr);
114 static int ppu_enable(const char *devname, u8 phy_addr)
119 ret = sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_CTRL, ®);
121 printf("%s: Error reading global ctrl reg\n", __func__);
127 ret = sw_reg_write(devname, phy_addr, GLOBAL, GLOBAL_CTRL, reg);
129 printf("%s: Error writing global ctrl reg\n", __func__);
133 for (i = 0; i < 1000; i++) {
134 sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS,
136 if ((reg & 0xc000) == 0xc000)
144 static int ppu_disable(const char *devname, u8 phy_addr)
149 ret = sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_CTRL, ®);
151 printf("%s: Error reading global ctrl reg\n", __func__);
157 ret = sw_reg_write(devname, phy_addr, GLOBAL, GLOBAL_CTRL, reg);
159 printf("%s: Error writing global ctrl reg\n", __func__);
163 for (i = 0; i < 1000; i++) {
164 sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS,
166 if ((reg & 0xc000) != 0xc000)
174 int mv88e_sw_program(const char *devname, u8 phy_addr,
175 struct mv88e_sw_reg *regs, int regs_nb)
179 /* first we need to disable the PPU */
180 ret = ppu_disable(devname, phy_addr);
182 printf("%s: Error disabling PPU\n", __func__);
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);
190 printf("%s: Error configuring switch\n", __func__);
191 ppu_enable(devname, phy_addr);
196 /* re-enable the PPU */
197 ret = ppu_enable(devname, phy_addr);
199 printf("%s: Error enabling PPU\n", __func__);
206 int mv88e_sw_reset(const char *devname, u8 phy_addr)
211 ret = sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_CTRL, ®);
213 printf("%s: Error reading global ctrl reg\n", __func__);
217 reg = SW_RESET | PPU_ENABLE | 0x0400;
219 ret = sw_reg_write(devname, phy_addr, GLOBAL, GLOBAL_CTRL, reg);
221 printf("%s: Error writing global ctrl reg\n", __func__);
225 for (i = 0; i < 1000; i++) {
226 sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS,
228 if ((reg & 0xc800) != 0xc800)
236 int do_mvsw_reg_read(const char *name, int argc, char *const argv[])
238 u16 value = 0, phyaddr, reg, port;
241 phyaddr = simple_strtoul(argv[1], NULL, 10);
242 port = simple_strtoul(argv[2], NULL, 10);
243 reg = simple_strtoul(argv[3], NULL, 10);
245 ret = sw_reg_read(name, phyaddr, port, reg, &value);
246 printf("%#x\n", value);
251 int do_mvsw_reg_write(const char *name, int argc, char *const argv[])
253 u16 value = 0, phyaddr, reg, port;
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);
261 ret = sw_reg_write(name, phyaddr, port, reg, value);
267 int do_mvsw_reg(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
270 const char *cmd, *ethname;
273 return cmd_usage(cmdtp);
279 if (strcmp(cmd, "read") == 0) {
281 return cmd_usage(cmdtp);
285 ret = do_mvsw_reg_read(ethname, argc, argv);
286 } else if (strcmp(cmd, "write") == 0) {
288 return cmd_usage(cmdtp);
292 ret = do_mvsw_reg_write(ethname, argc, argv);
294 return cmd_usage(cmdtp);
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"