⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mpc52xx_pic.c

📁 linux内核源码
💻 C
字号:
/* * * Programmable Interrupt Controller functions for the Freescale MPC52xx. * * Copyright (C) 2006 bplan GmbH * * Based on the code from the 2.4 kernel by * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg. * * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com> * Copyright (C) 2003 Montavista Software, Inc * * 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. * */#undef DEBUG#include <linux/irq.h>#include <linux/of.h>#include <asm/io.h>#include <asm/prom.h>#include <asm/mpc52xx.h>#include "mpc52xx_pic.h"/* **/static struct mpc52xx_intr __iomem *intr;static struct mpc52xx_sdma __iomem *sdma;static struct irq_host *mpc52xx_irqhost = NULL;static unsigned char mpc52xx_map_senses[4] = {	IRQ_TYPE_LEVEL_HIGH,	IRQ_TYPE_EDGE_RISING,	IRQ_TYPE_EDGE_FALLING,	IRQ_TYPE_LEVEL_LOW,};/* **/static inline void io_be_setbit(u32 __iomem *addr, int bitno){	out_be32(addr, in_be32(addr) | (1 << bitno));}static inline void io_be_clrbit(u32 __iomem *addr, int bitno){	out_be32(addr, in_be32(addr) & ~(1 << bitno));}/* * IRQ[0-3] interrupt irq_chip*/static void mpc52xx_extirq_mask(unsigned int virq){	int irq;	int l2irq;	irq = irq_map[virq].hwirq;	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);	io_be_clrbit(&intr->ctrl, 11 - l2irq);}static void mpc52xx_extirq_unmask(unsigned int virq){	int irq;	int l2irq;	irq = irq_map[virq].hwirq;	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);	io_be_setbit(&intr->ctrl, 11 - l2irq);}static void mpc52xx_extirq_ack(unsigned int virq){	int irq;	int l2irq;	irq = irq_map[virq].hwirq;	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);	io_be_setbit(&intr->ctrl, 27-l2irq);}static struct irq_chip mpc52xx_extirq_irqchip = {	.typename = " MPC52xx IRQ[0-3] ",	.mask = mpc52xx_extirq_mask,	.unmask = mpc52xx_extirq_unmask,	.ack = mpc52xx_extirq_ack,};/* * Main interrupt irq_chip*/static void mpc52xx_main_mask(unsigned int virq){	int irq;	int l2irq;	irq = irq_map[virq].hwirq;	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);	io_be_setbit(&intr->main_mask, 16 - l2irq);}static void mpc52xx_main_unmask(unsigned int virq){	int irq;	int l2irq;	irq = irq_map[virq].hwirq;	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);	io_be_clrbit(&intr->main_mask, 16 - l2irq);}static struct irq_chip mpc52xx_main_irqchip = {	.typename = "MPC52xx Main",	.mask = mpc52xx_main_mask,	.mask_ack = mpc52xx_main_mask,	.unmask = mpc52xx_main_unmask,};/* * Peripherals interrupt irq_chip*/static void mpc52xx_periph_mask(unsigned int virq){	int irq;	int l2irq;	irq = irq_map[virq].hwirq;	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);	io_be_setbit(&intr->per_mask, 31 - l2irq);}static void mpc52xx_periph_unmask(unsigned int virq){	int irq;	int l2irq;	irq = irq_map[virq].hwirq;	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);	io_be_clrbit(&intr->per_mask, 31 - l2irq);}static struct irq_chip mpc52xx_periph_irqchip = {	.typename = "MPC52xx Peripherals",	.mask = mpc52xx_periph_mask,	.mask_ack = mpc52xx_periph_mask,	.unmask = mpc52xx_periph_unmask,};/* * SDMA interrupt irq_chip*/static void mpc52xx_sdma_mask(unsigned int virq){	int irq;	int l2irq;	irq = irq_map[virq].hwirq;	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);	io_be_setbit(&sdma->IntMask, l2irq);}static void mpc52xx_sdma_unmask(unsigned int virq){	int irq;	int l2irq;	irq = irq_map[virq].hwirq;	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);	io_be_clrbit(&sdma->IntMask, l2irq);}static void mpc52xx_sdma_ack(unsigned int virq){	int irq;	int l2irq;	irq = irq_map[virq].hwirq;	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);	out_be32(&sdma->IntPend, 1 << l2irq);}static struct irq_chip mpc52xx_sdma_irqchip = {	.typename = "MPC52xx SDMA",	.mask = mpc52xx_sdma_mask,	.unmask = mpc52xx_sdma_unmask,	.ack = mpc52xx_sdma_ack,};/* * irq_host*/static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct,				 u32 * intspec, unsigned int intsize,				 irq_hw_number_t * out_hwirq,				 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];	intrvect_type = (int)intspec[2];	intrvect_linux =	    (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) & MPC52xx_IRQ_L1_MASK;	intrvect_linux |=	    (intrvect_l2 << MPC52xx_IRQ_L2_OFFSET) & MPC52xx_IRQ_L2_MASK;	pr_debug("return %x, l1=%d, l2=%d\n", intrvect_linux, intrvect_l1,		 intrvect_l2);	*out_hwirq = intrvect_linux;	*out_flags = mpc52xx_map_senses[intrvect_type];	return 0;}/* * this function retrieves the correct IRQ type out * of the MPC regs * Only externals IRQs needs this*/static int mpc52xx_irqx_gettype(int irq){	int type;	u32 ctrl_reg;	ctrl_reg = in_be32(&intr->ctrl);	type = (ctrl_reg >> (22 - irq * 2)) & 0x3;	return mpc52xx_map_senses[type];}static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq,			       irq_hw_number_t irq){	int l1irq;	int l2irq;	struct irq_chip *good_irqchip;	void *good_handle;	int type;	l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET;	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;	/*	 * Most of ours IRQs will be level low	 * Only external IRQs on some platform may be others	 */	type = IRQ_TYPE_LEVEL_LOW;	switch (l1irq) {	case MPC52xx_IRQ_L1_CRIT:		pr_debug("%s: Critical. l2=%x\n", __func__, l2irq);		BUG_ON(l2irq != 0);		type = mpc52xx_irqx_gettype(l2irq);		good_irqchip = &mpc52xx_extirq_irqchip;		break;	case MPC52xx_IRQ_L1_MAIN:		pr_debug("%s: Main IRQ[1-3] l2=%x\n", __func__, l2irq);		if ((l2irq >= 1) && (l2irq <= 3)) {			type = mpc52xx_irqx_gettype(l2irq);			good_irqchip = &mpc52xx_extirq_irqchip;		} else {			good_irqchip = &mpc52xx_main_irqchip;		}		break;	case MPC52xx_IRQ_L1_PERP:		pr_debug("%s: Peripherals. l2=%x\n", __func__, l2irq);		good_irqchip = &mpc52xx_periph_irqchip;		break;	case MPC52xx_IRQ_L1_SDMA:		pr_debug("%s: SDMA. l2=%x\n", __func__, l2irq);		good_irqchip = &mpc52xx_sdma_irqchip;		break;	default:		pr_debug("%s: Error, unknown L1 IRQ (0x%x)\n", __func__, l1irq);		printk(KERN_ERR "Unknow IRQ!\n");		return -EINVAL;	}	switch (type) {	case IRQ_TYPE_EDGE_FALLING:	case IRQ_TYPE_EDGE_RISING:		good_handle = handle_edge_irq;		break;	default:		good_handle = handle_level_irq;	}	set_irq_chip_and_handler(virq, good_irqchip, good_handle);	pr_debug("%s: virq=%x, hw=%x. type=%x\n", __func__, virq,		 (int)irq, type);	return 0;}static struct irq_host_ops mpc52xx_irqhost_ops = {	.xlate = mpc52xx_irqhost_xlate,	.map = mpc52xx_irqhost_map,};/* * init (public)*/void __init mpc52xx_init_irq(void){	u32 intr_ctrl;	struct device_node *picnode;	/* Remap the necessary zones */	picnode = of_find_compatible_node(NULL, NULL, "mpc5200-pic");	intr = mpc52xx_find_and_map("mpc5200-pic");	if (!intr)		panic(__FILE__	": find_and_map failed on 'mpc5200-pic'. "				"Check node !");	sdma = mpc52xx_find_and_map("mpc5200-bestcomm");	if (!sdma)		panic(__FILE__	": find_and_map failed on 'mpc5200-bestcomm'. "				"Check node !");	/* 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	 */	mpc52xx_irqhost = irq_alloc_host(picnode, IRQ_HOST_MAP_LINEAR,	                                 MPC52xx_IRQ_HIGHTESTHWIRQ,	                                 &mpc52xx_irqhost_ops, -1);	if (!mpc52xx_irqhost)		panic(__FILE__ ": Cannot allocate the IRQ host\n");	printk(KERN_INFO "MPC52xx PIC is up and running!\n");}/* * get_irq (public)*/unsigned int mpc52xx_get_irq(void){	u32 status;	int irq = NO_IRQ_IGNORE;	status = in_be32(&intr->enc_status);	if (status & 0x00000400) {	/* critical */		irq = (status >> 8) & 0x3;		if (irq == 2)	/* high priority peripheral */			goto peripheral;		irq |=	(MPC52xx_IRQ_L1_CRIT << MPC52xx_IRQ_L1_OFFSET) &			MPC52xx_IRQ_L1_MASK;	} else if (status & 0x00200000) {	/* main */		irq = (status >> 16) & 0x1f;		if (irq == 4)	/* low priority peripheral */			goto peripheral;		irq |=	(MPC52xx_IRQ_L1_MAIN << MPC52xx_IRQ_L1_OFFSET) &			MPC52xx_IRQ_L1_MASK;	} else if (status & 0x20000000) {	/* peripheral */	      peripheral:		irq = (status >> 24) & 0x1f;		if (irq == 0) {	/* bestcomm */			status = in_be32(&sdma->IntPend);			irq = ffs(status) - 1;			irq |=	(MPC52xx_IRQ_L1_SDMA << MPC52xx_IRQ_L1_OFFSET) &				MPC52xx_IRQ_L1_MASK;		} else {			irq |=	(MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET) &				MPC52xx_IRQ_L1_MASK;		}	}	pr_debug("%s: irq=%x. virq=%d\n", __func__, irq,		 irq_linear_revmap(mpc52xx_irqhost, irq));	return irq_linear_revmap(mpc52xx_irqhost, irq);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -