1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /* Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/ */
7 * This file implements support for the Direct memory access to CoreSight
8 * Access Ports (APs) or emulate the same to access CoreSight debug registers
18 #include <helper/align.h>
19 #include <helper/types.h>
20 #include <helper/system.h>
21 #include <helper/time_support.h>
22 #include <helper/list.h>
23 #include <jtag/interface.h>
25 #include <target/arm_adi_v5.h>
26 #include <transport/transport.h>
28 struct dmem_emu_ap_info
{
30 /* Emulation mode AP state variables */
36 * This bit tells if the transaction is coming in from jtag or not
37 * we just mask this out to emulate direct address access
39 #define ARM_APB_PADDR31 BIT(31)
41 static void *dmem_map_base
, *dmem_virt_base_addr
;
42 static size_t dmem_mapped_size
;
44 /* Default dmem device. */
45 #define DMEM_DEV_PATH_DEFAULT "/dev/mem"
46 static char *dmem_dev_path
;
47 static uint64_t dmem_dap_base_address
;
48 static unsigned int dmem_dap_max_aps
= 1;
49 static uint32_t dmem_dap_ap_offset
= 0x100;
52 static int dmem_dap_retval
= ERROR_OK
;
54 /* AP Emulation Mode */
55 static uint64_t dmem_emu_base_address
;
56 static uint64_t dmem_emu_size
;
57 static void *dmem_emu_map_base
, *dmem_emu_virt_base_addr
;
58 static size_t dmem_emu_mapped_size
;
59 #define DMEM_MAX_EMULATE_APS 5
60 static unsigned int dmem_emu_ap_count
;
61 static struct dmem_emu_ap_info dmem_emu_ap_list
[DMEM_MAX_EMULATE_APS
];
64 * This helper is used to determine the TAR increment size in bytes. The AP's
65 * CSW encoding for SIZE supports byte count decode using "1 << SIZE".
67 static uint32_t dmem_memap_tar_inc(uint32_t csw
)
69 if ((csw
& CSW_ADDRINC_MASK
) != 0)
70 return 1 << (csw
& CSW_SIZE_MASK
);
75 * EMULATION MODE: In Emulation MODE, we assume the following:
76 * TCL still describes as system is operational from the view of AP (ex. jtag)
77 * However, the hardware doesn't permit direct memory access to these APs
78 * (only permitted via JTAG).
80 * So, the access to these APs have to be decoded to a memory map
81 * access which we can directly access.
83 * A few TI processors have this issue.
85 static bool dmem_is_emulated_ap(struct adiv5_ap
*ap
, unsigned int *idx
)
87 for (unsigned int i
= 0; i
< dmem_emu_ap_count
; i
++) {
88 if (ap
->ap_num
== dmem_emu_ap_list
[i
].ap_num
) {
96 static void dmem_emu_set_ap_reg(uint64_t addr
, uint32_t val
)
98 addr
&= ~ARM_APB_PADDR31
;
100 *(volatile uint32_t *)((uintptr_t)dmem_emu_virt_base_addr
+ addr
) = val
;
103 static uint32_t dmem_emu_get_ap_reg(uint64_t addr
)
107 addr
&= ~ARM_APB_PADDR31
;
109 val
= *(volatile uint32_t *)((uintptr_t)dmem_emu_virt_base_addr
+ addr
);
114 static int dmem_emu_ap_q_read(unsigned int ap_idx
, unsigned int reg
, uint32_t *data
)
118 struct dmem_emu_ap_info
*ap_info
= &dmem_emu_ap_list
[ap_idx
];
121 case ADIV5_MEM_AP_REG_CSW
:
122 *data
= ap_info
->apbap_csw
;
124 case ADIV5_MEM_AP_REG_TAR
:
125 *data
= ap_info
->apbap_tar
;
127 case ADIV5_MEM_AP_REG_CFG
:
130 case ADIV5_MEM_AP_REG_BASE
:
133 case ADIV5_AP_REG_IDR
:
136 case ADIV5_MEM_AP_REG_BD0
:
137 case ADIV5_MEM_AP_REG_BD1
:
138 case ADIV5_MEM_AP_REG_BD2
:
139 case ADIV5_MEM_AP_REG_BD3
:
140 addr
= (ap_info
->apbap_tar
& ~0xf) + (reg
& 0x0C);
142 *data
= dmem_emu_get_ap_reg(addr
);
145 case ADIV5_MEM_AP_REG_DRW
:
146 addr
= ap_info
->apbap_tar
;
148 *data
= dmem_emu_get_ap_reg(addr
);
150 ap_info
->apbap_tar
+= dmem_memap_tar_inc(ap_info
->apbap_csw
);
153 LOG_INFO("%s: Unknown reg: 0x%02x", __func__
, reg
);
158 /* Track the last error code. */
160 dmem_dap_retval
= ret
;
165 static int dmem_emu_ap_q_write(unsigned int ap_idx
, unsigned int reg
, uint32_t data
)
169 struct dmem_emu_ap_info
*ap_info
= &dmem_emu_ap_list
[ap_idx
];
172 case ADIV5_MEM_AP_REG_CSW
:
174 * This implementation only supports 32-bit accesses.
175 * Force this by ensuring CSW_SIZE field indicates 32-BIT.
177 ap_info
->apbap_csw
= ((data
& ~CSW_SIZE_MASK
) | CSW_32BIT
);
179 case ADIV5_MEM_AP_REG_TAR
:
181 * This implementation only supports 32-bit accesses.
182 * Force LS 2-bits of TAR to 00b
184 ap_info
->apbap_tar
= (data
& ~0x3);
187 case ADIV5_MEM_AP_REG_CFG
:
188 case ADIV5_MEM_AP_REG_BASE
:
189 case ADIV5_AP_REG_IDR
:
190 /* We don't use this, so we don't need to store */
193 case ADIV5_MEM_AP_REG_BD0
:
194 case ADIV5_MEM_AP_REG_BD1
:
195 case ADIV5_MEM_AP_REG_BD2
:
196 case ADIV5_MEM_AP_REG_BD3
:
197 addr
= (ap_info
->apbap_tar
& ~0xf) + (reg
& 0x0C);
199 dmem_emu_set_ap_reg(addr
, data
);
202 case ADIV5_MEM_AP_REG_DRW
:
203 addr
= ap_info
->apbap_tar
;
204 dmem_emu_set_ap_reg(addr
, data
);
206 ap_info
->apbap_tar
+= dmem_memap_tar_inc(ap_info
->apbap_csw
);
209 LOG_INFO("%s: Unknown reg: 0x%02x", __func__
, reg
);
214 /* Track the last error code. */
216 dmem_dap_retval
= ret
;
222 static uint32_t dmem_get_ap_reg_offset(struct adiv5_ap
*ap
, unsigned int reg
)
224 return (dmem_dap_ap_offset
* ap
->ap_num
) + reg
;
227 static void dmem_set_ap_reg(struct adiv5_ap
*ap
, unsigned int reg
, uint32_t val
)
229 *(volatile uint32_t *)((uintptr_t)dmem_virt_base_addr
+
230 dmem_get_ap_reg_offset(ap
, reg
)) = val
;
233 static uint32_t dmem_get_ap_reg(struct adiv5_ap
*ap
, unsigned int reg
)
235 return *(volatile uint32_t *)((uintptr_t)dmem_virt_base_addr
+
236 dmem_get_ap_reg_offset(ap
, reg
));
239 static int dmem_dp_q_read(struct adiv5_dap
*dap
, unsigned int reg
, uint32_t *data
)
246 *data
= CDBGPWRUPACK
| CSYSPWRUPACK
;
257 static int dmem_dp_q_write(struct adiv5_dap
*dap
, unsigned int reg
, uint32_t data
)
262 static int dmem_ap_q_read(struct adiv5_ap
*ap
, unsigned int reg
, uint32_t *data
)
266 if (is_adiv6(ap
->dap
)) {
267 static bool error_flagged
;
270 LOG_ERROR("ADIv6 dap not supported by dmem dap-direct mode");
272 error_flagged
= true;
277 if (dmem_is_emulated_ap(ap
, &idx
))
278 return dmem_emu_ap_q_read(idx
, reg
, data
);
280 *data
= dmem_get_ap_reg(ap
, reg
);
285 static int dmem_ap_q_write(struct adiv5_ap
*ap
, unsigned int reg
, uint32_t data
)
289 if (is_adiv6(ap
->dap
)) {
290 static bool error_flagged
;
293 LOG_ERROR("ADIv6 dap not supported by dmem dap-direct mode");
295 error_flagged
= true;
300 if (dmem_is_emulated_ap(ap
, &idx
))
301 return dmem_emu_ap_q_write(idx
, reg
, data
);
303 dmem_set_ap_reg(ap
, reg
, data
);
308 static int dmem_ap_q_abort(struct adiv5_dap
*dap
, uint8_t *ack
)
313 static int dmem_dp_run(struct adiv5_dap
*dap
)
315 int retval
= dmem_dap_retval
;
317 /* Clear the error code. */
318 dmem_dap_retval
= ERROR_OK
;
323 static int dmem_connect(struct adiv5_dap
*dap
)
328 COMMAND_HANDLER(dmem_dap_device_command
)
331 return ERROR_COMMAND_SYNTAX_ERROR
;
334 dmem_dev_path
= strdup(CMD_ARGV
[0]);
339 COMMAND_HANDLER(dmem_dap_base_address_command
)
342 return ERROR_COMMAND_SYNTAX_ERROR
;
344 COMMAND_PARSE_NUMBER(u64
, CMD_ARGV
[0], dmem_dap_base_address
);
349 COMMAND_HANDLER(dmem_dap_max_aps_command
)
352 return ERROR_COMMAND_SYNTAX_ERROR
;
354 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], dmem_dap_max_aps
);
359 COMMAND_HANDLER(dmem_dap_ap_offset_command
)
362 return ERROR_COMMAND_SYNTAX_ERROR
;
364 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], dmem_dap_ap_offset
);
369 COMMAND_HANDLER(dmem_emu_base_address_command
)
372 return ERROR_COMMAND_SYNTAX_ERROR
;
374 COMMAND_PARSE_NUMBER(u64
, CMD_ARGV
[0], dmem_emu_base_address
);
375 COMMAND_PARSE_NUMBER(u64
, CMD_ARGV
[1], dmem_emu_size
);
380 COMMAND_HANDLER(dmem_emu_ap_list_command
)
384 if (CMD_ARGC
< 1 || CMD_ARGC
> DMEM_MAX_EMULATE_APS
)
385 return ERROR_COMMAND_SYNTAX_ERROR
;
387 for (unsigned int i
= 0; i
< CMD_ARGC
; i
++) {
388 COMMAND_PARSE_NUMBER(u64
, CMD_ARGV
[i
], em_ap
);
389 dmem_emu_ap_list
[i
].ap_num
= em_ap
;
392 dmem_emu_ap_count
= CMD_ARGC
;
397 COMMAND_HANDLER(dmem_dap_config_info_command
)
400 return ERROR_COMMAND_SYNTAX_ERROR
;
402 command_print(CMD
, "dmem (Direct Memory) AP Adapter Configuration:");
403 command_print(CMD
, " Device : %s",
404 dmem_dev_path
? dmem_dev_path
: DMEM_DEV_PATH_DEFAULT
);
405 command_print(CMD
, " Base Address : 0x%" PRIx64
, dmem_dap_base_address
);
406 command_print(CMD
, " Max APs : %u", dmem_dap_max_aps
);
407 command_print(CMD
, " AP offset : 0x%08" PRIx32
, dmem_dap_ap_offset
);
408 command_print(CMD
, " Emulated AP Count : %u", dmem_emu_ap_count
);
410 if (dmem_emu_ap_count
) {
411 command_print(CMD
, " Emulated AP details:");
412 command_print(CMD
, " Emulated address : 0x%" PRIx64
, dmem_emu_base_address
);
413 command_print(CMD
, " Emulated size : 0x%" PRIx64
, dmem_emu_size
);
414 for (unsigned int i
= 0; i
< dmem_emu_ap_count
; i
++)
415 command_print(CMD
, " Emulated AP [%u] : %" PRIx64
, i
,
416 dmem_emu_ap_list
[i
].ap_num
);
421 static const struct command_registration dmem_dap_subcommand_handlers
[] = {
424 .handler
= dmem_dap_config_info_command
,
426 .help
= "print the config info",
431 .handler
= dmem_dap_device_command
,
432 .mode
= COMMAND_CONFIG
,
433 .help
= "set the dmem memory access device (default: /dev/mem)",
434 .usage
= "device_path",
437 .name
= "base_address",
438 .handler
= dmem_dap_base_address_command
,
439 .mode
= COMMAND_CONFIG
,
440 .help
= "set the dmem dap AP memory map base address",
441 .usage
= "base_address",
444 .name
= "ap_address_offset",
445 .handler
= dmem_dap_ap_offset_command
,
446 .mode
= COMMAND_CONFIG
,
447 .help
= "set the offsets of each ap index",
448 .usage
= "offset_address",
452 .handler
= dmem_dap_max_aps_command
,
453 .mode
= COMMAND_CONFIG
,
454 .help
= "set the maximum number of APs this will support",
458 .name
= "emu_ap_list",
459 .handler
= dmem_emu_ap_list_command
,
460 .mode
= COMMAND_CONFIG
,
461 .help
= "set the list of AP indices to be emulated (upto max)",
465 .name
= "emu_base_address_range",
466 .handler
= dmem_emu_base_address_command
,
467 .mode
= COMMAND_CONFIG
,
468 .help
= "set the base address and size of emulated AP range (all emulated APs access this range)",
469 .usage
= "base_address address_window_size",
471 COMMAND_REGISTRATION_DONE
474 static const struct command_registration dmem_dap_command_handlers
[] = {
478 .help
= "Perform dmem (Direct Memory) DAP management and configuration",
479 .chain
= dmem_dap_subcommand_handlers
,
482 COMMAND_REGISTRATION_DONE
485 static int dmem_dap_init(void)
487 char *path
= dmem_dev_path
? dmem_dev_path
: DMEM_DEV_PATH_DEFAULT
;
488 uint32_t dmem_total_memory_window_size
;
489 long page_size
= sysconf(_SC_PAGESIZE
);
490 size_t dmem_mapped_start
, dmem_mapped_end
;
494 if (!dmem_dap_base_address
) {
495 LOG_ERROR("dmem DAP Base address NOT set? value is 0");
499 dmem_fd
= open(path
, O_RDWR
| O_SYNC
);
501 LOG_ERROR("Unable to open %s", path
);
505 dmem_total_memory_window_size
= (dmem_dap_max_aps
+ 1) * dmem_dap_ap_offset
;
507 dmem_mapped_start
= dmem_dap_base_address
;
508 dmem_mapped_end
= dmem_dap_base_address
+ dmem_total_memory_window_size
;
509 /* mmap() requires page aligned offsets */
510 dmem_mapped_start
= ALIGN_DOWN(dmem_mapped_start
, page_size
);
511 dmem_mapped_end
= ALIGN_UP(dmem_mapped_end
, page_size
);
513 dmem_mapped_size
= dmem_mapped_end
- dmem_mapped_start
;
514 start_delta
= dmem_mapped_start
- dmem_dap_base_address
;
516 dmem_map_base
= mmap(NULL
,
518 (PROT_READ
| PROT_WRITE
),
521 if (dmem_map_base
== MAP_FAILED
) {
522 LOG_ERROR("Mapping address 0x%lx for 0x%lx bytes failed!",
523 dmem_mapped_start
, dmem_mapped_size
);
527 dmem_virt_base_addr
= (void *)((uintptr_t)dmem_map_base
+ start_delta
);
529 /* Lets Map the emulated address if necessary */
530 if (dmem_emu_ap_count
) {
531 dmem_mapped_start
= dmem_emu_base_address
;
532 dmem_mapped_end
= dmem_emu_base_address
+ dmem_emu_size
;
533 /* mmap() requires page aligned offsets */
534 dmem_mapped_start
= ALIGN_DOWN(dmem_mapped_start
, page_size
);
535 dmem_mapped_end
= ALIGN_UP(dmem_mapped_end
, page_size
);
537 dmem_emu_mapped_size
= dmem_mapped_end
- dmem_mapped_start
;
538 start_delta
= dmem_mapped_start
- dmem_emu_base_address
;
540 dmem_emu_map_base
= mmap(NULL
,
541 dmem_emu_mapped_size
,
542 (PROT_READ
| PROT_WRITE
),
545 if (dmem_emu_map_base
== MAP_FAILED
) {
546 LOG_ERROR("Mapping EMU address 0x%lx for 0x%lx bytes failed!",
547 dmem_emu_base_address
, dmem_emu_size
);
550 dmem_emu_virt_base_addr
= (void *)((uintptr_t)dmem_emu_map_base
+
562 static int dmem_dap_quit(void)
564 if (munmap(dmem_map_base
, dmem_mapped_size
) == -1)
565 LOG_ERROR("%s: Failed to unmap mapped memory!", __func__
);
567 if (dmem_emu_ap_count
568 && munmap(dmem_emu_map_base
, dmem_emu_mapped_size
) == -1)
569 LOG_ERROR("%s: Failed to unmap emu mapped memory!", __func__
);
574 static int dmem_dap_reset(int req_trst
, int req_srst
)
579 static int dmem_dap_speed(int speed
)
584 static int dmem_dap_khz(int khz
, int *jtag_speed
)
590 static int dmem_dap_speed_div(int speed
, int *khz
)
596 /* DAP operations. */
597 static const struct dap_ops dmem_dap_ops
= {
598 .connect
= dmem_connect
,
599 .queue_dp_read
= dmem_dp_q_read
,
600 .queue_dp_write
= dmem_dp_q_write
,
601 .queue_ap_read
= dmem_ap_q_read
,
602 .queue_ap_write
= dmem_ap_q_write
,
603 .queue_ap_abort
= dmem_ap_q_abort
,
607 static const char *const dmem_dap_transport
[] = { "dapdirect_swd", NULL
};
609 struct adapter_driver dmem_dap_adapter_driver
= {
611 .transports
= dmem_dap_transport
,
612 .commands
= dmem_dap_command_handlers
,
614 .init
= dmem_dap_init
,
615 .quit
= dmem_dap_quit
,
616 .reset
= dmem_dap_reset
,
617 .speed
= dmem_dap_speed
,
619 .speed_div
= dmem_dap_speed_div
,
621 .dap_swd_ops
= &dmem_dap_ops
,
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)