[RFC PATCH vN net-next 1/2] net: mscc: ocelot: add support for non-mmio regmaps

From: Colin Foster
Date: Tue May 04 2021 - 01:11:53 EST


Control for external VSC75XX chips can be performed via non-mmio
interfaces, e.g. SPI. Adding the offets array (one per target) and
the offset element per port allows the ability to track this
location that would otherwise be found in the MMIO regmap resource.

Tracking this offset in the ocelot driver and allowing the
ocelot_regmap_init function to be overloaded with a device-specific
initializer. This driver could update the *offset element to handle the
value that would otherwise be mapped via resource *res->start.

Signed-off-by: Colin Foster <colin.foster@xxxxxxxxxxxxxxxx>
---
drivers/net/dsa/ocelot/felix.c | 6 ++++--
drivers/net/dsa/ocelot/felix.h | 2 ++
drivers/net/dsa/ocelot/felix_vsc9959.c | 1 +
drivers/net/dsa/ocelot/seville_vsc9953.c | 1 +
drivers/net/ethernet/mscc/ocelot_io.c | 27 +++++++++++++++++-------
include/soc/mscc/ocelot.h | 5 ++++-
6 files changed, 31 insertions(+), 11 deletions(-)

diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
index 628afb47b579..71aa11b209e8 100644
--- a/drivers/net/dsa/ocelot/felix.c
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -1122,7 +1122,8 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
res.start += felix->switch_base;
res.end += felix->switch_base;

- target = ocelot_regmap_init(ocelot, &res);
+ target = felix->info->init_regmap(ocelot, &res,
+ &ocelot->offsets[i]);
if (IS_ERR(target)) {
dev_err(ocelot->dev,
"Failed to map device memory space\n");
@@ -1159,7 +1160,8 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
res.start += felix->switch_base;
res.end += felix->switch_base;

- target = ocelot_regmap_init(ocelot, &res);
+ target = felix->info->init_regmap(ocelot, &res,
+ &ocelot_port->offset);
if (IS_ERR(target)) {
dev_err(ocelot->dev,
"Failed to map memory space for port %d\n",
diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h
index 4d96cad815d5..03ae576e018a 100644
--- a/drivers/net/dsa/ocelot/felix.h
+++ b/drivers/net/dsa/ocelot/felix.h
@@ -47,6 +47,8 @@ struct felix_info {
enum tc_setup_type type, void *type_data);
void (*port_sched_speed_set)(struct ocelot *ocelot, int port,
u32 speed);
+ struct regmap *(*init_regmap)(struct ocelot *ocelot,
+ struct resource *res, u32 *offset);
};

extern const struct dsa_switch_ops felix_switch_ops;
diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c
index 5ff623ee76a6..87178345116b 100644
--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
+++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
@@ -1362,6 +1362,7 @@ static const struct felix_info felix_info_vsc9959 = {
.prevalidate_phy_mode = vsc9959_prevalidate_phy_mode,
.port_setup_tc = vsc9959_port_setup_tc,
.port_sched_speed_set = vsc9959_sched_speed_set,
+ .init_regmap = ocelot_regmap_init,
};

static irqreturn_t felix_irq_handler(int irq, void *data)
diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c b/drivers/net/dsa/ocelot/seville_vsc9953.c
index 84f93a874d50..d88a9729222c 100644
--- a/drivers/net/dsa/ocelot/seville_vsc9953.c
+++ b/drivers/net/dsa/ocelot/seville_vsc9953.c
@@ -1181,6 +1181,7 @@ static const struct felix_info seville_info_vsc9953 = {
.mdio_bus_free = vsc9953_mdio_bus_free,
.phylink_validate = vsc9953_phylink_validate,
.prevalidate_phy_mode = vsc9953_prevalidate_phy_mode,
+ .init_regmap = ocelot_regmap_init,
};

static int seville_probe(struct platform_device *pdev)
diff --git a/drivers/net/ethernet/mscc/ocelot_io.c b/drivers/net/ethernet/mscc/ocelot_io.c
index ea4e83410fe4..8f314639faff 100644
--- a/drivers/net/ethernet/mscc/ocelot_io.c
+++ b/drivers/net/ethernet/mscc/ocelot_io.c
@@ -18,7 +18,8 @@ u32 __ocelot_read_ix(struct ocelot *ocelot, u32 reg, u32 offset)
WARN_ON(!target);

regmap_read(ocelot->targets[target],
- ocelot->map[target][reg & REG_MASK] + offset, &val);
+ ocelot->offsets[target] +
+ ocelot->map[target][reg & REG_MASK] + offset, &val);
return val;
}
EXPORT_SYMBOL(__ocelot_read_ix);
@@ -30,7 +31,8 @@ void __ocelot_write_ix(struct ocelot *ocelot, u32 val, u32 reg, u32 offset)
WARN_ON(!target);

regmap_write(ocelot->targets[target],
- ocelot->map[target][reg & REG_MASK] + offset, val);
+ ocelot->offsets[target] +
+ ocelot->map[target][reg & REG_MASK] + offset, val);
}
EXPORT_SYMBOL(__ocelot_write_ix);

@@ -42,7 +44,8 @@ void __ocelot_rmw_ix(struct ocelot *ocelot, u32 val, u32 mask, u32 reg,
WARN_ON(!target);

regmap_update_bits(ocelot->targets[target],
- ocelot->map[target][reg & REG_MASK] + offset,
+ ocelot->offsets[target] +
+ ocelot->map[target][reg & REG_MASK] + offset,
mask, val);
}
EXPORT_SYMBOL(__ocelot_rmw_ix);
@@ -55,7 +58,8 @@ u32 ocelot_port_readl(struct ocelot_port *port, u32 reg)

WARN_ON(!target);

- regmap_read(port->target, ocelot->map[target][reg & REG_MASK], &val);
+ regmap_read(port->target,
+ port->offset + ocelot->map[target][reg & REG_MASK], &val);
return val;
}
EXPORT_SYMBOL(ocelot_port_readl);
@@ -67,7 +71,8 @@ void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg)

WARN_ON(!target);

- regmap_write(port->target, ocelot->map[target][reg & REG_MASK], val);
+ regmap_write(port->target,
+ port->offset + ocelot->map[target][reg & REG_MASK], val);
}
EXPORT_SYMBOL(ocelot_port_writel);

@@ -85,7 +90,8 @@ u32 __ocelot_target_read_ix(struct ocelot *ocelot, enum ocelot_target target,
u32 val;

regmap_read(ocelot->targets[target],
- ocelot->map[target][reg] + offset, &val);
+ ocelot->offsets[target] + ocelot->map[target][reg] + offset,
+ &val);
return val;
}

@@ -93,7 +99,9 @@ void __ocelot_target_write_ix(struct ocelot *ocelot, enum ocelot_target target,
u32 val, u32 reg, u32 offset)
{
regmap_write(ocelot->targets[target],
- ocelot->map[target][reg] + offset, val);
+ ocelot->offsets[target] + ocelot->map[target][reg] +
+ offset,
+ val);
}

int ocelot_regfields_init(struct ocelot *ocelot,
@@ -136,10 +144,13 @@ static struct regmap_config ocelot_regmap_config = {
.reg_stride = 4,
};

-struct regmap *ocelot_regmap_init(struct ocelot *ocelot, struct resource *res)
+struct regmap *ocelot_regmap_init(struct ocelot *ocelot, struct resource *res,
+ u32 *offset)
{
void __iomem *regs;

+ *offset = 0;
+
regs = devm_ioremap_resource(ocelot->dev, res);
if (IS_ERR(regs))
return ERR_CAST(regs);
diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
index 425ff29d9389..ad45c1af4be9 100644
--- a/include/soc/mscc/ocelot.h
+++ b/include/soc/mscc/ocelot.h
@@ -591,6 +591,7 @@ struct ocelot_port {
struct ocelot *ocelot;

struct regmap *target;
+ u32 offset;

bool vlan_aware;
/* VLAN that untagged frames are classified to, on ingress */
@@ -621,6 +622,7 @@ struct ocelot {
const struct ocelot_ops *ops;
struct regmap *targets[TARGET_MAX];
struct regmap_field *regfields[REGFIELD_MAX];
+ u32 offsets[TARGET_MAX];
const u32 *const *map;
const struct ocelot_stat_layout *stats_layout;
unsigned int num_stats;
@@ -780,7 +782,8 @@ static inline void ocelot_drain_cpu_queue(struct ocelot *ocelot, int grp)
/* Hardware initialization */
int ocelot_regfields_init(struct ocelot *ocelot,
const struct reg_field *const regfields);
-struct regmap *ocelot_regmap_init(struct ocelot *ocelot, struct resource *res);
+struct regmap *ocelot_regmap_init(struct ocelot *ocelot, struct resource *res,
+ u32 *offset);
int ocelot_init(struct ocelot *ocelot);
void ocelot_deinit(struct ocelot *ocelot);
void ocelot_init_port(struct ocelot *ocelot, int port);
--
2.25.1