 26a2056eb2
			
		
	
	
	26a2056eb2
	
	
	
		
			
			When removing prom.h include by of.h, several OF headers will no longer be implicitly included. Add explicit includes of of_*.h as needed. Signed-off-by: Rob Herring <rob.herring@calxeda.com> Acked-by: Grant Likely <grant.likely@linaro.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Anatolij Gustschin <agust@denx.de> Cc: Kumar Gala <galak@kernel.crashing.org> Cc: Olof Johansson <olof@lixom.net> Cc: linuxppc-dev@lists.ozlabs.org
		
			
				
	
	
		
			314 lines
		
	
	
	
		
			8.4 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			314 lines
		
	
	
	
		
			8.4 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  *  Copyright (C) 2008 Ilya Yanok, Emcraft Systems
 | |
|  *
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or modify
 | |
|  * it under the terms of the GNU General Public License version 2 as
 | |
|  * published by the Free Software Foundation.
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #include <linux/irq.h>
 | |
| #include <linux/of_address.h>
 | |
| #include <linux/of_irq.h>
 | |
| #include <linux/of_platform.h>
 | |
| #include <linux/io.h>
 | |
| 
 | |
| /*
 | |
|  * The FPGA supports 9 interrupt sources, which can be routed to 3
 | |
|  * interrupt request lines of the MPIC. The line to be used can be
 | |
|  * specified through the third cell of FDT property  "interrupts".
 | |
|  */
 | |
| 
 | |
| #define SOCRATES_FPGA_NUM_IRQS	9
 | |
| 
 | |
| #define FPGA_PIC_IRQCFG		(0x0)
 | |
| #define FPGA_PIC_IRQMASK(n)	(0x4 + 0x4 * (n))
 | |
| 
 | |
| #define SOCRATES_FPGA_IRQ_MASK	((1 << SOCRATES_FPGA_NUM_IRQS) - 1)
 | |
| 
 | |
| struct socrates_fpga_irq_info {
 | |
| 	unsigned int irq_line;
 | |
| 	int type;
 | |
| };
 | |
| 
 | |
| /*
 | |
|  * Interrupt routing and type table
 | |
|  *
 | |
|  * IRQ_TYPE_NONE means the interrupt type is configurable,
 | |
|  * otherwise it's fixed to the specified value.
 | |
|  */
 | |
| static struct socrates_fpga_irq_info fpga_irqs[SOCRATES_FPGA_NUM_IRQS] = {
 | |
| 	[0] = {0, IRQ_TYPE_NONE},
 | |
| 	[1] = {0, IRQ_TYPE_LEVEL_HIGH},
 | |
| 	[2] = {0, IRQ_TYPE_LEVEL_LOW},
 | |
| 	[3] = {0, IRQ_TYPE_NONE},
 | |
| 	[4] = {0, IRQ_TYPE_NONE},
 | |
| 	[5] = {0, IRQ_TYPE_NONE},
 | |
| 	[6] = {0, IRQ_TYPE_NONE},
 | |
| 	[7] = {0, IRQ_TYPE_NONE},
 | |
| 	[8] = {0, IRQ_TYPE_LEVEL_HIGH},
 | |
| };
 | |
| 
 | |
| static DEFINE_RAW_SPINLOCK(socrates_fpga_pic_lock);
 | |
| 
 | |
| static void __iomem *socrates_fpga_pic_iobase;
 | |
| static struct irq_domain *socrates_fpga_pic_irq_host;
 | |
| static unsigned int socrates_fpga_irqs[3];
 | |
| 
 | |
| static inline uint32_t socrates_fpga_pic_read(int reg)
 | |
| {
 | |
| 	return in_be32(socrates_fpga_pic_iobase + reg);
 | |
| }
 | |
| 
 | |
| static inline void socrates_fpga_pic_write(int reg, uint32_t val)
 | |
| {
 | |
| 	out_be32(socrates_fpga_pic_iobase + reg, val);
 | |
| }
 | |
| 
 | |
| static inline unsigned int socrates_fpga_pic_get_irq(unsigned int irq)
 | |
| {
 | |
| 	uint32_t cause;
 | |
| 	unsigned long flags;
 | |
| 	int i;
 | |
| 
 | |
| 	/* Check irq line routed to the MPIC */
 | |
| 	for (i = 0; i < 3; i++) {
 | |
| 		if (irq == socrates_fpga_irqs[i])
 | |
| 			break;
 | |
| 	}
 | |
| 	if (i == 3)
 | |
| 		return NO_IRQ;
 | |
| 
 | |
| 	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
 | |
| 	cause = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(i));
 | |
| 	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
 | |
| 	for (i = SOCRATES_FPGA_NUM_IRQS - 1; i >= 0; i--) {
 | |
| 		if (cause >> (i + 16))
 | |
| 			break;
 | |
| 	}
 | |
| 	return irq_linear_revmap(socrates_fpga_pic_irq_host,
 | |
| 			(irq_hw_number_t)i);
 | |
| }
 | |
| 
 | |
| void socrates_fpga_pic_cascade(unsigned int irq, struct irq_desc *desc)
 | |
| {
 | |
| 	struct irq_chip *chip = irq_desc_get_chip(desc);
 | |
| 	unsigned int cascade_irq;
 | |
| 
 | |
| 	/*
 | |
| 	 * See if we actually have an interrupt, call generic handling code if
 | |
| 	 * we do.
 | |
| 	 */
 | |
| 	cascade_irq = socrates_fpga_pic_get_irq(irq);
 | |
| 
 | |
| 	if (cascade_irq != NO_IRQ)
 | |
| 		generic_handle_irq(cascade_irq);
 | |
| 	chip->irq_eoi(&desc->irq_data);
 | |
| }
 | |
| 
 | |
| static void socrates_fpga_pic_ack(struct irq_data *d)
 | |
| {
 | |
| 	unsigned long flags;
 | |
| 	unsigned int irq_line, hwirq = irqd_to_hwirq(d);
 | |
| 	uint32_t mask;
 | |
| 
 | |
| 	irq_line = fpga_irqs[hwirq].irq_line;
 | |
| 	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
 | |
| 	mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
 | |
| 		& SOCRATES_FPGA_IRQ_MASK;
 | |
| 	mask |= (1 << (hwirq + 16));
 | |
| 	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
 | |
| 	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
 | |
| }
 | |
| 
 | |
| static void socrates_fpga_pic_mask(struct irq_data *d)
 | |
| {
 | |
| 	unsigned long flags;
 | |
| 	unsigned int hwirq = irqd_to_hwirq(d);
 | |
| 	int irq_line;
 | |
| 	u32 mask;
 | |
| 
 | |
| 	irq_line = fpga_irqs[hwirq].irq_line;
 | |
| 	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
 | |
| 	mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
 | |
| 		& SOCRATES_FPGA_IRQ_MASK;
 | |
| 	mask &= ~(1 << hwirq);
 | |
| 	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
 | |
| 	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
 | |
| }
 | |
| 
 | |
| static void socrates_fpga_pic_mask_ack(struct irq_data *d)
 | |
| {
 | |
| 	unsigned long flags;
 | |
| 	unsigned int hwirq = irqd_to_hwirq(d);
 | |
| 	int irq_line;
 | |
| 	u32 mask;
 | |
| 
 | |
| 	irq_line = fpga_irqs[hwirq].irq_line;
 | |
| 	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
 | |
| 	mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
 | |
| 		& SOCRATES_FPGA_IRQ_MASK;
 | |
| 	mask &= ~(1 << hwirq);
 | |
| 	mask |= (1 << (hwirq + 16));
 | |
| 	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
 | |
| 	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
 | |
| }
 | |
| 
 | |
| static void socrates_fpga_pic_unmask(struct irq_data *d)
 | |
| {
 | |
| 	unsigned long flags;
 | |
| 	unsigned int hwirq = irqd_to_hwirq(d);
 | |
| 	int irq_line;
 | |
| 	u32 mask;
 | |
| 
 | |
| 	irq_line = fpga_irqs[hwirq].irq_line;
 | |
| 	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
 | |
| 	mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
 | |
| 		& SOCRATES_FPGA_IRQ_MASK;
 | |
| 	mask |= (1 << hwirq);
 | |
| 	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
 | |
| 	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
 | |
| }
 | |
| 
 | |
| static void socrates_fpga_pic_eoi(struct irq_data *d)
 | |
| {
 | |
| 	unsigned long flags;
 | |
| 	unsigned int hwirq = irqd_to_hwirq(d);
 | |
| 	int irq_line;
 | |
| 	u32 mask;
 | |
| 
 | |
| 	irq_line = fpga_irqs[hwirq].irq_line;
 | |
| 	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
 | |
| 	mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
 | |
| 		& SOCRATES_FPGA_IRQ_MASK;
 | |
| 	mask |= (1 << (hwirq + 16));
 | |
| 	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
 | |
| 	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
 | |
| }
 | |
| 
 | |
| static int socrates_fpga_pic_set_type(struct irq_data *d,
 | |
| 		unsigned int flow_type)
 | |
| {
 | |
| 	unsigned long flags;
 | |
| 	unsigned int hwirq = irqd_to_hwirq(d);
 | |
| 	int polarity;
 | |
| 	u32 mask;
 | |
| 
 | |
| 	if (fpga_irqs[hwirq].type != IRQ_TYPE_NONE)
 | |
| 		return -EINVAL;
 | |
| 
 | |
| 	switch (flow_type & IRQ_TYPE_SENSE_MASK) {
 | |
| 	case IRQ_TYPE_LEVEL_HIGH:
 | |
| 		polarity = 1;
 | |
| 		break;
 | |
| 	case IRQ_TYPE_LEVEL_LOW:
 | |
| 		polarity = 0;
 | |
| 		break;
 | |
| 	default:
 | |
| 		return -EINVAL;
 | |
| 	}
 | |
| 	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
 | |
| 	mask = socrates_fpga_pic_read(FPGA_PIC_IRQCFG);
 | |
| 	if (polarity)
 | |
| 		mask |= (1 << hwirq);
 | |
| 	else
 | |
| 		mask &= ~(1 << hwirq);
 | |
| 	socrates_fpga_pic_write(FPGA_PIC_IRQCFG, mask);
 | |
| 	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static struct irq_chip socrates_fpga_pic_chip = {
 | |
| 	.name		= "FPGA-PIC",
 | |
| 	.irq_ack	= socrates_fpga_pic_ack,
 | |
| 	.irq_mask	= socrates_fpga_pic_mask,
 | |
| 	.irq_mask_ack	= socrates_fpga_pic_mask_ack,
 | |
| 	.irq_unmask	= socrates_fpga_pic_unmask,
 | |
| 	.irq_eoi	= socrates_fpga_pic_eoi,
 | |
| 	.irq_set_type	= socrates_fpga_pic_set_type,
 | |
| };
 | |
| 
 | |
| static int socrates_fpga_pic_host_map(struct irq_domain *h, unsigned int virq,
 | |
| 		irq_hw_number_t hwirq)
 | |
| {
 | |
| 	/* All interrupts are LEVEL sensitive */
 | |
| 	irq_set_status_flags(virq, IRQ_LEVEL);
 | |
| 	irq_set_chip_and_handler(virq, &socrates_fpga_pic_chip,
 | |
| 				 handle_fasteoi_irq);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int socrates_fpga_pic_host_xlate(struct irq_domain *h,
 | |
| 		struct device_node *ct,	const u32 *intspec, unsigned int intsize,
 | |
| 		irq_hw_number_t *out_hwirq, unsigned int *out_flags)
 | |
| {
 | |
| 	struct socrates_fpga_irq_info *fpga_irq = &fpga_irqs[intspec[0]];
 | |
| 
 | |
| 	*out_hwirq = intspec[0];
 | |
| 	if  (fpga_irq->type == IRQ_TYPE_NONE) {
 | |
| 		/* type is configurable */
 | |
| 		if (intspec[1] != IRQ_TYPE_LEVEL_LOW &&
 | |
| 		    intspec[1] != IRQ_TYPE_LEVEL_HIGH) {
 | |
| 			pr_warning("FPGA PIC: invalid irq type, "
 | |
| 				   "setting default active low\n");
 | |
| 			*out_flags = IRQ_TYPE_LEVEL_LOW;
 | |
| 		} else {
 | |
| 			*out_flags = intspec[1];
 | |
| 		}
 | |
| 	} else {
 | |
| 		/* type is fixed */
 | |
| 		*out_flags = fpga_irq->type;
 | |
| 	}
 | |
| 
 | |
| 	/* Use specified interrupt routing */
 | |
| 	if (intspec[2] <= 2)
 | |
| 		fpga_irq->irq_line = intspec[2];
 | |
| 	else
 | |
| 		pr_warning("FPGA PIC: invalid irq routing\n");
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static const struct irq_domain_ops socrates_fpga_pic_host_ops = {
 | |
| 	.map    = socrates_fpga_pic_host_map,
 | |
| 	.xlate  = socrates_fpga_pic_host_xlate,
 | |
| };
 | |
| 
 | |
| void socrates_fpga_pic_init(struct device_node *pic)
 | |
| {
 | |
| 	unsigned long flags;
 | |
| 	int i;
 | |
| 
 | |
| 	/* Setup an irq_domain structure */
 | |
| 	socrates_fpga_pic_irq_host = irq_domain_add_linear(pic,
 | |
| 		    SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops, NULL);
 | |
| 	if (socrates_fpga_pic_irq_host == NULL) {
 | |
| 		pr_err("FPGA PIC: Unable to allocate host\n");
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	for (i = 0; i < 3; i++) {
 | |
| 		socrates_fpga_irqs[i] = irq_of_parse_and_map(pic, i);
 | |
| 		if (socrates_fpga_irqs[i] == NO_IRQ) {
 | |
| 			pr_warning("FPGA PIC: can't get irq%d.\n", i);
 | |
| 			continue;
 | |
| 		}
 | |
| 		irq_set_chained_handler(socrates_fpga_irqs[i],
 | |
| 					socrates_fpga_pic_cascade);
 | |
| 	}
 | |
| 
 | |
| 	socrates_fpga_pic_iobase = of_iomap(pic, 0);
 | |
| 
 | |
| 	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
 | |
| 	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(0),
 | |
| 			SOCRATES_FPGA_IRQ_MASK << 16);
 | |
| 	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(1),
 | |
| 			SOCRATES_FPGA_IRQ_MASK << 16);
 | |
| 	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(2),
 | |
| 			SOCRATES_FPGA_IRQ_MASK << 16);
 | |
| 	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
 | |
| 
 | |
| 	pr_info("FPGA PIC: Setting up Socrates FPGA PIC\n");
 | |
| }
 |