3 * Valentin Lontgchamp, Keymile AG, valentin.longchamp@keymile.com
5 * See file CREDITS for list of people who contributed to this
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 #include <asm/errno.h>
27 #include <mv88e6352.h>
29 #define SMI_HDR ((0x8 | 0x1) << 12)
30 #define SMI_BUSY_MASK (0x8000)
31 #define SMIRD_OP (0x2 << 10)
32 #define SMIWR_OP (0x1 << 10)
39 /* global registers */
42 #define GLOBAL_STATUS 0x00
43 #define PPU_STATE 0x8000
45 #define GLOBAL_CTRL 0x04
46 #define SW_RESET 0x8000
47 #define PPU_ENABLE 0x4000
49 static int sw_wait_rdy(const char *devname, u8 phy_addr)
55 /* wait till the SMI is not busy */
57 /* read command register */
58 ret = miiphy_read(devname, phy_addr, COMMAND_REG, &command);
60 printf("%s: Error reading command register\n",
65 printf("Err..(%s) SMI busy timeout\n", __func__);
68 } while (command & SMI_BUSY_MASK);
73 static int sw_reg_read(const char *devname, u8 phy_addr, u8 port,
79 ret = sw_wait_rdy(devname, phy_addr);
83 command = SMI_HDR | SMIRD_OP | ((port&SMI_MASK) << PORT_SHIFT) |
85 debug("%s: write to command: %#x\n", __func__, command);
86 ret = miiphy_write(devname, phy_addr, COMMAND_REG, command);
90 ret = sw_wait_rdy(devname, phy_addr);
94 ret = miiphy_read(devname, phy_addr, DATA_REG, data);
99 static int sw_reg_write(const char *devname, u8 phy_addr, u8 port,
105 ret = sw_wait_rdy(devname, phy_addr);
109 debug("%s: write to data: %#x\n", __func__, data);
110 ret = miiphy_write(devname, phy_addr, DATA_REG, data);
114 value = SMI_HDR | SMIWR_OP | ((port & SMI_MASK) << PORT_SHIFT) |
116 debug("%s: write to command: %#x\n", __func__, value);
117 ret = miiphy_write(devname, phy_addr, COMMAND_REG, value);
121 ret = sw_wait_rdy(devname, phy_addr);
128 static int ppu_enable(const char *devname, u8 phy_addr)
133 ret = sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_CTRL, ®);
135 printf("%s: Error reading global ctrl reg\n", __func__);
141 ret = sw_reg_write(devname, phy_addr, GLOBAL, GLOBAL_CTRL, reg);
143 printf("%s: Error writing global ctrl reg\n", __func__);
147 for (i = 0; i < 1000; i++) {
148 sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS,
150 if ((reg & 0xc000) == 0xc000)
158 static int ppu_disable(const char *devname, u8 phy_addr)
163 ret = sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_CTRL, ®);
165 printf("%s: Error reading global ctrl reg\n", __func__);
171 ret = sw_reg_write(devname, phy_addr, GLOBAL, GLOBAL_CTRL, reg);
173 printf("%s: Error writing global ctrl reg\n", __func__);
177 for (i = 0; i < 1000; i++) {
178 sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS,
180 if ((reg & 0xc000) != 0xc000)
188 int mv88e_sw_program(const char *devname, u8 phy_addr,
189 struct mv88e_sw_reg *regs, int regs_nb)
193 /* first we need to disable the PPU */
194 ret = ppu_disable(devname, phy_addr);
196 printf("%s: Error disabling PPU\n", __func__);
200 for (i = 0; i < regs_nb; i++) {
201 ret = sw_reg_write(devname, phy_addr, regs[i].port,
202 regs[i].reg, regs[i].value);
204 printf("%s: Error configuring switch\n", __func__);
205 ppu_enable(devname, phy_addr);
210 /* re-enable the PPU */
211 ret = ppu_enable(devname, phy_addr);
213 printf("%s: Error enabling PPU\n", __func__);
220 int mv88e_sw_reset(const char *devname, u8 phy_addr)
225 ret = sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_CTRL, ®);
227 printf("%s: Error reading global ctrl reg\n", __func__);
231 reg = SW_RESET | PPU_ENABLE | 0x0400;
233 ret = sw_reg_write(devname, phy_addr, GLOBAL, GLOBAL_CTRL, reg);
235 printf("%s: Error writing global ctrl reg\n", __func__);
239 for (i = 0; i < 1000; i++) {
240 sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS,
242 if ((reg & 0xc800) != 0xc800)
250 int do_mvsw_reg_read(const char *name, int argc, char * const argv[])
252 u16 value = 0, phyaddr, reg, port;
255 phyaddr = simple_strtoul(argv[1], NULL, 10);
256 port = simple_strtoul(argv[2], NULL, 10);
257 reg = simple_strtoul(argv[3], NULL, 10);
259 ret = sw_reg_read(name, phyaddr, port, reg, &value);
260 printf("%#x\n", value);
265 int do_mvsw_reg_write(const char *name, int argc, char * const argv[])
267 u16 value = 0, phyaddr, reg, port;
270 phyaddr = simple_strtoul(argv[1], NULL, 10);
271 port = simple_strtoul(argv[2], NULL, 10);
272 reg = simple_strtoul(argv[3], NULL, 10);
273 value = simple_strtoul(argv[4], NULL, 16);
275 ret = sw_reg_write(name, phyaddr, port, reg, value);
281 int do_mvsw_reg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
284 const char *cmd, *ethname;
287 return cmd_usage(cmdtp);
293 if (strcmp(cmd, "read") == 0) {
295 return cmd_usage(cmdtp);
299 ret = do_mvsw_reg_read(ethname, argc, argv);
300 } else if (strcmp(cmd, "write") == 0) {
302 return cmd_usage(cmdtp);
306 ret = do_mvsw_reg_write(ethname, argc, argv);
308 return cmd_usage(cmdtp);
314 mvsw_reg, 7, 1, do_mvsw_reg,
315 "marvell 88e6352 switch register access",
316 "write ethname phyaddr port reg value\n"
317 "mvsw_reg read ethname phyaddr port reg\n"