kernel: bump 6.1 to 6.1.39
[openwrt/openwrt.git] / target / linux / bcm27xx / patches-6.1 / 950-0704-pinctrl-bcm2835-Workaround-for-edge-IRQ-loss.patch
1 From dcb717bc899cd55a969fb4f1f8526f313efe148c Mon Sep 17 00:00:00 2001
2 From: Phil Elwell <phil@raspberrypi.com>
3 Date: Fri, 5 May 2023 11:25:48 +0100
4 Subject: [PATCH] pinctrl: bcm2835: Workaround for edge IRQ loss
5
6 It has been observed that edge events can be lost when GPIO edges occur
7 close to each other. Investigation suggests this is due to a hardware
8 bug, although no mechanism has been identified.
9
10 Work around the event loss by moving the IRQ acknowledgement into the
11 main ISR, adding missing events by explicit level-change detection.
12
13 See: https://forums.raspberrypi.com/viewtopic.php?t=350295
14
15 Signed-off-by: Phil Elwell <phil@raspberrypi.com>
16 ---
17 drivers/pinctrl/bcm/pinctrl-bcm2835.c | 23 ++++++++++++++++++-----
18 1 file changed, 18 insertions(+), 5 deletions(-)
19
20 --- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
21 +++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
22 @@ -420,15 +420,32 @@ static void bcm2835_gpio_irq_handle_bank
23 unsigned long events;
24 unsigned offset;
25 unsigned gpio;
26 + u32 levs, levs2;
27
28 events = bcm2835_gpio_rd(pc, GPEDS0 + bank * 4);
29 + levs = bcm2835_gpio_rd(pc, GPLEV0 + bank * 4);
30 events &= mask;
31 events &= pc->enabled_irq_map[bank];
32 + bcm2835_gpio_wr(pc, GPEDS0 + bank * 4, events);
33 +
34 +retry:
35 for_each_set_bit(offset, &events, 32) {
36 gpio = (32 * bank) + offset;
37 generic_handle_domain_irq(pc->gpio_chip.irq.domain,
38 gpio);
39 }
40 + events = bcm2835_gpio_rd(pc, GPEDS0 + bank * 4);
41 + levs2 = bcm2835_gpio_rd(pc, GPLEV0 + bank * 4);
42 +
43 + events |= levs2 & ~levs & bcm2835_gpio_rd(pc, GPREN0 + bank * 4);
44 + events |= ~levs2 & levs & bcm2835_gpio_rd(pc, GPFEN0 + bank * 4);
45 + events &= mask;
46 + events &= pc->enabled_irq_map[bank];
47 + if (events) {
48 + bcm2835_gpio_wr(pc, GPEDS0 + bank * 4, events);
49 + levs = levs2;
50 + goto retry;
51 + }
52 }
53
54 static void bcm2835_gpio_irq_handler(struct irq_desc *desc)
55 @@ -668,11 +685,7 @@ static int bcm2835_gpio_irq_set_type(str
56
57 static void bcm2835_gpio_irq_ack(struct irq_data *data)
58 {
59 - struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
60 - struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
61 - unsigned gpio = irqd_to_hwirq(data);
62 -
63 - bcm2835_gpio_set_bit(pc, GPEDS0, gpio);
64 + /* Nothing to do - the main interrupt handler includes the ACK */
65 }
66
67 static int bcm2835_gpio_irq_set_wake(struct irq_data *data, unsigned int on)