1// SPDX-License-Identifier: (GPL-2.0 OR MIT)
2/*
3 * Microsemi Ocelot Switch driver
4 *
5 * Copyright (c) 2017 Microsemi Corporation
6 */
7#include <linux/io.h>
8#include <linux/kernel.h>
9#include <linux/platform_device.h>
10
11#include "ocelot.h"
12
13int __ocelot_bulk_read_ix(struct ocelot *ocelot, enum ocelot_reg reg,
14			  u32 offset, void *buf, int count)
15{
16	enum ocelot_target target;
17	u32 addr;
18
19	ocelot_reg_to_target_addr(ocelot, reg, &target, &addr);
20	WARN_ON(!target);
21
22	return regmap_bulk_read(ocelot->targets[target], addr + offset,
23				buf, count);
24}
25EXPORT_SYMBOL_GPL(__ocelot_bulk_read_ix);
26
27u32 __ocelot_read_ix(struct ocelot *ocelot, enum ocelot_reg reg, u32 offset)
28{
29	enum ocelot_target target;
30	u32 addr, val;
31
32	ocelot_reg_to_target_addr(ocelot, reg, &target, &addr);
33	WARN_ON(!target);
34
35	regmap_read(ocelot->targets[target], addr + offset, &val);
36	return val;
37}
38EXPORT_SYMBOL_GPL(__ocelot_read_ix);
39
40void __ocelot_write_ix(struct ocelot *ocelot, u32 val, enum ocelot_reg reg,
41		       u32 offset)
42{
43	enum ocelot_target target;
44	u32 addr;
45
46	ocelot_reg_to_target_addr(ocelot, reg, &target, &addr);
47	WARN_ON(!target);
48
49	regmap_write(ocelot->targets[target], addr + offset, val);
50}
51EXPORT_SYMBOL_GPL(__ocelot_write_ix);
52
53void __ocelot_rmw_ix(struct ocelot *ocelot, u32 val, u32 mask,
54		     enum ocelot_reg reg, u32 offset)
55{
56	enum ocelot_target target;
57	u32 addr;
58
59	ocelot_reg_to_target_addr(ocelot, reg, &target, &addr);
60	WARN_ON(!target);
61
62	regmap_update_bits(ocelot->targets[target], addr + offset, mask, val);
63}
64EXPORT_SYMBOL_GPL(__ocelot_rmw_ix);
65
66u32 ocelot_port_readl(struct ocelot_port *port, enum ocelot_reg reg)
67{
68	struct ocelot *ocelot = port->ocelot;
69	u16 target = reg >> TARGET_OFFSET;
70	u32 val;
71
72	WARN_ON(!target);
73
74	regmap_read(port->target, ocelot->map[target][reg & REG_MASK], &val);
75	return val;
76}
77EXPORT_SYMBOL_GPL(ocelot_port_readl);
78
79void ocelot_port_writel(struct ocelot_port *port, u32 val, enum ocelot_reg reg)
80{
81	struct ocelot *ocelot = port->ocelot;
82	u16 target = reg >> TARGET_OFFSET;
83
84	WARN_ON(!target);
85
86	regmap_write(port->target, ocelot->map[target][reg & REG_MASK], val);
87}
88EXPORT_SYMBOL_GPL(ocelot_port_writel);
89
90void ocelot_port_rmwl(struct ocelot_port *port, u32 val, u32 mask,
91		      enum ocelot_reg reg)
92{
93	u32 cur = ocelot_port_readl(port, reg);
94
95	ocelot_port_writel(port, (cur & (~mask)) | val, reg);
96}
97EXPORT_SYMBOL_GPL(ocelot_port_rmwl);
98
99u32 __ocelot_target_read_ix(struct ocelot *ocelot, enum ocelot_target target,
100			    u32 reg, u32 offset)
101{
102	u32 val;
103
104	regmap_read(ocelot->targets[target],
105		    ocelot->map[target][reg] + offset, &val);
106	return val;
107}
108
109void __ocelot_target_write_ix(struct ocelot *ocelot, enum ocelot_target target,
110			      u32 val, u32 reg, u32 offset)
111{
112	regmap_write(ocelot->targets[target],
113		     ocelot->map[target][reg] + offset, val);
114}
115
116int ocelot_regfields_init(struct ocelot *ocelot,
117			  const struct reg_field *const regfields)
118{
119	unsigned int i;
120	u16 target;
121
122	for (i = 0; i < REGFIELD_MAX; i++) {
123		struct reg_field regfield = {};
124		u32 reg = regfields[i].reg;
125
126		if (!reg)
127			continue;
128
129		target = regfields[i].reg >> TARGET_OFFSET;
130
131		regfield.reg = ocelot->map[target][reg & REG_MASK];
132		regfield.lsb = regfields[i].lsb;
133		regfield.msb = regfields[i].msb;
134		regfield.id_size = regfields[i].id_size;
135		regfield.id_offset = regfields[i].id_offset;
136
137		ocelot->regfields[i] =
138		devm_regmap_field_alloc(ocelot->dev,
139					ocelot->targets[target],
140					regfield);
141
142		if (IS_ERR(ocelot->regfields[i]))
143			return PTR_ERR(ocelot->regfields[i]);
144	}
145
146	return 0;
147}
148EXPORT_SYMBOL_GPL(ocelot_regfields_init);
149
150static struct regmap_config ocelot_regmap_config = {
151	.reg_bits	= 32,
152	.val_bits	= 32,
153	.reg_stride	= 4,
154};
155
156struct regmap *ocelot_regmap_init(struct ocelot *ocelot, struct resource *res)
157{
158	void __iomem *regs;
159
160	regs = devm_ioremap_resource(ocelot->dev, res);
161	if (IS_ERR(regs))
162		return ERR_CAST(regs);
163
164	ocelot_regmap_config.name = res->name;
165
166	return devm_regmap_init_mmio(ocelot->dev, regs, &ocelot_regmap_config);
167}
168EXPORT_SYMBOL_GPL(ocelot_regmap_init);
169