xref: /netbsd-src/sys/dev/tc/tcu.c (revision c7fb772b85b2b5d4cfb282f868f454b4701534fd)
1*c7fb772bSthorpej /* $NetBSD: tcu.c,v 1.6 2021/08/07 16:19:16 thorpej Exp $ */
2cf039764Schristos 
3cf039764Schristos /*-
4cf039764Schristos  * Copyright (c) 2016, Felix Deichmann
5cf039764Schristos  * All rights reserved.
6cf039764Schristos  *
7cf039764Schristos  * Redistribution and use in source and binary forms, with or without
8cf039764Schristos  * modification, are permitted provided that the following conditions
9cf039764Schristos  * are met:
10cf039764Schristos  * 1. Redistributions of source code must retain the above copyright
11cf039764Schristos  *    notice, this list of conditions and the following disclaimer.
12cf039764Schristos  * 2. Redistributions in binary form must reproduce the above copyright
13cf039764Schristos  *    notice, this list of conditions and the following disclaimer in the
14cf039764Schristos  *    documentation and/or other materials provided with the distribution.
15cf039764Schristos  *
16cf039764Schristos  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17cf039764Schristos  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18cf039764Schristos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19cf039764Schristos  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20cf039764Schristos  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21cf039764Schristos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22cf039764Schristos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23cf039764Schristos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24cf039764Schristos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25cf039764Schristos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26cf039764Schristos  * POSSIBILITY OF SUCH DAMAGE.
27cf039764Schristos  */
28cf039764Schristos 
29cf039764Schristos /*
30cf039764Schristos  * flxd TC-USB - TURBOchannel USB host option
31cf039764Schristos  */
32cf039764Schristos 
33cf039764Schristos #include <sys/cdefs.h>
34*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: tcu.c,v 1.6 2021/08/07 16:19:16 thorpej Exp $");
35cf039764Schristos 
36cf039764Schristos #include <sys/param.h>
37cf039764Schristos #include <sys/systm.h>
38cf039764Schristos #include <sys/device.h>
39cf039764Schristos #include <sys/gpio.h>
40cf039764Schristos 
41cf039764Schristos #include <sys/bus.h>
42cf039764Schristos 
43cf039764Schristos #include <dev/tc/tcvar.h>
44cf039764Schristos 
45cf039764Schristos #include <dev/gpio/gpiovar.h>
46cf039764Schristos 
47cf039764Schristos #include "gpio.h"
48cf039764Schristos #include "slhci_tcu.h"
49cf039764Schristos 
50cf039764Schristos #define TCU_GPIO_NPINS	8
519d57a94cSchristos 
529d57a94cSchristos #define TCU_CPLD_OFFS	0x80
539d57a94cSchristos #define TCU_CPLD_SIZE	(4 * 4)
549d57a94cSchristos 
559d57a94cSchristos #define TCU_CFG		0x0
569d57a94cSchristos #define   TCU_CFG_RUN	__BIT(7)	/* write-only */
57cb798baaSflxd #define   TCU_CFG_S1_1	__BIT(3)	/* read-only */
58cb798baaSflxd #define   TCU_CFG_S1_2	__BIT(2)	/* read-only */
59cb798baaSflxd #define   TCU_CFG_S1_3	__BIT(1)	/* read-only */
60cb798baaSflxd #define   TCU_CFG_S1_4	__BIT(0)	/* read-only */
619d57a94cSchristos #define TCU_GPIO_DIR	0x4
629d57a94cSchristos #define TCU_GPIO_IN	0x8
639d57a94cSchristos #define TCU_GPIO_OUT	0xc
64cf039764Schristos 
65cf039764Schristos struct tcu_softc {
66cf039764Schristos #if NGPIO > 0
67cf039764Schristos 	kmutex_t		sc_gpio_mtx;
68cf039764Schristos 	struct gpio_chipset_tag	sc_gpio_gc;
69cf039764Schristos 	gpio_pin_t		sc_gpio_pins[TCU_GPIO_NPINS];
70cf039764Schristos 	bus_space_tag_t		sc_gpio_iot;
71cf039764Schristos 	bus_space_handle_t	sc_gpio_ioh;
72cf039764Schristos #endif /* NGPIO > 0 */
73cf039764Schristos };
74cf039764Schristos 
75cf039764Schristos static int  tcu_match(device_t, cfdata_t, void *);
76cf039764Schristos static void tcu_attach(device_t, device_t, void *);
77cf039764Schristos 
78cf039764Schristos #if NSLHCI_TCU > 0
79cf039764Schristos static int  tcu_print(void *, const char *);
80cf039764Schristos #endif /* NSLHCI_TCU > 0 */
81cf039764Schristos #if NGPIO > 0
82cf039764Schristos static void tcu_gpio_attach(device_t, device_t, void *);
83cf039764Schristos static int  tcu_gpio_read(void *, int);
84cf039764Schristos static void tcu_gpio_write(void *, int, int);
85cf039764Schristos static void tcu_gpio_ctl(void *, int, int);
86cf039764Schristos #endif /* NGPIO > 0 */
87cf039764Schristos 
88cf039764Schristos CFATTACH_DECL_NEW(tcu, sizeof(struct tcu_softc),
89cf039764Schristos     tcu_match, tcu_attach, NULL, NULL);
90cf039764Schristos 
91cf039764Schristos static int
tcu_match(device_t parent,cfdata_t cf,void * aux)92cf039764Schristos tcu_match(device_t parent, cfdata_t cf, void *aux)
93cf039764Schristos {
94cf039764Schristos 	struct tc_attach_args *ta = aux;
95cf039764Schristos 
96cf039764Schristos 	if (strncmp("TC-USB  ", ta->ta_modname, TC_ROM_LLEN))
97cf039764Schristos 		return 0;
98cf039764Schristos 
99cf039764Schristos 	return 1;
100cf039764Schristos }
101cf039764Schristos 
102cf039764Schristos static void
tcu_attach(device_t parent,device_t self,void * aux)103cf039764Schristos tcu_attach(device_t parent, device_t self, void *aux)
104cf039764Schristos {
1059d57a94cSchristos 	struct tc_attach_args *ta = aux;
1069d57a94cSchristos 	bus_space_tag_t iot = ta->ta_memt;
1079d57a94cSchristos 	bus_space_handle_t ioh;
1089d57a94cSchristos 	int error;
1099d57a94cSchristos 	uint8_t cfg;
1109d57a94cSchristos 	char buf[30];
111cf039764Schristos 
112cf039764Schristos 	printf(": TC-USB\n");
1139d57a94cSchristos 
1149d57a94cSchristos 	error = bus_space_map(iot, ta->ta_addr + TCU_CPLD_OFFS, TCU_CPLD_SIZE,
1159d57a94cSchristos 	    0, &ioh);
1169d57a94cSchristos 	if (error) {
1179d57a94cSchristos 		aprint_error_dev(self, "bus_space_map() failed (%d)\n", error);
1189d57a94cSchristos 		return;
1199d57a94cSchristos 	}
1209d57a94cSchristos 
1219d57a94cSchristos 	/*
1229d57a94cSchristos 	 * Force reset in case system didn't. SL811 reset pulse and hold time
1239d57a94cSchristos 	 * must be min. 16 clocks long (at 48 MHz clock) each.
1249d57a94cSchristos 	 */
1259d57a94cSchristos 	bus_space_write_1(iot, ioh, TCU_CFG, 0);
1269d57a94cSchristos 	DELAY(1000);
1279d57a94cSchristos 	bus_space_write_1(iot, ioh, TCU_CFG, TCU_CFG_RUN);
1289d57a94cSchristos 	DELAY(1000);
1299d57a94cSchristos 
1309d57a94cSchristos 	cfg = bus_space_read_1(iot, ioh, TCU_CFG);
1319d57a94cSchristos 
1329d57a94cSchristos 	bus_space_unmap(iot, ioh, TCU_CPLD_SIZE);
1339d57a94cSchristos 
1349d57a94cSchristos 	/* Display DIP switch configuration. */
1359d57a94cSchristos 	(void)snprintb(buf, sizeof(buf),
1369d57a94cSchristos 	    "\177\020"
1379d57a94cSchristos 	    "b\3S1-1\0"
1389d57a94cSchristos 	    "b\2S1-2\0"
1399d57a94cSchristos 	    "b\1S1-3\0"
1409d57a94cSchristos 	    "b\0S1-4\0"
1419d57a94cSchristos 	    "\0", cfg);
1429d57a94cSchristos 	aprint_normal_dev(self, "config %s\n", buf);
1439d57a94cSchristos 
144cb798baaSflxd 	if ((cfg & TCU_CFG_S1_1) != 0 && ta->ta_busspeed != TC_SPEED_12_5_MHZ)
145cb798baaSflxd 		aprint_error_dev(self, "warning: switch S1-1 asserted with "
14611a5313aSflxd 		    "clock != 12.5 MHz\n");
147cb798baaSflxd 
148cf039764Schristos #if NSLHCI_TCU > 0
149cf039764Schristos 	/* Attach slhci. */
1502685996bSthorpej 	(void)config_found(self, aux, tcu_print,
151*c7fb772bSthorpej 	    CFARGS(.iattr = "tcu"));
152cf039764Schristos #endif /* NSLHCI_TCU > 0 */
153cf039764Schristos #if NGPIO > 0
154cf039764Schristos 	/* Attach gpio(bus). */
155cf039764Schristos 	tcu_gpio_attach(parent, self, aux);
156cf039764Schristos #endif /* NGPIO > 0 */
157cf039764Schristos }
158cf039764Schristos 
159cf039764Schristos #if NSLHCI_TCU > 0
160cf039764Schristos static int
tcu_print(void * aux,const char * pnp)161cf039764Schristos tcu_print(void *aux, const char *pnp)
162cf039764Schristos {
163cf039764Schristos 
164cf039764Schristos 	/* This function is only used for "slhci at tcu". */
165cf039764Schristos 	if (pnp)
166cf039764Schristos 		aprint_normal("slhci at %s", pnp);
167cf039764Schristos 
168cf039764Schristos 	return UNCONF;
169cf039764Schristos }
170cf039764Schristos #endif /* NSLHCI_TCU > 0 */
171cf039764Schristos 
172cf039764Schristos #if NGPIO > 0
173cf039764Schristos static void
tcu_gpio_attach(device_t parent,device_t self,void * aux)174cf039764Schristos tcu_gpio_attach(device_t parent, device_t self, void *aux)
175cf039764Schristos {
176cf039764Schristos 	struct tcu_softc *sc = device_private(self);
177cf039764Schristos 	struct tc_attach_args *ta = aux;
178cf039764Schristos 	struct gpiobus_attach_args gba;
179cf039764Schristos 	bus_space_tag_t iot = ta->ta_memt;
180cf039764Schristos 	uint32_t v;
181cf039764Schristos 	int error;
182cf039764Schristos 
183cf039764Schristos 	sc->sc_gpio_iot = iot;
184cf039764Schristos 
1859d57a94cSchristos 	error = bus_space_map(iot, ta->ta_addr + TCU_CPLD_OFFS, TCU_CPLD_SIZE,
186cf039764Schristos 	    0, &sc->sc_gpio_ioh);
187cf039764Schristos 	if (error) {
188cf039764Schristos 		aprint_error_dev(self, "bus_space_map() failed (%d)\n", error);
189cf039764Schristos 		return;
190cf039764Schristos 	}
191cf039764Schristos 
192cf039764Schristos 	mutex_init(&sc->sc_gpio_mtx, MUTEX_DEFAULT, IPL_NONE);
193cf039764Schristos 
194cf039764Schristos 	v = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, TCU_GPIO_DIR);
195cf039764Schristos 
196cf039764Schristos 	for (int pin = 0; pin < TCU_GPIO_NPINS; pin++) {
197cf039764Schristos 		sc->sc_gpio_pins[pin].pin_num = pin;
198cf039764Schristos 		sc->sc_gpio_pins[pin].pin_caps = GPIO_PIN_INPUT |
199cf039764Schristos 		    GPIO_PIN_OUTPUT;
200cf039764Schristos 		sc->sc_gpio_pins[pin].pin_flags = (v & (UINT32_C(1) << pin)) ?
201cf039764Schristos 		    GPIO_PIN_OUTPUT : GPIO_PIN_INPUT;
202cf039764Schristos 		sc->sc_gpio_pins[pin].pin_state = tcu_gpio_read(sc, pin);
203cf039764Schristos 	}
204cf039764Schristos 
205cf039764Schristos 	sc->sc_gpio_gc.gp_cookie = sc;
206cf039764Schristos 	sc->sc_gpio_gc.gp_pin_read = tcu_gpio_read;
207cf039764Schristos 	sc->sc_gpio_gc.gp_pin_write = tcu_gpio_write;
208cf039764Schristos 	sc->sc_gpio_gc.gp_pin_ctl = tcu_gpio_ctl;
209cf039764Schristos 
210cf039764Schristos 	memset(&gba, 0, sizeof(gba));
211cf039764Schristos 
212cf039764Schristos 	gba.gba_gc = &sc->sc_gpio_gc;
213cf039764Schristos 	gba.gba_pins = sc->sc_gpio_pins;
214cf039764Schristos 	gba.gba_npins = TCU_GPIO_NPINS;
215cf039764Schristos 
2162685996bSthorpej 	config_found(self, &gba, gpiobus_print,
217*c7fb772bSthorpej 	    CFARGS(.iattr = "gpiobus"));
218cf039764Schristos }
219cf039764Schristos 
220cf039764Schristos static int
tcu_gpio_read(void * arg,int pin)221cf039764Schristos tcu_gpio_read(void *arg, int pin)
222cf039764Schristos {
223cf039764Schristos 	struct tcu_softc *sc = arg;
224cf039764Schristos 	uint32_t v;
225cf039764Schristos 
226cf039764Schristos 	mutex_enter(&sc->sc_gpio_mtx);
227cf039764Schristos 	v = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, TCU_GPIO_IN);
228cf039764Schristos 	mutex_exit(&sc->sc_gpio_mtx);
229cf039764Schristos 
230cf039764Schristos 	return (v & (UINT32_C(1) << pin)) ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
231cf039764Schristos }
232cf039764Schristos 
233cf039764Schristos static void
tcu_gpio_write(void * arg,int pin,int val)234cf039764Schristos tcu_gpio_write(void *arg, int pin, int val)
235cf039764Schristos {
236cf039764Schristos 	struct tcu_softc *sc = arg;
237cf039764Schristos 	uint32_t v;
238cf039764Schristos 
239cf039764Schristos 	mutex_enter(&sc->sc_gpio_mtx);
240cf039764Schristos 
241cf039764Schristos 	v = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, TCU_GPIO_OUT);
242cf039764Schristos 
243cf039764Schristos 	if (val == GPIO_PIN_LOW)
244cf039764Schristos 		v &= ~(UINT32_C(1) << pin);
245cf039764Schristos 	else if (val == GPIO_PIN_HIGH)
246cf039764Schristos 		v |= (UINT32_C(1) << pin);
247cf039764Schristos 
248cf039764Schristos 	bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, TCU_GPIO_OUT, v);
249cf039764Schristos 
250cf039764Schristos 	mutex_exit(&sc->sc_gpio_mtx);
251cf039764Schristos }
252cf039764Schristos 
253cf039764Schristos static void
tcu_gpio_ctl(void * arg,int pin,int flags)254cf039764Schristos tcu_gpio_ctl(void *arg, int pin, int flags)
255cf039764Schristos {
256cf039764Schristos 	struct tcu_softc *sc = arg;
257cf039764Schristos 	uint32_t v;
258cf039764Schristos 
259cf039764Schristos 	mutex_enter(&sc->sc_gpio_mtx);
260cf039764Schristos 
261cf039764Schristos 	v = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, TCU_GPIO_DIR);
262cf039764Schristos 
263cf039764Schristos 	if (flags & GPIO_PIN_INPUT)
264cf039764Schristos 		v &= ~(UINT32_C(1) << pin);
265cf039764Schristos 	if (flags & GPIO_PIN_OUTPUT)
266cf039764Schristos 		v |= (UINT32_C(1) << pin);
267cf039764Schristos 
268cf039764Schristos 	bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, TCU_GPIO_DIR, v);
269cf039764Schristos 
270cf039764Schristos 	mutex_exit(&sc->sc_gpio_mtx);
271cf039764Schristos }
272cf039764Schristos #endif /* NGPIO > 0 */
273