0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/delay.h>
0011 #include <linux/io.h>
0012 #include <linux/kernel.h>
0013
0014 #include "cpsw_sl.h"
0015
0016 #define CPSW_SL_REG_NOTUSED U16_MAX
0017
0018 static const u16 cpsw_sl_reg_map_cpsw[] = {
0019 [CPSW_SL_IDVER] = 0x00,
0020 [CPSW_SL_MACCONTROL] = 0x04,
0021 [CPSW_SL_MACSTATUS] = 0x08,
0022 [CPSW_SL_SOFT_RESET] = 0x0c,
0023 [CPSW_SL_RX_MAXLEN] = 0x10,
0024 [CPSW_SL_BOFFTEST] = 0x14,
0025 [CPSW_SL_RX_PAUSE] = 0x18,
0026 [CPSW_SL_TX_PAUSE] = 0x1c,
0027 [CPSW_SL_EMCONTROL] = 0x20,
0028 [CPSW_SL_RX_PRI_MAP] = 0x24,
0029 [CPSW_SL_TX_GAP] = 0x28,
0030 };
0031
0032 static const u16 cpsw_sl_reg_map_66ak2hk[] = {
0033 [CPSW_SL_IDVER] = 0x00,
0034 [CPSW_SL_MACCONTROL] = 0x04,
0035 [CPSW_SL_MACSTATUS] = 0x08,
0036 [CPSW_SL_SOFT_RESET] = 0x0c,
0037 [CPSW_SL_RX_MAXLEN] = 0x10,
0038 [CPSW_SL_BOFFTEST] = CPSW_SL_REG_NOTUSED,
0039 [CPSW_SL_RX_PAUSE] = 0x18,
0040 [CPSW_SL_TX_PAUSE] = 0x1c,
0041 [CPSW_SL_EMCONTROL] = 0x20,
0042 [CPSW_SL_RX_PRI_MAP] = 0x24,
0043 [CPSW_SL_TX_GAP] = CPSW_SL_REG_NOTUSED,
0044 };
0045
0046 static const u16 cpsw_sl_reg_map_66ak2x_xgbe[] = {
0047 [CPSW_SL_IDVER] = 0x00,
0048 [CPSW_SL_MACCONTROL] = 0x04,
0049 [CPSW_SL_MACSTATUS] = 0x08,
0050 [CPSW_SL_SOFT_RESET] = 0x0c,
0051 [CPSW_SL_RX_MAXLEN] = 0x10,
0052 [CPSW_SL_BOFFTEST] = CPSW_SL_REG_NOTUSED,
0053 [CPSW_SL_RX_PAUSE] = 0x18,
0054 [CPSW_SL_TX_PAUSE] = 0x1c,
0055 [CPSW_SL_EMCONTROL] = 0x20,
0056 [CPSW_SL_RX_PRI_MAP] = CPSW_SL_REG_NOTUSED,
0057 [CPSW_SL_TX_GAP] = 0x28,
0058 };
0059
0060 static const u16 cpsw_sl_reg_map_66ak2elg_am65[] = {
0061 [CPSW_SL_IDVER] = CPSW_SL_REG_NOTUSED,
0062 [CPSW_SL_MACCONTROL] = 0x00,
0063 [CPSW_SL_MACSTATUS] = 0x04,
0064 [CPSW_SL_SOFT_RESET] = 0x08,
0065 [CPSW_SL_RX_MAXLEN] = CPSW_SL_REG_NOTUSED,
0066 [CPSW_SL_BOFFTEST] = 0x0c,
0067 [CPSW_SL_RX_PAUSE] = 0x10,
0068 [CPSW_SL_TX_PAUSE] = 0x40,
0069 [CPSW_SL_EMCONTROL] = 0x70,
0070 [CPSW_SL_RX_PRI_MAP] = CPSW_SL_REG_NOTUSED,
0071 [CPSW_SL_TX_GAP] = 0x74,
0072 };
0073
0074 #define CPSW_SL_SOFT_RESET_BIT BIT(0)
0075
0076 #define CPSW_SL_STATUS_PN_IDLE BIT(31)
0077 #define CPSW_SL_AM65_STATUS_PN_E_IDLE BIT(30)
0078 #define CPSW_SL_AM65_STATUS_PN_P_IDLE BIT(29)
0079 #define CPSW_SL_AM65_STATUS_PN_TX_IDLE BIT(28)
0080
0081 #define CPSW_SL_STATUS_IDLE_MASK_BASE (CPSW_SL_STATUS_PN_IDLE)
0082
0083 #define CPSW_SL_STATUS_IDLE_MASK_K3 \
0084 (CPSW_SL_STATUS_IDLE_MASK_BASE | CPSW_SL_AM65_STATUS_PN_E_IDLE | \
0085 CPSW_SL_AM65_STATUS_PN_P_IDLE | CPSW_SL_AM65_STATUS_PN_TX_IDLE)
0086
0087 #define CPSW_SL_CTL_FUNC_BASE \
0088 (CPSW_SL_CTL_FULLDUPLEX |\
0089 CPSW_SL_CTL_LOOPBACK |\
0090 CPSW_SL_CTL_RX_FLOW_EN |\
0091 CPSW_SL_CTL_TX_FLOW_EN |\
0092 CPSW_SL_CTL_GMII_EN |\
0093 CPSW_SL_CTL_TX_PACE |\
0094 CPSW_SL_CTL_GIG |\
0095 CPSW_SL_CTL_CMD_IDLE |\
0096 CPSW_SL_CTL_IFCTL_A |\
0097 CPSW_SL_CTL_IFCTL_B |\
0098 CPSW_SL_CTL_GIG_FORCE |\
0099 CPSW_SL_CTL_EXT_EN |\
0100 CPSW_SL_CTL_RX_CEF_EN |\
0101 CPSW_SL_CTL_RX_CSF_EN |\
0102 CPSW_SL_CTL_RX_CMF_EN)
0103
0104 struct cpsw_sl {
0105 struct device *dev;
0106 void __iomem *sl_base;
0107 const u16 *regs;
0108 u32 control_features;
0109 u32 idle_mask;
0110 };
0111
0112 struct cpsw_sl_dev_id {
0113 const char *device_id;
0114 const u16 *regs;
0115 const u32 control_features;
0116 const u32 regs_offset;
0117 const u32 idle_mask;
0118 };
0119
0120 static const struct cpsw_sl_dev_id cpsw_sl_id_match[] = {
0121 {
0122 .device_id = "cpsw",
0123 .regs = cpsw_sl_reg_map_cpsw,
0124 .control_features = CPSW_SL_CTL_FUNC_BASE |
0125 CPSW_SL_CTL_MTEST |
0126 CPSW_SL_CTL_TX_SHORT_GAP_EN |
0127 CPSW_SL_CTL_TX_SG_LIM_EN,
0128 .idle_mask = CPSW_SL_STATUS_IDLE_MASK_BASE,
0129 },
0130 {
0131 .device_id = "66ak2hk",
0132 .regs = cpsw_sl_reg_map_66ak2hk,
0133 .control_features = CPSW_SL_CTL_FUNC_BASE |
0134 CPSW_SL_CTL_TX_SHORT_GAP_EN,
0135 .idle_mask = CPSW_SL_STATUS_IDLE_MASK_BASE,
0136 },
0137 {
0138 .device_id = "66ak2x_xgbe",
0139 .regs = cpsw_sl_reg_map_66ak2x_xgbe,
0140 .control_features = CPSW_SL_CTL_FUNC_BASE |
0141 CPSW_SL_CTL_XGIG |
0142 CPSW_SL_CTL_TX_SHORT_GAP_EN |
0143 CPSW_SL_CTL_CRC_TYPE |
0144 CPSW_SL_CTL_XGMII_EN,
0145 .idle_mask = CPSW_SL_STATUS_IDLE_MASK_BASE,
0146 },
0147 {
0148 .device_id = "66ak2el",
0149 .regs = cpsw_sl_reg_map_66ak2elg_am65,
0150 .regs_offset = 0x330,
0151 .control_features = CPSW_SL_CTL_FUNC_BASE |
0152 CPSW_SL_CTL_MTEST |
0153 CPSW_SL_CTL_TX_SHORT_GAP_EN |
0154 CPSW_SL_CTL_CRC_TYPE |
0155 CPSW_SL_CTL_EXT_EN_RX_FLO |
0156 CPSW_SL_CTL_EXT_EN_TX_FLO |
0157 CPSW_SL_CTL_TX_SG_LIM_EN,
0158 .idle_mask = CPSW_SL_STATUS_IDLE_MASK_BASE,
0159 },
0160 {
0161 .device_id = "66ak2g",
0162 .regs = cpsw_sl_reg_map_66ak2elg_am65,
0163 .regs_offset = 0x330,
0164 .control_features = CPSW_SL_CTL_FUNC_BASE |
0165 CPSW_SL_CTL_MTEST |
0166 CPSW_SL_CTL_CRC_TYPE |
0167 CPSW_SL_CTL_EXT_EN_RX_FLO |
0168 CPSW_SL_CTL_EXT_EN_TX_FLO,
0169 },
0170 {
0171 .device_id = "am65",
0172 .regs = cpsw_sl_reg_map_66ak2elg_am65,
0173 .regs_offset = 0x330,
0174 .control_features = CPSW_SL_CTL_FUNC_BASE |
0175 CPSW_SL_CTL_MTEST |
0176 CPSW_SL_CTL_XGIG |
0177 CPSW_SL_CTL_TX_SHORT_GAP_EN |
0178 CPSW_SL_CTL_CRC_TYPE |
0179 CPSW_SL_CTL_XGMII_EN |
0180 CPSW_SL_CTL_EXT_EN_RX_FLO |
0181 CPSW_SL_CTL_EXT_EN_TX_FLO |
0182 CPSW_SL_CTL_TX_SG_LIM_EN |
0183 CPSW_SL_CTL_EXT_EN_XGIG,
0184 .idle_mask = CPSW_SL_STATUS_IDLE_MASK_K3,
0185 },
0186 { },
0187 };
0188
0189 u32 cpsw_sl_reg_read(struct cpsw_sl *sl, enum cpsw_sl_regs reg)
0190 {
0191 int val;
0192
0193 if (sl->regs[reg] == CPSW_SL_REG_NOTUSED) {
0194 dev_err(sl->dev, "cpsw_sl: not sup r reg: %04X\n",
0195 sl->regs[reg]);
0196 return 0;
0197 }
0198
0199 val = readl(sl->sl_base + sl->regs[reg]);
0200 dev_dbg(sl->dev, "cpsw_sl: reg: %04X r 0x%08X\n", sl->regs[reg], val);
0201 return val;
0202 }
0203
0204 void cpsw_sl_reg_write(struct cpsw_sl *sl, enum cpsw_sl_regs reg, u32 val)
0205 {
0206 if (sl->regs[reg] == CPSW_SL_REG_NOTUSED) {
0207 dev_err(sl->dev, "cpsw_sl: not sup w reg: %04X\n",
0208 sl->regs[reg]);
0209 return;
0210 }
0211
0212 dev_dbg(sl->dev, "cpsw_sl: reg: %04X w 0x%08X\n", sl->regs[reg], val);
0213 writel(val, sl->sl_base + sl->regs[reg]);
0214 }
0215
0216 static const struct cpsw_sl_dev_id *cpsw_sl_match_id(
0217 const struct cpsw_sl_dev_id *id,
0218 const char *device_id)
0219 {
0220 if (!id || !device_id)
0221 return NULL;
0222
0223 while (id->device_id) {
0224 if (strcmp(device_id, id->device_id) == 0)
0225 return id;
0226 id++;
0227 }
0228 return NULL;
0229 }
0230
0231 struct cpsw_sl *cpsw_sl_get(const char *device_id, struct device *dev,
0232 void __iomem *sl_base)
0233 {
0234 const struct cpsw_sl_dev_id *sl_dev_id;
0235 struct cpsw_sl *sl;
0236
0237 sl = devm_kzalloc(dev, sizeof(struct cpsw_sl), GFP_KERNEL);
0238 if (!sl)
0239 return ERR_PTR(-ENOMEM);
0240 sl->dev = dev;
0241 sl->sl_base = sl_base;
0242
0243 sl_dev_id = cpsw_sl_match_id(cpsw_sl_id_match, device_id);
0244 if (!sl_dev_id) {
0245 dev_err(sl->dev, "cpsw_sl: dev_id %s not found.\n", device_id);
0246 return ERR_PTR(-EINVAL);
0247 }
0248 sl->regs = sl_dev_id->regs;
0249 sl->control_features = sl_dev_id->control_features;
0250 sl->idle_mask = sl_dev_id->idle_mask;
0251 sl->sl_base += sl_dev_id->regs_offset;
0252
0253 return sl;
0254 }
0255
0256 void cpsw_sl_reset(struct cpsw_sl *sl, unsigned long tmo)
0257 {
0258 unsigned long timeout = jiffies + msecs_to_jiffies(tmo);
0259
0260
0261 cpsw_sl_reg_write(sl, CPSW_SL_SOFT_RESET, CPSW_SL_SOFT_RESET_BIT);
0262
0263
0264 do {
0265 usleep_range(100, 200);
0266 } while ((cpsw_sl_reg_read(sl, CPSW_SL_SOFT_RESET) &
0267 CPSW_SL_SOFT_RESET_BIT) &&
0268 time_after(timeout, jiffies));
0269
0270 if (cpsw_sl_reg_read(sl, CPSW_SL_SOFT_RESET) & CPSW_SL_SOFT_RESET_BIT)
0271 dev_err(sl->dev, "cpsw_sl failed to soft-reset.\n");
0272 }
0273
0274 u32 cpsw_sl_ctl_set(struct cpsw_sl *sl, u32 ctl_funcs)
0275 {
0276 u32 val;
0277
0278 if (ctl_funcs & ~sl->control_features) {
0279 dev_err(sl->dev, "cpsw_sl: unsupported func 0x%08X\n",
0280 ctl_funcs & (~sl->control_features));
0281 return -EINVAL;
0282 }
0283
0284 val = cpsw_sl_reg_read(sl, CPSW_SL_MACCONTROL);
0285 val |= ctl_funcs;
0286 cpsw_sl_reg_write(sl, CPSW_SL_MACCONTROL, val);
0287
0288 return 0;
0289 }
0290
0291 u32 cpsw_sl_ctl_clr(struct cpsw_sl *sl, u32 ctl_funcs)
0292 {
0293 u32 val;
0294
0295 if (ctl_funcs & ~sl->control_features) {
0296 dev_err(sl->dev, "cpsw_sl: unsupported func 0x%08X\n",
0297 ctl_funcs & (~sl->control_features));
0298 return -EINVAL;
0299 }
0300
0301 val = cpsw_sl_reg_read(sl, CPSW_SL_MACCONTROL);
0302 val &= ~ctl_funcs;
0303 cpsw_sl_reg_write(sl, CPSW_SL_MACCONTROL, val);
0304
0305 return 0;
0306 }
0307
0308 void cpsw_sl_ctl_reset(struct cpsw_sl *sl)
0309 {
0310 cpsw_sl_reg_write(sl, CPSW_SL_MACCONTROL, 0);
0311 }
0312
0313 int cpsw_sl_wait_for_idle(struct cpsw_sl *sl, unsigned long tmo)
0314 {
0315 unsigned long timeout = jiffies + msecs_to_jiffies(tmo);
0316
0317 do {
0318 usleep_range(100, 200);
0319 } while (!(cpsw_sl_reg_read(sl, CPSW_SL_MACSTATUS) &
0320 sl->idle_mask) && time_after(timeout, jiffies));
0321
0322 if (!(cpsw_sl_reg_read(sl, CPSW_SL_MACSTATUS) & sl->idle_mask)) {
0323 dev_err(sl->dev, "cpsw_sl failed to soft-reset.\n");
0324 return -ETIMEDOUT;
0325 }
0326
0327 return 0;
0328 }