1 /* $Id: setup_cqreek.c,v 1.9 2001/07/30 12:43:28 gniibe Exp $
2  *
3  * arch/sh/kernel/setup_cqreek.c
4  *
5  * Copyright (C) 2000  Niibe Yutaka
6  *
7  * CqREEK IDE/ISA Bridge Support.
8  *
9  */
10 
11 #include <linux/config.h>
12 #include <linux/kernel.h>
13 #include <linux/init.h>
14 #include <linux/irq.h>
15 
16 #include <asm/io.h>
17 #include <asm/io_generic.h>
18 #include <asm/irq.h>
19 #include <asm/machvec.h>
20 #include <asm/machvec_init.h>
21 #include <asm/rtc.h>
22 
23 #define BRIDGE_FEATURE		0x0002
24 
25 #define BRIDGE_IDE_CTRL		0x0018
26 #define BRIDGE_IDE_INTR_LVL    	0x001A
27 #define BRIDGE_IDE_INTR_MASK	0x001C
28 #define BRIDGE_IDE_INTR_STAT	0x001E
29 
30 #define BRIDGE_ISA_CTRL		0x0028
31 #define BRIDGE_ISA_INTR_LVL    	0x002A
32 #define BRIDGE_ISA_INTR_MASK	0x002C
33 #define BRIDGE_ISA_INTR_STAT	0x002E
34 
35 #define IDE_OFFSET 0xA4000000UL
36 #define ISA_OFFSET 0xA4A00000UL
37 
cqreek_port2addr(unsigned long port)38 static unsigned long cqreek_port2addr(unsigned long port)
39 {
40 	if (0x0000<=port && port<=0x0040)
41 		return IDE_OFFSET + port;
42 	if ((0x01f0<=port && port<=0x01f7) || port == 0x03f6)
43 		return IDE_OFFSET + port;
44 
45 	return ISA_OFFSET + port;
46 }
47 
48 struct cqreek_irq_data {
49 	unsigned short mask_port;	/* Port of Interrupt Mask Register */
50 	unsigned short stat_port;	/* Port of Interrupt Status Register */
51 	unsigned short bit;		/* Value of the bit */
52 };
53 static struct cqreek_irq_data cqreek_irq_data[NR_IRQS];
54 
disable_cqreek_irq(unsigned int irq)55 static void disable_cqreek_irq(unsigned int irq)
56 {
57 	unsigned long flags;
58 	unsigned short mask;
59 	unsigned short mask_port = cqreek_irq_data[irq].mask_port;
60 	unsigned short bit = cqreek_irq_data[irq].bit;
61 
62 	save_and_cli(flags);
63 	/* Disable IRQ */
64 	mask = inw(mask_port) & ~bit;
65 	outw_p(mask, mask_port);
66 	restore_flags(flags);
67 }
68 
enable_cqreek_irq(unsigned int irq)69 static void enable_cqreek_irq(unsigned int irq)
70 {
71 	unsigned long flags;
72 	unsigned short mask;
73 	unsigned short mask_port = cqreek_irq_data[irq].mask_port;
74 	unsigned short bit = cqreek_irq_data[irq].bit;
75 
76 	save_and_cli(flags);
77 	/* Enable IRQ */
78 	mask = inw(mask_port) | bit;
79 	outw_p(mask, mask_port);
80 	restore_flags(flags);
81 }
82 
mask_and_ack_cqreek(unsigned int irq)83 static void mask_and_ack_cqreek(unsigned int irq)
84 {
85 	unsigned short stat_port = cqreek_irq_data[irq].stat_port;
86 	unsigned short bit = cqreek_irq_data[irq].bit;
87 
88 	disable_cqreek_irq(irq);
89 	/* Clear IRQ (it might be edge IRQ) */
90 	inw(stat_port);
91 	outw_p(bit, stat_port);
92 }
93 
end_cqreek_irq(unsigned int irq)94 static void end_cqreek_irq(unsigned int irq)
95 {
96 	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
97 		enable_cqreek_irq(irq);
98 }
99 
startup_cqreek_irq(unsigned int irq)100 static unsigned int startup_cqreek_irq(unsigned int irq)
101 {
102 	enable_cqreek_irq(irq);
103 	return 0;
104 }
105 
shutdown_cqreek_irq(unsigned int irq)106 static void shutdown_cqreek_irq(unsigned int irq)
107 {
108 	disable_cqreek_irq(irq);
109 }
110 
111 static struct hw_interrupt_type cqreek_irq_type = {
112 	"CqREEK-IRQ",
113 	startup_cqreek_irq,
114 	shutdown_cqreek_irq,
115 	enable_cqreek_irq,
116 	disable_cqreek_irq,
117 	mask_and_ack_cqreek,
118 	end_cqreek_irq
119 };
120 
121 static int has_ide, has_isa;
122 
123 /* XXX: This is just for test for my NE2000 ISA board
124    What we really need is virtualized IRQ and demultiplexer like HP600 port */
init_cqreek_IRQ(void)125 void __init init_cqreek_IRQ(void)
126 {
127 	if (has_ide) {
128 		cqreek_irq_data[14].mask_port = BRIDGE_IDE_INTR_MASK;
129 		cqreek_irq_data[14].stat_port = BRIDGE_IDE_INTR_STAT;
130 		cqreek_irq_data[14].bit = 1;
131 
132 		irq_desc[14].handler = &cqreek_irq_type;
133 		irq_desc[14].status = IRQ_DISABLED;
134 		irq_desc[14].action = 0;
135 		irq_desc[14].depth = 1;
136 
137 		disable_cqreek_irq(14);
138 	}
139 
140 	if (has_isa) {
141 		cqreek_irq_data[10].mask_port = BRIDGE_ISA_INTR_MASK;
142 		cqreek_irq_data[10].stat_port = BRIDGE_ISA_INTR_STAT;
143 		cqreek_irq_data[10].bit = (1 << 10);
144 
145 		/* XXX: Err... we may need demultiplexer for ISA irq... */
146 		irq_desc[10].handler = &cqreek_irq_type;
147 		irq_desc[10].status = IRQ_DISABLED;
148 		irq_desc[10].action = 0;
149 		irq_desc[10].depth = 1;
150 
151 		disable_cqreek_irq(10);
152 	}
153 }
154 
155 /*
156  * Initialize the board
157  */
setup_cqreek(void)158 void __init setup_cqreek(void)
159 {
160 	int i;
161 /* udelay is not available at setup time yet... */
162 #define DELAY() do {for (i=0; i<10000; i++) ctrl_inw(0xa0000000);} while(0)
163 
164 	if ((inw (BRIDGE_FEATURE) & 1)) { /* We have IDE interface */
165 		outw_p(0, BRIDGE_IDE_INTR_LVL);
166 		outw_p(0, BRIDGE_IDE_INTR_MASK);
167 
168 		outw_p(0, BRIDGE_IDE_CTRL);
169 		DELAY();
170 
171 		outw_p(0x8000, BRIDGE_IDE_CTRL);
172 		DELAY();
173 
174 		outw_p(0xffff, BRIDGE_IDE_INTR_STAT); /* Clear interrupt status */
175 		outw_p(0x0f-14, BRIDGE_IDE_INTR_LVL); /* Use 14 IPR */
176 		outw_p(1, BRIDGE_IDE_INTR_MASK); /* Enable interrupt */
177 		has_ide=1;
178 	}
179 
180 	if ((inw (BRIDGE_FEATURE) & 2)) { /* We have ISA interface */
181 		outw_p(0, BRIDGE_ISA_INTR_LVL);
182 		outw_p(0, BRIDGE_ISA_INTR_MASK);
183 
184 		outw_p(0, BRIDGE_ISA_CTRL);
185 		DELAY();
186 		outw_p(0x8000, BRIDGE_ISA_CTRL);
187 		DELAY();
188 
189 		outw_p(0xffff, BRIDGE_ISA_INTR_STAT); /* Clear interrupt status */
190 		outw_p(0x0f-10, BRIDGE_ISA_INTR_LVL); /* Use 10 IPR */
191 		outw_p(0xfff8, BRIDGE_ISA_INTR_MASK); /* Enable interrupt */
192 		has_isa=1;
193 	}
194 
195 	printk(KERN_INFO "CqREEK Setup (IDE=%d, ISA=%d)...done\n", has_ide, has_isa);
196 }
197 
198 /*
199  * The Machine Vector
200  */
201 
202 struct sh_machine_vector mv_cqreek __initmv = {
203 	mv_name:		"CqREEK",
204 
205 #if defined(__SH4__)
206 	mv_nr_irqs:		48,
207 #elif defined(CONFIG_CPU_SUBTYPE_SH7708)
208 	mv_nr_irqs:		32,
209 #elif defined(CONFIG_CPU_SUBTYPE_SH7709)
210 	mv_nr_irqs:		61,
211 #endif
212 
213 	mv_inb:			generic_inb,
214 	mv_inw:			generic_inw,
215 	mv_inl:			generic_inl,
216 	mv_outb:		generic_outb,
217 	mv_outw:		generic_outw,
218 	mv_outl:		generic_outl,
219 
220 	mv_inb_p:		generic_inb_p,
221 	mv_inw_p:		generic_inw_p,
222 	mv_inl_p:		generic_inl_p,
223 	mv_outb_p:		generic_outb_p,
224 	mv_outw_p:		generic_outw_p,
225 	mv_outl_p:		generic_outl_p,
226 
227 	mv_insb:		generic_insb,
228 	mv_insw:		generic_insw,
229 	mv_insl:		generic_insl,
230 	mv_outsb:		generic_outsb,
231 	mv_outsw:		generic_outsw,
232 	mv_outsl:		generic_outsl,
233 
234 	mv_readb:		generic_readb,
235 	mv_readw:		generic_readw,
236 	mv_readl:		generic_readl,
237 	mv_writeb:		generic_writeb,
238 	mv_writew:		generic_writew,
239 	mv_writel:		generic_writel,
240 
241 	mv_init_arch:		setup_cqreek,
242 	mv_init_irq:		init_cqreek_IRQ,
243 
244 	mv_isa_port2addr:	cqreek_port2addr,
245 
246 	mv_ioremap:		generic_ioremap,
247 	mv_iounmap:		generic_iounmap,
248 
249 	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
250 	mv_rtc_settimeofday:	sh_rtc_settimeofday,
251 };
252 ALIAS_MV(cqreek)
253