Commit bbfc7e2b authored by Roger Quadros's avatar Roger Quadros Committed by David S. Miller

net: ethernet: ti: cpsw_ale: use regfields for ALE registers

Map the entire ALE registerspace using regmap.

Add regfields for Major and Minor Version fields.
Signed-off-by: default avatarRoger Quadros <rogerq@kernel.org>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent da70d184
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/err.h> #include <linux/err.h>
...@@ -76,7 +77,7 @@ enum { ...@@ -76,7 +77,7 @@ enum {
* @dev_id: ALE version/SoC id * @dev_id: ALE version/SoC id
* @features: features supported by ALE * @features: features supported by ALE
* @tbl_entries: number of ALE entries * @tbl_entries: number of ALE entries
* @major_ver_mask: mask of ALE Major Version Value in ALE_IDVER reg. * @reg_fields: pointer to array of register field configuration
* @nu_switch_ale: NU Switch ALE * @nu_switch_ale: NU Switch ALE
* @vlan_entry_tbl: ALE vlan entry fields description tbl * @vlan_entry_tbl: ALE vlan entry fields description tbl
*/ */
...@@ -84,7 +85,7 @@ struct cpsw_ale_dev_id { ...@@ -84,7 +85,7 @@ struct cpsw_ale_dev_id {
const char *dev_id; const char *dev_id;
u32 features; u32 features;
u32 tbl_entries; u32 tbl_entries;
u32 major_ver_mask; const struct reg_field *reg_fields;
bool nu_switch_ale; bool nu_switch_ale;
const struct ale_entry_fld *vlan_entry_tbl; const struct ale_entry_fld *vlan_entry_tbl;
}; };
...@@ -1292,25 +1293,37 @@ void cpsw_ale_stop(struct cpsw_ale *ale) ...@@ -1292,25 +1293,37 @@ void cpsw_ale_stop(struct cpsw_ale *ale)
cpsw_ale_control_set(ale, 0, ALE_ENABLE, 0); cpsw_ale_control_set(ale, 0, ALE_ENABLE, 0);
} }
static const struct reg_field ale_fields_cpsw[] = {
/* CPSW_ALE_IDVER_REG */
[MINOR_VER] = REG_FIELD(ALE_IDVER, 0, 7),
[MAJOR_VER] = REG_FIELD(ALE_IDVER, 8, 15),
};
static const struct reg_field ale_fields_cpsw_nu[] = {
/* CPSW_ALE_IDVER_REG */
[MINOR_VER] = REG_FIELD(ALE_IDVER, 0, 7),
[MAJOR_VER] = REG_FIELD(ALE_IDVER, 8, 10),
};
static const struct cpsw_ale_dev_id cpsw_ale_id_match[] = { static const struct cpsw_ale_dev_id cpsw_ale_id_match[] = {
{ {
/* am3/4/5, dra7. dm814x, 66ak2hk-gbe */ /* am3/4/5, dra7. dm814x, 66ak2hk-gbe */
.dev_id = "cpsw", .dev_id = "cpsw",
.tbl_entries = 1024, .tbl_entries = 1024,
.major_ver_mask = 0xff, .reg_fields = ale_fields_cpsw,
.vlan_entry_tbl = vlan_entry_cpsw, .vlan_entry_tbl = vlan_entry_cpsw,
}, },
{ {
/* 66ak2h_xgbe */ /* 66ak2h_xgbe */
.dev_id = "66ak2h-xgbe", .dev_id = "66ak2h-xgbe",
.tbl_entries = 2048, .tbl_entries = 2048,
.major_ver_mask = 0xff, .reg_fields = ale_fields_cpsw,
.vlan_entry_tbl = vlan_entry_cpsw, .vlan_entry_tbl = vlan_entry_cpsw,
}, },
{ {
.dev_id = "66ak2el", .dev_id = "66ak2el",
.features = CPSW_ALE_F_STATUS_REG, .features = CPSW_ALE_F_STATUS_REG,
.major_ver_mask = 0x7, .reg_fields = ale_fields_cpsw_nu,
.nu_switch_ale = true, .nu_switch_ale = true,
.vlan_entry_tbl = vlan_entry_nu, .vlan_entry_tbl = vlan_entry_nu,
}, },
...@@ -1318,7 +1331,7 @@ static const struct cpsw_ale_dev_id cpsw_ale_id_match[] = { ...@@ -1318,7 +1331,7 @@ static const struct cpsw_ale_dev_id cpsw_ale_id_match[] = {
.dev_id = "66ak2g", .dev_id = "66ak2g",
.features = CPSW_ALE_F_STATUS_REG, .features = CPSW_ALE_F_STATUS_REG,
.tbl_entries = 64, .tbl_entries = 64,
.major_ver_mask = 0x7, .reg_fields = ale_fields_cpsw_nu,
.nu_switch_ale = true, .nu_switch_ale = true,
.vlan_entry_tbl = vlan_entry_nu, .vlan_entry_tbl = vlan_entry_nu,
}, },
...@@ -1326,20 +1339,20 @@ static const struct cpsw_ale_dev_id cpsw_ale_id_match[] = { ...@@ -1326,20 +1339,20 @@ static const struct cpsw_ale_dev_id cpsw_ale_id_match[] = {
.dev_id = "am65x-cpsw2g", .dev_id = "am65x-cpsw2g",
.features = CPSW_ALE_F_STATUS_REG | CPSW_ALE_F_HW_AUTOAGING, .features = CPSW_ALE_F_STATUS_REG | CPSW_ALE_F_HW_AUTOAGING,
.tbl_entries = 64, .tbl_entries = 64,
.major_ver_mask = 0x7, .reg_fields = ale_fields_cpsw_nu,
.nu_switch_ale = true, .nu_switch_ale = true,
.vlan_entry_tbl = vlan_entry_nu, .vlan_entry_tbl = vlan_entry_nu,
}, },
{ {
.dev_id = "j721e-cpswxg", .dev_id = "j721e-cpswxg",
.features = CPSW_ALE_F_STATUS_REG | CPSW_ALE_F_HW_AUTOAGING, .features = CPSW_ALE_F_STATUS_REG | CPSW_ALE_F_HW_AUTOAGING,
.major_ver_mask = 0x7, .reg_fields = ale_fields_cpsw_nu,
.vlan_entry_tbl = vlan_entry_k3_cpswxg, .vlan_entry_tbl = vlan_entry_k3_cpswxg,
}, },
{ {
.dev_id = "am64-cpswxg", .dev_id = "am64-cpswxg",
.features = CPSW_ALE_F_STATUS_REG | CPSW_ALE_F_HW_AUTOAGING, .features = CPSW_ALE_F_STATUS_REG | CPSW_ALE_F_HW_AUTOAGING,
.major_ver_mask = 0x7, .reg_fields = ale_fields_cpsw_nu,
.vlan_entry_tbl = vlan_entry_k3_cpswxg, .vlan_entry_tbl = vlan_entry_k3_cpswxg,
.tbl_entries = 512, .tbl_entries = 512,
}, },
...@@ -1361,41 +1374,76 @@ cpsw_ale_dev_id *cpsw_ale_match_id(const struct cpsw_ale_dev_id *id, ...@@ -1361,41 +1374,76 @@ cpsw_ale_dev_id *cpsw_ale_match_id(const struct cpsw_ale_dev_id *id,
return NULL; return NULL;
} }
static const struct regmap_config ale_regmap_cfg = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.name = "cpsw-ale",
};
static int cpsw_ale_regfield_init(struct cpsw_ale *ale)
{
const struct reg_field *reg_fields = ale->params.reg_fields;
struct device *dev = ale->params.dev;
struct regmap *regmap = ale->regmap;
int i;
for (i = 0; i < ALE_FIELDS_MAX; i++) {
ale->fields[i] = devm_regmap_field_alloc(dev, regmap,
reg_fields[i]);
if (IS_ERR(ale->fields[i])) {
dev_err(dev, "Unable to allocate regmap field %d\n", i);
return PTR_ERR(ale->fields[i]);
}
}
return 0;
}
struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params) struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params)
{ {
const struct cpsw_ale_dev_id *ale_dev_id; const struct cpsw_ale_dev_id *ale_dev_id;
u32 ale_entries, rev_major, rev_minor;
struct cpsw_ale *ale; struct cpsw_ale *ale;
u32 rev, ale_entries; int ret;
ale_dev_id = cpsw_ale_match_id(cpsw_ale_id_match, params->dev_id); ale_dev_id = cpsw_ale_match_id(cpsw_ale_id_match, params->dev_id);
if (!ale_dev_id) if (!ale_dev_id)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
params->ale_entries = ale_dev_id->tbl_entries; params->ale_entries = ale_dev_id->tbl_entries;
params->major_ver_mask = ale_dev_id->major_ver_mask;
params->nu_switch_ale = ale_dev_id->nu_switch_ale; params->nu_switch_ale = ale_dev_id->nu_switch_ale;
params->reg_fields = ale_dev_id->reg_fields;
ale = devm_kzalloc(params->dev, sizeof(*ale), GFP_KERNEL); ale = devm_kzalloc(params->dev, sizeof(*ale), GFP_KERNEL);
if (!ale) if (!ale)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
ale->regmap = devm_regmap_init_mmio(params->dev, params->ale_regs,
&ale_regmap_cfg);
if (IS_ERR(ale->regmap)) {
dev_err(params->dev, "Couldn't create CPSW ALE regmap\n");
return ERR_PTR(-ENOMEM);
}
ale->params = *params;
ret = cpsw_ale_regfield_init(ale);
if (ret)
return ERR_PTR(ret);
ale->p0_untag_vid_mask = devm_bitmap_zalloc(params->dev, VLAN_N_VID, ale->p0_untag_vid_mask = devm_bitmap_zalloc(params->dev, VLAN_N_VID,
GFP_KERNEL); GFP_KERNEL);
if (!ale->p0_untag_vid_mask) if (!ale->p0_untag_vid_mask)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
ale->params = *params;
ale->ageout = ale->params.ale_ageout * HZ; ale->ageout = ale->params.ale_ageout * HZ;
ale->features = ale_dev_id->features; ale->features = ale_dev_id->features;
ale->vlan_entry_tbl = ale_dev_id->vlan_entry_tbl; ale->vlan_entry_tbl = ale_dev_id->vlan_entry_tbl;
rev = readl_relaxed(ale->params.ale_regs + ALE_IDVER); regmap_field_read(ale->fields[MINOR_VER], &rev_minor);
ale->version = regmap_field_read(ale->fields[MAJOR_VER], &rev_major);
(ALE_VERSION_MAJOR(rev, ale->params.major_ver_mask) << 8) | ale->version = rev_major << 8 | rev_minor;
ALE_VERSION_MINOR(rev);
dev_info(ale->params.dev, "initialized cpsw ale version %d.%d\n", dev_info(ale->params.dev, "initialized cpsw ale version %d.%d\n",
ALE_VERSION_MAJOR(rev, ale->params.major_ver_mask), rev_major, rev_minor);
ALE_VERSION_MINOR(rev));
if (ale->features & CPSW_ALE_F_STATUS_REG && if (ale->features & CPSW_ALE_F_STATUS_REG &&
!ale->params.ale_entries) { !ale->params.ale_entries) {
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#ifndef __TI_CPSW_ALE_H__ #ifndef __TI_CPSW_ALE_H__
#define __TI_CPSW_ALE_H__ #define __TI_CPSW_ALE_H__
struct reg_fields;
struct cpsw_ale_params { struct cpsw_ale_params {
struct device *dev; struct device *dev;
void __iomem *ale_regs; void __iomem *ale_regs;
...@@ -20,19 +22,26 @@ struct cpsw_ale_params { ...@@ -20,19 +22,26 @@ struct cpsw_ale_params {
* to identify this hardware. * to identify this hardware.
*/ */
bool nu_switch_ale; bool nu_switch_ale;
/* mask bit used in NU Switch ALE is 3 bits instead of 8 bits. So const struct reg_field *reg_fields;
* pass it from caller.
*/
u32 major_ver_mask;
const char *dev_id; const char *dev_id;
unsigned long bus_freq; unsigned long bus_freq;
}; };
struct ale_entry_fld; struct ale_entry_fld;
struct regmap;
enum ale_fields {
MINOR_VER,
MAJOR_VER,
/* terminator */
ALE_FIELDS_MAX,
};
struct cpsw_ale { struct cpsw_ale {
struct cpsw_ale_params params; struct cpsw_ale_params params;
struct timer_list timer; struct timer_list timer;
struct regmap *regmap;
struct regmap_field *fields[ALE_FIELDS_MAX];
unsigned long ageout; unsigned long ageout;
u32 version; u32 version;
u32 features; u32 features;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment