mxs-sparse-irq

The series adds irqdomain support for mach-mxs and then enables
 sparse-irq.  It dependes on pull request mxs-dt-3.7.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.11 (GNU/Linux)
 
 iQEcBAABAgAGBQJQTtHGAAoJEFBXWFqHsHzOLZ4H/2soWxo3WGDj7918e6APZK98
 sVFJbDgkDgcJ+h33jdt6DwWbi435R7IaTEFP1RpL8eaxUX6yapLnu8tRjyNvAuXu
 Igp9+eRaedAlc7rQxbdBG4ge3s1Qb4teGOgWwaNp2cqsaYQ9sk1jCE7aSOVwPPNx
 URJkEAjVGfWX/hnRa7dKYfg6hBA7+Ht0vFHEi/2pW1CXGz5jo12HzRwxK4E4iOIK
 qkRZX0FUOeRAdCJGsA6XehHkjDkTH8db/faMltIpzX6WcVujz+Z0+iMkuHSe2RJN
 PVo0bungpwuWsScVSaAydGQ1QBgfoZPf9iITI89Yspw6qGE24lJMD92MQ0i3jxE=
 =JZGL
 -----END PGP SIGNATURE-----

Merge tag 'mxs-sparse-irq' of git://git.linaro.org/people/shawnguo/linux-2.6 into next/soc2

The series adds irqdomain support for mach-mxs and then enables
sparse-irq.  It dependes on pull request mxs-dt-3.7.

* tag 'mxs-sparse-irq' of git://git.linaro.org/people/shawnguo/linux-2.6:
  ARM: mxs: remove mach/irqs.h
  ARM: mxs: select SPARSE_IRQ
  ARM: mxs: adopt irq_domain support for icoll driver
  ARM: mxs: select MULTI_IRQ_HANDLER
  ARM: mxs: retrieve timer irq from device tree
  gpio/mxs: adopt irq_domain support for mxs gpio driver
This commit is contained in:
Olof Johansson 2012-09-12 22:54:16 -07:00
commit 36246a8200
12 changed files with 112 additions and 137 deletions

View File

@ -489,7 +489,9 @@ config ARCH_MXS
select CLKSRC_MMIO
select COMMON_CLK
select HAVE_CLK_PREPARE
select MULTI_IRQ_HANDLER
select PINCTRL
select SPARSE_IRQ
select USE_OF
help
Support for Freescale MXS-based family of processors

View File

@ -43,7 +43,7 @@ apbh@80000000 {
ranges;
icoll: interrupt-controller@80000000 {
compatible = "fsl,imx23-icoll", "fsl,mxs-icoll";
compatible = "fsl,imx23-icoll", "fsl,icoll";
interrupt-controller;
#interrupt-cells = <1>;
reg = <0x80000000 0x2000>;
@ -389,8 +389,9 @@ pwm: pwm@80064000 {
};
timrot@80068000 {
compatible = "fsl,imx23-timrot", "fsl,timrot";
reg = <0x80068000 0x2000>;
status = "disabled";
interrupts = <28 29 30 31>;
};
auart0: serial@8006c000 {

View File

@ -50,7 +50,7 @@ apbh@80000000 {
ranges;
icoll: interrupt-controller@80000000 {
compatible = "fsl,imx28-icoll", "fsl,mxs-icoll";
compatible = "fsl,imx28-icoll", "fsl,icoll";
interrupt-controller;
#interrupt-cells = <1>;
reg = <0x80000000 0x2000>;
@ -683,8 +683,9 @@ pwm: pwm@80064000 {
};
timrot@80068000 {
compatible = "fsl,imx28-timrot", "fsl,timrot";
reg = <0x80068000 0x2000>;
status = "disabled";
interrupts = <48 49 50 51>;
};
auart0: serial@8006a000 {

View File

@ -19,20 +19,27 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <asm/exception.h>
#include <mach/mxs.h>
#include <mach/common.h>
#define HW_ICOLL_VECTOR 0x0000
#define HW_ICOLL_LEVELACK 0x0010
#define HW_ICOLL_CTRL 0x0020
#define HW_ICOLL_STAT_OFFSET 0x0070
#define HW_ICOLL_INTERRUPTn_SET(n) (0x0124 + (n) * 0x10)
#define HW_ICOLL_INTERRUPTn_CLR(n) (0x0128 + (n) * 0x10)
#define BM_ICOLL_INTERRUPTn_ENABLE 0x00000004
#define BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0 0x1
#define ICOLL_NUM_IRQS 128
static void __iomem *icoll_base = MXS_IO_ADDRESS(MXS_ICOLL_BASE_ADDR);
static struct irq_domain *icoll_domain;
static void icoll_ack_irq(struct irq_data *d)
{
@ -48,13 +55,13 @@ static void icoll_ack_irq(struct irq_data *d)
static void icoll_mask_irq(struct irq_data *d)
{
__raw_writel(BM_ICOLL_INTERRUPTn_ENABLE,
icoll_base + HW_ICOLL_INTERRUPTn_CLR(d->irq));
icoll_base + HW_ICOLL_INTERRUPTn_CLR(d->hwirq));
}
static void icoll_unmask_irq(struct irq_data *d)
{
__raw_writel(BM_ICOLL_INTERRUPTn_ENABLE,
icoll_base + HW_ICOLL_INTERRUPTn_SET(d->irq));
icoll_base + HW_ICOLL_INTERRUPTn_SET(d->hwirq));
}
static struct irq_chip mxs_icoll_chip = {
@ -63,18 +70,56 @@ static struct irq_chip mxs_icoll_chip = {
.irq_unmask = icoll_unmask_irq,
};
void __init icoll_init_irq(void)
asmlinkage void __exception_irq_entry icoll_handle_irq(struct pt_regs *regs)
{
int i;
u32 irqnr;
do {
irqnr = __raw_readl(icoll_base + HW_ICOLL_STAT_OFFSET);
if (irqnr != 0x7f) {
__raw_writel(irqnr, icoll_base + HW_ICOLL_VECTOR);
irqnr = irq_find_mapping(icoll_domain, irqnr);
handle_IRQ(irqnr, regs);
continue;
}
break;
} while (1);
}
static int icoll_irq_domain_map(struct irq_domain *d, unsigned int virq,
irq_hw_number_t hw)
{
irq_set_chip_and_handler(virq, &mxs_icoll_chip, handle_level_irq);
set_irq_flags(virq, IRQF_VALID);
return 0;
}
static struct irq_domain_ops icoll_irq_domain_ops = {
.map = icoll_irq_domain_map,
.xlate = irq_domain_xlate_onecell,
};
void __init icoll_of_init(struct device_node *np,
struct device_node *interrupt_parent)
{
/*
* Interrupt Collector reset, which initializes the priority
* for each irq to level 0.
*/
mxs_reset_block(icoll_base + HW_ICOLL_CTRL);
for (i = 0; i < MXS_INTERNAL_IRQS; i++) {
irq_set_chip_and_handler(i, &mxs_icoll_chip, handle_level_irq);
set_irq_flags(i, IRQF_VALID);
}
icoll_domain = irq_domain_add_linear(np, ICOLL_NUM_IRQS,
&icoll_irq_domain_ops, NULL);
WARN_ON(!icoll_domain);
}
static const struct of_device_id icoll_of_match[] __initconst = {
{.compatible = "fsl,icoll", .data = icoll_of_init},
{ /* sentinel */ }
};
void __init icoll_init_irq(void)
{
of_irq_init(icoll_of_match);
}

View File

@ -13,7 +13,7 @@
extern const u32 *mxs_get_ocotp(void);
extern int mxs_reset_block(void __iomem *);
extern void mxs_timer_init(int);
extern void mxs_timer_init(void);
extern void mxs_restart(char, const char *);
extern int mxs_saif_clkmux_select(unsigned int clkmux);
@ -28,6 +28,7 @@ extern void mx28_map_io(void);
extern void mx28_init_irq(void);
extern void icoll_init_irq(void);
extern void icoll_handle_irq(struct pt_regs *);
extern struct platform_device *mxs_add_dma(const char *devid,
resource_size_t base);

View File

@ -1,35 +0,0 @@
/*
* Low-level IRQ helper macros for Freescale MXS-based
*
* Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <mach/mxs.h>
#define MXS_ICOLL_VBASE MXS_IO_ADDRESS(MXS_ICOLL_BASE_ADDR)
#define HW_ICOLL_STAT_OFFSET 0x70
.macro get_irqnr_and_base, irqnr, irqstat, base, tmp
ldr \irqnr, [\base, #HW_ICOLL_STAT_OFFSET]
cmp \irqnr, #0x7F
strne \irqnr, [\base]
moveqs \irqnr, #0
.endm
.macro get_irqnr_preamble, base, tmp
ldr \base, =MXS_ICOLL_VBASE
.endm

View File

@ -1,32 +0,0 @@
/*
* Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __MACH_MXS_IRQS_H__
#define __MACH_MXS_IRQS_H__
#define MXS_INTERNAL_IRQS 128
#define MXS_GPIO_IRQ_START MXS_INTERNAL_IRQS
/* the maximum for MXS-based */
#define MXS_GPIO_IRQS (32 * 5)
/*
* The next 16 interrupts are for board specific purposes. Since
* the kernel can only run on one machine at a time, we can re-use
* these. If you need more, increase MXS_BOARD_IRQS, but keep it
* within sensible limits.
*/
#define MXS_BOARD_IRQ_START (MXS_GPIO_IRQ_START + MXS_GPIO_IRQS)
#define MXS_BOARD_IRQS 16
#define NR_IRQS (MXS_BOARD_IRQ_START + MXS_BOARD_IRQS)
#endif /* __MACH_MXS_IRQS_H__ */

View File

@ -15,10 +15,8 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/init.h>
#include <linux/irqdomain.h>
#include <linux/micrel_phy.h>
#include <linux/mxsfb.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/phy.h>
#include <asm/mach/arch.h>
@ -105,37 +103,6 @@ static struct of_dev_auxdata mxs_auxdata_lookup[] __initdata = {
{ /* sentinel */ }
};
static int __init mxs_icoll_add_irq_domain(struct device_node *np,
struct device_node *interrupt_parent)
{
irq_domain_add_legacy(np, 128, 0, 0, &irq_domain_simple_ops, NULL);
return 0;
}
static int __init mxs_gpio_add_irq_domain(struct device_node *np,
struct device_node *interrupt_parent)
{
static int gpio_irq_base = MXS_GPIO_IRQ_START;
irq_domain_add_legacy(np, 32, gpio_irq_base, 0, &irq_domain_simple_ops, NULL);
gpio_irq_base += 32;
return 0;
}
static const struct of_device_id mxs_irq_match[] __initconst = {
{ .compatible = "fsl,mxs-icoll", .data = mxs_icoll_add_irq_domain, },
{ .compatible = "fsl,mxs-gpio", .data = mxs_gpio_add_irq_domain, },
{ /* sentinel */ }
};
static void __init mxs_dt_init_irq(void)
{
icoll_init_irq();
of_irq_init(mxs_irq_match);
}
static void __init imx23_timer_init(void)
{
mx23_clocks_init();
@ -305,7 +272,8 @@ static const char *imx28_dt_compat[] __initdata = {
DT_MACHINE_START(IMX23, "Freescale i.MX23 (Device Tree)")
.map_io = mx23_map_io,
.init_irq = mxs_dt_init_irq,
.init_irq = icoll_init_irq,
.handle_irq = icoll_handle_irq,
.timer = &imx23_timer,
.init_machine = mxs_machine_init,
.dt_compat = imx23_dt_compat,
@ -314,7 +282,8 @@ MACHINE_END
DT_MACHINE_START(IMX28, "Freescale i.MX28 (Device Tree)")
.map_io = mx28_map_io,
.init_irq = mxs_dt_init_irq,
.init_irq = icoll_init_irq,
.handle_irq = icoll_handle_irq,
.timer = &imx28_timer,
.init_machine = mxs_machine_init,
.dt_compat = imx28_dt_compat,

View File

@ -25,6 +25,8 @@
#include <linux/irq.h>
#include <linux/clockchips.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <asm/mach/time.h>
#include <mach/mxs.h>
@ -244,9 +246,17 @@ static int __init mxs_clocksource_init(struct clk *timer_clk)
return 0;
}
void __init mxs_timer_init(int irq)
void __init mxs_timer_init(void)
{
struct device_node *np;
struct clk *timer_clk;
int irq;
np = of_find_compatible_node(NULL, NULL, "fsl,timrot");
if (!np) {
pr_err("%s: failed find timrot node\n", __func__);
return;
}
timer_clk = clk_get_sys("timrot", NULL);
if (IS_ERR(timer_clk)) {
@ -295,5 +305,6 @@ void __init mxs_timer_init(int irq)
mxs_clockevent_init(timer_clk);
/* Make irqs happen */
irq = irq_of_parse_and_map(np, 0);
setup_irq(irq, &mxs_timer_irq);
}

View File

@ -200,7 +200,7 @@ int __init mx23_clocks_init(void)
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
clk_prepare_enable(clks[clks_init_on[i]]);
mxs_timer_init(MX23_INT_TIMER0);
mxs_timer_init();
return 0;
}

View File

@ -337,7 +337,7 @@ int __init mx28_clocks_init(void)
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
clk_prepare_enable(clks[clks_init_on[i]]);
mxs_timer_init(MX28_INT_TIMER0);
mxs_timer_init();
return 0;
}

View File

@ -24,6 +24,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_address.h>
@ -52,8 +53,6 @@
#define GPIO_INT_LEV_MASK (1 << 0)
#define GPIO_INT_POL_MASK (1 << 1)
#define irq_to_gpio(irq) ((irq) - MXS_GPIO_IRQ_START)
enum mxs_gpio_id {
IMX23_GPIO,
IMX28_GPIO,
@ -63,7 +62,7 @@ struct mxs_gpio_port {
void __iomem *base;
int id;
int irq;
int virtual_irq_start;
struct irq_domain *domain;
struct bgpio_chip bgc;
enum mxs_gpio_id devid;
};
@ -82,8 +81,7 @@ static inline int is_imx28_gpio(struct mxs_gpio_port *port)
static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
{
u32 gpio = irq_to_gpio(d->irq);
u32 pin_mask = 1 << (gpio & 31);
u32 pin_mask = 1 << d->hwirq;
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct mxs_gpio_port *port = gc->private;
void __iomem *pin_addr;
@ -120,7 +118,7 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
else
writel(pin_mask, pin_addr + MXS_CLR);
writel(1 << (gpio & 0x1f),
writel(pin_mask,
port->base + PINCTRL_IRQSTAT(port) + MXS_CLR);
return 0;
@ -131,7 +129,6 @@ static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc)
{
u32 irq_stat;
struct mxs_gpio_port *port = irq_get_handler_data(irq);
u32 gpio_irq_no_base = port->virtual_irq_start;
desc->irq_data.chip->irq_ack(&desc->irq_data);
@ -140,7 +137,7 @@ static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc)
while (irq_stat != 0) {
int irqoffset = fls(irq_stat) - 1;
generic_handle_irq(gpio_irq_no_base + irqoffset);
generic_handle_irq(irq_find_mapping(port->domain, irqoffset));
irq_stat &= ~(1 << irqoffset);
}
}
@ -167,12 +164,12 @@ static int mxs_gpio_set_wake_irq(struct irq_data *d, unsigned int enable)
return 0;
}
static void __init mxs_gpio_init_gc(struct mxs_gpio_port *port)
static void __init mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base)
{
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
gc = irq_alloc_generic_chip("gpio-mxs", 1, port->virtual_irq_start,
gc = irq_alloc_generic_chip("gpio-mxs", 1, irq_base,
port->base, handle_level_irq);
gc->private = port;
@ -194,7 +191,7 @@ static int mxs_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
struct mxs_gpio_port *port =
container_of(bgc, struct mxs_gpio_port, bgc);
return port->virtual_irq_start + offset;
return irq_find_mapping(port->domain, offset);
}
static struct platform_device_id mxs_gpio_ids[] = {
@ -226,6 +223,7 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev)
static void __iomem *base;
struct mxs_gpio_port *port;
struct resource *iores = NULL;
int irq_base;
int err;
port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
@ -241,7 +239,6 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev)
port->id = pdev->id;
port->devid = pdev->id_entry->driver_data;
}
port->virtual_irq_start = MXS_GPIO_IRQ_START + port->id * 32;
port->irq = platform_get_irq(pdev, 0);
if (port->irq < 0)
@ -275,8 +272,19 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev)
/* clear address has to be used to clear IRQSTAT bits */
writel(~0U, port->base + PINCTRL_IRQSTAT(port) + MXS_CLR);
irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id());
if (irq_base < 0)
return irq_base;
port->domain = irq_domain_add_legacy(np, 32, irq_base, 0,
&irq_domain_simple_ops, NULL);
if (!port->domain) {
err = -ENODEV;
goto out_irqdesc_free;
}
/* gpio-mxs can be a generic irq chip */
mxs_gpio_init_gc(port);
mxs_gpio_init_gc(port, irq_base);
/* setup one handler for each entry */
irq_set_chained_handler(port->irq, mxs_gpio_irq_handler);
@ -287,18 +295,22 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev)
port->base + PINCTRL_DOUT(port), NULL,
port->base + PINCTRL_DOE(port), NULL, 0);
if (err)
return err;
goto out_irqdesc_free;
port->bgc.gc.to_irq = mxs_gpio_to_irq;
port->bgc.gc.base = port->id * 32;
err = gpiochip_add(&port->bgc.gc);
if (err) {
bgpio_remove(&port->bgc);
return err;
}
if (err)
goto out_bgpio_remove;
return 0;
out_bgpio_remove:
bgpio_remove(&port->bgc);
out_irqdesc_free:
irq_free_descs(irq_base, 32);
return err;
}
static struct platform_driver mxs_gpio_driver = {