Skip to content

Commit

Permalink
net: ethernet: ti: cpsw_ale: use regfields for ALE registers
Browse files Browse the repository at this point in the history
Map the entire ALE registerspace using regmap.

Add regfields for Major and Minor Version fields.

Signed-off-by: Roger Quadros <rogerq@kernel.org>
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
rogerq authored and davem330 committed Sep 13, 2024
1 parent da70d18 commit bbfc7e2
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 22 deletions.
84 changes: 66 additions & 18 deletions drivers/net/ethernet/ti/cpsw_ale.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/err.h>
Expand Down Expand Up @@ -76,15 +77,15 @@ enum {
* @dev_id: ALE version/SoC id
* @features: features supported by ALE
* @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
* @vlan_entry_tbl: ALE vlan entry fields description tbl
*/
struct cpsw_ale_dev_id {
const char *dev_id;
u32 features;
u32 tbl_entries;
u32 major_ver_mask;
const struct reg_field *reg_fields;
bool nu_switch_ale;
const struct ale_entry_fld *vlan_entry_tbl;
};
Expand Down Expand Up @@ -1292,54 +1293,66 @@ void cpsw_ale_stop(struct cpsw_ale *ale)
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[] = {
{
/* am3/4/5, dra7. dm814x, 66ak2hk-gbe */
.dev_id = "cpsw",
.tbl_entries = 1024,
.major_ver_mask = 0xff,
.reg_fields = ale_fields_cpsw,
.vlan_entry_tbl = vlan_entry_cpsw,
},
{
/* 66ak2h_xgbe */
.dev_id = "66ak2h-xgbe",
.tbl_entries = 2048,
.major_ver_mask = 0xff,
.reg_fields = ale_fields_cpsw,
.vlan_entry_tbl = vlan_entry_cpsw,
},
{
.dev_id = "66ak2el",
.features = CPSW_ALE_F_STATUS_REG,
.major_ver_mask = 0x7,
.reg_fields = ale_fields_cpsw_nu,
.nu_switch_ale = true,
.vlan_entry_tbl = vlan_entry_nu,
},
{
.dev_id = "66ak2g",
.features = CPSW_ALE_F_STATUS_REG,
.tbl_entries = 64,
.major_ver_mask = 0x7,
.reg_fields = ale_fields_cpsw_nu,
.nu_switch_ale = true,
.vlan_entry_tbl = vlan_entry_nu,
},
{
.dev_id = "am65x-cpsw2g",
.features = CPSW_ALE_F_STATUS_REG | CPSW_ALE_F_HW_AUTOAGING,
.tbl_entries = 64,
.major_ver_mask = 0x7,
.reg_fields = ale_fields_cpsw_nu,
.nu_switch_ale = true,
.vlan_entry_tbl = vlan_entry_nu,
},
{
.dev_id = "j721e-cpswxg",
.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,
},
{
.dev_id = "am64-cpswxg",
.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,
.tbl_entries = 512,
},
Expand All @@ -1361,41 +1374,76 @@ cpsw_ale_dev_id *cpsw_ale_match_id(const struct cpsw_ale_dev_id *id,
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)
{
const struct cpsw_ale_dev_id *ale_dev_id;
u32 ale_entries, rev_major, rev_minor;
struct cpsw_ale *ale;
u32 rev, ale_entries;
int ret;

ale_dev_id = cpsw_ale_match_id(cpsw_ale_id_match, params->dev_id);
if (!ale_dev_id)
return ERR_PTR(-EINVAL);

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->reg_fields = ale_dev_id->reg_fields;

ale = devm_kzalloc(params->dev, sizeof(*ale), GFP_KERNEL);
if (!ale)
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,
GFP_KERNEL);
if (!ale->p0_untag_vid_mask)
return ERR_PTR(-ENOMEM);

ale->params = *params;
ale->ageout = ale->params.ale_ageout * HZ;
ale->features = ale_dev_id->features;
ale->vlan_entry_tbl = ale_dev_id->vlan_entry_tbl;

rev = readl_relaxed(ale->params.ale_regs + ALE_IDVER);
ale->version =
(ALE_VERSION_MAJOR(rev, ale->params.major_ver_mask) << 8) |
ALE_VERSION_MINOR(rev);
regmap_field_read(ale->fields[MINOR_VER], &rev_minor);
regmap_field_read(ale->fields[MAJOR_VER], &rev_major);
ale->version = rev_major << 8 | rev_minor;
dev_info(ale->params.dev, "initialized cpsw ale version %d.%d\n",
ALE_VERSION_MAJOR(rev, ale->params.major_ver_mask),
ALE_VERSION_MINOR(rev));
rev_major, rev_minor);

if (ale->features & CPSW_ALE_F_STATUS_REG &&
!ale->params.ale_entries) {
Expand Down
17 changes: 13 additions & 4 deletions drivers/net/ethernet/ti/cpsw_ale.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#ifndef __TI_CPSW_ALE_H__
#define __TI_CPSW_ALE_H__

struct reg_fields;

struct cpsw_ale_params {
struct device *dev;
void __iomem *ale_regs;
Expand All @@ -20,19 +22,26 @@ struct cpsw_ale_params {
* to identify this hardware.
*/
bool nu_switch_ale;
/* mask bit used in NU Switch ALE is 3 bits instead of 8 bits. So
* pass it from caller.
*/
u32 major_ver_mask;
const struct reg_field *reg_fields;
const char *dev_id;
unsigned long bus_freq;
};

struct ale_entry_fld;
struct regmap;

enum ale_fields {
MINOR_VER,
MAJOR_VER,
/* terminator */
ALE_FIELDS_MAX,
};

struct cpsw_ale {
struct cpsw_ale_params params;
struct timer_list timer;
struct regmap *regmap;
struct regmap_field *fields[ALE_FIELDS_MAX];
unsigned long ageout;
u32 version;
u32 features;
Expand Down

0 comments on commit bbfc7e2

Please sign in to comment.