summaryrefslogtreecommitdiffstats
path: root/utils/rk27utils/rk27load
diff options
context:
space:
mode:
Diffstat (limited to 'utils/rk27utils/rk27load')
-rw-r--r--utils/rk27utils/rk27load/Makefile7
-rw-r--r--utils/rk27utils/rk27load/checksum.c35
-rw-r--r--utils/rk27utils/rk27load/checksum.h1
-rw-r--r--utils/rk27utils/rk27load/common.c16
-rw-r--r--utils/rk27utils/rk27load/common.h1
-rw-r--r--utils/rk27utils/rk27load/main.c165
-rw-r--r--utils/rk27utils/rk27load/rk27load.h11
-rw-r--r--utils/rk27utils/rk27load/scramble.c46
-rw-r--r--utils/rk27utils/rk27load/scramble.h1
-rw-r--r--utils/rk27utils/rk27load/stage1/Makefile48
-rw-r--r--utils/rk27utils/rk27load/stage1/main.S42
-rw-r--r--utils/rk27utils/rk27load/stage1/stage1.lds23
-rw-r--r--utils/rk27utils/rk27load/stage1_upload.c113
-rw-r--r--utils/rk27utils/rk27load/stage1_upload.h3
-rw-r--r--utils/rk27utils/rk27load/stage2/Makefile48
-rw-r--r--utils/rk27utils/rk27load/stage2/crt0.S55
-rw-r--r--utils/rk27utils/rk27load/stage2/irq.S103
-rw-r--r--utils/rk27utils/rk27load/stage2/main.S89
-rw-r--r--utils/rk27utils/rk27load/stage2/stage2.lds40
-rw-r--r--utils/rk27utils/rk27load/stage2_upload.c102
-rw-r--r--utils/rk27utils/rk27load/stage2_upload.h3
-rw-r--r--utils/rk27utils/rk27load/stage3_upload.c93
-rw-r--r--utils/rk27utils/rk27load/stage3_upload.h1
23 files changed, 1046 insertions, 0 deletions
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 @@
+all: rk27load
+
+rk27load: main.c scramble.c checksum.c common.c stage1_upload.c stage2_upload.c stage3_upload.c
+ gcc -g -std=c99 -o $@ -W -Wall -lusb-1.0 -I/usr/include/libusb-1.0/ $^
+
+clean:
+ 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 @@
+#include <stdint.h>
+#include "checksum.h"
+
+uint16_t checksum(void *buff, uint32_t size)
+{
+ uint32_t r2 = 0xffff;
+ uint32_t r3 = 0;
+ uint32_t i, j;
+
+ for (i=0; i<size; i++) {
+ r3 = 0x80;
+ for (j=0; j<8; j++) {
+ if ((r2 & 0x8000) != 0) {
+ r2 <<= 17;
+ r2 >>= 16;
+ r2 ^= 0x1000;
+ r2 ^= 0x21;
+ }
+ else {
+ r2 <<= 17;
+ r2 >>= 16;
+ }
+
+ if ((((uint8_t *)buff)[i] & r3) != 0) {
+ r2 ^= 0x1000;
+ r2 ^= 0x21;
+ }
+
+ r3 >>= 1;
+ }
+ }
+
+ return r2 & 0xffff;
+}
+
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 @@
+#include <stdint.h>
+#include <stdio.h>
+
+#include "common.h"
+
+uint32_t filesize(FILE * f)
+{
+ uint32_t filesize;
+
+ fseek(f, 0, SEEK_END);
+ filesize = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ return filesize;
+}
+
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 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <libusb.h>
+
+#include "rk27load.h"
+#include "common.h"
+#include "stage1_upload.h"
+#include "stage2_upload.h"
+#include "stage3_upload.h"
+
+#define VERSION "v0.2"
+
+enum {
+ NONE = 0,
+ ENCODE_S1 = 1,
+ ENCODE_S2 = 2
+};
+
+static void usage(char *name)
+{
+ printf("usage: (sudo) %s [-e1 -e2] -s1 stage1.bin -s2 stage2.bin -s3 usercode.bin\n", name);
+ printf("stage1.bin - binary of the stage1 (sdram init)\n");
+ printf("stage2.bin - binary of the stage2 bootloader\n");
+ printf("usercode.bin - binary of the custom usercode\n");
+ printf("\n");
+ printf("options:\n");
+ printf("-e1 - encode stage1 bootloader\n");
+ printf("-e2 - encode stage2 bootloader\n");
+}
+
+int main(int argc, char **argv)
+{
+ libusb_device_handle *hdev;
+ char *filenames[3];
+ int i=1, action=0, ret=0;
+
+ while (i < argc)
+ {
+ if (strcmp(argv[i],"-e1") == 0)
+ {
+ action |= ENCODE_S1;
+ i++;
+ }
+ else if (strcmp(argv[i],"-e2") == 0)
+ {
+ action |= ENCODE_S2;
+ i++;
+ }
+ else if (strcmp(argv[i],"-s1") == 0)
+ {
+ i++;
+ if (i == argc)
+ {
+ usage(argv[0]);
+ return -1;
+ }
+ filenames[0] = argv[i];
+ printf("%s", argv[i]);
+ i++;
+ }
+ else if (strcmp(argv[i],"-s2") == 0)
+ {
+ i++;
+ if (i == argc)
+ {
+ usage(argv[0]);
+ return -2;
+ }
+ filenames[1] = argv[i];
+ i++;
+ }
+ else if (strcmp(argv[i],"-s3") == 0)
+ {
+ i++;
+ if (i == argc)
+ {
+ usage(argv[0]);
+ return -3;
+ }
+ filenames[2] = argv[i];
+ i++;
+ }
+ else
+ {
+ usage(argv[0]);
+ return -4;
+ }
+ }
+
+
+ fprintf(stderr,"rk27load " VERSION "\n");
+ fprintf(stderr,"(C) Marcin Bukat 2011\n");
+ fprintf(stderr,"Based on rk27load ver. 0.1 written by AleMaxx (alemaxx at hotmail.de)\n\n");
+ fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n");
+ fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
+
+ /* initialize libusb */
+ libusb_init(NULL);
+
+ /* configure device */
+ fprintf(stderr, "[info]: Initializing device... ");
+ hdev = libusb_open_device_with_vid_pid(NULL, VENDORID, PRODUCTID);
+
+ if (hdev == NULL)
+ {
+ fprintf(stderr, "\n[error]: Could not find rockchip device\n");
+ ret = -2;
+ goto finish;
+ }
+
+ ret = libusb_set_configuration(hdev, 1);
+ if (ret < 0)
+ {
+ fprintf(stderr, "\n[error]: Could not select configuration (1)\n");
+ ret = -3;
+ goto finish;
+ }
+
+ ret = libusb_claim_interface(hdev, 0);
+ if (ret < 0)
+ {
+ fprintf(stderr, "\n[error]: Could not claim interface #0\n");
+ ret = -4;
+ goto finish;
+ }
+
+ ret = libusb_set_interface_alt_setting(hdev, 0, 0);
+ if (ret < 0)
+ {
+ fprintf(stderr, "\n[error]: Could not set alternate interface #0\n");
+ ret = -5;
+ goto finish;
+ }
+
+ fprintf(stderr, "done\n");
+
+
+ ret = upload_stage1_code(hdev, filenames[0], (action & ENCODE_S1));
+ if (ret < 0)
+ goto finish;
+
+ ret = upload_stage2_code(hdev, filenames[1], (action & ENCODE_S2));
+ if (ret < 0)
+ goto finish;
+
+ ret = upload_stage3_code(hdev, filenames[2]);
+ if (ret < 0)
+ goto finish;
+
+ /* done */
+ ret = 0;
+
+ finish:
+ if (hdev != NULL)
+ libusb_close(hdev);
+
+ if (ret < 0)
+ fprintf(stderr, "[error]: Error %d\n", ret);
+
+ return ret;
+}
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 @@
+#define USB_TIMEOUT 512
+
+#define VENDORID 0x71b
+#define PRODUCTID 0x3201
+
+#define USB_EP0 0x41
+
+#define VCMD_UPLOAD 0x0c
+#define VCMD_INDEX_STAGE1 0x471
+#define VCMD_INDEX_STAGE2 0x472
+
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 @@
+#include <stdint.h>
+#include "scramble.h"
+
+void scramble(uint8_t *in, uint8_t *out, const int size)
+{
+ /* table extracted from bootrom */
+ static const uint8_t key[] = {
+ 0x7C, 0x4E, 0x03, 0x04,
+ 0x55, 0x05, 0x09, 0x07,
+ 0x2D, 0x2C, 0x7B, 0x38,
+ 0x17, 0x0D, 0x17, 0x11
+ };
+
+ int i, i3, x, val, idx;
+
+ uint8_t key1[0x100];
+ uint8_t key2[0x100];
+
+ for (i=0; i<0x100; i++) {
+ key1[i] = i;
+ key2[i] = key[i&0xf];
+ }
+
+ i3 = 0;
+ for (i=0; i<0x100; i++) {
+ x = key1[i];
+ i3 = key1[i] + i3;
+ i3 += key2[i];
+ i3 &= 0xff;
+ key1[i] = key1[i3];
+ key1[i3] = x;
+ }
+
+ idx = 0;
+ for (i=0; i<size; i++) {
+ x = key1[(i+1) & 0xff];
+ val = x;
+ idx = (x + idx) & 0xff;
+ key1[(i+1) & 0xff] = key1[idx];
+ key1[idx] = (x & 0xff);
+ val = (key1[(i+1)&0xff] + x) & 0xff;
+ val = key1[val];
+ out[i] = val ^ in[i];
+ }
+}
+
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 @@
+
+TARGET = stage1
+
+TOOLCHAIN = arm-elf-eabi-
+
+CC = $(TOOLCHAIN)gcc
+CPP = $(TOOLCHAIN)cpp
+LD = $(TOOLCHAIN)gcc
+AS = $(TOOLCHAIN)as
+OBJCOPY = $(TOOLCHAIN)objcopy
+OBJDUMP = $(TOOLCHAIN)objdump
+
+CFLAGS = -Wundef -marm -march=armv5te -nostdlib -mfpu=fpa -O0 -c
+#ASFLAGS = -mcpu=arm926ej-s
+
+OBJS = main.o
+LDSCRIPT= stage1.lds
+
+#LIBDIRS = -L../arm/lib/gcc/arm-elf/4.1.0/ -L../lib
+#LIBS = -lgcc
+LIBS =
+LDFLAGS = -Wundef -marm -march=armv5te -T$(LDSCRIPT) -nostartfiles \
+ -mfpu=fpa -nostdlib -Xlinker -Map=$(TARGET).map
+
+all : $(TARGET).bin
+ ls -ls $(TARGET).bin
+
+%.o : %.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(INCDIRS) $< -o $@
+
+%.o : %.S
+ $(CC) $(CFLAGS) -c $< -o $@
+
+$(TARGET).elf : $(OBJS)
+ $(LD) $(LDFLAGS) $(OBJS) $(LIBDIRS) $(LIBS) -o $(TARGET).elf
+
+$(TARGET).bin : $(TARGET).elf
+ $(OBJCOPY) -O binary $(TARGET).elf $(TARGET).bin
+
+dasm : $(TARGET).bin
+ $(OBJDUMP) -m arm -D $(TARGET).elf | cat > $(TARGET).asm
+
+clean :
+ rm -f $(OBJS)
+ rm -f $(TARGET).elf
+ rm -f $(TARGET).bin
+ rm -f $(TARGET).asm
+ 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 @@
+.section .text,"ax",%progbits
+.global start
+
+start:
+ msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ/FIQ */
+
+pll_setup:
+ mov r0, #0x18000000
+ add r0, r0, #0x1c000
+
+ /* setup ARM core freq = 200MHz */
+ /* AHB bus freq (HCLK) = 100MHz */
+ /* APB bus freq (PCLK) = 50MHz */
+ ldr r1, [r0,#0x14] /* SCU_DIVCON1 */
+ orr r1, #9 /* ARM slow mode, HCLK:PCLK = 2:1 */
+ str r1, [r0,#0x14]
+
+ ldr r1,=0x01970c70 /* (1<<24) | (1<<23) | (23<<16) | (199<<4) */
+ str r1, [r0,#0x08]
+
+ ldr r2,=0x40000
+1:
+ ldr r1, [r0,#0x2c] /* SCU_STATUS */
+ tst r1, #1 /* ARM pll lock */
+ bne 1f
+ subs r2, #1
+ bne 1b
+1:
+ ldr r1, [r0,#0x14] /* SCU_DIVCON1 */
+ bic r1, #5 /* leave ARM slow mode, ARMclk:HCLK = 2:1 */
+ str r1, [r0,#0x14]
+
+sdram_config:
+ add r0, r0, #0x94000 /* SDRAM base */
+
+ mov r1, #1
+ str r1, [r0,#0x10c] /* MCSDR_BASIC Round-robin, SDRAM width 16bits */
+
+ add r1, #0x10
+ str r1, [r0,#0x108] /* MCSDR_ADDCFG 12 bits row/9 bits col addr */
+
+ 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 @@
+ENTRY(start)
+OUTPUT_FORMAT(elf32-littlearm)
+OUTPUT_ARCH(arm)
+/* STARTUP(crt0.o) */
+
+/* this is where bootrom loads sdram init code */
+MEMORY
+{
+ IRAM : ORIGIN = 0x18200E00, LENGTH = 0x00000200
+}
+
+SECTIONS
+{
+ .text : {
+ *(.text*)
+ *(.glue_7*)
+ } > IRAM
+
+ .data : {
+ *(.rodata*)
+ *(.data*)
+ } > IRAM
+}
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 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libusb.h>
+
+#include "rk27load.h"
+#include "common.h"
+#include "scramble.h"
+#include "checksum.h"
+#include "stage1_upload.h"
+
+/* ### upload sdram init code ### */
+int upload_stage1_code(libusb_device_handle *hdev, char *fn_stage1,
+ bool do_scramble)
+{
+ FILE *f;
+ int ret;
+ uint8_t *code;
+ uint32_t codesize;
+ uint16_t cks;
+
+ if ((f = fopen(fn_stage1, "rb")) == NULL)
+ {
+ fprintf(stderr, "[error]: Could not open file \"%s\"\n", fn_stage1);
+ return -10;
+ }
+
+ codesize = filesize(f);
+
+ if (codesize > 0x1fe)
+ {
+ fprintf(stderr, "[error]: Code too big for stage1\n");
+ return -11;
+ }
+
+ fprintf(stderr, "[stage1]: Loading %d bytes (%s) of code... ", codesize, fn_stage1);
+
+ code = (uint8_t *)malloc(0x200);
+ if (code == NULL)
+ {
+ fprintf(stderr, "\n[error]: Out of memory\n");
+ fclose(f);
+ return -12;
+ }
+
+ memset(code, 0, 0x200);
+ if (fread(code, 1, codesize, f) != codesize)
+ {
+ fprintf(stderr, "\n[error]: I/O error\n");
+ fclose(f);
+ free(code);
+ return -13;
+ }
+
+ fprintf(stderr, "done\n");
+ fclose(f);
+
+ /* encode data if requested */
+ if (do_scramble)
+ {
+
+ fprintf(stderr, "[stage1]: Encoding %d bytes of data ... ", codesize);
+ scramble(code, code, codesize);
+ fprintf(stderr, "done\n");
+ }
+
+
+ fprintf(stderr, "[stage1]: codesize = %d (0x%x)\n", codesize, codesize);
+
+ fprintf(stderr, "[stage1]: Calculating checksum... ");
+ cks = checksum((void *)code, codesize);
+ fprintf(stderr, "0x%04x\n", cks);
+ code[0x1fe] = (cks >> 8) & 0xff;
+ code[0x1ff] = cks & 0xff;
+ codesize += 2;
+
+ fprintf(stderr, "[stage1]: Uploading code (%d bytes)... ", codesize);
+
+ ret = libusb_control_transfer(hdev, /* device handle */
+ USB_EP0, /* bmRequestType */
+ VCMD_UPLOAD, /* bRequest */
+ 0, /* wValue */
+ VCMD_INDEX_STAGE1, /* wIndex */
+ code, /* data */
+ codesize, /* wLength */
+ USB_TIMEOUT /* timeout */
+ );
+ if (ret < 0)
+ {
+ fprintf(stderr, "\n[error]: Code upload request failed (ret=%d)\n", ret);
+ free(code);
+ return -14;
+ }
+
+ if (ret != (int)codesize)
+ {
+ fprintf(stderr, "\n[error]: Sent %d of %d total\n", ret, codesize);
+ free(code);
+ return -15;
+ }
+
+ sleep(1); /* wait for code to finish */
+ fprintf(stderr, "done\n");
+
+ /* free code */
+ free(code);
+
+ return 0;
+}
+
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 @@
+int upload_stage1_code(libusb_device_handle * hdev, char *fn_stage1,
+ bool do_scramble);
+
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 @@
+
+TARGET = stage2
+
+TOOLCHAIN = arm-elf-eabi-
+
+CC = $(TOOLCHAIN)gcc
+CPP = $(TOOLCHAIN)cpp
+LD = $(TOOLCHAIN)gcc
+AS = $(TOOLCHAIN)as
+OBJCOPY = $(TOOLCHAIN)objcopy
+OBJDUMP = $(TOOLCHAIN)objdump
+
+CFLAGS = -Wundef -marm -march=armv5te -nostdlib -mfpu=fpa -O0 -c
+#ASFLAGS = -mcpu=arm926ej-s
+
+OBJS = crt0.o main.o irq.o
+LDSCRIPT= stage2.lds
+
+#LIBDIRS = -L../arm/lib/gcc/arm-elf/4.1.0/ -L../lib
+#LIBS = -lgcc
+LIBS =
+LDFLAGS = -Wundef -marm -march=armv5te -T$(LDSCRIPT) -nostartfiles \
+ -mfpu=fpa -nostdlib -Xlinker -Map=$(TARGET).map
+
+all : $(TARGET).bin
+ ls -ls $(TARGET).bin
+
+%.o : %.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(INCDIRS) $< -o $@
+
+%.o : %.S
+ $(CC) $(CFLAGS) -c $< -o $@
+
+$(TARGET).elf : $(OBJS)
+ $(LD) $(LDFLAGS) $(OBJS) $(LIBDIRS) $(LIBS) -o $(TARGET).elf
+
+$(TARGET).bin : $(TARGET).elf
+ $(OBJCOPY) -O binary $(TARGET).elf $(TARGET).bin
+
+dasm : $(TARGET).bin
+ $(OBJDUMP) -m arm -D $(TARGET).elf | cat > $(TARGET).asm
+
+clean :
+ rm -f $(OBJS)
+ rm -f $(TARGET).elf
+ rm -f $(TARGET).bin
+ rm -f $(TARGET).asm
+ 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 @@
+//
+// startup code
+//
+//
+
+#define PSR_MODE 0x0000001f
+#define PSR_USR_MODE 0x00000010
+#define PSR_IRQ_MODE 0x00000012
+#define PSR_SVC_MODE 0x00000013
+
+#define PSR_INT_MASK 0x000000c0
+#define PSR_FIQ_DIS 0x00000040
+#define PSR_IRQ_DIS 0x00000080
+
+.section .init.text,"ax",%progbits
+.global start
+.extern _interrupt_disable
+
+// -----------------------------------------------------
+// startup code (setup stacks, branch to main)
+// -----------------------------------------------------
+start:
+ // setup IRQ stack
+ mov r0, #(PSR_IRQ_MODE|PSR_FIQ_DIS|PSR_IRQ_DIS)
+ msr cpsr, r0
+ ldr sp,=irqstackend
+
+ // setup SVC stack
+ mov r0, #(PSR_SVC_MODE|PSR_FIQ_DIS|PSR_IRQ_DIS)
+ msr cpsr, r0
+ ldr sp,=stackend
+
+ // disbale interrupts
+ mrs r0, cpsr
+ orr r0, r0, #0xc0
+ msr cpsr_c, r0
+
+ // remap
+ mov r0, #0x18000000
+ add r0, r0, #0x1C000
+ ldr r1,=0xdeadbeef
+ str r1, [r0, #4]
+
+ // relocate itself
+ ldr r0,=_relocstart
+ ldr r1,=_relocend
+ ldr r2,=0x0
+1:
+ cmp r1,r0
+ ldrhi r3,[r0],#4
+ strhi r3,[r2],#4
+ bhi 1b
+
+ // continue running in SVC (supervisor mode)
+ 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 @@
+ .section .text
+ .align 4
+
+ .global irq_handler
+ #define BUFF_ADDR 0x60800000
+
+irq_handler:
+ stmfd sp!, {r0-r7, ip, lr}
+
+ // get interrupt number
+ mov r4, #0x18000000
+ add r4, r4, #0x80000
+ ldr r5, [r4, #0x104]
+ and r5, r5, #0x1f
+ cmp r5, #0x10 // UDC interrupt
+
+ bleq udc_irq
+
+ // clear pending interrupt
+ mov r3, #1
+ mov r2, r3, LSL r5
+ str r2, [r4, #0x118]
+
+ ldmfd sp!, {r0-r7, ip, lr}
+ subs pc, lr, #4
+
+udc_irq:
+ stmfd sp!, {r4-r8, lr}
+
+ // handle usb interrupt
+ ldr r4,=0x180A0000
+ ldr r5, [r4, #0x18] // UDC_INTFLAG
+
+ // ep0 in intr
+ tst r5, #0x04
+ beq bulk_recv_intr
+
+ // write_reg32(UDC_TX0STAT, read_reg32(UDC_TX0STAT) & ~0x7FF);
+ ldr r5, [r4, #0x40]
+ mov r5, r5, lsr #10
+ mov r5, r5, lsl #10 // clear clower 10 bits
+ str r5, [r4, #0x40]
+
+ // write_reg32(UDC_DMA0LM_OADDR, (uint32_t)(state.ctrlep_data));
+ mov r5, #0x60000000
+ str r5, [r4, #0x3c]
+
+ // write_reg32(UDC_DMA0CTLO, read_reg32(UDC_DMA0CTLO) | ENP_DMA_START);
+ mov r5, #1
+ str r5, [r4, #0x38]
+
+ ldmfd sp!, {r4-r8, pc}
+
+// bulk out interrupt
+bulk_recv_intr:
+ tst r5, #0x100
+ ldmeqfd sp!, {r4-r8, pc}
+
+ // read UDC_RX1STAT
+ ldr r5, [r4, #0x54]
+ mov r5, r5, lsl #21
+ mov r5, r5, lsr #21 // r5 = length
+
+ ldr r6,=usb_sz
+ ldr r6, [r6]
+ ldr r7, [r6] // r7 = total_code_length expected
+
+ subs r7, r7, r5
+ bne usb_bulk_out1_recv
+
+ // copy from buff to the begining of the ram
+ ldr r0,=BUFF_ADDR
+ ldr r1,[r0,#-4] // size
+
+ ldr r1,=0x800000 // buffer size
+
+ add r1,r1,r0 // end address
+ ldr r2,=0x60000000 // destination
+1:
+ cmp r1,r0
+ ldrhi r3,[r0],#4
+ strhi r3,[r2],#4
+ bhi 1b
+
+ // execute user code
+ ldr r0,=0x60000000
+ bx r0 // jump to 0x60000000
+
+usb_bulk_out1_recv:
+ str r7, [r6] // size = size - received
+
+ ldr r6,=usb_write_addr
+ ldr r7, [r6]
+
+ add r7, r7, r5
+ str r7, [r6] // usb_write_addr += length
+
+ str r7, [r4, #0x60] // DMA1LM_OADDR = usb_write_addr
+
+ mov r5, #1
+ str r5, [r4, #0x5c] // DMA1_CTL0 = ENP_DMA_START
+
+ 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 @@
+
+ .section .text
+ .align 4
+
+ .arm
+
+ .global main
+ .global _interrupt_disable
+ .global _interrupt_enable
+
+ .global usb_write_addr
+ .global usb_sz
+
+ #define BUFF_ADDR 0x60800000
+
+// -----------------------------------------------------
+// vector table
+// -----------------------------------------------------
+ ldr pc, =main
+ ldr pc, =main
+ ldr pc, =main
+ ldr pc, =main
+ ldr pc, =main
+ ldr pc, =main
+ ldr pc, =irq_handler
+ ldr pc, =main
+
+// -----------------------------------------------------
+// main
+// -----------------------------------------------------
+main:
+ // turn on usb interrupts
+ mov r0, #0x18000000
+ add r0, r0, #0x80000
+ ldr r1, [r0, #0x10c]
+ orr r1, r1, #0x10000
+ str r1, [r0, #0x10c]
+
+ // enable usb-bulk
+ add r0, r0, #0x20000 // R0 = 0x180A0000 (UDC_BASE)
+
+ // enable EP1, write_reg32(UDC_RX1CON, (0x1 << 8) | RxACKINTEN | RxEPEN);
+ mov r1, #0x190 // bits 8,7,4 -> 0x190
+ str r1, [r0, #0x58]
+
+ // setup receive buffer (must be aligned on dword boundary)
+ ldr r1,=usb_write_addr // write_reg32(UDC_DMA1LM_OADDR, (uint32_t)rx_buff);
+ ldr r1, [r1]
+ str r1, [r0, #0x60] // UDC_DMA1LM_OADDR = usb_write_addr
+
+ // write_reg32(UDC_DMA1CTRLO, read_reg32(UDC_DMA1CTRLO) | ENP_DMA_START);
+ ldr r1, [r0, #0x5c]
+ orr r1, r1, #2
+ str r1, [r0, #0x5c]
+
+ // enable bulk_out1 interrupt
+ ldr r1, [r0, #0x14] // UDC_ENINT
+ orr r1, r1, #0x100 // EN_BOUT1_INTR
+ str r1, [r0, #0x14]
+
+ bl _interrupt_enable
+idle:
+ b idle
+
+// -----------------------------------------------------
+// _interrupt_enable - enables interrupts
+// -----------------------------------------------------
+_interrupt_enable:
+ mrs r0, cpsr
+ bic r0, r0, #0x80
+ msr cpsr_c, r0
+ mov pc, lr
+
+// -----------------------------------------------------
+// _interrupt_disable - disables interrupts
+// -----------------------------------------------------
+_interrupt_disable:
+ mrs r0, cpsr
+ orr r0, r0, #0xc0
+ msr cpsr_c, r0
+ mov pc, lr
+
+
+ .section .data
+usb_write_addr:
+ .word (BUFF_ADDR-4)
+
+usb_sz:
+ .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 @@
+ENTRY(start)
+OUTPUT_FORMAT(elf32-littlearm)
+OUTPUT_ARCH(arm)
+/* STARTUP(crt0.o) */
+
+MEMORY
+{
+ DRAM : ORIGIN = 0x60000000, LENGTH = 0x01000000
+ IRAM : ORIGIN = 0x00000000, LENGTH = 0x00002000
+}
+
+SECTIONS
+{
+ .init.text : {
+ *(.init.text)
+ } > DRAM
+
+ .text : {
+ *(.text*)
+ *(.glue_7*)
+ } > IRAM AT > DRAM
+
+ .data : {
+ *(.data*)
+ } > IRAM AT > DRAM
+
+ _relocstart = LOADADDR(.text);
+ _relocend = LOADADDR(.data) + SIZEOF(.data);
+
+ .stack (NOLOAD) : {
+ . = ALIGN(0x100);
+ *(.stack)
+ stackbegin = .;
+ . += 0x200;
+ stackend = .;
+ irqstackbegin = .;
+ . += 0x200;
+ irqstackend = .;
+ } > IRAM
+}
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 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libusb.h>
+
+#include "rk27load.h"
+#include "common.h"
+#include "scramble.h"
+#include "checksum.h"
+#include "stage2_upload.h"
+
+int upload_stage2_code(libusb_device_handle *hdev, char *fn_stage2,
+ bool do_scramble)
+{
+ FILE *f;
+ uint32_t codesize;
+ uint8_t *code;
+ uint16_t cks;
+ int ret;
+
+ if ((f = fopen(fn_stage2, "rb")) == NULL)
+ {
+ fprintf(stderr, "[error]: Could not open file \"%s\"\n", fn_stage2);
+ return -21;
+ }
+
+ codesize = filesize(f);
+
+ fprintf(stderr, "[stage1]: Loading %d bytes (%s) of code... ", codesize, fn_stage2);
+
+ code = (uint8_t *) malloc(codesize + 0x400);
+ if (code == NULL)
+ {
+ fprintf(stderr, "\n[error]: Out of memory\n");
+ fclose(f);
+ return -22;
+
+ }
+
+ memset(code, 0, codesize + 0x400);
+
+ if (fread(code, 1, codesize, f) != codesize)
+ {
+ fprintf(stderr, "\n[error]: I/O error\n");
+ fclose(f);
+ free(code);
+ return -23;
+ }
+ fprintf(stderr, "done\n");
+ fclose(f);
+
+ codesize = ((codesize + 0x201) & 0xfffffe00) - 2;
+
+ if (do_scramble)
+ {
+ /* encode data if its user code */
+ fprintf(stderr, "[stage2]: Encoding %d bytes data... ", codesize);
+ scramble(code, code, codesize);
+ fprintf(stderr, "done\n");
+ }
+
+ fprintf(stderr, "[stage2]: Calculating checksum... ");
+ cks = checksum(code, codesize);
+ code[codesize + 0] = (cks >> 8) & 0xff;
+ code[codesize + 1] = cks & 0xff;
+ codesize += 2;
+ fprintf(stderr, "0x%04x\n", cks);
+
+ fprintf(stderr, "[stage2]: Uploading code (%d bytes)... ", codesize);
+
+ ret = libusb_control_transfer(hdev, /* device handle */
+ USB_EP0, /* bmRequestType */
+ VCMD_UPLOAD, /* bRequest */
+ 0, /* wValue */
+ VCMD_INDEX_STAGE2, /* wIndex */
+ code, /* data */
+ codesize, /* wLength */
+ USB_TIMEOUT /* timeout */
+ );
+
+ if (ret < 0)
+ {
+ fprintf(stderr, "\n[error]: Code upload request failed (ret=%d)\n", ret);
+ free(code);
+ return -24;
+ }
+
+ if (ret != (int)codesize)
+ {
+ fprintf(stderr, "[error]: Sent %d of %d total\n", ret, codesize);
+ free(code);
+ return -25;
+ }
+
+ fprintf(stderr, "done\n");
+
+ free(code);
+ return 0;
+}
+
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 @@
+int upload_stage2_code(libusb_device_handle * hdev, char *fn_stage2,
+ bool do_scramble);
+
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 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libusb.h>
+
+#include "rk27load.h"
+#include "common.h"
+#include "scramble.h"
+#include "checksum.h"
+#include "stage3_upload.h"
+
+int upload_stage3_code(libusb_device_handle *hdev, char *fn_stage3)
+{
+ FILE *f;
+ uint32_t codesize;
+ uint32_t remain;
+ uint8_t *code;
+ uint16_t send_size = 0x200;
+ uint32_t i = 0;
+ int ret, transfered;
+
+ if ((f = fopen(fn_stage3, "rb")) == NULL)
+ {
+ fprintf(stderr, "[error]: Could not open file \"%s\"\n", fn_stage3);
+ return -31;
+ }
+
+ codesize = filesize(f);
+
+ fprintf(stderr, "[stage3]: Loading user code (%d bytes)... ", codesize);
+
+ /* allocate buffer */
+ code = (uint8_t *) malloc(codesize + 0x204);
+ if (code == NULL)
+ {
+ fprintf(stderr, "\n[error]: Out of memory\n");
+ fclose(f);
+ return -32;
+ }
+
+ memset(code, 0, codesize + 0x204);
+ /* read usercode into buffer */
+ if (fread(&code[4], 1, codesize, f) != codesize)
+ {
+ fprintf(stderr, "\n[error]: I/O error\n");
+ fclose(f);
+ free(f);
+ return -33;
+ }
+ fprintf(stderr, "done\n");
+
+ fclose(f);
+
+ /* put code size at the first 4 bytes */
+ codesize += 4;
+ code[0] = codesize & 0xff;
+ code[1] = (codesize >> 8) & 0xff;
+ code[2] = (codesize >> 16) & 0xff;
+ code[3] = (codesize >> 24) & 0xff;
+
+ fprintf(stderr, "[stage3]: Uploading user code (%d bytes)... ", codesize);
+
+ remain = codesize;
+
+ while (remain > 0)
+ {
+ if (remain < 0x200)
+ send_size = remain;
+
+ ret = libusb_bulk_transfer(hdev, /* handle */
+ 1, /* EP */
+ &code[i * 0x200], /* data */
+ send_size, /* length */
+ &transfered, /* xfered */
+ USB_TIMEOUT /* timeout */
+ );
+
+ if (ret != LIBUSB_SUCCESS)
+ {
+ fprintf(stderr, "\n[error]: Bulk transfer error (%d, %d)\n", ret, i);
+ free(code);
+ return -34;
+ }
+
+ remain -= send_size;
+ i++;
+ }
+
+ fprintf(stderr,"done (sent %d blocks)\n", i);
+ return 0;
+}
+
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);