xref: /OK3568_Linux_fs/kernel/drivers/net/ethernet/ti/cpsw_sl.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Texas Instruments Ethernet Switch media-access-controller (MAC) submodule/
4*4882a593Smuzhiyun  * Ethernet MAC Sliver (CPGMAC_SL)
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright (C) 2019 Texas Instruments
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/delay.h>
11*4882a593Smuzhiyun #include <linux/io.h>
12*4882a593Smuzhiyun #include <linux/kernel.h>
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #include "cpsw_sl.h"
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #define CPSW_SL_REG_NOTUSED U16_MAX
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun static const u16 cpsw_sl_reg_map_cpsw[] = {
19*4882a593Smuzhiyun 	[CPSW_SL_IDVER] = 0x00,
20*4882a593Smuzhiyun 	[CPSW_SL_MACCONTROL] = 0x04,
21*4882a593Smuzhiyun 	[CPSW_SL_MACSTATUS] = 0x08,
22*4882a593Smuzhiyun 	[CPSW_SL_SOFT_RESET] = 0x0c,
23*4882a593Smuzhiyun 	[CPSW_SL_RX_MAXLEN] = 0x10,
24*4882a593Smuzhiyun 	[CPSW_SL_BOFFTEST] = 0x14,
25*4882a593Smuzhiyun 	[CPSW_SL_RX_PAUSE] = 0x18,
26*4882a593Smuzhiyun 	[CPSW_SL_TX_PAUSE] = 0x1c,
27*4882a593Smuzhiyun 	[CPSW_SL_EMCONTROL] = 0x20,
28*4882a593Smuzhiyun 	[CPSW_SL_RX_PRI_MAP] = 0x24,
29*4882a593Smuzhiyun 	[CPSW_SL_TX_GAP] = 0x28,
30*4882a593Smuzhiyun };
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun static const u16 cpsw_sl_reg_map_66ak2hk[] = {
33*4882a593Smuzhiyun 	[CPSW_SL_IDVER] = 0x00,
34*4882a593Smuzhiyun 	[CPSW_SL_MACCONTROL] = 0x04,
35*4882a593Smuzhiyun 	[CPSW_SL_MACSTATUS] = 0x08,
36*4882a593Smuzhiyun 	[CPSW_SL_SOFT_RESET] = 0x0c,
37*4882a593Smuzhiyun 	[CPSW_SL_RX_MAXLEN] = 0x10,
38*4882a593Smuzhiyun 	[CPSW_SL_BOFFTEST] = CPSW_SL_REG_NOTUSED,
39*4882a593Smuzhiyun 	[CPSW_SL_RX_PAUSE] = 0x18,
40*4882a593Smuzhiyun 	[CPSW_SL_TX_PAUSE] = 0x1c,
41*4882a593Smuzhiyun 	[CPSW_SL_EMCONTROL] = 0x20,
42*4882a593Smuzhiyun 	[CPSW_SL_RX_PRI_MAP] = 0x24,
43*4882a593Smuzhiyun 	[CPSW_SL_TX_GAP] = CPSW_SL_REG_NOTUSED,
44*4882a593Smuzhiyun };
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun static const u16 cpsw_sl_reg_map_66ak2x_xgbe[] = {
47*4882a593Smuzhiyun 	[CPSW_SL_IDVER] = 0x00,
48*4882a593Smuzhiyun 	[CPSW_SL_MACCONTROL] = 0x04,
49*4882a593Smuzhiyun 	[CPSW_SL_MACSTATUS] = 0x08,
50*4882a593Smuzhiyun 	[CPSW_SL_SOFT_RESET] = 0x0c,
51*4882a593Smuzhiyun 	[CPSW_SL_RX_MAXLEN] = 0x10,
52*4882a593Smuzhiyun 	[CPSW_SL_BOFFTEST] = CPSW_SL_REG_NOTUSED,
53*4882a593Smuzhiyun 	[CPSW_SL_RX_PAUSE] = 0x18,
54*4882a593Smuzhiyun 	[CPSW_SL_TX_PAUSE] = 0x1c,
55*4882a593Smuzhiyun 	[CPSW_SL_EMCONTROL] = 0x20,
56*4882a593Smuzhiyun 	[CPSW_SL_RX_PRI_MAP] = CPSW_SL_REG_NOTUSED,
57*4882a593Smuzhiyun 	[CPSW_SL_TX_GAP] = 0x28,
58*4882a593Smuzhiyun };
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun static const u16 cpsw_sl_reg_map_66ak2elg_am65[] = {
61*4882a593Smuzhiyun 	[CPSW_SL_IDVER] = CPSW_SL_REG_NOTUSED,
62*4882a593Smuzhiyun 	[CPSW_SL_MACCONTROL] = 0x00,
63*4882a593Smuzhiyun 	[CPSW_SL_MACSTATUS] = 0x04,
64*4882a593Smuzhiyun 	[CPSW_SL_SOFT_RESET] = 0x08,
65*4882a593Smuzhiyun 	[CPSW_SL_RX_MAXLEN] = CPSW_SL_REG_NOTUSED,
66*4882a593Smuzhiyun 	[CPSW_SL_BOFFTEST] = 0x0c,
67*4882a593Smuzhiyun 	[CPSW_SL_RX_PAUSE] = 0x10,
68*4882a593Smuzhiyun 	[CPSW_SL_TX_PAUSE] = 0x40,
69*4882a593Smuzhiyun 	[CPSW_SL_EMCONTROL] = 0x70,
70*4882a593Smuzhiyun 	[CPSW_SL_RX_PRI_MAP] = CPSW_SL_REG_NOTUSED,
71*4882a593Smuzhiyun 	[CPSW_SL_TX_GAP] = 0x74,
72*4882a593Smuzhiyun };
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun #define CPSW_SL_SOFT_RESET_BIT		BIT(0)
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun #define CPSW_SL_STATUS_PN_IDLE		BIT(31)
77*4882a593Smuzhiyun #define CPSW_SL_AM65_STATUS_PN_E_IDLE	BIT(30)
78*4882a593Smuzhiyun #define CPSW_SL_AM65_STATUS_PN_P_IDLE	BIT(29)
79*4882a593Smuzhiyun #define CPSW_SL_AM65_STATUS_PN_TX_IDLE	BIT(28)
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun #define CPSW_SL_STATUS_IDLE_MASK_BASE (CPSW_SL_STATUS_PN_IDLE)
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun #define CPSW_SL_STATUS_IDLE_MASK_K3 \
84*4882a593Smuzhiyun 	(CPSW_SL_STATUS_IDLE_MASK_BASE | CPSW_SL_AM65_STATUS_PN_E_IDLE | \
85*4882a593Smuzhiyun 	 CPSW_SL_AM65_STATUS_PN_P_IDLE | CPSW_SL_AM65_STATUS_PN_TX_IDLE)
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun #define CPSW_SL_CTL_FUNC_BASE \
88*4882a593Smuzhiyun 	(CPSW_SL_CTL_FULLDUPLEX |\
89*4882a593Smuzhiyun 	CPSW_SL_CTL_LOOPBACK |\
90*4882a593Smuzhiyun 	CPSW_SL_CTL_RX_FLOW_EN |\
91*4882a593Smuzhiyun 	CPSW_SL_CTL_TX_FLOW_EN |\
92*4882a593Smuzhiyun 	CPSW_SL_CTL_GMII_EN |\
93*4882a593Smuzhiyun 	CPSW_SL_CTL_TX_PACE |\
94*4882a593Smuzhiyun 	CPSW_SL_CTL_GIG |\
95*4882a593Smuzhiyun 	CPSW_SL_CTL_CMD_IDLE |\
96*4882a593Smuzhiyun 	CPSW_SL_CTL_IFCTL_A |\
97*4882a593Smuzhiyun 	CPSW_SL_CTL_IFCTL_B |\
98*4882a593Smuzhiyun 	CPSW_SL_CTL_GIG_FORCE |\
99*4882a593Smuzhiyun 	CPSW_SL_CTL_EXT_EN |\
100*4882a593Smuzhiyun 	CPSW_SL_CTL_RX_CEF_EN |\
101*4882a593Smuzhiyun 	CPSW_SL_CTL_RX_CSF_EN |\
102*4882a593Smuzhiyun 	CPSW_SL_CTL_RX_CMF_EN)
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun struct cpsw_sl {
105*4882a593Smuzhiyun 	struct device *dev;
106*4882a593Smuzhiyun 	void __iomem *sl_base;
107*4882a593Smuzhiyun 	const u16 *regs;
108*4882a593Smuzhiyun 	u32 control_features;
109*4882a593Smuzhiyun 	u32 idle_mask;
110*4882a593Smuzhiyun };
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun struct cpsw_sl_dev_id {
113*4882a593Smuzhiyun 	const char *device_id;
114*4882a593Smuzhiyun 	const u16 *regs;
115*4882a593Smuzhiyun 	const u32 control_features;
116*4882a593Smuzhiyun 	const u32 regs_offset;
117*4882a593Smuzhiyun 	const u32 idle_mask;
118*4882a593Smuzhiyun };
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun static const struct cpsw_sl_dev_id cpsw_sl_id_match[] = {
121*4882a593Smuzhiyun 	{
122*4882a593Smuzhiyun 		.device_id = "cpsw",
123*4882a593Smuzhiyun 		.regs = cpsw_sl_reg_map_cpsw,
124*4882a593Smuzhiyun 		.control_features = CPSW_SL_CTL_FUNC_BASE |
125*4882a593Smuzhiyun 				    CPSW_SL_CTL_MTEST |
126*4882a593Smuzhiyun 				    CPSW_SL_CTL_TX_SHORT_GAP_EN |
127*4882a593Smuzhiyun 				    CPSW_SL_CTL_TX_SG_LIM_EN,
128*4882a593Smuzhiyun 		.idle_mask = CPSW_SL_STATUS_IDLE_MASK_BASE,
129*4882a593Smuzhiyun 	},
130*4882a593Smuzhiyun 	{
131*4882a593Smuzhiyun 		.device_id = "66ak2hk",
132*4882a593Smuzhiyun 		.regs = cpsw_sl_reg_map_66ak2hk,
133*4882a593Smuzhiyun 		.control_features = CPSW_SL_CTL_FUNC_BASE |
134*4882a593Smuzhiyun 				    CPSW_SL_CTL_TX_SHORT_GAP_EN,
135*4882a593Smuzhiyun 		.idle_mask = CPSW_SL_STATUS_IDLE_MASK_BASE,
136*4882a593Smuzhiyun 	},
137*4882a593Smuzhiyun 	{
138*4882a593Smuzhiyun 		.device_id = "66ak2x_xgbe",
139*4882a593Smuzhiyun 		.regs = cpsw_sl_reg_map_66ak2x_xgbe,
140*4882a593Smuzhiyun 		.control_features = CPSW_SL_CTL_FUNC_BASE |
141*4882a593Smuzhiyun 				    CPSW_SL_CTL_XGIG |
142*4882a593Smuzhiyun 				    CPSW_SL_CTL_TX_SHORT_GAP_EN |
143*4882a593Smuzhiyun 				    CPSW_SL_CTL_CRC_TYPE |
144*4882a593Smuzhiyun 				    CPSW_SL_CTL_XGMII_EN,
145*4882a593Smuzhiyun 		.idle_mask = CPSW_SL_STATUS_IDLE_MASK_BASE,
146*4882a593Smuzhiyun 	},
147*4882a593Smuzhiyun 	{
148*4882a593Smuzhiyun 		.device_id = "66ak2el",
149*4882a593Smuzhiyun 		.regs = cpsw_sl_reg_map_66ak2elg_am65,
150*4882a593Smuzhiyun 		.regs_offset = 0x330,
151*4882a593Smuzhiyun 		.control_features = CPSW_SL_CTL_FUNC_BASE |
152*4882a593Smuzhiyun 				    CPSW_SL_CTL_MTEST |
153*4882a593Smuzhiyun 				    CPSW_SL_CTL_TX_SHORT_GAP_EN |
154*4882a593Smuzhiyun 				    CPSW_SL_CTL_CRC_TYPE |
155*4882a593Smuzhiyun 				    CPSW_SL_CTL_EXT_EN_RX_FLO |
156*4882a593Smuzhiyun 				    CPSW_SL_CTL_EXT_EN_TX_FLO |
157*4882a593Smuzhiyun 				    CPSW_SL_CTL_TX_SG_LIM_EN,
158*4882a593Smuzhiyun 		.idle_mask = CPSW_SL_STATUS_IDLE_MASK_BASE,
159*4882a593Smuzhiyun 	},
160*4882a593Smuzhiyun 	{
161*4882a593Smuzhiyun 		.device_id = "66ak2g",
162*4882a593Smuzhiyun 		.regs = cpsw_sl_reg_map_66ak2elg_am65,
163*4882a593Smuzhiyun 		.regs_offset = 0x330,
164*4882a593Smuzhiyun 		.control_features = CPSW_SL_CTL_FUNC_BASE |
165*4882a593Smuzhiyun 				    CPSW_SL_CTL_MTEST |
166*4882a593Smuzhiyun 				    CPSW_SL_CTL_CRC_TYPE |
167*4882a593Smuzhiyun 				    CPSW_SL_CTL_EXT_EN_RX_FLO |
168*4882a593Smuzhiyun 				    CPSW_SL_CTL_EXT_EN_TX_FLO,
169*4882a593Smuzhiyun 	},
170*4882a593Smuzhiyun 	{
171*4882a593Smuzhiyun 		.device_id = "am65",
172*4882a593Smuzhiyun 		.regs = cpsw_sl_reg_map_66ak2elg_am65,
173*4882a593Smuzhiyun 		.regs_offset = 0x330,
174*4882a593Smuzhiyun 		.control_features = CPSW_SL_CTL_FUNC_BASE |
175*4882a593Smuzhiyun 				    CPSW_SL_CTL_MTEST |
176*4882a593Smuzhiyun 				    CPSW_SL_CTL_XGIG |
177*4882a593Smuzhiyun 				    CPSW_SL_CTL_TX_SHORT_GAP_EN |
178*4882a593Smuzhiyun 				    CPSW_SL_CTL_CRC_TYPE |
179*4882a593Smuzhiyun 				    CPSW_SL_CTL_XGMII_EN |
180*4882a593Smuzhiyun 				    CPSW_SL_CTL_EXT_EN_RX_FLO |
181*4882a593Smuzhiyun 				    CPSW_SL_CTL_EXT_EN_TX_FLO |
182*4882a593Smuzhiyun 				    CPSW_SL_CTL_TX_SG_LIM_EN |
183*4882a593Smuzhiyun 				    CPSW_SL_CTL_EXT_EN_XGIG,
184*4882a593Smuzhiyun 		.idle_mask = CPSW_SL_STATUS_IDLE_MASK_K3,
185*4882a593Smuzhiyun 	},
186*4882a593Smuzhiyun 	{ },
187*4882a593Smuzhiyun };
188*4882a593Smuzhiyun 
cpsw_sl_reg_read(struct cpsw_sl * sl,enum cpsw_sl_regs reg)189*4882a593Smuzhiyun u32 cpsw_sl_reg_read(struct cpsw_sl *sl, enum cpsw_sl_regs reg)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun 	int val;
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	if (sl->regs[reg] == CPSW_SL_REG_NOTUSED) {
194*4882a593Smuzhiyun 		dev_err(sl->dev, "cpsw_sl: not sup r reg: %04X\n",
195*4882a593Smuzhiyun 			sl->regs[reg]);
196*4882a593Smuzhiyun 		return 0;
197*4882a593Smuzhiyun 	}
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	val = readl(sl->sl_base + sl->regs[reg]);
200*4882a593Smuzhiyun 	dev_dbg(sl->dev, "cpsw_sl: reg: %04X r 0x%08X\n", sl->regs[reg], val);
201*4882a593Smuzhiyun 	return val;
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun 
cpsw_sl_reg_write(struct cpsw_sl * sl,enum cpsw_sl_regs reg,u32 val)204*4882a593Smuzhiyun void cpsw_sl_reg_write(struct cpsw_sl *sl, enum cpsw_sl_regs reg, u32 val)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun 	if (sl->regs[reg] == CPSW_SL_REG_NOTUSED) {
207*4882a593Smuzhiyun 		dev_err(sl->dev, "cpsw_sl: not sup w reg: %04X\n",
208*4882a593Smuzhiyun 			sl->regs[reg]);
209*4882a593Smuzhiyun 		return;
210*4882a593Smuzhiyun 	}
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	dev_dbg(sl->dev, "cpsw_sl: reg: %04X w 0x%08X\n", sl->regs[reg], val);
213*4882a593Smuzhiyun 	writel(val, sl->sl_base + sl->regs[reg]);
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun 
cpsw_sl_match_id(const struct cpsw_sl_dev_id * id,const char * device_id)216*4882a593Smuzhiyun static const struct cpsw_sl_dev_id *cpsw_sl_match_id(
217*4882a593Smuzhiyun 		const struct cpsw_sl_dev_id *id,
218*4882a593Smuzhiyun 		const char *device_id)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun 	if (!id || !device_id)
221*4882a593Smuzhiyun 		return NULL;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	while (id->device_id) {
224*4882a593Smuzhiyun 		if (strcmp(device_id, id->device_id) == 0)
225*4882a593Smuzhiyun 			return id;
226*4882a593Smuzhiyun 		id++;
227*4882a593Smuzhiyun 	}
228*4882a593Smuzhiyun 	return NULL;
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun 
cpsw_sl_get(const char * device_id,struct device * dev,void __iomem * sl_base)231*4882a593Smuzhiyun struct cpsw_sl *cpsw_sl_get(const char *device_id, struct device *dev,
232*4882a593Smuzhiyun 			    void __iomem *sl_base)
233*4882a593Smuzhiyun {
234*4882a593Smuzhiyun 	const struct cpsw_sl_dev_id *sl_dev_id;
235*4882a593Smuzhiyun 	struct cpsw_sl *sl;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	sl = devm_kzalloc(dev, sizeof(struct cpsw_sl), GFP_KERNEL);
238*4882a593Smuzhiyun 	if (!sl)
239*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
240*4882a593Smuzhiyun 	sl->dev = dev;
241*4882a593Smuzhiyun 	sl->sl_base = sl_base;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	sl_dev_id = cpsw_sl_match_id(cpsw_sl_id_match, device_id);
244*4882a593Smuzhiyun 	if (!sl_dev_id) {
245*4882a593Smuzhiyun 		dev_err(sl->dev, "cpsw_sl: dev_id %s not found.\n", device_id);
246*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
247*4882a593Smuzhiyun 	}
248*4882a593Smuzhiyun 	sl->regs = sl_dev_id->regs;
249*4882a593Smuzhiyun 	sl->control_features = sl_dev_id->control_features;
250*4882a593Smuzhiyun 	sl->idle_mask = sl_dev_id->idle_mask;
251*4882a593Smuzhiyun 	sl->sl_base += sl_dev_id->regs_offset;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	return sl;
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun 
cpsw_sl_reset(struct cpsw_sl * sl,unsigned long tmo)256*4882a593Smuzhiyun void cpsw_sl_reset(struct cpsw_sl *sl, unsigned long tmo)
257*4882a593Smuzhiyun {
258*4882a593Smuzhiyun 	unsigned long timeout = jiffies + msecs_to_jiffies(tmo);
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	/* Set the soft reset bit */
261*4882a593Smuzhiyun 	cpsw_sl_reg_write(sl, CPSW_SL_SOFT_RESET, CPSW_SL_SOFT_RESET_BIT);
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	/* Wait for the bit to clear */
264*4882a593Smuzhiyun 	do {
265*4882a593Smuzhiyun 		usleep_range(100, 200);
266*4882a593Smuzhiyun 	} while ((cpsw_sl_reg_read(sl, CPSW_SL_SOFT_RESET) &
267*4882a593Smuzhiyun 		  CPSW_SL_SOFT_RESET_BIT) &&
268*4882a593Smuzhiyun 		  time_after(timeout, jiffies));
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	if (cpsw_sl_reg_read(sl, CPSW_SL_SOFT_RESET) & CPSW_SL_SOFT_RESET_BIT)
271*4882a593Smuzhiyun 		dev_err(sl->dev, "cpsw_sl failed to soft-reset.\n");
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun 
cpsw_sl_ctl_set(struct cpsw_sl * sl,u32 ctl_funcs)274*4882a593Smuzhiyun u32 cpsw_sl_ctl_set(struct cpsw_sl *sl, u32 ctl_funcs)
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun 	u32 val;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	if (ctl_funcs & ~sl->control_features) {
279*4882a593Smuzhiyun 		dev_err(sl->dev, "cpsw_sl: unsupported func 0x%08X\n",
280*4882a593Smuzhiyun 			ctl_funcs & (~sl->control_features));
281*4882a593Smuzhiyun 		return -EINVAL;
282*4882a593Smuzhiyun 	}
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	val = cpsw_sl_reg_read(sl, CPSW_SL_MACCONTROL);
285*4882a593Smuzhiyun 	val |= ctl_funcs;
286*4882a593Smuzhiyun 	cpsw_sl_reg_write(sl, CPSW_SL_MACCONTROL, val);
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	return 0;
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun 
cpsw_sl_ctl_clr(struct cpsw_sl * sl,u32 ctl_funcs)291*4882a593Smuzhiyun u32 cpsw_sl_ctl_clr(struct cpsw_sl *sl, u32 ctl_funcs)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun 	u32 val;
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	if (ctl_funcs & ~sl->control_features) {
296*4882a593Smuzhiyun 		dev_err(sl->dev, "cpsw_sl: unsupported func 0x%08X\n",
297*4882a593Smuzhiyun 			ctl_funcs & (~sl->control_features));
298*4882a593Smuzhiyun 		return -EINVAL;
299*4882a593Smuzhiyun 	}
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	val = cpsw_sl_reg_read(sl, CPSW_SL_MACCONTROL);
302*4882a593Smuzhiyun 	val &= ~ctl_funcs;
303*4882a593Smuzhiyun 	cpsw_sl_reg_write(sl, CPSW_SL_MACCONTROL, val);
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	return 0;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun 
cpsw_sl_ctl_reset(struct cpsw_sl * sl)308*4882a593Smuzhiyun void cpsw_sl_ctl_reset(struct cpsw_sl *sl)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun 	cpsw_sl_reg_write(sl, CPSW_SL_MACCONTROL, 0);
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun 
cpsw_sl_wait_for_idle(struct cpsw_sl * sl,unsigned long tmo)313*4882a593Smuzhiyun int cpsw_sl_wait_for_idle(struct cpsw_sl *sl, unsigned long tmo)
314*4882a593Smuzhiyun {
315*4882a593Smuzhiyun 	unsigned long timeout = jiffies + msecs_to_jiffies(tmo);
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	do {
318*4882a593Smuzhiyun 		usleep_range(100, 200);
319*4882a593Smuzhiyun 	} while (!(cpsw_sl_reg_read(sl, CPSW_SL_MACSTATUS) &
320*4882a593Smuzhiyun 		  sl->idle_mask) && time_after(timeout, jiffies));
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	if (!(cpsw_sl_reg_read(sl, CPSW_SL_MACSTATUS) & sl->idle_mask)) {
323*4882a593Smuzhiyun 		dev_err(sl->dev, "cpsw_sl failed to soft-reset.\n");
324*4882a593Smuzhiyun 		return -ETIMEDOUT;
325*4882a593Smuzhiyun 	}
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	return 0;
328*4882a593Smuzhiyun }
329