ipdbg: fix double free of virtual-ir data
[openocd.git] / src / jtag / drivers / bcm2835gpio.c
index 6db4340e81f9d3c2c6126fc8cf832383405578b2..ff10b0a78cb78d0072a4d3e8a509b6b2dc68d1a1 100644 (file)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
 /***************************************************************************
  *   Copyright (C) 2013 by Paul Fertser, fercerpav@gmail.com               *
  *                                                                         *
  *   Copyright (C) 2012 by Creative Product Design, marc @ cpdesign.com.au *
  *   Based on at91rm9200.c (c) Anders Larsen                               *
  *   and RPi GPIO examples by Gert van Loo & Dom                           *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
  ***************************************************************************/
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
+#include <jtag/adapter.h>
 #include <jtag/interface.h>
 #include <transport/transport.h>
 #include "bitbang.h"
 
 #include <sys/mman.h>
 
-uint32_t bcm2835_peri_base = 0x20000000;
+static char *bcm2835_peri_mem_dev;
+static off_t bcm2835_peri_base = 0x20000000;
 #define BCM2835_GPIO_BASE      (bcm2835_peri_base + 0x200000) /* GPIO controller */
 
 #define BCM2835_PADS_GPIO_0_27         (bcm2835_peri_base + 0x100000)
 #define BCM2835_PADS_GPIO_0_27_OFFSET  (0x2c / 4)
 
+/* See "GPIO Function Select Registers (GPFSELn)" in "Broadcom BCM2835 ARM Peripherals" datasheet. */
+#define BCM2835_GPIO_MODE_INPUT 0
+#define BCM2835_GPIO_MODE_OUTPUT 1
+
 /* GPIO setup macros */
 #define MODE_GPIO(g) (*(pio_base+((g)/10))>>(((g)%10)*3) & 7)
 #define INP_GPIO(g) do { *(pio_base+((g)/10)) &= ~(7<<(((g)%10)*3)); } while (0)
 #define SET_MODE_GPIO(g, m) do { /* clear the mode bits first, then set as necessary */ \
                INP_GPIO(g);                                            \
                *(pio_base+((g)/10)) |=  ((m)<<(((g)%10)*3)); } while (0)
-#define OUT_GPIO(g) SET_MODE_GPIO(g, 1)
+#define OUT_GPIO(g) SET_MODE_GPIO(g, BCM2835_GPIO_MODE_OUTPUT)
 
 #define GPIO_SET (*(pio_base+7))  /* sets   bits which are 1, ignores bits which are 0 */
 #define GPIO_CLR (*(pio_base+10)) /* clears bits which are 1, ignores bits which are 0 */
 #define GPIO_LEV (*(pio_base+13)) /* current level of the pin */
 
 static int dev_mem_fd;
-static volatile uint32_t *pio_base;
-
-static bb_value_t bcm2835gpio_read(void);
-static int bcm2835gpio_write(int tck, int tms, int tdi);
-
-static int bcm2835_swdio_read(void);
-static void bcm2835_swdio_drive(bool is_output);
-static int bcm2835gpio_swd_write(int swclk, int swdio);
-
-static int bcm2835gpio_init(void);
-static int bcm2835gpio_quit(void);
-
-static struct bitbang_interface bcm2835gpio_bitbang = {
-       .read = bcm2835gpio_read,
-       .write = bcm2835gpio_write,
-       .swdio_read = bcm2835_swdio_read,
-       .swdio_drive = bcm2835_swdio_drive,
-       .swd_write = bcm2835gpio_swd_write,
-       .blink = NULL
-};
-
-/* GPIO numbers for each signal. Negative values are invalid */
-static int tck_gpio = -1;
-static int tck_gpio_mode;
-static int tms_gpio = -1;
-static int tms_gpio_mode;
-static int tdi_gpio = -1;
-static int tdi_gpio_mode;
-static int tdo_gpio = -1;
-static int tdo_gpio_mode;
-static int trst_gpio = -1;
-static int trst_gpio_mode;
-static int srst_gpio = -1;
-static int srst_gpio_mode;
-static int swclk_gpio = -1;
-static int swclk_gpio_mode;
-static int swdio_gpio = -1;
-static int swdio_gpio_mode;
-static int swdio_dir_gpio = -1;
-static int swdio_dir_gpio_mode;
+static volatile uint32_t *pio_base = MAP_FAILED;
+static volatile uint32_t *pads_base = MAP_FAILED;
 
 /* Transition delay coefficients */
 static int speed_coeff = 113714;
 static int speed_offset = 28;
 static unsigned int jtag_delay;
 
-static bb_value_t bcm2835gpio_read(void)
-{
-       return (GPIO_LEV & 1<<tdo_gpio) ? BB_HIGH : BB_LOW;
-}
+static const struct adapter_gpio_config *adapter_gpio_config;
+static struct initial_gpio_state {
+       unsigned int mode;
+       unsigned int output_level;
+} initial_gpio_state[ADAPTER_GPIO_IDX_NUM];
+static uint32_t initial_drive_strength_etc;
 
-static int bcm2835gpio_write(int tck, int tms, int tdi)
+static inline const char *bcm2835_get_mem_dev(void)
 {
-       uint32_t set = tck<<tck_gpio | tms<<tms_gpio | tdi<<tdi_gpio;
-       uint32_t clear = !tck<<tck_gpio | !tms<<tms_gpio | !tdi<<tdi_gpio;
-
-       GPIO_SET = set;
-       GPIO_CLR = clear;
-
-       for (unsigned int i = 0; i < jtag_delay; i++)
-               asm volatile ("");
+       if (bcm2835_peri_mem_dev)
+               return bcm2835_peri_mem_dev;
 
-       return ERROR_OK;
+       return "/dev/gpiomem";
 }
 
-static int bcm2835gpio_swd_write(int swclk, int swdio)
+static inline void bcm2835_gpio_synchronize(void)
 {
-       uint32_t set = swclk << swclk_gpio | swdio << swdio_gpio;
-       uint32_t clear = !swclk << swclk_gpio | !swdio << swdio_gpio;
-
-       GPIO_SET = set;
-       GPIO_CLR = clear;
+       /* Ensure that previous writes to GPIO registers are flushed out of
+        * the inner shareable domain to prevent pipelined writes to the
+        * same address being merged.
+        */
+       __sync_synchronize();
+}
 
+static inline void bcm2835_delay(void)
+{
        for (unsigned int i = 0; i < jtag_delay; i++)
                asm volatile ("");
-
-       return ERROR_OK;
 }
 
-/* (1) assert or (0) deassert reset lines */
-static int bcm2835gpio_reset(int trst, int srst)
+static bool is_gpio_config_valid(enum adapter_gpio_config_index idx)
 {
-       uint32_t set = 0;
-       uint32_t clear = 0;
-
-       if (trst_gpio > 0) {
-               set |= !trst<<trst_gpio;
-               clear |= trst<<trst_gpio;
-       }
-
-       if (srst_gpio > 0) {
-               set |= !srst<<srst_gpio;
-               clear |= srst<<srst_gpio;
-       }
-
-       GPIO_SET = set;
-       GPIO_CLR = clear;
-
-       return ERROR_OK;
+       /* Only chip 0 is supported, accept unset value (-1) too */
+       return adapter_gpio_config[idx].gpio_num <= 31;
 }
 
-static void bcm2835_swdio_drive(bool is_output)
+static void set_gpio_value(const struct adapter_gpio_config *gpio_config, int value)
 {
-       if (swdio_dir_gpio > 0) {
-               if (is_output) {
-                       GPIO_SET = 1 << swdio_dir_gpio;
-                       OUT_GPIO(swdio_gpio);
+       value = value ^ (gpio_config->active_low ? 1 : 0);
+       switch (gpio_config->drive) {
+       case ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL:
+               if (value)
+                       GPIO_SET = 1 << gpio_config->gpio_num;
+               else
+                       GPIO_CLR = 1 << gpio_config->gpio_num;
+               /* For performance reasons assume the GPIO is already set as an output
+                * and therefore the call can be omitted here.
+                */
+               break;
+       case ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN:
+               if (value) {
+                       INP_GPIO(gpio_config->gpio_num);
                } else {
-                       INP_GPIO(swdio_gpio);
-                       GPIO_CLR = 1 << swdio_dir_gpio;
+                       GPIO_CLR = 1 << gpio_config->gpio_num;
+                       OUT_GPIO(gpio_config->gpio_num);
                }
-       } else {
-               if (is_output)
-                       OUT_GPIO(swdio_gpio);
-               else
-                       INP_GPIO(swdio_gpio);
+               break;
+       case ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE:
+               if (value) {
+                       GPIO_SET = 1 << gpio_config->gpio_num;
+                       OUT_GPIO(gpio_config->gpio_num);
+               } else {
+                       INP_GPIO(gpio_config->gpio_num);
+               }
+               break;
        }
+       bcm2835_gpio_synchronize();
 }
 
-static int bcm2835_swdio_read(void)
-{
-       return !!(GPIO_LEV & 1 << swdio_gpio);
-}
-
-static int bcm2835gpio_khz(int khz, int *jtag_speed)
+static void restore_gpio(enum adapter_gpio_config_index idx)
 {
-       if (!khz) {
-               LOG_DEBUG("RCLK not supported");
-               return ERROR_FAIL;
+       if (is_gpio_config_valid(idx)) {
+               SET_MODE_GPIO(adapter_gpio_config[idx].gpio_num, initial_gpio_state[idx].mode);
+               if (initial_gpio_state[idx].mode == BCM2835_GPIO_MODE_OUTPUT) {
+                       if (initial_gpio_state[idx].output_level)
+                               GPIO_SET = 1 << adapter_gpio_config[idx].gpio_num;
+                       else
+                               GPIO_CLR = 1 << adapter_gpio_config[idx].gpio_num;
+               }
        }
-       *jtag_speed = speed_coeff/khz - speed_offset;
-       if (*jtag_speed < 0)
-               *jtag_speed = 0;
-       return ERROR_OK;
+       bcm2835_gpio_synchronize();
 }
 
-static int bcm2835gpio_speed_div(int speed, int *khz)
+static void initialize_gpio(enum adapter_gpio_config_index idx)
 {
-       *khz = speed_coeff/(speed + speed_offset);
-       return ERROR_OK;
-}
+       if (!is_gpio_config_valid(idx))
+               return;
+
+       initial_gpio_state[idx].mode = MODE_GPIO(adapter_gpio_config[idx].gpio_num);
+       unsigned int shift = adapter_gpio_config[idx].gpio_num;
+       initial_gpio_state[idx].output_level = (GPIO_LEV >> shift) & 1;
+       LOG_DEBUG("saved GPIO mode for %s (GPIO %d %d): %d",
+                       adapter_gpio_get_name(idx), adapter_gpio_config[idx].chip_num, adapter_gpio_config[idx].gpio_num,
+                       initial_gpio_state[idx].mode);
+
+       if (adapter_gpio_config[idx].pull != ADAPTER_GPIO_PULL_NONE) {
+               LOG_WARNING("BCM2835 GPIO does not support pull-up or pull-down settings (signal %s)",
+                       adapter_gpio_get_name(idx));
+       }
 
-static int bcm2835gpio_speed(int speed)
-{
-       jtag_delay = speed;
-       return ERROR_OK;
-}
+       switch (adapter_gpio_config[idx].init_state) {
+       case ADAPTER_GPIO_INIT_STATE_INACTIVE:
+               set_gpio_value(&adapter_gpio_config[idx], 0);
+               break;
+       case ADAPTER_GPIO_INIT_STATE_ACTIVE:
+               set_gpio_value(&adapter_gpio_config[idx], 1);
+               break;
+       case ADAPTER_GPIO_INIT_STATE_INPUT:
+               INP_GPIO(adapter_gpio_config[idx].gpio_num);
+               break;
+       }
 
-static int is_gpio_valid(int gpio)
-{
-       return gpio >= 0 && gpio <= 53;
+       /* Direction for non push-pull is already set by set_gpio_value() */
+       if (adapter_gpio_config[idx].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL
+               && adapter_gpio_config[idx].init_state != ADAPTER_GPIO_INIT_STATE_INPUT)
+               OUT_GPIO(adapter_gpio_config[idx].gpio_num);
+       bcm2835_gpio_synchronize();
 }
 
-COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionums)
+static bb_value_t bcm2835gpio_read(void)
 {
-       if (CMD_ARGC == 4) {
-               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio);
-               COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tms_gpio);
-               COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], tdi_gpio);
-               COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], tdo_gpio);
-       } else if (CMD_ARGC != 0) {
-               return ERROR_COMMAND_SYNTAX_ERROR;
-       }
+       unsigned int shift = adapter_gpio_config[ADAPTER_GPIO_IDX_TDO].gpio_num;
+       uint32_t value = (GPIO_LEV >> shift) & 1;
+       return value ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_TDO].active_low ? BB_HIGH : BB_LOW);
 
-       command_print(CMD,
-                       "BCM2835 GPIO config: tck = %d, tms = %d, tdi = %d, tdo = %d",
-                       tck_gpio, tms_gpio, tdi_gpio, tdo_gpio);
-
-       return ERROR_OK;
 }
 
-COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tck)
+static int bcm2835gpio_write(int tck, int tms, int tdi)
 {
-       if (CMD_ARGC == 1)
-               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio);
+       uint32_t set = tck << adapter_gpio_config[ADAPTER_GPIO_IDX_TCK].gpio_num |
+                       tms << adapter_gpio_config[ADAPTER_GPIO_IDX_TMS].gpio_num |
+                       tdi << adapter_gpio_config[ADAPTER_GPIO_IDX_TDI].gpio_num;
+       uint32_t clear = !tck << adapter_gpio_config[ADAPTER_GPIO_IDX_TCK].gpio_num |
+                       !tms << adapter_gpio_config[ADAPTER_GPIO_IDX_TMS].gpio_num |
+                       !tdi << adapter_gpio_config[ADAPTER_GPIO_IDX_TDI].gpio_num;
 
-       command_print(CMD, "BCM2835 GPIO config: tck = %d", tck_gpio);
-       return ERROR_OK;
-}
+       GPIO_SET = set;
+       GPIO_CLR = clear;
+       bcm2835_gpio_synchronize();
 
-COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tms)
-{
-       if (CMD_ARGC == 1)
-               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tms_gpio);
+       bcm2835_delay();
 
-       command_print(CMD, "BCM2835 GPIO config: tms = %d", tms_gpio);
        return ERROR_OK;
 }
 
-COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tdo)
+/* Requires push-pull drive mode for swclk and swdio */
+static int bcm2835gpio_swd_write_fast(int swclk, int swdio)
 {
-       if (CMD_ARGC == 1)
-               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdo_gpio);
+       swclk = swclk ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].active_low ? 1 : 0);
+       swdio = swdio ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].active_low ? 1 : 0);
 
-       command_print(CMD, "BCM2835 GPIO config: tdo = %d", tdo_gpio);
-       return ERROR_OK;
-}
+       uint32_t set = swclk << adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].gpio_num |
+                                       swdio << adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num;
+       uint32_t clear = !swclk << adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].gpio_num |
+                                       !swdio << adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num;
 
-COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tdi)
-{
-       if (CMD_ARGC == 1)
-               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdi_gpio);
+       GPIO_SET = set;
+       GPIO_CLR = clear;
+       bcm2835_gpio_synchronize();
+
+       bcm2835_delay();
 
-       command_print(CMD, "BCM2835 GPIO config: tdi = %d", tdi_gpio);
        return ERROR_OK;
 }
 
-COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_srst)
+/* Generic mode that works for open-drain/open-source drive modes, but slower */
+static int bcm2835gpio_swd_write_generic(int swclk, int swdio)
 {
-       if (CMD_ARGC == 1)
-               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], srst_gpio);
+       set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO], swdio);
+       set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK], swclk); /* Write clock last */
+
+       bcm2835_delay();
 
-       command_print(CMD, "BCM2835 GPIO config: srst = %d", srst_gpio);
        return ERROR_OK;
 }
 
-COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_trst)
+/* (1) assert or (0) deassert reset lines */
+static int bcm2835gpio_reset(int trst, int srst)
 {
-       if (CMD_ARGC == 1)
-               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], trst_gpio);
-
-       command_print(CMD, "BCM2835 GPIO config: trst = %d", trst_gpio);
+       /* As the "adapter reset_config" command keeps the srst and trst gpio drive
+        * mode settings in sync we can use our standard set_gpio_value() function
+        * that honours drive mode and active low.
+        */
+       if (is_gpio_config_valid(ADAPTER_GPIO_IDX_SRST))
+               set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SRST], srst);
+
+       if (is_gpio_config_valid(ADAPTER_GPIO_IDX_TRST))
+               set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_TRST], trst);
+
+       LOG_DEBUG("trst %d gpio: %d %d, srst %d gpio: %d %d",
+               trst,
+               (int)adapter_gpio_config[ADAPTER_GPIO_IDX_TRST].chip_num,
+               (int)adapter_gpio_config[ADAPTER_GPIO_IDX_TRST].gpio_num,
+               srst,
+               (int)adapter_gpio_config[ADAPTER_GPIO_IDX_SRST].chip_num,
+               (int)adapter_gpio_config[ADAPTER_GPIO_IDX_SRST].gpio_num);
        return ERROR_OK;
 }
 
-COMMAND_HANDLER(bcm2835gpio_handle_swd_gpionums)
+static void bcm2835_swdio_drive(bool is_output)
 {
-       if (CMD_ARGC == 2) {
-               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio);
-               COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], swdio_gpio);
-       } else if (CMD_ARGC != 0) {
-               return ERROR_COMMAND_SYNTAX_ERROR;
+       if (is_output) {
+               if (is_gpio_config_valid(ADAPTER_GPIO_IDX_SWDIO_DIR))
+                       set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR], 1);
+               OUT_GPIO(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num);
+       } else {
+               INP_GPIO(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num);
+               if (is_gpio_config_valid(ADAPTER_GPIO_IDX_SWDIO_DIR))
+                       set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR], 0);
        }
-
-       command_print(CMD,
-                       "BCM2835 GPIO nums: swclk = %d, swdio = %d",
-                       swclk_gpio, swdio_gpio);
-
-       return ERROR_OK;
+       bcm2835_gpio_synchronize();
 }
 
-COMMAND_HANDLER(bcm2835gpio_handle_swd_gpionum_swclk)
+static int bcm2835_swdio_read(void)
 {
-       if (CMD_ARGC == 1)
-               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio);
+       unsigned int shift = adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num;
+       uint32_t value = (GPIO_LEV >> shift) & 1;
+       return value ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].active_low ? 1 : 0);
+}
 
-       command_print(CMD, "BCM2835 num: swclk = %d", swclk_gpio);
+static int bcm2835gpio_khz(int khz, int *jtag_speed)
+{
+       if (!khz) {
+               LOG_DEBUG("BCM2835 GPIO: RCLK not supported");
+               return ERROR_FAIL;
+       }
+       *jtag_speed = DIV_ROUND_UP(speed_coeff, khz) - speed_offset;
+       LOG_DEBUG("jtag_delay %d", *jtag_speed);
+       if (*jtag_speed < 0)
+               *jtag_speed = 0;
        return ERROR_OK;
 }
 
-COMMAND_HANDLER(bcm2835gpio_handle_swd_gpionum_swdio)
+static int bcm2835gpio_speed_div(int speed, int *khz)
 {
-       if (CMD_ARGC == 1)
-               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swdio_gpio);
-
-       command_print(CMD, "BCM2835 num: swdio = %d", swdio_gpio);
+       int divisor = speed + speed_offset;
+       /* divide with roundig to the closest */
+       *khz = (speed_coeff + divisor / 2) / divisor;
        return ERROR_OK;
 }
 
-COMMAND_HANDLER(bcm2835gpio_handle_swd_dir_gpionum_swdio)
+static int bcm2835gpio_speed(int speed)
 {
-       if (CMD_ARGC == 1)
-               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swdio_dir_gpio);
-
-       command_print(CMD, "BCM2835 num: swdio_dir = %d", swdio_dir_gpio);
+       jtag_delay = speed;
        return ERROR_OK;
 }
 
@@ -328,163 +310,128 @@ COMMAND_HANDLER(bcm2835gpio_handle_speed_coeffs)
        return ERROR_OK;
 }
 
+COMMAND_HANDLER(bcm2835gpio_handle_peripheral_mem_dev)
+{
+       if (CMD_ARGC == 1) {
+               free(bcm2835_peri_mem_dev);
+               bcm2835_peri_mem_dev = strdup(CMD_ARGV[0]);
+       }
+
+       command_print(CMD, "BCM2835 GPIO: peripheral_mem_dev = %s",
+                                 bcm2835_get_mem_dev());
+       return ERROR_OK;
+}
+
 COMMAND_HANDLER(bcm2835gpio_handle_peripheral_base)
 {
-       if (CMD_ARGC == 1)
-               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], bcm2835_peri_base);
+       uint64_t tmp_base;
+       if (CMD_ARGC == 1) {
+               COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], tmp_base);
+               bcm2835_peri_base = (off_t)tmp_base;
+       }
 
-       command_print(CMD, "BCM2835 GPIO: peripheral_base = 0x%08x",
-                                 bcm2835_peri_base);
+       tmp_base = bcm2835_peri_base;
+       command_print(CMD, "BCM2835 GPIO: peripheral_base = 0x%08" PRIx64,
+                                 tmp_base);
        return ERROR_OK;
 }
 
-static const struct command_registration bcm2835gpio_command_handlers[] = {
+static const struct command_registration bcm2835gpio_subcommand_handlers[] = {
        {
-               .name = "bcm2835gpio_jtag_nums",
-               .handler = &bcm2835gpio_handle_jtag_gpionums,
-               .mode = COMMAND_CONFIG,
-               .help = "gpio numbers for tck, tms, tdi, tdo. (in that order)",
-               .usage = "[tck tms tdi tdo]",
-       },
-       {
-               .name = "bcm2835gpio_tck_num",
-               .handler = &bcm2835gpio_handle_jtag_gpionum_tck,
-               .mode = COMMAND_CONFIG,
-               .help = "gpio number for tck.",
-               .usage = "[tck]",
-       },
-       {
-               .name = "bcm2835gpio_tms_num",
-               .handler = &bcm2835gpio_handle_jtag_gpionum_tms,
-               .mode = COMMAND_CONFIG,
-               .help = "gpio number for tms.",
-               .usage = "[tms]",
-       },
-       {
-               .name = "bcm2835gpio_tdo_num",
-               .handler = &bcm2835gpio_handle_jtag_gpionum_tdo,
-               .mode = COMMAND_CONFIG,
-               .help = "gpio number for tdo.",
-               .usage = "[tdo]",
-       },
-       {
-               .name = "bcm2835gpio_tdi_num",
-               .handler = &bcm2835gpio_handle_jtag_gpionum_tdi,
-               .mode = COMMAND_CONFIG,
-               .help = "gpio number for tdi.",
-               .usage = "[tdi]",
-       },
-       {
-               .name = "bcm2835gpio_swd_nums",
-               .handler = &bcm2835gpio_handle_swd_gpionums,
-               .mode = COMMAND_CONFIG,
-               .help = "gpio numbers for swclk, swdio. (in that order)",
-               .usage = "[swclk swdio]",
-       },
-       {
-               .name = "bcm2835gpio_swclk_num",
-               .handler = &bcm2835gpio_handle_swd_gpionum_swclk,
-               .mode = COMMAND_CONFIG,
-               .help = "gpio number for swclk.",
-               .usage = "[swclk]",
-       },
-       {
-               .name = "bcm2835gpio_swdio_num",
-               .handler = &bcm2835gpio_handle_swd_gpionum_swdio,
-               .mode = COMMAND_CONFIG,
-               .help = "gpio number for swdio.",
-               .usage = "[swdio]",
-       },
-       {
-               .name = "bcm2835gpio_swdio_dir_num",
-               .handler = &bcm2835gpio_handle_swd_dir_gpionum_swdio,
-               .mode = COMMAND_CONFIG,
-               .help = "gpio number for swdio direction control pin (set=output mode, clear=input mode)",
-               .usage = "[swdio_dir]",
-       },
-       {
-               .name = "bcm2835gpio_srst_num",
-               .handler = &bcm2835gpio_handle_jtag_gpionum_srst,
-               .mode = COMMAND_CONFIG,
-               .help = "gpio number for srst.",
-               .usage = "[srst]",
-       },
-       {
-               .name = "bcm2835gpio_trst_num",
-               .handler = &bcm2835gpio_handle_jtag_gpionum_trst,
-               .mode = COMMAND_CONFIG,
-               .help = "gpio number for trst.",
-               .usage = "[trst]",
-       },
-       {
-               .name = "bcm2835gpio_speed_coeffs",
+               .name = "speed_coeffs",
                .handler = &bcm2835gpio_handle_speed_coeffs,
                .mode = COMMAND_CONFIG,
                .help = "SPEED_COEFF and SPEED_OFFSET for delay calculations.",
                .usage = "[SPEED_COEFF SPEED_OFFSET]",
        },
        {
-               .name = "bcm2835gpio_peripheral_base",
+               .name = "peripheral_mem_dev",
+               .handler = &bcm2835gpio_handle_peripheral_mem_dev,
+               .mode = COMMAND_CONFIG,
+               .help = "device to map memory mapped GPIOs from.",
+               .usage = "[device]",
+       },
+       {
+               .name = "peripheral_base",
                .handler = &bcm2835gpio_handle_peripheral_base,
                .mode = COMMAND_CONFIG,
-               .help = "peripheral base to access GPIOs (RPi1 0x20000000, RPi2 0x3F000000).",
+               .help = "peripheral base to access GPIOs, not needed with /dev/gpiomem.",
                .usage = "[base]",
        },
 
        COMMAND_REGISTRATION_DONE
 };
 
-static const char * const bcm2835_transports[] = { "jtag", "swd", NULL };
-
-static struct jtag_interface bcm2835gpio_interface = {
-       .supported = DEBUG_CAP_TMS_SEQ,
-       .execute_queue = bitbang_execute_queue,
-};
-
-struct adapter_driver bcm2835gpio_adapter_driver = {
-       .name = "bcm2835gpio",
-       .transports = bcm2835_transports,
-       .commands = bcm2835gpio_command_handlers,
-
-       .init = bcm2835gpio_init,
-       .quit = bcm2835gpio_quit,
-       .reset = bcm2835gpio_reset,
-       .speed = bcm2835gpio_speed,
-       .khz = bcm2835gpio_khz,
-       .speed_div = bcm2835gpio_speed_div,
-
-       .jtag_ops = &bcm2835gpio_interface,
-       .swd_ops = &bitbang_swd,
+static const struct command_registration bcm2835gpio_command_handlers[] = {
+       {
+               .name = "bcm2835gpio",
+               .mode = COMMAND_ANY,
+               .help = "perform bcm2835gpio management",
+               .chain = bcm2835gpio_subcommand_handlers,
+               .usage = "",
+       },
+       COMMAND_REGISTRATION_DONE
 };
 
 static bool bcm2835gpio_jtag_mode_possible(void)
 {
-       if (!is_gpio_valid(tck_gpio))
-               return 0;
-       if (!is_gpio_valid(tms_gpio))
-               return 0;
-       if (!is_gpio_valid(tdi_gpio))
-               return 0;
-       if (!is_gpio_valid(tdo_gpio))
-               return 0;
-       return 1;
+       if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TCK))
+               return false;
+       if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TMS))
+               return false;
+       if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TDI))
+               return false;
+       if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TDO))
+               return false;
+       return true;
 }
 
 static bool bcm2835gpio_swd_mode_possible(void)
 {
-       if (!is_gpio_valid(swclk_gpio))
-               return 0;
-       if (!is_gpio_valid(swdio_gpio))
-               return 0;
-       return 1;
+       if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_SWCLK))
+               return false;
+       if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_SWDIO))
+               return false;
+       return true;
 }
 
-static int bcm2835gpio_init(void)
+static void bcm2835gpio_munmap(void)
 {
-       bitbang_interface = &bcm2835gpio_bitbang;
+       if (pio_base != MAP_FAILED) {
+               munmap((void *)pio_base, sysconf(_SC_PAGE_SIZE));
+               pio_base = MAP_FAILED;
+       }
+
+       if (pads_base != MAP_FAILED) {
+               munmap((void *)pads_base, sysconf(_SC_PAGE_SIZE));
+               pads_base = MAP_FAILED;
+       }
+}
 
+static int bcm2835gpio_blink(int on)
+{
+       if (is_gpio_config_valid(ADAPTER_GPIO_IDX_LED))
+               set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_LED], on);
+
+       return ERROR_OK;
+}
+
+static struct bitbang_interface bcm2835gpio_bitbang = {
+       .read = bcm2835gpio_read,
+       .write = bcm2835gpio_write,
+       .swdio_read = bcm2835_swdio_read,
+       .swdio_drive = bcm2835_swdio_drive,
+       .swd_write = bcm2835gpio_swd_write_generic,
+       .blink = bcm2835gpio_blink,
+};
+
+static int bcm2835gpio_init(void)
+{
        LOG_INFO("BCM2835 GPIO JTAG/SWD bitbang driver");
 
+       bitbang_interface = &bcm2835gpio_bitbang;
+       adapter_gpio_config = adapter_gpio_get_config();
+
        if (transport_is_jtag() && !bcm2835gpio_jtag_mode_possible()) {
                LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode");
                return ERROR_JTAG_INIT_FAILED;
@@ -495,13 +442,16 @@ static int bcm2835gpio_init(void)
                return ERROR_JTAG_INIT_FAILED;
        }
 
-       dev_mem_fd = open("/dev/gpiomem", O_RDWR | O_SYNC);
-       if (dev_mem_fd < 0) {
-               LOG_DEBUG("Cannot open /dev/gpiomem, fallback to /dev/mem");
-               dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
-       }
+       bool is_gpiomem = strcmp(bcm2835_get_mem_dev(), "/dev/gpiomem") == 0;
+       bool pad_mapping_possible = !is_gpiomem;
+
+       dev_mem_fd = open(bcm2835_get_mem_dev(), O_RDWR | O_SYNC);
        if (dev_mem_fd < 0) {
-               LOG_ERROR("open: %s", strerror(errno));
+               LOG_ERROR("open %s: %s", bcm2835_get_mem_dev(), strerror(errno));
+               /* TODO: add /dev/mem specific doc and refer to it
+                * if (!is_gpiomem && (errno == EACCES || errno == EPERM))
+                *      LOG_INFO("Consult the user's guide chapter 4.? how to set permissions and capabilities");
+                */
                return ERROR_JTAG_INIT_FAILED;
        }
 
@@ -514,70 +464,69 @@ static int bcm2835gpio_init(void)
                return ERROR_JTAG_INIT_FAILED;
        }
 
-       static volatile uint32_t *pads_base;
-       pads_base = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE,
+       /* TODO: move pads config to a separate utility */
+       if (pad_mapping_possible) {
+               pads_base = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE,
                                MAP_SHARED, dev_mem_fd, BCM2835_PADS_GPIO_0_27);
 
-       if (pads_base == MAP_FAILED) {
-               LOG_ERROR("mmap: %s", strerror(errno));
-               close(dev_mem_fd);
-               return ERROR_JTAG_INIT_FAILED;
+               if (pads_base == MAP_FAILED) {
+                       LOG_ERROR("mmap pads: %s", strerror(errno));
+                       LOG_WARNING("Continuing with unchanged GPIO pad settings (drive strength and slew rate)");
+               }
+       } else {
+               pads_base = MAP_FAILED;
        }
 
-       /* set 4mA drive strength, slew rate limited, hysteresis on */
-       pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5a000008 + 1;
+       close(dev_mem_fd);
 
-       /*
-        * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST
-        * as outputs.  Drive TDI and TCK low, and TMS/TRST/SRST high.
+       if (pads_base != MAP_FAILED) {
+               /* set 4mA drive strength, slew rate limited, hysteresis on */
+               initial_drive_strength_etc = pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] & 0x1f;
+LOG_INFO("initial pads conf %08x", pads_base[BCM2835_PADS_GPIO_0_27_OFFSET]);
+               pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5a000008 + 1;
+LOG_INFO("pads conf set to %08x", pads_base[BCM2835_PADS_GPIO_0_27_OFFSET]);
+       }
+
+       /* Configure JTAG/SWD signals. Default directions and initial states are handled
+        * by adapter.c and "adapter gpio" command.
         */
        if (transport_is_jtag()) {
-               tdo_gpio_mode = MODE_GPIO(tdo_gpio);
-               tdi_gpio_mode = MODE_GPIO(tdi_gpio);
-               tck_gpio_mode = MODE_GPIO(tck_gpio);
-               tms_gpio_mode = MODE_GPIO(tms_gpio);
-
-               INP_GPIO(tdo_gpio);
-
-               GPIO_CLR = 1<<tdi_gpio | 1<<tck_gpio;
-               GPIO_SET = 1<<tms_gpio;
-
-               OUT_GPIO(tdi_gpio);
-               OUT_GPIO(tck_gpio);
-               OUT_GPIO(tms_gpio);
-
-               if (trst_gpio != -1) {
-                       trst_gpio_mode = MODE_GPIO(trst_gpio);
-                       GPIO_SET = 1 << trst_gpio;
-                       OUT_GPIO(trst_gpio);
-               }
+               initialize_gpio(ADAPTER_GPIO_IDX_TDO);
+               initialize_gpio(ADAPTER_GPIO_IDX_TDI);
+               initialize_gpio(ADAPTER_GPIO_IDX_TMS);
+               initialize_gpio(ADAPTER_GPIO_IDX_TCK);
+               initialize_gpio(ADAPTER_GPIO_IDX_TRST);
        }
 
        if (transport_is_swd()) {
-               swclk_gpio_mode = MODE_GPIO(swclk_gpio);
-               swdio_gpio_mode = MODE_GPIO(swdio_gpio);
-
-               GPIO_CLR = 1<<swdio_gpio | 1<<swclk_gpio;
-
-               OUT_GPIO(swclk_gpio);
-               OUT_GPIO(swdio_gpio);
-       }
+               /* swdio and its buffer should be initialized in the order that prevents
+                * two outputs from being connected together. This will occur if the
+                * swdio GPIO of the AM335x is configured as an output while its
+                * external buffer is configured to send the swdio signal from the
+                * target to the AM335x.
+                */
+               if (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].init_state == ADAPTER_GPIO_INIT_STATE_INPUT) {
+                       initialize_gpio(ADAPTER_GPIO_IDX_SWDIO);
+                       initialize_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR);
+               } else {
+                       initialize_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR);
+                       initialize_gpio(ADAPTER_GPIO_IDX_SWDIO);
+               }
 
-       if (srst_gpio != -1) {
-               srst_gpio_mode = MODE_GPIO(srst_gpio);
-               GPIO_SET = 1 << srst_gpio;
-               OUT_GPIO(srst_gpio);
-       }
+               initialize_gpio(ADAPTER_GPIO_IDX_SWCLK);
 
-       if (swdio_dir_gpio != -1) {
-               swdio_dir_gpio_mode = MODE_GPIO(swdio_dir_gpio);
-               GPIO_SET = 1 << swdio_dir_gpio;
-               OUT_GPIO(swdio_dir_gpio);
+               if (adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL &&
+                               adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL) {
+                       LOG_DEBUG("BCM2835 GPIO using fast mode for SWD write");
+                       bcm2835gpio_bitbang.swd_write = bcm2835gpio_swd_write_fast;
+               } else {
+                       LOG_DEBUG("BCM2835 GPIO using generic mode for SWD write");
+                       bcm2835gpio_bitbang.swd_write = bcm2835gpio_swd_write_generic;
+               }
        }
 
-       LOG_DEBUG("saved pinmux settings: tck %d tms %d tdi %d "
-                 "tdo %d trst %d srst %d", tck_gpio_mode, tms_gpio_mode,
-                 tdi_gpio_mode, tdo_gpio_mode, trst_gpio_mode, srst_gpio_mode);
+       initialize_gpio(ADAPTER_GPIO_IDX_SRST);
+       initialize_gpio(ADAPTER_GPIO_IDX_LED);
 
        return ERROR_OK;
 }
@@ -585,24 +534,57 @@ static int bcm2835gpio_init(void)
 static int bcm2835gpio_quit(void)
 {
        if (transport_is_jtag()) {
-               SET_MODE_GPIO(tdo_gpio, tdo_gpio_mode);
-               SET_MODE_GPIO(tdi_gpio, tdi_gpio_mode);
-               SET_MODE_GPIO(tck_gpio, tck_gpio_mode);
-               SET_MODE_GPIO(tms_gpio, tms_gpio_mode);
-               if (trst_gpio != -1)
-                       SET_MODE_GPIO(trst_gpio, trst_gpio_mode);
+               restore_gpio(ADAPTER_GPIO_IDX_TDO);
+               restore_gpio(ADAPTER_GPIO_IDX_TDI);
+               restore_gpio(ADAPTER_GPIO_IDX_TCK);
+               restore_gpio(ADAPTER_GPIO_IDX_TMS);
+               restore_gpio(ADAPTER_GPIO_IDX_TRST);
        }
 
        if (transport_is_swd()) {
-               SET_MODE_GPIO(swclk_gpio, swclk_gpio_mode);
-               SET_MODE_GPIO(swdio_gpio, swdio_gpio_mode);
+               /* Restore swdio/swdio_dir to their initial modes, even if that means
+                * connecting two outputs. Begin by making swdio an input so that the
+                * current and final states of swdio and swdio_dir do not have to be
+                * considered to calculate the safe restoration order.
+                */
+               INP_GPIO(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num);
+               restore_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR);
+               restore_gpio(ADAPTER_GPIO_IDX_SWDIO);
+               restore_gpio(ADAPTER_GPIO_IDX_SWCLK);
        }
 
-       if (srst_gpio != -1)
-               SET_MODE_GPIO(srst_gpio, srst_gpio_mode);
+       restore_gpio(ADAPTER_GPIO_IDX_SRST);
+       restore_gpio(ADAPTER_GPIO_IDX_LED);
 
-       if (swdio_dir_gpio != -1)
-               SET_MODE_GPIO(swdio_dir_gpio, swdio_dir_gpio_mode);
+       if (pads_base != MAP_FAILED) {
+               /* Restore drive strength. MSB is password ("5A") */
+               pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5A000000 | initial_drive_strength_etc;
+       }
+       bcm2835gpio_munmap();
+       free(bcm2835_peri_mem_dev);
 
        return ERROR_OK;
 }
+
+
+static const char * const bcm2835_transports[] = { "jtag", "swd", NULL };
+
+static struct jtag_interface bcm2835gpio_interface = {
+       .supported = DEBUG_CAP_TMS_SEQ,
+       .execute_queue = bitbang_execute_queue,
+};
+struct adapter_driver bcm2835gpio_adapter_driver = {
+       .name = "bcm2835gpio",
+       .transports = bcm2835_transports,
+       .commands = bcm2835gpio_command_handlers,
+
+       .init = bcm2835gpio_init,
+       .quit = bcm2835gpio_quit,
+       .reset = bcm2835gpio_reset,
+       .speed = bcm2835gpio_speed,
+       .khz = bcm2835gpio_khz,
+       .speed_div = bcm2835gpio_speed_div,
+
+       .jtag_ops = &bcm2835gpio_interface,
+       .swd_ops = &bitbang_swd,
+};

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)