This is an automated email from Gerrit.

"Steve Marple <stevemar...@googlemail.com>" just uploaded a new patch set to 
Gerrit, which you can find at https://review.openocd.org/c/openocd/+/7130

-- gerrit

commit 6cb9a12565c68446c3cdb1fc37fab6a285a054ba
Author: Steve Marple <stevemar...@googlemail.com>
Date:   Tue Aug 16 23:37:47 2022 +0100

    drivers/bcm2835gpio: Implement srst and power sensing
    
    Signed-off-by: Steve Marple <stevemar...@googlemail.com>
    Change-Id: Ib3904278737350b0f74bd95e4abf487e19fa646f

diff --git a/doc/openocd.texi b/doc/openocd.texi
index 5b37ad1299..26c7bd6075 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -3299,8 +3299,12 @@ 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}}.
 
-See @file{interface/raspberrypi-native.cfg} for a sample config and
-pinout.
+The driver supports the @command{adapter gpio pwr_ctrl}, @command{adapter gpio
+pwr_sense}, and @command{adapter gpio srst_sense} commands. When sensing inputs
+the GPIO peripheral should not generate interrupts as this may cause Linux to
+hang so be sure to include the line @samp{dtoverlay=gpio-no-irq} in the file
+@file{/boot/config.txt}. See @file{interface/raspberrypi-native.cfg} for a
+sample config and pinout.
 
 @deffn {Config Command} {bcm2835gpio speed_coeffs} @var{speed_coeff} 
@var{speed_offset}
 Set SPEED_COEFF and SPEED_OFFSET for delay calculations. If unspecified,
diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c
index 51f737251b..16aaaa2098 100644
--- a/src/jtag/drivers/bcm2835gpio.c
+++ b/src/jtag/drivers/bcm2835gpio.c
@@ -40,10 +40,24 @@ uint32_t bcm2835_peri_base = 0x20000000;
 #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 = MAP_FAILED;
-static volatile uint32_t *pads_base = MAP_FAILED;
+#define GPIO_GPEDS0 (*(pio_base+16)) /* event detect status 0 */
+#define GPIO_GPREN0 (*(pio_base+19)) /* rising-edge detect enable 0 */
+#define GPIO_GPFEN0 (*(pio_base+22)) /* falling-edge detect enable 0 */
+#define GPIO_GPHEN0 (*(pio_base+25)) /* high detect enable 0 */
+#define GPIO_GPLEN0 (*(pio_base+28)) /* low detect enable 0 */
+#define GPIO_GPAREN0 (*(pio_base+31)) /* asynchronous rising-edge detection 
(0) */
+#define GPIO_GPAFEN0 (*(pio_base+34)) /* asynchronous falling-edge detection 
(0) */
+
+/* There are various options for sensing: level detection, edge detection, and
+ * asynchronous edge detection. Try asynchronous detection since it should 
catch
+ * narrow glitches that the pattern-matching edge-detection choices might
+ * reject.
+ */
+#define GPIO_SENSE_LOW GPIO_GPAFEN0
+#define GPIO_SENSE_HIGH GPIO_GPAREN0
+
+static int dev_mem_fd; static volatile uint32_t *pio_base = MAP_FAILED; static
+volatile uint32_t *pads_base = MAP_FAILED;
 
 /* Transition delay coefficients */
 static int speed_coeff = 113714;
@@ -107,6 +121,20 @@ static void restore_gpio(enum adapter_gpio_config_index 
idx)
                        else
                                GPIO_CLR = 1 << 
adapter_gpio_config[idx].gpio_num;
                }
+
+               /* TODO: restore edge and level detection settings for sense 
inputs? Is
+                * it worthwhile?
+                */
+               if (idx == ADAPTER_GPIO_IDX_SRST_SENSE || idx == 
ADAPTER_GPIO_IDX_PWR_SENSE) {
+                       uint32_t mask = (1 << 
adapter_gpio_config[idx].gpio_num);
+                       /* Clear all edge and level detection for this GPIO. */
+                       GPIO_GPREN0 &= ~mask;
+                       GPIO_GPFEN0 &= ~mask;
+                       GPIO_GPHEN0 &= ~mask;
+                       GPIO_GPLEN0 &= ~mask;
+                       GPIO_GPAREN0 &= ~mask;
+                       GPIO_GPAFEN0 &= ~mask;
+               }
        }
 }
 
@@ -139,6 +167,29 @@ static void initialize_gpio(enum adapter_gpio_config_index 
idx)
                break;
        }
 
+       if (idx == ADAPTER_GPIO_IDX_SRST_SENSE || idx == 
ADAPTER_GPIO_IDX_PWR_SENSE) {
+               /* Enabling edge detection can lead to unwanted interactions 
with the OS
+                * (almost certainly Linux) that can result in Linux hanging. 
The
+                * solution is to disable interrupts from the GPIO peripheral 
when
+                * sensing srst or power dropout; do so by including
+                * "dtoverlay=gpio-no-irq" in /boot/config.txt
+                */
+               uint32_t mask = (1 << adapter_gpio_config[idx].gpio_num); /* 
Clear all
+               edge and level detection for this GPIO. */
+               GPIO_GPREN0 &= ~mask;
+               GPIO_GPFEN0 &= ~mask;
+               GPIO_GPHEN0 &= ~mask;
+               GPIO_GPLEN0 &= ~mask;
+               GPIO_GPAREN0 &= ~mask;
+               GPIO_GPAFEN0 &= ~mask;
+
+               if (adapter_gpio_config[idx].active_low)
+                       GPIO_SENSE_LOW |= mask;
+               else
+                       GPIO_SENSE_HIGH |= mask;
+               GPIO_GPEDS0 = mask; /* Clear any existing event for this GPIO */
+       }
+
        /* Direction for non push-pull is already set by set_gpio_value() */
        if (adapter_gpio_config[idx].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL)
                OUT_GPIO(adapter_gpio_config[idx].gpio_num);
@@ -471,6 +522,8 @@ static int bcm2835gpio_init(void)
 
        initialize_gpio(ADAPTER_GPIO_IDX_SRST);
        initialize_gpio(ADAPTER_GPIO_IDX_LED);
+       initialize_gpio(ADAPTER_GPIO_IDX_SRST_SENSE);
+       initialize_gpio(ADAPTER_GPIO_IDX_PWR_SENSE);
 
        return ERROR_OK;
 }
@@ -499,6 +552,8 @@ static int bcm2835gpio_quit(void)
 
        restore_gpio(ADAPTER_GPIO_IDX_SRST);
        restore_gpio(ADAPTER_GPIO_IDX_LED);
+       restore_gpio(ADAPTER_GPIO_IDX_SRST_SENSE);
+       restore_gpio(ADAPTER_GPIO_IDX_PWR_SENSE);
 
        /* Keep powered until last possible moment */
        restore_gpio(ADAPTER_GPIO_IDX_PWR_CTRL);
@@ -508,6 +563,36 @@ static int bcm2835gpio_quit(void)
        return ERROR_OK;
 }
 
+static int bcm2835gpio_input_sense(enum adapter_gpio_config_index idx, int 
*sensed)
+{
+       if (!is_gpio_config_valid(idx)) {
+               *sensed = 0;
+               return ERROR_OK;
+       }
+
+       /* Check if any events occurred since last time; read out all. */
+       uint32_t mask = (1 << adapter_gpio_config[idx].gpio_num);
+       if (GPIO_GPEDS0 & mask) {
+               *sensed = 1;
+               GPIO_GPEDS0 = mask;
+               LOG_ERROR("BCM2835: %s asserted", adapter_gpio_get_name(idx));
+       } else {
+               *sensed = 0;
+       }
+
+       return ERROR_OK;
+}
+
+static int bcm2835gpio_power_dropout(int *power_dropout)
+{
+       return bcm2835gpio_input_sense(ADAPTER_GPIO_IDX_PWR_SENSE, 
power_dropout);
+}
+
+static int bcm2835gpio_srst_asserted(int *srst_asserted)
+{
+       return bcm2835gpio_input_sense(ADAPTER_GPIO_IDX_SRST_SENSE, 
srst_asserted);
+}
+
 struct adapter_driver bcm2835gpio_adapter_driver = {
        .name = "bcm2835gpio",
        .transports = bcm2835_transports,
@@ -519,6 +604,8 @@ struct adapter_driver bcm2835gpio_adapter_driver = {
        .speed = bcm2835gpio_speed,
        .khz = bcm2835gpio_khz,
        .speed_div = bcm2835gpio_speed_div,
+       .power_dropout = bcm2835gpio_power_dropout,
+       .srst_asserted = bcm2835gpio_srst_asserted,
 
        .jtag_ops = &bcm2835gpio_interface,
        .swd_ops = &bitbang_swd,

-- 

Reply via email to