1 /* $NetBSD: com_hpcio.c,v 1.10 2006/07/13 22:56:01 gdamore Exp $ */
4 * Copyright (c) 2002 TAKEMRUA Shin. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the project nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: com_hpcio.c,v 1.10 2006/07/13 22:56:01 gdamore Exp $");
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/device.h>
40 #include <sys/reboot.h>
41 #include <sys/termios.h>
43 #include <machine/intr.h>
44 #include <machine/bus.h>
45 #include <machine/platid.h>
46 #include <machine/platid_mask.h>
48 #include <hpcmips/dev/com_hpciovar.h>
50 #include <dev/hpc/hpciovar.h>
51 #include <dev/ic/comvar.h>
52 #include <dev/ic/comreg.h>
56 #define COM_HPCIODEBUG
58 int com_hpcio_debug
= 0;
59 #define DPRINTF(arg...) do { if (com_hpcio_debug) printf(arg); } while (0)
61 #define DPRINTF(arg...) do {} while (0)
65 * XXX: NOTE: With the new com(4) COM_REGMAP support, the custom bus_space
66 * in this file could/should probably be removed and replaced with a custom
67 * map. Resulting in smaller/cleaner code. An hpcmips hacker should fix
68 * this, since I don't have h/w to test with -- I'm taking the route of least
72 #define COM_HPCIO_BYTE_ALIGNMENT 0
73 #define COM_HPCIO_HALFWORD_ALIGNMENT 1
75 struct com_hpcio_softc
{
76 struct com_softc hsc_com
;
77 struct bus_space_tag hsc_iot
;
78 struct hpcio_chip
*hsc_hc
;
80 static struct bus_space_tag com_hpcio_cniotx
;
81 static bus_space_tag_t com_hpcio_cniot
= &com_hpcio_cniotx
;
82 static int com_hpcio_cniobase
;
84 static int com_hpcio_probe(device_t
, cfdata_t
, void *);
85 static void com_hpcio_attach(device_t
, device_t
, void *);
86 static int com_hpcio_common_probe(bus_space_tag_t
, int, int *);
87 void com_hpcio_iot_init(bus_space_tag_t iot
, bus_space_tag_t base
);
88 bus_space_protos(bs_notimpl
);
89 bus_space_protos(bs_through
);
90 bus_space_protos(com_hpcio
);
92 CFATTACH_DECL_NEW(com_hpcio
, sizeof(struct com_hpcio_softc
),
93 com_hpcio_probe
, com_hpcio_attach
, NULL
, NULL
);
95 struct bus_space_ops com_hpcio_bs_ops
= {
96 /* mapping/unmapping */
99 bs_through_bs_subregion
,
101 /* allocation/deallocation */
105 /* get kernel virtual address */
106 bs_through_bs_vaddr
, /* there is no linear mapping */
108 /* Mmap bus space for user */
112 bs_through_bs_barrier
,
154 #ifdef BUS_SPACE_HAS_REAL_STREAM_METHODS
155 /* read stream (single) */
161 /* read multiple stream */
167 /* read region stream */
173 /* write stream (single) */
179 /* write multiple stream */
185 /* write region stream */
190 #endif /* BUS_SPACE_HAS_REAL_STREAM_METHODS */
212 com_hpcio_cndb_attach(bus_space_tag_t iot
, int iobase
, int rate
,
213 int frequency
, tcflag_t cflag
, int kgdb
)
217 DPRINTF("com_hpcio_cndb_attach()\n");
218 if (!com_hpcio_common_probe(iot
, iobase
, &alignment
)) {
219 DPRINTF("com_hpcio_cndb_attach(): probe failed\n");
222 if (alignment
== COM_HPCIO_HALFWORD_ALIGNMENT
) {
223 DPRINTF("com_hpcio_cndb_attach(): half word aligned\n");
224 com_hpcio_iot_init(&com_hpcio_cniotx
, iot
);
225 com_hpcio_cniot
= &com_hpcio_cniotx
;
227 com_hpcio_cniot
= iot
;
229 com_hpcio_cniobase
= iobase
;
230 DPRINTF("com_hpcio_cndb_attach(): probe succeeded\n");
233 return (com_kgdb_attach(com_hpcio_cniot
, iobase
, rate
,
234 frequency
, COM_TYPE_NORMAL
, cflag
));
237 return (comcnattach(com_hpcio_cniot
, iobase
, rate
,
238 frequency
, COM_TYPE_NORMAL
, cflag
));
242 com_hpcio_common_probe(bus_space_tag_t iot
, int iobase
, int *alignment
)
244 bus_space_handle_t ioh
;
245 static struct bus_space_tag tmpiot
;
249 * try byte aligned register
251 *alignment
= COM_HPCIO_BYTE_ALIGNMENT
;
252 if (bus_space_map(iot
, iobase
, 1, 0, &ioh
))
254 rv
= comprobe1(iot
, ioh
);
255 bus_space_unmap(iot
, ioh
, 1);
261 * try half word aligned register
263 *alignment
= COM_HPCIO_HALFWORD_ALIGNMENT
;
264 com_hpcio_iot_init(&tmpiot
, iot
);
265 if (bus_space_map(&tmpiot
, iobase
, 1, 0, &ioh
))
267 rv
= comprobe1(&tmpiot
, ioh
);
268 bus_space_unmap(&tmpiot
, ioh
, 1);
274 com_hpcio_probe(device_t parent
, cfdata_t cf
, void *aux
)
276 struct hpcio_attach_args
*haa
= aux
;
277 bus_space_tag_t iot
= haa
->haa_iot
;
280 if (cf
->cf_loc
[HPCIOIFCF_PLATFORM
] != HPCIOIFCF_PLATFORM_DEFAULT
) {
283 mask
= PLATID_DEREF(cf
->cf_loc
[HPCIOIFCF_PLATFORM
]);
284 if (!platid_match(&platid
, &mask
))
285 return (0); /* platform id didn't match */
288 if ((addr
= cf
->cf_loc
[HPCIOIFCF_ADDR
]) == HPCIOIFCF_ADDR_DEFAULT
)
289 return (0); /* address wasn't specified */
291 return com_hpcio_common_probe(iot
, addr
, &alignment
);
296 com_hpcio_attach(device_t parent
, device_t self
, void *aux
)
298 struct com_hpcio_softc
*hsc
= device_private(self
);
299 struct com_softc
*sc
= &hsc
->hsc_com
;
300 struct hpcio_attach_args
*haa
= aux
;
302 bus_space_handle_t ioh
;
303 int addr
, port
, mode
, alignment
, *loc
;
306 loc
= device_cfdata(sc
->sc_dev
)->cf_loc
;
307 addr
= loc
[HPCIOIFCF_ADDR
];
308 aprint_normal(" addr %x", addr
);
309 if ((com_hpcio_cniot
== haa
->haa_iot
||
310 com_hpcio_cniot
->bs_base
== haa
->haa_iot
) &&
311 com_hpcio_cniobase
== addr
&&
312 com_is_console(com_hpcio_cniot
, addr
, 0)) {
313 iot
= com_hpcio_cniot
;
314 if (com_hpcio_cniot
->bs_base
== haa
->haa_iot
)
315 aprint_normal(", half word aligned");
317 com_hpcio_common_probe(haa
->haa_iot
, addr
, &alignment
);
318 if (alignment
== COM_HPCIO_HALFWORD_ALIGNMENT
) {
319 aprint_normal(", half word aligned");
321 com_hpcio_iot_init(iot
, haa
->haa_iot
);
326 if (bus_space_map(iot
, addr
, 1, 0, &ioh
)) {
327 aprint_error(": can't map bus space\n");
330 COM_INIT_REGS(sc
->sc_regs
, iot
, ioh
, addr
);
335 sc
->sc_frequency
= COM_FREQ
;
338 hsc
->hsc_hc
= (*haa
->haa_getchip
)(haa
->haa_sc
, loc
[HPCIOIFCF_IOCHIP
]);
339 port
= loc
[HPCIOIFCF_PORT
];
340 mode
= HPCIO_INTR_LEVEL
| HPCIO_INTR_HIGH
;
341 hpcio_intr_establish(hsc
->hsc_hc
, port
, mode
, comintr
, sc
);
345 * bus stuff (registershalf word aligned)
348 com_hpcio_iot_init(bus_space_tag_t iot
, bus_space_tag_t base
)
352 iot
->bs_ops
= com_hpcio_bs_ops
; /* structure assignment */
353 iot
->bs_ops
.bs_r_1
= com_hpcio_bs_r_1
;
354 iot
->bs_ops
.bs_w_1
= com_hpcio_bs_w_1
;
355 iot
->bs_ops
.bs_wm_1
= com_hpcio_bs_wm_1
;
359 com_hpcio_bs_r_1(bus_space_tag_t t
, bus_space_handle_t bsh
,
362 return bus_space_read_1(t
->bs_base
, bsh
, offset
* 2);
366 com_hpcio_bs_w_1(bus_space_tag_t t
, bus_space_handle_t bsh
,
367 bus_size_t offset
, u_int8_t value
)
369 bus_space_write_1(t
->bs_base
, bsh
, offset
* 2, value
);
373 com_hpcio_bs_wm_1(bus_space_tag_t t
, bus_space_handle_t bsh
,
374 bus_size_t offset
, const u_int8_t
*addr
, bus_size_t count
)
376 bus_space_write_multi_1(t
->bs_base
, bsh
, offset
* 2, addr
, count
);