Linux Audio

Check our new training course

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