18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0 OR MIT)
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Microsemi Ocelot Switch driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2017 Microsemi Corporation
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include <linux/io.h>
88c2ecf20Sopenharmony_ci#include <linux/kernel.h>
98c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include "ocelot.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ciu32 __ocelot_read_ix(struct ocelot *ocelot, u32 reg, u32 offset)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	u16 target = reg >> TARGET_OFFSET;
168c2ecf20Sopenharmony_ci	u32 val;
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci	WARN_ON(!target);
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci	regmap_read(ocelot->targets[target],
218c2ecf20Sopenharmony_ci		    ocelot->map[target][reg & REG_MASK] + offset, &val);
228c2ecf20Sopenharmony_ci	return val;
238c2ecf20Sopenharmony_ci}
248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__ocelot_read_ix);
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_civoid __ocelot_write_ix(struct ocelot *ocelot, u32 val, u32 reg, u32 offset)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	u16 target = reg >> TARGET_OFFSET;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	WARN_ON(!target);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	regmap_write(ocelot->targets[target],
338c2ecf20Sopenharmony_ci		     ocelot->map[target][reg & REG_MASK] + offset, val);
348c2ecf20Sopenharmony_ci}
358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__ocelot_write_ix);
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_civoid __ocelot_rmw_ix(struct ocelot *ocelot, u32 val, u32 mask, u32 reg,
388c2ecf20Sopenharmony_ci		     u32 offset)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	u16 target = reg >> TARGET_OFFSET;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	WARN_ON(!target);
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	regmap_update_bits(ocelot->targets[target],
458c2ecf20Sopenharmony_ci			   ocelot->map[target][reg & REG_MASK] + offset,
468c2ecf20Sopenharmony_ci			   mask, val);
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__ocelot_rmw_ix);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ciu32 ocelot_port_readl(struct ocelot_port *port, u32 reg)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	struct ocelot *ocelot = port->ocelot;
538c2ecf20Sopenharmony_ci	u16 target = reg >> TARGET_OFFSET;
548c2ecf20Sopenharmony_ci	u32 val;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	WARN_ON(!target);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	regmap_read(port->target, ocelot->map[target][reg & REG_MASK], &val);
598c2ecf20Sopenharmony_ci	return val;
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ocelot_port_readl);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_civoid ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	struct ocelot *ocelot = port->ocelot;
668c2ecf20Sopenharmony_ci	u16 target = reg >> TARGET_OFFSET;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	WARN_ON(!target);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	regmap_write(port->target, ocelot->map[target][reg & REG_MASK], val);
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ocelot_port_writel);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_civoid ocelot_port_rmwl(struct ocelot_port *port, u32 val, u32 mask, u32 reg)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	u32 cur = ocelot_port_readl(port, reg);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	ocelot_port_writel(port, (cur & (~mask)) | val, reg);
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ocelot_port_rmwl);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ciu32 __ocelot_target_read_ix(struct ocelot *ocelot, enum ocelot_target target,
838c2ecf20Sopenharmony_ci			    u32 reg, u32 offset)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	u32 val;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	regmap_read(ocelot->targets[target],
888c2ecf20Sopenharmony_ci		    ocelot->map[target][reg] + offset, &val);
898c2ecf20Sopenharmony_ci	return val;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_civoid __ocelot_target_write_ix(struct ocelot *ocelot, enum ocelot_target target,
938c2ecf20Sopenharmony_ci			      u32 val, u32 reg, u32 offset)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	regmap_write(ocelot->targets[target],
968c2ecf20Sopenharmony_ci		     ocelot->map[target][reg] + offset, val);
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ciint ocelot_regfields_init(struct ocelot *ocelot,
1008c2ecf20Sopenharmony_ci			  const struct reg_field *const regfields)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	unsigned int i;
1038c2ecf20Sopenharmony_ci	u16 target;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	for (i = 0; i < REGFIELD_MAX; i++) {
1068c2ecf20Sopenharmony_ci		struct reg_field regfield = {};
1078c2ecf20Sopenharmony_ci		u32 reg = regfields[i].reg;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci		if (!reg)
1108c2ecf20Sopenharmony_ci			continue;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci		target = regfields[i].reg >> TARGET_OFFSET;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci		regfield.reg = ocelot->map[target][reg & REG_MASK];
1158c2ecf20Sopenharmony_ci		regfield.lsb = regfields[i].lsb;
1168c2ecf20Sopenharmony_ci		regfield.msb = regfields[i].msb;
1178c2ecf20Sopenharmony_ci		regfield.id_size = regfields[i].id_size;
1188c2ecf20Sopenharmony_ci		regfield.id_offset = regfields[i].id_offset;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci		ocelot->regfields[i] =
1218c2ecf20Sopenharmony_ci		devm_regmap_field_alloc(ocelot->dev,
1228c2ecf20Sopenharmony_ci					ocelot->targets[target],
1238c2ecf20Sopenharmony_ci					regfield);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci		if (IS_ERR(ocelot->regfields[i]))
1268c2ecf20Sopenharmony_ci			return PTR_ERR(ocelot->regfields[i]);
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	return 0;
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ocelot_regfields_init);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic struct regmap_config ocelot_regmap_config = {
1348c2ecf20Sopenharmony_ci	.reg_bits	= 32,
1358c2ecf20Sopenharmony_ci	.val_bits	= 32,
1368c2ecf20Sopenharmony_ci	.reg_stride	= 4,
1378c2ecf20Sopenharmony_ci};
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistruct regmap *ocelot_regmap_init(struct ocelot *ocelot, struct resource *res)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	void __iomem *regs;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	regs = devm_ioremap_resource(ocelot->dev, res);
1448c2ecf20Sopenharmony_ci	if (IS_ERR(regs))
1458c2ecf20Sopenharmony_ci		return ERR_CAST(regs);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	ocelot_regmap_config.name = res->name;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	return devm_regmap_init_mmio(ocelot->dev, regs, &ocelot_regmap_config);
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ocelot_regmap_init);
152