3 * Valentin Lontgchamp, Keymile AG, valentin.longchamp@keymile.com
5 * SPDX-License-Identifier: GPL-2.0+
10 #include <asm/errno.h>
11 #include <mv88e6352.h>
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)
23 /* global registers */
26 #define GLOBAL_STATUS 0x00
27 #define PPU_STATE 0x8000
29 #define GLOBAL_CTRL 0x04
30 #define SW_RESET 0x8000
31 #define PPU_ENABLE 0x4000
33 static int sw_wait_rdy(const char *devname, u8 phy_addr)
39 /* wait till the SMI is not busy */
41 /* read command register */
42 ret = miiphy_read(devname, phy_addr, COMMAND_REG, &command);
44 printf("%s: Error reading command register\n",
49 printf("Err..(%s) SMI busy timeout\n", __func__);
52 } while (command & SMI_BUSY_MASK);
57 static int sw_reg_read(const char *devname, u8 phy_addr, u8 port,
63 ret = sw_wait_rdy(devname, phy_addr);
67 command = SMI_HDR | SMIRD_OP | ((port&SMI_MASK) << PORT_SHIFT) |
69 debug("%s: write to command: %#x\n", __func__, command);
70 ret = miiphy_write(devname, phy_addr, COMMAND_REG, command);
74 ret = sw_wait_rdy(devname, phy_addr);
78 ret = miiphy_read(devname, phy_addr, DATA_REG, data);
83 static int sw_reg_write(const char *devname, u8 phy_addr, u8 port,
89 ret = sw_wait_rdy(devname, phy_addr);
93 debug("%s: write to data: %#x\n", __func__, data);
94 ret = miiphy_write(devname, phy_addr, DATA_REG, data);
98 value = SMI_HDR | SMIWR_OP | ((port & SMI_MASK) << PORT_SHIFT) |
100 debug("%s: write to command: %#x\n", __func__, value);
101 ret = miiphy_write(devname, phy_addr, COMMAND_REG, value);
105 ret = sw_wait_rdy(devname, phy_addr);
112 static int ppu_enable(const char *devname, u8 phy_addr)
117 ret = sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_CTRL, ®);
119 printf("%s: Error reading global ctrl reg\n", __func__);
125 ret = sw_reg_write(devname, phy_addr, GLOBAL, GLOBAL_CTRL, reg);
127 printf("%s: Error writing global ctrl reg\n", __func__);
131 for (i = 0; i < 1000; i++) {
132 sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS,
134 if ((reg & 0xc000) == 0xc000)
142 static int ppu_disable(const char *devname, u8 phy_addr)
147 ret = sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_CTRL, ®);
149 printf("%s: Error reading global ctrl reg\n", __func__);
155 ret = sw_reg_write(devname, phy_addr, GLOBAL, GLOBAL_CTRL, reg);
157 printf("%s: Error writing global ctrl reg\n", __func__);
161 for (i = 0; i < 1000; i++) {
162 sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS,
164 if ((reg & 0xc000) != 0xc000)
172 int mv88e_sw_program(const char *devname, u8 phy_addr,
173 struct mv88e_sw_reg *regs, int regs_nb)
177 /* first we need to disable the PPU */
178 ret = ppu_disable(devname, phy_addr);
180 printf("%s: Error disabling PPU\n", __func__);
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);
188 printf("%s: Error configuring switch\n", __func__);
189 ppu_enable(devname, phy_addr);
194 /* re-enable the PPU */
195 ret = ppu_enable(devname, phy_addr);
197 printf("%s: Error enabling PPU\n", __func__);
204 int mv88e_sw_reset(const char *devname, u8 phy_addr)
209 ret = sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_CTRL, ®);
211 printf("%s: Error reading global ctrl reg\n", __func__);
215 reg = SW_RESET | PPU_ENABLE | 0x0400;
217 ret = sw_reg_write(devname, phy_addr, GLOBAL, GLOBAL_CTRL, reg);
219 printf("%s: Error writing global ctrl reg\n", __func__);
223 for (i = 0; i < 1000; i++) {
224 sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS,
226 if ((reg & 0xc800) != 0xc800)
234 int do_mvsw_reg_read(const char *name, int argc, char * const argv[])
236 u16 value = 0, phyaddr, reg, port;
239 phyaddr = simple_strtoul(argv[1], NULL, 10);
240 port = simple_strtoul(argv[2], NULL, 10);
241 reg = simple_strtoul(argv[3], NULL, 10);
243 ret = sw_reg_read(name, phyaddr, port, reg, &value);
244 printf("%#x\n", value);
249 int do_mvsw_reg_write(const char *name, int argc, char * const argv[])
251 u16 value = 0, phyaddr, reg, port;
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);
259 ret = sw_reg_write(name, phyaddr, port, reg, value);
265 int do_mvsw_reg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
268 const char *cmd, *ethname;
271 return cmd_usage(cmdtp);
277 if (strcmp(cmd, "read") == 0) {
279 return cmd_usage(cmdtp);
283 ret = do_mvsw_reg_read(ethname, argc, argv);
284 } else if (strcmp(cmd, "write") == 0) {
286 return cmd_usage(cmdtp);
290 ret = do_mvsw_reg_write(ethname, argc, argv);
292 return cmd_usage(cmdtp);
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"