bcm2835gpio: use maximum drive strength
[openocd.git] / src / jtag / drivers / bcm2835gpio.c
1 /***************************************************************************
2 * Copyright (C) 2013 by Paul Fertser, fercerpav@gmail.com *
3 * *
4 * Copyright (C) 2012 by Creative Product Design, marc @ cpdesign.com.au *
5 * Based on at91rm9200.c (c) Anders Larsen *
6 * and RPi GPIO examples by Gert van Loo & Dom *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
22 ***************************************************************************/
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <jtag/interface.h>
29 #include "bitbang.h"
30
31 #include <sys/mman.h>
32
33 #define BCM2835_PERI_BASE 0x20000000
34 #define BCM2835_GPIO_BASE (BCM2835_PERI_BASE + 0x200000) /* GPIO controller */
35
36 #define BCM2835_PADS_GPIO_0_27 (BCM2835_PERI_BASE + 0x100000)
37 #define BCM2835_PADS_GPIO_0_27_OFFSET (0x2c / 4)
38
39 /* GPIO setup macros */
40 #define MODE_GPIO(g) (*(pio_base+((g)/10))>>(((g)%10)*3) & 7)
41 #define INP_GPIO(g) do { *(pio_base+((g)/10)) &= ~(7<<(((g)%10)*3)); } while (0)
42 #define SET_MODE_GPIO(g, m) do { /* clear the mode bits first, then set as necessary */ \
43 INP_GPIO(g); \
44 *(pio_base+((g)/10)) |= ((m)<<(((g)%10)*3)); } while (0)
45 #define OUT_GPIO(g) SET_MODE_GPIO(g, 1)
46
47 #define GPIO_SET (*(pio_base+7)) /* sets bits which are 1, ignores bits which are 0 */
48 #define GPIO_CLR (*(pio_base+10)) /* clears bits which are 1, ignores bits which are 0 */
49 #define GPIO_LEV (*(pio_base+13)) /* current level of the pin */
50
51 static int dev_mem_fd;
52 static volatile uint32_t *pio_base;
53
54 static int bcm2835gpio_read(void);
55 static void bcm2835gpio_write(int tck, int tms, int tdi);
56 static void bcm2835gpio_reset(int trst, int srst);
57
58 static int bcm2835gpio_init(void);
59 static int bcm2835gpio_quit(void);
60
61 static struct bitbang_interface bcm2835gpio_bitbang = {
62 .read = bcm2835gpio_read,
63 .write = bcm2835gpio_write,
64 .reset = bcm2835gpio_reset,
65 .blink = NULL
66 };
67
68 /* GPIO numbers for each signal. Negative values are invalid */
69 static int tck_gpio = -1;
70 static int tck_gpio_mode;
71 static int tms_gpio = -1;
72 static int tms_gpio_mode;
73 static int tdi_gpio = -1;
74 static int tdi_gpio_mode;
75 static int tdo_gpio = -1;
76 static int tdo_gpio_mode;
77 static int trst_gpio = -1;
78 static int trst_gpio_mode;
79 static int srst_gpio = -1;
80 static int srst_gpio_mode;
81
82 /* Transition delay coefficients */
83 static int speed_coeff = 113714;
84 static int speed_offset = 28;
85 static unsigned int jtag_delay;
86
87 static int bcm2835gpio_read(void)
88 {
89 return !!(GPIO_LEV & 1<<tdo_gpio);
90 }
91
92 static void bcm2835gpio_write(int tck, int tms, int tdi)
93 {
94 uint32_t set = tck<<tck_gpio | tms<<tms_gpio | tdi<<tdi_gpio;
95 uint32_t clear = !tck<<tck_gpio | !tms<<tms_gpio | !tdi<<tdi_gpio;
96
97 GPIO_SET = set;
98 GPIO_CLR = clear;
99
100 for (unsigned int i = 0; i < jtag_delay; i++)
101 asm volatile ("");
102 }
103
104 /* (1) assert or (0) deassert reset lines */
105 static void bcm2835gpio_reset(int trst, int srst)
106 {
107 uint32_t set = 0;
108 uint32_t clear = 0;
109
110 if (trst_gpio > 0) {
111 set |= !trst<<trst_gpio;
112 clear |= trst<<trst_gpio;
113 }
114
115 if (srst_gpio > 0) {
116 set |= !srst<<srst_gpio;
117 clear |= srst<<srst_gpio;
118 }
119
120 GPIO_SET = set;
121 GPIO_CLR = clear;
122 }
123
124 static int bcm2835gpio_khz(int khz, int *jtag_speed)
125 {
126 if (!khz) {
127 LOG_DEBUG("RCLK not supported");
128 return ERROR_FAIL;
129 }
130 *jtag_speed = speed_coeff/khz - speed_offset;
131 if (*jtag_speed < 0)
132 *jtag_speed = 0;
133 return ERROR_OK;
134 }
135
136 static int bcm2835gpio_speed_div(int speed, int *khz)
137 {
138 *khz = speed_coeff/(speed + speed_offset);
139 return ERROR_OK;
140 }
141
142 static int bcm2835gpio_speed(int speed)
143 {
144 jtag_delay = speed;
145 return ERROR_OK;
146 }
147
148 static int is_gpio_valid(int gpio)
149 {
150 return gpio >= 0 && gpio <= 53;
151 }
152
153 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionums)
154 {
155 if (CMD_ARGC == 4) {
156 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio);
157 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tms_gpio);
158 COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], tdi_gpio);
159 COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], tdo_gpio);
160 } else if (CMD_ARGC != 0) {
161 return ERROR_COMMAND_SYNTAX_ERROR;
162 }
163
164 command_print(CMD_CTX,
165 "BCM2835 GPIO config: tck = %d, tms = %d, tdi = %d, tdi = %d",
166 tck_gpio, tms_gpio, tdi_gpio, tdo_gpio);
167
168 return ERROR_OK;
169 }
170
171 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tck)
172 {
173 if (CMD_ARGC == 1)
174 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio);
175
176 command_print(CMD_CTX, "BCM2835 GPIO config: tck = %d", tck_gpio);
177 return ERROR_OK;
178 }
179
180 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tms)
181 {
182 if (CMD_ARGC == 1)
183 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tms_gpio);
184
185 command_print(CMD_CTX, "BCM2835 GPIO config: tms = %d", tms_gpio);
186 return ERROR_OK;
187 }
188
189 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tdo)
190 {
191 if (CMD_ARGC == 1)
192 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdo_gpio);
193
194 command_print(CMD_CTX, "BCM2835 GPIO config: tdo = %d", tdo_gpio);
195 return ERROR_OK;
196 }
197
198 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tdi)
199 {
200 if (CMD_ARGC == 1)
201 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdi_gpio);
202
203 command_print(CMD_CTX, "BCM2835 GPIO config: tdi = %d", tdi_gpio);
204 return ERROR_OK;
205 }
206
207 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_srst)
208 {
209 if (CMD_ARGC == 1)
210 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], srst_gpio);
211
212 command_print(CMD_CTX, "BCM2835 GPIO config: srst = %d", srst_gpio);
213 return ERROR_OK;
214 }
215
216 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_trst)
217 {
218 if (CMD_ARGC == 1)
219 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], trst_gpio);
220
221 command_print(CMD_CTX, "BCM2835 GPIO config: trst = %d", trst_gpio);
222 return ERROR_OK;
223 }
224
225 COMMAND_HANDLER(bcm2835gpio_handle_speed_coeffs)
226 {
227 if (CMD_ARGC == 2) {
228 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], speed_coeff);
229 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], speed_offset);
230 }
231 return ERROR_OK;
232 }
233
234 static const struct command_registration bcm2835gpio_command_handlers[] = {
235 {
236 .name = "bcm2835gpio_jtag_nums",
237 .handler = &bcm2835gpio_handle_jtag_gpionums,
238 .mode = COMMAND_CONFIG,
239 .help = "gpio numbers for tck, tms, tdi, tdo. (in that order)",
240 .usage = "(tck tms tdi tdo)* ",
241 },
242 {
243 .name = "bcm2835gpio_tck_num",
244 .handler = &bcm2835gpio_handle_jtag_gpionum_tck,
245 .mode = COMMAND_CONFIG,
246 .help = "gpio number for tck.",
247 },
248 {
249 .name = "bcm2835gpio_tms_num",
250 .handler = &bcm2835gpio_handle_jtag_gpionum_tms,
251 .mode = COMMAND_CONFIG,
252 .help = "gpio number for tms.",
253 },
254 {
255 .name = "bcm2835gpio_tdo_num",
256 .handler = &bcm2835gpio_handle_jtag_gpionum_tdo,
257 .mode = COMMAND_CONFIG,
258 .help = "gpio number for tdo.",
259 },
260 {
261 .name = "bcm2835gpio_tdi_num",
262 .handler = &bcm2835gpio_handle_jtag_gpionum_tdi,
263 .mode = COMMAND_CONFIG,
264 .help = "gpio number for tdi.",
265 },
266 {
267 .name = "bcm2835gpio_srst_num",
268 .handler = &bcm2835gpio_handle_jtag_gpionum_srst,
269 .mode = COMMAND_CONFIG,
270 .help = "gpio number for srst.",
271 },
272 {
273 .name = "bcm2835gpio_trst_num",
274 .handler = &bcm2835gpio_handle_jtag_gpionum_trst,
275 .mode = COMMAND_CONFIG,
276 .help = "gpio number for trst.",
277 },
278 {
279 .name = "bcm2835gpio_speed_coeffs",
280 .handler = &bcm2835gpio_handle_speed_coeffs,
281 .mode = COMMAND_CONFIG,
282 .help = "SPEED_COEFF and SPEED_OFFSET for delay calculations.",
283 },
284 COMMAND_REGISTRATION_DONE
285 };
286
287 struct jtag_interface bcm2835gpio_interface = {
288 .name = "bcm2835gpio",
289 .supported = DEBUG_CAP_TMS_SEQ,
290 .execute_queue = bitbang_execute_queue,
291 .transports = jtag_only,
292 .speed = bcm2835gpio_speed,
293 .khz = bcm2835gpio_khz,
294 .speed_div = bcm2835gpio_speed_div,
295 .commands = bcm2835gpio_command_handlers,
296 .init = bcm2835gpio_init,
297 .quit = bcm2835gpio_quit,
298 };
299
300 static int bcm2835gpio_init(void)
301 {
302 bitbang_interface = &bcm2835gpio_bitbang;
303
304 if (!is_gpio_valid(tdo_gpio) || !is_gpio_valid(tdi_gpio) ||
305 !is_gpio_valid(tck_gpio) || !is_gpio_valid(tms_gpio) ||
306 (trst_gpio != -1 && !is_gpio_valid(trst_gpio)) ||
307 (srst_gpio != -1 && !is_gpio_valid(srst_gpio)))
308 return ERROR_JTAG_INIT_FAILED;
309
310 dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
311 if (dev_mem_fd < 0) {
312 perror("open");
313 return ERROR_JTAG_INIT_FAILED;
314 }
315
316 pio_base = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE,
317 MAP_SHARED, dev_mem_fd, BCM2835_GPIO_BASE);
318
319 if (pio_base == MAP_FAILED) {
320 perror("mmap");
321 close(dev_mem_fd);
322 return ERROR_JTAG_INIT_FAILED;
323 }
324
325 static volatile uint32_t *pads_base;
326 pads_base = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE,
327 MAP_SHARED, dev_mem_fd, BCM2835_PADS_GPIO_0_27);
328
329 if (pads_base == MAP_FAILED) {
330 perror("mmap");
331 close(dev_mem_fd);
332 return ERROR_JTAG_INIT_FAILED;
333 }
334
335 /* set 16mA drive strength */
336 pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5a000018 + 7;
337
338 tdo_gpio_mode = MODE_GPIO(tdo_gpio);
339 tdi_gpio_mode = MODE_GPIO(tdi_gpio);
340 tck_gpio_mode = MODE_GPIO(tck_gpio);
341 tms_gpio_mode = MODE_GPIO(tms_gpio);
342 /*
343 * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST
344 * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high.
345 */
346 INP_GPIO(tdo_gpio);
347
348 GPIO_CLR = 1<<tdi_gpio | 1<<tck_gpio;
349 GPIO_SET = 1<<tms_gpio;
350
351 OUT_GPIO(tdi_gpio);
352 OUT_GPIO(tck_gpio);
353 OUT_GPIO(tms_gpio);
354 if (trst_gpio != -1) {
355 trst_gpio_mode = MODE_GPIO(trst_gpio);
356 GPIO_SET = 1 << trst_gpio;
357 OUT_GPIO(trst_gpio);
358 }
359 if (srst_gpio != -1) {
360 srst_gpio_mode = MODE_GPIO(srst_gpio);
361 GPIO_SET = 1 << srst_gpio;
362 OUT_GPIO(srst_gpio);
363 }
364
365 LOG_DEBUG("saved pinmux settings: tck %d tms %d tdi %d "
366 "tdo %d trst %d srst %d", tck_gpio_mode, tms_gpio_mode,
367 tdi_gpio_mode, tdo_gpio_mode, trst_gpio_mode, srst_gpio_mode);
368
369 return ERROR_OK;
370 }
371
372 static int bcm2835gpio_quit(void)
373 {
374 SET_MODE_GPIO(tdo_gpio, tdo_gpio_mode);
375 SET_MODE_GPIO(tdi_gpio, tdi_gpio_mode);
376 SET_MODE_GPIO(tck_gpio, tck_gpio_mode);
377 SET_MODE_GPIO(tms_gpio, tms_gpio_mode);
378 if (trst_gpio != -1)
379 SET_MODE_GPIO(trst_gpio, trst_gpio_mode);
380 if (srst_gpio != -1)
381 SET_MODE_GPIO(srst_gpio, srst_gpio_mode);
382
383 return ERROR_OK;
384 }

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)