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