xref: /rk3399_rockchip-uboot/drivers/net/phy/mv88e6352.c (revision 1221ce459d04a428f8880f58581f671b736c3c27)
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, &reg);
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 			&reg);
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, &reg);
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 			&reg);
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, &reg);
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 			&reg);
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