diff --git a/bootloader/rk27xx.c b/bootloader/rk27xx.c
index b74526f..a33d559 100644
--- a/bootloader/rk27xx.c
+++ b/bootloader/rk27xx.c
@@ -1,184 +1,240 @@
-#include "config.h"
-#include <stdlib.h>
 #include <stdio.h>
-#include <string.h>
-#include "inttypes.h"
-#include "string.h"
-#include "cpu.h"
-#include "system.h"
+#include <system.h>
+#include <inttypes.h>
+#include "config.h"
+#include "gcc_extensions.h"
 #include "lcd.h"
-#include "kernel.h"
-#include "thread.h"
-#include "backlight.h"
-#include "backlight-target.h"
 #include "font.h"
+#include "backlight.h"
+#include "adc.h"
+#include "button-target.h"
+#include "button.h"
 #include "common.h"
-#include "version.h"
-
-// 441 Hz samples table, 44100 Hz and 441 Hz -> 100 samples 
-const int16_t samples[] = {
-         0,   2057,   4106,   6139,   8148,  10125,  12062,  13951,  15785,  17557,
-     19259,  20886,  22430,  23886,  25247,  26509,  27666,  28713,  29648,  30465,
-     31163,  31737,  32186,  32508,  32702,  32767,  32702,  32508,  32186,  31737,
-     31163,  30465,  29648,  28713,  27666,  26509,  25247,  23886,  22430,  20886,
-     19259,  17557,  15785,  13951,  12062,  10125,   8148,   6139,   4106,   2057,
-         0,  -2057,  -4106,  -6139,  -8148, -10125, -12062, -13951, -15785, -17557,
-    -19259, -20886, -22430, -23886, -25247, -26509, -27666, -28713, -29648, -30465,
-    -31163, -31737, -32186, -32508, -32702, -32767, -32702, -32508, -32186, -31737,
-    -31163, -30465, -29648, -28713, -27666, -26509, -25247, -23886, -22430, -20886,
-    -19259, -17557, -15785, -13951, -12062, -10125,  -8148,  -6139,  -4106,  -2057 };
+#include "storage.h"
+#include "disk.h"
+#include "panic.h"
+#include "power.h"
+#include "string.h"
+#include "file.h"
+
+#define DRAM_ORIG 0x60000000
+#define LOAD_SIZE 0x700000
+
+#define RKLD_MAGIC 0x4c44524b
+#define RKW_HEADER_CRC 0x40000000
+#define RKW_IMAGE_CRC 0x20000000
 
 extern void show_logo( void );
 
-void INT_HDMA(void)
+struct rkw_header_t {
+    uint32_t magic_number;    /* Magic number. 0x4C44524B */
+    uint32_t header_size;     /* Size of the header */
+    uint32_t image_base;      /* Base address of the firmware image */
+    uint32_t load_address;    /* Load address */
+    uint32_t load_limit;      /* End of the firmware image */
+    uint32_t bss_start;       /* This is the start of .bss section of the firmware I suppose */
+    uint32_t reserved0;       /* reserved - I've seen only zeros in this field so far */
+    uint32_t reserved1;       /* reserved - I've seen only zeros in this field so far */
+    uint32_t entry_point;     /* Entry point address */
+    uint32_t load_options;    /* 0x80000000 - setup flag (I don't know what it means 
+                               * but is present in every RKW I saw), 
+                               * 0x40000000 - check header crc, 
+                               * 0x20000000 - check firmware crc
+                               */
+    uint32_t crc;              /* crc32 of the header (excluding crc32 field itself) */
+};
+
+static uint32_t rkw_crc32(const void *src, uint32_t len)
 {
-#if 0
-//    static uint32_t i;
-//    printf("hdma int: %d", i++);
-
-    HDMA_ISRC0 = (uint32_t)&samples;
-    HDMA_IDST0 = (uint32_t)&I2S_TXR;
-    HDMA_ICNT0 = (sizeof(samples)/4) - 1;
-    HDMA_CON0 = (1<<22)|  // slice mode
-                (1<<21)|  // channel enable
-                (1<<18)|  // interrupt mode
-                (5<<13)|  // transfer mode inc8
-                (6<<9) |  // hdreq from i2s tx
-                (0<<7) |  // source address increment
-                (1<<5) |  // destination address fixed
-                (2<<3) |  // data size word
-                (1<<0);   // enable hardware triggered dma
-
-    HDMA_ISR = (1<<13) | // mask ch1 page overflow
-               (1<<11) | // mask ch1 page count down
-               (1<<9);   // mask ch1 interrupts
-#endif
-return;
+    const unsigned char *buf = (const unsigned char *)src;
+
+    /* polynomial 0x04c10db7 */
+    static const uint32_t crc32_lookup[16] =
+    {   /* lookup table for 4 bits at a time is affordable */
+        0x00000000, 0x04C10DB7, 0x09821B6E, 0x0D4316D9,
+        0x130436DC, 0x17C53B6B, 0x1A862DB2, 0x1E472005,
+        0x26086DB8, 0x22C9600F, 0x2F8A76D6, 0x2B4B7B61,
+        0x350C5B64, 0x31CD56D3, 0x3C8E400A, 0x384F4DBD
+    };
+
+    uint32_t crc32 = 0;
+    unsigned char byte;
+    uint32_t t;
+
+    while (len--)
+    {
+        byte = *buf++; /* get one byte of data */
+
+        /* upper nibble of our data */
+        t = crc32 >> 28; /* extract the 4 most significant bits */
+        t ^= byte >> 4; /* XOR in 4 bits of data into the extracted bits */
+        crc32 <<= 4; /* shift the CRC register left 4 bits */
+        crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */
+
+        /* lower nibble of our data */
+        t = crc32 >> 28; /* extract the 4 most significant bits */
+        t ^= byte & 0x0F; /* XOR in 4 bits of data into the extracted bits */
+        crc32 <<= 4; /* shift the CRC register left 4 bits */
+        crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */
+    }
+
+    return crc32;
 }
 
-static int codec_write(uint8_t reg, uint8_t data)
+/* based on load_firmware() */
+int load_rkw(unsigned char* buf, char* firmware, int buffer_size)
 {
-    uint8_t tmp = data;
-    return i2c_write(0x27<<1, reg<<1, 1, &tmp);
+    int fd;
+    int rc;
+    int len;
+    uint32_t crc, fw_crc;
+    char filename[MAX_PATH];
+    struct rkw_header_t rkw_info;
+
+    snprintf(filename,sizeof(filename), BOOTDIR "/%s",firmware);
+    fd = open(filename, O_RDONLY);
+
+    if(fd < 0)
+    {
+        snprintf(filename,sizeof(filename),"/%s",firmware);
+        fd = open(filename, O_RDONLY);
+        if(fd < 0)
+            return EFILE_NOT_FOUND;
+    }
+
+    rc = read(fd, &rkw_info, sizeof(rkw_info));
+    if (rc < (int)sizeof(rkw_info))
+        return -100; /* TODO introduce some meaningfull error code */
+
+    /* check if RKW is valid */
+    if (rkw_info.magic_number != RKLD_MAGIC)
+    {
+        printf("RKW invalid magic 0x%0x != 0x%0x", rkw_info.magic_number, RKLD_MAGIC);
+        return -101;
+    }
+
+    /* check header crc if present */
+    if (rkw_info.load_options & RKW_HEADER_CRC)
+    {
+        crc = rkw_crc32((uint8_t *)&rkw_info, sizeof(rkw_info)-sizeof(uint32_t));
+        if (rkw_info.crc != crc)
+        {
+            printf("RKW header CRC error 0x%0x != 0x%0x", rkw_info.crc, crc);
+            return -102;
+        }
+    }
+
+    /* check image size */
+    len = rkw_info.load_limit - rkw_info.load_address;
+    if (len > buffer_size)
+    {
+        printf("RKW image too big");
+        return EFILE_TOO_BIG;
+    }
+
+    /* check load address - we support loading only at 0x60000000 */
+    if (rkw_info.load_address != (uint32_t)buf)
+    {
+        printf("RKW unsupported load address");
+        return -103;
+    }
+
+    printf("Loading %s", firmware);
+
+    /* skip header */
+    lseek(fd, sizeof(rkw_info), SEEK_SET);
+
+    /* load image into buffer */
+    rc = read(fd, buf, len);
+
+    if(rc < len)
+    {
+        printf("RKW loading failed");
+        return EREAD_IMAGE_FAILED;
+    }
+
+
+    if (rkw_info.load_options & RKW_IMAGE_CRC)
+    {
+        rc = read(fd, &fw_crc, sizeof(uint32_t));
+
+        crc = rkw_crc32((uint8_t *)buf, len);
+
+        if (fw_crc != crc)
+        {
+            printf("RKW firmware CRC error 0x%0x != 0x%0x", fw_crc, crc);
+            return EBAD_CHKSUM;
+        }
+    }
+
+    close(fd);
+
+    return EOK;
 }
 
+void main(void) NORETURN_ATTR;
 void main(void)
 {
-    int i;
-
-    _backlight_init();
+    unsigned char* loadbuffer;
+    void(*kernel_entry)(void);
+    int ret;
+    enum {rb, of} boot = rb;
 
     system_init();
     kernel_init();
     enable_irq();
 
-    lcd_init_device();
-    _backlight_on();
+    adc_init();
+    lcd_init();
+    backlight_init();
+    button_init_device();
+
     font_init();
     lcd_setfont(FONT_SYSFIXED);
 
     show_logo();
-    sleep(HZ*2);
-
-printf("show logo passed");
-    // I2S init
-    SCU_CLKCFG &= ~((1<<17) | (1<<16)); // enable i2s, i2c pclk
-//SCU_CLKCFG |= ((1<<17) | (1<<16));
-    I2S_OPR = (1<<17) |    // reset Tx
-              (1<<16) |    // reset Rx
-              (1<<6)  |    // disable HDMA Req1
-              (1<<5);      // disable HDMA Req2
-
-    I2S_TXCTL = (1<<16) |  // LRCK/SCLK = 64
-                (4<<8)  |  // MCLK/SCK = 4
-                (1<<4)  |  // 16bit samples
-                (0<<3)  |  // stereo mode
-                (0<<1);    // I2S
- 
-    I2S_RXCTL = (1<<16) |  // LRCK/SCLK = 64
-                (4<<8)  |  // MCLK/SCK = 4
-                (1<<4)  |  // 16bit samples
-                (0<<3)  |  // stereo mode
-                (0<<1);    // I2S
-
-    I2S_FIFOSTS = (1<<18) |  // Tx int trigger half full
-                  (1<<16);   // Rx int trigger half full
-
-    // I2S start
-    I2S_OPR = (1<<17) | (1<<16);
-    sleep(HZ/100);
-
-    I2S_OPR = (0<<6) | // req channel 1 enable                               
-              (1<<5) | // req channel 2 disable
-              (0<<4) | // HDMA req channel 1 Tx
-              (0<<2) | // normal I2S operation (no loopback)
-              (1<<1);  // Tx start
-
-printf("I2S config passed");
-
-    HDMA_ISRC0 = (uint32_t)&samples;
-    HDMA_IDST0 = (uint32_t)&I2S_TXR;
-    HDMA_ICNT0 = (sizeof(samples)/4) - 1;
-    HDMA_ISCNT0 = 7;
-    HDMA_IPNCNTD0 = 1;
-    HDMA_CON0 = (1<<22)|  // slice mode
-                (1<<21)|  // channel enable
-                (1<<18)|  // interrupt mode
-                (5<<13)|  // transfer mode inc8
-                (6<<9) |  // hdreq from i2s tx
-                (0<<7) |  // source address increment
-                (1<<5) |  // destination address fixed
-                (2<<3) |  // data size word
-                (1<<0);   // enable hardware triggered dma
-
-    HDMA_ISR = (1<<13) | // mask ch1 page overflow
-               (1<<11) | // mask ch1 page count down
-               (1<<9);   // mask ch1 interrupts
-
-    INTC_IMR |= (1<<12);
-    INTC_IECR |= (1<<12);
-
-printf("HDMA config passed");
-
-    i2c_init();
-
-printf("I2C config passed");
-
-    // codec init
-    codec_write(0x00, (1<<3)|(1<<2)|(1<<1)|(1<<0)); // AICR
-    codec_write(0x01, (1<<7)|(1<<5)|(1<<3));        // CR1
-    codec_write(0x02, (1<<2));                      // CR2
-    codec_write(0x03, 0);                           // CCR1
-    codec_write(0x04, (2<<4)|(2<<0));               // CCR2
-    codec_write(0x07, (3<<5)|(3<<0));               // CCR
-
-
-    codec_write(0x0f, 0x1f|(2<<6));                 // CGR6
-    codec_write(0x14, (1<<1));                      // TR1
-    codec_write(0x05, (1<<6)|(1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|(1<<0)); // PMR1
-    sleep(HZ/100);
-
-    codec_write(0x06, (1<<3)|(1<<2)|(1<<0));               // PMR2
-
-
-    codec_write(0x05, (1<<6)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|(1<<0));        // PMR1
-    codec_write(0x05, (1<<4)|(1<<3)|(1<<2)|(1<<1)|(1<<0));               // PMR1
-
-
-    // DACout mode
-    codec_write(0x01, (1<<7)|(1<<3)|(1<<5)|(1<<4));  // CR1
-    codec_write(0x05, (1<<4)|(1<<3)|(1<<2)|(1<<1)|(1<<0)); //PMR1
-//    codec_write(0x06, (1<<3)|(1<<2));                // PMR2
-
-printf("codec init passed");
-
-    codec_write(0x01, (1<<7)|(1<<3));         // CR1
-
-    codec_write(0x0a, 0); // 0dB digital gain
-    codec_write(0x11, 15|(2<<6)); // 
-
-    while(1)
-    {
-        printf("HDMA_CCNT0: 0x%0x FIFOSTS: 0x%0x", HDMA_CCNT0, I2S_FIFOSTS);
-    }
+
+    int btn = button_read_device();
+
+    /* if there is some other button pressed
+     * besides POWER/PLAY we boot into OF
+     */
+    if ((btn & ~POWEROFF_BUTTON))
+        boot = of;
+
+    /* if we are woken up by USB insert boot into OF */
+    if (DEV_INFO & (1<<20))
+        boot = of;
+
+    lcd_clear_display();
+
+    ret = storage_init();
+    if(ret < 0)
+        error(EATA, ret, true);
+
+    while(!disk_init(IF_MV(0)))
+        panicf("disk_init failed!");
+
+    while((ret = disk_mount_all()) <= 0)
+        error(EDISK, ret, true);
+
+    printf("Loading firmware");
+    loadbuffer = (unsigned char*)DRAM_ORIG; /* DRAM */
+   
+    if (boot == rb) 
+        while((ret = load_rkw(loadbuffer, "rockbox.rkw", LOAD_SIZE)) < 0)
+            error(EBOOTFILE, ret, true);
+    else if (boot == of)
+        while((ret = load_rkw(loadbuffer, "BASE.RKW", LOAD_SIZE)) < 0)
+            error(EBOOTFILE, ret, true);
+
+    kernel_entry = (void*) loadbuffer;
+    commit_discard_idcache();
+    printf("Executing");
+    kernel_entry();
+
+    printf("ERR: Failed to boot");
+
+    /* hang */
+    while(1);
 }
diff --git a/firmware/export/config/rk27generic.h b/firmware/export/config/rk27generic.h
index 5944a82..cdd103e 100644
--- a/firmware/export/config/rk27generic.h
+++ b/firmware/export/config/rk27generic.h
@@ -3,7 +3,7 @@
  */
 
 /* For Rolo and boot loader */
-#define MODEL_NUMBER 78
+#define MODEL_NUMBER 73
 
 #define MODEL_NAME   "Rockchip 27xx generic"
 
diff --git a/firmware/target/arm/rk27xx/app.lds b/firmware/target/arm/rk27xx/app.lds
index 080c74f..d3f5268 100644
--- a/firmware/target/arm/rk27xx/app.lds
+++ b/firmware/target/arm/rk27xx/app.lds
@@ -37,8 +37,8 @@ SECTIONS
 
   .intvect : {
     _intvectstart = . ;
-    *(.intvect)
-    _intvectend = _newstart ;  
+    KEEP(*(.intvect))
+    _intvectend = . ;  
   } > IRAM AT > DRAM
   _intvectcopy = LOADADDR(.intvect) ;
 
diff --git a/firmware/target/arm/rk27xx/boot.lds b/firmware/target/arm/rk27xx/boot.lds
index b7bc9be..03766f3 100644
--- a/firmware/target/arm/rk27xx/boot.lds
+++ b/firmware/target/arm/rk27xx/boot.lds
@@ -12,36 +12,46 @@ STARTUP(target/arm/rk27xx/crt0.o)
 #define DRAMORIG 0x60000000
 #define DRAMSIZE (MEMORYSIZE * 0x100000)
 
+#define RUN_OFFSET 0x700000
+#define DRAM_RUN_ORIG (DRAMORIG + RUN_OFFSET)
+#define DRAM_RUN_SIZE (DRAMSIZE - RUN_OFFSET)
+
 #define IRAMORIG 0x00000000
 #define IRAMSIZE 4K
 
 MEMORY
 {
     DRAM  : ORIGIN = DRAMORIG, LENGTH = DRAMSIZE
+    DRAM_RUN : ORIGIN = DRAM_RUN_ORIG, LENGTH = DRAM_RUN_SIZE
     IRAM  : ORIGIN = IRAMORIG, LENGTH = IRAMSIZE
 }
 
 SECTIONS
 {
+  .bootloader_reloc : {
+    *(.bootloader_reloc)
+  } > DRAM
+
   .intvect : {
     _intvectstart = . ;
-    *(.intvect)
-    _intvectend = _newstart ;  
+    KEEP(*(.intvect))
+    _intvectend = . ;  
   } > IRAM AT > DRAM
   _intvectcopy = LOADADDR(.intvect) ;
 
   .text : {
+    _relocstart = .;
     *(.init.text)
     *(.text*)
     *(.glue_7*)
-  } > DRAM
+  } > DRAM_RUN AT > DRAM 
 
   .data : {
     *(.rodata*)
     *(.data*)
     *(.ncdata*);
     . = ALIGN(0x4);
-  } > DRAM
+  } > DRAM_RUN AT > DRAM
 
   .idata : {
     _datastart = . ;
@@ -50,7 +60,7 @@ SECTIONS
     *(.idata)
     . = ALIGN(0x4);
     _dataend = . ;
-   } > DRAM
+   } > DRAM_RUN AT > DRAM
    _datacopy = LOADADDR(.idata) ;
 
   .stack (NOLOAD) :
@@ -67,7 +77,7 @@ SECTIONS
      _fiqstackbegin = .;
      . += 0x400;
      _fiqstackend = .;
-  } > DRAM
+  } > DRAM_RUN AT > DRAM
 
   .bss (NOLOAD) : {
      _edata = .;
@@ -77,5 +87,7 @@ SECTIONS
      *(COMMON);
     . = ALIGN(0x4);
      _end = .;
-  } > DRAM
+     _relocend = .;
+  } > DRAM_RUN AT > DRAM
+  _reloccopy = LOADADDR(.text) ;
 }
diff --git a/firmware/target/arm/rk27xx/crt0.S b/firmware/target/arm/rk27xx/crt0.S
index 23f3fcf..9d9b5f3 100644
--- a/firmware/target/arm/rk27xx/crt0.S
+++ b/firmware/target/arm/rk27xx/crt0.S
@@ -24,12 +24,36 @@
 #include "config.h"
 #include "cpu.h"
 
+    .global start
+    .global _newstart
+#ifdef BOOTLOADER
+    .section .bootloader_reloc,"ax",%progbits
+start:
+    msr     cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ/FIQ */
+
+    /* setup caches */
+    ldr     r0, =0xefff0000    /* cache controler base address */
+    ldrh    r1, [r0]
+    strh    r1, [r0]          /* global cache disable */
+
+    ldr     r2, =_relocstart
+    ldr     r3, =_relocend
+    ldr     r4, =_reloccopy
+1:
+    cmp     r3, r2
+    ldrhi   r1, [r4], #4
+    strhi   r1, [r2], #4
+    bhi     1b
+    ldr     pc, =_newstart
+    .ltorg
+#endif
+
     .section .intvect,"ax",%progbits
-    .global    start
-    .global    _newstart
     /* Exception vectors */
+#ifndef BOOTLOADER
 start:
-    b _newstart
+#endif
+    ldr pc, =_newstart
     ldr pc, =undef_instr_handler
     ldr pc, =software_int_handler
     ldr pc, =prefetch_abort_handler
@@ -38,12 +62,10 @@ start:
     ldr pc, =irq_handler
     ldr pc, =fiq_handler
     .ltorg
-_newstart:
-    ldr pc, =newstart2
+
     .section .init.text,"ax",%progbits
-newstart2:
+_newstart:
     msr     cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ/FIQ */
-
     mov     r0, #0x18000000
     add     r0, r0, #0x1c000
 
@@ -184,7 +206,6 @@ newstart2:
     strhi   r3, [r2], #4
     bhi     1b
 
-
     bl      main
 
     .text
diff --git a/firmware/target/arm/rk27xx/sd-rk27xx.c b/firmware/target/arm/rk27xx/sd-rk27xx.c
index f3081d2..b6cd88f 100644
--- a/firmware/target/arm/rk27xx/sd-rk27xx.c
+++ b/firmware/target/arm/rk27xx/sd-rk27xx.c
@@ -402,6 +402,7 @@ static void init_controller(void)
     SCU_IOMUXA_CON |= IOMUX_SD;
 
     /* enable and unmask SD interrupts in interrupt controller */
+    SCU_CLKCFG &= ~(1<<22);
     INTC_IMR |= (1<<10);
     INTC_IECR |= (1<<10);
 
diff --git a/tools/Makefile b/tools/Makefile
index da0d3df..2b4b1ae 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -18,10 +18,10 @@ all: scramble descramble sh2d rdf2binary mkboot mkzenboot convbdf codepages \
   uclpack rbspeexenc voicefont mk500boot
 
 scramble: scramble.o iriver.o mi4.o gigabeat.o gigabeats.o telechips.o \
-  iaudio_bl_flash.o creative.o hmac-sha1.o
+  iaudio_bl_flash.o creative.o hmac-sha1.o rkw.o
 descramble: descramble.o iriver.o gigabeat.o
 scramble.o: scramble.c iriver.h mi4.h gigabeat.h telechips.h iaudio_bl_flash.h \
-  creative.h
+  creative.h rkw.h
 
 descramble.o: descramble.c iriver.h gigabeat.h
 creative.o: creative.c creative.h
@@ -31,6 +31,7 @@ gigabeat.o: gigabeat.c gigabeat.h
 gigabeats.o: gigabeats.c gigabeats.h
 mi4.o: mi4.c mi4.h
 telechips.o: telechips.c telechips.h
+rkw.o: rkw.c rkw.h
 iaudio_bl_flash.o: iaudio_bl_flash.c iaudio_bl_flash.h
 iaudio_bl_flash.c iaudio_bl_flash.h: iaudio_bl_flash.bmp bmp2rb
   $(SILENT)./bmp2rb -f 7 -h . $< >iaudio_bl_flash.c
diff --git a/tools/configure b/tools/configure
index ee76ed7..fc141d7 100755
--- a/tools/configure
+++ b/tools/configure
@@ -3082,11 +3082,11 @@ fi
     target="RK27_GENERIC"
     memory=16 # always
     arm7ejscc
-    tool="$rootdir/tools/scramble -add=rk27"
+    tool="$rootdir/tools/scramble -rkw"
     bmp2rb_mono="$rootdir/tools/bmp2rb -f 0"
     bmp2rb_native="$rootdir/tools/bmp2rb -f 4"
-    output="rockbox.rk27"
-    bootoutput="bootloader.rk27"
+    output="rockbox.rkw"
+    bootoutput="bootloader.rkw"
     appextra="recorder:gui:radio"
     plugins="yes"
     swcodec="yes"
@@ -3105,11 +3105,11 @@ fi
     target="HM60X"
     memory=16
     arm7ejscc
-    tool="$rootdir/tools/scramble -add=rk27"
+    tool="$rootdir/tools/scramble -rkw"
     bmp2rb_mono="$rootdir/tools/bmp2rb -f 0"
     bmp2rb_native="$rootdir/tools/bmp2rb -f 4"
-    output="rockbox.rk27"
-    bootoutput="bootloader.rk27"
+    output="rockbox.rkw"
+    bootoutput="bootloader.rkw"
     appextra="recorder:gui"
     plugins="yes"
     swcodec="yes"
@@ -3128,11 +3128,11 @@ fi
     target="HM801"
     memory=16
     arm7ejscc
-    tool="$rootdir/tools/scramble -add=rk27"
+    tool="$rootdir/tools/scramble -rkw"
     bmp2rb_mono="$rootdir/tools/bmp2rb -f 0"
     bmp2rb_native="$rootdir/tools/bmp2rb -f 4"
-    output="rockbox.rk27"
-    bootoutput="bootloader.rk27"
+    output="rockbox.rkw"
+    bootoutput="bootloader.rkw"
     appextra="recorder:gui"
     plugins="yes"
     swcodec="yes"
diff --git a/tools/rkw.c b/tools/rkw.c
new file mode 100644
index 0000000..796d93c
--- /dev/null
+++ b/tools/rkw.c
@@ -0,0 +1,164 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ *
+ * Copyright (C) 2012 Marcin Bukat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#define RKLD_MAGIC 0x4c44524b
+#define RKW_HEADER_SIZE 0x2c
+
+/* slightly modified version from crc32.c in rockbox */
+static uint32_t rkw_crc32(const void *src, uint32_t len)
+{
+    const unsigned char *buf = (const unsigned char *)src;
+
+    /* polynomial 0x04c10db7 */
+    static const uint32_t crc32_lookup[16] =
+    {   /* lookup table for 4 bits at a time is affordable */
+        0x00000000, 0x04C10DB7, 0x09821B6E, 0x0D4316D9,
+        0x130436DC, 0x17C53B6B, 0x1A862DB2, 0x1E472005,
+        0x26086DB8, 0x22C9600F, 0x2F8A76D6, 0x2B4B7B61,
+        0x350C5B64, 0x31CD56D3, 0x3C8E400A, 0x384F4DBD
+    };
+
+    uint32_t crc32 = 0;
+    unsigned char byte;
+    uint32_t t;
+
+    while (len--)
+    {
+        byte = *buf++; /* get one byte of data */
+
+        /* upper nibble of our data */
+        t = crc32 >> 28; /* extract the 4 most significant bits */
+        t ^= byte >> 4; /* XOR in 4 bits of data into the extracted bits */
+        crc32 <<= 4; /* shift the CRC register left 4 bits */
+        crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */
+
+        /* lower nibble of our data */
+        t = crc32 >> 28; /* extract the 4 most significant bits */
+        t ^= byte & 0x0F; /* XOR in 4 bits of data into the extracted bits */
+        crc32 <<= 4; /* shift the CRC register left 4 bits */
+        crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */
+    }
+
+    return crc32;
+}
+
+static void int2le(unsigned int val, unsigned char* addr)
+{
+    addr[0] = val & 0xFF;
+    addr[1] = (val >> 8) & 0xff;
+    addr[2] = (val >> 16) & 0xff;
+    addr[3] = (val >> 24) & 0xff;
+}
+
+int rkw_encode(char *iname, char *oname)
+{
+    size_t len;
+    int length;
+    int rkwlength;
+    FILE *file;
+    uint32_t binary_crc, header_crc;
+    unsigned char *outbuf;
+
+    file = fopen(iname, "rb");
+    if (!file)
+    {
+       perror(iname);
+       return -1;
+    }
+
+    fseek(file,0,SEEK_END);
+    length = ftell(file);
+    
+    fseek(file,0,SEEK_SET);
+
+    /* length of the RKW header + binary length + 4 bytes of CRC */
+    rkwlength = (length + RKW_HEADER_SIZE + 4);
+
+    outbuf = malloc(rkwlength);
+
+    if (!outbuf)
+    {
+       printf("out of memory!\n");
+       fclose(file);
+       return -1;
+    }
+
+    /* Clear the buffer to zero */
+    memset(outbuf, 0, rkwlength);
+
+    /* Build the RKW header */
+    int2le(RKLD_MAGIC, outbuf);                /* magic */
+    int2le(RKW_HEADER_SIZE, outbuf+0x04);      /* header size */
+    int2le(0x60000000, outbuf+0x08);           /* base address */
+    int2le(0x60000000, outbuf+0x0c);           /* load address */
+    int2le(0x60000000+length, outbuf+0x10);    /* end address */
+    int2le(0x6035a5e4, outbuf+0x14);           /* bss address (not used) */
+    int2le(0, outbuf+0x18);                    /* reserved */
+    int2le(0, outbuf+0x1c);                    /* reserved */
+    int2le(0x60000000, outbuf+0x20);           /* entry point */
+    int2le(0xe0000000, outbuf+0x24);           /* flags */
+
+    header_crc = rkw_crc32(outbuf, RKW_HEADER_SIZE - 4);
+
+    int2le(header_crc, outbuf+0x28);           /* header CRC */
+
+    /* Copy the binary */
+    len = fread(outbuf + RKW_HEADER_SIZE, 1, length, file);
+    if(len < (size_t)length)
+    {
+        perror(iname);
+        free(outbuf);
+        fclose(file);
+        return -2;
+    }
+    fclose(file);
+
+    /* calc binary CRC and put at the end */
+    binary_crc = rkw_crc32 (outbuf + RKW_HEADER_SIZE, length);
+    int2le(binary_crc, outbuf + rkwlength - 4);
+
+    file = fopen(oname, "wb");
+    if (!file)
+    {
+        perror(oname);
+        free(outbuf);
+        return -3;
+    }
+    
+    len = fwrite(outbuf, 1, rkwlength, file);
+    if(len < (size_t)length)
+    {
+        perror(oname);
+        fclose(file);
+        free(outbuf);
+        return -4;
+    }
+
+    fclose(file);
+    free(outbuf);
+    fprintf(stderr, "File encoded successfully\n" );
+
+    return 0;
+}
diff --git a/tools/rkw.h b/tools/rkw.h
new file mode 100644
index 0000000..583f171
--- /dev/null
+++ b/tools/rkw.h
@@ -0,0 +1,26 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ *
+ * Copyright (C) 2012 Marcin Bukat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _RKW_H
+#define _RKW_H
+
+int rkw_encode(char *iname, char *oname);
+
+#endif
diff --git a/tools/scramble.c b/tools/scramble.c
index 7c7a847..130f2a0 100644
--- a/tools/scramble.c
+++ b/tools/scramble.c
@@ -30,6 +30,7 @@
 #include "telechips.h"
 #include "creative.h"
 #include "iaudio_bl_flash.h"
+#include "rkw.h"
 
 static int iaudio_encode(char *iname, char *oname, char *idstring);
 static int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc);
@@ -119,11 +120,12 @@ void usage(void)
            "\t        -type=XXXX    where XXXX is a string indicating the \n"
            "\t                      type of binary, eg. RBOS, RBBL\n"
            "\t-tcc=X  Telechips generic firmware format (X values: sum, crc)\n"
+           "\t-rkw Rockchip RKW format\n"
            "\t-add=X  Rockbox generic \"add-up\" checksum format\n"
            "\t        (X values: h100, h120, h140, h300, ipco, nano, ipvd, mn2g\n"
-           "\t                   ip3g, ip4g, mini, iax5, iam5, iam3, h10, h10_5gb,\n"
-           "\t                   tpj2, c200, e200, giga, gigs, m100, m500, d2,\n");
-    printf("\t                   9200, 1630, 6330, ldax, m200, c100, clip, e2v2,\n"
+           "\t                   ip3g, ip4g, mini, iax5, iam5, iam3, h10, h10_5gb,\n");
+    printf("\t                   tpj2, c200, e200, giga, gigs, m100, m500, d2,\n"
+           "\t                   9200, 1630, 6330, ldax, m200, c100, clip, e2v2,\n"
            "\t                   m2v4, fuze, c2v2, clv2, y820, y920, y925, x747,\n"
            "\t                   747p, x777, nn2g, m244, cli+, fuz2, hd20, hd30,\n"
            "\t                   ip6g, rk27, clzp)\n");
@@ -148,7 +150,7 @@ int main (int argc, char** argv)
     unsigned long modelnum;
     char modelname[5];
     int model_id;
-    enum { none, scramble, xor, tcc_sum, tcc_crc, add } method = scramble;
+    enum { none, scramble, xor, tcc_sum, tcc_crc, rkw, add } method = scramble;
     bool creative_enable_ciff;
 
     model_id = ARCHOS_PLAYER;
@@ -222,6 +224,11 @@ int main (int argc, char** argv)
             return 2;
         }
     }
+    else if(!strncmp(argv[1], "-rkw", 4)) {
+        iname = argv[2];
+        oname = argv[3];
+        return (rkw_encode(iname, oname) != 0) ? -1 : 0;
+    }
     else if(!strncmp(argv[1], "-add=", 5)) {
         iname = argv[2];
         oname = argv[3];
@@ -337,8 +344,6 @@ int main (int argc, char** argv)
             modelnum = 71;
         else if (!strcmp(&argv[1][5], "fuz+")) /* Sansa Fuze+ */
             modelnum = 72;
-        else if (!strcmp(&argv[1][5], "rk27")) /* rockchip 27xx generic */
-            modelnum = 73;
         else if (!strcmp(&argv[1][5], "clzp")) /* Sansa Clip Zip */
             modelnum = 79;
         else if (!strcmp(&argv[1][5], "conn")) /* Sansa Connect */
diff --git a/tools/tools.make b/tools/tools.make
index c143157..3350ad0 100644
--- a/tools/tools.make
+++ b/tools/tools.make
@@ -13,7 +13,9 @@ $(TOOLSDIR)/scramble: $(TOOLSDIR)/scramble.c $(TOOLSDIR)/iriver.c \
     $(TOOLSDIR)/mi4.c $(TOOLSDIR)/gigabeat.c \
     $(TOOLSDIR)/gigabeats.c $(TOOLSDIR)/telechips.c \
     $(TOOLSDIR)/iaudio_bl_flash.c \
-    $(TOOLSDIR)/creative.c $(TOOLSDIR)/hmac-sha1.c
+    $(TOOLSDIR)/creative.c $(TOOLSDIR)/hmac-sha1.c \
+    $(TOOLSDIR)/rkw.c
+
 $(TOOLSDIR)/rdf2binary:  $(TOOLSDIR)/rdf2binary.c
 $(TOOLSDIR)/convbdf: $(TOOLSDIR)/convbdf.c
 $(TOOLSDIR)/codepages: $(TOOLSDIR)/codepages.c $(TOOLSDIR)/codepage_tables.c
diff --git a/utils/rk27utils/rk27load/Makefile b/utils/rk27utils/rk27load/Makefile
index f777e76..9bc9301 100644
--- a/utils/rk27utils/rk27load/Makefile
+++ b/utils/rk27utils/rk27load/Makefile
@@ -1,7 +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/ $^
+  gcc -g -std=c99 -o $@ -W -Wall -I/usr/include/libusb-1.0/ $^ -lusb-1.0
 
 clean:
   rm -fr *.o rk27load