1 /* $NetBSD: tx39io.c,v 1.20 2006/03/08 02:10:04 christos Exp $ */
4 * Copyright (c) 1999-2001 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.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: tx39io.c,v 1.20 2006/03/08 02:10:04 christos Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/device.h>
39 #include <machine/bus.h>
41 #include <hpcmips/tx/tx39var.h>
42 #include <hpcmips/tx/tx39icureg.h>
43 #define __TX39IO_PRIVATE
44 #include <hpcmips/tx/tx39iovar.h>
45 #include <hpcmips/tx/tx39ioreg.h>
48 #define DPRINTF_ENABLE
49 #define DPRINTF_DEBUG tx39io_debug
51 #include <machine/debug.h>
53 #define ISBITSET(x, s) ((x) & (1 << (s)))
55 int tx39io_match(struct device
*, struct cfdata
*, void *);
56 void tx39io_attach(struct device
*, struct device
*, void *);
58 CFATTACH_DECL(tx39io
, sizeof(struct tx39io_softc
),
59 tx39io_match
, tx39io_attach
, NULL
, NULL
);
62 static void port_intr_disestablish(hpcio_chip_t
, hpcio_intr_handle_t
);
63 static void port_intr_clear(hpcio_chip_t
, hpcio_intr_handle_t
);
65 static void *mfio_intr_establish(hpcio_chip_t
, int, int, int (*)(void *),
67 static int mfio_in(hpcio_chip_t
, int);
68 static void mfio_out(hpcio_chip_t
, int, int);
69 static int mfio_intr_map(int *, int, int);
70 static void mfio_dump(hpcio_chip_t
);
71 static void mfio_update(hpcio_chip_t
);
73 static void *io_intr_establish(hpcio_chip_t
, int, int, int (*)(void *),
76 static int tx391x_io_in(hpcio_chip_t
, int);
77 static void tx391x_io_out(hpcio_chip_t
, int, int);
78 static void tx391x_io_update(hpcio_chip_t
);
79 static int tx391x_io_intr_map(int *, int, int);
82 static int tx392x_io_in(hpcio_chip_t
, int);
83 static void tx392x_io_out(hpcio_chip_t
, int, int);
84 static void tx392x_io_update(hpcio_chip_t
);
85 static int tx392x_io_intr_map(int *, int, int);
87 #if defined TX391X && defined TX392X
88 #define tx39_io_intr_map(t, s, p, m) \
90 ? tx391x_io_intr_map(s
, p
, m
) : tx392x_io_intr_map(s
, p
, m
))
92 #define tx39io_intr_map(t, s, p, m) tx391x_io_intr_map(s, p, m)
94 #define tx39io_intr_map(t, s, p, m) tx392x_io_intr_map(s, p, m)
96 static void io_dump(hpcio_chip_t
);
98 static void __print_port_status(struct tx39io_port_status
*, int);
101 tx39io_match(struct device
*parent
, struct cfdata
*cf
, void *aux
)
103 return (ATTACH_FIRST
); /* 1st attach group of txsim */
107 tx39io_attach(struct device
*parent
, struct device
*self
, void *aux
)
109 struct txsim_attach_args
*ta
= aux
;
110 struct tx39io_softc
*sc
= (void *)self
;
112 struct hpcio_chip
*io_hc
= &sc
->sc_io_ops
;
113 struct hpcio_chip
*mfio_hc
= &sc
->sc_mfio_ops
;
115 tc
= sc
->sc_tc
= ta
->ta_tc
;
118 sc
->sc_stat_io_mask
= ~(1 << 5); /* exclude Plum2 INT */
119 sc
->sc_stat_mfio_mask
= ~(0x3|(0x3 << 23));
122 io_hc
->hc_chipid
= IO
;
123 io_hc
->hc_name
= "IO";
125 io_hc
->hc_intr_establish
= io_intr_establish
;
126 io_hc
->hc_intr_disestablish
= port_intr_disestablish
;
127 io_hc
->hc_intr_clear
= port_intr_clear
;
128 io_hc
->hc_dump
= io_dump
;
131 io_hc
->hc_portread
= tx391x_io_in
;
132 io_hc
->hc_portwrite
= tx391x_io_out
;
133 io_hc
->hc_update
= tx391x_io_update
;
135 } else if (IS_TX392X(tc
)) {
137 io_hc
->hc_portread
= tx392x_io_in
;
138 io_hc
->hc_portwrite
= tx392x_io_out
;
139 io_hc
->hc_update
= tx392x_io_update
;
142 tx_conf_register_ioman(tc
, io_hc
);
145 mfio_hc
->hc_chipid
= MFIO
;
146 mfio_hc
->hc_name
= "MFIO";
148 mfio_hc
->hc_portread
= mfio_in
;
149 mfio_hc
->hc_portwrite
= mfio_out
;
150 mfio_hc
->hc_intr_establish
= mfio_intr_establish
;
151 mfio_hc
->hc_intr_disestablish
= port_intr_disestablish
;
152 mfio_hc
->hc_update
= mfio_update
;
153 mfio_hc
->hc_dump
= mfio_dump
;
155 tx_conf_register_ioman(tc
, mfio_hc
);
158 hpcio_update(mfio_hc
);
163 printf("IO i0x%08x o0x%08x MFIO i0x%08x o0x%08x\n",
164 sc
->sc_stat_io
.in
, sc
->sc_stat_io
.out
,
165 sc
->sc_stat_mfio
.in
, sc
->sc_stat_mfio
.out
);
166 #endif /* TX39IO_DEBUG */
170 * TX391X, TX392X common
173 io_intr_establish(hpcio_chip_t arg
, int port
, int mode
, int (*func
)(void *),
176 struct tx39io_softc
*sc
= arg
->hc_sc
;
179 if (tx39io_intr_map(sc
->sc_tc
, &src
, port
, mode
) != 0)
182 return (tx_intr_establish(sc
->sc_tc
, src
, IST_EDGE
, IPL_CLOCK
, func
,
187 mfio_intr_establish(hpcio_chip_t arg
, int port
, int mode
, int (*func
)(void *),
190 struct tx39io_softc
*sc
= arg
->hc_sc
;
193 if (mfio_intr_map(&src
, port
, mode
) != 0)
196 return (tx_intr_establish(sc
->sc_tc
, src
, IST_EDGE
, IPL_CLOCK
, func
,
201 port_intr_disestablish(hpcio_chip_t arg
, void *ih
)
203 struct tx39io_softc
*sc
= arg
->hc_sc
;
204 tx_intr_disestablish(sc
->sc_tc
, ih
);
208 port_intr_clear(hpcio_chip_t arg
, void *ih
)
213 mfio_out(hpcio_chip_t arg
, int port
, int onoff
)
215 struct tx39io_softc
*sc
= arg
->hc_sc
;
219 DPRINTF("port #%d\n", port
);
224 if (!(sc
->sc_stat_mfio
.dir
& pos
)) {
225 panic("%s: MFIO%d is not output port.",
226 sc
->sc_dev
.dv_xname
, port
);
229 reg
= tx_conf_read(tc
, TX39_IOMFIODATAOUT_REG
);
234 tx_conf_write(tc
, TX39_IOMFIODATAOUT_REG
, reg
);
238 mfio_in(hpcio_chip_t arg
, int port
)
240 struct tx39io_softc
*sc
__attribute__((__unused__
)) = arg
->hc_sc
;
242 DPRINTF("port #%d\n", port
);
243 return (tx_conf_read(sc
->sc_tc
, TX39_IOMFIODATAIN_REG
) & (1 << port
));
247 mfio_intr_map(int *src
, int port
, int mode
)
250 if (mode
& HPCIO_INTR_POSEDGE
) {
251 *src
= MAKEINTR(3, (1 << port
));
253 } else if (mode
& HPCIO_INTR_NEGEDGE
) {
254 *src
= MAKEINTR(4, (1 << port
));
258 DPRINTF("invalid interrupt mode.\n");
264 mfio_update(hpcio_chip_t arg
)
266 struct tx39io_softc
*sc
= arg
->hc_sc
;
267 tx_chipset_tag_t tc
= sc
->sc_tc
;
268 struct tx39io_port_status
*stat_mfio
= &sc
->sc_stat_mfio
;
270 sc
->sc_ostat_mfio
= *stat_mfio
; /* save old status */
271 stat_mfio
->dir
= tx_conf_read(tc
, TX39_IOMFIODATADIR_REG
);
272 stat_mfio
->in
= tx_conf_read(tc
, TX39_IOMFIODATAIN_REG
);
273 stat_mfio
->out
= tx_conf_read(tc
, TX39_IOMFIODATAOUT_REG
);
274 stat_mfio
->power
= tx_conf_read(tc
, TX39_IOMFIOPOWERDWN_REG
);
275 stat_mfio
->u
.select
= tx_conf_read(tc
, TX39_IOMFIODATASEL_REG
);
283 tx391x_io_in(hpcio_chip_t arg
, int port
)
285 struct tx39io_softc
*sc
__attribute__((__unused__
)) = arg
->hc_sc
;
286 txreg_t reg
= tx_conf_read(sc
->sc_tc
, TX39_IOCTRL_REG
);
288 DPRINTF("port #%d\n", port
);
289 return (TX391X_IOCTRL_IODIN(reg
) & (1 << port
));
293 tx391x_io_out(hpcio_chip_t arg
, int port
, int onoff
)
295 struct tx39io_softc
*sc
= arg
->hc_sc
;
297 txreg_t reg
, pos
, iostat
;
300 DPRINTF("port #%d\n", port
);
307 if (!(sc
->sc_stat_io
.dir
& pos
))
308 panic("%s: IO%d is not output port.", sc
->sc_dev
.dv_xname
,
311 reg
= tx_conf_read(tc
, TX39_IOCTRL_REG
);
312 iostat
= TX391X_IOCTRL_IODOUT(reg
);
317 TX391X_IOCTRL_IODOUT_CLR(reg
);
318 reg
= TX391X_IOCTRL_IODOUT_SET(reg
, iostat
);
319 tx_conf_write(tc
, TX39_IOCTRL_REG
, reg
);
323 tx391x_io_update(hpcio_chip_t arg
)
325 struct tx39io_softc
*sc
= arg
->hc_sc
;
326 struct tx39io_port_status
*stat_io
= &sc
->sc_stat_io
;
327 tx_chipset_tag_t tc
= sc
->sc_tc
;
331 sc
->sc_ostat_io
= *stat_io
; /* save old status */
332 reg
= tx_conf_read(tc
, TX39_IOCTRL_REG
);
333 stat_io
->dir
= TX391X_IOCTRL_IODIREC(reg
);
334 stat_io
->in
= TX391X_IOCTRL_IODIN(reg
);
335 stat_io
->out
= TX391X_IOCTRL_IODOUT(reg
);
336 stat_io
->u
.debounce
= TX391X_IOCTRL_IODEBSEL(reg
);
337 reg
= tx_conf_read(tc
, TX39_IOIOPOWERDWN_REG
);
338 stat_io
->power
= TX391X_IOIOPOWERDWN_IOPD(reg
);
342 tx391x_io_intr_map(int *src
, int port
, int mode
)
345 if (mode
& HPCIO_INTR_POSEDGE
) {
346 *src
= MAKEINTR(5, (1 << (port
+ 7)));
348 } else if (mode
& HPCIO_INTR_NEGEDGE
) {
349 *src
= MAKEINTR(5, (1 << port
));
353 DPRINTF("invalid interrupt mode.\n");
364 tx392x_io_in(hpcio_chip_t arg
, int port
)
366 struct tx39io_softc
*sc
__attribute__((__unused__
)) = arg
->hc_sc
;
367 txreg_t reg
= tx_conf_read(sc
->sc_tc
, TX392X_IODATAINOUT_REG
);
369 DPRINTF("port #%d\n", port
);
371 return (TX392X_IODATAINOUT_DIN(reg
) & (1 << port
));
375 tx392x_io_out(hpcio_chip_t arg
, int port
, int onoff
)
377 struct tx39io_softc
*sc
= arg
->hc_sc
;
379 const char *devname
= sc
->sc_dev
.dv_xname
;
381 tx_chipset_tag_t tc
= sc
->sc_tc
;
382 txreg_t reg
, pos
, iostat
;
384 DPRINTF("port #%d\n", port
);
388 if (!(sc
->sc_stat_io
.dir
& pos
))
389 panic("%s: IO%d is not output port.", devname
, port
);
391 reg
= tx_conf_read(tc
, TX392X_IODATAINOUT_REG
);
392 iostat
= TX392X_IODATAINOUT_DOUT(reg
);
397 TX392X_IODATAINOUT_DOUT_CLR(reg
);
398 reg
= TX392X_IODATAINOUT_DOUT_SET(reg
, iostat
);
399 tx_conf_write(tc
, TX392X_IODATAINOUT_REG
, reg
);
403 tx392x_io_intr_map(int *src
, int port
, int mode
)
406 if (mode
& HPCIO_INTR_POSEDGE
) {
407 *src
= MAKEINTR(8, (1 << (port
+ 16)));
409 } else if (mode
& HPCIO_INTR_NEGEDGE
) {
410 *src
= MAKEINTR(8, (1 << port
));
414 DPRINTF("invalid interrupt mode.\n");
420 tx392x_io_update(hpcio_chip_t arg
)
422 struct tx39io_softc
*sc
= arg
->hc_sc
;
423 struct tx39io_port_status
*stat_io
= &sc
->sc_stat_io
;
424 tx_chipset_tag_t tc
= sc
->sc_tc
;
427 sc
->sc_ostat_io
= *stat_io
; /* save old status */
429 reg
= tx_conf_read(tc
, TX39_IOCTRL_REG
);
430 stat_io
->dir
= TX392X_IOCTRL_IODIREC(reg
);
431 stat_io
->u
.debounce
= TX392X_IOCTRL_IODEBSEL(reg
);
432 reg
= tx_conf_read(tc
, TX392X_IODATAINOUT_REG
);
433 stat_io
->in
= TX392X_IODATAINOUT_DIN(reg
);
434 stat_io
->out
= TX392X_IODATAINOUT_DOUT(reg
);
435 reg
= tx_conf_read(tc
, TX39_IOIOPOWERDWN_REG
);
436 stat_io
->power
= TX392X_IOIOPOWERDWN_IOPD(reg
);
441 static const char *line
= "--------------------------------------------------"
444 mfio_dump(hpcio_chip_t arg
)
446 struct tx39io_softc
*sc
= arg
->hc_sc
;
447 const struct tx39io_mfio_map
*map
= tx39io_get_mfio_map(tc
);
448 struct tx39io_port_status
*stat
;
452 stat
= &sc
->sc_stat_mfio
;
453 for (i
= TX39_IO_MFIO_MAX
- 1; i
>= 0 ; i
--) {
454 /* MFIO port has power down state */
455 printf("MFIO %2d: - ", i
);
456 __print_port_status(stat
, i
);
457 printf(ISBITSET(stat
->u
.select
, i
) ? " MFIO(%s)\n" : " %s\n",
458 map
[i
].std_pin_name
);
464 io_dump(hpcio_chip_t arg
)
466 struct tx39io_softc
*sc
= arg
->hc_sc
;
467 struct tx39io_port_status
*stat
;
470 printf("%s Debounce Direction DataOut DataIn PowerDown Select"
472 stat
= &sc
->sc_stat_io
;
473 for (i
= tx39io_get_io_max(tc
) - 1; i
>= 0 ; i
--) {
474 /* IO port has debouncer */
475 printf("IO %2d: %s ", i
,
476 ISBITSET(stat
->u
.debounce
, i
) ? "On " : "Off");
477 __print_port_status(stat
, i
);
483 __print_port_status(struct tx39io_port_status
*stat
, int i
)
485 printf("%s %d %d %s",
486 ISBITSET(stat
->dir
, i
) ? "Out" : "In ",
487 ISBITSET(stat
->out
, i
) ? 1 : 0,
488 ISBITSET(stat
->in
, i
) ? 1 : 0,
489 ISBITSET(stat
->power
, i
) ? "Down ": "Active");