diff options
Diffstat (limited to 'utils')
28 files changed, 1845 insertions, 0 deletions
diff --git a/utils/rk27utils/README b/utils/rk27utils/README new file mode 100644 index 0000000000..a43d69a88f --- /dev/null +++ b/utils/rk27utils/README | |||
@@ -0,0 +1,37 @@ | |||
1 | This is the collection of small utilities needed to hack Rockchip rk27xx | ||
2 | series based DAPs. This tools were tested on linux only. | ||
3 | |||
4 | |||
5 | rk27load | ||
6 | This directory contains tool which can send arbitrary image(s) to the device | ||
7 | in rockchip recovery mode (VID:PID 0x071B:0x3201). | ||
8 | |||
9 | The first image can not exceed 510 bytes (+2 bytes checksum) and entry | ||
10 | point is 0x18020e00. Usually this code is used to configure SDRAM controller. | ||
11 | One can use first stage image extracted from Rock27Boot.bin file (a bit | ||
12 | more sofisticated) or the one provided in rk27load/stage1 directory. | ||
13 | |||
14 | The second image is loaded at the begining of the dram (0x60000000) | ||
15 | and executed. For some reason (which is still unclear) the size of | ||
16 | 2nd stage image is limited to about 3-4 kB. | ||
17 | |||
18 | You can find example of custom 2nd stage image in rk27load/stage2 directory. | ||
19 | The purpose of this image is to configure bulk transfer and allow to | ||
20 | load usercode without size restriction mentioned above (the max size | ||
21 | is 8MB actually). The entry point of usercode is 0x60000000. | ||
22 | |||
23 | You need libusb 1.0 + header files in order to compile this utility. | ||
24 | You need working arm-eabi crosscompiler in order to compile stage1/stage2 | ||
25 | bootloader binaries (but You should have one already if You tinker whith this) | ||
26 | |||
27 | |||
28 | rkboottool | ||
29 | This directory contains tool which allows to extract (and decrypt) images | ||
30 | stored in Rock27Boot.bin recovery file. | ||
31 | |||
32 | |||
33 | rkusbtool | ||
34 | This directory contains tool which sends custom scsi commands to the | ||
35 | rockchip player. | ||
36 | |||
37 | You need libusb-1.0 + header files in order to compile this utility. | ||
diff --git a/utils/rk27utils/rk27load/Makefile b/utils/rk27utils/rk27load/Makefile new file mode 100644 index 0000000000..f777e76c36 --- /dev/null +++ b/utils/rk27utils/rk27load/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | all: rk27load | ||
2 | |||
3 | rk27load: main.c scramble.c checksum.c common.c stage1_upload.c stage2_upload.c stage3_upload.c | ||
4 | gcc -g -std=c99 -o $@ -W -Wall -lusb-1.0 -I/usr/include/libusb-1.0/ $^ | ||
5 | |||
6 | clean: | ||
7 | rm -fr *.o rk27load | ||
diff --git a/utils/rk27utils/rk27load/checksum.c b/utils/rk27utils/rk27load/checksum.c new file mode 100644 index 0000000000..f0fe59350e --- /dev/null +++ b/utils/rk27utils/rk27load/checksum.c | |||
@@ -0,0 +1,35 @@ | |||
1 | #include <stdint.h> | ||
2 | #include "checksum.h" | ||
3 | |||
4 | uint16_t checksum(void *buff, uint32_t size) | ||
5 | { | ||
6 | uint32_t r2 = 0xffff; | ||
7 | uint32_t r3 = 0; | ||
8 | uint32_t i, j; | ||
9 | |||
10 | for (i=0; i<size; i++) { | ||
11 | r3 = 0x80; | ||
12 | for (j=0; j<8; j++) { | ||
13 | if ((r2 & 0x8000) != 0) { | ||
14 | r2 <<= 17; | ||
15 | r2 >>= 16; | ||
16 | r2 ^= 0x1000; | ||
17 | r2 ^= 0x21; | ||
18 | } | ||
19 | else { | ||
20 | r2 <<= 17; | ||
21 | r2 >>= 16; | ||
22 | } | ||
23 | |||
24 | if ((((uint8_t *)buff)[i] & r3) != 0) { | ||
25 | r2 ^= 0x1000; | ||
26 | r2 ^= 0x21; | ||
27 | } | ||
28 | |||
29 | r3 >>= 1; | ||
30 | } | ||
31 | } | ||
32 | |||
33 | return r2 & 0xffff; | ||
34 | } | ||
35 | |||
diff --git a/utils/rk27utils/rk27load/checksum.h b/utils/rk27utils/rk27load/checksum.h new file mode 100644 index 0000000000..468ca6643e --- /dev/null +++ b/utils/rk27utils/rk27load/checksum.h | |||
@@ -0,0 +1 @@ | |||
uint16_t checksum(void *buff, uint32_t size); | |||
diff --git a/utils/rk27utils/rk27load/common.c b/utils/rk27utils/rk27load/common.c new file mode 100644 index 0000000000..b97cfbcd79 --- /dev/null +++ b/utils/rk27utils/rk27load/common.c | |||
@@ -0,0 +1,16 @@ | |||
1 | #include <stdint.h> | ||
2 | #include <stdio.h> | ||
3 | |||
4 | #include "common.h" | ||
5 | |||
6 | uint32_t filesize(FILE * f) | ||
7 | { | ||
8 | uint32_t filesize; | ||
9 | |||
10 | fseek(f, 0, SEEK_END); | ||
11 | filesize = ftell(f); | ||
12 | fseek(f, 0, SEEK_SET); | ||
13 | |||
14 | return filesize; | ||
15 | } | ||
16 | |||
diff --git a/utils/rk27utils/rk27load/common.h b/utils/rk27utils/rk27load/common.h new file mode 100644 index 0000000000..f22ec7de40 --- /dev/null +++ b/utils/rk27utils/rk27load/common.h | |||
@@ -0,0 +1 @@ | |||
uint32_t filesize(FILE * f); | |||
diff --git a/utils/rk27utils/rk27load/main.c b/utils/rk27utils/rk27load/main.c new file mode 100644 index 0000000000..d183ae2df1 --- /dev/null +++ b/utils/rk27utils/rk27load/main.c | |||
@@ -0,0 +1,165 @@ | |||
1 | #include <stdlib.h> | ||
2 | #include <stdio.h> | ||
3 | #include <string.h> | ||
4 | #include <stdint.h> | ||
5 | #include <stdbool.h> | ||
6 | |||
7 | #include <libusb.h> | ||
8 | |||
9 | #include "rk27load.h" | ||
10 | #include "common.h" | ||
11 | #include "stage1_upload.h" | ||
12 | #include "stage2_upload.h" | ||
13 | #include "stage3_upload.h" | ||
14 | |||
15 | #define VERSION "v0.2" | ||
16 | |||
17 | enum { | ||
18 | NONE = 0, | ||
19 | ENCODE_S1 = 1, | ||
20 | ENCODE_S2 = 2 | ||
21 | }; | ||
22 | |||
23 | static void usage(char *name) | ||
24 | { | ||
25 | printf("usage: (sudo) %s [-e1 -e2] -s1 stage1.bin -s2 stage2.bin -s3 usercode.bin\n", name); | ||
26 | printf("stage1.bin - binary of the stage1 (sdram init)\n"); | ||
27 | printf("stage2.bin - binary of the stage2 bootloader\n"); | ||
28 | printf("usercode.bin - binary of the custom usercode\n"); | ||
29 | printf("\n"); | ||
30 | printf("options:\n"); | ||
31 | printf("-e1 - encode stage1 bootloader\n"); | ||
32 | printf("-e2 - encode stage2 bootloader\n"); | ||
33 | } | ||
34 | |||
35 | int main(int argc, char **argv) | ||
36 | { | ||
37 | libusb_device_handle *hdev; | ||
38 | char *filenames[3]; | ||
39 | int i=1, action=0, ret=0; | ||
40 | |||
41 | while (i < argc) | ||
42 | { | ||
43 | if (strcmp(argv[i],"-e1") == 0) | ||
44 | { | ||
45 | action |= ENCODE_S1; | ||
46 | i++; | ||
47 | } | ||
48 | else if (strcmp(argv[i],"-e2") == 0) | ||
49 | { | ||
50 | action |= ENCODE_S2; | ||
51 | i++; | ||
52 | } | ||
53 | else if (strcmp(argv[i],"-s1") == 0) | ||
54 | { | ||
55 | i++; | ||
56 | if (i == argc) | ||
57 | { | ||
58 | usage(argv[0]); | ||
59 | return -1; | ||
60 | } | ||
61 | filenames[0] = argv[i]; | ||
62 | printf("%s", argv[i]); | ||
63 | i++; | ||
64 | } | ||
65 | else if (strcmp(argv[i],"-s2") == 0) | ||
66 | { | ||
67 | i++; | ||
68 | if (i == argc) | ||
69 | { | ||
70 | usage(argv[0]); | ||
71 | return -2; | ||
72 | } | ||
73 | filenames[1] = argv[i]; | ||
74 | i++; | ||
75 | } | ||
76 | else if (strcmp(argv[i],"-s3") == 0) | ||
77 | { | ||
78 | i++; | ||
79 | if (i == argc) | ||
80 | { | ||
81 | usage(argv[0]); | ||
82 | return -3; | ||
83 | } | ||
84 | filenames[2] = argv[i]; | ||
85 | i++; | ||
86 | } | ||
87 | else | ||
88 | { | ||
89 | usage(argv[0]); | ||
90 | return -4; | ||
91 | } | ||
92 | } | ||
93 | |||
94 | |||
95 | fprintf(stderr,"rk27load " VERSION "\n"); | ||
96 | fprintf(stderr,"(C) Marcin Bukat 2011\n"); | ||
97 | fprintf(stderr,"Based on rk27load ver. 0.1 written by AleMaxx (alemaxx at hotmail.de)\n\n"); | ||
98 | fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n"); | ||
99 | fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"); | ||
100 | |||
101 | /* initialize libusb */ | ||
102 | libusb_init(NULL); | ||
103 | |||
104 | /* configure device */ | ||
105 | fprintf(stderr, "[info]: Initializing device... "); | ||
106 | hdev = libusb_open_device_with_vid_pid(NULL, VENDORID, PRODUCTID); | ||
107 | |||
108 | if (hdev == NULL) | ||
109 | { | ||
110 | fprintf(stderr, "\n[error]: Could not find rockchip device\n"); | ||
111 | ret = -2; | ||
112 | goto finish; | ||
113 | } | ||
114 | |||
115 | ret = libusb_set_configuration(hdev, 1); | ||
116 | if (ret < 0) | ||
117 | { | ||
118 | fprintf(stderr, "\n[error]: Could not select configuration (1)\n"); | ||
119 | ret = -3; | ||
120 | goto finish; | ||
121 | } | ||
122 | |||
123 | ret = libusb_claim_interface(hdev, 0); | ||
124 | if (ret < 0) | ||
125 | { | ||
126 | fprintf(stderr, "\n[error]: Could not claim interface #0\n"); | ||
127 | ret = -4; | ||
128 | goto finish; | ||
129 | } | ||
130 | |||
131 | ret = libusb_set_interface_alt_setting(hdev, 0, 0); | ||
132 | if (ret < 0) | ||
133 | { | ||
134 | fprintf(stderr, "\n[error]: Could not set alternate interface #0\n"); | ||
135 | ret = -5; | ||
136 | goto finish; | ||
137 | } | ||
138 | |||
139 | fprintf(stderr, "done\n"); | ||
140 | |||
141 | |||
142 | ret = upload_stage1_code(hdev, filenames[0], (action & ENCODE_S1)); | ||
143 | if (ret < 0) | ||
144 | goto finish; | ||
145 | |||
146 | ret = upload_stage2_code(hdev, filenames[1], (action & ENCODE_S2)); | ||
147 | if (ret < 0) | ||
148 | goto finish; | ||
149 | |||
150 | ret = upload_stage3_code(hdev, filenames[2]); | ||
151 | if (ret < 0) | ||
152 | goto finish; | ||
153 | |||
154 | /* done */ | ||
155 | ret = 0; | ||
156 | |||
157 | finish: | ||
158 | if (hdev != NULL) | ||
159 | libusb_close(hdev); | ||
160 | |||
161 | if (ret < 0) | ||
162 | fprintf(stderr, "[error]: Error %d\n", ret); | ||
163 | |||
164 | return ret; | ||
165 | } | ||
diff --git a/utils/rk27utils/rk27load/rk27load.h b/utils/rk27utils/rk27load/rk27load.h new file mode 100644 index 0000000000..8239176a0d --- /dev/null +++ b/utils/rk27utils/rk27load/rk27load.h | |||
@@ -0,0 +1,11 @@ | |||
1 | #define USB_TIMEOUT 512 | ||
2 | |||
3 | #define VENDORID 0x71b | ||
4 | #define PRODUCTID 0x3201 | ||
5 | |||
6 | #define USB_EP0 0x41 | ||
7 | |||
8 | #define VCMD_UPLOAD 0x0c | ||
9 | #define VCMD_INDEX_STAGE1 0x471 | ||
10 | #define VCMD_INDEX_STAGE2 0x472 | ||
11 | |||
diff --git a/utils/rk27utils/rk27load/scramble.c b/utils/rk27utils/rk27load/scramble.c new file mode 100644 index 0000000000..7e5b1518d7 --- /dev/null +++ b/utils/rk27utils/rk27load/scramble.c | |||
@@ -0,0 +1,46 @@ | |||
1 | #include <stdint.h> | ||
2 | #include "scramble.h" | ||
3 | |||
4 | void scramble(uint8_t *in, uint8_t *out, const int size) | ||
5 | { | ||
6 | /* table extracted from bootrom */ | ||
7 | static const uint8_t key[] = { | ||
8 | 0x7C, 0x4E, 0x03, 0x04, | ||
9 | 0x55, 0x05, 0x09, 0x07, | ||
10 | 0x2D, 0x2C, 0x7B, 0x38, | ||
11 | 0x17, 0x0D, 0x17, 0x11 | ||
12 | }; | ||
13 | |||
14 | int i, i3, x, val, idx; | ||
15 | |||
16 | uint8_t key1[0x100]; | ||
17 | uint8_t key2[0x100]; | ||
18 | |||
19 | for (i=0; i<0x100; i++) { | ||
20 | key1[i] = i; | ||
21 | key2[i] = key[i&0xf]; | ||
22 | } | ||
23 | |||
24 | i3 = 0; | ||
25 | for (i=0; i<0x100; i++) { | ||
26 | x = key1[i]; | ||
27 | i3 = key1[i] + i3; | ||
28 | i3 += key2[i]; | ||
29 | i3 &= 0xff; | ||
30 | key1[i] = key1[i3]; | ||
31 | key1[i3] = x; | ||
32 | } | ||
33 | |||
34 | idx = 0; | ||
35 | for (i=0; i<size; i++) { | ||
36 | x = key1[(i+1) & 0xff]; | ||
37 | val = x; | ||
38 | idx = (x + idx) & 0xff; | ||
39 | key1[(i+1) & 0xff] = key1[idx]; | ||
40 | key1[idx] = (x & 0xff); | ||
41 | val = (key1[(i+1)&0xff] + x) & 0xff; | ||
42 | val = key1[val]; | ||
43 | out[i] = val ^ in[i]; | ||
44 | } | ||
45 | } | ||
46 | |||
diff --git a/utils/rk27utils/rk27load/scramble.h b/utils/rk27utils/rk27load/scramble.h new file mode 100644 index 0000000000..ed4b291316 --- /dev/null +++ b/utils/rk27utils/rk27load/scramble.h | |||
@@ -0,0 +1 @@ | |||
void scramble(uint8_t *in, uint8_t *out, const int size); | |||
diff --git a/utils/rk27utils/rk27load/stage1/Makefile b/utils/rk27utils/rk27load/stage1/Makefile new file mode 100644 index 0000000000..5291685032 --- /dev/null +++ b/utils/rk27utils/rk27load/stage1/Makefile | |||
@@ -0,0 +1,48 @@ | |||
1 | |||
2 | TARGET = stage1 | ||
3 | |||
4 | TOOLCHAIN = arm-elf-eabi- | ||
5 | |||
6 | CC = $(TOOLCHAIN)gcc | ||
7 | CPP = $(TOOLCHAIN)cpp | ||
8 | LD = $(TOOLCHAIN)gcc | ||
9 | AS = $(TOOLCHAIN)as | ||
10 | OBJCOPY = $(TOOLCHAIN)objcopy | ||
11 | OBJDUMP = $(TOOLCHAIN)objdump | ||
12 | |||
13 | CFLAGS = -Wundef -marm -march=armv5te -nostdlib -mfpu=fpa -O0 -c | ||
14 | #ASFLAGS = -mcpu=arm926ej-s | ||
15 | |||
16 | OBJS = main.o | ||
17 | LDSCRIPT= stage1.lds | ||
18 | |||
19 | #LIBDIRS = -L../arm/lib/gcc/arm-elf/4.1.0/ -L../lib | ||
20 | #LIBS = -lgcc | ||
21 | LIBS = | ||
22 | LDFLAGS = -Wundef -marm -march=armv5te -T$(LDSCRIPT) -nostartfiles \ | ||
23 | -mfpu=fpa -nostdlib -Xlinker -Map=$(TARGET).map | ||
24 | |||
25 | all : $(TARGET).bin | ||
26 | ls -ls $(TARGET).bin | ||
27 | |||
28 | %.o : %.c | ||
29 | $(CC) $(CPPFLAGS) $(CFLAGS) $(INCDIRS) $< -o $@ | ||
30 | |||
31 | %.o : %.S | ||
32 | $(CC) $(CFLAGS) -c $< -o $@ | ||
33 | |||
34 | $(TARGET).elf : $(OBJS) | ||
35 | $(LD) $(LDFLAGS) $(OBJS) $(LIBDIRS) $(LIBS) -o $(TARGET).elf | ||
36 | |||
37 | $(TARGET).bin : $(TARGET).elf | ||
38 | $(OBJCOPY) -O binary $(TARGET).elf $(TARGET).bin | ||
39 | |||
40 | dasm : $(TARGET).bin | ||
41 | $(OBJDUMP) -m arm -D $(TARGET).elf | cat > $(TARGET).asm | ||
42 | |||
43 | clean : | ||
44 | rm -f $(OBJS) | ||
45 | rm -f $(TARGET).elf | ||
46 | rm -f $(TARGET).bin | ||
47 | rm -f $(TARGET).asm | ||
48 | rm -f $(TARGET).map | ||
diff --git a/utils/rk27utils/rk27load/stage1/main.S b/utils/rk27utils/rk27load/stage1/main.S new file mode 100644 index 0000000000..44e7e2f914 --- /dev/null +++ b/utils/rk27utils/rk27load/stage1/main.S | |||
@@ -0,0 +1,42 @@ | |||
1 | .section .text,"ax",%progbits | ||
2 | .global start | ||
3 | |||
4 | start: | ||
5 | msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ/FIQ */ | ||
6 | |||
7 | pll_setup: | ||
8 | mov r0, #0x18000000 | ||
9 | add r0, r0, #0x1c000 | ||
10 | |||
11 | /* setup ARM core freq = 200MHz */ | ||
12 | /* AHB bus freq (HCLK) = 100MHz */ | ||
13 | /* APB bus freq (PCLK) = 50MHz */ | ||
14 | ldr r1, [r0,#0x14] /* SCU_DIVCON1 */ | ||
15 | orr r1, #9 /* ARM slow mode, HCLK:PCLK = 2:1 */ | ||
16 | str r1, [r0,#0x14] | ||
17 | |||
18 | ldr r1,=0x01970c70 /* (1<<24) | (1<<23) | (23<<16) | (199<<4) */ | ||
19 | str r1, [r0,#0x08] | ||
20 | |||
21 | ldr r2,=0x40000 | ||
22 | 1: | ||
23 | ldr r1, [r0,#0x2c] /* SCU_STATUS */ | ||
24 | tst r1, #1 /* ARM pll lock */ | ||
25 | bne 1f | ||
26 | subs r2, #1 | ||
27 | bne 1b | ||
28 | 1: | ||
29 | ldr r1, [r0,#0x14] /* SCU_DIVCON1 */ | ||
30 | bic r1, #5 /* leave ARM slow mode, ARMclk:HCLK = 2:1 */ | ||
31 | str r1, [r0,#0x14] | ||
32 | |||
33 | sdram_config: | ||
34 | add r0, r0, #0x94000 /* SDRAM base */ | ||
35 | |||
36 | mov r1, #1 | ||
37 | str r1, [r0,#0x10c] /* MCSDR_BASIC Round-robin, SDRAM width 16bits */ | ||
38 | |||
39 | add r1, #0x10 | ||
40 | str r1, [r0,#0x108] /* MCSDR_ADDCFG 12 bits row/9 bits col addr */ | ||
41 | |||
42 | mov pc, lr /* we are done, return to bootrom code */ | ||
diff --git a/utils/rk27utils/rk27load/stage1/stage1.lds b/utils/rk27utils/rk27load/stage1/stage1.lds new file mode 100644 index 0000000000..4af8b93c55 --- /dev/null +++ b/utils/rk27utils/rk27load/stage1/stage1.lds | |||
@@ -0,0 +1,23 @@ | |||
1 | ENTRY(start) | ||
2 | OUTPUT_FORMAT(elf32-littlearm) | ||
3 | OUTPUT_ARCH(arm) | ||
4 | /* STARTUP(crt0.o) */ | ||
5 | |||
6 | /* this is where bootrom loads sdram init code */ | ||
7 | MEMORY | ||
8 | { | ||
9 | IRAM : ORIGIN = 0x18200E00, LENGTH = 0x00000200 | ||
10 | } | ||
11 | |||
12 | SECTIONS | ||
13 | { | ||
14 | .text : { | ||
15 | *(.text*) | ||
16 | *(.glue_7*) | ||
17 | } > IRAM | ||
18 | |||
19 | .data : { | ||
20 | *(.rodata*) | ||
21 | *(.data*) | ||
22 | } > IRAM | ||
23 | } | ||
diff --git a/utils/rk27utils/rk27load/stage1_upload.c b/utils/rk27utils/rk27load/stage1_upload.c new file mode 100644 index 0000000000..8eb4ae9e37 --- /dev/null +++ b/utils/rk27utils/rk27load/stage1_upload.c | |||
@@ -0,0 +1,113 @@ | |||
1 | #include <unistd.h> | ||
2 | #include <stdio.h> | ||
3 | #include <stdint.h> | ||
4 | #include <stdbool.h> | ||
5 | #include <stdlib.h> | ||
6 | #include <string.h> | ||
7 | #include <libusb.h> | ||
8 | |||
9 | #include "rk27load.h" | ||
10 | #include "common.h" | ||
11 | #include "scramble.h" | ||
12 | #include "checksum.h" | ||
13 | #include "stage1_upload.h" | ||
14 | |||
15 | /* ### upload sdram init code ### */ | ||
16 | int upload_stage1_code(libusb_device_handle *hdev, char *fn_stage1, | ||
17 | bool do_scramble) | ||
18 | { | ||
19 | FILE *f; | ||
20 | int ret; | ||
21 | uint8_t *code; | ||
22 | uint32_t codesize; | ||
23 | uint16_t cks; | ||
24 | |||
25 | if ((f = fopen(fn_stage1, "rb")) == NULL) | ||
26 | { | ||
27 | fprintf(stderr, "[error]: Could not open file \"%s\"\n", fn_stage1); | ||
28 | return -10; | ||
29 | } | ||
30 | |||
31 | codesize = filesize(f); | ||
32 | |||
33 | if (codesize > 0x1fe) | ||
34 | { | ||
35 | fprintf(stderr, "[error]: Code too big for stage1\n"); | ||
36 | return -11; | ||
37 | } | ||
38 | |||
39 | fprintf(stderr, "[stage1]: Loading %d bytes (%s) of code... ", codesize, fn_stage1); | ||
40 | |||
41 | code = (uint8_t *)malloc(0x200); | ||
42 | if (code == NULL) | ||
43 | { | ||
44 | fprintf(stderr, "\n[error]: Out of memory\n"); | ||
45 | fclose(f); | ||
46 | return -12; | ||
47 | } | ||
48 | |||
49 | memset(code, 0, 0x200); | ||
50 | if (fread(code, 1, codesize, f) != codesize) | ||
51 | { | ||
52 | fprintf(stderr, "\n[error]: I/O error\n"); | ||
53 | fclose(f); | ||
54 | free(code); | ||
55 | return -13; | ||
56 | } | ||
57 | |||
58 | fprintf(stderr, "done\n"); | ||
59 | fclose(f); | ||
60 | |||
61 | /* encode data if requested */ | ||
62 | if (do_scramble) | ||
63 | { | ||
64 | |||
65 | fprintf(stderr, "[stage1]: Encoding %d bytes of data ... ", codesize); | ||
66 | scramble(code, code, codesize); | ||
67 | fprintf(stderr, "done\n"); | ||
68 | } | ||
69 | |||
70 | |||
71 | fprintf(stderr, "[stage1]: codesize = %d (0x%x)\n", codesize, codesize); | ||
72 | |||
73 | fprintf(stderr, "[stage1]: Calculating checksum... "); | ||
74 | cks = checksum((void *)code, codesize); | ||
75 | fprintf(stderr, "0x%04x\n", cks); | ||
76 | code[0x1fe] = (cks >> 8) & 0xff; | ||
77 | code[0x1ff] = cks & 0xff; | ||
78 | codesize += 2; | ||
79 | |||
80 | fprintf(stderr, "[stage1]: Uploading code (%d bytes)... ", codesize); | ||
81 | |||
82 | ret = libusb_control_transfer(hdev, /* device handle */ | ||
83 | USB_EP0, /* bmRequestType */ | ||
84 | VCMD_UPLOAD, /* bRequest */ | ||
85 | 0, /* wValue */ | ||
86 | VCMD_INDEX_STAGE1, /* wIndex */ | ||
87 | code, /* data */ | ||
88 | codesize, /* wLength */ | ||
89 | USB_TIMEOUT /* timeout */ | ||
90 | ); | ||
91 | if (ret < 0) | ||
92 | { | ||
93 | fprintf(stderr, "\n[error]: Code upload request failed (ret=%d)\n", ret); | ||
94 | free(code); | ||
95 | return -14; | ||
96 | } | ||
97 | |||
98 | if (ret != (int)codesize) | ||
99 | { | ||
100 | fprintf(stderr, "\n[error]: Sent %d of %d total\n", ret, codesize); | ||
101 | free(code); | ||
102 | return -15; | ||
103 | } | ||
104 | |||
105 | sleep(1); /* wait for code to finish */ | ||
106 | fprintf(stderr, "done\n"); | ||
107 | |||
108 | /* free code */ | ||
109 | free(code); | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
diff --git a/utils/rk27utils/rk27load/stage1_upload.h b/utils/rk27utils/rk27load/stage1_upload.h new file mode 100644 index 0000000000..efb1c3407e --- /dev/null +++ b/utils/rk27utils/rk27load/stage1_upload.h | |||
@@ -0,0 +1,3 @@ | |||
1 | int upload_stage1_code(libusb_device_handle * hdev, char *fn_stage1, | ||
2 | bool do_scramble); | ||
3 | |||
diff --git a/utils/rk27utils/rk27load/stage2/Makefile b/utils/rk27utils/rk27load/stage2/Makefile new file mode 100644 index 0000000000..4b216db2f3 --- /dev/null +++ b/utils/rk27utils/rk27load/stage2/Makefile | |||
@@ -0,0 +1,48 @@ | |||
1 | |||
2 | TARGET = stage2 | ||
3 | |||
4 | TOOLCHAIN = arm-elf-eabi- | ||
5 | |||
6 | CC = $(TOOLCHAIN)gcc | ||
7 | CPP = $(TOOLCHAIN)cpp | ||
8 | LD = $(TOOLCHAIN)gcc | ||
9 | AS = $(TOOLCHAIN)as | ||
10 | OBJCOPY = $(TOOLCHAIN)objcopy | ||
11 | OBJDUMP = $(TOOLCHAIN)objdump | ||
12 | |||
13 | CFLAGS = -Wundef -marm -march=armv5te -nostdlib -mfpu=fpa -O0 -c | ||
14 | #ASFLAGS = -mcpu=arm926ej-s | ||
15 | |||
16 | OBJS = crt0.o main.o irq.o | ||
17 | LDSCRIPT= stage2.lds | ||
18 | |||
19 | #LIBDIRS = -L../arm/lib/gcc/arm-elf/4.1.0/ -L../lib | ||
20 | #LIBS = -lgcc | ||
21 | LIBS = | ||
22 | LDFLAGS = -Wundef -marm -march=armv5te -T$(LDSCRIPT) -nostartfiles \ | ||
23 | -mfpu=fpa -nostdlib -Xlinker -Map=$(TARGET).map | ||
24 | |||
25 | all : $(TARGET).bin | ||
26 | ls -ls $(TARGET).bin | ||
27 | |||
28 | %.o : %.c | ||
29 | $(CC) $(CPPFLAGS) $(CFLAGS) $(INCDIRS) $< -o $@ | ||
30 | |||
31 | %.o : %.S | ||
32 | $(CC) $(CFLAGS) -c $< -o $@ | ||
33 | |||
34 | $(TARGET).elf : $(OBJS) | ||
35 | $(LD) $(LDFLAGS) $(OBJS) $(LIBDIRS) $(LIBS) -o $(TARGET).elf | ||
36 | |||
37 | $(TARGET).bin : $(TARGET).elf | ||
38 | $(OBJCOPY) -O binary $(TARGET).elf $(TARGET).bin | ||
39 | |||
40 | dasm : $(TARGET).bin | ||
41 | $(OBJDUMP) -m arm -D $(TARGET).elf | cat > $(TARGET).asm | ||
42 | |||
43 | clean : | ||
44 | rm -f $(OBJS) | ||
45 | rm -f $(TARGET).elf | ||
46 | rm -f $(TARGET).bin | ||
47 | rm -f $(TARGET).asm | ||
48 | rm -f $(TARGET).map | ||
diff --git a/utils/rk27utils/rk27load/stage2/crt0.S b/utils/rk27utils/rk27load/stage2/crt0.S new file mode 100644 index 0000000000..c85477546d --- /dev/null +++ b/utils/rk27utils/rk27load/stage2/crt0.S | |||
@@ -0,0 +1,55 @@ | |||
1 | // | ||
2 | // startup code | ||
3 | // | ||
4 | // | ||
5 | |||
6 | #define PSR_MODE 0x0000001f | ||
7 | #define PSR_USR_MODE 0x00000010 | ||
8 | #define PSR_IRQ_MODE 0x00000012 | ||
9 | #define PSR_SVC_MODE 0x00000013 | ||
10 | |||
11 | #define PSR_INT_MASK 0x000000c0 | ||
12 | #define PSR_FIQ_DIS 0x00000040 | ||
13 | #define PSR_IRQ_DIS 0x00000080 | ||
14 | |||
15 | .section .init.text,"ax",%progbits | ||
16 | .global start | ||
17 | .extern _interrupt_disable | ||
18 | |||
19 | // ----------------------------------------------------- | ||
20 | // startup code (setup stacks, branch to main) | ||
21 | // ----------------------------------------------------- | ||
22 | start: | ||
23 | // setup IRQ stack | ||
24 | mov r0, #(PSR_IRQ_MODE|PSR_FIQ_DIS|PSR_IRQ_DIS) | ||
25 | msr cpsr, r0 | ||
26 | ldr sp,=irqstackend | ||
27 | |||
28 | // setup SVC stack | ||
29 | mov r0, #(PSR_SVC_MODE|PSR_FIQ_DIS|PSR_IRQ_DIS) | ||
30 | msr cpsr, r0 | ||
31 | ldr sp,=stackend | ||
32 | |||
33 | // disbale interrupts | ||
34 | mrs r0, cpsr | ||
35 | orr r0, r0, #0xc0 | ||
36 | msr cpsr_c, r0 | ||
37 | |||
38 | // remap | ||
39 | mov r0, #0x18000000 | ||
40 | add r0, r0, #0x1C000 | ||
41 | ldr r1,=0xdeadbeef | ||
42 | str r1, [r0, #4] | ||
43 | |||
44 | // relocate itself | ||
45 | ldr r0,=_relocstart | ||
46 | ldr r1,=_relocend | ||
47 | ldr r2,=0x0 | ||
48 | 1: | ||
49 | cmp r1,r0 | ||
50 | ldrhi r3,[r0],#4 | ||
51 | strhi r3,[r2],#4 | ||
52 | bhi 1b | ||
53 | |||
54 | // continue running in SVC (supervisor mode) | ||
55 | ldr pc,=0x0 | ||
diff --git a/utils/rk27utils/rk27load/stage2/irq.S b/utils/rk27utils/rk27load/stage2/irq.S new file mode 100644 index 0000000000..043bf185a5 --- /dev/null +++ b/utils/rk27utils/rk27load/stage2/irq.S | |||
@@ -0,0 +1,103 @@ | |||
1 | .section .text | ||
2 | .align 4 | ||
3 | |||
4 | .global irq_handler | ||
5 | #define BUFF_ADDR 0x60800000 | ||
6 | |||
7 | irq_handler: | ||
8 | stmfd sp!, {r0-r7, ip, lr} | ||
9 | |||
10 | // get interrupt number | ||
11 | mov r4, #0x18000000 | ||
12 | add r4, r4, #0x80000 | ||
13 | ldr r5, [r4, #0x104] | ||
14 | and r5, r5, #0x1f | ||
15 | cmp r5, #0x10 // UDC interrupt | ||
16 | |||
17 | bleq udc_irq | ||
18 | |||
19 | // clear pending interrupt | ||
20 | mov r3, #1 | ||
21 | mov r2, r3, LSL r5 | ||
22 | str r2, [r4, #0x118] | ||
23 | |||
24 | ldmfd sp!, {r0-r7, ip, lr} | ||
25 | subs pc, lr, #4 | ||
26 | |||
27 | udc_irq: | ||
28 | stmfd sp!, {r4-r8, lr} | ||
29 | |||
30 | // handle usb interrupt | ||
31 | ldr r4,=0x180A0000 | ||
32 | ldr r5, [r4, #0x18] // UDC_INTFLAG | ||
33 | |||
34 | // ep0 in intr | ||
35 | tst r5, #0x04 | ||
36 | beq bulk_recv_intr | ||
37 | |||
38 | // write_reg32(UDC_TX0STAT, read_reg32(UDC_TX0STAT) & ~0x7FF); | ||
39 | ldr r5, [r4, #0x40] | ||
40 | mov r5, r5, lsr #10 | ||
41 | mov r5, r5, lsl #10 // clear clower 10 bits | ||
42 | str r5, [r4, #0x40] | ||
43 | |||
44 | // write_reg32(UDC_DMA0LM_OADDR, (uint32_t)(state.ctrlep_data)); | ||
45 | mov r5, #0x60000000 | ||
46 | str r5, [r4, #0x3c] | ||
47 | |||
48 | // write_reg32(UDC_DMA0CTLO, read_reg32(UDC_DMA0CTLO) | ENP_DMA_START); | ||
49 | mov r5, #1 | ||
50 | str r5, [r4, #0x38] | ||
51 | |||
52 | ldmfd sp!, {r4-r8, pc} | ||
53 | |||
54 | // bulk out interrupt | ||
55 | bulk_recv_intr: | ||
56 | tst r5, #0x100 | ||
57 | ldmeqfd sp!, {r4-r8, pc} | ||
58 | |||
59 | // read UDC_RX1STAT | ||
60 | ldr r5, [r4, #0x54] | ||
61 | mov r5, r5, lsl #21 | ||
62 | mov r5, r5, lsr #21 // r5 = length | ||
63 | |||
64 | ldr r6,=usb_sz | ||
65 | ldr r6, [r6] | ||
66 | ldr r7, [r6] // r7 = total_code_length expected | ||
67 | |||
68 | subs r7, r7, r5 | ||
69 | bne usb_bulk_out1_recv | ||
70 | |||
71 | // copy from buff to the begining of the ram | ||
72 | ldr r0,=BUFF_ADDR | ||
73 | ldr r1,[r0,#-4] // size | ||
74 | |||
75 | ldr r1,=0x800000 // buffer size | ||
76 | |||
77 | add r1,r1,r0 // end address | ||
78 | ldr r2,=0x60000000 // destination | ||
79 | 1: | ||
80 | cmp r1,r0 | ||
81 | ldrhi r3,[r0],#4 | ||
82 | strhi r3,[r2],#4 | ||
83 | bhi 1b | ||
84 | |||
85 | // execute user code | ||
86 | ldr r0,=0x60000000 | ||
87 | bx r0 // jump to 0x60000000 | ||
88 | |||
89 | usb_bulk_out1_recv: | ||
90 | str r7, [r6] // size = size - received | ||
91 | |||
92 | ldr r6,=usb_write_addr | ||
93 | ldr r7, [r6] | ||
94 | |||
95 | add r7, r7, r5 | ||
96 | str r7, [r6] // usb_write_addr += length | ||
97 | |||
98 | str r7, [r4, #0x60] // DMA1LM_OADDR = usb_write_addr | ||
99 | |||
100 | mov r5, #1 | ||
101 | str r5, [r4, #0x5c] // DMA1_CTL0 = ENP_DMA_START | ||
102 | |||
103 | ldmfd sp!, {r4-r8, pc} | ||
diff --git a/utils/rk27utils/rk27load/stage2/main.S b/utils/rk27utils/rk27load/stage2/main.S new file mode 100644 index 0000000000..c8474b0579 --- /dev/null +++ b/utils/rk27utils/rk27load/stage2/main.S | |||
@@ -0,0 +1,89 @@ | |||
1 | |||
2 | .section .text | ||
3 | .align 4 | ||
4 | |||
5 | .arm | ||
6 | |||
7 | .global main | ||
8 | .global _interrupt_disable | ||
9 | .global _interrupt_enable | ||
10 | |||
11 | .global usb_write_addr | ||
12 | .global usb_sz | ||
13 | |||
14 | #define BUFF_ADDR 0x60800000 | ||
15 | |||
16 | // ----------------------------------------------------- | ||
17 | // vector table | ||
18 | // ----------------------------------------------------- | ||
19 | ldr pc, =main | ||
20 | ldr pc, =main | ||
21 | ldr pc, =main | ||
22 | ldr pc, =main | ||
23 | ldr pc, =main | ||
24 | ldr pc, =main | ||
25 | ldr pc, =irq_handler | ||
26 | ldr pc, =main | ||
27 | |||
28 | // ----------------------------------------------------- | ||
29 | // main | ||
30 | // ----------------------------------------------------- | ||
31 | main: | ||
32 | // turn on usb interrupts | ||
33 | mov r0, #0x18000000 | ||
34 | add r0, r0, #0x80000 | ||
35 | ldr r1, [r0, #0x10c] | ||
36 | orr r1, r1, #0x10000 | ||
37 | str r1, [r0, #0x10c] | ||
38 | |||
39 | // enable usb-bulk | ||
40 | add r0, r0, #0x20000 // R0 = 0x180A0000 (UDC_BASE) | ||
41 | |||
42 | // enable EP1, write_reg32(UDC_RX1CON, (0x1 << 8) | RxACKINTEN | RxEPEN); | ||
43 | mov r1, #0x190 // bits 8,7,4 -> 0x190 | ||
44 | str r1, [r0, #0x58] | ||
45 | |||
46 | // setup receive buffer (must be aligned on dword boundary) | ||
47 | ldr r1,=usb_write_addr // write_reg32(UDC_DMA1LM_OADDR, (uint32_t)rx_buff); | ||
48 | ldr r1, [r1] | ||
49 | str r1, [r0, #0x60] // UDC_DMA1LM_OADDR = usb_write_addr | ||
50 | |||
51 | // write_reg32(UDC_DMA1CTRLO, read_reg32(UDC_DMA1CTRLO) | ENP_DMA_START); | ||
52 | ldr r1, [r0, #0x5c] | ||
53 | orr r1, r1, #2 | ||
54 | str r1, [r0, #0x5c] | ||
55 | |||
56 | // enable bulk_out1 interrupt | ||
57 | ldr r1, [r0, #0x14] // UDC_ENINT | ||
58 | orr r1, r1, #0x100 // EN_BOUT1_INTR | ||
59 | str r1, [r0, #0x14] | ||
60 | |||
61 | bl _interrupt_enable | ||
62 | idle: | ||
63 | b idle | ||
64 | |||
65 | // ----------------------------------------------------- | ||
66 | // _interrupt_enable - enables interrupts | ||
67 | // ----------------------------------------------------- | ||
68 | _interrupt_enable: | ||
69 | mrs r0, cpsr | ||
70 | bic r0, r0, #0x80 | ||
71 | msr cpsr_c, r0 | ||
72 | mov pc, lr | ||
73 | |||
74 | // ----------------------------------------------------- | ||
75 | // _interrupt_disable - disables interrupts | ||
76 | // ----------------------------------------------------- | ||
77 | _interrupt_disable: | ||
78 | mrs r0, cpsr | ||
79 | orr r0, r0, #0xc0 | ||
80 | msr cpsr_c, r0 | ||
81 | mov pc, lr | ||
82 | |||
83 | |||
84 | .section .data | ||
85 | usb_write_addr: | ||
86 | .word (BUFF_ADDR-4) | ||
87 | |||
88 | usb_sz: | ||
89 | .word (BUFF_ADDR-4) | ||
diff --git a/utils/rk27utils/rk27load/stage2/stage2.lds b/utils/rk27utils/rk27load/stage2/stage2.lds new file mode 100644 index 0000000000..2c07b201f7 --- /dev/null +++ b/utils/rk27utils/rk27load/stage2/stage2.lds | |||
@@ -0,0 +1,40 @@ | |||
1 | ENTRY(start) | ||
2 | OUTPUT_FORMAT(elf32-littlearm) | ||
3 | OUTPUT_ARCH(arm) | ||
4 | /* STARTUP(crt0.o) */ | ||
5 | |||
6 | MEMORY | ||
7 | { | ||
8 | DRAM : ORIGIN = 0x60000000, LENGTH = 0x01000000 | ||
9 | IRAM : ORIGIN = 0x00000000, LENGTH = 0x00002000 | ||
10 | } | ||
11 | |||
12 | SECTIONS | ||
13 | { | ||
14 | .init.text : { | ||
15 | *(.init.text) | ||
16 | } > DRAM | ||
17 | |||
18 | .text : { | ||
19 | *(.text*) | ||
20 | *(.glue_7*) | ||
21 | } > IRAM AT > DRAM | ||
22 | |||
23 | .data : { | ||
24 | *(.data*) | ||
25 | } > IRAM AT > DRAM | ||
26 | |||
27 | _relocstart = LOADADDR(.text); | ||
28 | _relocend = LOADADDR(.data) + SIZEOF(.data); | ||
29 | |||
30 | .stack (NOLOAD) : { | ||
31 | . = ALIGN(0x100); | ||
32 | *(.stack) | ||
33 | stackbegin = .; | ||
34 | . += 0x200; | ||
35 | stackend = .; | ||
36 | irqstackbegin = .; | ||
37 | . += 0x200; | ||
38 | irqstackend = .; | ||
39 | } > IRAM | ||
40 | } | ||
diff --git a/utils/rk27utils/rk27load/stage2_upload.c b/utils/rk27utils/rk27load/stage2_upload.c new file mode 100644 index 0000000000..820ad4463c --- /dev/null +++ b/utils/rk27utils/rk27load/stage2_upload.c | |||
@@ -0,0 +1,102 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <stdint.h> | ||
3 | #include <stdbool.h> | ||
4 | #include <stdlib.h> | ||
5 | #include <string.h> | ||
6 | #include <libusb.h> | ||
7 | |||
8 | #include "rk27load.h" | ||
9 | #include "common.h" | ||
10 | #include "scramble.h" | ||
11 | #include "checksum.h" | ||
12 | #include "stage2_upload.h" | ||
13 | |||
14 | int upload_stage2_code(libusb_device_handle *hdev, char *fn_stage2, | ||
15 | bool do_scramble) | ||
16 | { | ||
17 | FILE *f; | ||
18 | uint32_t codesize; | ||
19 | uint8_t *code; | ||
20 | uint16_t cks; | ||
21 | int ret; | ||
22 | |||
23 | if ((f = fopen(fn_stage2, "rb")) == NULL) | ||
24 | { | ||
25 | fprintf(stderr, "[error]: Could not open file \"%s\"\n", fn_stage2); | ||
26 | return -21; | ||
27 | } | ||
28 | |||
29 | codesize = filesize(f); | ||
30 | |||
31 | fprintf(stderr, "[stage1]: Loading %d bytes (%s) of code... ", codesize, fn_stage2); | ||
32 | |||
33 | code = (uint8_t *) malloc(codesize + 0x400); | ||
34 | if (code == NULL) | ||
35 | { | ||
36 | fprintf(stderr, "\n[error]: Out of memory\n"); | ||
37 | fclose(f); | ||
38 | return -22; | ||
39 | |||
40 | } | ||
41 | |||
42 | memset(code, 0, codesize + 0x400); | ||
43 | |||
44 | if (fread(code, 1, codesize, f) != codesize) | ||
45 | { | ||
46 | fprintf(stderr, "\n[error]: I/O error\n"); | ||
47 | fclose(f); | ||
48 | free(code); | ||
49 | return -23; | ||
50 | } | ||
51 | fprintf(stderr, "done\n"); | ||
52 | fclose(f); | ||
53 | |||
54 | codesize = ((codesize + 0x201) & 0xfffffe00) - 2; | ||
55 | |||
56 | if (do_scramble) | ||
57 | { | ||
58 | /* encode data if its user code */ | ||
59 | fprintf(stderr, "[stage2]: Encoding %d bytes data... ", codesize); | ||
60 | scramble(code, code, codesize); | ||
61 | fprintf(stderr, "done\n"); | ||
62 | } | ||
63 | |||
64 | fprintf(stderr, "[stage2]: Calculating checksum... "); | ||
65 | cks = checksum(code, codesize); | ||
66 | code[codesize + 0] = (cks >> 8) & 0xff; | ||
67 | code[codesize + 1] = cks & 0xff; | ||
68 | codesize += 2; | ||
69 | fprintf(stderr, "0x%04x\n", cks); | ||
70 | |||
71 | fprintf(stderr, "[stage2]: Uploading code (%d bytes)... ", codesize); | ||
72 | |||
73 | ret = libusb_control_transfer(hdev, /* device handle */ | ||
74 | USB_EP0, /* bmRequestType */ | ||
75 | VCMD_UPLOAD, /* bRequest */ | ||
76 | 0, /* wValue */ | ||
77 | VCMD_INDEX_STAGE2, /* wIndex */ | ||
78 | code, /* data */ | ||
79 | codesize, /* wLength */ | ||
80 | USB_TIMEOUT /* timeout */ | ||
81 | ); | ||
82 | |||
83 | if (ret < 0) | ||
84 | { | ||
85 | fprintf(stderr, "\n[error]: Code upload request failed (ret=%d)\n", ret); | ||
86 | free(code); | ||
87 | return -24; | ||
88 | } | ||
89 | |||
90 | if (ret != (int)codesize) | ||
91 | { | ||
92 | fprintf(stderr, "[error]: Sent %d of %d total\n", ret, codesize); | ||
93 | free(code); | ||
94 | return -25; | ||
95 | } | ||
96 | |||
97 | fprintf(stderr, "done\n"); | ||
98 | |||
99 | free(code); | ||
100 | return 0; | ||
101 | } | ||
102 | |||
diff --git a/utils/rk27utils/rk27load/stage2_upload.h b/utils/rk27utils/rk27load/stage2_upload.h new file mode 100644 index 0000000000..852d17adb2 --- /dev/null +++ b/utils/rk27utils/rk27load/stage2_upload.h | |||
@@ -0,0 +1,3 @@ | |||
1 | int upload_stage2_code(libusb_device_handle * hdev, char *fn_stage2, | ||
2 | bool do_scramble); | ||
3 | |||
diff --git a/utils/rk27utils/rk27load/stage3_upload.c b/utils/rk27utils/rk27load/stage3_upload.c new file mode 100644 index 0000000000..6f10a7c995 --- /dev/null +++ b/utils/rk27utils/rk27load/stage3_upload.c | |||
@@ -0,0 +1,93 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <stdint.h> | ||
3 | #include <stdlib.h> | ||
4 | #include <string.h> | ||
5 | #include <libusb.h> | ||
6 | |||
7 | #include "rk27load.h" | ||
8 | #include "common.h" | ||
9 | #include "scramble.h" | ||
10 | #include "checksum.h" | ||
11 | #include "stage3_upload.h" | ||
12 | |||
13 | int upload_stage3_code(libusb_device_handle *hdev, char *fn_stage3) | ||
14 | { | ||
15 | FILE *f; | ||
16 | uint32_t codesize; | ||
17 | uint32_t remain; | ||
18 | uint8_t *code; | ||
19 | uint16_t send_size = 0x200; | ||
20 | uint32_t i = 0; | ||
21 | int ret, transfered; | ||
22 | |||
23 | if ((f = fopen(fn_stage3, "rb")) == NULL) | ||
24 | { | ||
25 | fprintf(stderr, "[error]: Could not open file \"%s\"\n", fn_stage3); | ||
26 | return -31; | ||
27 | } | ||
28 | |||
29 | codesize = filesize(f); | ||
30 | |||
31 | fprintf(stderr, "[stage3]: Loading user code (%d bytes)... ", codesize); | ||
32 | |||
33 | /* allocate buffer */ | ||
34 | code = (uint8_t *) malloc(codesize + 0x204); | ||
35 | if (code == NULL) | ||
36 | { | ||
37 | fprintf(stderr, "\n[error]: Out of memory\n"); | ||
38 | fclose(f); | ||
39 | return -32; | ||
40 | } | ||
41 | |||
42 | memset(code, 0, codesize + 0x204); | ||
43 | /* read usercode into buffer */ | ||
44 | if (fread(&code[4], 1, codesize, f) != codesize) | ||
45 | { | ||
46 | fprintf(stderr, "\n[error]: I/O error\n"); | ||
47 | fclose(f); | ||
48 | free(f); | ||
49 | return -33; | ||
50 | } | ||
51 | fprintf(stderr, "done\n"); | ||
52 | |||
53 | fclose(f); | ||
54 | |||
55 | /* put code size at the first 4 bytes */ | ||
56 | codesize += 4; | ||
57 | code[0] = codesize & 0xff; | ||
58 | code[1] = (codesize >> 8) & 0xff; | ||
59 | code[2] = (codesize >> 16) & 0xff; | ||
60 | code[3] = (codesize >> 24) & 0xff; | ||
61 | |||
62 | fprintf(stderr, "[stage3]: Uploading user code (%d bytes)... ", codesize); | ||
63 | |||
64 | remain = codesize; | ||
65 | |||
66 | while (remain > 0) | ||
67 | { | ||
68 | if (remain < 0x200) | ||
69 | send_size = remain; | ||
70 | |||
71 | ret = libusb_bulk_transfer(hdev, /* handle */ | ||
72 | 1, /* EP */ | ||
73 | &code[i * 0x200], /* data */ | ||
74 | send_size, /* length */ | ||
75 | &transfered, /* xfered */ | ||
76 | USB_TIMEOUT /* timeout */ | ||
77 | ); | ||
78 | |||
79 | if (ret != LIBUSB_SUCCESS) | ||
80 | { | ||
81 | fprintf(stderr, "\n[error]: Bulk transfer error (%d, %d)\n", ret, i); | ||
82 | free(code); | ||
83 | return -34; | ||
84 | } | ||
85 | |||
86 | remain -= send_size; | ||
87 | i++; | ||
88 | } | ||
89 | |||
90 | fprintf(stderr,"done (sent %d blocks)\n", i); | ||
91 | return 0; | ||
92 | } | ||
93 | |||
diff --git a/utils/rk27utils/rk27load/stage3_upload.h b/utils/rk27utils/rk27load/stage3_upload.h new file mode 100644 index 0000000000..03f9f0e46a --- /dev/null +++ b/utils/rk27utils/rk27load/stage3_upload.h | |||
@@ -0,0 +1 @@ | |||
int upload_stage3_code(libusb_device_handle *hdev, char *fn_stage3); | |||
diff --git a/utils/rk27utils/rkboottool/Makefile b/utils/rk27utils/rkboottool/Makefile new file mode 100644 index 0000000000..895dfc87cc --- /dev/null +++ b/utils/rk27utils/rkboottool/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | all: rkboottool | ||
2 | |||
3 | rkboottool: rkboottool.c | ||
4 | gcc -g -std=c99 -o $@ -W -Wall $^ | ||
5 | |||
6 | clean: | ||
7 | rm -fr rkboottool | ||
diff --git a/utils/rk27utils/rkboottool/rkboottool.c b/utils/rk27utils/rkboottool/rkboottool.c new file mode 100644 index 0000000000..ad08b0b5f6 --- /dev/null +++ b/utils/rk27utils/rkboottool/rkboottool.c | |||
@@ -0,0 +1,360 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <stdint.h> | ||
3 | #include <stdbool.h> | ||
4 | #include <stdlib.h> | ||
5 | #include <string.h> | ||
6 | |||
7 | #define VERSION "v0.3" | ||
8 | |||
9 | /* time field stucture */ | ||
10 | struct rktime_t | ||
11 | { | ||
12 | uint16_t year; | ||
13 | uint16_t month; | ||
14 | uint16_t day; | ||
15 | uint16_t hour; | ||
16 | uint16_t minute; | ||
17 | uint16_t second; | ||
18 | }; | ||
19 | |||
20 | /* Rock27Boot.bin header structure */ | ||
21 | struct rkboot_info_t | ||
22 | { | ||
23 | char sign[32]; | ||
24 | uint8_t check_values[16]; | ||
25 | struct rktime_t time; | ||
26 | uint32_t ui_master_version; | ||
27 | uint32_t ui_slave_version; | ||
28 | uint32_t s1_offset; | ||
29 | int32_t s1_len; | ||
30 | uint32_t s2_offset; | ||
31 | int32_t s2_len; | ||
32 | uint32_t s3_offset; | ||
33 | int32_t s3_len; | ||
34 | uint32_t s4_offset; | ||
35 | int32_t s4_len; | ||
36 | uint32_t version_flag; | ||
37 | }; | ||
38 | |||
39 | /* actions */ | ||
40 | enum { | ||
41 | NONE = 0, | ||
42 | INFO = 1, | ||
43 | EXTRACT = 2, | ||
44 | SCRAMBLE = 4 | ||
45 | }; | ||
46 | |||
47 | /* scramble mode */ | ||
48 | enum { | ||
49 | CONTINOUS_ENC, /* scramble whole block at once */ | ||
50 | PAGE_ENC /* nand bootloader is scrambled in 0x200 chunks */ | ||
51 | }; | ||
52 | |||
53 | /* scrambling/descrambling reverse engineered by AleMaxx */ | ||
54 | static void encode_page(uint8_t *inpg, uint8_t *outpg, const int size) | ||
55 | { | ||
56 | |||
57 | uint8_t key[] = { | ||
58 | 0x7C, 0x4E, 0x03, 0x04, | ||
59 | 0x55, 0x05, 0x09, 0x07, | ||
60 | 0x2D, 0x2C, 0x7B, 0x38, | ||
61 | 0x17, 0x0D, 0x17, 0x11 | ||
62 | }; | ||
63 | int i, i3, x, val, idx; | ||
64 | |||
65 | uint8_t key1[0x100]; | ||
66 | uint8_t key2[0x100]; | ||
67 | |||
68 | for (i=0; i<0x100; i++) { | ||
69 | key1[i] = i; | ||
70 | key2[i] = key[i&0xf]; | ||
71 | } | ||
72 | |||
73 | i3 = 0; | ||
74 | for (i=0; i<0x100; i++) { | ||
75 | x = key1[i]; | ||
76 | i3 = key1[i] + i3; | ||
77 | i3 += key2[i]; | ||
78 | i3 &= 0xff; | ||
79 | key1[i] = key1[i3]; | ||
80 | key1[i3] = x; | ||
81 | } | ||
82 | |||
83 | idx = 0; | ||
84 | for (i=0; i<size; i++) { | ||
85 | x = key1[(i+1) & 0xff]; | ||
86 | val = x; | ||
87 | idx = (x + idx) & 0xff; | ||
88 | key1[(i+1) & 0xff] = key1[idx]; | ||
89 | key1[idx] = (x & 0xff); | ||
90 | val = (key1[(i+1)&0xff] + x) & 0xff; | ||
91 | val = key1[val]; | ||
92 | outpg[i] = val ^ inpg[i]; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | static void *binary_extract(FILE *fp, uint32_t offset, uint32_t len, int descramble, int encode_mode) | ||
97 | { | ||
98 | void *buff, *buff_ptr; | ||
99 | uint32_t ret; | ||
100 | |||
101 | if ((fp == NULL) || len == 0) | ||
102 | return NULL; | ||
103 | |||
104 | /* allocate buff */ | ||
105 | if ((buff = malloc(len)) == NULL) | ||
106 | return NULL; | ||
107 | |||
108 | /* seek to the begining of the data */ | ||
109 | fseek(fp, offset, SEEK_SET); | ||
110 | |||
111 | /* read into the buffer */ | ||
112 | ret = fread(buff, 1, len, fp); | ||
113 | |||
114 | if (ret != len) | ||
115 | { | ||
116 | free(buff); | ||
117 | return NULL; | ||
118 | } | ||
119 | |||
120 | /* descramble */ | ||
121 | if ( descramble ) | ||
122 | { | ||
123 | buff_ptr = buff; | ||
124 | if (encode_mode == PAGE_ENC) | ||
125 | { | ||
126 | while (len >= 0x200) | ||
127 | { | ||
128 | encode_page((uint8_t *)buff_ptr, | ||
129 | (uint8_t *)buff_ptr, | ||
130 | 0x200); | ||
131 | |||
132 | buff_ptr += 0x200; | ||
133 | len -= 0x200; | ||
134 | } | ||
135 | } | ||
136 | encode_page((uint8_t *)buff_ptr, (uint8_t *)buff_ptr, len); | ||
137 | } | ||
138 | |||
139 | return buff; | ||
140 | } | ||
141 | |||
142 | static void usage(void) | ||
143 | { | ||
144 | printf("Usage: rkboottool [options] Rock27Boot.bin\n"); | ||
145 | printf("-h|--help This help message\n"); | ||
146 | printf("-e|--extract Extract binary images from Rock27Boot.bin file\n"); | ||
147 | printf("-d|--descramble Descramble extracted binary images\n"); | ||
148 | printf("-i|--info Print info about Rock27Boot.bin file\n"); | ||
149 | printf("\n"); | ||
150 | printf("Usually you would like to use -d -e together to obtain raw binary\n"); | ||
151 | printf("(out files rkboot_s1.bin, rkboot_s2.bin, rkboot_s3.bin, rkboot_s4.bin)\n"); | ||
152 | } | ||
153 | |||
154 | int main (int argc, char **argv) | ||
155 | { | ||
156 | struct rkboot_info_t rkboot_info; | ||
157 | FILE *fp_in, *fp_out; | ||
158 | int32_t i = 0, action = NONE; | ||
159 | int32_t ret; | ||
160 | void *buff; | ||
161 | char *in_filename = NULL; | ||
162 | |||
163 | if ( argc < 2 ) | ||
164 | { | ||
165 | usage(); | ||
166 | return -1; | ||
167 | } | ||
168 | |||
169 | /* print banner */ | ||
170 | fprintf(stderr,"rkboottool " VERSION "\n"); | ||
171 | fprintf(stderr,"(C) Marcin Bukat 2011\n"); | ||
172 | fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n"); | ||
173 | fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"); | ||
174 | |||
175 | /* arguments handling */ | ||
176 | while (i < argc) | ||
177 | { | ||
178 | if ((strcmp(argv[i],"-i")==0) || (strcmp(argv[i],"--info")==0)) | ||
179 | { | ||
180 | action |= INFO; | ||
181 | } | ||
182 | else if ((strcmp(argv[i],"-e")==0) || (strcmp(argv[i],"--extract")==0)) | ||
183 | { | ||
184 | action |= EXTRACT; | ||
185 | } | ||
186 | else if ((strcmp(argv[i],"-d")==0) || (strcmp(argv[i],"--descramble")==0)) | ||
187 | { | ||
188 | action |= SCRAMBLE; | ||
189 | } | ||
190 | else if ((strcmp(argv[i],"-h")==0) || (strcmp(argv[i],"--help")==0)) | ||
191 | { | ||
192 | usage(); | ||
193 | return 0; | ||
194 | } | ||
195 | else if ( argv[i][0] != '-' ) | ||
196 | { | ||
197 | /* file argument */ | ||
198 | in_filename = argv[i]; | ||
199 | } | ||
200 | i++; | ||
201 | } | ||
202 | |||
203 | if ( (fp_in = fopen(in_filename, "rb")) == NULL ) | ||
204 | { | ||
205 | fprintf(stderr, "error: can't open %s file for reading\n", in_filename); | ||
206 | return -1; | ||
207 | } | ||
208 | |||
209 | ret = fread(&rkboot_info, 1, sizeof(rkboot_info), fp_in); | ||
210 | |||
211 | if (ret != sizeof(rkboot_info)) | ||
212 | { | ||
213 | fclose(fp_in); | ||
214 | fprintf(stderr, "error: can't read %s file header\n", in_filename); | ||
215 | fprintf(stderr, "read %d, expected %d\n", ret, sizeof(rkboot_info)); | ||
216 | return -2; | ||
217 | } | ||
218 | |||
219 | if (action & INFO) | ||
220 | { | ||
221 | printf("file: %s\n", in_filename); | ||
222 | printf("signature: %s\n", rkboot_info.sign); | ||
223 | printf("check bytes: "); | ||
224 | for (i = 0; i < 16; i++) | ||
225 | printf("0x%0x ", rkboot_info.check_values[i]); | ||
226 | |||
227 | printf("\n"); | ||
228 | printf("timestamp %d.%d.%d %d:%d:%d\n", rkboot_info.time.day, | ||
229 | rkboot_info.time.month, | ||
230 | rkboot_info.time.year, | ||
231 | rkboot_info.time.hour, | ||
232 | rkboot_info.time.minute, | ||
233 | rkboot_info.time.second); | ||
234 | printf("UI master version: 0x%0x\n", rkboot_info.ui_master_version); | ||
235 | printf("UI slave version: 0x%0x\n", rkboot_info.ui_slave_version); | ||
236 | printf("s1 data offset: 0x%0x\n", rkboot_info.s1_offset); | ||
237 | printf("s1 data len: 0x%0x\n", rkboot_info.s1_len); | ||
238 | printf("s2 offset: 0x%0x\n", rkboot_info.s2_offset); | ||
239 | printf("s2 len: 0x%0x\n", rkboot_info.s2_len); | ||
240 | printf("s3 offset: 0x%0x\n", rkboot_info.s3_offset); | ||
241 | printf("s3 len: 0x%0x\n", rkboot_info.s3_len); | ||
242 | printf("s4 offset: 0x%0x\n", rkboot_info.s4_offset); | ||
243 | printf("s4 len: 0x%0x\n", rkboot_info.s4_len); | ||
244 | printf("UI version flag: 0x%0x\n", rkboot_info.version_flag); | ||
245 | } | ||
246 | |||
247 | if (action & EXTRACT) | ||
248 | { | ||
249 | /* first stage */ | ||
250 | buff = binary_extract(fp_in, rkboot_info.s1_offset, | ||
251 | rkboot_info.s1_len, | ||
252 | action & SCRAMBLE, | ||
253 | CONTINOUS_ENC); | ||
254 | |||
255 | if ( buff == NULL ) | ||
256 | { | ||
257 | fclose(fp_in); | ||
258 | fprintf(stderr, "error: can't extract image\n"); | ||
259 | return -2; | ||
260 | } | ||
261 | |||
262 | /* output */ | ||
263 | if ((fp_out = fopen("rkboot_s1.bin", "wb")) == NULL) | ||
264 | { | ||
265 | free(buff); | ||
266 | fclose(fp_in); | ||
267 | fprintf(stderr, "[error]: can't open rkboot_s1.bin for writing\n"); | ||
268 | return -3; | ||
269 | } | ||
270 | |||
271 | fwrite(buff, 1, rkboot_info.s1_len, fp_out); | ||
272 | |||
273 | fprintf(stderr, "[info]: extracted rkboot_s1.bin file\n"); | ||
274 | free(buff); | ||
275 | fclose(fp_out); | ||
276 | |||
277 | /* second stage */ | ||
278 | buff = binary_extract(fp_in, rkboot_info.s2_offset, | ||
279 | rkboot_info.s2_len, | ||
280 | action & SCRAMBLE, | ||
281 | CONTINOUS_ENC); | ||
282 | |||
283 | if ( buff == NULL ) | ||
284 | { | ||
285 | fclose(fp_in); | ||
286 | fprintf(stderr, "error: can't extract image\n"); | ||
287 | return -2; | ||
288 | } | ||
289 | |||
290 | if ((fp_out = fopen("rkboot_s2.bin", "wb")) == NULL) | ||
291 | { | ||
292 | free(buff); | ||
293 | fclose(fp_in); | ||
294 | fprintf(stderr, "[error]: can't open rkboot_s2.bin for writing\n"); | ||
295 | return -4; | ||
296 | } | ||
297 | |||
298 | fwrite(buff, 1, rkboot_info.s2_len, fp_out); | ||
299 | |||
300 | fprintf(stderr, "[info]: extracted rkboot_s2.bin file\n"); | ||
301 | free(buff); | ||
302 | fclose(fp_out); | ||
303 | |||
304 | /* third stage */ | ||
305 | buff = binary_extract(fp_in, rkboot_info.s3_offset, | ||
306 | rkboot_info.s3_len, | ||
307 | action & SCRAMBLE, | ||
308 | PAGE_ENC); | ||
309 | if ( buff == NULL ) | ||
310 | { | ||
311 | fclose(fp_in); | ||
312 | fprintf(stderr, "[error]: can't extract image.\n"); | ||
313 | return -2; | ||
314 | } | ||
315 | |||
316 | if ((fp_out = fopen("rkboot_s3.bin", "wb")) == NULL) | ||
317 | { | ||
318 | free(buff); | ||
319 | fclose(fp_in); | ||
320 | fprintf(stderr, "[error]: can't open rkboot_s3.bin for writing\n"); | ||
321 | return -4; | ||
322 | } | ||
323 | |||
324 | fwrite(buff, 1, rkboot_info.s3_len, fp_out); | ||
325 | |||
326 | fprintf(stderr, "[info]: extracted rkboot_s3.bin file\n"); | ||
327 | free(buff); | ||
328 | fclose(fp_out); | ||
329 | |||
330 | /* forth stage */ | ||
331 | buff = binary_extract(fp_in, rkboot_info.s4_offset, | ||
332 | rkboot_info.s4_len, | ||
333 | action & SCRAMBLE, | ||
334 | CONTINOUS_ENC); | ||
335 | if ( buff == NULL ) | ||
336 | { | ||
337 | fclose(fp_in); | ||
338 | fprintf(stderr, "[error]: can't extract image\n"); | ||
339 | return -2; | ||
340 | } | ||
341 | |||
342 | if ((fp_out = fopen("rkboot_s4.bin", "wb")) == NULL) | ||
343 | { | ||
344 | free(buff); | ||
345 | fclose(fp_in); | ||
346 | fprintf(stderr, "[error]: can't open rkboot_s4.bin for writing\n"); | ||
347 | return -4; | ||
348 | } | ||
349 | |||
350 | fwrite(buff, 1, rkboot_info.s4_len, fp_out); | ||
351 | |||
352 | fprintf(stderr, "[info]: extracted rkboot_s4.bin file\n"); | ||
353 | free(buff); | ||
354 | fclose(fp_out); | ||
355 | } | ||
356 | |||
357 | fclose(fp_in); | ||
358 | return 0; | ||
359 | } | ||
360 | |||
diff --git a/utils/rk27utils/rkusbtool/Makefile b/utils/rk27utils/rkusbtool/Makefile new file mode 100644 index 0000000000..785a09a1f1 --- /dev/null +++ b/utils/rk27utils/rkusbtool/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | all: rkusbtool | ||
2 | |||
3 | rkusbtool: rkusbtool.c | ||
4 | gcc -g -std=c99 -o $@ -W -Wall -lusb-1.0 -I/usr/include/libusb-1.0/ $^ | ||
5 | |||
6 | clean: | ||
7 | rm -fr rkusbtool | ||
diff --git a/utils/rk27utils/rkusbtool/rkusbtool.c b/utils/rk27utils/rkusbtool/rkusbtool.c new file mode 100644 index 0000000000..06fb7e860c --- /dev/null +++ b/utils/rk27utils/rkusbtool/rkusbtool.c | |||
@@ -0,0 +1,388 @@ | |||
1 | /* on ubuntu compile with gcc -W rkusbtool.c -o rkusbtool -lusb-1.0 -I/usr/include/libusb-1.0/ */ | ||
2 | #include <libusb.h> | ||
3 | #include <stdint.h> | ||
4 | #include <stdio.h> | ||
5 | #include <string.h> | ||
6 | |||
7 | #define VERSION "v0.1" | ||
8 | |||
9 | #define RETRY_MAX 5 | ||
10 | #define USB_TIMEOUT 512 | ||
11 | #define VENDORID 0x071b | ||
12 | #define PRODUCTID 0x3203 | ||
13 | |||
14 | #define OUT_EP 0x01 | ||
15 | #define IN_EP 0x82 | ||
16 | |||
17 | #define CBW_SIGNATURE 0x43425355 | ||
18 | #define CSW_SIGNATURE 0x53425355 | ||
19 | #define SCSICMD_READ_12 0xa8 | ||
20 | |||
21 | /* rockchip specific commands */ | ||
22 | #define RK_CMD 0xe0 | ||
23 | #define RK_GET_VERSION 0xffffffff | ||
24 | #define RK_SWITCH_ROCKUSB 0xfeffffff | ||
25 | #define RK_CHECK_USB 0xfdffffff | ||
26 | #define RK_OPEN_SYSDISK 0xfcffffff | ||
27 | |||
28 | enum { | ||
29 | NONE = 0, | ||
30 | INFO = 1, | ||
31 | RKUSB = 2, | ||
32 | SYSDISK = 4, | ||
33 | CHECKUSB = 8 | ||
34 | }; | ||
35 | |||
36 | enum { | ||
37 | COMMAND_PASSED = 0, | ||
38 | COMMAND_FAILED = 1, | ||
39 | PHASE_ERROR = 2 | ||
40 | }; | ||
41 | |||
42 | struct CBWCB_t | ||
43 | { | ||
44 | uint8_t cbCode; | ||
45 | uint8_t cbLun; | ||
46 | uint32_t LBA; | ||
47 | uint32_t cbLen; | ||
48 | uint8_t reseved; | ||
49 | uint8_t control; | ||
50 | } __attribute__((__packed__)); | ||
51 | |||
52 | struct CBW_t | ||
53 | { | ||
54 | uint32_t dCBWSignature; | ||
55 | uint32_t dCBWTag; | ||
56 | uint32_t dCBWDataTransferLength; | ||
57 | uint8_t bmCBWFlags; | ||
58 | uint8_t bCBWLUN; | ||
59 | uint8_t bCBWCBLength; | ||
60 | uint8_t CBWCB[16]; | ||
61 | } __attribute__((__packed__)); | ||
62 | |||
63 | struct CSW_t | ||
64 | { | ||
65 | uint32_t dCSWSignature; | ||
66 | uint32_t dCSWTag; | ||
67 | uint32_t dCSWDataResidue; | ||
68 | uint8_t bCSWStatus; | ||
69 | } __attribute__((__packed__)); | ||
70 | |||
71 | static int send_msc_cmd(libusb_device_handle *hdev, struct CBWCB_t *cbwcb, uint32_t data_len, uint32_t *reftag) | ||
72 | { | ||
73 | struct CBW_t cbw; | ||
74 | int ret, repeat, transferred; | ||
75 | static uint32_t tag = 0xdaefbc01; | ||
76 | |||
77 | memset(&cbw, 0, sizeof(cbw)); | ||
78 | cbw.dCBWSignature = CBW_SIGNATURE; | ||
79 | cbw.dCBWTag = tag++; | ||
80 | cbw.dCBWDataTransferLength = data_len; | ||
81 | cbw.bmCBWFlags = 0x80; /* device to host */ | ||
82 | cbw.bCBWLUN = 0; | ||
83 | cbw.bCBWCBLength = sizeof(struct CBWCB_t); | ||
84 | memcpy(cbw.CBWCB, cbwcb, sizeof(struct CBWCB_t)); | ||
85 | |||
86 | *reftag = cbw.dCBWTag; | ||
87 | do | ||
88 | { | ||
89 | /* transfer command to the device */ | ||
90 | ret = libusb_bulk_transfer(hdev, OUT_EP, (unsigned char*)&cbw, 31, &transferred, USB_TIMEOUT); | ||
91 | if (ret == LIBUSB_ERROR_PIPE) | ||
92 | { | ||
93 | libusb_clear_halt(hdev, OUT_EP); | ||
94 | } | ||
95 | repeat++; | ||
96 | } while ((ret == LIBUSB_ERROR_PIPE) && (repeat < RETRY_MAX)); | ||
97 | |||
98 | if (ret != LIBUSB_SUCCESS) | ||
99 | { | ||
100 | printf("error: command transfer error\n"); | ||
101 | return -1; | ||
102 | } | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static int get_msc_csw(libusb_device_handle *hdev, uint32_t reftag) | ||
108 | { | ||
109 | struct CSW_t csw; | ||
110 | int ret, repeat, transferred; | ||
111 | |||
112 | /* get CSW response from device */ | ||
113 | repeat = 0; | ||
114 | do | ||
115 | { | ||
116 | ret = libusb_bulk_transfer(hdev, IN_EP, (unsigned char *)&csw, 13, &transferred, USB_TIMEOUT); | ||
117 | if (ret == LIBUSB_ERROR_PIPE) | ||
118 | { | ||
119 | libusb_clear_halt(hdev, IN_EP); | ||
120 | } | ||
121 | repeat++; | ||
122 | } while ((ret == LIBUSB_ERROR_PIPE) && (repeat < RETRY_MAX)); | ||
123 | |||
124 | if (ret != LIBUSB_SUCCESS) | ||
125 | { | ||
126 | printf("error reading CSW\n"); | ||
127 | return -3; | ||
128 | } | ||
129 | |||
130 | if (transferred != 13) | ||
131 | { | ||
132 | printf("error wrong size of CSW packet\n"); | ||
133 | return -4; | ||
134 | } | ||
135 | |||
136 | if (csw.dCSWSignature != CSW_SIGNATURE) | ||
137 | { | ||
138 | printf("error: wrong CSW signature.\n"); | ||
139 | return -5; | ||
140 | } | ||
141 | |||
142 | if (csw.dCSWTag != reftag) | ||
143 | { | ||
144 | printf("error: CSW dCSWTag mismatch\n"); | ||
145 | return -6; | ||
146 | } | ||
147 | |||
148 | if (csw.bCSWStatus) | ||
149 | { | ||
150 | /* In case of CSW indicating error dump the content of the packet */ | ||
151 | printf ("dCSWSignature: 0x%0x\n", csw.dCSWSignature); | ||
152 | printf ("dCSWTag: 0x%0x\n", csw.dCSWTag); | ||
153 | printf ("dCSWDataResidue: 0x%0x\n", csw.dCSWDataResidue); | ||
154 | printf ("bCSWStatus: 0x%0x\n", csw.bCSWStatus); | ||
155 | } | ||
156 | |||
157 | return csw.bCSWStatus; | ||
158 | } | ||
159 | |||
160 | static int rk_cmd(libusb_device_handle *hdev, uint32_t command, uint8_t *buf, uint8_t len) | ||
161 | { | ||
162 | struct CBWCB_t cbwcb; | ||
163 | int ret, transferred; | ||
164 | uint32_t reftag; | ||
165 | |||
166 | /* enter command */ | ||
167 | memset(&cbwcb, 0, sizeof(cbwcb)); | ||
168 | cbwcb.cbCode = SCSICMD_READ_12; | ||
169 | cbwcb.cbLun = RK_CMD; | ||
170 | cbwcb.LBA = command; /* RK_GET_VERSION, RK_OPEN_SYSDISK, RK_SWITCH_ROCKUSB */ | ||
171 | cbwcb.cbLen = len; /* size of transfer in response to this command */ | ||
172 | |||
173 | ret = send_msc_cmd(hdev, &cbwcb, len, &reftag); | ||
174 | |||
175 | /* get the response */ | ||
176 | if (len > 0) | ||
177 | { | ||
178 | ret = libusb_bulk_transfer(hdev, IN_EP, buf, len, &transferred, USB_TIMEOUT); | ||
179 | if (ret != LIBUSB_SUCCESS || transferred != len) | ||
180 | { | ||
181 | printf("error: reading response data failed\n"); | ||
182 | return -2; | ||
183 | } | ||
184 | } | ||
185 | |||
186 | return get_msc_csw(hdev, reftag); | ||
187 | } | ||
188 | |||
189 | static int get_sense(libusb_device_handle *hdev) | ||
190 | { | ||
191 | struct CBWCB_t cbwcb; | ||
192 | unsigned char sense[0x12]; | ||
193 | int size, ret; | ||
194 | uint32_t reftag; | ||
195 | |||
196 | memset(&cbwcb, 0, sizeof(cbwcb)); | ||
197 | cbwcb.cbCode = 0x03; | ||
198 | cbwcb.cbLun = 0; | ||
199 | cbwcb.LBA = 0; | ||
200 | cbwcb.cbLen = 0x12; | ||
201 | |||
202 | ret = send_msc_cmd(hdev, &cbwcb, 0x12, &reftag); | ||
203 | libusb_bulk_transfer(hdev, IN_EP, (unsigned char*)&sense, 0x12, &size, USB_TIMEOUT); | ||
204 | |||
205 | return get_msc_csw(hdev, reftag); | ||
206 | } | ||
207 | |||
208 | static void usage(void) | ||
209 | { | ||
210 | printf("Usage: rkusbtool [options]\n"); | ||
211 | printf("-h|--help This help message\n"); | ||
212 | printf("-i|--info Get version string from the device\n"); | ||
213 | printf("-d|--dfu Put device into DFU mode\n"); | ||
214 | printf("-s|--sysdisk Open system disk\n"); | ||
215 | printf("-c|--checkusb Check if dev is in System or Loader USB mode\n"); | ||
216 | } | ||
217 | |||
218 | int main (int argc, char **argv) | ||
219 | { | ||
220 | libusb_device_handle *hdev; | ||
221 | int ret; | ||
222 | int i = 0, action = NONE; | ||
223 | uint32_t ver[3]; | ||
224 | |||
225 | if (argc < 2) | ||
226 | { | ||
227 | usage(); | ||
228 | return 1; | ||
229 | } | ||
230 | |||
231 | /* print banner */ | ||
232 | fprintf(stderr,"rkusbtool " VERSION "\n"); | ||
233 | fprintf(stderr,"(C) Marcin Bukat 2011\n"); | ||
234 | fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n"); | ||
235 | fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"); | ||
236 | |||
237 | /* arguments handling */ | ||
238 | while (i < argc) | ||
239 | { | ||
240 | if ((strcmp(argv[i],"-i")==0) || (strcmp(argv[i],"--info")==0)) | ||
241 | { | ||
242 | action |= INFO; | ||
243 | } | ||
244 | else if ((strcmp(argv[i],"-d")==0) || (strcmp(argv[i],"--dfu")==0)) | ||
245 | { | ||
246 | action |= RKUSB; | ||
247 | } | ||
248 | else if ((strcmp(argv[i],"-s")==0) || (strcmp(argv[i],"--sysdisk")==0)) | ||
249 | { | ||
250 | action |= SYSDISK; | ||
251 | } | ||
252 | else if ((strcmp(argv[i],"-c")==0) || (strcmp(argv[i],"--checkusb")==0)) | ||
253 | { | ||
254 | action |= CHECKUSB; | ||
255 | } | ||
256 | else if ((strcmp(argv[i],"-h")==0) || (strcmp(argv[i],"--help")==0)) | ||
257 | { | ||
258 | usage(); | ||
259 | return 0; | ||
260 | } | ||
261 | i++; | ||
262 | } | ||
263 | |||
264 | /* initialize libusb */ | ||
265 | libusb_init(NULL); | ||
266 | /* usb_set_debug(2); */ | ||
267 | |||
268 | hdev = libusb_open_device_with_vid_pid(NULL, VENDORID, PRODUCTID); | ||
269 | if (hdev == NULL) | ||
270 | { | ||
271 | printf("error: can't open device\n"); | ||
272 | return -10; | ||
273 | } | ||
274 | |||
275 | ret = libusb_kernel_driver_active(hdev, 0); | ||
276 | |||
277 | if (ret < 0) | ||
278 | { | ||
279 | printf ("error checking kernel driver active\n"); | ||
280 | libusb_close(hdev); | ||
281 | return -3; | ||
282 | } | ||
283 | else | ||
284 | { | ||
285 | if (ret) | ||
286 | libusb_detach_kernel_driver(hdev, 0); | ||
287 | } | ||
288 | |||
289 | ret = libusb_set_configuration(hdev, 1); | ||
290 | if (ret < 0) | ||
291 | { | ||
292 | printf("error: could not select configuration (1)\n"); | ||
293 | libusb_close(hdev); | ||
294 | return -3; | ||
295 | } | ||
296 | |||
297 | ret = libusb_claim_interface(hdev, 0); | ||
298 | if (ret < 0) | ||
299 | { | ||
300 | printf("error: could not claim interface #0\n"); | ||
301 | libusb_close(hdev); | ||
302 | return -11; | ||
303 | } | ||
304 | |||
305 | ret = libusb_set_interface_alt_setting(hdev, 0, 0); | ||
306 | if ( ret != LIBUSB_SUCCESS) | ||
307 | { | ||
308 | printf("error: could not set alt setting for interface #0\n"); | ||
309 | libusb_close(hdev); | ||
310 | return -11; | ||
311 | } | ||
312 | |||
313 | /* BulkOnly reset */ | ||
314 | //ret = libusb_control_transfer(hdev, 0x21, 0xff, 0, 0, NULL, 0, USB_TIMEOUT); | ||
315 | |||
316 | /* BulkOnly get max lun */ | ||
317 | //ret = libusb_control_transfer(hdev, 0xa1, 0xfe, 0, 0, &maxlun, 1, USB_TIMEOUT); | ||
318 | |||
319 | /* Devices that do not support multiple LUNs may STALL this command. */ | ||
320 | //if (ret == 0) | ||
321 | // maxlun = -1; | ||
322 | |||
323 | //printf("MAXLUN: %d\n", maxlun); | ||
324 | |||
325 | get_sense(hdev); | ||
326 | |||
327 | if (action & INFO) | ||
328 | { | ||
329 | ret = rk_cmd(hdev, RK_GET_VERSION, (uint8_t *)ver, 12); | ||
330 | |||
331 | if (ret) | ||
332 | { | ||
333 | printf("error sending RK_GET_VERSION command. Err 0x%0x\n", ret); | ||
334 | libusb_close(hdev); | ||
335 | return ret; | ||
336 | } | ||
337 | |||
338 | printf("Rockchip device info:\n"); | ||
339 | printf("loader ver: %x.%x\n", (ver[0]>>16)&0xff, ver[0]&0xff); | ||
340 | printf("kernel ver: %x.%x\n", (ver[1]>>16)&0xff, ver[1]&0xff); | ||
341 | printf("sdk ver: %x.%x\n", (ver[2]>>16)&0xff, ver[2]&0xff); | ||
342 | } | ||
343 | |||
344 | if (action & CHECKUSB) | ||
345 | { | ||
346 | printf("Checking USB mode...\n"); | ||
347 | ret = rk_cmd(hdev, RK_CHECK_USB, (uint8_t *)ver, 1); | ||
348 | |||
349 | //if (ret) | ||
350 | //{ | ||
351 | // libusb_close(hdev); | ||
352 | // return ret; | ||
353 | //} | ||
354 | |||
355 | if (*(char *)ver) | ||
356 | printf("The device is in Loader USB mode\n"); | ||
357 | else | ||
358 | printf("The device is in System USB mode\n"); | ||
359 | } | ||
360 | |||
361 | if (action & SYSDISK) | ||
362 | { | ||
363 | printf("Opening system disk...\n"); | ||
364 | ret = rk_cmd(hdev, RK_OPEN_SYSDISK, NULL, 0); | ||
365 | |||
366 | if (ret) | ||
367 | { | ||
368 | libusb_close(hdev); | ||
369 | return ret; | ||
370 | } | ||
371 | } | ||
372 | |||
373 | if (action & RKUSB) | ||
374 | { | ||
375 | printf("Switching into rk DFU mode...\n"); | ||
376 | ret = rk_cmd(hdev, RK_SWITCH_ROCKUSB, NULL, 0); | ||
377 | |||
378 | if (ret) | ||
379 | { | ||
380 | libusb_close(hdev); | ||
381 | return ret; | ||
382 | } | ||
383 | } | ||
384 | |||
385 | libusb_close(hdev); | ||
386 | libusb_exit(NULL); | ||
387 | return 0; | ||
388 | } | ||