5af92c36375bf537a04ed34b2858224537a7e51a
[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 /* GPIO setup macros */
37 #define MODE_GPIO(g) (*(pio_base+((g)/10))>>(((g)%10)*3) & 7)
38 #define INP_GPIO(g) do { *(pio_base+((g)/10)) &= ~(7<<(((g)%10)*3)); } while (0)
39 #define SET_MODE_GPIO(g, m) do { /* clear the mode bits first, then set as necessary */ \
40 INP_GPIO(g); \
41 *(pio_base+((g)/10)) |= ((m)<<(((g)%10)*3)); } while (0)
42 #define OUT_GPIO(g) SET_MODE_GPIO(g, 1)
43
44 #define GPIO_SET (*(pio_base+7)) /* sets bits which are 1, ignores bits which are 0 */
45 #define GPIO_CLR (*(pio_base+10)) /* clears bits which are 1, ignores bits which are 0 */
46 #define GPIO_LEV (*(pio_base+13)) /* current level of the pin */
47
48 static int dev_mem_fd;
49 static volatile uint32_t *pio_base;
50
51 static int bcm2835gpio_read(void);
52 static void bcm2835gpio_write(int tck, int tms, int tdi);
53 static void bcm2835gpio_reset(int trst, int srst);
54
55 static int bcm2835gpio_init(void);
56 static int bcm2835gpio_quit(void);
57
58 static struct bitbang_interface bcm2835gpio_bitbang = {
59 .read = bcm2835gpio_read,
60 .write = bcm2835gpio_write,
61 .reset = bcm2835gpio_reset,
62 .blink = NULL
63 };
64
65 /* GPIO numbers for each signal. Negative values are invalid */
66 static int tck_gpio = -1;
67 static int tck_gpio_mode;
68 static int tms_gpio = -1;
69 static int tms_gpio_mode;
70 static int tdi_gpio = -1;
71 static int tdi_gpio_mode;
72 static int tdo_gpio = -1;
73 static int tdo_gpio_mode;
74 static int trst_gpio = -1;
75 static int trst_gpio_mode;
76 static int srst_gpio = -1;
77 static int srst_gpio_mode;
78
79 /* Transition delay coefficients */
80 static int speed_coeff = 113714;
81 static int speed_offset = 28;
82 static unsigned int jtag_delay;
83
84 static int bcm2835gpio_read(void)
85 {
86 return !!(GPIO_LEV & 1<<tdo_gpio);
87 }
88
89 static void bcm2835gpio_write(int tck, int tms, int tdi)
90 {
91 uint32_t set = tck<<tck_gpio | tms<<tms_gpio | tdi<<tdi_gpio;
92 uint32_t clear = !tck<<tck_gpio | !tms<<tms_gpio | !tdi<<tdi_gpio;
93
94 GPIO_SET = set;
95 GPIO_CLR = clear;
96
97 for (unsigned int i = 0; i < jtag_delay; i++)
98 asm volatile ("");
99 }
100
101 /* (1) assert or (0) deassert reset lines */
102 static void bcm2835gpio_reset(int trst, int srst)
103 {
104 uint32_t set = 0;
105 uint32_t clear = 0;
106
107 if (trst_gpio > 0) {
108 set |= !trst<<trst_gpio;
109 clear |= trst<<trst_gpio;
110 }
111
112 if (srst_gpio > 0) {
113 set |= !srst<<srst_gpio;
114 clear |= srst<<srst_gpio;
115 }
116
117 GPIO_SET = set;
118 GPIO_CLR = clear;
119 }
120
121 static int bcm2835gpio_khz(int khz, int *jtag_speed)
122 {
123 if (!khz) {
124 LOG_DEBUG("RCLK not supported");
125 return ERROR_FAIL;
126 }
127 *jtag_speed = speed_coeff/khz - speed_offset;
128 if (*jtag_speed < 0)
129 *jtag_speed = 0;
130 return ERROR_OK;
131 }
132
133 static int bcm2835gpio_speed_div(int speed, int *khz)
134 {
135 *khz = speed_coeff/(speed + speed_offset);
136 return ERROR_OK;
137 }
138
139 static int bcm2835gpio_speed(int speed)
140 {
141 jtag_delay = speed;
142 return ERROR_OK;
143 }
144
145 static int is_gpio_valid(int gpio)
146 {
147 return gpio >= 0 && gpio <= 53;
148 }
149
150 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionums)
151 {
152 if (CMD_ARGC == 4) {
153 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio);
154 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tms_gpio);
155 COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], tdi_gpio);
156 COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], tdo_gpio);
157 } else if (CMD_ARGC != 0) {
158 return ERROR_COMMAND_SYNTAX_ERROR;
159 }
160
161 command_print(CMD_CTX,
162 "BCM2835 GPIO config: tck = %d, tms = %d, tdi = %d, tdi = %d",
163 tck_gpio, tms_gpio, tdi_gpio, tdo_gpio);
164
165 return ERROR_OK;
166 }
167
168 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tck)
169 {
170 if (CMD_ARGC == 1)
171 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio);
172
173 command_print(CMD_CTX, "BCM2835 GPIO config: tck = %d", tck_gpio);
174 return ERROR_OK;
175 }
176
177 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tms)
178 {
179 if (CMD_ARGC == 1)
180 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tms_gpio);
181
182 command_print(CMD_CTX, "BCM2835 GPIO config: tms = %d", tms_gpio);
183 return ERROR_OK;
184 }
185
186 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tdo)
187 {
188 if (CMD_ARGC == 1)
189 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdo_gpio);
190
191 command_print(CMD_CTX, "BCM2835 GPIO config: tdo = %d", tdo_gpio);
192 return ERROR_OK;
193 }
194
195 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tdi)
196 {
197 if (CMD_ARGC == 1)
198 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdi_gpio);
199
200 command_print(CMD_CTX, "BCM2835 GPIO config: tdi = %d", tdi_gpio);
201 return ERROR_OK;
202 }
203
204 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_srst)
205 {
206 if (CMD_ARGC == 1)
207 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], srst_gpio);
208
209 command_print(CMD_CTX, "BCM2835 GPIO config: srst = %d", srst_gpio);
210 return ERROR_OK;
211 }
212
213 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_trst)
214 {
215 if (CMD_ARGC == 1)
216 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], trst_gpio);
217
218 command_print(CMD_CTX, "BCM2835 GPIO config: trst = %d", trst_gpio);
219 return ERROR_OK;
220 }
221
222 COMMAND_HANDLER(bcm2835gpio_handle_speed_coeffs)
223 {
224 if (CMD_ARGC == 2) {
225 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], speed_coeff);
226 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], speed_offset);
227 }
228 return ERROR_OK;
229 }
230
231 static const struct command_registration bcm2835gpio_command_handlers[] = {
232 {
233 .name = "bcm2835gpio_jtag_nums",
234 .handler = &bcm2835gpio_handle_jtag_gpionums,
235 .mode = COMMAND_CONFIG,
236 .help = "gpio numbers for tck, tms, tdi, tdo. (in that order)",
237 .usage = "(tck tms tdi tdo)* ",
238 },
239 {
240 .name = "bcm2835gpio_tck_num",
241 .handler = &bcm2835gpio_handle_jtag_gpionum_tck,
242 .mode = COMMAND_CONFIG,
243 .help = "gpio number for tck.",
244 },
245 {
246 .name = "bcm2835gpio_tms_num",
247 .handler = &bcm2835gpio_handle_jtag_gpionum_tms,
248 .mode = COMMAND_CONFIG,
249 .help = "gpio number for tms.",
250 },
251 {
252 .name = "bcm2835gpio_tdo_num",
253 .handler = &bcm2835gpio_handle_jtag_gpionum_tdo,
254 .mode = COMMAND_CONFIG,
255 .help = "gpio number for tdo.",
256 },
257 {
258 .name = "bcm2835gpio_tdi_num",
259 .handler = &bcm2835gpio_handle_jtag_gpionum_tdi,
260 .mode = COMMAND_CONFIG,
261 .help = "gpio number for tdi.",
262 },
263 {
264 .name = "bcm2835gpio_srst_num",
265 .handler = &bcm2835gpio_handle_jtag_gpionum_srst,
266 .mode = COMMAND_CONFIG,
267 .help = "gpio number for srst.",
268 },
269 {
270 .name = "bcm2835gpio_trst_num",
271 .handler = &bcm2835gpio_handle_jtag_gpionum_trst,
272 .mode = COMMAND_CONFIG,
273 .help = "gpio number for trst.",
274 },
275 {
276 .name = "bcm2835gpio_speed_coeffs",
277 .handler = &bcm2835gpio_handle_speed_coeffs,
278 .mode = COMMAND_CONFIG,
279 .help = "SPEED_COEFF and SPEED_OFFSET for delay calculations.",
280 },
281 COMMAND_REGISTRATION_DONE
282 };
283
284 struct jtag_interface bcm2835gpio_interface = {
285 .name = "bcm2835gpio",
286 .supported = DEBUG_CAP_TMS_SEQ,
287 .execute_queue = bitbang_execute_queue,
288 .transports = jtag_only,
289 .speed = bcm2835gpio_speed,
290 .khz = bcm2835gpio_khz,
291 .speed_div = bcm2835gpio_speed_div,
292 .commands = bcm2835gpio_command_handlers,
293 .init = bcm2835gpio_init,
294 .quit = bcm2835gpio_quit,
295 };
296
297 static int bcm2835gpio_init(void)
298 {
299 bitbang_interface = &bcm2835gpio_bitbang;
300
301 if (!is_gpio_valid(tdo_gpio) || !is_gpio_valid(tdi_gpio) ||
302 !is_gpio_valid(tck_gpio) || !is_gpio_valid(tms_gpio) ||
303 (trst_gpio != -1 && !is_gpio_valid(trst_gpio)) ||
304 (srst_gpio != -1 && !is_gpio_valid(srst_gpio)))
305 return ERROR_JTAG_INIT_FAILED;
306
307 dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
308 if (dev_mem_fd < 0) {
309 perror("open");
310 return ERROR_JTAG_INIT_FAILED;
311 }
312
313 pio_base = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE,
314 MAP_SHARED, dev_mem_fd, BCM2835_GPIO_BASE);
315
316 if (pio_base == MAP_FAILED) {
317 perror("mmap");
318 close(dev_mem_fd);
319 return ERROR_JTAG_INIT_FAILED;
320 }
321
322 tdo_gpio_mode = MODE_GPIO(tdo_gpio);
323 tdi_gpio_mode = MODE_GPIO(tdi_gpio);
324 tck_gpio_mode = MODE_GPIO(tck_gpio);
325 tms_gpio_mode = MODE_GPIO(tms_gpio);
326 /*
327 * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST
328 * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high.
329 */
330 INP_GPIO(tdo_gpio);
331
332 GPIO_CLR = 1<<tdi_gpio | 1<<tck_gpio;
333 GPIO_SET = 1<<tms_gpio;
334
335 OUT_GPIO(tdi_gpio);
336 OUT_GPIO(tck_gpio);
337 OUT_GPIO(tms_gpio);
338 if (trst_gpio != -1) {
339 trst_gpio_mode = MODE_GPIO(trst_gpio);
340 GPIO_SET = 1 << trst_gpio;
341 OUT_GPIO(trst_gpio);
342 }
343 if (srst_gpio != -1) {
344 srst_gpio_mode = MODE_GPIO(srst_gpio);
345 GPIO_SET = 1 << srst_gpio;
346 OUT_GPIO(srst_gpio);
347 }
348
349 LOG_DEBUG("saved pinmux settings: tck %d tms %d tdi %d "
350 "tdo %d trst %d srst %d", tck_gpio_mode, tms_gpio_mode,
351 tdi_gpio_mode, tdo_gpio_mode, trst_gpio_mode, srst_gpio_mode);
352
353 return ERROR_OK;
354 }
355
356 static int bcm2835gpio_quit(void)
357 {
358 SET_MODE_GPIO(tdo_gpio, tdo_gpio_mode);
359 SET_MODE_GPIO(tdi_gpio, tdi_gpio_mode);
360 SET_MODE_GPIO(tck_gpio, tck_gpio_mode);
361 SET_MODE_GPIO(tms_gpio, tms_gpio_mode);
362 if (trst_gpio != -1)
363 SET_MODE_GPIO(trst_gpio, trst_gpio_mode);
364 if (srst_gpio != -1)
365 SET_MODE_GPIO(srst_gpio, srst_gpio_mode);
366
367 return ERROR_OK;
368 }

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)