mx51: support FIQ on TZIC, revised
Add support for FIQ on mx51 TZIC TZIC changes tested with FIQ audio on an mx51 board AVIC changes build with mx3_defconfig, not tested Signed-off-by: Peter Horton <phorton@bitbox.co.uk> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
committed by
Sascha Hauer
parent
8be9252f7c
commit
cdc3f10630
@@ -3,7 +3,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
# Common support
|
# Common support
|
||||||
obj-y := clock.o gpio.o time.o devices.o cpu.o system.o
|
obj-y := clock.o gpio.o time.o devices.o cpu.o system.o irq-common.o
|
||||||
|
|
||||||
# MX51 uses the TZIC interrupt controller, older platforms use AVIC
|
# MX51 uses the TZIC interrupt controller, older platforms use AVIC
|
||||||
obj-$(CONFIG_MXC_TZIC) += tzic.o
|
obj-$(CONFIG_MXC_TZIC) += tzic.o
|
||||||
|
@@ -24,6 +24,8 @@
|
|||||||
#include <asm/mach/irq.h>
|
#include <asm/mach/irq.h>
|
||||||
#include <mach/hardware.h>
|
#include <mach/hardware.h>
|
||||||
|
|
||||||
|
#include "irq-common.h"
|
||||||
|
|
||||||
#define AVIC_INTCNTL 0x00 /* int control reg */
|
#define AVIC_INTCNTL 0x00 /* int control reg */
|
||||||
#define AVIC_NIMASK 0x04 /* int mask reg */
|
#define AVIC_NIMASK 0x04 /* int mask reg */
|
||||||
#define AVIC_INTENNUM 0x08 /* int enable number reg */
|
#define AVIC_INTENNUM 0x08 /* int enable number reg */
|
||||||
@@ -46,9 +48,9 @@
|
|||||||
|
|
||||||
void __iomem *avic_base;
|
void __iomem *avic_base;
|
||||||
|
|
||||||
int imx_irq_set_priority(unsigned char irq, unsigned char prio)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_MXC_IRQ_PRIOR
|
#ifdef CONFIG_MXC_IRQ_PRIOR
|
||||||
|
static int avic_irq_set_priority(unsigned char irq, unsigned char prio)
|
||||||
|
{
|
||||||
unsigned int temp;
|
unsigned int temp;
|
||||||
unsigned int mask = 0x0F << irq % 8 * 4;
|
unsigned int mask = 0x0F << irq % 8 * 4;
|
||||||
|
|
||||||
@@ -62,14 +64,11 @@ int imx_irq_set_priority(unsigned char irq, unsigned char prio)
|
|||||||
__raw_writel(temp, avic_base + AVIC_NIPRIORITY(irq / 8));
|
__raw_writel(temp, avic_base + AVIC_NIPRIORITY(irq / 8));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
|
||||||
return -ENOSYS;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(imx_irq_set_priority);
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_FIQ
|
#ifdef CONFIG_FIQ
|
||||||
int mxc_set_irq_fiq(unsigned int irq, unsigned int type)
|
static int avic_set_irq_fiq(unsigned int irq, unsigned int type)
|
||||||
{
|
{
|
||||||
unsigned int irqt;
|
unsigned int irqt;
|
||||||
|
|
||||||
@@ -87,7 +86,6 @@ int mxc_set_irq_fiq(unsigned int irq, unsigned int type)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(mxc_set_irq_fiq);
|
|
||||||
#endif /* CONFIG_FIQ */
|
#endif /* CONFIG_FIQ */
|
||||||
|
|
||||||
/* Disable interrupt number "irq" in the AVIC */
|
/* Disable interrupt number "irq" in the AVIC */
|
||||||
@@ -102,10 +100,18 @@ static void mxc_unmask_irq(unsigned int irq)
|
|||||||
__raw_writel(irq, avic_base + AVIC_INTENNUM);
|
__raw_writel(irq, avic_base + AVIC_INTENNUM);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct irq_chip mxc_avic_chip = {
|
static struct mxc_irq_chip mxc_avic_chip = {
|
||||||
.ack = mxc_mask_irq,
|
.base = {
|
||||||
.mask = mxc_mask_irq,
|
.ack = mxc_mask_irq,
|
||||||
.unmask = mxc_unmask_irq,
|
.mask = mxc_mask_irq,
|
||||||
|
.unmask = mxc_unmask_irq,
|
||||||
|
},
|
||||||
|
#ifdef CONFIG_MXC_IRQ_PRIOR
|
||||||
|
.set_priority = avic_irq_set_priority,
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_FIQ
|
||||||
|
.set_irq_fiq = avic_set_irq_fiq,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -133,7 +139,7 @@ void __init mxc_init_irq(void __iomem *irqbase)
|
|||||||
__raw_writel(0, avic_base + AVIC_INTTYPEH);
|
__raw_writel(0, avic_base + AVIC_INTTYPEH);
|
||||||
__raw_writel(0, avic_base + AVIC_INTTYPEL);
|
__raw_writel(0, avic_base + AVIC_INTTYPEL);
|
||||||
for (i = 0; i < MXC_INTERNAL_IRQS; i++) {
|
for (i = 0; i < MXC_INTERNAL_IRQS; i++) {
|
||||||
set_irq_chip(i, &mxc_avic_chip);
|
set_irq_chip(i, &mxc_avic_chip.base);
|
||||||
set_irq_handler(i, handle_level_irq);
|
set_irq_handler(i, handle_level_irq);
|
||||||
set_irq_flags(i, IRQF_VALID);
|
set_irq_flags(i, IRQF_VALID);
|
||||||
}
|
}
|
||||||
|
@@ -54,15 +54,15 @@
|
|||||||
#elif defined CONFIG_MXC_TZIC
|
#elif defined CONFIG_MXC_TZIC
|
||||||
@ Load offset & priority of the highest priority
|
@ Load offset & priority of the highest priority
|
||||||
@ interrupt pending.
|
@ interrupt pending.
|
||||||
|
@ 0x080 is INTSEC0 register
|
||||||
@ 0xD80 is HIPND0 register
|
@ 0xD80 is HIPND0 register
|
||||||
mov \irqnr, #0
|
mov \irqnr, #0
|
||||||
mov \irqstat, #0x0D80
|
1000: add \irqstat, \base, \irqnr, lsr #3
|
||||||
1000:
|
ldr \tmp, [\irqstat, #0xd80]
|
||||||
ldr \tmp, [\irqstat, \base]
|
ldr \irqstat, [\irqstat, #0x080]
|
||||||
cmp \tmp, #0
|
ands \tmp, \tmp, \irqstat
|
||||||
bne 1001f
|
bne 1001f
|
||||||
addeq \irqnr, \irqnr, #32
|
add \irqnr, \irqnr, #32
|
||||||
addeq \irqstat, \irqstat, #4
|
|
||||||
cmp \irqnr, #128
|
cmp \irqnr, #128
|
||||||
blo 1000b
|
blo 1000b
|
||||||
b 2001f
|
b 2001f
|
||||||
|
60
arch/arm/plat-mxc/irq-common.c
Normal file
60
arch/arm/plat-mxc/irq-common.c
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) BitBox Ltd 2010
|
||||||
|
*
|
||||||
|
* 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/module.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
|
|
||||||
|
#include "irq-common.h"
|
||||||
|
|
||||||
|
int imx_irq_set_priority(unsigned char irq, unsigned char prio)
|
||||||
|
{
|
||||||
|
struct mxc_irq_chip *chip;
|
||||||
|
struct irq_chip *base;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = -ENOSYS;
|
||||||
|
|
||||||
|
base = get_irq_chip(irq);
|
||||||
|
if (base) {
|
||||||
|
chip = container_of(base, struct mxc_irq_chip, base);
|
||||||
|
if (chip->set_priority)
|
||||||
|
ret = chip->set_priority(irq, prio);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(imx_irq_set_priority);
|
||||||
|
|
||||||
|
int mxc_set_irq_fiq(unsigned int irq, unsigned int type)
|
||||||
|
{
|
||||||
|
struct mxc_irq_chip *chip;
|
||||||
|
struct irq_chip *base;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = -ENOSYS;
|
||||||
|
|
||||||
|
base = get_irq_chip(irq);
|
||||||
|
if (base) {
|
||||||
|
chip = container_of(base, struct mxc_irq_chip, base);
|
||||||
|
if (chip->set_irq_fiq)
|
||||||
|
ret = chip->set_irq_fiq(irq, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(mxc_set_irq_fiq);
|
29
arch/arm/plat-mxc/irq-common.h
Normal file
29
arch/arm/plat-mxc/irq-common.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) BitBox Ltd 2010
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PLAT_MXC_IRQ_COMMON_H__
|
||||||
|
#define __PLAT_MXC_IRQ_COMMON_H__
|
||||||
|
|
||||||
|
struct mxc_irq_chip
|
||||||
|
{
|
||||||
|
struct irq_chip base;
|
||||||
|
int (*set_priority)(unsigned char irq, unsigned char prio);
|
||||||
|
int (*set_irq_fiq)(unsigned int irq, unsigned int type);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@@ -21,6 +21,8 @@
|
|||||||
#include <mach/hardware.h>
|
#include <mach/hardware.h>
|
||||||
#include <mach/common.h>
|
#include <mach/common.h>
|
||||||
|
|
||||||
|
#include "irq-common.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*****************************************
|
*****************************************
|
||||||
* TZIC Registers *
|
* TZIC Registers *
|
||||||
@@ -47,6 +49,25 @@
|
|||||||
|
|
||||||
void __iomem *tzic_base; /* Used as irq controller base in entry-macro.S */
|
void __iomem *tzic_base; /* Used as irq controller base in entry-macro.S */
|
||||||
|
|
||||||
|
#ifdef CONFIG_FIQ
|
||||||
|
static int tzic_set_irq_fiq(unsigned int irq, unsigned int type)
|
||||||
|
{
|
||||||
|
unsigned int index, mask, value;
|
||||||
|
|
||||||
|
index = irq >> 5;
|
||||||
|
if (unlikely(index >= 4))
|
||||||
|
return -EINVAL;
|
||||||
|
mask = 1U << (irq & 0x1F);
|
||||||
|
|
||||||
|
value = __raw_readl(tzic_base + TZIC_INTSEC0(index)) | mask;
|
||||||
|
if (type)
|
||||||
|
value &= ~mask;
|
||||||
|
__raw_writel(value, tzic_base + TZIC_INTSEC0(index));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tzic_mask_irq() - Disable interrupt number "irq" in the TZIC
|
* tzic_mask_irq() - Disable interrupt number "irq" in the TZIC
|
||||||
*
|
*
|
||||||
@@ -104,12 +125,17 @@ static int tzic_set_wake_irq(unsigned int irq, unsigned int enable)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct irq_chip mxc_tzic_chip = {
|
static struct mxc_irq_chip mxc_tzic_chip = {
|
||||||
.name = "MXC_TZIC",
|
.base = {
|
||||||
.ack = tzic_mask_irq,
|
.name = "MXC_TZIC",
|
||||||
.mask = tzic_mask_irq,
|
.ack = tzic_mask_irq,
|
||||||
.unmask = tzic_unmask_irq,
|
.mask = tzic_mask_irq,
|
||||||
.set_wake = tzic_set_wake_irq,
|
.unmask = tzic_unmask_irq,
|
||||||
|
.set_wake = tzic_set_wake_irq,
|
||||||
|
},
|
||||||
|
#ifdef CONFIG_FIQ
|
||||||
|
.set_irq_fiq = tzic_set_irq_fiq,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -141,10 +167,16 @@ void __init tzic_init_irq(void __iomem *irqbase)
|
|||||||
/* all IRQ no FIQ Warning :: No selection */
|
/* all IRQ no FIQ Warning :: No selection */
|
||||||
|
|
||||||
for (i = 0; i < MXC_INTERNAL_IRQS; i++) {
|
for (i = 0; i < MXC_INTERNAL_IRQS; i++) {
|
||||||
set_irq_chip(i, &mxc_tzic_chip);
|
set_irq_chip(i, &mxc_tzic_chip.base);
|
||||||
set_irq_handler(i, handle_level_irq);
|
set_irq_handler(i, handle_level_irq);
|
||||||
set_irq_flags(i, IRQF_VALID);
|
set_irq_flags(i, IRQF_VALID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_FIQ
|
||||||
|
/* Initialize FIQ */
|
||||||
|
init_FIQ();
|
||||||
|
#endif
|
||||||
|
|
||||||
pr_info("TrustZone Interrupt Controller (TZIC) initialized\n");
|
pr_info("TrustZone Interrupt Controller (TZIC) initialized\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user