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