1 /* $NetBSD: dio.c,v 1.36 2008/03/29 06:47:07 tsutsui Exp $ */
4 * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Autoconfiguration and mapping support for the DIO bus.
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: dio.c,v 1.36 2008/03/29 06:47:07 tsutsui Exp $");
39 #define _HP300_INTR_H_PRIVATE
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/device.h>
46 #include <machine/bus.h>
48 #include <uvm/uvm_extern.h>
50 #include <machine/autoconf.h>
51 #include <machine/cpu.h>
52 #include <machine/hp300spu.h>
54 #include <hp300/dev/dmavar.h>
56 #include <hp300/dev/dioreg.h>
57 #include <hp300/dev/diovar.h>
59 #include <hp300/dev/diodevs.h>
60 #include <hp300/dev/diodevs_data.h>
63 #define diocf_scode cf_loc[DIOCF_SCODE]
67 struct bus_space_tag sc_tag
;
70 static int dio_scodesize(struct dio_attach_args
*);
71 static const char *dio_devinfo(struct dio_attach_args
*, char *, size_t);
73 static int diomatch(device_t
, cfdata_t
, void *);
74 static void dioattach(device_t
, device_t
, void *);
75 static int dioprint(void *, const char *);
76 static int diosubmatch(device_t
, cfdata_t
, const int *, void *);
78 CFATTACH_DECL_NEW(dio
, sizeof(struct dio_softc
),
79 diomatch
, dioattach
, NULL
, NULL
);
82 diomatch(device_t parent
, cfdata_t cf
, void *aux
)
84 static int dio_matched
= 0;
86 /* Allow only one instance. */
95 dioattach(device_t parent
, device_t self
, void *aux
)
97 struct dio_softc
*sc
= device_private(self
);
98 struct dio_attach_args da
;
101 bus_space_tag_t bst
= &sc
->sc_tag
;
102 bus_space_handle_t bsh
;
103 int scode
, scmax
, scodesize
;
108 memset(bst
, 0, sizeof(struct bus_space_tag
));
109 bst
->bustype
= HP300_BUS_SPACE_DIO
;
111 scmax
= DIO_SCMAX(machineid
);
113 for (scode
= 0; scode
< scmax
; ) {
114 if (DIO_INHOLE(scode
)) {
120 * Temporarily map the space corresponding to
121 * the current select code unless:
123 pa
= (bus_addr_t
)dio_scodetopa(scode
);
124 if (bus_space_map(bst
, pa
, PAGE_SIZE
, 0, &bsh
)) {
125 aprint_error_dev(self
, "can't map scode %d\n", scode
);
129 va
= bus_space_vaddr(bst
, bsh
);
131 /* Check for hardware. */
133 bus_space_unmap(bst
, bsh
, PAGE_SIZE
);
138 /* Fill out attach args. */
139 memset(&da
, 0, sizeof(da
));
143 da
.da_id
= DIO_ID(va
);
144 if (DIO_ISFRAMEBUFFER(da
.da_id
))
145 da
.da_secid
= DIO_SECID(va
);
147 da
.da_size
= DIO_SIZE(scode
, va
);
148 scodesize
= dio_scodesize(&da
);
149 if (DIO_ISDIO(scode
))
150 da
.da_size
*= scodesize
;
151 da
.da_ipl
= DIO_IPL(va
);
153 /* No longer need the device to be mapped. */
154 bus_space_unmap(bst
, bsh
, PAGE_SIZE
);
156 /* Attach matching device. */
157 config_found_sm_loc(self
, "dio", NULL
, &da
, dioprint
,
164 diosubmatch(device_t parent
, cfdata_t cf
, const int *ldesc
, void *aux
)
166 struct dio_attach_args
*da
= aux
;
168 if (cf
->diocf_scode
!= DIOCF_SCODE_DEFAULT
&&
169 cf
->diocf_scode
!= da
->da_scode
)
172 return config_match(parent
, cf
, aux
);
176 dioprint(void *aux
, const char *pnp
)
178 struct dio_attach_args
*da
= aux
;
182 aprint_normal("%s at %s",
183 dio_devinfo(da
, buf
, sizeof(buf
)), pnp
);
184 aprint_normal(" scode %d ipl %d", da
->da_scode
, da
->da_ipl
);
189 * Convert a select code to a system physical address.
192 dio_scodetopa(int scode
)
196 if (DIO_ISDIO(scode
))
197 rval
= DIO_BASE
+ (scode
* DIO_DEVSIZE
);
198 else if (DIO_ISDIOII(scode
))
199 rval
= DIOII_BASE
+ ((scode
- DIOII_SCBASE
) * DIOII_DEVSIZE
);
207 * Return the select code size for this device, defaulting to 1
208 * if we don't know what kind of device we have.
211 dio_scodesize(struct dio_attach_args
*da
)
216 * Find the dio_devdata matchind the primary id.
217 * If we're a framebuffer, we also check the secondary id.
219 for (i
= 0; i
< DIO_NDEVICES
; i
++) {
220 if (da
->da_id
== dio_devdatas
[i
].dd_id
) {
221 if (DIO_ISFRAMEBUFFER(da
->da_id
)) {
222 if (da
->da_secid
== dio_devdatas
[i
].dd_secid
) {
227 return dio_devdatas
[i
].dd_nscode
;
233 * Device is unknown. Print a warning and assume a default.
235 aprint_error("WARNING: select code size unknown "
236 "for id = 0x%x secid = 0x%x\n",
237 da
->da_id
, da
->da_secid
);
242 * Return a reasonable description of a DIO device.
245 dio_devinfo(struct dio_attach_args
*da
, char *buf
, size_t buflen
)
251 memset(buf
, 0, buflen
);
255 * Find the description matching our primary id.
256 * If we're a framebuffer, we also check the secondary id.
258 for (i
= 0; i
< DIO_NDEVICES
; i
++) {
259 if (da
->da_id
== dio_devdescs
[i
].dd_id
) {
260 if (DIO_ISFRAMEBUFFER(da
->da_id
)) {
261 if (da
->da_secid
== dio_devdescs
[i
].dd_secid
) {
266 sprintf(buf
, "%s", dio_devdescs
[i
].dd_desc
);
271 #endif /* DIOVERBOSE */
274 * Device is unknown. Construct something reasonable.
276 sprintf(buf
, "device id = 0x%x secid = 0x%x",
277 da
->da_id
, da
->da_secid
);
282 * Establish an interrupt handler for a DIO device.
285 dio_intr_establish(int (*func
)(void *), void *arg
, int ipl
, int priority
)
289 ih
= intr_establish(func
, arg
, ipl
, priority
);
291 if (priority
== IPL_BIO
)
298 * Remove an interrupt handler for a DIO device.
301 dio_intr_disestablish(void *arg
)
303 struct hp300_intrhand
*ih
= arg
;
304 int priority
= ih
->ih_priority
;
306 intr_disestablish(arg
);
308 if (priority
== IPL_BIO
)
313 * DIO specific bus_space(9) support functions.
315 static uint8_t dio_bus_space_read_oddbyte_1(bus_space_tag_t
,
316 bus_space_handle_t
, bus_size_t
);
317 static void dio_bus_space_write_oddbyte_1(bus_space_tag_t
,
318 bus_space_handle_t
, bus_size_t
, uint8_t);
320 static void dio_bus_space_read_multi_oddbyte_1(bus_space_tag_t
,
321 bus_space_handle_t
, bus_size_t
, uint8_t *, bus_size_t
);
322 static void dio_bus_space_write_multi_oddbyte_1(bus_space_tag_t
,
323 bus_space_handle_t
, bus_size_t
, const uint8_t *, bus_size_t
);
325 static void dio_bus_space_read_region_oddbyte_1(bus_space_tag_t
,
326 bus_space_handle_t
, bus_size_t
, uint8_t *, bus_size_t
);
327 static void dio_bus_space_write_region_oddbyte_1(bus_space_tag_t
,
328 bus_space_handle_t
, bus_size_t
, const uint8_t *, bus_size_t
);
330 static void dio_bus_space_set_multi_oddbyte_1(bus_space_tag_t
,
331 bus_space_handle_t
, bus_size_t
, uint8_t, bus_size_t
);
333 static void dio_bus_space_set_region_oddbyte_1(bus_space_tag_t
,
334 bus_space_handle_t
, bus_size_t
, uint8_t, bus_size_t
);
337 * dio_set_bus_space_oddbyte():
338 * Override bus_space functions in bus_space_tag_t
339 * for devices which have odd byte address space.
342 dio_set_bus_space_oddbyte(bus_space_tag_t bst
)
345 /* XXX only 1-byte functions for now */
346 bst
->bsr1
= dio_bus_space_read_oddbyte_1
;
347 bst
->bsw1
= dio_bus_space_write_oddbyte_1
;
349 bst
->bsrm1
= dio_bus_space_read_multi_oddbyte_1
;
350 bst
->bswm1
= dio_bus_space_write_multi_oddbyte_1
;
352 bst
->bsrr1
= dio_bus_space_read_region_oddbyte_1
;
353 bst
->bswr1
= dio_bus_space_write_region_oddbyte_1
;
355 bst
->bssm1
= dio_bus_space_set_multi_oddbyte_1
;
357 bst
->bssr1
= dio_bus_space_set_region_oddbyte_1
;
361 dio_bus_space_read_oddbyte_1(bus_space_tag_t bst
, bus_space_handle_t bsh
,
365 return *(volatile uint8_t *)(bsh
+ (offset
<< 1) + 1);
369 dio_bus_space_write_oddbyte_1(bus_space_tag_t bst
, bus_space_handle_t bsh
,
370 bus_size_t offset
, uint8_t val
)
373 *(volatile uint8_t *)(bsh
+ (offset
<< 1) + 1) = val
;
377 dio_bus_space_read_multi_oddbyte_1(bus_space_tag_t bst
, bus_space_handle_t bsh
,
378 bus_size_t offset
, uint8_t *addr
, bus_size_t len
)
385 "1: movb %%a0@,%%a1@+ ;\n"
389 : "r" (bsh
+ (offset
<< 1) + 1), "g" (addr
), "g" (len
)
390 : "%a0","%a1","%d0");
394 dio_bus_space_write_multi_oddbyte_1(bus_space_tag_t bst
, bus_space_handle_t bsh
,
395 bus_size_t offset
, const uint8_t *addr
, bus_size_t len
)
402 "1: movb %%a1@+,%%a0@ ;\n"
406 : "r" (bsh
+ (offset
<< 1) + 1), "g" (addr
), "g" (len
)
407 : "%a0","%a1","%d0");
411 dio_bus_space_read_region_oddbyte_1(bus_space_tag_t bst
, bus_space_handle_t bsh
,
412 bus_size_t offset
, uint8_t *addr
, bus_size_t len
)
418 "1: movb %%a0@,%%a1@+ ;\n"
423 : "r" (bsh
+ (offset
<< 1) + 1), "g" (addr
), "g" (len
)
424 : "%a0","%a1","%d0");
428 dio_bus_space_write_region_oddbyte_1(bus_space_tag_t bst
,
429 bus_space_handle_t bsh
, bus_size_t offset
, const uint8_t *addr
,
437 "1: movb %%a1@+,%%a0@ ;\n"
442 : "r" (bsh
+ (offset
<< 1) + 1), "g" (addr
), "g" (len
)
443 : "%a0","%a1","%d0");
447 dio_bus_space_set_multi_oddbyte_1(bus_space_tag_t bst
, bus_space_handle_t bsh
,
448 bus_size_t offset
, uint8_t val
, bus_size_t count
)
454 "1: movb %%d1,%%a0@ ;\n"
458 : "r" (bsh
+ (offset
<< 1) + 1), "g" (val
), "g" (count
)
459 : "%a0","%d0","%d1");
463 dio_bus_space_set_region_oddbyte_1(bus_space_tag_t bst
, bus_space_handle_t bsh
,
464 bus_size_t offset
, uint8_t val
, bus_size_t count
)
471 "1: movb %%d1,%%a0@ ;\n"
476 : "r" (bsh
+ (offset
<< 1) + 1), "g" (val
), "g" (count
)
477 : "%a0","%d0","%d1");