[][kernel][common][app][Add bit-field read feature to the regs utility]

[Description]
Add bit-field read feature to the regs utility.

Example1: Read value from the specific regsiter
root@OpenWrt:/# regs r 10060018
Value at 0x10060018 (0x7fa1513018): 0x98968
0x10060018: 00098968

Example2: Read specific bit-field from the specific register
root@OpenWrt:/# regs r 10060018 0 20
Value at 0x10060018 (0x7fb7952018): 0x98968
0x10060018[19: 0] = 98968 (hex)
                  = 625000 (dec)
                  = 10011000100101101000 (bin)

[Release-log]
N/A


Change-Id: I4d9b52c2f202c9335e8216bd3de471dbc53a8e33
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7464563
diff --git a/feed/regs/src/regs.c b/feed/regs/src/regs.c
index 09e088c..2e54c1d 100755
--- a/feed/regs/src/regs.c
+++ b/feed/regs/src/regs.c
@@ -46,7 +46,7 @@
 
 void dump_page(uint32_t *vaddr, uint32_t *vbase, uint32_t *pbase)
 {
-	int i =0;
+	int i = 0;
 	uint32_t *end = vaddr + (MAP_SIZE >> 6);
 	uint32_t *start = vaddr;
 
@@ -57,16 +57,17 @@
 	}
 }
 
-void reg_mod_bits(uint32_t *virt_addr, int data, int  start_bit, int data_len)
+void reg_mod_bits(uint32_t *virt_addr, int data, int start_bit, int data_len)
 {
-    int mask=0;
-    int value;
-    int i;
+	int mask = 0;
+	int value;
+	int i;
 
 	if ((start_bit < 0) || (start_bit > 31) ||
 	    (data_len < 1) || (data_len > 32) ||
 	    (start_bit + data_len > 32)) {
-		fprintf(stderr, "Startbit range[0~31], and DataLen range[1~32], and Startbit + DataLen <= 32\n");
+		fprintf(stderr,
+			"Startbit range[0~31], and DataLen range[1~32], and Startbit + DataLen <= 32\n");
 		return;
 	}
 
@@ -86,28 +87,80 @@
 	printf("Modify 0x%X[%d:%d]; ", data, start_bit + data_len - 1, start_bit);
 }
 
+void print_binary(uint32_t data)
+{
+	if (data > 1)
+		print_binary(data >> 1);
+
+	printf("%x", data % 2);
+}
+
+void reg_read_bits(uint32_t *virt_addr, uint32_t *virt_base, uint32_t *phy_base,
+		   int start_bit, int data_len)
+{
+	uint32_t mask = 0;
+	uint32_t value;
+	int i;
+
+	if ((start_bit < 0) || (start_bit > 31) ||
+	    (data_len < 1) || (data_len > 32) ||
+	    (start_bit + data_len > 32)) {
+		fprintf(stderr,
+			"Startbit range[0~31], and DataLen range[1~32], and Startbit + DataLen <= 32\n");
+		return;
+	}
+
+	for (i = 0; i < data_len; i++) {
+		if (start_bit + i > 31)
+			break;
+
+		mask |= 1 << (start_bit + i);
+	}
+
+	value = *((uint32_t *)virt_addr);
+	value &= mask;
+
+	if (start_bit == 0 && data_len == 32)
+		printf("%p: %08x\n",
+		       virt_addr - virt_base + phy_base, value);
+	else {
+		printf("%p[%2d:%2d] = %x (hex)\n",
+		       virt_addr - virt_base + phy_base,
+		       start_bit + data_len - 1, start_bit,
+		       value >> start_bit);
+		printf("%17s = %d (dec)\n", "", value >> start_bit);
+		printf("%17s = ", "");
+		print_binary(value >> start_bit);
+		printf(" (bin)\n");
+	}
+}
+
 void usage(void)
 {
-		fprintf(stderr, "\nUsage:\tregs [Type] [ Offset:Hex ] [ Data:Hex ] [StartBit:Dec] [DataLen:Dec]\n"
-			"\tType    : access operation type : [m]odify, [w]wite, [d]ump\n"
-			"\tOffset  : offset into memory region to act upon\n"
-			"\tData    : data to be written\n"
-			"\tStartbit: Startbit of Addr that want to be modified. Range[0~31]\n"
-			"\tDataLen : Data length of Data. Range[1~32], and Startbit + DataLen <= 32\n\n"
-			"Example:\tRead/Write/Modify register \n"
-			"\tRead    : regs d 0x1b100000           //dump 0x1b100000~0x1b1000f0 \n"
-			"\tWrite   : regs w 0x1b100000 0x1234    //write 0x1b100000=0x1234\n"
-			"\tModify  : regs m 0x1b100000 0x0 29 3  //modify 0x1b100000[29:31]=0\n");
+	fprintf(stderr,
+		"\nUsage:\tregs [Type] [ Offset:Hex ] [ Data:Hex ] [StartBit:Dec] [DataLen:Dec]\n"
+		"\tType    : access operation type : [m]odify, [w]wite, [d]ump\n"
+		"\tOffset  : offset into memory region to act upon\n"
+		"\tData    : data to be written\n"
+		"\tStartbit: Startbit of Addr that want to be modified. Range[0~31]\n"
+		"\tDataLen : Data length of Data. Range[1~32], and Startbit + DataLen <= 32\n\n"
+		"Example:\tRead/Write/Modify register\n"
+		"\tDump    : regs d 0x1b100000           //dump 0x1b100000~0x1b1000f0\n"
+		"\tRead    : regs r 0x1b100000           //read 0x1b100000\n"
+		"\tRead    : regs r 0x1b100000 29 3      //read 0x1b100000[29:31]\n"
+		"\tWrite   : regs w 0x1b100000 0x1234    //write 0x1b100000=0x1234\n"
+		"\tModify  : regs m 0x1b100000 0x0 29 3  //modify 0x1b100000[29:31]=0\n");
 }
 
-int main(int argc, char **argv) {
+int main(int argc, char **argv)
+{
 	int fd;
 	void *map_base = NULL;
-        void *virt_addr = NULL;
+	void *virt_addr = NULL;
 	uint32_t read_result =0;
-        uint32_t writeval = 0;
+	uint32_t writeval = 0;
 	uint32_t startbit = 0;
-       	uint32_t datalen = 0;
+	uint32_t datalen = 0;
 	char *filename = NULL;
 	off_t offset = 0;
 	int access_type = 0;
@@ -151,7 +204,23 @@
 			printf("Written 0x%X; ", writeval);
 			break;
 		case 'd':
-			dump_page(virt_addr, map_base, (uint32_t *)(offset & ~MAP_MASK));
+			dump_page((uint32_t *)virt_addr, (uint32_t *)map_base,
+				  (uint32_t *)(offset & ~MAP_MASK));
+			goto out;
+		case 'r':
+			if (argc == 3)
+				reg_read_bits((uint32_t *)virt_addr,
+					      (uint32_t *)map_base,
+					      (uint32_t *)(offset & ~MAP_MASK),
+					      0, 32);
+			else {
+				startbit = strtoul(argv[3], 0, 10);
+				datalen  = strtoul(argv[4], 0, 10);
+				reg_read_bits((uint32_t *)virt_addr,
+					      (uint32_t *)map_base,
+					      (uint32_t *)(offset & ~MAP_MASK),
+					      startbit, datalen);
+			}
 			goto out;
 		default:
 			fprintf(stderr, "Illegal data type '%c'.\n", access_type);