tcu.c revision 1.5
11.5Sthorpej/* $NetBSD: tcu.c,v 1.5 2021/04/24 23:36:59 thorpej Exp $ */
21.1Schristos
31.1Schristos/*-
41.1Schristos * Copyright (c) 2016, Felix Deichmann
51.1Schristos * All rights reserved.
61.1Schristos *
71.1Schristos * Redistribution and use in source and binary forms, with or without
81.1Schristos * modification, are permitted provided that the following conditions
91.1Schristos * are met:
101.1Schristos * 1. Redistributions of source code must retain the above copyright
111.1Schristos *    notice, this list of conditions and the following disclaimer.
121.1Schristos * 2. Redistributions in binary form must reproduce the above copyright
131.1Schristos *    notice, this list of conditions and the following disclaimer in the
141.1Schristos *    documentation and/or other materials provided with the distribution.
151.1Schristos *
161.1Schristos * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
171.1Schristos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
181.1Schristos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
191.1Schristos * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
201.1Schristos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
211.1Schristos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
221.1Schristos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
231.1Schristos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
241.1Schristos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
251.1Schristos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
261.1Schristos * POSSIBILITY OF SUCH DAMAGE.
271.1Schristos */
281.1Schristos
291.1Schristos/*
301.1Schristos * flxd TC-USB - TURBOchannel USB host option
311.1Schristos */
321.1Schristos
331.1Schristos#include <sys/cdefs.h>
341.5Sthorpej__KERNEL_RCSID(0, "$NetBSD: tcu.c,v 1.5 2021/04/24 23:36:59 thorpej Exp $");
351.1Schristos
361.1Schristos#include <sys/param.h>
371.1Schristos#include <sys/systm.h>
381.1Schristos#include <sys/device.h>
391.1Schristos#include <sys/gpio.h>
401.1Schristos
411.1Schristos#include <sys/bus.h>
421.1Schristos
431.1Schristos#include <dev/tc/tcvar.h>
441.1Schristos
451.1Schristos#include <dev/gpio/gpiovar.h>
461.1Schristos
471.1Schristos#include "gpio.h"
481.1Schristos#include "slhci_tcu.h"
491.1Schristos
501.1Schristos#define TCU_GPIO_NPINS	8
511.2Schristos
521.2Schristos#define TCU_CPLD_OFFS	0x80
531.2Schristos#define TCU_CPLD_SIZE	(4 * 4)
541.2Schristos
551.2Schristos#define TCU_CFG		0x0
561.2Schristos#define   TCU_CFG_RUN	__BIT(7)	/* write-only */
571.3Sflxd#define   TCU_CFG_S1_1	__BIT(3)	/* read-only */
581.3Sflxd#define   TCU_CFG_S1_2	__BIT(2)	/* read-only */
591.3Sflxd#define   TCU_CFG_S1_3	__BIT(1)	/* read-only */
601.3Sflxd#define   TCU_CFG_S1_4	__BIT(0)	/* read-only */
611.2Schristos#define TCU_GPIO_DIR	0x4
621.2Schristos#define TCU_GPIO_IN	0x8
631.2Schristos#define TCU_GPIO_OUT	0xc
641.1Schristos
651.1Schristosstruct tcu_softc {
661.1Schristos#if NGPIO > 0
671.1Schristos	kmutex_t		sc_gpio_mtx;
681.1Schristos	struct gpio_chipset_tag	sc_gpio_gc;
691.1Schristos	gpio_pin_t		sc_gpio_pins[TCU_GPIO_NPINS];
701.1Schristos	bus_space_tag_t		sc_gpio_iot;
711.1Schristos	bus_space_handle_t	sc_gpio_ioh;
721.1Schristos#endif /* NGPIO > 0 */
731.1Schristos};
741.1Schristos
751.1Schristosstatic int  tcu_match(device_t, cfdata_t, void *);
761.1Schristosstatic void tcu_attach(device_t, device_t, void *);
771.1Schristos
781.1Schristos#if NSLHCI_TCU > 0
791.1Schristosstatic int  tcu_print(void *, const char *);
801.1Schristos#endif /* NSLHCI_TCU > 0 */
811.1Schristos#if NGPIO > 0
821.1Schristosstatic void tcu_gpio_attach(device_t, device_t, void *);
831.1Schristosstatic int  tcu_gpio_read(void *, int);
841.1Schristosstatic void tcu_gpio_write(void *, int, int);
851.1Schristosstatic void tcu_gpio_ctl(void *, int, int);
861.1Schristos#endif /* NGPIO > 0 */
871.1Schristos
881.1SchristosCFATTACH_DECL_NEW(tcu, sizeof(struct tcu_softc),
891.1Schristos    tcu_match, tcu_attach, NULL, NULL);
901.1Schristos
911.1Schristosstatic int
921.1Schristostcu_match(device_t parent, cfdata_t cf, void *aux)
931.1Schristos{
941.1Schristos	struct tc_attach_args *ta = aux;
951.1Schristos
961.1Schristos	if (strncmp("TC-USB  ", ta->ta_modname, TC_ROM_LLEN))
971.1Schristos		return 0;
981.1Schristos
991.1Schristos	return 1;
1001.1Schristos}
1011.1Schristos
1021.1Schristosstatic void
1031.1Schristostcu_attach(device_t parent, device_t self, void *aux)
1041.1Schristos{
1051.2Schristos	struct tc_attach_args *ta = aux;
1061.2Schristos	bus_space_tag_t iot = ta->ta_memt;
1071.2Schristos	bus_space_handle_t ioh;
1081.2Schristos	int error;
1091.2Schristos	uint8_t cfg;
1101.2Schristos	char buf[30];
1111.1Schristos
1121.1Schristos	printf(": TC-USB\n");
1131.2Schristos
1141.2Schristos	error = bus_space_map(iot, ta->ta_addr + TCU_CPLD_OFFS, TCU_CPLD_SIZE,
1151.2Schristos	    0, &ioh);
1161.2Schristos	if (error) {
1171.2Schristos		aprint_error_dev(self, "bus_space_map() failed (%d)\n", error);
1181.2Schristos		return;
1191.2Schristos	}
1201.2Schristos
1211.2Schristos	/*
1221.2Schristos	 * Force reset in case system didn't. SL811 reset pulse and hold time
1231.2Schristos	 * must be min. 16 clocks long (at 48 MHz clock) each.
1241.2Schristos	 */
1251.2Schristos	bus_space_write_1(iot, ioh, TCU_CFG, 0);
1261.2Schristos	DELAY(1000);
1271.2Schristos	bus_space_write_1(iot, ioh, TCU_CFG, TCU_CFG_RUN);
1281.2Schristos	DELAY(1000);
1291.2Schristos
1301.2Schristos	cfg = bus_space_read_1(iot, ioh, TCU_CFG);
1311.2Schristos
1321.2Schristos	bus_space_unmap(iot, ioh, TCU_CPLD_SIZE);
1331.2Schristos
1341.2Schristos	/* Display DIP switch configuration. */
1351.2Schristos	(void)snprintb(buf, sizeof(buf),
1361.2Schristos	    "\177\020"
1371.2Schristos	    "b\3S1-1\0"
1381.2Schristos	    "b\2S1-2\0"
1391.2Schristos	    "b\1S1-3\0"
1401.2Schristos	    "b\0S1-4\0"
1411.2Schristos	    "\0", cfg);
1421.2Schristos	aprint_normal_dev(self, "config %s\n", buf);
1431.2Schristos
1441.3Sflxd	if ((cfg & TCU_CFG_S1_1) != 0 && ta->ta_busspeed != TC_SPEED_12_5_MHZ)
1451.3Sflxd		aprint_error_dev(self, "warning: switch S1-1 asserted with "
1461.4Sflxd		    "clock != 12.5 MHz\n");
1471.3Sflxd
1481.1Schristos#if NSLHCI_TCU > 0
1491.1Schristos	/* Attach slhci. */
1501.5Sthorpej	(void)config_found(self, aux, tcu_print,
1511.5Sthorpej	    CFARG_IATTR, "tcu",
1521.5Sthorpej	    CFARG_EOL);
1531.1Schristos#endif /* NSLHCI_TCU > 0 */
1541.1Schristos#if NGPIO > 0
1551.1Schristos	/* Attach gpio(bus). */
1561.1Schristos	tcu_gpio_attach(parent, self, aux);
1571.1Schristos#endif /* NGPIO > 0 */
1581.1Schristos}
1591.1Schristos
1601.1Schristos#if NSLHCI_TCU > 0
1611.1Schristosstatic int
1621.1Schristostcu_print(void *aux, const char *pnp)
1631.1Schristos{
1641.1Schristos
1651.1Schristos	/* This function is only used for "slhci at tcu". */
1661.1Schristos	if (pnp)
1671.1Schristos		aprint_normal("slhci at %s", pnp);
1681.1Schristos
1691.1Schristos	return UNCONF;
1701.1Schristos}
1711.1Schristos#endif /* NSLHCI_TCU > 0 */
1721.1Schristos
1731.1Schristos#if NGPIO > 0
1741.1Schristosstatic void
1751.1Schristostcu_gpio_attach(device_t parent, device_t self, void *aux)
1761.1Schristos{
1771.1Schristos	struct tcu_softc *sc = device_private(self);
1781.1Schristos	struct tc_attach_args *ta = aux;
1791.1Schristos	struct gpiobus_attach_args gba;
1801.1Schristos	bus_space_tag_t iot = ta->ta_memt;
1811.1Schristos	uint32_t v;
1821.1Schristos	int error;
1831.1Schristos
1841.1Schristos	sc->sc_gpio_iot = iot;
1851.1Schristos
1861.2Schristos	error = bus_space_map(iot, ta->ta_addr + TCU_CPLD_OFFS, TCU_CPLD_SIZE,
1871.1Schristos	    0, &sc->sc_gpio_ioh);
1881.1Schristos	if (error) {
1891.1Schristos		aprint_error_dev(self, "bus_space_map() failed (%d)\n", error);
1901.1Schristos		return;
1911.1Schristos	}
1921.1Schristos
1931.1Schristos	mutex_init(&sc->sc_gpio_mtx, MUTEX_DEFAULT, IPL_NONE);
1941.1Schristos
1951.1Schristos	v = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, TCU_GPIO_DIR);
1961.1Schristos
1971.1Schristos	for (int pin = 0; pin < TCU_GPIO_NPINS; pin++) {
1981.1Schristos		sc->sc_gpio_pins[pin].pin_num = pin;
1991.1Schristos		sc->sc_gpio_pins[pin].pin_caps = GPIO_PIN_INPUT |
2001.1Schristos		    GPIO_PIN_OUTPUT;
2011.1Schristos		sc->sc_gpio_pins[pin].pin_flags = (v & (UINT32_C(1) << pin)) ?
2021.1Schristos		    GPIO_PIN_OUTPUT : GPIO_PIN_INPUT;
2031.1Schristos		sc->sc_gpio_pins[pin].pin_state = tcu_gpio_read(sc, pin);
2041.1Schristos	}
2051.1Schristos
2061.1Schristos	sc->sc_gpio_gc.gp_cookie = sc;
2071.1Schristos	sc->sc_gpio_gc.gp_pin_read = tcu_gpio_read;
2081.1Schristos	sc->sc_gpio_gc.gp_pin_write = tcu_gpio_write;
2091.1Schristos	sc->sc_gpio_gc.gp_pin_ctl = tcu_gpio_ctl;
2101.1Schristos
2111.1Schristos	memset(&gba, 0, sizeof(gba));
2121.1Schristos
2131.1Schristos	gba.gba_gc = &sc->sc_gpio_gc;
2141.1Schristos	gba.gba_pins = sc->sc_gpio_pins;
2151.1Schristos	gba.gba_npins = TCU_GPIO_NPINS;
2161.1Schristos
2171.5Sthorpej	config_found(self, &gba, gpiobus_print,
2181.5Sthorpej	    CFARG_IATTR, "gpiobus",
2191.5Sthorpej	    CFARG_EOL);
2201.1Schristos}
2211.1Schristos
2221.1Schristosstatic int
2231.1Schristostcu_gpio_read(void *arg, int pin)
2241.1Schristos{
2251.1Schristos	struct tcu_softc *sc = arg;
2261.1Schristos	uint32_t v;
2271.1Schristos
2281.1Schristos	mutex_enter(&sc->sc_gpio_mtx);
2291.1Schristos	v = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, TCU_GPIO_IN);
2301.1Schristos	mutex_exit(&sc->sc_gpio_mtx);
2311.1Schristos
2321.1Schristos	return (v & (UINT32_C(1) << pin)) ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
2331.1Schristos}
2341.1Schristos
2351.1Schristosstatic void
2361.1Schristostcu_gpio_write(void *arg, int pin, int val)
2371.1Schristos{
2381.1Schristos	struct tcu_softc *sc = arg;
2391.1Schristos	uint32_t v;
2401.1Schristos
2411.1Schristos	mutex_enter(&sc->sc_gpio_mtx);
2421.1Schristos
2431.1Schristos	v = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, TCU_GPIO_OUT);
2441.1Schristos
2451.1Schristos	if (val == GPIO_PIN_LOW)
2461.1Schristos		v &= ~(UINT32_C(1) << pin);
2471.1Schristos	else if (val == GPIO_PIN_HIGH)
2481.1Schristos		v |= (UINT32_C(1) << pin);
2491.1Schristos
2501.1Schristos	bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, TCU_GPIO_OUT, v);
2511.1Schristos
2521.1Schristos	mutex_exit(&sc->sc_gpio_mtx);
2531.1Schristos}
2541.1Schristos
2551.1Schristosstatic void
2561.1Schristostcu_gpio_ctl(void *arg, int pin, int flags)
2571.1Schristos{
2581.1Schristos	struct tcu_softc *sc = arg;
2591.1Schristos	uint32_t v;
2601.1Schristos
2611.1Schristos	mutex_enter(&sc->sc_gpio_mtx);
2621.1Schristos
2631.1Schristos	v = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, TCU_GPIO_DIR);
2641.1Schristos
2651.1Schristos	if (flags & GPIO_PIN_INPUT)
2661.1Schristos		v &= ~(UINT32_C(1) << pin);
2671.1Schristos	if (flags & GPIO_PIN_OUTPUT)
2681.1Schristos		v |= (UINT32_C(1) << pin);
2691.1Schristos
2701.1Schristos	bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, TCU_GPIO_DIR, v);
2711.1Schristos
2721.1Schristos	mutex_exit(&sc->sc_gpio_mtx);
2731.1Schristos}
2741.1Schristos#endif /* NGPIO > 0 */
275