1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 /***************************************************************************
4 * Copyright (C) 2022 by Steve Marple, stevemarple@googlemail.com *
6 * Based on bcm2835gpio.c and linuxgpiod.c *
7 ***************************************************************************/
13 #include <jtag/adapter.h>
14 #include <jtag/interface.h>
15 #include <transport/transport.h>
20 /* GPIO register base addresses. Values taken from "AM335x and AMIC110 Sitara
21 * Processors Technical Reference Manual", Chapter 2 Memory Map.
23 #define AM335XGPIO_NUM_GPIO_PER_CHIP 32
24 #define AM335XGPIO_NUM_GPIO_CHIPS 4
25 #define AM335XGPIO_GPIO0_HW_ADDR 0x44E07000
26 #define AM335XGPIO_GPIO1_HW_ADDR 0x4804C000
27 #define AM335XGPIO_GPIO2_HW_ADDR 0x481AC000
28 #define AM335XGPIO_GPIO3_HW_ADDR 0x481AE000
30 /* 32-bit offsets from GPIO chip base address. Values taken from "AM335x and
31 * AMIC110 Sitara Processors Technical Reference Manual", Chapter 25
32 * General-Purpose Input/Output.
34 #define AM335XGPIO_GPIO_OE_OFFSET (0x134 / 4)
35 #define AM335XGPIO_GPIO_DATAIN_OFFSET (0x138 / 4)
36 #define AM335XGPIO_GPIO_DATAOUT_OFFSET (0x13C / 4) /* DATAOUT register uses 0 for output, 1 for input */
37 #define AM335XGPIO_GPIO_CLEARDATAOUT_OFFSET (0x190 / 4)
38 #define AM335XGPIO_GPIO_SETDATAOUT_OFFSET (0x194 / 4)
40 #define AM335XGPIO_READ_REG(chip_num, offset) \
41 (*(am335xgpio_gpio_chip_mmap_addr[(chip_num)] + (offset)))
43 #define AM335XGPIO_WRITE_REG(chip_num, offset, value) \
44 (*(am335xgpio_gpio_chip_mmap_addr[(chip_num)] + (offset)) = (value))
46 #define AM335XGPIO_SET_REG_BITS(chip_num, offset, bit_mask) \
47 (*(am335xgpio_gpio_chip_mmap_addr[(chip_num)] + (offset)) |= (bit_mask))
49 #define AM335XGPIO_CLEAR_REG_BITS(chip_num, offset, bit_mask) \
50 (*(am335xgpio_gpio_chip_mmap_addr[(chip_num)] + (offset)) &= ~(bit_mask))
52 #define AM335XGPIO_SET_INPUT(gpio_config) \
53 AM335XGPIO_SET_REG_BITS((gpio_config)->chip_num, AM335XGPIO_GPIO_OE_OFFSET, BIT((gpio_config)->gpio_num))
54 #define AM335XGPIO_SET_OUTPUT(gpio_config) \
55 AM335XGPIO_CLEAR_REG_BITS((gpio_config)->chip_num, AM335XGPIO_GPIO_OE_OFFSET, BIT((gpio_config)->gpio_num))
56 #define AM335XGPIO_SET_HIGH(gpio_config) \
57 AM335XGPIO_WRITE_REG((gpio_config)->chip_num, AM335XGPIO_GPIO_SETDATAOUT_OFFSET, BIT((gpio_config)->gpio_num))
58 #define AM335XGPIO_SET_LOW(gpio_config) \
59 AM335XGPIO_WRITE_REG((gpio_config)->chip_num, AM335XGPIO_GPIO_CLEARDATAOUT_OFFSET, BIT((gpio_config)->gpio_num))
61 enum amx335gpio_initial_gpio_mode
{
62 AM335XGPIO_GPIO_MODE_INPUT
,
63 AM335XGPIO_GPIO_MODE_OUTPUT_LOW
,
64 AM335XGPIO_GPIO_MODE_OUTPUT_HIGH
,
67 static const uint32_t am335xgpio_gpio_chip_hw_addr
[AM335XGPIO_NUM_GPIO_CHIPS
] = {
68 AM335XGPIO_GPIO0_HW_ADDR
,
69 AM335XGPIO_GPIO1_HW_ADDR
,
70 AM335XGPIO_GPIO2_HW_ADDR
,
71 AM335XGPIO_GPIO3_HW_ADDR
,
74 /* Memory-mapped address pointers */
75 static volatile uint32_t *am335xgpio_gpio_chip_mmap_addr
[AM335XGPIO_NUM_GPIO_CHIPS
];
77 static int dev_mem_fd
;
78 static enum amx335gpio_initial_gpio_mode initial_gpio_mode
[ADAPTER_GPIO_IDX_NUM
];
80 /* Transition delay coefficients */
81 static int speed_coeff
= 600000;
82 static int speed_offset
= 575;
83 static unsigned int jtag_delay
;
85 static const struct adapter_gpio_config
*adapter_gpio_config
;
87 static bool is_gpio_config_valid(const struct adapter_gpio_config
*gpio_config
)
89 return gpio_config
->chip_num
>= 0
90 && gpio_config
->chip_num
< AM335XGPIO_NUM_GPIO_CHIPS
91 && gpio_config
->gpio_num
>= 0
92 && gpio_config
->gpio_num
< AM335XGPIO_NUM_GPIO_PER_CHIP
;
95 static int get_gpio_value(const struct adapter_gpio_config
*gpio_config
)
97 unsigned int shift
= gpio_config
->gpio_num
;
98 uint32_t value
= AM335XGPIO_READ_REG(gpio_config
->chip_num
, AM335XGPIO_GPIO_DATAIN_OFFSET
);
99 value
= (value
>> shift
) & 1;
100 return value
^ (gpio_config
->active_low
? 1 : 0);
103 static void set_gpio_value(const struct adapter_gpio_config
*gpio_config
, int value
)
105 value
= value
^ (gpio_config
->active_low
? 1 : 0);
106 switch (gpio_config
->drive
) {
107 case ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL
:
109 AM335XGPIO_SET_HIGH(gpio_config
);
111 AM335XGPIO_SET_LOW(gpio_config
);
112 /* For performance reasons assume the GPIO is already set as an output
113 * and therefore the call can be omitted here.
116 case ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN
:
118 AM335XGPIO_SET_INPUT(gpio_config
);
120 AM335XGPIO_SET_LOW(gpio_config
);
121 AM335XGPIO_SET_OUTPUT(gpio_config
);
124 case ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE
:
126 AM335XGPIO_SET_HIGH(gpio_config
);
127 AM335XGPIO_SET_OUTPUT(gpio_config
);
129 AM335XGPIO_SET_INPUT(gpio_config
);
135 static enum amx335gpio_initial_gpio_mode
get_gpio_mode(const struct adapter_gpio_config
*gpio_config
)
137 if (AM335XGPIO_READ_REG(gpio_config
->chip_num
, AM335XGPIO_GPIO_OE_OFFSET
) & BIT(gpio_config
->gpio_num
))
138 return AM335XGPIO_GPIO_MODE_INPUT
;
140 /* Return output level too so that pin mode can be fully restored */
141 if (AM335XGPIO_READ_REG(gpio_config
->chip_num
, AM335XGPIO_GPIO_DATAOUT_OFFSET
) & BIT(gpio_config
->gpio_num
))
142 return AM335XGPIO_GPIO_MODE_OUTPUT_HIGH
;
143 return AM335XGPIO_GPIO_MODE_OUTPUT_LOW
;
146 static const char *get_gpio_mode_name(enum amx335gpio_initial_gpio_mode gpio_mode
)
149 case AM335XGPIO_GPIO_MODE_INPUT
:
151 case AM335XGPIO_GPIO_MODE_OUTPUT_LOW
:
152 return "output (low)";
153 case AM335XGPIO_GPIO_MODE_OUTPUT_HIGH
:
154 return "output (high)";
159 static void initialize_gpio(enum adapter_gpio_config_index idx
)
161 if (!is_gpio_config_valid(&adapter_gpio_config
[idx
]))
164 initial_gpio_mode
[idx
] = get_gpio_mode(&adapter_gpio_config
[idx
]);
165 LOG_DEBUG("saved GPIO mode for %s (GPIO %d %d): %s",
166 adapter_gpio_get_name(idx
), adapter_gpio_config
[idx
].chip_num
, adapter_gpio_config
[idx
].gpio_num
,
167 get_gpio_mode_name(initial_gpio_mode
[idx
]));
169 if (adapter_gpio_config
[idx
].pull
!= ADAPTER_GPIO_PULL_NONE
) {
170 LOG_WARNING("am335xgpio does not support pull-up or pull-down settings (signal %s)",
171 adapter_gpio_get_name(idx
));
174 switch (adapter_gpio_config
[idx
].init_state
) {
175 case ADAPTER_GPIO_INIT_STATE_INACTIVE
:
176 set_gpio_value(&adapter_gpio_config
[idx
], 0);
178 case ADAPTER_GPIO_INIT_STATE_ACTIVE
:
179 set_gpio_value(&adapter_gpio_config
[idx
], 1);
181 case ADAPTER_GPIO_INIT_STATE_INPUT
:
182 AM335XGPIO_SET_INPUT(&adapter_gpio_config
[idx
]);
186 /* Direction for non push-pull is already set by set_gpio_value() */
187 if (adapter_gpio_config
[idx
].drive
== ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL
)
188 AM335XGPIO_SET_OUTPUT(&adapter_gpio_config
[idx
]);
191 static void restore_gpio(enum adapter_gpio_config_index idx
)
193 if (is_gpio_config_valid(&adapter_gpio_config
[idx
])) {
194 switch (initial_gpio_mode
[idx
]) {
195 case AM335XGPIO_GPIO_MODE_INPUT
:
196 AM335XGPIO_SET_INPUT(&adapter_gpio_config
[idx
]);
198 case AM335XGPIO_GPIO_MODE_OUTPUT_LOW
:
199 AM335XGPIO_SET_LOW(&adapter_gpio_config
[idx
]);
200 AM335XGPIO_SET_OUTPUT(&adapter_gpio_config
[idx
]);
202 case AM335XGPIO_GPIO_MODE_OUTPUT_HIGH
:
203 AM335XGPIO_SET_HIGH(&adapter_gpio_config
[idx
]);
204 AM335XGPIO_SET_OUTPUT(&adapter_gpio_config
[idx
]);
210 static bb_value_t
am335xgpio_read(void)
212 return get_gpio_value(&adapter_gpio_config
[ADAPTER_GPIO_IDX_TDO
]) ? BB_HIGH
: BB_LOW
;
215 static int am335xgpio_write(int tck
, int tms
, int tdi
)
217 set_gpio_value(&adapter_gpio_config
[ADAPTER_GPIO_IDX_TDI
], tdi
);
218 set_gpio_value(&adapter_gpio_config
[ADAPTER_GPIO_IDX_TMS
], tms
);
219 set_gpio_value(&adapter_gpio_config
[ADAPTER_GPIO_IDX_TCK
], tck
); /* Write clock last */
221 for (unsigned int i
= 0; i
< jtag_delay
; ++i
)
227 static int am335xgpio_swd_write(int swclk
, int swdio
)
229 set_gpio_value(&adapter_gpio_config
[ADAPTER_GPIO_IDX_SWDIO
], swdio
);
230 set_gpio_value(&adapter_gpio_config
[ADAPTER_GPIO_IDX_SWCLK
], swclk
); /* Write clock last */
232 for (unsigned int i
= 0; i
< jtag_delay
; ++i
)
238 /* (1) assert or (0) deassert reset lines */
239 static int am335xgpio_reset(int trst
, int srst
)
241 /* As the "adapter reset_config" command keeps the srst and trst gpio drive
242 * mode settings in sync we can use our standard set_gpio_value() function
243 * that honours drive mode and active low.
245 if (is_gpio_config_valid(&adapter_gpio_config
[ADAPTER_GPIO_IDX_SRST
]))
246 set_gpio_value(&adapter_gpio_config
[ADAPTER_GPIO_IDX_SRST
], srst
);
248 if (is_gpio_config_valid(&adapter_gpio_config
[ADAPTER_GPIO_IDX_TRST
]))
249 set_gpio_value(&adapter_gpio_config
[ADAPTER_GPIO_IDX_TRST
], trst
);
251 LOG_DEBUG("am335xgpio_reset(%d, %d), trst_gpio: %d %d, srst_gpio: %d %d",
253 adapter_gpio_config
[ADAPTER_GPIO_IDX_TRST
].chip_num
, adapter_gpio_config
[ADAPTER_GPIO_IDX_TRST
].gpio_num
,
254 adapter_gpio_config
[ADAPTER_GPIO_IDX_SRST
].chip_num
, adapter_gpio_config
[ADAPTER_GPIO_IDX_SRST
].gpio_num
);
258 static void am335xgpio_swdio_drive(bool is_output
)
261 if (is_gpio_config_valid(&adapter_gpio_config
[ADAPTER_GPIO_IDX_SWDIO_DIR
]))
262 set_gpio_value(&adapter_gpio_config
[ADAPTER_GPIO_IDX_SWDIO_DIR
], 1);
263 AM335XGPIO_SET_OUTPUT(&adapter_gpio_config
[ADAPTER_GPIO_IDX_SWDIO
]);
265 AM335XGPIO_SET_INPUT(&adapter_gpio_config
[ADAPTER_GPIO_IDX_SWDIO
]);
266 if (is_gpio_config_valid(&adapter_gpio_config
[ADAPTER_GPIO_IDX_SWDIO_DIR
]))
267 set_gpio_value(&adapter_gpio_config
[ADAPTER_GPIO_IDX_SWDIO_DIR
], 0);
271 static int am335xgpio_swdio_read(void)
273 return get_gpio_value(&adapter_gpio_config
[ADAPTER_GPIO_IDX_SWDIO
]);
276 static int am335xgpio_blink(int on
)
278 if (is_gpio_config_valid(&adapter_gpio_config
[ADAPTER_GPIO_IDX_LED
]))
279 set_gpio_value(&adapter_gpio_config
[ADAPTER_GPIO_IDX_LED
], on
);
284 static struct bitbang_interface am335xgpio_bitbang
= {
285 .read
= am335xgpio_read
,
286 .write
= am335xgpio_write
,
287 .swdio_read
= am335xgpio_swdio_read
,
288 .swdio_drive
= am335xgpio_swdio_drive
,
289 .swd_write
= am335xgpio_swd_write
,
290 .blink
= am335xgpio_blink
293 static int am335xgpio_khz(int khz
, int *jtag_speed
)
296 LOG_DEBUG("RCLK not supported");
299 *jtag_speed
= speed_coeff
/ khz
- speed_offset
;
305 static int am335xgpio_speed_div(int speed
, int *khz
)
307 *khz
= speed_coeff
/ (speed
+ speed_offset
);
311 static int am335xgpio_speed(int speed
)
317 COMMAND_HANDLER(am335xgpio_handle_speed_coeffs
)
320 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], speed_coeff
);
321 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[1], speed_offset
);
324 command_print(CMD
, "AM335x GPIO config: speed_coeffs = %d, speed_offset = %d",
325 speed_coeff
, speed_offset
);
329 static const struct command_registration am335xgpio_subcommand_handlers
[] = {
331 .name
= "speed_coeffs",
332 .handler
= am335xgpio_handle_speed_coeffs
,
333 .mode
= COMMAND_CONFIG
,
334 .help
= "SPEED_COEFF and SPEED_OFFSET for delay calculations.",
335 .usage
= "[SPEED_COEFF SPEED_OFFSET]",
337 COMMAND_REGISTRATION_DONE
340 static const struct command_registration am335xgpio_command_handlers
[] = {
342 .name
= "am335xgpio",
344 .help
= "perform am335xgpio management",
345 .chain
= am335xgpio_subcommand_handlers
,
348 COMMAND_REGISTRATION_DONE
351 static const char * const am335xgpio_transports
[] = { "jtag", "swd", NULL
};
353 static struct jtag_interface am335xgpio_interface
= {
354 .supported
= DEBUG_CAP_TMS_SEQ
,
355 .execute_queue
= bitbang_execute_queue
,
358 static bool am335xgpio_jtag_mode_possible(void)
360 if (!is_gpio_config_valid(&adapter_gpio_config
[ADAPTER_GPIO_IDX_TCK
]))
362 if (!is_gpio_config_valid(&adapter_gpio_config
[ADAPTER_GPIO_IDX_TMS
]))
364 if (!is_gpio_config_valid(&adapter_gpio_config
[ADAPTER_GPIO_IDX_TDI
]))
366 if (!is_gpio_config_valid(&adapter_gpio_config
[ADAPTER_GPIO_IDX_TDO
]))
371 static bool am335xgpio_swd_mode_possible(void)
373 if (!is_gpio_config_valid(&adapter_gpio_config
[ADAPTER_GPIO_IDX_SWCLK
]))
375 if (!is_gpio_config_valid(&adapter_gpio_config
[ADAPTER_GPIO_IDX_SWDIO
]))
380 static int am335xgpio_init(void)
382 LOG_INFO("AM335x GPIO JTAG/SWD bitbang driver");
384 bitbang_interface
= &am335xgpio_bitbang
;
385 adapter_gpio_config
= adapter_gpio_get_config();
387 if (transport_is_jtag() && !am335xgpio_jtag_mode_possible()) {
388 LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode");
389 return ERROR_JTAG_INIT_FAILED
;
392 if (transport_is_swd() && !am335xgpio_swd_mode_possible()) {
393 LOG_ERROR("Require swclk and swdio gpio for SWD mode");
394 return ERROR_JTAG_INIT_FAILED
;
397 dev_mem_fd
= open("/dev/gpiomem", O_RDWR
| O_SYNC
);
398 if (dev_mem_fd
< 0) {
399 LOG_DEBUG("Cannot open /dev/gpiomem, fallback to /dev/mem");
400 dev_mem_fd
= open("/dev/mem", O_RDWR
| O_SYNC
);
402 if (dev_mem_fd
< 0) {
403 LOG_ERROR("open: %s", strerror(errno
));
404 return ERROR_JTAG_INIT_FAILED
;
407 for (unsigned int i
= 0; i
< AM335XGPIO_NUM_GPIO_CHIPS
; ++i
) {
408 am335xgpio_gpio_chip_mmap_addr
[i
] = mmap(NULL
, sysconf(_SC_PAGE_SIZE
), PROT_READ
| PROT_WRITE
,
409 MAP_SHARED
, dev_mem_fd
, am335xgpio_gpio_chip_hw_addr
[i
]);
411 if (am335xgpio_gpio_chip_mmap_addr
[i
] == MAP_FAILED
) {
412 LOG_ERROR("mmap: %s", strerror(errno
));
414 return ERROR_JTAG_INIT_FAILED
;
418 /* Configure JTAG/SWD signals. Default directions and initial states are handled
419 * by adapter.c and "adapter gpio" command.
421 if (transport_is_jtag()) {
422 initialize_gpio(ADAPTER_GPIO_IDX_TDO
);
423 initialize_gpio(ADAPTER_GPIO_IDX_TDI
);
424 initialize_gpio(ADAPTER_GPIO_IDX_TMS
);
425 initialize_gpio(ADAPTER_GPIO_IDX_TCK
);
426 initialize_gpio(ADAPTER_GPIO_IDX_TRST
);
429 if (transport_is_swd()) {
430 /* swdio and its buffer should be initialized in the order that prevents
431 * two outputs from being connected together. This will occur if the
432 * swdio GPIO of the AM335x is configured as an output while its
433 * external buffer is configured to send the swdio signal from the
434 * target to the AM335x.
436 if (adapter_gpio_config
[ADAPTER_GPIO_IDX_SWDIO
].init_state
== ADAPTER_GPIO_INIT_STATE_INPUT
) {
437 initialize_gpio(ADAPTER_GPIO_IDX_SWDIO
);
438 initialize_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR
);
440 initialize_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR
);
441 initialize_gpio(ADAPTER_GPIO_IDX_SWDIO
);
444 initialize_gpio(ADAPTER_GPIO_IDX_SWCLK
);
447 initialize_gpio(ADAPTER_GPIO_IDX_SRST
);
448 initialize_gpio(ADAPTER_GPIO_IDX_LED
);
453 static int am335xgpio_quit(void)
455 if (transport_is_jtag()) {
456 restore_gpio(ADAPTER_GPIO_IDX_TDO
);
457 restore_gpio(ADAPTER_GPIO_IDX_TDI
);
458 restore_gpio(ADAPTER_GPIO_IDX_TMS
);
459 restore_gpio(ADAPTER_GPIO_IDX_TCK
);
460 restore_gpio(ADAPTER_GPIO_IDX_TRST
);
463 if (transport_is_swd()) {
464 /* Restore swdio/swdio_dir to their initial modes, even if that means
465 * connecting two outputs. Begin by making swdio an input so that the
466 * current and final states of swdio and swdio_dir do not have to be
467 * considered to calculate the safe restoration order.
469 AM335XGPIO_SET_INPUT(&adapter_gpio_config
[ADAPTER_GPIO_IDX_SWDIO
]);
470 restore_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR
);
471 restore_gpio(ADAPTER_GPIO_IDX_SWDIO
);
473 restore_gpio(ADAPTER_GPIO_IDX_SWCLK
);
476 restore_gpio(ADAPTER_GPIO_IDX_SRST
);
477 restore_gpio(ADAPTER_GPIO_IDX_LED
);
482 struct adapter_driver am335xgpio_adapter_driver
= {
483 .name
= "am335xgpio",
484 .transports
= am335xgpio_transports
,
485 .commands
= am335xgpio_command_handlers
,
487 .init
= am335xgpio_init
,
488 .quit
= am335xgpio_quit
,
489 .reset
= am335xgpio_reset
,
490 .speed
= am335xgpio_speed
,
491 .khz
= am335xgpio_khz
,
492 .speed_div
= am335xgpio_speed_div
,
494 .jtag_ops
= &am335xgpio_interface
,
495 .swd_ops
= &bitbang_swd
,
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)