hd64465.c revision 1.1.2.1 1 /* $NetBSD: hd64465.c,v 1.1.2.1 2002/02/28 04:10:09 nathanw Exp $ */
2
3 /*-
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by UCHIYAMA Yasushi.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/device.h>
42 #include <sys/malloc.h>
43 #include <sys/boot_flag.h>
44
45 #include <machine/bus.h>
46 #include <machine/intr.h>
47 #include <sh3/shbvar.h>
48
49 #include <machine/debug.h>
50
51 #include <hpcsh/dev/hd64465/hd64465var.h>
52 #include <hpcsh/dev/hd64465/hd64465reg.h>
53 #include <hpcsh/dev/hd64465/hd64465intcreg.h>
54
55 /* HD64465 modules. */
56 STATIC const struct hd64465_module {
57 const char *name;
58 } hd64465_modules[] = {
59 [HD64465_MODULE_PS2IF] = { "hd64465ps2if" },
60 [HD64465_MODULE_PCMCIA] = { "hd64465pcmcia" },
61 [HD64465_MODULE_AFE] = { "hd64465afe" },
62 [HD64465_MODULE_GPIO] = { "hd64465gpio" },
63 [HD64465_MODULE_KBC] = { "hd64465kbc" },
64 [HD64465_MODULE_IRDA] = { "hd64465irda" },
65 [HD64465_MODULE_UART] = { "hd64465uart" },
66 [HD64465_MODULE_PARALEL] = { "hd64465paralel" },
67 [HD64465_MODULE_CODEC] = { "hd64465codec" },
68 [HD64465_MODULE_OHCI] = { "hd64465ohci" },
69 [HD64465_MODULE_ADC] = { "hd64465adc" }
70 };
71 #define HD64465_NMODULE \
72 (sizeof hd64465_modules / sizeof(struct hd64465_module))
73
74 STATIC struct hd64465_intr_entry {
75 int (*func)(void *);
76 void *arg;
77 int priority;
78 const u_int16_t bit;
79 } hd64465_intr_entry[] = {
80 #define IRQ_ENTRY(x) [HD64465_IRQ_ ## x] = { 0, 0, 0, HD64465_ ## x }
81 IRQ_ENTRY(PS2KB),
82 IRQ_ENTRY(PCC0),
83 IRQ_ENTRY(PCC1),
84 IRQ_ENTRY(AFE),
85 IRQ_ENTRY(GPIO),
86 IRQ_ENTRY(TMU0),
87 IRQ_ENTRY(TMU1),
88 IRQ_ENTRY(KBC),
89 IRQ_ENTRY(PS2MS),
90 IRQ_ENTRY(IRDA),
91 IRQ_ENTRY(UART),
92 IRQ_ENTRY(PPR),
93 IRQ_ENTRY(SCDI),
94 IRQ_ENTRY(OHCI),
95 IRQ_ENTRY(ADC)
96 #undef IRQ_ENTRY
97 };
98 #define HD64465_IRQ_MAX \
99 (sizeof hd64465_intr_entry / sizeof(struct hd64465_intr_entry))
100
101 STATIC struct hd64465 {
102 int attached;
103 u_int16_t imask;
104 } hd64465;
105
106 STATIC int hd64465_match(struct device *, struct cfdata *, void *);
107 STATIC void hd64465_attach(struct device *, struct device *, void *);
108 STATIC int hd64465_print(void *, const char *);
109 STATIC int hd64465_intr(void *);
110
111 struct cfattach hd64465if_ca = {
112 sizeof(struct device), hd64465_match, hd64465_attach
113 };
114
115 int
116 hd64465_match(struct device *parent, struct cfdata *cf, void *aux)
117 {
118
119 if (hd64465.attached++)
120 return (0); /* only one instance */
121
122 if (strcmp("hd64465if", cf->cf_driver->cd_name))
123 return (0);
124
125 if (hd64465_reg_read_2(HD64465_SDIDR) != 0x8122) {
126 /* not HD64465 */
127 return (0);
128 }
129
130 return (1);
131 }
132
133 void
134 hd64465_attach(struct device *parent, struct device *self, void *aux)
135 {
136 struct shb_attach_args *ia = aux;
137 const struct hd64465_module *module;
138 struct hd64465_attach_args ha;
139 u_int16_t r;
140 int i;
141
142 printf("\n");
143
144 r = hd64465_reg_read_2(HD64465_SRR);
145 printf("%s: HITACHI HD64465 rev. %d.%d\n", self->dv_xname,
146 (r >> 8) & 0xff, r & 0xff);
147
148 hd64465_intr_disable();
149
150 /* Attach all sub modules */
151 for (i = 0, module = hd64465_modules; i < HD64465_NMODULE;
152 i++, module++) {
153 if (module->name == 0)
154 continue;
155 ha.ha_module_id = i;
156 config_found(self, &ha, hd64465_print);
157 }
158
159 shb_intr_establish(ia->ia_irq, IST_EDGE, IPL_TTY, hd64465_intr, self);
160 }
161
162 int
163 hd64465_print(void *aux, const char *pnp)
164 {
165 struct hd64465_attach_args *ha = aux;
166
167 if (pnp)
168 printf("%s at %s", hd64465_modules[ha->ha_module_id].name, pnp);
169
170 return (UNCONF);
171 }
172
173 void *
174 hd64465_intr_establish(enum hd64465_irq irq, int mode, int level,
175 int (*func)(void *), void *arg)
176 {
177 struct hd64465_intr_entry *entry = &hd64465_intr_entry[irq];
178 u_int16_t r, bit;
179 int s;
180
181 s = splhigh();
182
183 entry->func = func;
184 entry->arg = arg;
185 entry->priority = level;
186
187 bit = entry->bit;
188
189 /* Trigger type */
190 r = hd64465_reg_read_2(HD64465_NITR);
191 switch (mode) {
192 case IST_PULSE:
193 /* FALLTHROUGH */
194 case IST_EDGE:
195 r |= bit;
196 break;
197 case IST_LEVEL:
198 r &= ~bit;
199 break;
200 }
201 hd64465_reg_write_2(HD64465_NITR, r);
202
203 /* Enable interrupt */
204 hd64465.imask &= ~bit;
205 hd64465_reg_write_2(HD64465_NIMR, hd64465.imask);
206
207 splx(s);
208
209 return (void *)irq;
210 }
211
212 void
213 hd64465_intr_disestablish(void *handle)
214 {
215 int irq = (int)handle;
216 struct hd64465_intr_entry *entry = &hd64465_intr_entry[irq];
217 int s;
218
219 s = splhigh();
220
221 /* disable interrupt */
222 hd64465.imask |= entry->bit;
223 hd64465_reg_write_2(HD64465_NIMR, hd64465.imask);
224
225 entry->func = 0;
226
227 splx(s);
228 }
229
230 int
231 hd64465_intr(void *arg)
232 {
233 struct hd64465_intr_entry *entry = hd64465_intr_entry;
234 u_int16_t cause;
235 int i;
236
237 cause = hd64465_reg_read_2(HD64465_NIRR) & ~hd64465.imask;
238 hd64465_reg_write_2(HD64465_NIRR, 0);
239
240 for (i = 0; i < HD64465_IRQ_MAX; i++, entry++) {
241 if (entry->func == 0)
242 continue;
243 if (cause & entry->bit)
244 (*entry->func)(entry->arg);
245 }
246
247 __dbg_heart_beat(HEART_BEAT_BLUE);
248
249 return (0);
250 }
251
252 void
253 hd64465_intr_disable()
254 {
255
256 /* Mask all interrupt */
257 hd64465.imask = 0xffff;
258 hd64465_reg_write_2(HD64465_NIMR, 0xffff);
259
260 /* Edge trigger mode */
261 hd64465_reg_write_2(HD64465_NITR, 0xffff);
262 /* Clear pending interrupt */
263 hd64465_reg_write_2(HD64465_NIRR, 0x0000);
264 }
265
266 void
267 hd64465_intr_mask()
268 {
269
270 hd64465_reg_write_2(HD64465_NIMR, 0xffff);
271 }
272
273 void
274 hd64465_intr_unmask()
275 {
276
277 hd64465_reg_write_2(HD64465_NIMR, hd64465.imask);
278 }
279
280 /* For the sake of Windows CE reboot clearly. */
281 void
282 hd64465_intr_reboot()
283 {
284
285 /* Enable all interrupt */
286 hd64465_reg_write_2(HD64465_NIMR, 0x0000);
287
288 /* Level trigger mode */
289 hd64465_reg_write_2(HD64465_NITR, 0x0000);
290 }
291