irq.c 4.2 KB
Newer Older
E
Erik Gilling 已提交
1 2 3 4 5 6
/*
 * Copyright (C) 2010 Google, Inc.
 *
 * Author:
 *	Colin Cross <ccross@google.com>
 *
7 8
 * Copyright (C) 2010, NVIDIA Corporation
 *
E
Erik Gilling 已提交
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * 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.
 *
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>

#include <asm/hardware/gic.h>

#include <mach/iomap.h>

#include "board.h"

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
#define INT_SYS_NR	(INT_GPIO_BASE - INT_PRI_BASE)
#define INT_SYS_SZ	(INT_SEC_BASE - INT_PRI_BASE)
#define PPI_NR		((INT_SYS_NR+INT_SYS_SZ-1)/INT_SYS_SZ)

#define APBDMA_IRQ_STA_CPU  0x14
#define APBDMA_IRQ_MASK_SET 0x20
#define APBDMA_IRQ_MASK_CLR 0x24

#define ICTLR_CPU_IER		0x20
#define ICTLR_CPU_IER_SET	0x24
#define ICTLR_CPU_IER_CLR	0x28
#define ICTLR_CPU_IEP_CLASS	0x2c
#define ICTLR_COP_IER		0x30
#define ICTLR_COP_IER_SET	0x34
#define ICTLR_COP_IER_CLR	0x38
#define ICTLR_COP_IEP_CLASS	0x3c

49 50
static void (*tegra_gic_mask_irq)(struct irq_data *d);
static void (*tegra_gic_unmask_irq)(struct irq_data *d);
51

52
#define irq_to_ictlr(irq) (((irq) - 32) >> 5)
53
static void __iomem *tegra_ictlr_base = IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE);
54
#define ictlr_to_virt(ictlr) (tegra_ictlr_base + (ictlr) * 0x100)
55

56
static void tegra_mask(struct irq_data *d)
57
{
58
	void __iomem *addr = ictlr_to_virt(irq_to_ictlr(d->irq));
59 60
	tegra_gic_mask_irq(d);
	writel(1 << (d->irq & 31), addr+ICTLR_CPU_IER_CLR);
61 62
}

63
static void tegra_unmask(struct irq_data *d)
64
{
65
	void __iomem *addr = ictlr_to_virt(irq_to_ictlr(d->irq));
66
	tegra_gic_unmask_irq(d);
67
	writel(1<<(d->irq&31), addr+ICTLR_CPU_IER_SET);
68 69 70 71
}

#ifdef CONFIG_PM

72
static int tegra_set_wake(struct irq_data *d, unsigned int on)
73 74 75 76 77 78 79
{
	return 0;
}
#endif

static struct irq_chip tegra_irq = {
	.name		= "PPI",
80 81
	.irq_mask	= tegra_mask,
	.irq_unmask	= tegra_unmask,
82
#ifdef CONFIG_PM
83
	.irq_set_wake	= tegra_set_wake,
84 85 86
#endif
};

E
Erik Gilling 已提交
87 88
void __init tegra_init_irq(void)
{
89 90 91 92 93 94 95 96
	struct irq_chip *gic;
	unsigned int i;

	for (i = 0; i < PPI_NR; i++) {
		writel(~0, ictlr_to_virt(i) + ICTLR_CPU_IER_CLR);
		writel(0, ictlr_to_virt(i) + ICTLR_CPU_IEP_CLASS);
	}

97 98
	gic_init(0, 29, IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE),
		 IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100));
99 100

	gic = get_irq_chip(29);
101 102
	tegra_gic_unmask_irq = gic->irq_unmask;
	tegra_gic_mask_irq = gic->irq_mask;
103
	tegra_irq.irq_ack = gic->irq_ack;
104
#ifdef CONFIG_SMP
105
	tegra_irq.irq_set_affinity = gic->irq_set_affinity;
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 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 156 157 158 159 160 161 162 163 164 165 166 167 168 169
#endif

	for (i = INT_PRI_BASE; i < INT_GPIO_BASE; i++) {
		set_irq_chip(i, &tegra_irq);
		set_irq_handler(i, handle_level_irq);
		set_irq_flags(i, IRQF_VALID);
	}
}

#ifdef CONFIG_PM
static u32 cop_ier[PPI_NR];
static u32 cpu_ier[PPI_NR];
static u32 cpu_iep[PPI_NR];

void tegra_irq_suspend(void)
{
	unsigned long flags;
	int i;

	for (i = INT_PRI_BASE; i < INT_GPIO_BASE; i++) {
		struct irq_desc *desc = irq_to_desc(i);
		if (!desc)
			continue;
		if (desc->status & IRQ_WAKEUP) {
			pr_debug("irq %d is wakeup\n", i);
			continue;
		}
		disable_irq(i);
	}

	local_irq_save(flags);
	for (i = 0; i < PPI_NR; i++) {
		void __iomem *ictlr = ictlr_to_virt(i);
		cpu_ier[i] = readl(ictlr + ICTLR_CPU_IER);
		cpu_iep[i] = readl(ictlr + ICTLR_CPU_IEP_CLASS);
		cop_ier[i] = readl(ictlr + ICTLR_COP_IER);
		writel(~0, ictlr + ICTLR_COP_IER_CLR);
	}
	local_irq_restore(flags);
}

void tegra_irq_resume(void)
{
	unsigned long flags;
	int i;

	local_irq_save(flags);
	for (i = 0; i < PPI_NR; i++) {
		void __iomem *ictlr = ictlr_to_virt(i);
		writel(cpu_iep[i], ictlr + ICTLR_CPU_IEP_CLASS);
		writel(~0ul, ictlr + ICTLR_CPU_IER_CLR);
		writel(cpu_ier[i], ictlr + ICTLR_CPU_IER_SET);
		writel(0, ictlr + ICTLR_COP_IEP_CLASS);
		writel(~0ul, ictlr + ICTLR_COP_IER_CLR);
		writel(cop_ier[i], ictlr + ICTLR_COP_IER_SET);
	}
	local_irq_restore(flags);

	for (i = INT_PRI_BASE; i < INT_GPIO_BASE; i++) {
		struct irq_desc *desc = irq_to_desc(i);
		if (!desc || (desc->status & IRQ_WAKEUP))
			continue;
		enable_irq(i);
	}
E
Erik Gilling 已提交
170
}
171
#endif