xref: /openbmc/linux/arch/sh/boards/mach-se/7724/irq.c (revision aaf9128a)
1aaf9128aSKuninori Morimoto // SPDX-License-Identifier: GPL-2.0
2287c1297SKuninori Morimoto /*
3287c1297SKuninori Morimoto  * linux/arch/sh/boards/se/7724/irq.c
4287c1297SKuninori Morimoto  *
5287c1297SKuninori Morimoto  * Copyright (C) 2009 Renesas Solutions Corp.
6287c1297SKuninori Morimoto  *
7287c1297SKuninori Morimoto  * Kuninori Morimoto <morimoto.kuninori@renesas.com>
8287c1297SKuninori Morimoto  *
9287c1297SKuninori Morimoto  * Based on  linux/arch/sh/boards/se/7722/irq.c
10287c1297SKuninori Morimoto  * Copyright (C) 2007  Nobuhiro Iwamatsu
11287c1297SKuninori Morimoto  *
12287c1297SKuninori Morimoto  * Hitachi UL SolutionEngine 7724 Support.
13287c1297SKuninori Morimoto  */
14287c1297SKuninori Morimoto #include <linux/init.h>
15287c1297SKuninori Morimoto #include <linux/irq.h>
16287c1297SKuninori Morimoto #include <linux/interrupt.h>
17d0e05bb3SPaul Mundt #include <linux/export.h>
18d0e05bb3SPaul Mundt #include <linux/topology.h>
19d0e05bb3SPaul Mundt #include <linux/io.h>
20d0e05bb3SPaul Mundt #include <linux/err.h>
21287c1297SKuninori Morimoto #include <mach-se/mach/se7724.h>
22287c1297SKuninori Morimoto 
23287c1297SKuninori Morimoto struct fpga_irq {
24287c1297SKuninori Morimoto 	unsigned long  sraddr;
25287c1297SKuninori Morimoto 	unsigned long  mraddr;
26287c1297SKuninori Morimoto 	unsigned short mask;
27287c1297SKuninori Morimoto 	unsigned int   base;
28287c1297SKuninori Morimoto };
29287c1297SKuninori Morimoto 
fpga2irq(unsigned int irq)30287c1297SKuninori Morimoto static unsigned int fpga2irq(unsigned int irq)
31287c1297SKuninori Morimoto {
32287c1297SKuninori Morimoto 	if (irq >= IRQ0_BASE &&
33287c1297SKuninori Morimoto 	    irq <= IRQ0_END)
34287c1297SKuninori Morimoto 		return IRQ0_IRQ;
35287c1297SKuninori Morimoto 	else if (irq >= IRQ1_BASE &&
36287c1297SKuninori Morimoto 		 irq <= IRQ1_END)
37287c1297SKuninori Morimoto 		return IRQ1_IRQ;
38287c1297SKuninori Morimoto 	else
39287c1297SKuninori Morimoto 		return IRQ2_IRQ;
40287c1297SKuninori Morimoto }
41287c1297SKuninori Morimoto 
get_fpga_irq(unsigned int irq)42287c1297SKuninori Morimoto static struct fpga_irq get_fpga_irq(unsigned int irq)
43287c1297SKuninori Morimoto {
44287c1297SKuninori Morimoto 	struct fpga_irq set;
45287c1297SKuninori Morimoto 
46287c1297SKuninori Morimoto 	switch (irq) {
47287c1297SKuninori Morimoto 	case IRQ0_IRQ:
48287c1297SKuninori Morimoto 		set.sraddr = IRQ0_SR;
49287c1297SKuninori Morimoto 		set.mraddr = IRQ0_MR;
50287c1297SKuninori Morimoto 		set.mask   = IRQ0_MASK;
51287c1297SKuninori Morimoto 		set.base   = IRQ0_BASE;
52287c1297SKuninori Morimoto 		break;
53287c1297SKuninori Morimoto 	case IRQ1_IRQ:
54287c1297SKuninori Morimoto 		set.sraddr = IRQ1_SR;
55287c1297SKuninori Morimoto 		set.mraddr = IRQ1_MR;
56287c1297SKuninori Morimoto 		set.mask   = IRQ1_MASK;
57287c1297SKuninori Morimoto 		set.base   = IRQ1_BASE;
58287c1297SKuninori Morimoto 		break;
59287c1297SKuninori Morimoto 	default:
60287c1297SKuninori Morimoto 		set.sraddr = IRQ2_SR;
61287c1297SKuninori Morimoto 		set.mraddr = IRQ2_MR;
62287c1297SKuninori Morimoto 		set.mask   = IRQ2_MASK;
63287c1297SKuninori Morimoto 		set.base   = IRQ2_BASE;
64287c1297SKuninori Morimoto 		break;
65287c1297SKuninori Morimoto 	}
66287c1297SKuninori Morimoto 
67287c1297SKuninori Morimoto 	return set;
68287c1297SKuninori Morimoto }
69287c1297SKuninori Morimoto 
disable_se7724_irq(struct irq_data * data)7015ff2c67SPaul Mundt static void disable_se7724_irq(struct irq_data *data)
71287c1297SKuninori Morimoto {
7215ff2c67SPaul Mundt 	unsigned int irq = data->irq;
73287c1297SKuninori Morimoto 	struct fpga_irq set = get_fpga_irq(fpga2irq(irq));
74287c1297SKuninori Morimoto 	unsigned int bit = irq - set.base;
759d56dd3bSPaul Mundt 	__raw_writew(__raw_readw(set.mraddr) | 0x0001 << bit, set.mraddr);
76287c1297SKuninori Morimoto }
77287c1297SKuninori Morimoto 
enable_se7724_irq(struct irq_data * data)7815ff2c67SPaul Mundt static void enable_se7724_irq(struct irq_data *data)
79287c1297SKuninori Morimoto {
8015ff2c67SPaul Mundt 	unsigned int irq = data->irq;
81287c1297SKuninori Morimoto 	struct fpga_irq set = get_fpga_irq(fpga2irq(irq));
82287c1297SKuninori Morimoto 	unsigned int bit = irq - set.base;
839d56dd3bSPaul Mundt 	__raw_writew(__raw_readw(set.mraddr) & ~(0x0001 << bit), set.mraddr);
84287c1297SKuninori Morimoto }
85287c1297SKuninori Morimoto 
86287c1297SKuninori Morimoto static struct irq_chip se7724_irq_chip __read_mostly = {
87287c1297SKuninori Morimoto 	.name		= "SE7724-FPGA",
8815ff2c67SPaul Mundt 	.irq_mask	= disable_se7724_irq,
8915ff2c67SPaul Mundt 	.irq_unmask	= enable_se7724_irq,
90287c1297SKuninori Morimoto };
91287c1297SKuninori Morimoto 
se7724_irq_demux(struct irq_desc * desc)92bd0b9ac4SThomas Gleixner static void se7724_irq_demux(struct irq_desc *desc)
93287c1297SKuninori Morimoto {
94c497615cSThomas Gleixner 	unsigned int irq = irq_desc_get_irq(desc);
95287c1297SKuninori Morimoto 	struct fpga_irq set = get_fpga_irq(irq);
969d56dd3bSPaul Mundt 	unsigned short intv = __raw_readw(set.sraddr);
97287c1297SKuninori Morimoto 	unsigned int ext_irq = set.base;
98287c1297SKuninori Morimoto 
99287c1297SKuninori Morimoto 	intv &= set.mask;
100287c1297SKuninori Morimoto 
101c7a96727SPaul Mundt 	for (; intv; intv >>= 1, ext_irq++) {
102c7a96727SPaul Mundt 		if (!(intv & 1))
103c7a96727SPaul Mundt 			continue;
104c7a96727SPaul Mundt 
105c7a96727SPaul Mundt 		generic_handle_irq(ext_irq);
106287c1297SKuninori Morimoto 	}
107287c1297SKuninori Morimoto }
108287c1297SKuninori Morimoto 
109287c1297SKuninori Morimoto /*
110287c1297SKuninori Morimoto  * Initialize IRQ setting
111287c1297SKuninori Morimoto  */
init_se7724_IRQ(void)112287c1297SKuninori Morimoto void __init init_se7724_IRQ(void)
113287c1297SKuninori Morimoto {
114d0e05bb3SPaul Mundt 	int irq_base, i;
115287c1297SKuninori Morimoto 
1169d56dd3bSPaul Mundt 	__raw_writew(0xffff, IRQ0_MR);  /* mask all */
1179d56dd3bSPaul Mundt 	__raw_writew(0xffff, IRQ1_MR);  /* mask all */
1189d56dd3bSPaul Mundt 	__raw_writew(0xffff, IRQ2_MR);  /* mask all */
1199d56dd3bSPaul Mundt 	__raw_writew(0x0000, IRQ0_SR);  /* clear irq */
1209d56dd3bSPaul Mundt 	__raw_writew(0x0000, IRQ1_SR);  /* clear irq */
1219d56dd3bSPaul Mundt 	__raw_writew(0x0000, IRQ2_SR);  /* clear irq */
1229d56dd3bSPaul Mundt 	__raw_writew(0x002a, IRQ_MODE); /* set irq type */
123287c1297SKuninori Morimoto 
124d0e05bb3SPaul Mundt 	irq_base = irq_alloc_descs(SE7724_FPGA_IRQ_BASE, SE7724_FPGA_IRQ_BASE,
125d0e05bb3SPaul Mundt 				   SE7724_FPGA_IRQ_NR, numa_node_id());
126d0e05bb3SPaul Mundt 	if (IS_ERR_VALUE(irq_base)) {
127d0e05bb3SPaul Mundt 		pr_err("%s: failed hooking irqs for FPGA\n", __func__);
128c7a96727SPaul Mundt 		return;
129c7a96727SPaul Mundt 	}
130c7a96727SPaul Mundt 
131d0e05bb3SPaul Mundt 	for (i = 0; i < SE7724_FPGA_IRQ_NR; i++)
132d0e05bb3SPaul Mundt 		irq_set_chip_and_handler_name(irq_base + i, &se7724_irq_chip,
133287c1297SKuninori Morimoto 					      handle_level_irq, "level");
134287c1297SKuninori Morimoto 
135fcb8918fSThomas Gleixner 	irq_set_chained_handler(IRQ0_IRQ, se7724_irq_demux);
136fcb8918fSThomas Gleixner 	irq_set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW);
137287c1297SKuninori Morimoto 
138fcb8918fSThomas Gleixner 	irq_set_chained_handler(IRQ1_IRQ, se7724_irq_demux);
139fcb8918fSThomas Gleixner 	irq_set_irq_type(IRQ1_IRQ, IRQ_TYPE_LEVEL_LOW);
140287c1297SKuninori Morimoto 
141fcb8918fSThomas Gleixner 	irq_set_chained_handler(IRQ2_IRQ, se7724_irq_demux);
142fcb8918fSThomas Gleixner 	irq_set_irq_type(IRQ2_IRQ, IRQ_TYPE_LEVEL_LOW);
143287c1297SKuninori Morimoto }
144