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