646 lines · 13.2 KB · C
RawDownload
/* * include/asm-ppc/ipic.c * * IPIC routines implementations. * * Copyright 2005 Freescale Semiconductor, Inc. * * 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 <asm/irq.h>#include <asm/io.h>#include <asm/ipic.h>#include <asm/mpc83xx.h> #include "ipic.h" static struct ipic p_ipic;static struct ipic * primary_ipic; static struct ipic_info ipic_info[] = {	[9] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_D,		.force	= IPIC_SIFCR_H,		.bit	= 24,		.prio_mask = 0,	},	[10] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_D,		.force	= IPIC_SIFCR_H,		.bit	= 25,		.prio_mask = 1,	},	[11] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_D,		.force	= IPIC_SIFCR_H,		.bit	= 26,		.prio_mask = 2,	},	[14] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_D,		.force	= IPIC_SIFCR_H,		.bit	= 29,		.prio_mask = 5,	},	[15] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_D,		.force	= IPIC_SIFCR_H,		.bit	= 30,		.prio_mask = 6,	},	[16] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_D,		.force	= IPIC_SIFCR_H,		.bit	= 31,		.prio_mask = 7,	},	[17] = {		.pend	= IPIC_SEPNR,		.mask	= IPIC_SEMSR,		.prio	= IPIC_SMPRR_A,		.force	= IPIC_SEFCR,		.bit	= 1,		.prio_mask = 5,	},	[18] = {		.pend	= IPIC_SEPNR,		.mask	= IPIC_SEMSR,		.prio	= IPIC_SMPRR_A,		.force	= IPIC_SEFCR,		.bit	= 2,		.prio_mask = 6,	},	[19] = {		.pend	= IPIC_SEPNR,		.mask	= IPIC_SEMSR,		.prio	= IPIC_SMPRR_A,		.force	= IPIC_SEFCR,		.bit	= 3,		.prio_mask = 7,	},	[20] = {		.pend	= IPIC_SEPNR,		.mask	= IPIC_SEMSR,		.prio	= IPIC_SMPRR_B,		.force	= IPIC_SEFCR,		.bit	= 4,		.prio_mask = 4,	},	[21] = {		.pend	= IPIC_SEPNR,		.mask	= IPIC_SEMSR,		.prio	= IPIC_SMPRR_B,		.force	= IPIC_SEFCR,		.bit	= 5,		.prio_mask = 5,	},	[22] = {		.pend	= IPIC_SEPNR,		.mask	= IPIC_SEMSR,		.prio	= IPIC_SMPRR_B,		.force	= IPIC_SEFCR,		.bit	= 6,		.prio_mask = 6,	},	[23] = {		.pend	= IPIC_SEPNR,		.mask	= IPIC_SEMSR,		.prio	= IPIC_SMPRR_B,		.force	= IPIC_SEFCR,		.bit	= 7,		.prio_mask = 7,	},	[32] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_A,		.force	= IPIC_SIFCR_H,		.bit	= 0,		.prio_mask = 0,	},	[33] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_A,		.force	= IPIC_SIFCR_H,		.bit	= 1,		.prio_mask = 1,	},	[34] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_A,		.force	= IPIC_SIFCR_H,		.bit	= 2,		.prio_mask = 2,	},	[35] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_A,		.force	= IPIC_SIFCR_H,		.bit	= 3,		.prio_mask = 3,	},	[36] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_A,		.force	= IPIC_SIFCR_H,		.bit	= 4,		.prio_mask = 4,	},	[37] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_A,		.force	= IPIC_SIFCR_H,		.bit	= 5,		.prio_mask = 5,	},	[38] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_A,		.force	= IPIC_SIFCR_H,		.bit	= 6,		.prio_mask = 6,	},	[39] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_A,		.force	= IPIC_SIFCR_H,		.bit	= 7,		.prio_mask = 7,	},	[48] = {		.pend	= IPIC_SEPNR,		.mask	= IPIC_SEMSR,		.prio	= IPIC_SMPRR_A,		.force	= IPIC_SEFCR,		.bit	= 0,		.prio_mask = 4,	},	[64] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_L,		.prio	= IPIC_SMPRR_A,		.force	= IPIC_SIFCR_L,		.bit	= 0,		.prio_mask = 0,	},	[65] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_L,		.prio	= IPIC_SMPRR_A,		.force	= IPIC_SIFCR_L,		.bit	= 1,		.prio_mask = 1,	},	[66] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_L,		.prio	= IPIC_SMPRR_A,		.force	= IPIC_SIFCR_L,		.bit	= 2,		.prio_mask = 2,	},	[67] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_L,		.prio	= IPIC_SMPRR_A,		.force	= IPIC_SIFCR_L,		.bit	= 3,		.prio_mask = 3,	},	[68] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_L,		.prio	= IPIC_SMPRR_B,		.force	= IPIC_SIFCR_L,		.bit	= 4,		.prio_mask = 0,	},	[69] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_L,		.prio	= IPIC_SMPRR_B,		.force	= IPIC_SIFCR_L,		.bit	= 5,		.prio_mask = 1,	},	[70] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_L,		.prio	= IPIC_SMPRR_B,		.force	= IPIC_SIFCR_L,		.bit	= 6,		.prio_mask = 2,	},	[71] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_L,		.prio	= IPIC_SMPRR_B,		.force	= IPIC_SIFCR_L,		.bit	= 7,		.prio_mask = 3,	},	[72] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 8,	},	[73] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 9,	},	[74] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 10,	},	[75] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 11,	},	[76] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 12,	},	[77] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 13,	},	[78] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 14,	},	[79] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 15,	},	[80] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 16,	},	[84] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 20,	},	[85] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 21,	},	[90] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 26,	},	[91] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 27,	},}; static inline u32 ipic_read(volatile u32 __iomem *base, unsigned int reg){	return in_be32(base + (reg >> 2));} static inline void ipic_write(volatile u32 __iomem *base, unsigned int reg, u32 value){	out_be32(base + (reg >> 2), value);} static inline struct ipic * ipic_from_irq(unsigned int irq){	return primary_ipic;} static void ipic_enable_irq(unsigned int irq){	struct ipic *ipic = ipic_from_irq(irq);	unsigned int src = irq - ipic->irq_offset;	u32 temp; 	temp = ipic_read(ipic->regs, ipic_info[src].mask);	temp |= (1 << (31 - ipic_info[src].bit));	ipic_write(ipic->regs, ipic_info[src].mask, temp);} static void ipic_disable_irq(unsigned int irq){	struct ipic *ipic = ipic_from_irq(irq);	unsigned int src = irq - ipic->irq_offset;	u32 temp; 	temp = ipic_read(ipic->regs, ipic_info[src].mask);	temp &= ~(1 << (31 - ipic_info[src].bit));	ipic_write(ipic->regs, ipic_info[src].mask, temp);} static void ipic_disable_irq_and_ack(unsigned int irq){	struct ipic *ipic = ipic_from_irq(irq);	unsigned int src = irq - ipic->irq_offset;	u32 temp; 	ipic_disable_irq(irq); 	temp = ipic_read(ipic->regs, ipic_info[src].pend);	temp |= (1 << (31 - ipic_info[src].bit));	ipic_write(ipic->regs, ipic_info[src].pend, temp);} static void ipic_end_irq(unsigned int irq){	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))		ipic_enable_irq(irq);} struct hw_interrupt_type ipic = {	.typename = " IPIC  ",	.enable = ipic_enable_irq,	.disable = ipic_disable_irq,	.ack = ipic_disable_irq_and_ack,	.end = ipic_end_irq,}; void __init ipic_init(phys_addr_t phys_addr,		unsigned int flags,		unsigned int irq_offset,		unsigned char *senses,		unsigned int senses_count){	u32 i, temp = 0; 	primary_ipic = &p_ipic;	primary_ipic->regs = ioremap(phys_addr, MPC83xx_IPIC_SIZE); 	primary_ipic->irq_offset = irq_offset; 	ipic_write(primary_ipic->regs, IPIC_SICNR, 0x0); 	/* default priority scheme is grouped. If spread mode is required	 * configure SICFR accordingly */	if (flags & IPIC_SPREADMODE_GRP_A)		temp |= SICFR_IPSA;	if (flags & IPIC_SPREADMODE_GRP_D)		temp |= SICFR_IPSD;	if (flags & IPIC_SPREADMODE_MIX_A)		temp |= SICFR_MPSA;	if (flags & IPIC_SPREADMODE_MIX_B)		temp |= SICFR_MPSB; 	ipic_write(primary_ipic->regs, IPIC_SICNR, temp); 	/* handle MCP route */	temp = 0;	if (flags & IPIC_DISABLE_MCP_OUT)		temp = SERCR_MCPR;	ipic_write(primary_ipic->regs, IPIC_SERCR, temp); 	/* handle routing of IRQ0 to MCP */	temp = ipic_read(primary_ipic->regs, IPIC_SEMSR); 	if (flags & IPIC_IRQ0_MCP)		temp |= SEMSR_SIRQ0;	else		temp &= ~SEMSR_SIRQ0; 	ipic_write(primary_ipic->regs, IPIC_SEMSR, temp); 	for (i = 0 ; i < NR_IPIC_INTS ; i++) {		irq_desc[i+irq_offset].chip = &ipic;		irq_desc[i+irq_offset].status = IRQ_LEVEL;	} 	temp = 0;	for (i = 0 ; i < senses_count ; i++) {		if ((senses[i] & IRQ_SENSE_MASK) == IRQ_SENSE_EDGE) {			temp |= 1 << (15 - i);			if (i != 0)				irq_desc[i + irq_offset + MPC83xx_IRQ_EXT1 - 1].status = 0;			else				irq_desc[irq_offset + MPC83xx_IRQ_EXT0].status = 0;		}	}	ipic_write(primary_ipic->regs, IPIC_SECNR, temp); 	printk ("IPIC (%d IRQ sources, %d External IRQs) at %p\n", NR_IPIC_INTS,			senses_count, primary_ipic->regs);} int ipic_set_priority(unsigned int irq, unsigned int priority){	struct ipic *ipic = ipic_from_irq(irq);	unsigned int src = irq - ipic->irq_offset;	u32 temp; 

Lines 1–500 of 646.