tzic.c 5.0 KB
Newer Older
1
/*
2
 * Copyright (C)2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * The code contained herein is licensed under the GNU General Public
 * License. You may obtain a copy of the GNU General Public License
 * Version 2 or later at the following locations:
 *
 * http://www.opensource.org/licenses/gpl-license.html
 * http://www.gnu.org/copyleft/gpl.html
 */

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/io.h>

#include <asm/mach/irq.h>
20
#include <asm/exception.h>
21 22

#include <mach/hardware.h>
23
#include <mach/common.h>
24

P
Peter Horton 已提交
25 26
#include "irq-common.h"

27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
/*
 *****************************************
 * TZIC Registers                        *
 *****************************************
 */

#define TZIC_INTCNTL	0x0000	/* Control register */
#define TZIC_INTTYPE	0x0004	/* Controller Type register */
#define TZIC_IMPID	0x0008	/* Distributor Implementer Identification */
#define TZIC_PRIOMASK	0x000C	/* Priority Mask Reg */
#define TZIC_SYNCCTRL	0x0010	/* Synchronizer Control register */
#define TZIC_DSMINT	0x0014	/* DSM interrupt Holdoffregister */
#define TZIC_INTSEC0(i)	(0x0080 + ((i) << 2)) /* Interrupt Security Reg 0 */
#define TZIC_ENSET0(i)	(0x0100 + ((i) << 2)) /* Enable Set Reg 0 */
#define TZIC_ENCLEAR0(i) (0x0180 + ((i) << 2)) /* Enable Clear Reg 0 */
#define TZIC_SRCSET0	0x0200	/* Source Set Register 0 */
#define TZIC_SRCCLAR0	0x0280	/* Source Clear Register 0 */
#define TZIC_PRIORITY0	0x0400	/* Priority Register 0 */
#define TZIC_PND0	0x0D00	/* Pending Register 0 */
46
#define TZIC_HIPND(i)	(0x0D80+ ((i) << 2))	/* High Priority Pending Register */
47 48 49 50 51 52
#define TZIC_WAKEUP0(i)	(0x0E00 + ((i) << 2))	/* Wakeup Config Register */
#define TZIC_SWINT	0x0F00	/* Software Interrupt Rigger Register */
#define TZIC_ID0	0x0FD0	/* Indentification Register 0 */

void __iomem *tzic_base; /* Used as irq controller base in entry-macro.S */

53 54
#define TZIC_NUM_IRQS 128

P
Peter Horton 已提交
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
#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;
}
72 73
#else
#define tzic_set_irq_fiq NULL
P
Peter Horton 已提交
74 75
#endif

76
static unsigned int *wakeup_intr[4];
77

78 79 80 81 82 83
static struct mxc_extra_irq tzic_extra_irq = {
#ifdef CONFIG_FIQ
	.set_irq_fiq = tzic_set_irq_fiq,
#endif
};

84
static __init void tzic_init_gc(unsigned int irq_start)
85
{
86 87 88 89 90 91
	struct irq_chip_generic *gc;
	struct irq_chip_type *ct;
	int idx = irq_start >> 5;

	gc = irq_alloc_generic_chip("tzic", 1, irq_start, tzic_base,
				    handle_level_irq);
92
	gc->private = &tzic_extra_irq;
93 94 95 96 97 98 99 100 101 102 103
	gc->wake_enabled = IRQ_MSK(32);
	wakeup_intr[idx] = &gc->wake_active;

	ct = gc->chip_types;
	ct->chip.irq_mask = irq_gc_mask_disable_reg;
	ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
	ct->chip.irq_set_wake = irq_gc_set_wake;
	ct->regs.disable = TZIC_ENCLEAR0(idx);
	ct->regs.enable = TZIC_ENSET0(idx);

	irq_setup_generic_chip(gc, IRQ_MSK(32), 0, IRQ_NOREQUEST, 0);
104 105
}

106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
asmlinkage void __exception_irq_entry tzic_handle_irq(struct pt_regs *regs)
{
	u32 stat;
	int i, irqofs, handled;

	do {
		handled = 0;

		for (i = 0; i < 4; i++) {
			stat = __raw_readl(tzic_base + TZIC_HIPND(i)) &
				__raw_readl(tzic_base + TZIC_INTSEC0(i));

			while (stat) {
				handled = 1;
				irqofs = fls(stat) - 1;
				handle_IRQ(irqofs + i * 32, regs);
				stat &= ~(1 << irqofs);
			}
		}
	} while (handled);
}

128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
/*
 * This function initializes the TZIC hardware and disables all the
 * interrupts. It registers the interrupt enable and disable functions
 * to the kernel for each interrupt source.
 */
void __init tzic_init_irq(void __iomem *irqbase)
{
	int i;

	tzic_base = irqbase;
	/* put the TZIC into the reset value with
	 * all interrupts disabled
	 */
	i = __raw_readl(tzic_base + TZIC_INTCNTL);

	__raw_writel(0x80010001, tzic_base + TZIC_INTCNTL);
	__raw_writel(0x1f, tzic_base + TZIC_PRIOMASK);
	__raw_writel(0x02, tzic_base + TZIC_SYNCCTRL);

	for (i = 0; i < 4; i++)
		__raw_writel(0xFFFFFFFF, tzic_base + TZIC_INTSEC0(i));

	/* disable all interrupts */
	for (i = 0; i < 4; i++)
		__raw_writel(0xFFFFFFFF, tzic_base + TZIC_ENCLEAR0(i));

	/* all IRQ no FIQ Warning :: No selection */

156 157
	for (i = 0; i < TZIC_NUM_IRQS; i += 32)
		tzic_init_gc(i);
P
Peter Horton 已提交
158 159 160 161 162 163

#ifdef CONFIG_FIQ
	/* Initialize FIQ */
	init_FIQ();
#endif

164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
	pr_info("TrustZone Interrupt Controller (TZIC) initialized\n");
}

/**
 * tzic_enable_wake() - enable wakeup interrupt
 *
 * @param is_idle		1 if called in idle loop (ENSET0 register);
 *				0 to be used when called from low power entry
 * @return			0 if successful; non-zero otherwise
 */
int tzic_enable_wake(int is_idle)
{
	unsigned int i, v;

	__raw_writel(1, tzic_base + TZIC_DSMINT);
	if (unlikely(__raw_readl(tzic_base + TZIC_DSMINT) == 0))
		return -EAGAIN;

	for (i = 0; i < 4; i++) {
183
		v = is_idle ? __raw_readl(tzic_base + TZIC_ENSET0(i)) :
184
			*wakeup_intr[i];
185
		__raw_writel(v, tzic_base + TZIC_WAKEUP0(i));
186 187 188 189
	}

	return 0;
}