Home | History | Annotate | Line # | Download | only in sam460ex
      1 /*	$NetBSD: samfpga.c,v 1.1 2026/09/28 20:41:00 rkujawa Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2026 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Radoslaw Kujawa.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     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.
     18  *
     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.
     30  */
     31 
     32 /*
     33  * ACube Sam460ex board FPGA.
     34  * GPIO pins via J22 connector, LEDs, soft power off.
     35  */
     36 
     37 #include <sys/cdefs.h>
     38 __KERNEL_RCSID(0, "$NetBSD: samfpga.c,v 1.1 2026/09/28 20:41:00 rkujawa Exp $");
     39 
     40 #include "locators.h"
     41 #include "ioconf.h"
     42 
     43 #include <sys/param.h>
     44 #include <sys/systm.h>
     45 #include <sys/device.h>
     46 #include <sys/bus.h>
     47 #include <sys/mutex.h>
     48 #include <sys/gpio.h>
     49 
     50 #include <dev/gpio/gpiovar.h>
     51 #include <dev/led.h>
     52 
     53 #include <powerpc/ibm4xx/cpu.h>
     54 #include <powerpc/ibm4xx/dev/ebcvar.h>
     55 #include <evbppc/sam460ex/samfpgareg.h>
     56 
     57 #define	SAMFPGA_NLED	3
     58 
     59 struct samfpga_softc;
     60 
     61 struct samfpga_led {
     62 	struct samfpga_softc	*led_sc;
     63 	uint16_t		led_bit;
     64 };
     65 
     66 struct samfpga_softc {
     67 	device_t		sc_dev;
     68 	bus_space_tag_t		sc_bst;
     69 	bus_space_handle_t	sc_bsh;
     70 	kmutex_t		sc_lock;
     71 	struct gpio_chipset_tag	sc_gc;
     72 	gpio_pin_t		sc_pins[SAMFPGA_GPIO_NPINS];
     73 	struct samfpga_led	sc_leds[SAMFPGA_NLED];
     74 };
     75 
     76 static int	samfpga_match(device_t, cfdata_t, void *);
     77 static void	samfpga_attach(device_t, device_t, void *);
     78 
     79 static void	samfpga_powerdown(void);
     80 
     81 static int	samfpga_led_get(void *);
     82 static void	samfpga_led_set(void *, int);
     83 
     84 static int	samfpga_gpio_pin_read(void *, int);
     85 static void	samfpga_gpio_pin_write(void *, int, int);
     86 static void	samfpga_gpio_pin_ctl(void *, int, int);
     87 
     88 CFATTACH_DECL_NEW(samfpga, sizeof(struct samfpga_softc),
     89     samfpga_match, samfpga_attach, NULL, NULL);
     90 
     91 /* J22 pad names. */
     92 static const char samfpga_j22[SAMFPGA_GPIO_NPINS][4] = {
     93 	"B6", "B4", "B8", "B7", "C6", "A4", "A6", "C5",
     94 	"C4", "B5", "D10", "D8", "A8", "D7", "D4", "D5",
     95 	"A5", "B9", "C8", "D6", "C7", "B10", "D9", "C9",
     96 	"A9", "A7", "D11", "D16", "A15", "C10", "B15", "A10",
     97 	"A11", "B14", "C15", "D15", "A14", "C14", "D14", "C13",
     98 	"A13", "D13", "A12", "B13", "D12", "C12", "B12", "C21",
     99 	"B20", "A20", "C20", "D20", "B19", "A19", "C19", "A18",
    100 	"C18", "D19", "C17", "C16", "D18", "A17", "B17", "D17",
    101 	"B16", "A16", "B18", "C22", "A22", "B22", "A23", "B23",
    102 	"B11", "C11", "D21", "A21", "D22", "B21", "D23", "C23",
    103 };
    104 
    105 static const struct {
    106 	const char	*name;
    107 	uint16_t	bit;
    108 } samfpga_led_names[SAMFPGA_NLED] = {
    109 	{ "red",	SAMFPGA_CTL_LED_RED },
    110 	{ "yellow",	SAMFPGA_CTL_LED_YELLOW },
    111 	{ "amber",	SAMFPGA_CTL_LED_AMBER },
    112 };
    113 
    114 static inline uint16_t
    115 samfpga_read(struct samfpga_softc *sc, bus_size_t o)
    116 {
    117 	return bus_space_read_2(sc->sc_bst, sc->sc_bsh, o);
    118 }
    119 
    120 static inline void
    121 samfpga_write(struct samfpga_softc *sc, bus_size_t o, uint16_t v)
    122 {
    123 	bus_space_write_2(sc->sc_bst, sc->sc_bsh, o, v);
    124 }
    125 
    126 static inline unsigned
    127 samfpga_bcd(unsigned v)
    128 {
    129 	return (v >> 4) * 10 + (v & 0xf);
    130 }
    131 
    132 static int
    133 samfpga_match(device_t parent, cfdata_t cf, void *aux)
    134 {
    135 	struct ebc_attach_args * const eaa = aux;
    136 
    137 	if (eaa->ebc_width != 16 || eaa->ebc_usage != EBC_USAGE_RW ||
    138 	    eaa->ebc_size < SAMFPGA_SIZE)
    139 		return 0;
    140 
    141 	return 1;
    142 }
    143 
    144 static void
    145 samfpga_attach(device_t parent, device_t self, void *aux)
    146 {
    147 	struct samfpga_softc * const sc = device_private(self);
    148 	struct ebc_attach_args * const eaa = aux;
    149 	struct gpiobus_attach_args gba;
    150 	uint16_t date, year;
    151 	int i;
    152 
    153 	sc->sc_dev = self;
    154 	sc->sc_bst = eaa->ebc_bt;
    155 
    156 	if (bus_space_map(sc->sc_bst, eaa->ebc_addr, SAMFPGA_SIZE, 0,
    157 	    &sc->sc_bsh) != 0) {
    158 		aprint_error(": can't map registers\n");
    159 		return;
    160 	}
    161 
    162 	date = samfpga_read(sc, SAMFPGA_REV_DATE);
    163 	year = samfpga_read(sc, SAMFPGA_REV_YEAR);
    164 
    165 	aprint_naive(": board FPGA\n");
    166 	aprint_normal(": board FPGA, revision %u (20%02u-%02u-%02u)\n",
    167 	    samfpga_bcd(__SHIFTOUT(year, SAMFPGA_REV_YEAR_REV)),
    168 	    samfpga_bcd(__SHIFTOUT(year, SAMFPGA_REV_YEAR_YEAR)),
    169 	    samfpga_bcd(__SHIFTOUT(date, SAMFPGA_REV_DATE_MONTH)),
    170 	    samfpga_bcd(__SHIFTOUT(date, SAMFPGA_REV_DATE_DAY)));
    171 	aprint_verbose_dev(self, "rev 0x%04x 0x%04x ctl 0x%04x usb 0x%04x\n",
    172 	    date, year, samfpga_read(sc, SAMFPGA_CTL),
    173 	    samfpga_read(sc, SAMFPGA_USB));
    174 	for (i = 0; i < SAMFPGA_GPIO_NBANK; i++)
    175 		aprint_verbose_dev(self,
    176 		    "bank %d: dir 0x%04x out 0x%04x in 0x%04x\n", i,
    177 		    samfpga_read(sc, SAMFPGA_GPIO_DIR(i)),
    178 		    samfpga_read(sc, SAMFPGA_GPIO_OUT(i)),
    179 		    samfpga_read(sc, SAMFPGA_GPIO_IN(i)));
    180 
    181 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
    182 
    183 	for (i = 0; i < SAMFPGA_GPIO_NPINS; i++) {
    184 		gpio_pin_t * const pin = &sc->sc_pins[i];
    185 		const int bank = SAMFPGA_GPIO_BANK(i);
    186 		const uint16_t bit = SAMFPGA_GPIO_BIT(i);
    187 
    188 		pin->pin_num = i;
    189 		pin->pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
    190 		pin->pin_flags =
    191 		    (samfpga_read(sc, SAMFPGA_GPIO_DIR(bank)) & bit) ?
    192 		    GPIO_PIN_OUTPUT : GPIO_PIN_INPUT;
    193 		pin->pin_state =
    194 		    (samfpga_read(sc, SAMFPGA_GPIO_IN(bank)) & bit) ?
    195 		    GPIO_PIN_HIGH : GPIO_PIN_LOW;
    196 		snprintf(pin->pin_defname, sizeof(pin->pin_defname),
    197 		    "J22-%s", samfpga_j22[i]);
    198 	}
    199 
    200 	sc->sc_gc.gp_cookie = sc;
    201 	sc->sc_gc.gp_pin_read = samfpga_gpio_pin_read;
    202 	sc->sc_gc.gp_pin_write = samfpga_gpio_pin_write;
    203 	sc->sc_gc.gp_pin_ctl = samfpga_gpio_pin_ctl;
    204 
    205 	gba.gba_gc = &sc->sc_gc;
    206 	gba.gba_pins = sc->sc_pins;
    207 	gba.gba_npins = SAMFPGA_GPIO_NPINS;
    208 
    209 	config_found(self, &gba, gpiobus_print, CFARGS_NONE);
    210 
    211 	for (i = 0; i < SAMFPGA_NLED; i++) {
    212 		sc->sc_leds[i].led_sc = sc;
    213 		sc->sc_leds[i].led_bit = samfpga_led_names[i].bit;
    214 		if (led_attach(samfpga_led_names[i].name, &sc->sc_leds[i],
    215 		    samfpga_led_get, samfpga_led_set) == NULL)
    216 			aprint_error_dev(self, "can't attach led %s\n",
    217 			    samfpga_led_names[i].name);
    218 	}
    219 
    220 	md_powerdown = samfpga_powerdown;
    221 }
    222 
    223 static int
    224 samfpga_led_get(void *arg)
    225 {
    226 	struct samfpga_led * const led = arg;
    227 
    228 	return (samfpga_read(led->led_sc, SAMFPGA_CTL) & led->led_bit) ?
    229 	    LED_STATE_ON : LED_STATE_OFF;
    230 }
    231 
    232 static void
    233 samfpga_led_set(void *arg, int state)
    234 {
    235 	struct samfpga_led * const led = arg;
    236 	struct samfpga_softc * const sc = led->led_sc;
    237 	uint16_t v;
    238 
    239 	mutex_enter(&sc->sc_lock);
    240 	v = samfpga_read(sc, SAMFPGA_CTL);
    241 	if (state == LED_STATE_ON)
    242 		v |= led->led_bit;
    243 	else
    244 		v &= ~led->led_bit;
    245 	samfpga_write(sc, SAMFPGA_CTL, v);
    246 	mutex_exit(&sc->sc_lock);
    247 }
    248 
    249 static void
    250 samfpga_powerdown(void)
    251 {
    252 	struct samfpga_softc * const sc = device_lookup_private(&samfpga_cd, 0);
    253 	int i;
    254 
    255 	if (sc == NULL)
    256 		return;
    257 
    258 	/* Flash x3, then hold RESET. */
    259 	for (i = 0; i < 3; i++) {
    260 		samfpga_write(sc, SAMFPGA_CTL, (i & 1) ? 0 : SAMFPGA_CTL_LEDS);
    261 		delay(300 * 1000);
    262 	}
    263 	samfpga_write(sc, SAMFPGA_CTL, SAMFPGA_CTL_RESET);
    264 	delay(1000 * 1000);
    265 }
    266 
    267 static int
    268 samfpga_gpio_pin_read(void *arg, int pin)
    269 {
    270 	struct samfpga_softc * const sc = arg;
    271 	const int bank = SAMFPGA_GPIO_BANK(pin);
    272 
    273 	return (samfpga_read(sc, SAMFPGA_GPIO_IN(bank)) &
    274 	    SAMFPGA_GPIO_BIT(pin)) ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
    275 }
    276 
    277 static void
    278 samfpga_gpio_pin_write(void *arg, int pin, int value)
    279 {
    280 	struct samfpga_softc * const sc = arg;
    281 	const bus_size_t reg = SAMFPGA_GPIO_OUT(SAMFPGA_GPIO_BANK(pin));
    282 	const uint16_t bit = SAMFPGA_GPIO_BIT(pin);
    283 	uint16_t v;
    284 
    285 	mutex_enter(&sc->sc_lock);
    286 	v = samfpga_read(sc, reg);
    287 	if (value == GPIO_PIN_LOW)
    288 		v &= ~bit;
    289 	else
    290 		v |= bit;
    291 	samfpga_write(sc, reg, v);
    292 	mutex_exit(&sc->sc_lock);
    293 }
    294 
    295 static void
    296 samfpga_gpio_pin_ctl(void *arg, int pin, int flags)
    297 {
    298 	struct samfpga_softc * const sc = arg;
    299 	const bus_size_t reg = SAMFPGA_GPIO_DIR(SAMFPGA_GPIO_BANK(pin));
    300 	const uint16_t bit = SAMFPGA_GPIO_BIT(pin);
    301 	uint16_t v;
    302 
    303 	if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) == 0)
    304 		return;
    305 
    306 	mutex_enter(&sc->sc_lock);
    307 	v = samfpga_read(sc, reg);
    308 	if (flags & GPIO_PIN_OUTPUT)
    309 		v |= bit;
    310 	else
    311 		v &= ~bit;
    312 	samfpga_write(sc, reg, v);
    313 	mutex_exit(&sc->sc_lock);
    314 }
    315 
    316