linuxOS_D21X/source/artinchip/reg-dump/reg_dump.c
2024-11-29 16:33:21 +08:00

176 lines
4.2 KiB
C

/*
* Copyright (C) 2024 Artinchip Technology Co. Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* Author: Artinchip
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/mman.h>
#include <string.h>
#include <dirent.h>
#include <ctype.h>
void usage()
{
fprintf(stderr,
"Usage: reg-dump [[-a addr [value]] | [-m module]] [-c count] [-h]\n\n"
" -a addr dump address\n"
" -m module dump module register\n"
" -c count dump register count, default value is 4\n"
" -h show this help usage\n\n"
"\tFor example:\n"
"\t\tShow register value of specified address:\n"
"\t\t\tregister_dump -a 0x18020000\n"
"\t\tShow 48 register values from the specified address:\n"
"\t\t\tregister_dump -a 0x18020000 -c 48\n"
"\t\tWrite data to specified address:\n"
"\t\t\tregister_dump -a 0x18020000 0x12345678\n"
"\t\tShow module register values:\n"
"\t\t\tregister_dump -m Module_name\n"
"\t\tModule_name can be:\n"
"\t\t\ttwi0, serial0, ethernet0, adcim, cir, rgb, etc\n"
"\t\tModule_name can be found in directory /sys/firmware/devicetree/base/soc/\n\n");
}
int dump_core(unsigned int phy_addr, unsigned int count, unsigned int write_val, int write_flag)
{
void *map_base, *virt_addr;
unsigned int read_result;
unsigned int page_size, mapped_size, offset_in_page;
int fd, i;
fd = open("/dev/mem", O_RDWR);
mapped_size = page_size = getpagesize();
offset_in_page = phy_addr & (page_size - 1);
/* read or write unit is 4 bytes */
if (offset_in_page + 4 > page_size) {
mapped_size *= 2;
}
map_base = mmap(NULL, mapped_size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, phy_addr & ~(page_size - 1));
if (!map_base) {
printf("mmap failed\n");
close(fd);
exit(1);
}
virt_addr = (char *)map_base + offset_in_page;
if (write_flag) {
/* write data to register */
*(unsigned int *)virt_addr = write_val;
} else {
/* Read data from register */
for (i = 0; i < count; i++) {
if ((i % 4) == 0)
printf("\n0x%08x: ", phy_addr);
read_result = *(volatile unsigned int *)virt_addr;
printf("%08x ", read_result);
virt_addr += 4;
phy_addr += 4;
}
printf("\n");
}
munmap(map_base, mapped_size);
close(fd);
return 0;
}
int main(int argc, char *argv[])
{
char *module = NULL;
char *p;
char command[100];
char read_data[9] = {0};
unsigned int count = 4, dump_addr = 0, write_val = 0;
int ret;
int write_flag = 0;
int module_index = 0;
int fd;
char *dts_path = "/sys/firmware/devicetree/base/soc/";
if (argc == 1) {
usage();
exit(1);
}
while ((ret = getopt(argc, argv, "a:c:m:h")) != -1) {
switch (ret) {
case 'a':
dump_addr = strtoul(optarg, &p, 16);
if (argv[optind] && isdigit(argv[optind][0])) {
write_flag = 1;
write_val = strtoul(argv[optind], &p, 16);
}
break;
case 'c':
count = strtoul(optarg, &p, 10);
break;
case 'm':
module = optarg;
break;
default:
usage();
exit(1);
}
}
if (module && dump_addr) {
fprintf(stderr, "option parameter -a and -m could not be specified simultaneously\n");
usage();
exit(1);
}
if (!module && !dump_addr) {
fprintf(stderr, "Error: Both address and module_name are not specified\n");
usage();
exit(1);
}
if (module) {
if (isdigit(module[strlen(module) - 1]) &&
isdigit(module[strlen(module) - 2])) {
/* module name such as twi23 is invalid */
printf("module name is error!!!\n");
exit(1);
} else if (isdigit(module[strlen(module) - 1])) {
/* module name such as twi3, serial2, etc */
module_index = module[strlen(module) - 1] - '0' + 1;
module[strlen(module) - 1] = '\0';
} else {
/* module name such as adcim, rtc, etc */
module_index = 1;
}
sprintf(command, "ls %s | grep ^%s@ | sed -e 's/.*@//; %d!d' > /tmp/.tmp_reg\n", dts_path, module, module_index);
system(command);
fd = open("/tmp/.tmp_reg", O_RDWR);
if (fd == -1) {
printf("register_dump run error!\n");
exit(1);
}
ret = read(fd, (void *)read_data, 8);
if (ret != 8) {
printf("Module not exist!\n");
exit(1);
}
dump_addr = strtoul(read_data, &p, 16);
close(fd);
/* delete .tmp_reg file */
sprintf(command, "rm -f /tmp/.tmp_reg\n");
system(command);
}
return dump_core(dump_addr, count, write_val, write_flag);
}