Commit cff26083 authored by Philippe Gerum's avatar Philippe Gerum

pinctrl: bcm2835: ipipe: enable interrupt pipelining

Fix up the pin controller driver of the Broadcom 2835 SoC in order to
channel interrupts through the interrupt pipeline.
parent 18a52b74
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/irqdesc.h> #include <linux/irqdesc.h>
#include <linux/ipipe.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of.h> #include <linux/of.h>
...@@ -92,7 +93,11 @@ struct bcm2835_pinctrl { ...@@ -92,7 +93,11 @@ struct bcm2835_pinctrl {
struct gpio_chip gpio_chip; struct gpio_chip gpio_chip;
struct pinctrl_gpio_range gpio_range; struct pinctrl_gpio_range gpio_range;
spinlock_t irq_lock[BCM2835_NUM_BANKS]; #ifdef CONFIG_IPIPE
ipipe_spinlock_t irq_lock[BCM2835_NUM_BANKS];
#else
raw_spinlock_t irq_lock[BCM2835_NUM_BANKS];
#endif
}; };
/* pins are just named GPIO0..GPIO53 */ /* pins are just named GPIO0..GPIO53 */
...@@ -379,7 +384,7 @@ static void bcm2835_gpio_irq_handle_bank(struct bcm2835_pinctrl *pc, ...@@ -379,7 +384,7 @@ static void bcm2835_gpio_irq_handle_bank(struct bcm2835_pinctrl *pc,
events &= pc->enabled_irq_map[bank]; events &= pc->enabled_irq_map[bank];
for_each_set_bit(offset, &events, 32) { for_each_set_bit(offset, &events, 32) {
gpio = (32 * bank) + offset; gpio = (32 * bank) + offset;
generic_handle_irq(irq_linear_revmap(pc->gpio_chip.irqdomain, ipipe_handle_demuxed_irq(irq_linear_revmap(pc->gpio_chip.irqdomain,
gpio)); gpio));
} }
} }
...@@ -471,10 +476,11 @@ static void bcm2835_gpio_irq_enable(struct irq_data *data) ...@@ -471,10 +476,11 @@ static void bcm2835_gpio_irq_enable(struct irq_data *data)
unsigned bank = GPIO_REG_OFFSET(gpio); unsigned bank = GPIO_REG_OFFSET(gpio);
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&pc->irq_lock[bank], flags); raw_spin_lock_irqsave(&pc->irq_lock[bank], flags);
set_bit(offset, &pc->enabled_irq_map[bank]); set_bit(offset, &pc->enabled_irq_map[bank]);
bcm2835_gpio_irq_config(pc, gpio, true); bcm2835_gpio_irq_config(pc, gpio, true);
spin_unlock_irqrestore(&pc->irq_lock[bank], flags); ipipe_unlock_irq(data->irq);
raw_spin_unlock_irqrestore(&pc->irq_lock[bank], flags);
} }
static void bcm2835_gpio_irq_disable(struct irq_data *data) static void bcm2835_gpio_irq_disable(struct irq_data *data)
...@@ -486,12 +492,13 @@ static void bcm2835_gpio_irq_disable(struct irq_data *data) ...@@ -486,12 +492,13 @@ static void bcm2835_gpio_irq_disable(struct irq_data *data)
unsigned bank = GPIO_REG_OFFSET(gpio); unsigned bank = GPIO_REG_OFFSET(gpio);
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&pc->irq_lock[bank], flags); raw_spin_lock_irqsave(&pc->irq_lock[bank], flags);
bcm2835_gpio_irq_config(pc, gpio, false); bcm2835_gpio_irq_config(pc, gpio, false);
/* Clear events that were latched prior to clearing event sources */ /* Clear events that were latched prior to clearing event sources */
bcm2835_gpio_set_bit(pc, GPEDS0, gpio); bcm2835_gpio_set_bit(pc, GPEDS0, gpio);
clear_bit(offset, &pc->enabled_irq_map[bank]); clear_bit(offset, &pc->enabled_irq_map[bank]);
spin_unlock_irqrestore(&pc->irq_lock[bank], flags); ipipe_lock_irq(data->irq);
raw_spin_unlock_irqrestore(&pc->irq_lock[bank], flags);
} }
static int __bcm2835_gpio_irq_set_type_disabled(struct bcm2835_pinctrl *pc, static int __bcm2835_gpio_irq_set_type_disabled(struct bcm2835_pinctrl *pc,
...@@ -594,7 +601,7 @@ static int bcm2835_gpio_irq_set_type(struct irq_data *data, unsigned int type) ...@@ -594,7 +601,7 @@ static int bcm2835_gpio_irq_set_type(struct irq_data *data, unsigned int type)
unsigned long flags; unsigned long flags;
int ret; int ret;
spin_lock_irqsave(&pc->irq_lock[bank], flags); raw_spin_lock_irqsave(&pc->irq_lock[bank], flags);
if (test_bit(offset, &pc->enabled_irq_map[bank])) if (test_bit(offset, &pc->enabled_irq_map[bank]))
ret = __bcm2835_gpio_irq_set_type_enabled(pc, gpio, type); ret = __bcm2835_gpio_irq_set_type_enabled(pc, gpio, type);
...@@ -606,7 +613,7 @@ static int bcm2835_gpio_irq_set_type(struct irq_data *data, unsigned int type) ...@@ -606,7 +613,7 @@ static int bcm2835_gpio_irq_set_type(struct irq_data *data, unsigned int type)
else else
irq_set_handler_locked(data, handle_level_irq); irq_set_handler_locked(data, handle_level_irq);
spin_unlock_irqrestore(&pc->irq_lock[bank], flags); raw_spin_unlock_irqrestore(&pc->irq_lock[bank], flags);
return ret; return ret;
} }
...@@ -620,6 +627,39 @@ static void bcm2835_gpio_irq_ack(struct irq_data *data) ...@@ -620,6 +627,39 @@ static void bcm2835_gpio_irq_ack(struct irq_data *data)
bcm2835_gpio_set_bit(pc, GPEDS0, gpio); bcm2835_gpio_set_bit(pc, GPEDS0, gpio);
} }
#ifdef CONFIG_IPIPE
static void bcm2835_gpio_irq_hold(struct irq_data *data)
{
struct bcm2835_pinctrl *pc = irq_data_get_irq_chip_data(data);
unsigned gpio = irqd_to_hwirq(data);
unsigned offset = GPIO_REG_SHIFT(gpio);
unsigned bank = GPIO_REG_OFFSET(gpio);
unsigned long flags;
raw_spin_lock_irqsave(&pc->irq_lock[bank], flags);
bcm2835_gpio_irq_config(pc, gpio, false);
bcm2835_gpio_set_bit(pc, GPEDS0, gpio);
clear_bit(offset, &pc->enabled_irq_map[bank]);
raw_spin_unlock_irqrestore(&pc->irq_lock[bank], flags);
}
static void bcm2835_gpio_irq_release(struct irq_data *data)
{
struct bcm2835_pinctrl *pc = irq_data_get_irq_chip_data(data);
unsigned gpio = irqd_to_hwirq(data);
unsigned offset = GPIO_REG_SHIFT(gpio);
unsigned bank = GPIO_REG_OFFSET(gpio);
unsigned long flags;
raw_spin_lock_irqsave(&pc->irq_lock[bank], flags);
set_bit(offset, &pc->enabled_irq_map[bank]);
bcm2835_gpio_irq_config(pc, gpio, true);
raw_spin_unlock_irqrestore(&pc->irq_lock[bank], flags);
}
#endif
static struct irq_chip bcm2835_gpio_irq_chip = { static struct irq_chip bcm2835_gpio_irq_chip = {
.name = MODULE_NAME, .name = MODULE_NAME,
.irq_enable = bcm2835_gpio_irq_enable, .irq_enable = bcm2835_gpio_irq_enable,
...@@ -628,6 +668,11 @@ static struct irq_chip bcm2835_gpio_irq_chip = { ...@@ -628,6 +668,11 @@ static struct irq_chip bcm2835_gpio_irq_chip = {
.irq_ack = bcm2835_gpio_irq_ack, .irq_ack = bcm2835_gpio_irq_ack,
.irq_mask = bcm2835_gpio_irq_disable, .irq_mask = bcm2835_gpio_irq_disable,
.irq_unmask = bcm2835_gpio_irq_enable, .irq_unmask = bcm2835_gpio_irq_enable,
#ifdef CONFIG_IPIPE
.irq_hold = bcm2835_gpio_irq_hold,
.irq_release = bcm2835_gpio_irq_release,
#endif
.flags = IRQCHIP_PIPELINE_SAFE,
}; };
static int bcm2835_pctl_get_groups_count(struct pinctrl_dev *pctldev) static int bcm2835_pctl_get_groups_count(struct pinctrl_dev *pctldev)
...@@ -1021,7 +1066,7 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev) ...@@ -1021,7 +1066,7 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
for_each_set_bit(offset, &events, 32) for_each_set_bit(offset, &events, 32)
bcm2835_gpio_wr(pc, GPEDS0 + i * 4, BIT(offset)); bcm2835_gpio_wr(pc, GPEDS0 + i * 4, BIT(offset));
spin_lock_init(&pc->irq_lock[i]); raw_spin_lock_init(&pc->irq_lock[i]);
} }
err = gpiochip_add_data(&pc->gpio_chip, pc); err = gpiochip_add_data(&pc->gpio_chip, pc);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment