drivers/bcm2835gpio: Migrate to adapter gpio commands
[fw/openocd] / src / jtag / drivers / bcm2835gpio.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /***************************************************************************
4  *   Copyright (C) 2013 by Paul Fertser, fercerpav@gmail.com               *
5  *                                                                         *
6  *   Copyright (C) 2012 by Creative Product Design, marc @ cpdesign.com.au *
7  *   Based on at91rm9200.c (c) Anders Larsen                               *
8  *   and RPi GPIO examples by Gert van Loo & Dom                           *
9  ***************************************************************************/
10
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14
15 #include <jtag/adapter.h>
16 #include <jtag/interface.h>
17 #include <transport/transport.h>
18 #include "bitbang.h"
19
20 #include <sys/mman.h>
21
22 uint32_t bcm2835_peri_base = 0x20000000;
23 #define BCM2835_GPIO_BASE       (bcm2835_peri_base + 0x200000) /* GPIO controller */
24
25 #define BCM2835_PADS_GPIO_0_27          (bcm2835_peri_base + 0x100000)
26 #define BCM2835_PADS_GPIO_0_27_OFFSET   (0x2c / 4)
27
28 /* See "GPIO Function Select Registers (GPFSELn)" in "Broadcom BCM2835 ARM Peripherals" datasheet. */
29 #define BCM2835_GPIO_MODE_INPUT 0
30 #define BCM2835_GPIO_MODE_OUTPUT 1
31
32 /* GPIO setup macros */
33 #define MODE_GPIO(g) (*(pio_base+((g)/10))>>(((g)%10)*3) & 7)
34 #define INP_GPIO(g) do { *(pio_base+((g)/10)) &= ~(7<<(((g)%10)*3)); } while (0)
35 #define SET_MODE_GPIO(g, m) do { /* clear the mode bits first, then set as necessary */ \
36                 INP_GPIO(g);                                            \
37                 *(pio_base+((g)/10)) |=  ((m)<<(((g)%10)*3)); } while (0)
38 #define OUT_GPIO(g) SET_MODE_GPIO(g, BCM2835_GPIO_MODE_OUTPUT)
39
40 #define GPIO_SET (*(pio_base+7))  /* sets   bits which are 1, ignores bits which are 0 */
41 #define GPIO_CLR (*(pio_base+10)) /* clears bits which are 1, ignores bits which are 0 */
42 #define GPIO_LEV (*(pio_base+13)) /* current level of the pin */
43
44 static int dev_mem_fd;
45 static volatile uint32_t *pio_base = MAP_FAILED;
46 static volatile uint32_t *pads_base = MAP_FAILED;
47
48 /* Transition delay coefficients */
49 static int speed_coeff = 113714;
50 static int speed_offset = 28;
51 static unsigned int jtag_delay;
52
53 static const struct adapter_gpio_config *adapter_gpio_config;
54 static int initial_gpio_mode[ADAPTER_GPIO_IDX_NUM];
55
56 static bool is_gpio_config_valid(enum adapter_gpio_config_index idx)
57 {
58         /* Only chip 0 is supported, accept unset value (-1) too */
59         return adapter_gpio_config[idx].chip_num >= -1
60                 && adapter_gpio_config[idx].chip_num <= 0
61                 && adapter_gpio_config[idx].gpio_num >= 0
62                 && adapter_gpio_config[idx].gpio_num <= 31;
63 }
64
65 static void set_gpio_value(const struct adapter_gpio_config *gpio_config, int value)
66 {
67         value = value ^ (gpio_config->active_low ? 1 : 0);
68         switch (gpio_config->drive) {
69         case ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL:
70                 if (value)
71                         GPIO_SET = 1 << gpio_config->gpio_num;
72                 else
73                         GPIO_CLR = 1 << gpio_config->gpio_num;
74                 /* For performance reasons assume the GPIO is already set as an output
75                  * and therefore the call can be omitted here.
76                  */
77                 break;
78         case ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN:
79                 if (value) {
80                         INP_GPIO(gpio_config->gpio_num);
81                 } else {
82                         GPIO_CLR = 1 << gpio_config->gpio_num;
83                         OUT_GPIO(gpio_config->gpio_num);
84                 }
85                 break;
86         case ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE:
87                 if (value) {
88                         GPIO_SET = 1 << gpio_config->gpio_num;
89                         OUT_GPIO(gpio_config->gpio_num);
90                 } else {
91                         INP_GPIO(gpio_config->gpio_num);
92                 }
93                 break;
94         }
95 }
96
97 static void restore_gpio(enum adapter_gpio_config_index idx)
98 {
99         if (is_gpio_config_valid(idx))
100                 SET_MODE_GPIO(adapter_gpio_config[idx].gpio_num, initial_gpio_mode[idx]);
101 }
102
103 static void initialize_gpio(enum adapter_gpio_config_index idx)
104 {
105         if (!is_gpio_config_valid(idx))
106                 return;
107
108         initial_gpio_mode[idx] = MODE_GPIO(adapter_gpio_config[idx].gpio_num);
109         LOG_DEBUG("saved GPIO mode for %s (GPIO %d %d): %d",
110                         adapter_gpio_get_name(idx), adapter_gpio_config[idx].chip_num, adapter_gpio_config[idx].gpio_num,
111                         initial_gpio_mode[idx]);
112
113         if (adapter_gpio_config[idx].pull != ADAPTER_GPIO_PULL_NONE) {
114                 LOG_WARNING("BCM2835 GPIO does not support pull-up or pull-down settings (signal %s)",
115                         adapter_gpio_get_name(idx));
116         }
117
118         switch (adapter_gpio_config[idx].init_state) {
119         case ADAPTER_GPIO_INIT_STATE_INACTIVE:
120                 set_gpio_value(&adapter_gpio_config[idx], 0);
121                 break;
122         case ADAPTER_GPIO_INIT_STATE_ACTIVE:
123                 set_gpio_value(&adapter_gpio_config[idx], 1);
124                 break;
125         case ADAPTER_GPIO_INIT_STATE_INPUT:
126                 INP_GPIO(adapter_gpio_config[idx].gpio_num);
127                 break;
128         }
129
130         /* Direction for non push-pull is already set by set_gpio_value() */
131         if (adapter_gpio_config[idx].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL)
132                 OUT_GPIO(adapter_gpio_config[idx].gpio_num);
133 }
134
135 static bb_value_t bcm2835gpio_read(void)
136 {
137         unsigned int shift = adapter_gpio_config[ADAPTER_GPIO_IDX_TDO].gpio_num;
138         uint32_t value = (GPIO_LEV >> shift) & 1;
139         return value ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_TDO].active_low ? BB_HIGH : BB_LOW);
140
141 }
142
143 static int bcm2835gpio_write(int tck, int tms, int tdi)
144 {
145         uint32_t set = tck << adapter_gpio_config[ADAPTER_GPIO_IDX_TCK].gpio_num |
146                         tms << adapter_gpio_config[ADAPTER_GPIO_IDX_TMS].gpio_num |
147                         tdi << adapter_gpio_config[ADAPTER_GPIO_IDX_TDI].gpio_num;
148         uint32_t clear = !tck << adapter_gpio_config[ADAPTER_GPIO_IDX_TCK].gpio_num |
149                         !tms << adapter_gpio_config[ADAPTER_GPIO_IDX_TMS].gpio_num |
150                         !tdi << adapter_gpio_config[ADAPTER_GPIO_IDX_TDI].gpio_num;
151
152         GPIO_SET = set;
153         GPIO_CLR = clear;
154
155         for (unsigned int i = 0; i < jtag_delay; i++)
156                 asm volatile ("");
157
158         return ERROR_OK;
159 }
160
161 /* Requires push-pull drive mode for swclk and swdio */
162 static int bcm2835gpio_swd_write_fast(int swclk, int swdio)
163 {
164         swclk = swclk ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].active_low ? 1 : 0);
165         swdio = swdio ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].active_low ? 1 : 0);
166
167         uint32_t set = swclk << adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].gpio_num |
168                                         swdio << adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num;
169         uint32_t clear = !swclk << adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].gpio_num |
170                                         !swdio << adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num;
171
172         GPIO_SET = set;
173         GPIO_CLR = clear;
174
175         for (unsigned int i = 0; i < jtag_delay; i++)
176                 asm volatile ("");
177
178         return ERROR_OK;
179 }
180
181 /* Generic mode that works for open-drain/open-source drive modes, but slower */
182 static int bcm2835gpio_swd_write_generic(int swclk, int swdio)
183 {
184         set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO], swdio);
185         set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK], swclk); /* Write clock last */
186
187         for (unsigned int i = 0; i < jtag_delay; ++i)
188                 asm volatile ("");
189
190         return ERROR_OK;
191 }
192
193 /* (1) assert or (0) deassert reset lines */
194 static int bcm2835gpio_reset(int trst, int srst)
195 {
196         /* As the "adapter reset_config" command keeps the srst and trst gpio drive
197          * mode settings in sync we can use our standard set_gpio_value() function
198          * that honours drive mode and active low.
199          */
200         if (is_gpio_config_valid(ADAPTER_GPIO_IDX_SRST))
201                 set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SRST], srst);
202
203         if (is_gpio_config_valid(ADAPTER_GPIO_IDX_TRST))
204                 set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_TRST], trst);
205
206         LOG_DEBUG("BCM2835 GPIO: bcm2835gpio_reset(%d, %d), trst_gpio: %d %d, srst_gpio: %d %d",
207                 trst, srst,
208                 adapter_gpio_config[ADAPTER_GPIO_IDX_TRST].chip_num, adapter_gpio_config[ADAPTER_GPIO_IDX_TRST].gpio_num,
209                 adapter_gpio_config[ADAPTER_GPIO_IDX_SRST].chip_num, adapter_gpio_config[ADAPTER_GPIO_IDX_SRST].gpio_num);
210         return ERROR_OK;
211 }
212
213 static void bcm2835_swdio_drive(bool is_output)
214 {
215         if (is_output) {
216                 if (is_gpio_config_valid(ADAPTER_GPIO_IDX_SWDIO_DIR))
217                         set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR], 1);
218                 OUT_GPIO(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num);
219         } else {
220                 INP_GPIO(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num);
221                 if (is_gpio_config_valid(ADAPTER_GPIO_IDX_SWDIO_DIR))
222                         set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR], 0);
223         }
224 }
225
226 static int bcm2835_swdio_read(void)
227 {
228         unsigned int shift = adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num;
229         uint32_t value = (GPIO_LEV >> shift) & 1;
230         return value ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].active_low ? 1 : 0);
231 }
232
233 static int bcm2835gpio_khz(int khz, int *jtag_speed)
234 {
235         if (!khz) {
236                 LOG_DEBUG("BCM2835 GPIO: RCLK not supported");
237                 return ERROR_FAIL;
238         }
239         *jtag_speed = speed_coeff/khz - speed_offset;
240         if (*jtag_speed < 0)
241                 *jtag_speed = 0;
242         return ERROR_OK;
243 }
244
245 static int bcm2835gpio_speed_div(int speed, int *khz)
246 {
247         *khz = speed_coeff/(speed + speed_offset);
248         return ERROR_OK;
249 }
250
251 static int bcm2835gpio_speed(int speed)
252 {
253         jtag_delay = speed;
254         return ERROR_OK;
255 }
256
257 COMMAND_HANDLER(bcm2835gpio_handle_speed_coeffs)
258 {
259         if (CMD_ARGC == 2) {
260                 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], speed_coeff);
261                 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], speed_offset);
262         }
263
264         command_print(CMD, "BCM2835 GPIO: speed_coeffs = %d, speed_offset = %d",
265                                   speed_coeff, speed_offset);
266         return ERROR_OK;
267 }
268
269 COMMAND_HANDLER(bcm2835gpio_handle_peripheral_base)
270 {
271         if (CMD_ARGC == 1)
272                 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], bcm2835_peri_base);
273
274         command_print(CMD, "BCM2835 GPIO: peripheral_base = 0x%08x",
275                                   bcm2835_peri_base);
276         return ERROR_OK;
277 }
278
279 static const struct command_registration bcm2835gpio_subcommand_handlers[] = {
280         {
281                 .name = "speed_coeffs",
282                 .handler = &bcm2835gpio_handle_speed_coeffs,
283                 .mode = COMMAND_CONFIG,
284                 .help = "SPEED_COEFF and SPEED_OFFSET for delay calculations.",
285                 .usage = "[SPEED_COEFF SPEED_OFFSET]",
286         },
287         {
288                 .name = "peripheral_base",
289                 .handler = &bcm2835gpio_handle_peripheral_base,
290                 .mode = COMMAND_CONFIG,
291                 .help = "peripheral base to access GPIOs (RPi1 0x20000000, RPi2 0x3F000000).",
292                 .usage = "[base]",
293         },
294
295         COMMAND_REGISTRATION_DONE
296 };
297
298 static const struct command_registration bcm2835gpio_command_handlers[] = {
299         {
300                 .name = "bcm2835gpio",
301                 .mode = COMMAND_ANY,
302                 .help = "perform bcm2835gpio management",
303                 .chain = bcm2835gpio_subcommand_handlers,
304                 .usage = "",
305         },
306         COMMAND_REGISTRATION_DONE
307 };
308
309 static bool bcm2835gpio_jtag_mode_possible(void)
310 {
311         if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TCK))
312                 return false;
313         if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TMS))
314                 return false;
315         if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TDI))
316                 return false;
317         if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TDO))
318                 return false;
319         return true;
320 }
321
322 static bool bcm2835gpio_swd_mode_possible(void)
323 {
324         if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_SWCLK))
325                 return false;
326         if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_SWDIO))
327                 return false;
328         return true;
329 }
330
331 static void bcm2835gpio_munmap(void)
332 {
333         if (pio_base != MAP_FAILED) {
334                 munmap((void *)pio_base, sysconf(_SC_PAGE_SIZE));
335                 pio_base = MAP_FAILED;
336         }
337
338         if (pads_base != MAP_FAILED) {
339                 munmap((void *)pads_base, sysconf(_SC_PAGE_SIZE));
340                 pads_base = MAP_FAILED;
341         }
342 }
343
344 static struct bitbang_interface bcm2835gpio_bitbang = {
345         .read = bcm2835gpio_read,
346         .write = bcm2835gpio_write,
347         .swdio_read = bcm2835_swdio_read,
348         .swdio_drive = bcm2835_swdio_drive,
349         .swd_write = bcm2835gpio_swd_write_generic,
350         .blink = NULL
351 };
352
353 static int bcm2835gpio_init(void)
354 {
355         LOG_INFO("BCM2835 GPIO JTAG/SWD bitbang driver");
356
357         bitbang_interface = &bcm2835gpio_bitbang;
358         adapter_gpio_config = adapter_gpio_get_config();
359
360         if (transport_is_jtag() && !bcm2835gpio_jtag_mode_possible()) {
361                 LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode");
362                 return ERROR_JTAG_INIT_FAILED;
363         }
364
365         if (transport_is_swd() && !bcm2835gpio_swd_mode_possible()) {
366                 LOG_ERROR("Require swclk and swdio gpio for SWD mode");
367                 return ERROR_JTAG_INIT_FAILED;
368         }
369
370         dev_mem_fd = open("/dev/gpiomem", O_RDWR | O_SYNC);
371         if (dev_mem_fd < 0) {
372                 LOG_DEBUG("Cannot open /dev/gpiomem, fallback to /dev/mem");
373                 dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
374         }
375         if (dev_mem_fd < 0) {
376                 LOG_ERROR("open: %s", strerror(errno));
377                 return ERROR_JTAG_INIT_FAILED;
378         }
379
380         pio_base = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE,
381                                 MAP_SHARED, dev_mem_fd, BCM2835_GPIO_BASE);
382
383         if (pio_base == MAP_FAILED) {
384                 LOG_ERROR("mmap: %s", strerror(errno));
385                 close(dev_mem_fd);
386                 return ERROR_JTAG_INIT_FAILED;
387         }
388
389         pads_base = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE,
390                                 MAP_SHARED, dev_mem_fd, BCM2835_PADS_GPIO_0_27);
391
392         if (pads_base == MAP_FAILED) {
393                 LOG_ERROR("mmap: %s", strerror(errno));
394                 bcm2835gpio_munmap();
395                 close(dev_mem_fd);
396                 return ERROR_JTAG_INIT_FAILED;
397         }
398
399         close(dev_mem_fd);
400
401         /* set 4mA drive strength, slew rate limited, hysteresis on */
402         pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5a000008 + 1;
403
404         /* Configure JTAG/SWD signals. Default directions and initial states are handled
405          * by adapter.c and "adapter gpio" command.
406          */
407         if (transport_is_jtag()) {
408                 initialize_gpio(ADAPTER_GPIO_IDX_TDO);
409                 initialize_gpio(ADAPTER_GPIO_IDX_TDI);
410                 initialize_gpio(ADAPTER_GPIO_IDX_TMS);
411                 initialize_gpio(ADAPTER_GPIO_IDX_TCK);
412                 initialize_gpio(ADAPTER_GPIO_IDX_TRST);
413         }
414
415         if (transport_is_swd()) {
416                 /* swdio and its buffer should be initialized in the order that prevents
417                  * two outputs from being connected together. This will occur if the
418                  * swdio GPIO of the AM335x is configured as an output while its
419                  * external buffer is configured to send the swdio signal from the
420                  * target to the AM335x.
421                  */
422                 if (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].init_state == ADAPTER_GPIO_INIT_STATE_INPUT) {
423                         initialize_gpio(ADAPTER_GPIO_IDX_SWDIO);
424                         initialize_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR);
425                 } else {
426                         initialize_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR);
427                         initialize_gpio(ADAPTER_GPIO_IDX_SWDIO);
428                 }
429
430                 initialize_gpio(ADAPTER_GPIO_IDX_SWCLK);
431
432                 if (adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL &&
433                                 adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL) {
434                         LOG_DEBUG("BCM2835 GPIO using fast mode for SWD write");
435                         bcm2835gpio_bitbang.swd_write = bcm2835gpio_swd_write_fast;
436                 } else {
437                         LOG_DEBUG("BCM2835 GPIO using generic mode for SWD write");
438                         bcm2835gpio_bitbang.swd_write = bcm2835gpio_swd_write_generic;
439                 }
440         }
441
442         initialize_gpio(ADAPTER_GPIO_IDX_SRST);
443
444         return ERROR_OK;
445 }
446
447 static int bcm2835gpio_quit(void)
448 {
449         if (transport_is_jtag()) {
450                 restore_gpio(ADAPTER_GPIO_IDX_TDO);
451                 restore_gpio(ADAPTER_GPIO_IDX_TDI);
452                 restore_gpio(ADAPTER_GPIO_IDX_TCK);
453                 restore_gpio(ADAPTER_GPIO_IDX_TMS);
454                 restore_gpio(ADAPTER_GPIO_IDX_TRST);
455         }
456
457         if (transport_is_swd()) {
458                 /* Restore swdio/swdio_dir to their initial modes, even if that means
459                  * connecting two outputs. Begin by making swdio an input so that the
460                  * current and final states of swdio and swdio_dir do not have to be
461                  * considered to calculate the safe restoration order.
462                  */
463                 INP_GPIO(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num);
464                 restore_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR);
465                 restore_gpio(ADAPTER_GPIO_IDX_SWDIO);
466                 restore_gpio(ADAPTER_GPIO_IDX_SWCLK);
467         }
468
469         restore_gpio(ADAPTER_GPIO_IDX_SRST);
470
471         bcm2835gpio_munmap();
472
473         return ERROR_OK;
474 }
475
476
477 static const char * const bcm2835_transports[] = { "jtag", "swd", NULL };
478
479 static struct jtag_interface bcm2835gpio_interface = {
480         .supported = DEBUG_CAP_TMS_SEQ,
481         .execute_queue = bitbang_execute_queue,
482 };
483 struct adapter_driver bcm2835gpio_adapter_driver = {
484         .name = "bcm2835gpio",
485         .transports = bcm2835_transports,
486         .commands = bcm2835gpio_command_handlers,
487
488         .init = bcm2835gpio_init,
489         .quit = bcm2835gpio_quit,
490         .reset = bcm2835gpio_reset,
491         .speed = bcm2835gpio_speed,
492         .khz = bcm2835gpio_khz,
493         .speed_div = bcm2835gpio_speed_div,
494
495         .jtag_ops = &bcm2835gpio_interface,
496         .swd_ops = &bitbang_swd,
497 };