mpc52xx_pic.c 16.6 KB
Newer Older
1 2 3 4
/*
 *
 * Programmable Interrupt Controller functions for the Freescale MPC52xx.
 *
5
 * Copyright (C) 2008 Secret Lab Technologies Ltd.
6
 * Copyright (C) 2006 bplan GmbH
7 8
 * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
 * Copyright (C) 2003 Montavista Software, Inc
9 10 11 12 13 14 15 16 17 18
 *
 * Based on the code from the 2.4 kernel by
 * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg.
 *
 * This file is licensed under the terms of the GNU General Public License
 * version 2. This program is licensed "as is" without any warranty of any
 * kind, whether express or implied.
 *
 */

19 20 21 22 23 24 25 26 27 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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
/*
 * This is the device driver for the MPC5200 interrupt controller.
 *
 * hardware overview
 * -----------------
 * The MPC5200 interrupt controller groups the all interrupt sources into
 * three groups called 'critical', 'main', and 'peripheral'.  The critical
 * group has 3 irqs, External IRQ0, slice timer 0 irq, and wake from deep
 * sleep.  Main group include the other 3 external IRQs, slice timer 1, RTC,
 * gpios, and the general purpose timers.  Peripheral group contains the
 * remaining irq sources from all of the on-chip peripherals (PSCs, Ethernet,
 * USB, DMA, etc).
 *
 * virqs
 * -----
 * The Linux IRQ subsystem requires that each irq source be assigned a
 * system wide unique IRQ number starting at 1 (0 means no irq).  Since
 * systems can have multiple interrupt controllers, the virtual IRQ (virq)
 * infrastructure lets each interrupt controller to define a local set
 * of IRQ numbers and the virq infrastructure maps those numbers into
 * a unique range of the global IRQ# space.
 *
 * To define a range of virq numbers for this controller, this driver first
 * assigns a number to each of the irq groups (called the level 1 or L1
 * value).  Within each group individual irq sources are also assigned a
 * number, as defined by the MPC5200 user guide, and refers to it as the
 * level 2 or L2 value.  The virq number is determined by shifting up the
 * L1 value by MPC52xx_IRQ_L1_OFFSET and ORing it with the L2 value.
 *
 * For example, the TMR0 interrupt is irq 9 in the main group.  The
 * virq for TMR0 is calculated by ((1 << MPC52xx_IRQ_L1_OFFSET) | 9).
 *
 * The observant reader will also notice that this driver defines a 4th
 * interrupt group called 'bestcomm'.  The bestcomm group isn't physically
 * part of the MPC5200 interrupt controller, but it is used here to assign
 * a separate virq number for each bestcomm task (since any of the 16
 * bestcomm tasks can cause the bestcomm interrupt to be raised).  When a
 * bestcomm interrupt occurs (peripheral group, irq 0) this driver determines
 * which task needs servicing and returns the irq number for that task.  This
 * allows drivers which use bestcomm to define their own interrupt handlers.
 *
 * irq_chip structures
 * -------------------
 * For actually manipulating IRQs (masking, enabling, clearing, etc) this
 * driver defines four separate 'irq_chip' structures, one for the main
 * group, one for the peripherals group, one for the bestcomm group and one
 * for external interrupts.  The irq_chip structures provide the hooks needed
 * to manipulate each IRQ source, and since each group is has a separate set
 * of registers for controlling the irq, it makes sense to divide up the
 * hooks along those lines.
 *
 * You'll notice that there is not an irq_chip for the critical group and
 * you'll also notice that there is an irq_chip defined for external
 * interrupts even though there is no external interrupt group.  The reason
 * for this is that the four external interrupts are all managed with the same
 * register even though one of the external IRQs is in the critical group and
 * the other three are in the main group.  For this reason it makes sense for
 * the 4 external irqs to be managed using a separate set of hooks.  The
 * reason there is no crit irq_chip is that of the 3 irqs in the critical
 * group, only external interrupt is actually support at this time by this
 * driver and since external interrupt is the only one used, it can just
 * be directed to make use of the external irq irq_chip.
 *
 * device tree bindings
 * --------------------
 * The device tree bindings for this controller reflect the two level
 * organization of irqs in the device.  #interrupt-cells = <3> where the
 * first cell is the group number [0..3], the second cell is the irq
 * number in the group, and the third cell is the sense type (level/edge).
 * For reference, the following is a list of the interrupt property values
 * associated with external interrupt sources on the MPC5200 (just because
 * it is non-obvious to determine what the interrupts property should be
 * when reading the mpc5200 manual and it is a frequently asked question).
 *
 * External interrupts:
 * <0 0 n>	external irq0, n is sense	(n=0: level high,
 * <1 1 n>	external irq1, n is sense	 n=1: edge rising,
 * <1 2 n>	external irq2, n is sense	 n=2: edge falling,
 * <1 3 n>	external irq3, n is sense	 n=3: level low)
 */
99 100
#undef DEBUG

101
#include <linux/interrupt.h>
102
#include <linux/irq.h>
103
#include <linux/of.h>
104 105 106 107
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/mpc52xx.h>

108 109 110 111 112 113 114 115 116 117 118 119
/* HW IRQ mapping */
#define MPC52xx_IRQ_L1_CRIT	(0)
#define MPC52xx_IRQ_L1_MAIN	(1)
#define MPC52xx_IRQ_L1_PERP	(2)
#define MPC52xx_IRQ_L1_SDMA	(3)

#define MPC52xx_IRQ_L1_OFFSET	(6)
#define MPC52xx_IRQ_L1_MASK	(0x00c0)
#define MPC52xx_IRQ_L2_MASK	(0x003f)

#define MPC52xx_IRQ_HIGHTESTHWIRQ (0xd0)

120

121
/* MPC5200 device tree match tables */
122
static const struct of_device_id mpc52xx_pic_ids[] __initconst = {
123 124 125 126
	{ .compatible = "fsl,mpc5200-pic", },
	{ .compatible = "mpc5200-pic", },
	{}
};
127
static const struct of_device_id mpc52xx_sdma_ids[] __initconst = {
128 129 130 131 132
	{ .compatible = "fsl,mpc5200-bestcomm", },
	{ .compatible = "mpc5200-bestcomm", },
	{}
};

133 134
static struct mpc52xx_intr __iomem *intr;
static struct mpc52xx_sdma __iomem *sdma;
135
static struct irq_domain *mpc52xx_irqhost = NULL;
136 137 138 139 140 141 142 143

static unsigned char mpc52xx_map_senses[4] = {
	IRQ_TYPE_LEVEL_HIGH,
	IRQ_TYPE_EDGE_RISING,
	IRQ_TYPE_EDGE_FALLING,
	IRQ_TYPE_LEVEL_LOW,
};

144
/* Utility functions */
145
static inline void io_be_setbit(u32 __iomem *addr, int bitno)
146 147 148 149
{
	out_be32(addr, in_be32(addr) | (1 << bitno));
}

150
static inline void io_be_clrbit(u32 __iomem *addr, int bitno)
151 152 153 154 155 156
{
	out_be32(addr, in_be32(addr) & ~(1 << bitno));
}

/*
 * IRQ[0-3] interrupt irq_chip
157
 */
158
static void mpc52xx_extirq_mask(struct irq_data *d)
159
{
160
	int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
161 162 163
	io_be_clrbit(&intr->ctrl, 11 - l2irq);
}

164
static void mpc52xx_extirq_unmask(struct irq_data *d)
165
{
166
	int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
167 168 169
	io_be_setbit(&intr->ctrl, 11 - l2irq);
}

170
static void mpc52xx_extirq_ack(struct irq_data *d)
171
{
172
	int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
173
	io_be_setbit(&intr->ctrl, 27-l2irq);
174 175
}

176
static int mpc52xx_extirq_set_type(struct irq_data *d, unsigned int flow_type)
177 178
{
	u32 ctrl_reg, type;
179
	int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
180
	void *handler = handle_level_irq;
181

182 183
	pr_debug("%s: irq=%x. l2=%d flow_type=%d\n", __func__,
		(int) irqd_to_hwirq(d), l2irq, flow_type);
184 185

	switch (flow_type) {
186 187 188 189
	case IRQF_TRIGGER_HIGH: type = 0; break;
	case IRQF_TRIGGER_RISING: type = 1; handler = handle_edge_irq; break;
	case IRQF_TRIGGER_FALLING: type = 2; handler = handle_edge_irq; break;
	case IRQF_TRIGGER_LOW: type = 3; break;
190 191 192 193 194 195 196 197 198
	default:
		type = 0;
	}

	ctrl_reg = in_be32(&intr->ctrl);
	ctrl_reg &= ~(0x3 << (22 - (l2irq * 2)));
	ctrl_reg |= (type << (22 - (l2irq * 2)));
	out_be32(&intr->ctrl, ctrl_reg);

199
	irq_set_handler_locked(d, handler);
200

201 202 203
	return 0;
}

204
static struct irq_chip mpc52xx_extirq_irqchip = {
205
	.name = "MPC52xx External",
206 207 208 209
	.irq_mask = mpc52xx_extirq_mask,
	.irq_unmask = mpc52xx_extirq_unmask,
	.irq_ack = mpc52xx_extirq_ack,
	.irq_set_type = mpc52xx_extirq_set_type,
210 211 212 213
};

/*
 * Main interrupt irq_chip
214
 */
215
static int mpc52xx_null_set_type(struct irq_data *d, unsigned int flow_type)
216 217 218 219
{
	return 0; /* Do nothing so that the sense mask will get updated */
}

220
static void mpc52xx_main_mask(struct irq_data *d)
221
{
222
	int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
223
	io_be_setbit(&intr->main_mask, 16 - l2irq);
224 225
}

226
static void mpc52xx_main_unmask(struct irq_data *d)
227
{
228
	int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
229
	io_be_clrbit(&intr->main_mask, 16 - l2irq);
230 231 232
}

static struct irq_chip mpc52xx_main_irqchip = {
233
	.name = "MPC52xx Main",
234 235 236 237
	.irq_mask = mpc52xx_main_mask,
	.irq_mask_ack = mpc52xx_main_mask,
	.irq_unmask = mpc52xx_main_unmask,
	.irq_set_type = mpc52xx_null_set_type,
238 239 240 241
};

/*
 * Peripherals interrupt irq_chip
242
 */
243
static void mpc52xx_periph_mask(struct irq_data *d)
244
{
245
	int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
246 247 248
	io_be_setbit(&intr->per_mask, 31 - l2irq);
}

249
static void mpc52xx_periph_unmask(struct irq_data *d)
250
{
251
	int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
252 253 254 255
	io_be_clrbit(&intr->per_mask, 31 - l2irq);
}

static struct irq_chip mpc52xx_periph_irqchip = {
256
	.name = "MPC52xx Peripherals",
257 258 259 260
	.irq_mask = mpc52xx_periph_mask,
	.irq_mask_ack = mpc52xx_periph_mask,
	.irq_unmask = mpc52xx_periph_unmask,
	.irq_set_type = mpc52xx_null_set_type,
261 262 263 264
};

/*
 * SDMA interrupt irq_chip
265
 */
266
static void mpc52xx_sdma_mask(struct irq_data *d)
267
{
268
	int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
269 270 271
	io_be_setbit(&sdma->IntMask, l2irq);
}

272
static void mpc52xx_sdma_unmask(struct irq_data *d)
273
{
274
	int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
275 276 277
	io_be_clrbit(&sdma->IntMask, l2irq);
}

278
static void mpc52xx_sdma_ack(struct irq_data *d)
279
{
280
	int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
281 282 283 284
	out_be32(&sdma->IntPend, 1 << l2irq);
}

static struct irq_chip mpc52xx_sdma_irqchip = {
285
	.name = "MPC52xx SDMA",
286 287 288 289
	.irq_mask = mpc52xx_sdma_mask,
	.irq_unmask = mpc52xx_sdma_unmask,
	.irq_ack = mpc52xx_sdma_ack,
	.irq_set_type = mpc52xx_null_set_type,
290 291
};

292 293 294 295 296 297 298 299 300
/**
 * mpc52xx_is_extirq - Returns true if hwirq number is for an external IRQ
 */
static int mpc52xx_is_extirq(int l1, int l2)
{
	return ((l1 == 0) && (l2 == 0)) ||
	       ((l1 == 1) && (l2 >= 1) && (l2 <= 3));
}

301 302 303
/**
 * mpc52xx_irqhost_xlate - translate virq# from device tree interrupts property
 */
304
static int mpc52xx_irqhost_xlate(struct irq_domain *h, struct device_node *ct,
305
				 const u32 *intspec, unsigned int intsize,
306
				 irq_hw_number_t *out_hwirq,
307 308 309 310 311 312 313 314 315 316 317 318
				 unsigned int *out_flags)
{
	int intrvect_l1;
	int intrvect_l2;
	int intrvect_type;
	int intrvect_linux;

	if (intsize != 3)
		return -1;

	intrvect_l1 = (int)intspec[0];
	intrvect_l2 = (int)intspec[1];
319
	intrvect_type = (int)intspec[2] & 0x3;
320

321 322 323
	intrvect_linux = (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) &
			 MPC52xx_IRQ_L1_MASK;
	intrvect_linux |= intrvect_l2 & MPC52xx_IRQ_L2_MASK;
324 325

	*out_hwirq = intrvect_linux;
326 327 328
	*out_flags = IRQ_TYPE_LEVEL_LOW;
	if (mpc52xx_is_extirq(intrvect_l1, intrvect_l2))
		*out_flags = mpc52xx_map_senses[intrvect_type];
329

330 331
	pr_debug("return %x, l1=%d, l2=%d\n", intrvect_linux, intrvect_l1,
		 intrvect_l2);
332 333 334
	return 0;
}

335 336 337
/**
 * mpc52xx_irqhost_map - Hook to map from virq to an irq_chip structure
 */
338
static int mpc52xx_irqhost_map(struct irq_domain *h, unsigned int virq,
339 340 341 342
			       irq_hw_number_t irq)
{
	int l1irq;
	int l2irq;
343
	struct irq_chip *uninitialized_var(irqchip);
344
	void *hndlr;
345
	int type;
346
	u32 reg;
347 348

	l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET;
349
	l2irq = irq & MPC52xx_IRQ_L2_MASK;
350 351

	/*
352 353
	 * External IRQs are handled differently by the hardware so they are
	 * handled by a dedicated irq_chip structure.
354
	 */
355 356 357 358 359 360 361 362 363
	if (mpc52xx_is_extirq(l1irq, l2irq)) {
		reg = in_be32(&intr->ctrl);
		type = mpc52xx_map_senses[(reg >> (22 - l2irq * 2)) & 0x3];
		if ((type == IRQ_TYPE_EDGE_FALLING) ||
		    (type == IRQ_TYPE_EDGE_RISING))
			hndlr = handle_edge_irq;
		else
			hndlr = handle_level_irq;

364
		irq_set_chip_and_handler(virq, &mpc52xx_extirq_irqchip, hndlr);
365 366 367 368
		pr_debug("%s: External IRQ%i virq=%x, hw=%x. type=%x\n",
			 __func__, l2irq, virq, (int)irq, type);
		return 0;
	}
369

370
	/* It is an internal SOC irq.  Choose the correct irq_chip */
371
	switch (l1irq) {
372 373 374
	case MPC52xx_IRQ_L1_MAIN: irqchip = &mpc52xx_main_irqchip; break;
	case MPC52xx_IRQ_L1_PERP: irqchip = &mpc52xx_periph_irqchip; break;
	case MPC52xx_IRQ_L1_SDMA: irqchip = &mpc52xx_sdma_irqchip; break;
375 376
	case MPC52xx_IRQ_L1_CRIT:
		pr_warn("%s: Critical IRQ #%d is unsupported! Nopping it.\n",
377
			__func__, l2irq);
378 379
		irq_set_chip(virq, &no_irq_chip);
		return 0;
380 381
	}

382
	irq_set_chip_and_handler(virq, irqchip, handle_level_irq);
383
	pr_debug("%s: virq=%x, l1=%i, l2=%i\n", __func__, virq, l1irq, l2irq);
384 385 386 387

	return 0;
}

388
static const struct irq_domain_ops mpc52xx_irqhost_ops = {
389 390 391 392
	.xlate = mpc52xx_irqhost_xlate,
	.map = mpc52xx_irqhost_map,
};

393 394 395 396 397 398 399 400 401
/**
 * mpc52xx_init_irq - Initialize and register with the virq subsystem
 *
 * Hook for setting up IRQs on an mpc5200 system.  A pointer to this function
 * is to be put into the machine definition structure.
 *
 * This function searches the device tree for an MPC5200 interrupt controller,
 * initializes it, and registers it with the virq subsystem.
 */
402 403 404
void __init mpc52xx_init_irq(void)
{
	u32 intr_ctrl;
405
	struct device_node *picnode;
406
	struct device_node *np;
407 408

	/* Remap the necessary zones */
409
	picnode = of_find_matching_node(NULL, mpc52xx_pic_ids);
410
	intr = of_iomap(picnode, 0);
411
	if (!intr)
412
		panic(__FILE__	": find_and_map failed on 'mpc5200-pic'. "
413
				"Check node !");
414

415
	np = of_find_matching_node(NULL, mpc52xx_sdma_ids);
416 417
	sdma = of_iomap(np, 0);
	of_node_put(np);
418
	if (!sdma)
419
		panic(__FILE__	": find_and_map failed on 'mpc5200-bestcomm'. "
420
				"Check node !");
421

422 423
	pr_debug("MPC5200 IRQ controller mapped to 0x%p\n", intr);

424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
	/* Disable all interrupt sources. */
	out_be32(&sdma->IntPend, 0xffffffff);	/* 1 means clear pending */
	out_be32(&sdma->IntMask, 0xffffffff);	/* 1 means disabled */
	out_be32(&intr->per_mask, 0x7ffffc00);	/* 1 means disabled */
	out_be32(&intr->main_mask, 0x00010fff);	/* 1 means disabled */
	intr_ctrl = in_be32(&intr->ctrl);
	intr_ctrl &= 0x00ff0000;	/* Keeps IRQ[0-3] config */
	intr_ctrl |=	0x0f000000 |	/* clear IRQ 0-3 */
			0x00001000 |	/* MEE master external enable */
			0x00000000 |	/* 0 means disable IRQ 0-3 */
			0x00000001;	/* CEb route critical normally */
	out_be32(&intr->ctrl, intr_ctrl);

	/* Zero a bunch of the priority settings. */
	out_be32(&intr->per_pri1, 0);
	out_be32(&intr->per_pri2, 0);
	out_be32(&intr->per_pri3, 0);
	out_be32(&intr->main_pri1, 0);
	out_be32(&intr->main_pri2, 0);

	/*
	 * As last step, add an irq host to translate the real
	 * hw irq information provided by the ofw to linux virq
	 */
448
	mpc52xx_irqhost = irq_domain_add_linear(picnode,
449
	                                 MPC52xx_IRQ_HIGHTESTHWIRQ,
450
	                                 &mpc52xx_irqhost_ops, NULL);
451

452 453
	if (!mpc52xx_irqhost)
		panic(__FILE__ ": Cannot allocate the IRQ host\n");
454

455 456
	irq_set_default_host(mpc52xx_irqhost);

457
	pr_info("MPC52xx PIC is up and running!\n");
458 459
}

460 461 462
/**
 * mpc52xx_get_irq - Get pending interrupt number hook function
 *
L
Lucas De Marchi 已提交
463
 * Called by the interrupt handler to determine what IRQ handler needs to be
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
 * executed.
 *
 * Status of pending interrupts is determined by reading the encoded status
 * register.  The encoded status register has three fields; one for each of the
 * types of interrupts defined by the controller - 'critical', 'main' and
 * 'peripheral'.  This function reads the status register and returns the IRQ
 * number associated with the highest priority pending interrupt.  'Critical'
 * interrupts have the highest priority, followed by 'main' interrupts, and
 * then 'peripheral'.
 *
 * The mpc5200 interrupt controller can be configured to boost the priority
 * of individual 'peripheral' interrupts.  If this is the case then a special
 * value will appear in either the crit or main fields indicating a high
 * or medium priority peripheral irq has occurred.
 *
 * This function checks each of the 3 irq request fields and returns the
 * first pending interrupt that it finds.
 *
 * This function also identifies a 4th type of interrupt; 'bestcomm'.  Each
 * bestcomm DMA task can raise the bestcomm peripheral interrupt.  When this
 * occurs at task-specific IRQ# is decoded so that each task can have its
 * own IRQ handler.
 */
487 488 489
unsigned int mpc52xx_get_irq(void)
{
	u32 status;
490
	int irq;
491 492 493 494 495 496

	status = in_be32(&intr->enc_status);
	if (status & 0x00000400) {	/* critical */
		irq = (status >> 8) & 0x3;
		if (irq == 2)	/* high priority peripheral */
			goto peripheral;
497
		irq |= (MPC52xx_IRQ_L1_CRIT << MPC52xx_IRQ_L1_OFFSET);
498 499 500 501
	} else if (status & 0x00200000) {	/* main */
		irq = (status >> 16) & 0x1f;
		if (irq == 4)	/* low priority peripheral */
			goto peripheral;
502
		irq |= (MPC52xx_IRQ_L1_MAIN << MPC52xx_IRQ_L1_OFFSET);
503 504 505 506 507 508
	} else if (status & 0x20000000) {	/* peripheral */
	      peripheral:
		irq = (status >> 24) & 0x1f;
		if (irq == 0) {	/* bestcomm */
			status = in_be32(&sdma->IntPend);
			irq = ffs(status) - 1;
509
			irq |= (MPC52xx_IRQ_L1_SDMA << MPC52xx_IRQ_L1_OFFSET);
510
		} else {
511
			irq |= (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET);
512
		}
513 514
	} else {
		return NO_IRQ;
515 516 517 518
	}

	return irq_linear_revmap(mpc52xx_irqhost, irq);
}