uic.c 8.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/*
 * arch/powerpc/sysdev/uic.c
 *
 * IBM PowerPC 4xx Universal Interrupt Controller
 *
 * Copyright 2007 David Gibson <dwg@au1.ibm.com>, IBM Corporation.
 *
 * 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.
 */
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/reboot.h>
#include <linux/slab.h>
#include <linux/stddef.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/sysdev.h>
#include <linux/device.h>
#include <linux/bootmem.h>
#include <linux/spinlock.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
27
#include <linux/kernel_stat.h>
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/dcr.h>

#define NR_UIC_INTS	32

#define UIC_SR		0x0
#define UIC_ER		0x2
#define UIC_CR		0x3
#define UIC_PR		0x4
#define UIC_TR		0x5
#define UIC_MSR		0x6
#define UIC_VR		0x7
#define UIC_VCR		0x8

#define uic_irq_to_hw(virq)	(irq_map[virq].hwirq)

struct uic *primary_uic;

struct uic {
	int index;
	int dcrbase;

	spinlock_t lock;

	/* The remapper for this UIC */
	struct irq_host	*irqhost;
};

58
static void uic_unmask_irq(struct irq_data *d)
59
{
60 61 62
	struct irq_desc *desc = irq_to_desc(d->irq);
	struct uic *uic = irq_data_get_irq_chip_data(d);
	unsigned int src = uic_irq_to_hw(d->irq);
63
	unsigned long flags;
64
	u32 er, sr;
65

66
	sr = 1 << (31-src);
67
	spin_lock_irqsave(&uic->lock, flags);
68 69 70
	/* ack level-triggered interrupts here */
	if (desc->status & IRQ_LEVEL)
		mtdcr(uic->dcrbase + UIC_SR, sr);
71
	er = mfdcr(uic->dcrbase + UIC_ER);
72
	er |= sr;
73 74 75 76
	mtdcr(uic->dcrbase + UIC_ER, er);
	spin_unlock_irqrestore(&uic->lock, flags);
}

77
static void uic_mask_irq(struct irq_data *d)
78
{
79 80
	struct uic *uic = irq_data_get_irq_chip_data(d);
	unsigned int src = uic_irq_to_hw(d->irq);
81 82 83 84 85 86 87 88 89 90
	unsigned long flags;
	u32 er;

	spin_lock_irqsave(&uic->lock, flags);
	er = mfdcr(uic->dcrbase + UIC_ER);
	er &= ~(1 << (31 - src));
	mtdcr(uic->dcrbase + UIC_ER, er);
	spin_unlock_irqrestore(&uic->lock, flags);
}

91
static void uic_ack_irq(struct irq_data *d)
92
{
93 94
	struct uic *uic = irq_data_get_irq_chip_data(d);
	unsigned int src = uic_irq_to_hw(d->irq);
95 96 97 98 99 100 101
	unsigned long flags;

	spin_lock_irqsave(&uic->lock, flags);
	mtdcr(uic->dcrbase + UIC_SR, 1 << (31-src));
	spin_unlock_irqrestore(&uic->lock, flags);
}

102
static void uic_mask_ack_irq(struct irq_data *d)
103
{
104 105 106
	struct irq_desc *desc = irq_to_desc(d->irq);
	struct uic *uic = irq_data_get_irq_chip_data(d);
	unsigned int src = uic_irq_to_hw(d->irq);
107 108 109 110 111 112 113 114
	unsigned long flags;
	u32 er, sr;

	sr = 1 << (31-src);
	spin_lock_irqsave(&uic->lock, flags);
	er = mfdcr(uic->dcrbase + UIC_ER);
	er &= ~sr;
	mtdcr(uic->dcrbase + UIC_ER, er);
115 116 117 118 119 120 121 122 123 124
 	/* On the UIC, acking (i.e. clearing the SR bit)
	 * a level irq will have no effect if the interrupt
	 * is still asserted by the device, even if
	 * the interrupt is already masked. Therefore
	 * we only ack the egde interrupts here, while
	 * level interrupts are ack'ed after the actual
	 * isr call in the uic_unmask_irq()
	 */
	if (!(desc->status & IRQ_LEVEL))
		mtdcr(uic->dcrbase + UIC_SR, sr);
125 126 127
	spin_unlock_irqrestore(&uic->lock, flags);
}

128
static int uic_set_irq_type(struct irq_data *d, unsigned int flow_type)
129
{
130 131 132
	struct uic *uic = irq_data_get_irq_chip_data(d);
	unsigned int src = uic_irq_to_hw(d->irq);
	struct irq_desc *desc = irq_to_desc(d->irq);
133 134 135 136 137 138
	unsigned long flags;
	int trigger, polarity;
	u32 tr, pr, mask;

	switch (flow_type & IRQ_TYPE_SENSE_MASK) {
	case IRQ_TYPE_NONE:
139
		uic_mask_irq(d);
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 170
		return 0;

	case IRQ_TYPE_EDGE_RISING:
		trigger = 1; polarity = 1;
		break;
	case IRQ_TYPE_EDGE_FALLING:
		trigger = 1; polarity = 0;
		break;
	case IRQ_TYPE_LEVEL_HIGH:
		trigger = 0; polarity = 1;
		break;
	case IRQ_TYPE_LEVEL_LOW:
		trigger = 0; polarity = 0;
		break;
	default:
		return -EINVAL;
	}

	mask = ~(1 << (31 - src));

	spin_lock_irqsave(&uic->lock, flags);
	tr = mfdcr(uic->dcrbase + UIC_TR);
	pr = mfdcr(uic->dcrbase + UIC_PR);
	tr = (tr & mask) | (trigger << (31-src));
	pr = (pr & mask) | (polarity << (31-src));

	mtdcr(uic->dcrbase + UIC_PR, pr);
	mtdcr(uic->dcrbase + UIC_TR, tr);

	desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
	desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
171
	if (!trigger)
172 173 174 175 176 177 178 179
		desc->status |= IRQ_LEVEL;

	spin_unlock_irqrestore(&uic->lock, flags);

	return 0;
}

static struct irq_chip uic_irq_chip = {
180
	.name		= "UIC",
181 182 183 184 185
	.irq_unmask	= uic_unmask_irq,
	.irq_mask	= uic_mask_irq,
	.irq_mask_ack	= uic_mask_ack_irq,
	.irq_ack	= uic_ack_irq,
	.irq_set_type	= uic_set_irq_type,
186 187 188 189 190 191 192 193 194 195
};

static int uic_host_map(struct irq_host *h, unsigned int virq,
			irq_hw_number_t hw)
{
	struct uic *uic = h->host_data;

	set_irq_chip_data(virq, uic);
	/* Despite the name, handle_level_irq() works for both level
	 * and edge irqs on UIC.  FIXME: check this is correct */
196
	set_irq_chip_and_handler(virq, &uic_irq_chip, handle_level_irq);
197 198 199 200 201 202 203 204

	/* Set default irq type */
	set_irq_type(virq, IRQ_TYPE_NONE);

	return 0;
}

static int uic_host_xlate(struct irq_host *h, struct device_node *ct,
205
			  const u32 *intspec, unsigned int intsize,
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
			  irq_hw_number_t *out_hwirq, unsigned int *out_type)

{
	/* UIC intspecs must have 2 cells */
	BUG_ON(intsize != 2);
	*out_hwirq = intspec[0];
	*out_type = intspec[1];
	return 0;
}

static struct irq_host_ops uic_host_ops = {
	.map	= uic_host_map,
	.xlate	= uic_host_xlate,
};

221
void uic_irq_cascade(unsigned int virq, struct irq_desc *desc)
222
{
223
	struct irq_chip *chip = get_irq_desc_chip(desc);
224
	struct uic *uic = get_irq_data(virq);
225 226 227 228
	u32 msr;
	int src;
	int subvirq;

229
	raw_spin_lock(&desc->lock);
230
	if (desc->status & IRQ_LEVEL)
231
		chip->irq_mask(&desc->irq_data);
232
	else
233
		chip->irq_mask_ack(&desc->irq_data);
234
	raw_spin_unlock(&desc->lock);
235

236
	msr = mfdcr(uic->dcrbase + UIC_MSR);
237
	if (!msr) /* spurious interrupt */
238
		goto uic_irq_ret;
239

240 241 242 243 244
	src = 32 - ffs(msr);

	subvirq = irq_linear_revmap(uic->irqhost, src);
	generic_handle_irq(subvirq);

245
uic_irq_ret:
246
	raw_spin_lock(&desc->lock);
247
	if (desc->status & IRQ_LEVEL)
248 249 250
		chip->irq_ack(&desc->irq_data);
	if (!(desc->status & IRQ_DISABLED) && chip->irq_unmask)
		chip->irq_unmask(&desc->irq_data);
251
	raw_spin_unlock(&desc->lock);
252 253 254 255 256 257 258 259
}

static struct uic * __init uic_init_one(struct device_node *node)
{
	struct uic *uic;
	const u32 *indexp, *dcrreg;
	int len;

260
	BUG_ON(! of_device_is_compatible(node, "ibm,uic"));
261

262
	uic = kzalloc(sizeof(*uic), GFP_KERNEL);
263 264 265 266
	if (! uic)
		return NULL; /* FIXME: panic? */

	spin_lock_init(&uic->lock);
267
	indexp = of_get_property(node, "cell-index", &len);
268 269 270 271 272 273 274
	if (!indexp || (len != sizeof(u32))) {
		printk(KERN_ERR "uic: Device node %s has missing or invalid "
		       "cell-index property\n", node->full_name);
		return NULL;
	}
	uic->index = *indexp;

275
	dcrreg = of_get_property(node, "dcr-reg", &len);
276 277 278 279 280 281 282
	if (!dcrreg || (len != 2*sizeof(u32))) {
		printk(KERN_ERR "uic: Device node %s has missing or invalid "
		       "dcr-reg property\n", node->full_name);
		return NULL;
	}
	uic->dcrbase = *dcrreg;

283
	uic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR,
284
				      NR_UIC_INTS, &uic_host_ops, -1);
285
	if (! uic->irqhost)
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
		return NULL; /* FIXME: panic? */

	uic->irqhost->host_data = uic;

	/* Start with all interrupts disabled, level and non-critical */
	mtdcr(uic->dcrbase + UIC_ER, 0);
	mtdcr(uic->dcrbase + UIC_CR, 0);
	mtdcr(uic->dcrbase + UIC_TR, 0);
	/* Clear any pending interrupts, in case the firmware left some */
	mtdcr(uic->dcrbase + UIC_SR, 0xffffffff);

	printk ("UIC%d (%d IRQ sources) at DCR 0x%x\n", uic->index,
		NR_UIC_INTS, uic->dcrbase);

	return uic;
}

void __init uic_init_tree(void)
{
	struct device_node *np;
	struct uic *uic;
	const u32 *interrupts;

	/* First locate and initialize the top-level UIC */
310
	for_each_compatible_node(np, NULL, "ibm,uic") {
311
		interrupts = of_get_property(np, "interrupts", NULL);
312
		if (!interrupts)
313 314 315 316 317 318
			break;
	}

	BUG_ON(!np); /* uic_init_tree() assumes there's a UIC as the
		      * top-level interrupt controller */
	primary_uic = uic_init_one(np);
319
	if (!primary_uic)
320 321 322 323 324 325
		panic("Unable to initialize primary UIC %s\n", np->full_name);

	irq_set_default_host(primary_uic->irqhost);
	of_node_put(np);

	/* The scan again for cascaded UICs */
326
	for_each_compatible_node(np, NULL, "ibm,uic") {
327
		interrupts = of_get_property(np, "interrupts", NULL);
328 329 330 331 332 333 334 335 336 337 338
		if (interrupts) {
			/* Secondary UIC */
			int cascade_virq;

			uic = uic_init_one(np);
			if (! uic)
				panic("Unable to initialize a secondary UIC %s\n",
				      np->full_name);

			cascade_virq = irq_of_parse_and_map(np, 0);

339 340
			set_irq_data(cascade_virq, uic);
			set_irq_chained_handler(cascade_virq, uic_irq_cascade);
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359

			/* FIXME: setup critical cascade?? */
		}
	}
}

/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
unsigned int uic_get_irq(void)
{
	u32 msr;
	int src;

	BUG_ON(! primary_uic);

	msr = mfdcr(primary_uic->dcrbase + UIC_MSR);
	src = 32 - ffs(msr);

	return irq_linear_revmap(primary_uic->irqhost, src);
}