Commit 7a36071e authored by David Brownell's avatar David Brownell Committed by Kevin Hilman

davinci: dm365 gpio irq support

Support DM365 GPIOs ... primarily by handling non-banked GPIO IRQs:

 - Flag DM365 chips as using non-banked GPIO interrupts, using a
   new soc_info field.

 - Replace the gpio_to_irq() mapping logic.  This now uses some
   runtime infrastructure, keyed off that new soc_info field,
   which doesn't handle irq_to_gpio().

 - Provide a new irq_chip ... GPIO IRQs handled directly by AINTC
   still need edge triggering managed by the GPIO controller.

DM365 chips no longer falsely report 104 GPIO IRQs as they boot.

Intelligence about IRQ muxing is missing, so for the moment this
only exposes the first eight DM365 GPIOs, which are never muxed.
The next eight are muxed, half with Ethernet (which uses most of
those pins anyway).

Tested on DM355 (10 unbanked IRQs _or_ 104 banked ones) and also
on DM365 (16 unbanked ones, only 8 made available).
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarKevin Hilman <khilman@deeprootsystems.com>
parent af5dbaef
...@@ -882,7 +882,8 @@ static struct davinci_soc_info davinci_soc_info_dm365 = { ...@@ -882,7 +882,8 @@ static struct davinci_soc_info davinci_soc_info_dm365 = {
.timer_info = &dm365_timer_info, .timer_info = &dm365_timer_info,
.gpio_base = IO_ADDRESS(DAVINCI_GPIO_BASE), .gpio_base = IO_ADDRESS(DAVINCI_GPIO_BASE),
.gpio_num = 104, .gpio_num = 104,
.gpio_irq = 44, .gpio_irq = IRQ_DM365_GPIO0,
.gpio_unbanked = 8, /* really 16 ... skip muxed GPIOs */
.serial_dev = &dm365_serial_device, .serial_dev = &dm365_serial_device,
.emac_pdata = &dm365_emac_pdata, .emac_pdata = &dm365_emac_pdata,
.sram_dma = 0x00010000, .sram_dma = 0x00010000,
......
...@@ -34,6 +34,7 @@ static DEFINE_SPINLOCK(gpio_lock); ...@@ -34,6 +34,7 @@ static DEFINE_SPINLOCK(gpio_lock);
struct davinci_gpio { struct davinci_gpio {
struct gpio_chip chip; struct gpio_chip chip;
struct gpio_controller *__iomem regs; struct gpio_controller *__iomem regs;
int irq_base;
}; };
static struct davinci_gpio chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)]; static struct davinci_gpio chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];
...@@ -161,8 +162,7 @@ pure_initcall(davinci_gpio_setup); ...@@ -161,8 +162,7 @@ pure_initcall(davinci_gpio_setup);
* used as output pins ... which is convenient for testing. * used as output pins ... which is convenient for testing.
* *
* NOTE: The first few GPIOs also have direct INTC hookups in addition * NOTE: The first few GPIOs also have direct INTC hookups in addition
* to their GPIOBNK0 irq, with a bit less overhead but less flexibility * to their GPIOBNK0 irq, with a bit less overhead.
* on triggering (e.g. no edge options). We don't try to use those.
* *
* All those INTC hookups (direct, plus several IRQ banks) can also * All those INTC hookups (direct, plus several IRQ banks) can also
* serve as EDMA event triggers. * serve as EDMA event triggers.
...@@ -171,7 +171,7 @@ pure_initcall(davinci_gpio_setup); ...@@ -171,7 +171,7 @@ pure_initcall(davinci_gpio_setup);
static void gpio_irq_disable(unsigned irq) static void gpio_irq_disable(unsigned irq)
{ {
struct gpio_controller *__iomem g = get_irq_chip_data(irq); struct gpio_controller *__iomem g = get_irq_chip_data(irq);
u32 mask = __gpio_mask(irq_to_gpio(irq)); u32 mask = (u32) get_irq_data(irq);
__raw_writel(mask, &g->clr_falling); __raw_writel(mask, &g->clr_falling);
__raw_writel(mask, &g->clr_rising); __raw_writel(mask, &g->clr_rising);
...@@ -180,7 +180,7 @@ static void gpio_irq_disable(unsigned irq) ...@@ -180,7 +180,7 @@ static void gpio_irq_disable(unsigned irq)
static void gpio_irq_enable(unsigned irq) static void gpio_irq_enable(unsigned irq)
{ {
struct gpio_controller *__iomem g = get_irq_chip_data(irq); struct gpio_controller *__iomem g = get_irq_chip_data(irq);
u32 mask = __gpio_mask(irq_to_gpio(irq)); u32 mask = (u32) get_irq_data(irq);
unsigned status = irq_desc[irq].status; unsigned status = irq_desc[irq].status;
status &= IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING; status &= IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING;
...@@ -196,7 +196,7 @@ static void gpio_irq_enable(unsigned irq) ...@@ -196,7 +196,7 @@ static void gpio_irq_enable(unsigned irq)
static int gpio_irq_type(unsigned irq, unsigned trigger) static int gpio_irq_type(unsigned irq, unsigned trigger)
{ {
struct gpio_controller *__iomem g = get_irq_chip_data(irq); struct gpio_controller *__iomem g = get_irq_chip_data(irq);
u32 mask = __gpio_mask(irq_to_gpio(irq)); u32 mask = (u32) get_irq_data(irq);
if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
return -EINVAL; return -EINVAL;
...@@ -260,6 +260,45 @@ gpio_irq_handler(unsigned irq, struct irq_desc *desc) ...@@ -260,6 +260,45 @@ gpio_irq_handler(unsigned irq, struct irq_desc *desc)
/* now it may re-trigger */ /* now it may re-trigger */
} }
static int gpio_to_irq_banked(struct gpio_chip *chip, unsigned offset)
{
struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip);
if (d->irq_base >= 0)
return d->irq_base + offset;
else
return -ENODEV;
}
static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset)
{
struct davinci_soc_info *soc_info = &davinci_soc_info;
/* NOTE: we assume for now that only irqs in the first gpio_chip
* can provide direct-mapped IRQs to AINTC (up to 32 GPIOs).
*/
if (offset < soc_info->gpio_unbanked)
return soc_info->gpio_irq + offset;
else
return -ENODEV;
}
static int gpio_irq_type_unbanked(unsigned irq, unsigned trigger)
{
struct gpio_controller *__iomem g = get_irq_chip_data(irq);
u32 mask = (u32) get_irq_data(irq);
if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
return -EINVAL;
__raw_writel(mask, (trigger & IRQ_TYPE_EDGE_FALLING)
? &g->set_falling : &g->clr_falling);
__raw_writel(mask, (trigger & IRQ_TYPE_EDGE_RISING)
? &g->set_rising : &g->clr_rising);
return 0;
}
/* /*
* NOTE: for suspend/resume, probably best to make a platform_device with * NOTE: for suspend/resume, probably best to make a platform_device with
* suspend_late/resume_resume calls hooking into results of the set_wake() * suspend_late/resume_resume calls hooking into results of the set_wake()
...@@ -275,6 +314,7 @@ static int __init davinci_gpio_irq_setup(void) ...@@ -275,6 +314,7 @@ static int __init davinci_gpio_irq_setup(void)
u32 binten = 0; u32 binten = 0;
unsigned ngpio, bank_irq; unsigned ngpio, bank_irq;
struct davinci_soc_info *soc_info = &davinci_soc_info; struct davinci_soc_info *soc_info = &davinci_soc_info;
struct gpio_controller *__iomem g;
ngpio = soc_info->gpio_num; ngpio = soc_info->gpio_num;
...@@ -292,12 +332,63 @@ static int __init davinci_gpio_irq_setup(void) ...@@ -292,12 +332,63 @@ static int __init davinci_gpio_irq_setup(void)
} }
clk_enable(clk); clk_enable(clk);
/* Arrange gpio_to_irq() support, handling either direct IRQs or
* banked IRQs. Having GPIOs in the first GPIO bank use direct
* IRQs, while the others use banked IRQs, would need some setup
* tweaks to recognize hardware which can do that.
*/
for (gpio = 0, bank = 0; gpio < ngpio; bank++, gpio += 32) {
chips[bank].chip.to_irq = gpio_to_irq_banked;
chips[bank].irq_base = soc_info->gpio_unbanked
? -EINVAL
: (soc_info->intc_irq_num + gpio);
}
/*
* AINTC can handle direct/unbanked IRQs for GPIOs, with the GPIO
* controller only handling trigger modes. We currently assume no
* IRQ mux conflicts; gpio_irq_type_unbanked() is only for GPIOs.
*/
if (soc_info->gpio_unbanked) {
static struct irq_chip gpio_irqchip_unbanked;
/* pass "bank 0" GPIO IRQs to AINTC */
chips[0].chip.to_irq = gpio_to_irq_unbanked;
binten = BIT(0);
/* AINTC handles mask/unmask; GPIO handles triggering */
irq = bank_irq;
gpio_irqchip_unbanked = *get_irq_desc_chip(irq_to_desc(irq));
gpio_irqchip_unbanked.name = "GPIO-AINTC";
gpio_irqchip_unbanked.set_type = gpio_irq_type_unbanked;
/* default trigger: both edges */
g = gpio2controller(0);
__raw_writel(~0, &g->set_falling);
__raw_writel(~0, &g->set_rising);
/* set the direct IRQs up to use that irqchip */
for (gpio = 0; gpio < soc_info->gpio_unbanked; gpio++, irq++) {
set_irq_chip(irq, &gpio_irqchip_unbanked);
set_irq_data(irq, (void *) __gpio_mask(gpio));
set_irq_chip_data(irq, g);
irq_desc[irq].status |= IRQ_TYPE_EDGE_BOTH;
}
goto done;
}
/*
* Or, AINTC can handle IRQs for banks of 16 GPIO IRQs, which we
* then chain through our own handler.
*/
for (gpio = 0, irq = gpio_to_irq(0), bank = 0; for (gpio = 0, irq = gpio_to_irq(0), bank = 0;
gpio < ngpio; gpio < ngpio;
bank++, bank_irq++) { bank++, bank_irq++) {
struct gpio_controller *__iomem g = gpio2controller(gpio);
unsigned i; unsigned i;
/* disabled by default, enabled only as needed */
g = gpio2controller(gpio);
__raw_writel(~0, &g->clr_falling); __raw_writel(~0, &g->clr_falling);
__raw_writel(~0, &g->clr_rising); __raw_writel(~0, &g->clr_rising);
...@@ -309,6 +400,7 @@ static int __init davinci_gpio_irq_setup(void) ...@@ -309,6 +400,7 @@ static int __init davinci_gpio_irq_setup(void)
for (i = 0; i < 16 && gpio < ngpio; i++, irq++, gpio++) { for (i = 0; i < 16 && gpio < ngpio; i++, irq++, gpio++) {
set_irq_chip(irq, &gpio_irqchip); set_irq_chip(irq, &gpio_irqchip);
set_irq_chip_data(irq, g); set_irq_chip_data(irq, g);
set_irq_data(irq, (void *) __gpio_mask(gpio));
set_irq_handler(irq, handle_simple_irq); set_irq_handler(irq, handle_simple_irq);
set_irq_flags(irq, IRQF_VALID); set_irq_flags(irq, IRQF_VALID);
} }
...@@ -316,6 +408,7 @@ static int __init davinci_gpio_irq_setup(void) ...@@ -316,6 +408,7 @@ static int __init davinci_gpio_irq_setup(void)
binten |= BIT(bank); binten |= BIT(bank);
} }
done:
/* BINTEN -- per-bank interrupt enable. genirq would also let these /* BINTEN -- per-bank interrupt enable. genirq would also let these
* bits be set/cleared dynamically. * bits be set/cleared dynamically.
*/ */
......
...@@ -63,6 +63,7 @@ struct davinci_soc_info { ...@@ -63,6 +63,7 @@ struct davinci_soc_info {
void __iomem *gpio_base; void __iomem *gpio_base;
unsigned gpio_num; unsigned gpio_num;
unsigned gpio_irq; unsigned gpio_irq;
unsigned gpio_unbanked;
struct platform_device *serial_dev; struct platform_device *serial_dev;
struct emac_platform_data *emac_pdata; struct emac_platform_data *emac_pdata;
dma_addr_t sram_dma; dma_addr_t sram_dma;
......
...@@ -142,15 +142,13 @@ static inline int gpio_cansleep(unsigned gpio) ...@@ -142,15 +142,13 @@ static inline int gpio_cansleep(unsigned gpio)
static inline int gpio_to_irq(unsigned gpio) static inline int gpio_to_irq(unsigned gpio)
{ {
if (gpio >= DAVINCI_N_GPIO) return __gpio_to_irq(gpio);
return -EINVAL;
return davinci_soc_info.intc_irq_num + gpio;
} }
static inline int irq_to_gpio(unsigned irq) static inline int irq_to_gpio(unsigned irq)
{ {
/* caller guarantees gpio_to_irq() succeeded */ /* don't support the reverse mapping */
return irq - davinci_soc_info.intc_irq_num; return -ENOSYS;
} }
#endif /* __DAVINCI_GPIO_H */ #endif /* __DAVINCI_GPIO_H */
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