samfpga.c revision 1.1 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