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 | |
13 | int __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: &target, addr: &addr); |
20 | WARN_ON(!target); |
21 | |
22 | return regmap_bulk_read(map: ocelot->targets[target], reg: addr + offset, |
23 | val: buf, val_count: count); |
24 | } |
25 | EXPORT_SYMBOL_GPL(__ocelot_bulk_read_ix); |
26 | |
27 | u32 __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: &target, addr: &addr); |
33 | WARN_ON(!target); |
34 | |
35 | regmap_read(map: ocelot->targets[target], reg: addr + offset, val: &val); |
36 | return val; |
37 | } |
38 | EXPORT_SYMBOL_GPL(__ocelot_read_ix); |
39 | |
40 | void __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: &target, addr: &addr); |
47 | WARN_ON(!target); |
48 | |
49 | regmap_write(map: ocelot->targets[target], reg: addr + offset, val); |
50 | } |
51 | EXPORT_SYMBOL_GPL(__ocelot_write_ix); |
52 | |
53 | void __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: &target, addr: &addr); |
60 | WARN_ON(!target); |
61 | |
62 | regmap_update_bits(map: ocelot->targets[target], reg: addr + offset, mask, val); |
63 | } |
64 | EXPORT_SYMBOL_GPL(__ocelot_rmw_ix); |
65 | |
66 | u32 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(map: port->target, reg: ocelot->map[target][reg & REG_MASK], val: &val); |
75 | return val; |
76 | } |
77 | EXPORT_SYMBOL_GPL(ocelot_port_readl); |
78 | |
79 | void 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(map: port->target, reg: ocelot->map[target][reg & REG_MASK], val); |
87 | } |
88 | EXPORT_SYMBOL_GPL(ocelot_port_writel); |
89 | |
90 | void 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 | } |
97 | EXPORT_SYMBOL_GPL(ocelot_port_rmwl); |
98 | |
99 | u32 __ocelot_target_read_ix(struct ocelot *ocelot, enum ocelot_target target, |
100 | u32 reg, u32 offset) |
101 | { |
102 | u32 val; |
103 | |
104 | regmap_read(map: ocelot->targets[target], |
105 | reg: ocelot->map[target][reg] + offset, val: &val); |
106 | return val; |
107 | } |
108 | |
109 | void __ocelot_target_write_ix(struct ocelot *ocelot, enum ocelot_target target, |
110 | u32 val, u32 reg, u32 offset) |
111 | { |
112 | regmap_write(map: ocelot->targets[target], |
113 | reg: ocelot->map[target][reg] + offset, val); |
114 | } |
115 | |
116 | int 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(dev: ocelot->dev, |
139 | regmap: ocelot->targets[target], |
140 | reg_field: regfield); |
141 | |
142 | if (IS_ERR(ptr: ocelot->regfields[i])) |
143 | return PTR_ERR(ptr: ocelot->regfields[i]); |
144 | } |
145 | |
146 | return 0; |
147 | } |
148 | EXPORT_SYMBOL_GPL(ocelot_regfields_init); |
149 | |
150 | static struct regmap_config ocelot_regmap_config = { |
151 | .reg_bits = 32, |
152 | .val_bits = 32, |
153 | .reg_stride = 4, |
154 | }; |
155 | |
156 | struct regmap *ocelot_regmap_init(struct ocelot *ocelot, struct resource *res) |
157 | { |
158 | void __iomem *regs; |
159 | |
160 | regs = devm_ioremap_resource(dev: ocelot->dev, res); |
161 | if (IS_ERR(ptr: regs)) |
162 | return ERR_CAST(ptr: regs); |
163 | |
164 | ocelot_regmap_config.name = res->name; |
165 | |
166 | return devm_regmap_init_mmio(ocelot->dev, regs, &ocelot_regmap_config); |
167 | } |
168 | EXPORT_SYMBOL_GPL(ocelot_regmap_init); |
169 | |