Skip to content

Commit ee87f2b

Browse files
P33Mborneoa
authored andcommitted
jtag/drivers: bcm2835gpio: implement memory barriers when bitbashing
This GPIO driver is common to SoCs that have in-order ARM cores (BCM2835) as well as superscalar (BCM2836-7) and speculative out-of-order cores (BCM2711). For BCM2837 and BCM2711, the processor can dual-issue stores and is free to merge writes to peripheral memory for pages mapped MT_NORMAL_NC, which is the default provided by /dev/[gpio]mem. This can cause glitches (or missing edges) on GPIO pins when toggled with no delay, as pipelined writes to the same address can get arbitrarily squelched. To prevent this happening, make sure the preceding write ops are flushed outside the shareable domain by using a memory barrier. Signed-off-by: Jonathan Bell <[email protected]> Change-Id: I8805cc0911667bcb9b7f4ca340d7f4f1cb25d096 Reviewed-on: https://review.openocd.org/c/openocd/+/7258 Tested-by: jenkins Reviewed-by: Antonio Borneo <[email protected]>
1 parent a7ea1ef commit ee87f2b

File tree

1 file changed

+15
-0
lines changed

1 file changed

+15
-0
lines changed

src/jtag/drivers/bcm2835gpio.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ static struct initial_gpio_state {
5757
} initial_gpio_state[ADAPTER_GPIO_IDX_NUM];
5858
static uint32_t initial_drive_strength_etc;
5959

60+
static inline void bcm2835_gpio_synchronize(void)
61+
{
62+
/* Ensure that previous writes to GPIO registers are flushed out of
63+
* the inner shareable domain to prevent pipelined writes to the
64+
* same address being merged.
65+
*/
66+
__sync_synchronize();
67+
}
68+
6069
static bool is_gpio_config_valid(enum adapter_gpio_config_index idx)
6170
{
6271
/* Only chip 0 is supported, accept unset value (-1) too */
@@ -96,6 +105,7 @@ static void set_gpio_value(const struct adapter_gpio_config *gpio_config, int va
96105
}
97106
break;
98107
}
108+
bcm2835_gpio_synchronize();
99109
}
100110

101111
static void restore_gpio(enum adapter_gpio_config_index idx)
@@ -109,6 +119,7 @@ static void restore_gpio(enum adapter_gpio_config_index idx)
109119
GPIO_CLR = 1 << adapter_gpio_config[idx].gpio_num;
110120
}
111121
}
122+
bcm2835_gpio_synchronize();
112123
}
113124

114125
static void initialize_gpio(enum adapter_gpio_config_index idx)
@@ -143,6 +154,7 @@ static void initialize_gpio(enum adapter_gpio_config_index idx)
143154
/* Direction for non push-pull is already set by set_gpio_value() */
144155
if (adapter_gpio_config[idx].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL)
145156
OUT_GPIO(adapter_gpio_config[idx].gpio_num);
157+
bcm2835_gpio_synchronize();
146158
}
147159

148160
static bb_value_t bcm2835gpio_read(void)
@@ -164,6 +176,7 @@ static int bcm2835gpio_write(int tck, int tms, int tdi)
164176

165177
GPIO_SET = set;
166178
GPIO_CLR = clear;
179+
bcm2835_gpio_synchronize();
167180

168181
for (unsigned int i = 0; i < jtag_delay; i++)
169182
asm volatile ("");
@@ -184,6 +197,7 @@ static int bcm2835gpio_swd_write_fast(int swclk, int swdio)
184197

185198
GPIO_SET = set;
186199
GPIO_CLR = clear;
200+
bcm2835_gpio_synchronize();
187201

188202
for (unsigned int i = 0; i < jtag_delay; i++)
189203
asm volatile ("");
@@ -234,6 +248,7 @@ static void bcm2835_swdio_drive(bool is_output)
234248
if (is_gpio_config_valid(ADAPTER_GPIO_IDX_SWDIO_DIR))
235249
set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR], 0);
236250
}
251+
bcm2835_gpio_synchronize();
237252
}
238253

239254
static int bcm2835_swdio_read(void)

0 commit comments

Comments
 (0)