Merge branch 'next/soc2' into HEAD

This commit is contained in:
Olof Johansson 2012-10-01 14:26:04 -07:00
commit 5c008d7029
12 changed files with 112 additions and 137 deletions

View File

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

View File

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

View File

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

View File

@ -19,20 +19,27 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <asm/exception.h>
#include <mach/mxs.h> #include <mach/mxs.h>
#include <mach/common.h> #include <mach/common.h>
#define HW_ICOLL_VECTOR 0x0000 #define HW_ICOLL_VECTOR 0x0000
#define HW_ICOLL_LEVELACK 0x0010 #define HW_ICOLL_LEVELACK 0x0010
#define HW_ICOLL_CTRL 0x0020 #define HW_ICOLL_CTRL 0x0020
#define HW_ICOLL_STAT_OFFSET 0x0070
#define HW_ICOLL_INTERRUPTn_SET(n) (0x0124 + (n) * 0x10) #define HW_ICOLL_INTERRUPTn_SET(n) (0x0124 + (n) * 0x10)
#define HW_ICOLL_INTERRUPTn_CLR(n) (0x0128 + (n) * 0x10) #define HW_ICOLL_INTERRUPTn_CLR(n) (0x0128 + (n) * 0x10)
#define BM_ICOLL_INTERRUPTn_ENABLE 0x00000004 #define BM_ICOLL_INTERRUPTn_ENABLE 0x00000004
#define BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0 0x1 #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 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) 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) static void icoll_mask_irq(struct irq_data *d)
{ {
__raw_writel(BM_ICOLL_INTERRUPTn_ENABLE, __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) static void icoll_unmask_irq(struct irq_data *d)
{ {
__raw_writel(BM_ICOLL_INTERRUPTn_ENABLE, __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 = { static struct irq_chip mxs_icoll_chip = {
@ -63,18 +70,56 @@ static struct irq_chip mxs_icoll_chip = {
.irq_unmask = icoll_unmask_irq, .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 * Interrupt Collector reset, which initializes the priority
* for each irq to level 0. * for each irq to level 0.
*/ */
mxs_reset_block(icoll_base + HW_ICOLL_CTRL); mxs_reset_block(icoll_base + HW_ICOLL_CTRL);
for (i = 0; i < MXS_INTERNAL_IRQS; i++) { icoll_domain = irq_domain_add_linear(np, ICOLL_NUM_IRQS,
irq_set_chip_and_handler(i, &mxs_icoll_chip, handle_level_irq); &icoll_irq_domain_ops, NULL);
set_irq_flags(i, IRQF_VALID); 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 const u32 *mxs_get_ocotp(void);
extern int mxs_reset_block(void __iomem *); 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 void mxs_restart(char, const char *);
extern int mxs_saif_clkmux_select(unsigned int clkmux); extern int mxs_saif_clkmux_select(unsigned int clkmux);
@ -24,5 +24,6 @@ extern int mx28_clocks_init(void);
extern void mx28_map_io(void); extern void mx28_map_io(void);
extern void icoll_init_irq(void); extern void icoll_init_irq(void);
extern void icoll_handle_irq(struct pt_regs *);
#endif /* __MACH_MXS_COMMON_H__ */ #endif /* __MACH_MXS_COMMON_H__ */

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

@ -17,10 +17,8 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/irqdomain.h>
#include <linux/micrel_phy.h> #include <linux/micrel_phy.h>
#include <linux/mxsfb.h> #include <linux/mxsfb.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/phy.h> #include <linux/phy.h>
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
@ -141,37 +139,6 @@ static struct of_dev_auxdata mxs_auxdata_lookup[] __initdata = {
{ /* sentinel */ } { /* 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) static void __init imx23_timer_init(void)
{ {
mx23_clocks_init(); mx23_clocks_init();
@ -421,7 +388,8 @@ static const char *imx28_dt_compat[] __initdata = {
DT_MACHINE_START(IMX23, "Freescale i.MX23 (Device Tree)") DT_MACHINE_START(IMX23, "Freescale i.MX23 (Device Tree)")
.map_io = mx23_map_io, .map_io = mx23_map_io,
.init_irq = mxs_dt_init_irq, .init_irq = icoll_init_irq,
.handle_irq = icoll_handle_irq,
.timer = &imx23_timer, .timer = &imx23_timer,
.init_machine = mxs_machine_init, .init_machine = mxs_machine_init,
.dt_compat = imx23_dt_compat, .dt_compat = imx23_dt_compat,
@ -430,7 +398,8 @@ MACHINE_END
DT_MACHINE_START(IMX28, "Freescale i.MX28 (Device Tree)") DT_MACHINE_START(IMX28, "Freescale i.MX28 (Device Tree)")
.map_io = mx28_map_io, .map_io = mx28_map_io,
.init_irq = mxs_dt_init_irq, .init_irq = icoll_init_irq,
.handle_irq = icoll_handle_irq,
.timer = &imx28_timer, .timer = &imx28_timer,
.init_machine = mxs_machine_init, .init_machine = mxs_machine_init,
.dt_compat = imx28_dt_compat, .dt_compat = imx28_dt_compat,

View File

@ -25,6 +25,8 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/clockchips.h> #include <linux/clockchips.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <asm/mach/time.h> #include <asm/mach/time.h>
#include <mach/mxs.h> #include <mach/mxs.h>
@ -244,9 +246,17 @@ static int __init mxs_clocksource_init(struct clk *timer_clk)
return 0; return 0;
} }
void __init mxs_timer_init(int irq) void __init mxs_timer_init(void)
{ {
struct device_node *np;
struct clk *timer_clk; 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); timer_clk = clk_get_sys("timrot", NULL);
if (IS_ERR(timer_clk)) { if (IS_ERR(timer_clk)) {
@ -295,5 +305,6 @@ void __init mxs_timer_init(int irq)
mxs_clockevent_init(timer_clk); mxs_clockevent_init(timer_clk);
/* Make irqs happen */ /* Make irqs happen */
irq = irq_of_parse_and_map(np, 0);
setup_irq(irq, &mxs_timer_irq); setup_irq(irq, &mxs_timer_irq);
} }

View File

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

View File

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

View File

@ -24,6 +24,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
@ -52,8 +53,6 @@
#define GPIO_INT_LEV_MASK (1 << 0) #define GPIO_INT_LEV_MASK (1 << 0)
#define GPIO_INT_POL_MASK (1 << 1) #define GPIO_INT_POL_MASK (1 << 1)
#define irq_to_gpio(irq) ((irq) - MXS_GPIO_IRQ_START)
enum mxs_gpio_id { enum mxs_gpio_id {
IMX23_GPIO, IMX23_GPIO,
IMX28_GPIO, IMX28_GPIO,
@ -63,7 +62,7 @@ struct mxs_gpio_port {
void __iomem *base; void __iomem *base;
int id; int id;
int irq; int irq;
int virtual_irq_start; struct irq_domain *domain;
struct bgpio_chip bgc; struct bgpio_chip bgc;
enum mxs_gpio_id devid; 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) 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 << d->hwirq;
u32 pin_mask = 1 << (gpio & 31);
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct mxs_gpio_port *port = gc->private; struct mxs_gpio_port *port = gc->private;
void __iomem *pin_addr; void __iomem *pin_addr;
@ -120,7 +118,7 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
else else
writel(pin_mask, pin_addr + MXS_CLR); writel(pin_mask, pin_addr + MXS_CLR);
writel(1 << (gpio & 0x1f), writel(pin_mask,
port->base + PINCTRL_IRQSTAT(port) + MXS_CLR); port->base + PINCTRL_IRQSTAT(port) + MXS_CLR);
return 0; return 0;
@ -131,7 +129,6 @@ static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc)
{ {
u32 irq_stat; u32 irq_stat;
struct mxs_gpio_port *port = irq_get_handler_data(irq); 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); 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) { while (irq_stat != 0) {
int irqoffset = fls(irq_stat) - 1; 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); irq_stat &= ~(1 << irqoffset);
} }
} }
@ -167,12 +164,12 @@ static int mxs_gpio_set_wake_irq(struct irq_data *d, unsigned int enable)
return 0; 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_generic *gc;
struct irq_chip_type *ct; 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); port->base, handle_level_irq);
gc->private = port; gc->private = port;
@ -194,7 +191,7 @@ static int mxs_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
struct mxs_gpio_port *port = struct mxs_gpio_port *port =
container_of(bgc, struct mxs_gpio_port, bgc); 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[] = { 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; static void __iomem *base;
struct mxs_gpio_port *port; struct mxs_gpio_port *port;
struct resource *iores = NULL; struct resource *iores = NULL;
int irq_base;
int err; int err;
port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL); 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->id = pdev->id;
port->devid = pdev->id_entry->driver_data; 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); port->irq = platform_get_irq(pdev, 0);
if (port->irq < 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 */ /* clear address has to be used to clear IRQSTAT bits */
writel(~0U, port->base + PINCTRL_IRQSTAT(port) + MXS_CLR); 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 */ /* 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 */ /* setup one handler for each entry */
irq_set_chained_handler(port->irq, mxs_gpio_irq_handler); 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_DOUT(port), NULL,
port->base + PINCTRL_DOE(port), NULL, 0); port->base + PINCTRL_DOE(port), NULL, 0);
if (err) if (err)
return err; goto out_irqdesc_free;
port->bgc.gc.to_irq = mxs_gpio_to_irq; port->bgc.gc.to_irq = mxs_gpio_to_irq;
port->bgc.gc.base = port->id * 32; port->bgc.gc.base = port->id * 32;
err = gpiochip_add(&port->bgc.gc); err = gpiochip_add(&port->bgc.gc);
if (err) { if (err)
bgpio_remove(&port->bgc); goto out_bgpio_remove;
return err;
}
return 0; 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 = { static struct platform_driver mxs_gpio_driver = {