1*6b664a71Sisaki /* $NetBSD: slhci_intio.c,v 1.16 2024/01/07 07:58:33 isaki Exp $ */
2dd0e0396Sisaki
3dd0e0396Sisaki /*
4dd0e0396Sisaki * Copyright (c) 2001 The NetBSD Foundation, Inc.
5dd0e0396Sisaki * All rights reserved.
6dd0e0396Sisaki *
7dd0e0396Sisaki * This code is derived from software contributed to The NetBSD Foundation
8dd0e0396Sisaki * by Tetsuya Isaki.
9dd0e0396Sisaki *
10dd0e0396Sisaki * Redistribution and use in source and binary forms, with or without
11dd0e0396Sisaki * modification, are permitted provided that the following conditions
12dd0e0396Sisaki * are met:
13dd0e0396Sisaki * 1. Redistributions of source code must retain the above copyright
14dd0e0396Sisaki * notice, this list of conditions and the following disclaimer.
15dd0e0396Sisaki * 2. Redistributions in binary form must reproduce the above copyright
16dd0e0396Sisaki * notice, this list of conditions and the following disclaimer in the
17dd0e0396Sisaki * documentation and/or other materials provided with the distribution.
18dd0e0396Sisaki *
19dd0e0396Sisaki * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20dd0e0396Sisaki * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21dd0e0396Sisaki * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22dd0e0396Sisaki * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23dd0e0396Sisaki * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24dd0e0396Sisaki * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25dd0e0396Sisaki * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26dd0e0396Sisaki * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27dd0e0396Sisaki * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28dd0e0396Sisaki * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29dd0e0396Sisaki * POSSIBILITY OF SUCH DAMAGE.
30dd0e0396Sisaki */
31dd0e0396Sisaki
32dd0e0396Sisaki /*
33dd0e0396Sisaki * USB part of Nereid Ethernet/USB/Memory board
34dd0e0396Sisaki */
35dd0e0396Sisaki
36ab48a212Slukem #include <sys/cdefs.h>
37*6b664a71Sisaki __KERNEL_RCSID(0, "$NetBSD: slhci_intio.c,v 1.16 2024/01/07 07:58:33 isaki Exp $");
38ab48a212Slukem
39dd0e0396Sisaki #include <sys/param.h>
40dd0e0396Sisaki #include <sys/systm.h>
41dd0e0396Sisaki #include <sys/device.h>
42dd0e0396Sisaki
43dd0e0396Sisaki #include <machine/bus.h>
44dd0e0396Sisaki #include <machine/cpu.h>
45dd0e0396Sisaki
46dd0e0396Sisaki #include <dev/usb/usb.h>
47dd0e0396Sisaki #include <dev/usb/usbdi.h>
48dd0e0396Sisaki #include <dev/usb/usbdivar.h>
49dd0e0396Sisaki
50dd0e0396Sisaki #include <dev/ic/sl811hsreg.h>
51dd0e0396Sisaki #include <dev/ic/sl811hsvar.h>
52dd0e0396Sisaki
53dd0e0396Sisaki #include <arch/x68k/dev/intiovar.h>
54dd0e0396Sisaki
55dd0e0396Sisaki #include <arch/x68k/dev/slhci_intio_var.h>
56dd0e0396Sisaki
575fc34baaSisaki static int slhci_intio_match(device_t, cfdata_t, void *);
585fc34baaSisaki static void slhci_intio_attach(device_t, device_t, void *);
5944c89c76Skiyohara static void slhci_intio_enable_power(void *, enum power_change);
60dd0e0396Sisaki static void slhci_intio_enable_intr(void *, int);
61dd0e0396Sisaki
625fc34baaSisaki CFATTACH_DECL_NEW(slhci_intio, sizeof(struct slhci_intio_softc),
634bf871a7Sthorpej slhci_intio_match, slhci_intio_attach, NULL, NULL);
64dd0e0396Sisaki
6544c89c76Skiyohara #define INTR_ON 1
6644c89c76Skiyohara #define INTR_OFF 0
6744c89c76Skiyohara
68dd0e0396Sisaki static int
slhci_intio_match(device_t parent,cfdata_t cf,void * aux)695fc34baaSisaki slhci_intio_match(device_t parent, cfdata_t cf, void *aux)
70dd0e0396Sisaki {
71dd0e0396Sisaki struct intio_attach_args *ia = aux;
72dd0e0396Sisaki bus_space_tag_t iot = ia->ia_bst;
73dd0e0396Sisaki bus_space_handle_t ioh;
74dd0e0396Sisaki bus_space_handle_t nch;
75dd0e0396Sisaki int nc_addr;
76dd0e0396Sisaki int nc_size;
77dd0e0396Sisaki
78dd0e0396Sisaki if (ia->ia_addr == INTIOCF_ADDR_DEFAULT)
79dd0e0396Sisaki ia->ia_addr = SLHCI_INTIO_ADDR1;
80dd0e0396Sisaki if (ia->ia_intr == INTIOCF_INTR_DEFAULT)
81dd0e0396Sisaki ia->ia_intr = SLHCI_INTIO_INTR1;
82dd0e0396Sisaki
83dd0e0396Sisaki /* fixed parameters */
84dd0e0396Sisaki if ( !(ia->ia_addr == SLHCI_INTIO_ADDR1 &&
85dd0e0396Sisaki ia->ia_intr == SLHCI_INTIO_INTR1 ) &&
86dd0e0396Sisaki !(ia->ia_addr == SLHCI_INTIO_ADDR2 &&
87dd0e0396Sisaki ia->ia_intr == SLHCI_INTIO_INTR2 ) )
88dd0e0396Sisaki return 0;
89dd0e0396Sisaki
9009e97aa9Sisaki /* Whether the SL811 port is accessible or not */
9109e97aa9Sisaki if (badaddr((void *)IIOV(ia->ia_addr)))
9209e97aa9Sisaki return 0;
9309e97aa9Sisaki
94dd0e0396Sisaki /* Whether the control port is accessible or not */
95dd0e0396Sisaki nc_addr = ia->ia_addr + NEREID_ADDR_OFFSET;
96dd0e0396Sisaki nc_size = 0x02;
973b878f89Sisaki if (badbaddr((void *)IIOV(nc_addr)))
98dd0e0396Sisaki return 0;
99dd0e0396Sisaki
100dd0e0396Sisaki /* Map two I/O spaces */
101dd0e0396Sisaki ia->ia_size = SL11_PORTSIZE * 2;
102dd0e0396Sisaki if (bus_space_map(iot, ia->ia_addr, ia->ia_size,
103dd0e0396Sisaki BUS_SPACE_MAP_SHIFTED, &ioh))
104dd0e0396Sisaki return 0;
105dd0e0396Sisaki
106dd0e0396Sisaki if (bus_space_map(iot, nc_addr, nc_size,
107dd0e0396Sisaki BUS_SPACE_MAP_SHIFTED, &nch))
108dd0e0396Sisaki return 0;
109dd0e0396Sisaki
110dd0e0396Sisaki bus_space_unmap(iot, ioh, ia->ia_size);
111dd0e0396Sisaki bus_space_unmap(iot, nch, nc_size);
112dd0e0396Sisaki
113dd0e0396Sisaki return 1;
114dd0e0396Sisaki }
115dd0e0396Sisaki
116dd0e0396Sisaki static void
slhci_intio_attach(device_t parent,device_t self,void * aux)1175fc34baaSisaki slhci_intio_attach(device_t parent, device_t self, void *aux)
118dd0e0396Sisaki {
1195fc34baaSisaki struct slhci_intio_softc *isc = device_private(self);
1205fc34baaSisaki struct slhci_softc *sc = &isc->sc_sc;
121dd0e0396Sisaki struct intio_attach_args *ia = aux;
122dd0e0396Sisaki bus_space_tag_t iot = ia->ia_bst;
123dd0e0396Sisaki bus_space_handle_t ioh;
124dd0e0396Sisaki int nc_addr;
125dd0e0396Sisaki int nc_size;
126dd0e0396Sisaki
1275fc34baaSisaki sc->sc_dev = self;
1284e8e6643Sskrll sc->sc_bus.ub_hcpriv = sc;
1295fc34baaSisaki
130dd0e0396Sisaki printf(": Nereid USB\n");
131dd0e0396Sisaki
132dd0e0396Sisaki /* Map I/O space */
133dd0e0396Sisaki if (bus_space_map(iot, ia->ia_addr, SL11_PORTSIZE * 2,
134dd0e0396Sisaki BUS_SPACE_MAP_SHIFTED, &ioh)) {
135dd0e0396Sisaki printf("%s: can't map I/O space\n",
1365fc34baaSisaki device_xname(self));
137dd0e0396Sisaki return;
138dd0e0396Sisaki }
139dd0e0396Sisaki
140dd0e0396Sisaki nc_addr = ia->ia_addr + NEREID_ADDR_OFFSET;
141dd0e0396Sisaki nc_size = 0x02;
142dd0e0396Sisaki if (bus_space_map(iot, nc_addr, nc_size,
1435fc34baaSisaki BUS_SPACE_MAP_SHIFTED, &isc->sc_nch)) {
144dd0e0396Sisaki printf("%s: can't map I/O control space\n",
1455fc34baaSisaki device_xname(self));
146dd0e0396Sisaki return;
147dd0e0396Sisaki }
148dd0e0396Sisaki
149dd0e0396Sisaki /* Initialize sc */
1505fc34baaSisaki slhci_preinit(sc, slhci_intio_enable_power, iot, ioh, 30,
15144c89c76Skiyohara SL11_IDX_DATA);
152dd0e0396Sisaki
153dd0e0396Sisaki /* Establish the interrupt handler */
15444c89c76Skiyohara if (intio_intr_establish(ia->ia_intr, "slhci", slhci_intr, sc)) {
155dd0e0396Sisaki printf("%s: can't establish interrupt\n",
1565fc34baaSisaki device_xname(self));
157dd0e0396Sisaki return;
158dd0e0396Sisaki }
159dd0e0396Sisaki
160dd0e0396Sisaki /* Reset controller */
1615fc34baaSisaki bus_space_write_1(iot, isc->sc_nch, NEREID_CTRL, NEREID_CTRL_RESET);
162dd0e0396Sisaki delay(40000);
163dd0e0396Sisaki
16444c89c76Skiyohara slhci_intio_enable_intr(sc, INTR_ON);
16544c89c76Skiyohara
166dd0e0396Sisaki /* Attach SL811HS/T */
1675fc34baaSisaki if (slhci_attach(sc))
168dd0e0396Sisaki return;
169dd0e0396Sisaki }
170dd0e0396Sisaki
171dd0e0396Sisaki static void
slhci_intio_enable_power(void * arg,enum power_change mode)17244c89c76Skiyohara slhci_intio_enable_power(void *arg, enum power_change mode)
173dd0e0396Sisaki {
174dd0e0396Sisaki struct slhci_intio_softc *sc = arg;
175dd0e0396Sisaki bus_space_tag_t iot = sc->sc_sc.sc_iot;
176dd0e0396Sisaki u_int8_t r;
177dd0e0396Sisaki
178dd0e0396Sisaki r = bus_space_read_1(iot, sc->sc_nch, NEREID_CTRL);
179dd0e0396Sisaki if (mode == POWER_ON)
180dd0e0396Sisaki bus_space_write_1(iot, sc->sc_nch, NEREID_CTRL,
181dd0e0396Sisaki r | NEREID_CTRL_POWER);
182dd0e0396Sisaki else
183dd0e0396Sisaki bus_space_write_1(iot, sc->sc_nch, NEREID_CTRL,
184dd0e0396Sisaki r & ~NEREID_CTRL_POWER);
185dd0e0396Sisaki }
186dd0e0396Sisaki
187dd0e0396Sisaki static void
slhci_intio_enable_intr(void * arg,int mode)188dd0e0396Sisaki slhci_intio_enable_intr(void *arg, int mode)
189dd0e0396Sisaki {
190dd0e0396Sisaki struct slhci_intio_softc *sc = arg;
191dd0e0396Sisaki bus_space_tag_t iot = sc->sc_sc.sc_iot;
192dd0e0396Sisaki u_int8_t r;
193dd0e0396Sisaki
194dd0e0396Sisaki r = bus_space_read_1(iot, sc->sc_nch, NEREID_CTRL);
195dd0e0396Sisaki if (mode == INTR_ON)
196dd0e0396Sisaki bus_space_write_1(iot, sc->sc_nch, NEREID_CTRL,
197dd0e0396Sisaki r | NEREID_CTRL_INTR);
198dd0e0396Sisaki else
199dd0e0396Sisaki bus_space_write_1(iot, sc->sc_nch, NEREID_CTRL,
200dd0e0396Sisaki r & ~NEREID_CTRL_INTR);
201dd0e0396Sisaki }
202dd0e0396Sisaki
203