diff options
Diffstat (limited to 'target/linux/bcm27xx/patches-6.1/950-0855-gpio_brcmstb-Allow-to-build-for-ARCH_BCM2835.patch')
-rw-r--r-- | target/linux/bcm27xx/patches-6.1/950-0855-gpio_brcmstb-Allow-to-build-for-ARCH_BCM2835.patch | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/target/linux/bcm27xx/patches-6.1/950-0855-gpio_brcmstb-Allow-to-build-for-ARCH_BCM2835.patch b/target/linux/bcm27xx/patches-6.1/950-0855-gpio_brcmstb-Allow-to-build-for-ARCH_BCM2835.patch new file mode 100644 index 0000000000..7e39ac8abf --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0855-gpio_brcmstb-Allow-to-build-for-ARCH_BCM2835.patch @@ -0,0 +1,282 @@ +From fa18902ee1e53ad391a455a01be3ab2ea1c5af5f Mon Sep 17 00:00:00 2001 +From: Dom Cobley <popcornmix@gmail.com> +Date: Fri, 21 May 2021 12:33:38 +0100 +Subject: [PATCH] gpio_brcmstb: Allow to build for ARCH_BCM2835 + +gpio-brcmstb: Report the correct bank width + +gpio: brcmstb: Use bank address as gpiochip label + +If the path to the device node is used as gpiochip label then +gpio-brcmstb instances with multiple banks end up with duplicated +names. Instead, use a combination of the driver name with the physical +address of the bank, which is both unique and helpful for devmem +debugging. + +Signed-off-by: Phil Elwell <phil@raspberrypi.com> + +gpio: mmio: Add DIRECT mode for shared access + +The generic MMIO GPIO library uses shadow registers for efficiency, +but this breaks attempts by raspi-gpio to change other GPIOs in the +same bank. Add a DIRECT mode that makes fewer assumptions about the +existing register contents, but note that genuinely simultaneous +accesses are likely to lose updates. + +Signed-off-by: Phil Elwell <phil@raspberrypi.com> + +gpio: brcmstb: Don't always clear interrupt mask + +If the GPIO controller is not being used as an interrupt source +leave the interrupt mask register alone. On BCM2712 it might be used +to generate interrupts to the VPU firmware, and on other devices it +doesn't matter since no interrupts will be generated. + +Signed-off-by: Phil Elwell <phil@raspberrypi.com> +--- + drivers/gpio/Kconfig | 2 +- + drivers/gpio/gpio-brcmstb.c | 14 ++-- + drivers/gpio/gpio-mmio.c | 124 ++++++++++++++++++++++++++++++++++-- + include/linux/gpio/driver.h | 1 + + 4 files changed, 131 insertions(+), 10 deletions(-) + +--- a/drivers/gpio/Kconfig ++++ b/drivers/gpio/Kconfig +@@ -203,7 +203,7 @@ config GPIO_BCM_VIRT + config GPIO_BRCMSTB + tristate "BRCMSTB GPIO support" + default y if (ARCH_BRCMSTB || BMIPS_GENERIC) +- depends on OF_GPIO && (ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST) ++ depends on OF_GPIO && (ARCH_BRCMSTB || BMIPS_GENERIC || ARCH_BCM2835 || COMPILE_TEST) + select GPIO_GENERIC + select IRQ_DOMAIN + help +--- a/drivers/gpio/gpio-brcmstb.c ++++ b/drivers/gpio/gpio-brcmstb.c +@@ -640,6 +640,8 @@ static int brcmstb_gpio_probe(struct pla + #if defined(CONFIG_MIPS) && defined(__BIG_ENDIAN) + flags = BGPIOF_BIG_ENDIAN_BYTE_ORDER; + #endif ++ if (of_property_read_bool(np, "brcm,gpio-direct")) ++ flags |= BGPIOF_REG_DIRECT; + + of_property_for_each_u32(np, "brcm,gpio-bank-widths", prop, p, + bank_width) { +@@ -689,7 +691,9 @@ static int brcmstb_gpio_probe(struct pla + } + + gc->owner = THIS_MODULE; +- gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", np); ++ gc->label = devm_kasprintf(dev, GFP_KERNEL, "gpio-brcmstb@%zx", ++ (size_t)res->start + ++ GIO_BANK_OFF(bank->id, 0)); + if (!gc->label) { + err = -ENOMEM; + goto fail; +@@ -698,7 +702,7 @@ static int brcmstb_gpio_probe(struct pla + gc->of_gpio_n_cells = 2; + gc->of_xlate = brcmstb_gpio_of_xlate; + /* not all ngpio lines are valid, will use bank width later */ +- gc->ngpio = MAX_GPIO_PER_BANK; ++ gc->ngpio = bank_width; + gc->offset = bank->id * MAX_GPIO_PER_BANK; + if (priv->parent_irq > 0) + gc->to_irq = brcmstb_gpio_to_irq; +@@ -707,8 +711,10 @@ static int brcmstb_gpio_probe(struct pla + * Mask all interrupts by default, since wakeup interrupts may + * be retained from S5 cold boot + */ +- need_wakeup_event |= !!__brcmstb_gpio_get_active_irqs(bank); +- gc->write_reg(reg_base + GIO_MASK(bank->id), 0); ++ if (priv->parent_irq > 0) { ++ need_wakeup_event |= !!__brcmstb_gpio_get_active_irqs(bank); ++ gc->write_reg(reg_base + GIO_MASK(bank->id), 0); ++ } + + err = gpiochip_add_data(gc, bank); + if (err) { +--- a/drivers/gpio/gpio-mmio.c ++++ b/drivers/gpio/gpio-mmio.c +@@ -232,6 +232,25 @@ static void bgpio_set(struct gpio_chip * + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); + } + ++static void bgpio_set_direct(struct gpio_chip *gc, unsigned int gpio, int val) ++{ ++ unsigned long mask = bgpio_line2mask(gc, gpio); ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&gc->bgpio_lock, flags); ++ ++ gc->bgpio_data = gc->read_reg(gc->reg_dat); ++ ++ if (val) ++ gc->bgpio_data |= mask; ++ else ++ gc->bgpio_data &= ~mask; ++ ++ gc->write_reg(gc->reg_dat, gc->bgpio_data); ++ ++ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); ++} ++ + static void bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio, + int val) + { +@@ -324,6 +343,27 @@ static void bgpio_set_multiple_with_clea + gc->write_reg(gc->reg_clr, clear_mask); + } + ++static void bgpio_set_multiple_direct(struct gpio_chip *gc, ++ unsigned long *mask, ++ unsigned long *bits) ++{ ++ unsigned long flags; ++ unsigned long set_mask, clear_mask; ++ ++ raw_spin_lock_irqsave(&gc->bgpio_lock, flags); ++ ++ bgpio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask); ++ ++ gc->bgpio_data = gc->read_reg(gc->reg_dat); ++ ++ gc->bgpio_data |= set_mask; ++ gc->bgpio_data &= ~clear_mask; ++ ++ gc->write_reg(gc->reg_dat, gc->bgpio_data); ++ ++ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); ++} ++ + static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio) + { + return 0; +@@ -361,6 +401,29 @@ static int bgpio_dir_in(struct gpio_chip + return 0; + } + ++static int bgpio_dir_in_direct(struct gpio_chip *gc, unsigned int gpio) ++{ ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&gc->bgpio_lock, flags); ++ ++ if (gc->reg_dir_in) ++ gc->bgpio_dir = ~gc->read_reg(gc->reg_dir_in); ++ if (gc->reg_dir_out) ++ gc->bgpio_dir = gc->read_reg(gc->reg_dir_out); ++ ++ gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio); ++ ++ if (gc->reg_dir_in) ++ gc->write_reg(gc->reg_dir_in, ~gc->bgpio_dir); ++ if (gc->reg_dir_out) ++ gc->write_reg(gc->reg_dir_out, gc->bgpio_dir); ++ ++ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); ++ ++ return 0; ++} ++ + static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio) + { + /* Return 0 if output, 1 if input */ +@@ -399,6 +462,28 @@ static void bgpio_dir_out(struct gpio_ch + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); + } + ++static void bgpio_dir_out_direct(struct gpio_chip *gc, unsigned int gpio, ++ int val) ++{ ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&gc->bgpio_lock, flags); ++ ++ if (gc->reg_dir_in) ++ gc->bgpio_dir = ~gc->read_reg(gc->reg_dir_in); ++ if (gc->reg_dir_out) ++ gc->bgpio_dir = gc->read_reg(gc->reg_dir_out); ++ ++ gc->bgpio_dir |= bgpio_line2mask(gc, gpio); ++ ++ if (gc->reg_dir_in) ++ gc->write_reg(gc->reg_dir_in, ~gc->bgpio_dir); ++ if (gc->reg_dir_out) ++ gc->write_reg(gc->reg_dir_out, gc->bgpio_dir); ++ ++ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); ++} ++ + static int bgpio_dir_out_dir_first(struct gpio_chip *gc, unsigned int gpio, + int val) + { +@@ -415,6 +500,22 @@ static int bgpio_dir_out_val_first(struc + return 0; + } + ++static int bgpio_dir_out_dir_first_direct(struct gpio_chip *gc, ++ unsigned int gpio, int val) ++{ ++ bgpio_dir_out_direct(gc, gpio, val); ++ gc->set(gc, gpio, val); ++ return 0; ++} ++ ++static int bgpio_dir_out_val_first_direct(struct gpio_chip *gc, ++ unsigned int gpio, int val) ++{ ++ gc->set(gc, gpio, val); ++ bgpio_dir_out_direct(gc, gpio, val); ++ return 0; ++} ++ + static int bgpio_setup_accessors(struct device *dev, + struct gpio_chip *gc, + bool byte_be) +@@ -508,6 +609,9 @@ static int bgpio_setup_io(struct gpio_ch + } else if (flags & BGPIOF_NO_OUTPUT) { + gc->set = bgpio_set_none; + gc->set_multiple = NULL; ++ } else if (flags & BGPIOF_REG_DIRECT) { ++ gc->set = bgpio_set_direct; ++ gc->set_multiple = bgpio_set_multiple_direct; + } else { + gc->set = bgpio_set; + gc->set_multiple = bgpio_set_multiple; +@@ -544,11 +648,21 @@ static int bgpio_setup_direction(struct + if (dirout || dirin) { + gc->reg_dir_out = dirout; + gc->reg_dir_in = dirin; +- if (flags & BGPIOF_NO_SET_ON_INPUT) +- gc->direction_output = bgpio_dir_out_dir_first; +- else +- gc->direction_output = bgpio_dir_out_val_first; +- gc->direction_input = bgpio_dir_in; ++ if (flags & BGPIOF_REG_DIRECT) { ++ if (flags & BGPIOF_NO_SET_ON_INPUT) ++ gc->direction_output = ++ bgpio_dir_out_dir_first_direct; ++ else ++ gc->direction_output = ++ bgpio_dir_out_val_first_direct; ++ gc->direction_input = bgpio_dir_in_direct; ++ } else { ++ if (flags & BGPIOF_NO_SET_ON_INPUT) ++ gc->direction_output = bgpio_dir_out_dir_first; ++ else ++ gc->direction_output = bgpio_dir_out_val_first; ++ gc->direction_input = bgpio_dir_in; ++ } + gc->get_direction = bgpio_get_dir; + } else { + if (flags & BGPIOF_NO_OUTPUT) +--- a/include/linux/gpio/driver.h ++++ b/include/linux/gpio/driver.h +@@ -690,6 +690,7 @@ int bgpio_init(struct gpio_chip *gc, str + #define BGPIOF_READ_OUTPUT_REG_SET BIT(4) /* reg_set stores output value */ + #define BGPIOF_NO_OUTPUT BIT(5) /* only input */ + #define BGPIOF_NO_SET_ON_INPUT BIT(6) ++#define BGPIOF_REG_DIRECT BIT(7) /* ignore shadow registers */ + + int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq); |