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