Commit cdc3f106 authored by Peter Horton's avatar Peter Horton Committed by Sascha Hauer

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: default avatarPeter Horton <phorton@bitbox.co.uk>
Signed-off-by: default avatarSascha Hauer <s.hauer@pengutronix.de>
parent 8be9252f
...@@ -3,7 +3,7 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 = {
.base = {
.ack = mxc_mask_irq, .ack = mxc_mask_irq,
.mask = mxc_mask_irq, .mask = mxc_mask_irq,
.unmask = mxc_unmask_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) ...@@ -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 @@ ...@@ -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
......
/*
* 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);
/*
* 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 @@ ...@@ -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 @@ ...@@ -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) ...@@ -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 = {
.base = {
.name = "MXC_TZIC", .name = "MXC_TZIC",
.ack = tzic_mask_irq, .ack = tzic_mask_irq,
.mask = tzic_mask_irq, .mask = tzic_mask_irq,
.unmask = tzic_unmask_irq, .unmask = tzic_unmask_irq,
.set_wake = tzic_set_wake_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) ...@@ -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");
} }
......
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