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