cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cpsw_sl.c (8362B)


      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}