mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 19:51:31 -04:00
ARM: arm-soc cleanup for 3.10
Here is a collection of cleanup patches. Among the pieces that stand out are:
- The deletion of h720x platforms
- Split of at91 non-dt platforms to their own Kconfig file to keep them separate
- General cleanups and refactoring of i.MX and MXS platforms
- Some restructuring of clock tables for OMAP
- Convertion of PMC driver for Tegra to dt-only
- Some renames of sunxi -> sun4i (Allwinner A10)
- ... plus a bunch of other stuff that I haven't mentioned
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
iQIcBAABAgAGBQJRggUqAAoJEIwa5zzehBx3HjEQAJwp7heRs/HwTDzmzcyHkRMV
usbaa9dHBuAZ0DzsWjLK99xEn8VWD9TvbeP6hN5gNhxko06UVza3o8PI2iV1ztMB
9K3u2+LS5on/5cOxnsU1va16h5hBZ0ZIgNx5NY+PZ5mBY6v1U3qTjljPP62iXp63
w+sdXeZDe/c5JvuoDRbY0OBR++3Jp8cQg7KbU78jWz3r5D2rC1zwhkf2audcRY6b
jIWTj9M8CHynh/D6OzKqDcOYorBHNSRj0YbiWS2nnMfm+0V8nya00EPRpCPRiBUb
sobSy1CI9Qxiih3bOf6QCfzCRzJ5hbtE0zlI8g3bqtEZ1yOsE949HrKapWHJJdIU
JNTXrxXORAnaRhbzvSPNpp/iJBSDQRsfEETgv5BuHg/4lzTQfzElySbcgb4EeoHr
7Zt8ZR2/Du+u76qIPqs19ES3Wx+nOEOfSDAgZmlfPvlwmlGDYvqAXoeJ006VXnhG
JacLuD/cFnJ1w00Bcl48ZXMIsVkoRqjvsCG5q688HGXMM1lU8DfgUpQY6OCWAbdu
kFnBinJZk+HbE8FGS8O0BoQ+oiC0YIr2XhATL66PGHq7bLHb5ycwvZ7mrfC0AN9j
M9hqTFednwfo9wF8vSj5nMsxXwP8/mky4ECGoFvLsMYDosunrNVnAHtTgDSE+ZgO
6kQJ1P8jBBXn2LyjF88W
=xCAx
-----END PGP SIGNATURE-----
Merge tag 'cleanup-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC cleanup from Olof Johansson:
"Here is a collection of cleanup patches. Among the pieces that stand
out are:
- The deletion of h720x platforms
- Split of at91 non-dt platforms to their own Kconfig file to keep
them separate
- General cleanups and refactoring of i.MX and MXS platforms
- Some restructuring of clock tables for OMAP
- Convertion of PMC driver for Tegra to dt-only
- Some renames of sunxi -> sun4i (Allwinner A10)
- ... plus a bunch of other stuff that I haven't mentioned"
* tag 'cleanup-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (119 commits)
ARM: i.MX: remove unused ARCH_* configs
ARM i.MX53: remove platform ahci support
ARM: sunxi: Rework the restart code
irqchip: sunxi: Rename sunxi to sun4i
irqchip: sunxi: Make use of the IRQCHIP_DECLARE macro
clocksource: sunxi: Rename sunxi to sun4i
clocksource: sunxi: make use of CLKSRC_OF
clocksource: sunxi: Cleanup the timer code
ARM: at91: remove trailing semicolon from macros
ARM: at91/setup: fix trivial typos
ARM: EXYNOS: remove "config EXYNOS_DEV_DRM"
ARM: EXYNOS: change the name of USB ohci header
ARM: SAMSUNG: Remove unnecessary code for dma
ARM: S3C24XX: Remove unused GPIO drive strength register definitions
ARM: OMAP4+: PM: Restore CPU power state to ON with clockdomain force wakeup method
ARM: S3C24XX: Removed unneeded dependency on CPU_S3C2412
ARM: S3C24XX: Removed unneeded dependency on CPU_S3C2410
ARM: S3C24XX: Removed unneeded dependency on ARCH_S3C24XX for boards
ARM: SAMSUNG: Fix typo "CONFIG_SAMSUNG_DEV_RTC"
ARM: S5P64X0: Fix typo "CONFIG_S5P64X0_SETUP_SDHCI"
...
This commit is contained in:
commit
a7726350e0
263 changed files with 2919 additions and 6559 deletions
|
|
@ -2,9 +2,10 @@ obj-$(CONFIG_IRQCHIP) += irqchip.o
|
|||
|
||||
obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o
|
||||
obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o
|
||||
obj-$(CONFIG_ARCH_MXS) += irq-mxs.o
|
||||
obj-$(CONFIG_METAG) += irq-metag-ext.o
|
||||
obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o
|
||||
obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi.o
|
||||
obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o
|
||||
obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o
|
||||
obj-$(CONFIG_ARM_GIC) += irq-gic.o
|
||||
obj-$(CONFIG_ARM_VIC) += irq-vic.o
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <asm/mach/irq.h>
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/cpu_pm.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/io.h>
|
||||
|
|
@ -38,12 +39,12 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqchip/arm-gic.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/exception.h>
|
||||
#include <asm/smp_plat.h>
|
||||
#include <asm/mach/irq.h>
|
||||
|
||||
#include "irqchip.h"
|
||||
|
||||
|
|
@ -127,7 +128,7 @@ static inline void gic_set_base_accessor(struct gic_chip_data *data,
|
|||
#else
|
||||
#define gic_data_dist_base(d) ((d)->dist_base.common_base)
|
||||
#define gic_data_cpu_base(d) ((d)->cpu_base.common_base)
|
||||
#define gic_set_base_accessor(d,f)
|
||||
#define gic_set_base_accessor(d, f)
|
||||
#endif
|
||||
|
||||
static inline void __iomem *gic_dist_base(struct irq_data *d)
|
||||
|
|
@ -324,7 +325,7 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
|
|||
|
||||
cascade_irq = irq_find_mapping(chip_data->domain, gic_irq);
|
||||
if (unlikely(gic_irq < 32 || gic_irq > 1020))
|
||||
do_bad_IRQ(cascade_irq, desc);
|
||||
handle_bad_irq(cascade_irq, desc);
|
||||
else
|
||||
generic_handle_irq(cascade_irq);
|
||||
|
||||
|
|
@ -700,6 +701,25 @@ static int gic_irq_domain_xlate(struct irq_domain *d,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static int __cpuinit gic_secondary_init(struct notifier_block *nfb,
|
||||
unsigned long action, void *hcpu)
|
||||
{
|
||||
if (action == CPU_STARTING)
|
||||
gic_cpu_init(&gic_data[0]);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Notifier for enabling the GIC CPU interface. Set an arbitrarily high
|
||||
* priority because the GIC needs to be up before the ARM generic timers.
|
||||
*/
|
||||
static struct notifier_block __cpuinitdata gic_cpu_notifier = {
|
||||
.notifier_call = gic_secondary_init,
|
||||
.priority = 100,
|
||||
};
|
||||
#endif
|
||||
|
||||
const struct irq_domain_ops gic_irq_domain_ops = {
|
||||
.map = gic_irq_domain_map,
|
||||
.xlate = gic_irq_domain_xlate,
|
||||
|
|
@ -790,6 +810,7 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
|
|||
|
||||
#ifdef CONFIG_SMP
|
||||
set_smp_cross_call(gic_raise_softirq);
|
||||
register_cpu_notifier(&gic_cpu_notifier);
|
||||
#endif
|
||||
|
||||
set_handle_irq(gic_handle_irq);
|
||||
|
|
@ -800,15 +821,8 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
|
|||
gic_pm_init(gic);
|
||||
}
|
||||
|
||||
void __cpuinit gic_secondary_init(unsigned int gic_nr)
|
||||
{
|
||||
BUG_ON(gic_nr >= MAX_GIC_NR);
|
||||
|
||||
gic_cpu_init(&gic_data[gic_nr]);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int gic_cnt __initdata = 0;
|
||||
static int gic_cnt __initdata;
|
||||
|
||||
int __init gic_of_init(struct device_node *node, struct device_node *parent)
|
||||
{
|
||||
|
|
|
|||
121
drivers/irqchip/irq-mxs.c
Normal file
121
drivers/irqchip/irq-mxs.c
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* 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 <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_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/stmp_device.h>
|
||||
#include <asm/exception.h>
|
||||
|
||||
#include "irqchip.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;
|
||||
static struct irq_domain *icoll_domain;
|
||||
|
||||
static void icoll_ack_irq(struct irq_data *d)
|
||||
{
|
||||
/*
|
||||
* The Interrupt Collector is able to prioritize irqs.
|
||||
* Currently only level 0 is used. So acking can use
|
||||
* BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0 unconditionally.
|
||||
*/
|
||||
__raw_writel(BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0,
|
||||
icoll_base + HW_ICOLL_LEVELACK);
|
||||
}
|
||||
|
||||
static void icoll_mask_irq(struct irq_data *d)
|
||||
{
|
||||
__raw_writel(BM_ICOLL_INTERRUPTn_ENABLE,
|
||||
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->hwirq));
|
||||
}
|
||||
|
||||
static struct irq_chip mxs_icoll_chip = {
|
||||
.irq_ack = icoll_ack_irq,
|
||||
.irq_mask = icoll_mask_irq,
|
||||
.irq_unmask = icoll_unmask_irq,
|
||||
};
|
||||
|
||||
asmlinkage void __exception_irq_entry icoll_handle_irq(struct pt_regs *regs)
|
||||
{
|
||||
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,
|
||||
};
|
||||
|
||||
static void __init icoll_of_init(struct device_node *np,
|
||||
struct device_node *interrupt_parent)
|
||||
{
|
||||
icoll_base = of_iomap(np, 0);
|
||||
WARN_ON(!icoll_base);
|
||||
|
||||
/*
|
||||
* Interrupt Collector reset, which initializes the priority
|
||||
* for each irq to level 0.
|
||||
*/
|
||||
stmp_reset_block(icoll_base + HW_ICOLL_CTRL);
|
||||
|
||||
icoll_domain = irq_domain_add_linear(np, ICOLL_NUM_IRQS,
|
||||
&icoll_irq_domain_ops, NULL);
|
||||
WARN_ON(!icoll_domain);
|
||||
}
|
||||
IRQCHIP_DECLARE(mxs, "fsl,icoll", icoll_of_init);
|
||||
149
drivers/irqchip/irq-sun4i.c
Normal file
149
drivers/irqchip/irq-sun4i.c
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* Allwinner A1X SoCs IRQ chip driver.
|
||||
*
|
||||
* Copyright (C) 2012 Maxime Ripard
|
||||
*
|
||||
* Maxime Ripard <maxime.ripard@free-electrons.com>
|
||||
*
|
||||
* Based on code from
|
||||
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
|
||||
* Benn Huang <benn@allwinnertech.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
||||
#include <asm/exception.h>
|
||||
#include <asm/mach/irq.h>
|
||||
|
||||
#include "irqchip.h"
|
||||
|
||||
#define SUN4I_IRQ_VECTOR_REG 0x00
|
||||
#define SUN4I_IRQ_PROTECTION_REG 0x08
|
||||
#define SUN4I_IRQ_NMI_CTRL_REG 0x0c
|
||||
#define SUN4I_IRQ_PENDING_REG(x) (0x10 + 0x4 * x)
|
||||
#define SUN4I_IRQ_FIQ_PENDING_REG(x) (0x20 + 0x4 * x)
|
||||
#define SUN4I_IRQ_ENABLE_REG(x) (0x40 + 0x4 * x)
|
||||
#define SUN4I_IRQ_MASK_REG(x) (0x50 + 0x4 * x)
|
||||
|
||||
static void __iomem *sun4i_irq_base;
|
||||
static struct irq_domain *sun4i_irq_domain;
|
||||
|
||||
static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs);
|
||||
|
||||
void sun4i_irq_ack(struct irq_data *irqd)
|
||||
{
|
||||
unsigned int irq = irqd_to_hwirq(irqd);
|
||||
unsigned int irq_off = irq % 32;
|
||||
int reg = irq / 32;
|
||||
u32 val;
|
||||
|
||||
val = readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg));
|
||||
writel(val | (1 << irq_off),
|
||||
sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg));
|
||||
}
|
||||
|
||||
static void sun4i_irq_mask(struct irq_data *irqd)
|
||||
{
|
||||
unsigned int irq = irqd_to_hwirq(irqd);
|
||||
unsigned int irq_off = irq % 32;
|
||||
int reg = irq / 32;
|
||||
u32 val;
|
||||
|
||||
val = readl(sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(reg));
|
||||
writel(val & ~(1 << irq_off),
|
||||
sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(reg));
|
||||
}
|
||||
|
||||
static void sun4i_irq_unmask(struct irq_data *irqd)
|
||||
{
|
||||
unsigned int irq = irqd_to_hwirq(irqd);
|
||||
unsigned int irq_off = irq % 32;
|
||||
int reg = irq / 32;
|
||||
u32 val;
|
||||
|
||||
val = readl(sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(reg));
|
||||
writel(val | (1 << irq_off),
|
||||
sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(reg));
|
||||
}
|
||||
|
||||
static struct irq_chip sun4i_irq_chip = {
|
||||
.name = "sun4i_irq",
|
||||
.irq_ack = sun4i_irq_ack,
|
||||
.irq_mask = sun4i_irq_mask,
|
||||
.irq_unmask = sun4i_irq_unmask,
|
||||
};
|
||||
|
||||
static int sun4i_irq_map(struct irq_domain *d, unsigned int virq,
|
||||
irq_hw_number_t hw)
|
||||
{
|
||||
irq_set_chip_and_handler(virq, &sun4i_irq_chip,
|
||||
handle_level_irq);
|
||||
set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_domain_ops sun4i_irq_ops = {
|
||||
.map = sun4i_irq_map,
|
||||
.xlate = irq_domain_xlate_onecell,
|
||||
};
|
||||
|
||||
static int __init sun4i_of_init(struct device_node *node,
|
||||
struct device_node *parent)
|
||||
{
|
||||
sun4i_irq_base = of_iomap(node, 0);
|
||||
if (!sun4i_irq_base)
|
||||
panic("%s: unable to map IC registers\n",
|
||||
node->full_name);
|
||||
|
||||
/* Disable all interrupts */
|
||||
writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(0));
|
||||
writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(1));
|
||||
writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(2));
|
||||
|
||||
/* Mask all the interrupts */
|
||||
writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(0));
|
||||
writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(1));
|
||||
writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(2));
|
||||
|
||||
/* Clear all the pending interrupts */
|
||||
writel(0xffffffff, sun4i_irq_base + SUN4I_IRQ_PENDING_REG(0));
|
||||
writel(0xffffffff, sun4i_irq_base + SUN4I_IRQ_PENDING_REG(1));
|
||||
writel(0xffffffff, sun4i_irq_base + SUN4I_IRQ_PENDING_REG(2));
|
||||
|
||||
/* Enable protection mode */
|
||||
writel(0x01, sun4i_irq_base + SUN4I_IRQ_PROTECTION_REG);
|
||||
|
||||
/* Configure the external interrupt source type */
|
||||
writel(0x00, sun4i_irq_base + SUN4I_IRQ_NMI_CTRL_REG);
|
||||
|
||||
sun4i_irq_domain = irq_domain_add_linear(node, 3 * 32,
|
||||
&sun4i_irq_ops, NULL);
|
||||
if (!sun4i_irq_domain)
|
||||
panic("%s: unable to create IRQ domain\n", node->full_name);
|
||||
|
||||
set_handle_irq(sun4i_handle_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
IRQCHIP_DECLARE(allwinner_sun4i_ic, "allwinner,sun4i-ic", sun4i_of_init);
|
||||
|
||||
static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs)
|
||||
{
|
||||
u32 irq, hwirq;
|
||||
|
||||
hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2;
|
||||
while (hwirq != 0) {
|
||||
irq = irq_find_mapping(sun4i_irq_domain, hwirq);
|
||||
handle_IRQ(irq, regs);
|
||||
hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
/*
|
||||
* Allwinner A1X SoCs IRQ chip driver.
|
||||
*
|
||||
* Copyright (C) 2012 Maxime Ripard
|
||||
*
|
||||
* Maxime Ripard <maxime.ripard@free-electrons.com>
|
||||
*
|
||||
* Based on code from
|
||||
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
|
||||
* Benn Huang <benn@allwinnertech.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
||||
#include <linux/irqchip/sunxi.h>
|
||||
|
||||
#define SUNXI_IRQ_VECTOR_REG 0x00
|
||||
#define SUNXI_IRQ_PROTECTION_REG 0x08
|
||||
#define SUNXI_IRQ_NMI_CTRL_REG 0x0c
|
||||
#define SUNXI_IRQ_PENDING_REG(x) (0x10 + 0x4 * x)
|
||||
#define SUNXI_IRQ_FIQ_PENDING_REG(x) (0x20 + 0x4 * x)
|
||||
#define SUNXI_IRQ_ENABLE_REG(x) (0x40 + 0x4 * x)
|
||||
#define SUNXI_IRQ_MASK_REG(x) (0x50 + 0x4 * x)
|
||||
|
||||
static void __iomem *sunxi_irq_base;
|
||||
static struct irq_domain *sunxi_irq_domain;
|
||||
|
||||
void sunxi_irq_ack(struct irq_data *irqd)
|
||||
{
|
||||
unsigned int irq = irqd_to_hwirq(irqd);
|
||||
unsigned int irq_off = irq % 32;
|
||||
int reg = irq / 32;
|
||||
u32 val;
|
||||
|
||||
val = readl(sunxi_irq_base + SUNXI_IRQ_PENDING_REG(reg));
|
||||
writel(val | (1 << irq_off),
|
||||
sunxi_irq_base + SUNXI_IRQ_PENDING_REG(reg));
|
||||
}
|
||||
|
||||
static void sunxi_irq_mask(struct irq_data *irqd)
|
||||
{
|
||||
unsigned int irq = irqd_to_hwirq(irqd);
|
||||
unsigned int irq_off = irq % 32;
|
||||
int reg = irq / 32;
|
||||
u32 val;
|
||||
|
||||
val = readl(sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(reg));
|
||||
writel(val & ~(1 << irq_off),
|
||||
sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(reg));
|
||||
}
|
||||
|
||||
static void sunxi_irq_unmask(struct irq_data *irqd)
|
||||
{
|
||||
unsigned int irq = irqd_to_hwirq(irqd);
|
||||
unsigned int irq_off = irq % 32;
|
||||
int reg = irq / 32;
|
||||
u32 val;
|
||||
|
||||
val = readl(sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(reg));
|
||||
writel(val | (1 << irq_off),
|
||||
sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(reg));
|
||||
}
|
||||
|
||||
static struct irq_chip sunxi_irq_chip = {
|
||||
.name = "sunxi_irq",
|
||||
.irq_ack = sunxi_irq_ack,
|
||||
.irq_mask = sunxi_irq_mask,
|
||||
.irq_unmask = sunxi_irq_unmask,
|
||||
};
|
||||
|
||||
static int sunxi_irq_map(struct irq_domain *d, unsigned int virq,
|
||||
irq_hw_number_t hw)
|
||||
{
|
||||
irq_set_chip_and_handler(virq, &sunxi_irq_chip,
|
||||
handle_level_irq);
|
||||
set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_domain_ops sunxi_irq_ops = {
|
||||
.map = sunxi_irq_map,
|
||||
.xlate = irq_domain_xlate_onecell,
|
||||
};
|
||||
|
||||
static int __init sunxi_of_init(struct device_node *node,
|
||||
struct device_node *parent)
|
||||
{
|
||||
sunxi_irq_base = of_iomap(node, 0);
|
||||
if (!sunxi_irq_base)
|
||||
panic("%s: unable to map IC registers\n",
|
||||
node->full_name);
|
||||
|
||||
/* Disable all interrupts */
|
||||
writel(0, sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(0));
|
||||
writel(0, sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(1));
|
||||
writel(0, sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(2));
|
||||
|
||||
/* Mask all the interrupts */
|
||||
writel(0, sunxi_irq_base + SUNXI_IRQ_MASK_REG(0));
|
||||
writel(0, sunxi_irq_base + SUNXI_IRQ_MASK_REG(1));
|
||||
writel(0, sunxi_irq_base + SUNXI_IRQ_MASK_REG(2));
|
||||
|
||||
/* Clear all the pending interrupts */
|
||||
writel(0xffffffff, sunxi_irq_base + SUNXI_IRQ_PENDING_REG(0));
|
||||
writel(0xffffffff, sunxi_irq_base + SUNXI_IRQ_PENDING_REG(1));
|
||||
writel(0xffffffff, sunxi_irq_base + SUNXI_IRQ_PENDING_REG(2));
|
||||
|
||||
/* Enable protection mode */
|
||||
writel(0x01, sunxi_irq_base + SUNXI_IRQ_PROTECTION_REG);
|
||||
|
||||
/* Configure the external interrupt source type */
|
||||
writel(0x00, sunxi_irq_base + SUNXI_IRQ_NMI_CTRL_REG);
|
||||
|
||||
sunxi_irq_domain = irq_domain_add_linear(node, 3 * 32,
|
||||
&sunxi_irq_ops, NULL);
|
||||
if (!sunxi_irq_domain)
|
||||
panic("%s: unable to create IRQ domain\n", node->full_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id sunxi_irq_dt_ids[] __initconst = {
|
||||
{ .compatible = "allwinner,sunxi-ic", .data = sunxi_of_init },
|
||||
{ }
|
||||
};
|
||||
|
||||
void __init sunxi_init_irq(void)
|
||||
{
|
||||
of_irq_init(sunxi_irq_dt_ids);
|
||||
}
|
||||
|
||||
asmlinkage void __exception_irq_entry sunxi_handle_irq(struct pt_regs *regs)
|
||||
{
|
||||
u32 irq, hwirq;
|
||||
|
||||
hwirq = readl(sunxi_irq_base + SUNXI_IRQ_VECTOR_REG) >> 2;
|
||||
while (hwirq != 0) {
|
||||
irq = irq_find_mapping(sunxi_irq_domain, hwirq);
|
||||
handle_IRQ(irq, regs);
|
||||
hwirq = readl(sunxi_irq_base + SUNXI_IRQ_VECTOR_REG) >> 2;
|
||||
}
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
|
|
@ -33,7 +34,7 @@
|
|||
#include <linux/irqchip/arm-vic.h>
|
||||
|
||||
#include <asm/exception.h>
|
||||
#include <asm/mach/irq.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#include "irqchip.h"
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue