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