This is an automated email from Gerrit. "Vincent Fazio <vfa...@gmail.com>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/7732
-- gerrit commit ced3cc7e843e98eb12068f0d22b28059d776d8cb Author: Vincent Fazio <vfa...@gmail.com> Date: Fri Jun 2 18:22:19 2023 +0000 jtag/drivers/bcm2835gpio: Support GPIOs >= 32 Previously, not all 54 pins were supported by the driver. Performance was cited as being the primary justification, notably: 1. GPIO values cannot be written in bulk 2. The cost for calculating the memory offset for the pin In order to support pins >=32, the memory offset has to be calculated for each pin in use in order to be toggled. There's no guarantee that the mix of pins being used are backed by the same memory address, so bulk operations cannot be performed when all pins are supported. Add a new configure option to expand usable GPIO pins for the bcm2835 jtag driver. This drives a new define which will conditionally compile code to allow toggling newly supported pins. This is disabled by default and previous code patterns, including bulk GPIO operations, are used for the default case. When the config option is enabled, bulk operations are disabled and read/set/write ops are used for each pin being toggled. The performance cost for calculating the pin offset can largely be mitigated by using `unsigned` values so that integer division and modulo operations can be accomplished with cheap bit shift math. Use updated macros to provide consistent access to all pins. These macros now handle casting when necessary. New bulk macros are provided to preserve behavior for builds that only use the first 32 pins. Change-Id: I18853d1a2c86776658630326c71a6bf236fcc6da Signed-off-by: Jacob Zarnstorff <jacobzarnsto...@gmail.com> [vfazio: add configure option, conditional compile statements, and casts] Signed-off-by: Vincent Fazio <vfa...@gmail.com> diff --git a/configure.ac b/configure.ac index ac2808e1f5..16add843ad 100644 --- a/configure.ac +++ b/configure.ac @@ -296,6 +296,9 @@ AS_CASE(["${host_cpu}"], AC_ARG_ENABLE([bcm2835gpio], AS_HELP_STRING([--enable-bcm2835gpio], [Enable building support for bitbanging on BCM2835 (as found in Raspberry Pi)]), [build_bcm2835gpio=$enableval], [build_bcm2835gpio=no]) + AC_ARG_ENABLE([bcm2835gpio_all_gpio], + AS_HELP_STRING([--enable-bcm2835gpio_all_gpio], [Enable building support pins > 32 on BCM2835]), + [bcm2835gpio_all_gpio=$enableval], [bcm2835gpio_all_gpio=no]) AC_ARG_ENABLE([imx_gpio], AS_HELP_STRING([--enable-imx_gpio], [Enable building support for bitbanging on NXP IMX processors]), [build_imx_gpio=$enableval], [build_imx_gpio=no]) @@ -305,6 +308,7 @@ AS_CASE(["${host_cpu}"], ], [ build_bcm2835gpio=no + bcm2835gpio_all_gpio=no build_imx_gpio=no build_am335xgpio=no ]) @@ -501,6 +505,9 @@ AS_IF([test "x$build_at91rm9200" = "xyes"], [ AS_IF([test "x$build_bcm2835gpio" = "xyes"], [ build_bitbang=yes AC_DEFINE([BUILD_BCM2835GPIO], [1], [1 if you want bcm2835gpio.]) + AS_IF([test "x$bcm2835gpio_all_gpio" = "xyes"], [ + AC_DEFINE([BCM2835GPIO_ALL_GPIO], [1], [1 if you want support for all BCM2835 GPIO pins.]) + ], []) ], [ AC_DEFINE([BUILD_BCM2835GPIO], [0], [0 if you don't want bcm2835gpio.]) ]) diff --git a/doc/openocd.texi b/doc/openocd.texi index 9b485c5e1f..a633b55ec3 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -3289,8 +3289,8 @@ able to coexist nicely with both sysfs bitbanging and various peripherals' kernel drivers. The driver restores the previous configuration on exit. -GPIO numbers >= 32 can't be used for performance reasons. GPIO configuration is -handled by the generic command @ref{adapter gpio, @command{adapter gpio}}. +GPIO configuration is handled by the generic command +@ref{adapter gpio, @command{adapter gpio}}. See @file{interface/raspberrypi-native.cfg} for a sample config and @file{interface/raspberrypi-gpio-connector.cfg} for pinout. diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c index 39e4af3657..4af32109d3 100644 --- a/src/jtag/drivers/bcm2835gpio.c +++ b/src/jtag/drivers/bcm2835gpio.c @@ -38,9 +38,19 @@ static off_t bcm2835_peri_base = 0x20000000; *(pio_base+((g)/10)) |= ((m)<<(((g)%10)*3)); } while (0) #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 */ +#ifndef BCM2835GPIO_ALL_GPIO +#define GPIO_SET(g, v) (*(pio_base+7)) = v<<(uint32_t)g /* sets bits which are 1, ignores bits which are 0 */ +#define GPIO_CLR(g, v) (*(pio_base+10)) = v<<(uint32_t)g /* clears bits which are 1, ignores bits which are 0 */ +#define GPIO_LEV(g) ((*(pio_base+13)>>(uint32_t)g) & 1) /* current level of the pin */ +#define GPIO_BULK_SET(v) GPIO_SET(0, v) +#define GPIO_BULK_CLR(v) GPIO_CLR(0, v) +#else +#define GPIO_SET(g, v) do { /* sets bits which are 1, ignores bits which are 0 */ \ + *(pio_base+(7+((uint32_t)g/32))) = (v<<((uint32_t)g%32)); } while (0) +#define GPIO_CLR(g, v) do { /* clears bits which are 1, ignores bits which are 0 */ \ + *(pio_base+(10+((uint32_t)g/32))) = (v<<((uint32_t)g%32)); } while (0) +#define GPIO_LEV(g) ((*(pio_base+(13+((uint32_t)g/32)))>>((uint32_t)g%32)) & 1) /* current level of the pin */ +#endif static int dev_mem_fd; static volatile uint32_t *pio_base = MAP_FAILED; @@ -87,7 +97,11 @@ static bool is_gpio_config_valid(enum adapter_gpio_config_index idx) return adapter_gpio_config[idx].chip_num >= -1 && adapter_gpio_config[idx].chip_num <= 0 && adapter_gpio_config[idx].gpio_num >= 0 +#ifndef BCM2835GPIO_ALL_GPIO && adapter_gpio_config[idx].gpio_num <= 31; +#else + && adapter_gpio_config[idx].gpio_num <= 53; +#endif } static void set_gpio_value(const struct adapter_gpio_config *gpio_config, int value) @@ -96,9 +110,9 @@ static void set_gpio_value(const struct adapter_gpio_config *gpio_config, int va switch (gpio_config->drive) { case ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL: if (value) - GPIO_SET = 1 << gpio_config->gpio_num; + GPIO_SET(gpio_config->gpio_num, 1); else - GPIO_CLR = 1 << gpio_config->gpio_num; + GPIO_CLR(gpio_config->gpio_num, 1); /* For performance reasons assume the GPIO is already set as an output * and therefore the call can be omitted here. */ @@ -107,13 +121,13 @@ static void set_gpio_value(const struct adapter_gpio_config *gpio_config, int va if (value) { INP_GPIO(gpio_config->gpio_num); } else { - GPIO_CLR = 1 << gpio_config->gpio_num; + GPIO_CLR(gpio_config->gpio_num, 1); OUT_GPIO(gpio_config->gpio_num); } break; case ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE: if (value) { - GPIO_SET = 1 << gpio_config->gpio_num; + GPIO_SET(gpio_config->gpio_num, 1); OUT_GPIO(gpio_config->gpio_num); } else { INP_GPIO(gpio_config->gpio_num); @@ -129,9 +143,9 @@ static void restore_gpio(enum adapter_gpio_config_index 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; + GPIO_SET(adapter_gpio_config[idx].gpio_num, 1); else - GPIO_CLR = 1 << adapter_gpio_config[idx].gpio_num; + GPIO_CLR(adapter_gpio_config[idx].gpio_num, 1); } } bcm2835_gpio_synchronize(); @@ -143,8 +157,7 @@ static void initialize_gpio(enum adapter_gpio_config_index 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; + initial_gpio_state[idx].output_level = GPIO_LEV(adapter_gpio_config[idx].gpio_num); 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); @@ -174,23 +187,31 @@ static void initialize_gpio(enum adapter_gpio_config_index idx) static bb_value_t bcm2835gpio_read(void) { - unsigned int shift = adapter_gpio_config[ADAPTER_GPIO_IDX_TDO].gpio_num; - uint32_t value = (GPIO_LEV >> shift) & 1; + uint32_t value = GPIO_LEV(adapter_gpio_config[ADAPTER_GPIO_IDX_TDO].gpio_num); return value ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_TDO].active_low ? BB_HIGH : BB_LOW); } static int bcm2835gpio_write(int tck, int tms, int tdi) { +#ifndef BCM2835GPIO_ALL_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; - - GPIO_SET = set; - GPIO_CLR = clear; + GPIO_BULK_SET(set); + GPIO_BULK_CLR(clear); +#else + GPIO_SET(adapter_gpio_config[ADAPTER_GPIO_IDX_TCK].gpio_num, tck); + GPIO_SET(adapter_gpio_config[ADAPTER_GPIO_IDX_TMS].gpio_num, tms); + GPIO_SET(adapter_gpio_config[ADAPTER_GPIO_IDX_TDI].gpio_num, tdi); + + GPIO_CLR(adapter_gpio_config[ADAPTER_GPIO_IDX_TCK].gpio_num, !tck); + GPIO_CLR(adapter_gpio_config[ADAPTER_GPIO_IDX_TMS].gpio_num, !tms); + GPIO_CLR(adapter_gpio_config[ADAPTER_GPIO_IDX_TDI].gpio_num, !tdi); +#endif bcm2835_gpio_synchronize(); bcm2835_delay(); @@ -204,13 +225,20 @@ static int bcm2835gpio_swd_write_fast(int swclk, int swdio) 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); +#ifndef BCM2835GPIO_ALL_GPIO 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; - - GPIO_SET = set; - GPIO_CLR = clear; + GPIO_BULK_SET(set); + GPIO_BULK_CLR(clear); +#else + GPIO_SET(adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].gpio_num, swclk); + GPIO_SET(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num, swdio); + + GPIO_CLR(adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].gpio_num, !swclk); + GPIO_CLR(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num, !swdio); +#endif bcm2835_gpio_synchronize(); bcm2835_delay(); @@ -265,8 +293,7 @@ static void bcm2835_swdio_drive(bool is_output) static int bcm2835_swdio_read(void) { - unsigned int shift = adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num; - uint32_t value = (GPIO_LEV >> shift) & 1; + uint32_t value = GPIO_LEV(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num); return value ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].active_low ? 1 : 0); } --