]> git.ipfire.org Git - thirdparty/openwrt.git/blob
4c9ea7fe1244b0f086293b54355971b68cdf9535
[thirdparty/openwrt.git] /
1 From 32d617005475a71ebcc4ec8b2791e8d1481e9a10 Mon Sep 17 00:00:00 2001
2 From: Luiz Angelo Daros de Luca <luizluca@gmail.com>
3 Date: Sat, 27 Apr 2024 02:11:30 -0300
4 Subject: [PATCH 3/3] net: dsa: realtek: add LED drivers for rtl8366rb
5
6 This commit introduces LED drivers for rtl8366rb, enabling LEDs to be
7 described in the device tree using the same format as qca8k. Each port
8 can configure up to 4 LEDs.
9
10 If all LEDs in a group use the default state "keep", they will use the
11 default behavior after a reset. Changing the brightness of one LED,
12 either manually or by a trigger, will disable the default hardware
13 trigger and switch the entire LED group to manually controlled LEDs.
14 Once in this mode, there is no way to revert to hardware-controlled LEDs
15 (except by resetting the switch).
16
17 Software triggers function as expected with manually controlled LEDs.
18
19 Signed-off-by: Luiz Angelo Daros de Luca <luizluca@gmail.com>
20 Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
21 Signed-off-by: David S. Miller <davem@davemloft.net>
22 ---
23 drivers/net/dsa/realtek/rtl8366rb.c | 304 ++++++++++++++++++++++++----
24 1 file changed, 265 insertions(+), 39 deletions(-)
25
26 --- a/drivers/net/dsa/realtek/rtl8366rb.c
27 +++ b/drivers/net/dsa/realtek/rtl8366rb.c
28 @@ -180,6 +180,7 @@
29 #define RTL8366RB_VLAN_INGRESS_CTRL2_REG 0x037f
30
31 /* LED control registers */
32 +/* The LED blink rate is global; it is used by all triggers in all groups. */
33 #define RTL8366RB_LED_BLINKRATE_REG 0x0430
34 #define RTL8366RB_LED_BLINKRATE_MASK 0x0007
35 #define RTL8366RB_LED_BLINKRATE_28MS 0x0000
36 @@ -195,31 +196,21 @@
37 (4 * (led_group))
38 #define RTL8366RB_LED_CTRL_MASK(led_group) \
39 (0xf << RTL8366RB_LED_CTRL_OFFSET(led_group))
40 -#define RTL8366RB_LED_OFF 0x0
41 -#define RTL8366RB_LED_DUP_COL 0x1
42 -#define RTL8366RB_LED_LINK_ACT 0x2
43 -#define RTL8366RB_LED_SPD1000 0x3
44 -#define RTL8366RB_LED_SPD100 0x4
45 -#define RTL8366RB_LED_SPD10 0x5
46 -#define RTL8366RB_LED_SPD1000_ACT 0x6
47 -#define RTL8366RB_LED_SPD100_ACT 0x7
48 -#define RTL8366RB_LED_SPD10_ACT 0x8
49 -#define RTL8366RB_LED_SPD100_10_ACT 0x9
50 -#define RTL8366RB_LED_FIBER 0xa
51 -#define RTL8366RB_LED_AN_FAULT 0xb
52 -#define RTL8366RB_LED_LINK_RX 0xc
53 -#define RTL8366RB_LED_LINK_TX 0xd
54 -#define RTL8366RB_LED_MASTER 0xe
55 -#define RTL8366RB_LED_FORCE 0xf
56
57 /* The RTL8366RB_LED_X_X registers are used to manually set the LED state only
58 * when the corresponding LED group in RTL8366RB_LED_CTRL_REG is
59 - * RTL8366RB_LED_FORCE. Otherwise, it is ignored.
60 + * RTL8366RB_LEDGROUP_FORCE. Otherwise, it is ignored.
61 */
62 #define RTL8366RB_LED_0_1_CTRL_REG 0x0432
63 -#define RTL8366RB_LED_1_OFFSET 6
64 #define RTL8366RB_LED_2_3_CTRL_REG 0x0433
65 -#define RTL8366RB_LED_3_OFFSET 6
66 +#define RTL8366RB_LED_X_X_CTRL_REG(led_group) \
67 + ((led_group) <= 1 ? \
68 + RTL8366RB_LED_0_1_CTRL_REG : \
69 + RTL8366RB_LED_2_3_CTRL_REG)
70 +#define RTL8366RB_LED_0_X_CTRL_MASK GENMASK(5, 0)
71 +#define RTL8366RB_LED_X_1_CTRL_MASK GENMASK(11, 6)
72 +#define RTL8366RB_LED_2_X_CTRL_MASK GENMASK(5, 0)
73 +#define RTL8366RB_LED_X_3_CTRL_MASK GENMASK(11, 6)
74
75 #define RTL8366RB_MIB_COUNT 33
76 #define RTL8366RB_GLOBAL_MIB_COUNT 1
77 @@ -363,14 +354,44 @@
78 #define RTL8366RB_GREEN_FEATURE_TX BIT(0)
79 #define RTL8366RB_GREEN_FEATURE_RX BIT(2)
80
81 +enum rtl8366_ledgroup_mode {
82 + RTL8366RB_LEDGROUP_OFF = 0x0,
83 + RTL8366RB_LEDGROUP_DUP_COL = 0x1,
84 + RTL8366RB_LEDGROUP_LINK_ACT = 0x2,
85 + RTL8366RB_LEDGROUP_SPD1000 = 0x3,
86 + RTL8366RB_LEDGROUP_SPD100 = 0x4,
87 + RTL8366RB_LEDGROUP_SPD10 = 0x5,
88 + RTL8366RB_LEDGROUP_SPD1000_ACT = 0x6,
89 + RTL8366RB_LEDGROUP_SPD100_ACT = 0x7,
90 + RTL8366RB_LEDGROUP_SPD10_ACT = 0x8,
91 + RTL8366RB_LEDGROUP_SPD100_10_ACT = 0x9,
92 + RTL8366RB_LEDGROUP_FIBER = 0xa,
93 + RTL8366RB_LEDGROUP_AN_FAULT = 0xb,
94 + RTL8366RB_LEDGROUP_LINK_RX = 0xc,
95 + RTL8366RB_LEDGROUP_LINK_TX = 0xd,
96 + RTL8366RB_LEDGROUP_MASTER = 0xe,
97 + RTL8366RB_LEDGROUP_FORCE = 0xf,
98 +
99 + __RTL8366RB_LEDGROUP_MODE_MAX
100 +};
101 +
102 +struct rtl8366rb_led {
103 + u8 port_num;
104 + u8 led_group;
105 + struct realtek_priv *priv;
106 + struct led_classdev cdev;
107 +};
108 +
109 /**
110 * struct rtl8366rb - RTL8366RB-specific data
111 * @max_mtu: per-port max MTU setting
112 * @pvid_enabled: if PVID is set for respective port
113 + * @leds: per-port and per-ledgroup led info
114 */
115 struct rtl8366rb {
116 unsigned int max_mtu[RTL8366RB_NUM_PORTS];
117 bool pvid_enabled[RTL8366RB_NUM_PORTS];
118 + struct rtl8366rb_led leds[RTL8366RB_NUM_PORTS][RTL8366RB_NUM_LEDGROUPS];
119 };
120
121 static struct rtl8366_mib_counter rtl8366rb_mib_counters[] = {
122 @@ -813,6 +834,217 @@ static int rtl8366rb_jam_table(const str
123 return 0;
124 }
125
126 +static int rb8366rb_set_ledgroup_mode(struct realtek_priv *priv,
127 + u8 led_group,
128 + enum rtl8366_ledgroup_mode mode)
129 +{
130 + int ret;
131 + u32 val;
132 +
133 + val = mode << RTL8366RB_LED_CTRL_OFFSET(led_group);
134 +
135 + ret = regmap_update_bits(priv->map,
136 + RTL8366RB_LED_CTRL_REG,
137 + RTL8366RB_LED_CTRL_MASK(led_group),
138 + val);
139 + if (ret)
140 + return ret;
141 +
142 + return 0;
143 +}
144 +
145 +static inline u32 rtl8366rb_led_group_port_mask(u8 led_group, u8 port)
146 +{
147 + switch (led_group) {
148 + case 0:
149 + return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port));
150 + case 1:
151 + return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port));
152 + case 2:
153 + return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port));
154 + case 3:
155 + return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port));
156 + default:
157 + return 0;
158 + }
159 +}
160 +
161 +static int rb8366rb_get_port_led(struct rtl8366rb_led *led)
162 +{
163 + struct realtek_priv *priv = led->priv;
164 + u8 led_group = led->led_group;
165 + u8 port_num = led->port_num;
166 + int ret;
167 + u32 val;
168 +
169 + ret = regmap_read(priv->map, RTL8366RB_LED_X_X_CTRL_REG(led_group),
170 + &val);
171 + if (ret) {
172 + dev_err(priv->dev, "error reading LED on port %d group %d\n",
173 + led_group, port_num);
174 + return ret;
175 + }
176 +
177 + return !!(val & rtl8366rb_led_group_port_mask(led_group, port_num));
178 +}
179 +
180 +static int rb8366rb_set_port_led(struct rtl8366rb_led *led, bool enable)
181 +{
182 + struct realtek_priv *priv = led->priv;
183 + u8 led_group = led->led_group;
184 + u8 port_num = led->port_num;
185 + int ret;
186 +
187 + ret = regmap_update_bits(priv->map,
188 + RTL8366RB_LED_X_X_CTRL_REG(led_group),
189 + rtl8366rb_led_group_port_mask(led_group,
190 + port_num),
191 + enable ? 0xffff : 0);
192 + if (ret) {
193 + dev_err(priv->dev, "error updating LED on port %d group %d\n",
194 + led_group, port_num);
195 + return ret;
196 + }
197 +
198 + /* Change the LED group to manual controlled LEDs if required */
199 + ret = rb8366rb_set_ledgroup_mode(priv, led_group,
200 + RTL8366RB_LEDGROUP_FORCE);
201 +
202 + if (ret) {
203 + dev_err(priv->dev, "error updating LED GROUP group %d\n",
204 + led_group);
205 + return ret;
206 + }
207 +
208 + return 0;
209 +}
210 +
211 +static int
212 +rtl8366rb_cled_brightness_set_blocking(struct led_classdev *ldev,
213 + enum led_brightness brightness)
214 +{
215 + struct rtl8366rb_led *led = container_of(ldev, struct rtl8366rb_led,
216 + cdev);
217 +
218 + return rb8366rb_set_port_led(led, brightness == LED_ON);
219 +}
220 +
221 +static int rtl8366rb_setup_led(struct realtek_priv *priv, struct dsa_port *dp,
222 + struct fwnode_handle *led_fwnode)
223 +{
224 + struct rtl8366rb *rb = priv->chip_data;
225 + struct led_init_data init_data = { };
226 + enum led_default_state state;
227 + struct rtl8366rb_led *led;
228 + u32 led_group;
229 + int ret;
230 +
231 + ret = fwnode_property_read_u32(led_fwnode, "reg", &led_group);
232 + if (ret)
233 + return ret;
234 +
235 + if (led_group >= RTL8366RB_NUM_LEDGROUPS) {
236 + dev_warn(priv->dev, "Invalid LED reg %d defined for port %d",
237 + led_group, dp->index);
238 + return -EINVAL;
239 + }
240 +
241 + led = &rb->leds[dp->index][led_group];
242 + led->port_num = dp->index;
243 + led->led_group = led_group;
244 + led->priv = priv;
245 +
246 + state = led_init_default_state_get(led_fwnode);
247 + switch (state) {
248 + case LEDS_DEFSTATE_ON:
249 + led->cdev.brightness = 1;
250 + rb8366rb_set_port_led(led, 1);
251 + break;
252 + case LEDS_DEFSTATE_KEEP:
253 + led->cdev.brightness =
254 + rb8366rb_get_port_led(led);
255 + break;
256 + case LEDS_DEFSTATE_OFF:
257 + default:
258 + led->cdev.brightness = 0;
259 + rb8366rb_set_port_led(led, 0);
260 + }
261 +
262 + led->cdev.max_brightness = 1;
263 + led->cdev.brightness_set_blocking =
264 + rtl8366rb_cled_brightness_set_blocking;
265 + init_data.fwnode = led_fwnode;
266 + init_data.devname_mandatory = true;
267 +
268 + init_data.devicename = kasprintf(GFP_KERNEL, "Realtek-%d:0%d:%d",
269 + dp->ds->index, dp->index, led_group);
270 + if (!init_data.devicename)
271 + return -ENOMEM;
272 +
273 + ret = devm_led_classdev_register_ext(priv->dev, &led->cdev, &init_data);
274 + if (ret) {
275 + dev_warn(priv->dev, "Failed to init LED %d for port %d",
276 + led_group, dp->index);
277 + return ret;
278 + }
279 +
280 + return 0;
281 +}
282 +
283 +static int rtl8366rb_setup_all_leds_off(struct realtek_priv *priv)
284 +{
285 + int ret = 0;
286 + int i;
287 +
288 + regmap_update_bits(priv->map,
289 + RTL8366RB_INTERRUPT_CONTROL_REG,
290 + RTL8366RB_P4_RGMII_LED,
291 + 0);
292 +
293 + for (i = 0; i < RTL8366RB_NUM_LEDGROUPS; i++) {
294 + ret = rb8366rb_set_ledgroup_mode(priv, i,
295 + RTL8366RB_LEDGROUP_OFF);
296 + if (ret)
297 + return ret;
298 + }
299 +
300 + return ret;
301 +}
302 +
303 +static int rtl8366rb_setup_leds(struct realtek_priv *priv)
304 +{
305 + struct device_node *leds_np, *led_np;
306 + struct dsa_switch *ds = &priv->ds;
307 + struct dsa_port *dp;
308 + int ret = 0;
309 +
310 + dsa_switch_for_each_port(dp, ds) {
311 + if (!dp->dn)
312 + continue;
313 +
314 + leds_np = of_get_child_by_name(dp->dn, "leds");
315 + if (!leds_np) {
316 + dev_dbg(priv->dev, "No leds defined for port %d",
317 + dp->index);
318 + continue;
319 + }
320 +
321 + for_each_child_of_node(leds_np, led_np) {
322 + ret = rtl8366rb_setup_led(priv, dp,
323 + of_fwnode_handle(led_np));
324 + if (ret) {
325 + of_node_put(led_np);
326 + break;
327 + }
328 + }
329 +
330 + of_node_put(leds_np);
331 + if (ret)
332 + return ret;
333 + }
334 + return 0;
335 +}
336 +
337 static int rtl8366rb_setup(struct dsa_switch *ds)
338 {
339 struct realtek_priv *priv = ds->priv;
340 @@ -821,7 +1053,6 @@ static int rtl8366rb_setup(struct dsa_sw
341 u32 chip_ver = 0;
342 u32 chip_id = 0;
343 int jam_size;
344 - u32 val;
345 int ret;
346 int i;
347
348 @@ -997,7 +1228,9 @@ static int rtl8366rb_setup(struct dsa_sw
349 if (ret)
350 return ret;
351
352 - /* Set blinking, TODO: make this configurable */
353 + /* Set blinking, used by all LED groups using HW triggers.
354 + * TODO: make this configurable
355 + */
356 ret = regmap_update_bits(priv->map, RTL8366RB_LED_BLINKRATE_REG,
357 RTL8366RB_LED_BLINKRATE_MASK,
358 RTL8366RB_LED_BLINKRATE_56MS);
359 @@ -1005,26 +1238,19 @@ static int rtl8366rb_setup(struct dsa_sw
360 return ret;
361
362 /* Set up LED activity:
363 - * Each port has 4 LEDs, we configure all ports to the same
364 - * behaviour (no individual config) but we can set up each
365 - * LED separately.
366 + * Each port has 4 LEDs on fixed groups. Each group shares the same
367 + * hardware trigger across all ports. LEDs can only be indiviually
368 + * controlled setting the LED group to fixed mode and using the driver
369 + * to toggle them LEDs on/off.
370 */
371 if (priv->leds_disabled) {
372 - /* Turn everything off */
373 - regmap_update_bits(priv->map,
374 - RTL8366RB_INTERRUPT_CONTROL_REG,
375 - RTL8366RB_P4_RGMII_LED,
376 - 0);
377 -
378 - for (i = 0; i < RTL8366RB_NUM_LEDGROUPS; i++) {
379 - val = RTL8366RB_LED_OFF << RTL8366RB_LED_CTRL_OFFSET(i);
380 - ret = regmap_update_bits(priv->map,
381 - RTL8366RB_LED_CTRL_REG,
382 - RTL8366RB_LED_CTRL_MASK(i),
383 - val);
384 - if (ret)
385 - return ret;
386 - }
387 + ret = rtl8366rb_setup_all_leds_off(priv);
388 + if (ret)
389 + return ret;
390 + } else {
391 + ret = rtl8366rb_setup_leds(priv);
392 + if (ret)
393 + return ret;
394 }
395
396 ret = rtl8366_reset_vlan(priv);