From 412a8f99928beff605805807b0f07f6bf8d0a965 Mon Sep 17 00:00:00 2001
From: Uros Majstorovic <majstor@majstor.org>
Date: Fri, 13 May 2022 12:45:53 +0200
Subject: code rename

---
 fw/fe310/eos/cam.c             | 138 -------
 fw/fe310/eos/cam.h             |  88 -----
 fw/fe310/eos/cell.c            |  51 ---
 fw/fe310/eos/cell.h            |  51 ---
 fw/fe310/eos/dev/Makefile      |  16 +
 fw/fe310/eos/dev/bq25895.c     |  43 ++
 fw/fe310/eos/dev/bq25895.h     |   5 +
 fw/fe310/eos/dev/cam.c         | 138 +++++++
 fw/fe310/eos/dev/cam.h         |  88 +++++
 fw/fe310/eos/dev/drv2605.h     |   3 +
 fw/fe310/eos/dev/lcd.c         | 546 ++++++++++++++++++++++++++
 fw/fe310/eos/dev/lcd.h         |  12 +
 fw/fe310/eos/dev/lsm9ds1.h     |   4 +
 fw/fe310/eos/dev/ov2640.c      | 861 +++++++++++++++++++++++++++++++++++++++++
 fw/fe310/eos/dev/ov2640.h      |   8 +
 fw/fe310/eos/dev/ov2640_regs.h | 245 ++++++++++++
 fw/fe310/eos/dev/sdc_crypto.c  |  51 +++
 fw/fe310/eos/dev/sdc_crypto.h  |  18 +
 fw/fe310/eos/dev/sdcard.c      | 539 ++++++++++++++++++++++++++
 fw/fe310/eos/dev/sdcard.h      |  22 ++
 fw/fe310/eos/i2c.c             | 145 -------
 fw/fe310/eos/i2c.h             |  13 -
 fw/fe310/eos/i2c/Makefile      |  16 -
 fw/fe310/eos/i2c/bq25895.c     |  43 --
 fw/fe310/eos/i2c/bq25895.h     |   5 -
 fw/fe310/eos/i2c/drv2605.h     |   3 -
 fw/fe310/eos/i2c/lsm9ds1.h     |   4 -
 fw/fe310/eos/i2c/ov2640.c      | 861 -----------------------------------------
 fw/fe310/eos/i2c/ov2640.h      |   8 -
 fw/fe310/eos/i2c/ov2640_regs.h | 245 ------------
 fw/fe310/eos/i2s.c             | 477 -----------------------
 fw/fe310/eos/i2s.h             |  38 --
 fw/fe310/eos/i2s_def.h         |   8 -
 fw/fe310/eos/i2s_priv.h        |   8 -
 fw/fe310/eos/interrupt.c       |  75 ----
 fw/fe310/eos/interrupt.h       |  13 -
 fw/fe310/eos/lcd.c             | 546 --------------------------
 fw/fe310/eos/lcd.h             |  12 -
 fw/fe310/eos/net.c             | 602 ----------------------------
 fw/fe310/eos/net.h             |  47 ---
 fw/fe310/eos/net/cell.c        |  51 +++
 fw/fe310/eos/net/cell.h        |  51 +++
 fw/fe310/eos/net/rng.c         |  27 ++
 fw/fe310/eos/net/rng.h         |   5 +
 fw/fe310/eos/net/sock.c        | 154 ++++++++
 fw/fe310/eos/net/sock.h        |  28 ++
 fw/fe310/eos/net/wifi.c        | 106 +++++
 fw/fe310/eos/net/wifi.h        |  18 +
 fw/fe310/eos/pwr.c             | 133 -------
 fw/fe310/eos/pwr.h             |  25 --
 fw/fe310/eos/rng.c             |  27 --
 fw/fe310/eos/rng.h             |   5 -
 fw/fe310/eos/sdc_crypto.c      |  51 ---
 fw/fe310/eos/sdc_crypto.h      |  18 -
 fw/fe310/eos/sdcard.c          | 539 --------------------------
 fw/fe310/eos/sdcard.h          |  22 --
 fw/fe310/eos/soc/i2c.c         | 145 +++++++
 fw/fe310/eos/soc/i2c.h         |  13 +
 fw/fe310/eos/soc/i2s.c         | 477 +++++++++++++++++++++++
 fw/fe310/eos/soc/i2s.h         |  38 ++
 fw/fe310/eos/soc/i2s_def.h     |   8 +
 fw/fe310/eos/soc/i2s_priv.h    |   8 +
 fw/fe310/eos/soc/interrupt.c   |  75 ++++
 fw/fe310/eos/soc/interrupt.h   |  13 +
 fw/fe310/eos/soc/net.c         | 602 ++++++++++++++++++++++++++++
 fw/fe310/eos/soc/net.h         |  47 +++
 fw/fe310/eos/soc/pwr.c         | 133 +++++++
 fw/fe310/eos/soc/pwr.h         |  25 ++
 fw/fe310/eos/soc/spi.c         | 350 +++++++++++++++++
 fw/fe310/eos/soc/spi.h         |  28 ++
 fw/fe310/eos/soc/spi_cfg.h     |  37 ++
 fw/fe310/eos/soc/spi_dev.c     |  97 +++++
 fw/fe310/eos/soc/spi_dev.h     |  19 +
 fw/fe310/eos/soc/spi_priv.h    |   8 +
 fw/fe310/eos/soc/timer.c       | 137 +++++++
 fw/fe310/eos/soc/timer.h       |  23 ++
 fw/fe310/eos/soc/trap_entry.S  | 554 ++++++++++++++++++++++++++
 fw/fe310/eos/soc/uart.c        | 114 ++++++
 fw/fe310/eos/soc/uart.h        |  24 ++
 fw/fe310/eos/sock.c            | 154 --------
 fw/fe310/eos/sock.h            |  28 --
 fw/fe310/eos/spi.c             | 350 -----------------
 fw/fe310/eos/spi.h             |  28 --
 fw/fe310/eos/spi_cfg.h         |  37 --
 fw/fe310/eos/spi_dev.c         |  97 -----
 fw/fe310/eos/spi_dev.h         |  19 -
 fw/fe310/eos/spi_priv.h        |   8 -
 fw/fe310/eos/timer.c           | 137 -------
 fw/fe310/eos/timer.h           |  23 --
 fw/fe310/eos/trap_entry.S      | 554 --------------------------
 fw/fe310/eos/uart.c            | 114 ------
 fw/fe310/eos/uart.h            |  24 --
 fw/fe310/eos/wifi.c            | 106 -----
 fw/fe310/eos/wifi.h            |  18 -
 94 files changed, 6014 insertions(+), 6014 deletions(-)
 delete mode 100644 fw/fe310/eos/cam.c
 delete mode 100644 fw/fe310/eos/cam.h
 delete mode 100644 fw/fe310/eos/cell.c
 delete mode 100644 fw/fe310/eos/cell.h
 create mode 100644 fw/fe310/eos/dev/Makefile
 create mode 100644 fw/fe310/eos/dev/bq25895.c
 create mode 100644 fw/fe310/eos/dev/bq25895.h
 create mode 100644 fw/fe310/eos/dev/cam.c
 create mode 100644 fw/fe310/eos/dev/cam.h
 create mode 100644 fw/fe310/eos/dev/drv2605.h
 create mode 100644 fw/fe310/eos/dev/lcd.c
 create mode 100644 fw/fe310/eos/dev/lcd.h
 create mode 100644 fw/fe310/eos/dev/lsm9ds1.h
 create mode 100644 fw/fe310/eos/dev/ov2640.c
 create mode 100644 fw/fe310/eos/dev/ov2640.h
 create mode 100644 fw/fe310/eos/dev/ov2640_regs.h
 create mode 100644 fw/fe310/eos/dev/sdc_crypto.c
 create mode 100644 fw/fe310/eos/dev/sdc_crypto.h
 create mode 100644 fw/fe310/eos/dev/sdcard.c
 create mode 100644 fw/fe310/eos/dev/sdcard.h
 delete mode 100644 fw/fe310/eos/i2c.c
 delete mode 100644 fw/fe310/eos/i2c.h
 delete mode 100644 fw/fe310/eos/i2c/Makefile
 delete mode 100644 fw/fe310/eos/i2c/bq25895.c
 delete mode 100644 fw/fe310/eos/i2c/bq25895.h
 delete mode 100644 fw/fe310/eos/i2c/drv2605.h
 delete mode 100644 fw/fe310/eos/i2c/lsm9ds1.h
 delete mode 100644 fw/fe310/eos/i2c/ov2640.c
 delete mode 100644 fw/fe310/eos/i2c/ov2640.h
 delete mode 100644 fw/fe310/eos/i2c/ov2640_regs.h
 delete mode 100644 fw/fe310/eos/i2s.c
 delete mode 100644 fw/fe310/eos/i2s.h
 delete mode 100644 fw/fe310/eos/i2s_def.h
 delete mode 100644 fw/fe310/eos/i2s_priv.h
 delete mode 100644 fw/fe310/eos/interrupt.c
 delete mode 100644 fw/fe310/eos/interrupt.h
 delete mode 100644 fw/fe310/eos/lcd.c
 delete mode 100644 fw/fe310/eos/lcd.h
 delete mode 100644 fw/fe310/eos/net.c
 delete mode 100644 fw/fe310/eos/net.h
 create mode 100644 fw/fe310/eos/net/cell.c
 create mode 100644 fw/fe310/eos/net/cell.h
 create mode 100644 fw/fe310/eos/net/rng.c
 create mode 100644 fw/fe310/eos/net/rng.h
 create mode 100644 fw/fe310/eos/net/sock.c
 create mode 100644 fw/fe310/eos/net/sock.h
 create mode 100644 fw/fe310/eos/net/wifi.c
 create mode 100644 fw/fe310/eos/net/wifi.h
 delete mode 100644 fw/fe310/eos/pwr.c
 delete mode 100644 fw/fe310/eos/pwr.h
 delete mode 100644 fw/fe310/eos/rng.c
 delete mode 100644 fw/fe310/eos/rng.h
 delete mode 100644 fw/fe310/eos/sdc_crypto.c
 delete mode 100644 fw/fe310/eos/sdc_crypto.h
 delete mode 100644 fw/fe310/eos/sdcard.c
 delete mode 100644 fw/fe310/eos/sdcard.h
 create mode 100644 fw/fe310/eos/soc/i2c.c
 create mode 100644 fw/fe310/eos/soc/i2c.h
 create mode 100644 fw/fe310/eos/soc/i2s.c
 create mode 100644 fw/fe310/eos/soc/i2s.h
 create mode 100644 fw/fe310/eos/soc/i2s_def.h
 create mode 100644 fw/fe310/eos/soc/i2s_priv.h
 create mode 100644 fw/fe310/eos/soc/interrupt.c
 create mode 100644 fw/fe310/eos/soc/interrupt.h
 create mode 100644 fw/fe310/eos/soc/net.c
 create mode 100644 fw/fe310/eos/soc/net.h
 create mode 100644 fw/fe310/eos/soc/pwr.c
 create mode 100644 fw/fe310/eos/soc/pwr.h
 create mode 100644 fw/fe310/eos/soc/spi.c
 create mode 100644 fw/fe310/eos/soc/spi.h
 create mode 100644 fw/fe310/eos/soc/spi_cfg.h
 create mode 100644 fw/fe310/eos/soc/spi_dev.c
 create mode 100644 fw/fe310/eos/soc/spi_dev.h
 create mode 100644 fw/fe310/eos/soc/spi_priv.h
 create mode 100644 fw/fe310/eos/soc/timer.c
 create mode 100644 fw/fe310/eos/soc/timer.h
 create mode 100644 fw/fe310/eos/soc/trap_entry.S
 create mode 100644 fw/fe310/eos/soc/uart.c
 create mode 100644 fw/fe310/eos/soc/uart.h
 delete mode 100644 fw/fe310/eos/sock.c
 delete mode 100644 fw/fe310/eos/sock.h
 delete mode 100644 fw/fe310/eos/spi.c
 delete mode 100644 fw/fe310/eos/spi.h
 delete mode 100644 fw/fe310/eos/spi_cfg.h
 delete mode 100644 fw/fe310/eos/spi_dev.c
 delete mode 100644 fw/fe310/eos/spi_dev.h
 delete mode 100644 fw/fe310/eos/spi_priv.h
 delete mode 100644 fw/fe310/eos/timer.c
 delete mode 100644 fw/fe310/eos/timer.h
 delete mode 100644 fw/fe310/eos/trap_entry.S
 delete mode 100644 fw/fe310/eos/uart.c
 delete mode 100644 fw/fe310/eos/uart.h
 delete mode 100644 fw/fe310/eos/wifi.c
 delete mode 100644 fw/fe310/eos/wifi.h

(limited to 'fw')

diff --git a/fw/fe310/eos/cam.c b/fw/fe310/eos/cam.c
deleted file mode 100644
index 43293af..0000000
--- a/fw/fe310/eos/cam.c
+++ /dev/null
@@ -1,138 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-
-#include "eos.h"
-#include "spi.h"
-#include "cam.h"
-
-const int _eos_cam_resolution[][2] = {
-    {0,    0   },
-    // C/SIF Resolutions
-    {88,   72  },    /* QQCIF     */
-    {176,  144 },    /* QCIF      */
-    {352,  288 },    /* CIF       */
-    {88,   60  },    /* QQSIF     */
-    {176,  120 },    /* QSIF      */
-    {352,  240 },    /* SIF       */
-    // VGA Resolutions
-    {40,   30  },    /* QQQQVGA   */
-    {80,   60  },    /* QQQVGA    */
-    {160,  120 },    /* QQVGA     */
-    {320,  240 },    /* QVGA      */
-    {640,  480 },    /* VGA       */
-    {60,   40  },    /* HQQQVGA   */
-    {120,  80  },    /* HQQVGA    */
-    {240,  160 },    /* HQVGA     */
-    // FFT Resolutions
-    {64,   32  },    /* 64x32     */
-    {64,   64  },    /* 64x64     */
-    {128,  64  },    /* 128x64    */
-    {128,  128 },    /* 128x128   */
-    {320,  320 },    /* 128x128   */
-    // Other
-    {128,  160 },    /* LCD       */
-    {128,  160 },    /* QQVGA2    */
-    {720,  480 },    /* WVGA      */
-    {752,  480 },    /* WVGA2     */
-    {800,  600 },    /* SVGA      */
-    {1024, 768 },    /* XGA       */
-    {1280, 1024},    /* SXGA      */
-    {1600, 1200},    /* UXGA      */
-    {1280, 720 },    /* HD        */
-    {1920, 1080},    /* FHD       */
-    {2560, 1440},    /* QHD       */
-    {2048, 1536},    /* QXGA      */
-    {2560, 1600},    /* WQXGA     */
-    {2592, 1944},    /* WQXGA2    */
-};
-
-#define CAM_REG_CAPTURE_CTRL        0x01
-#define CAM_REG_FIFO_CTRL           0x04
-
-#define CAM_REG_GPIO_DIR            0x05
-#define CAM_REG_GPIO_WR             0x06
-#define CAM_REG_GPIO_RD             0x45
-
-#define CAM_REG_STATUS              0x41
-
-#define CAM_REG_VER                 0x40
-
-#define CAM_REG_READ_BURST          0x3c
-#define CAM_REG_READ_BYTE           0x3d
-
-#define CAM_REG_FIFO_SIZE1          0x42
-#define CAM_REG_FIFO_SIZE2          0x43
-#define CAM_REG_FIFO_SIZE3          0x44
-
-#define CAM_VAL_FIFO_CTRL_CLEAR     0x01
-#define CAM_VAL_FIFO_CTRL_START     0x02
-#define CAM_VAL_FIFO_CTRL_RSTWR     0x10
-#define CAM_VAL_FIFO_CTRL_RSTRD     0x20
-
-#define CAM_VAL_STATUS_VSYNC        0x01
-#define CAM_VAL_STATUS_SHUTTER      0x02
-#define CAM_VAL_STATUS_CPTDONE      0x08
-
-#define CAM_VAL_GPIO_RST            0x01
-#define CAM_VAL_GPIO_PWRDN          0x02
-#define CAM_VAL_GPIO_PWREN          0x04
-
-static uint8_t reg_read(uint8_t addr) {
-    uint8_t ret;
-
-    eos_spi_cs_set();
-    eos_spi_xchg8(addr, 0);
-    ret = eos_spi_xchg8(0, 0);
-    eos_spi_cs_clear();
-
-    return ret;
-}
-
-static void reg_write(uint8_t addr, uint8_t val) {
-    eos_spi_cs_set();
-    eos_spi_xchg8(addr | 0x80, 0);
-    eos_spi_xchg8(val, 0);
-    eos_spi_cs_clear();
-}
-
-void eos_cam_capture(void) {
-    reg_write(CAM_REG_FIFO_CTRL, CAM_VAL_FIFO_CTRL_START);
-}
-
-int eos_cam_capture_done(void) {
-    return !!(reg_read(CAM_REG_STATUS) & CAM_VAL_STATUS_CPTDONE);
-}
-
-void eos_cam_capture_wait(void) {
-    int done = 0;
-    
-    while (!done) {
-        done = eos_cam_capture_done();
-    }
-}
-
-uint32_t eos_cam_fbuf_size(void) {
-    uint32_t ret;
-    
-	ret = reg_read(CAM_REG_FIFO_SIZE1);
-    ret |= reg_read(CAM_REG_FIFO_SIZE2) << 8;
-    ret |= (reg_read(CAM_REG_FIFO_SIZE3) & 0x7f) << 16;
-    return ret;
-}
-
-void eos_cam_fbuf_read(uint8_t *buffer, uint16_t sz, int first) {
-    int i;
-    
-    eos_spi_cs_set();
-    eos_spi_xchg8(CAM_REG_READ_BURST, 0);
-    if (first) eos_spi_xchg8(0, 0);
-
-    for (i=0; i<sz; i++) {
-        buffer[i] = eos_spi_xchg8(0, 0);
-    }
-    eos_spi_cs_clear();
-}
-
-void eos_cam_fbuf_done(void) {
-    reg_write(CAM_REG_FIFO_CTRL, CAM_VAL_FIFO_CTRL_CLEAR);
-}
diff --git a/fw/fe310/eos/cam.h b/fw/fe310/eos/cam.h
deleted file mode 100644
index f61757b..0000000
--- a/fw/fe310/eos/cam.h
+++ /dev/null
@@ -1,88 +0,0 @@
-#include <stdint.h>
-
-typedef enum {
-    PIXFORMAT_INVALID = 0,
-    PIXFORMAT_BINARY,    // 1BPP/BINARY
-    PIXFORMAT_GRAYSCALE, // 1BPP/GRAYSCALE
-    PIXFORMAT_RGB565,    // 2BPP/RGB565
-    PIXFORMAT_YUV422,    // 2BPP/YUV422
-    PIXFORMAT_BAYER,     // 1BPP/RAW
-    PIXFORMAT_JPEG,      // JPEG/COMPRESSED
-} pixformat_t;
-
-typedef enum {
-    FRAMESIZE_INVALID = 0,
-    // C/SIF Resolutions
-    FRAMESIZE_QQCIF,    // 88x72
-    FRAMESIZE_QCIF,     // 176x144
-    FRAMESIZE_CIF,      // 352x288
-    FRAMESIZE_QQSIF,    // 88x60
-    FRAMESIZE_QSIF,     // 176x120
-    FRAMESIZE_SIF,      // 352x240
-    // VGA Resolutions
-    FRAMESIZE_QQQQVGA,  // 40x30
-    FRAMESIZE_QQQVGA,   // 80x60
-    FRAMESIZE_QQVGA,    // 160x120
-    FRAMESIZE_QVGA,     // 320x240
-    FRAMESIZE_VGA,      // 640x480
-    FRAMESIZE_HQQQVGA,  // 60x40
-    FRAMESIZE_HQQVGA,   // 120x80
-    FRAMESIZE_HQVGA,    // 240x160
-    // FFT Resolutions
-    FRAMESIZE_64X32,    // 64x32
-    FRAMESIZE_64X64,    // 64x64
-    FRAMESIZE_128X64,   // 128x64
-    FRAMESIZE_128X128,  // 128x128
-    FRAMESIZE_320X320,  // 320x320
-    // Other
-    FRAMESIZE_LCD,      // 128x160
-    FRAMESIZE_QQVGA2,   // 128x160
-    FRAMESIZE_WVGA,     // 720x480
-    FRAMESIZE_WVGA2,    // 752x480
-    FRAMESIZE_SVGA,     // 800x600
-    FRAMESIZE_XGA,      // 1024x768
-    FRAMESIZE_SXGA,     // 1280x1024
-    FRAMESIZE_UXGA,     // 1600x1200
-    FRAMESIZE_HD,       // 1280x720
-    FRAMESIZE_FHD,      // 1920x1080
-    FRAMESIZE_QHD,      // 2560x1440
-    FRAMESIZE_QXGA,     // 2048x1536
-    FRAMESIZE_WQXGA,    // 2560x1600
-    FRAMESIZE_WQXGA2,   // 2592x1944
-} framesize_t;
-
-typedef enum {
-    GAINCEILING_2X,
-    GAINCEILING_4X,
-    GAINCEILING_8X,
-    GAINCEILING_16X,
-    GAINCEILING_32X,
-    GAINCEILING_64X,
-    GAINCEILING_128X,
-} gainceiling_t;
-
-typedef enum {
-    SDE_NORMAL,
-    SDE_NEGATIVE,
-} sde_t;
-
-extern const int _eos_cam_resolution[][2];
-
-#define IM_LOG2_2(x)    (((x) &                0x2ULL) ? ( 2                        ) :             1) // NO ({ ... }) !
-#define IM_LOG2_4(x)    (((x) &                0xCULL) ? ( 2 +  IM_LOG2_2((x) >>  2)) :  IM_LOG2_2(x)) // NO ({ ... }) !
-#define IM_LOG2_8(x)    (((x) &               0xF0ULL) ? ( 4 +  IM_LOG2_4((x) >>  4)) :  IM_LOG2_4(x)) // NO ({ ... }) !
-#define IM_LOG2_16(x)   (((x) &             0xFF00ULL) ? ( 8 +  IM_LOG2_8((x) >>  8)) :  IM_LOG2_8(x)) // NO ({ ... }) !
-#define IM_LOG2_32(x)   (((x) &         0xFFFF0000ULL) ? (16 + IM_LOG2_16((x) >> 16)) : IM_LOG2_16(x)) // NO ({ ... }) !
-#define IM_LOG2(x)      (((x) & 0xFFFFFFFF00000000ULL) ? (32 + IM_LOG2_32((x) >> 32)) : IM_LOG2_32(x)) // NO ({ ... }) !
-
-#define IM_MAX(a,b)     ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a > _b ? _a : _b; })
-#define IM_MIN(a,b)     ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a < _b ? _a : _b; })
-#define IM_DIV(a,b)     ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _b ? (_a / _b) : 0; })
-#define IM_MOD(a,b)     ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _b ? (_a % _b) : 0; })
-
-void eos_cam_capture(void);
-int eos_cam_capture_done(void);
-void eos_cam_capture_wait(void);
-uint32_t eos_cam_fbuf_size(void);
-void eos_cam_fbuf_read(uint8_t *buffer, uint16_t sz, int first);
-void eos_cam_fbuf_done(void);
diff --git a/fw/fe310/eos/cell.c b/fw/fe310/eos/cell.c
deleted file mode 100644
index 20a9f42..0000000
--- a/fw/fe310/eos/cell.c
+++ /dev/null
@@ -1,51 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-
-#include "eos.h"
-#include "event.h"
-#include "net.h"
-
-#include "cell.h"
-
-static eos_evt_handler_t evt_handler[EOS_CELL_MAX_MTYPE];
-
-static void cell_handle_msg(unsigned char type, unsigned char *buffer, uint16_t len) {
-    unsigned char mtype;
-    unsigned char idx;
-
-    if ((buffer == NULL) || (len < 1)) {
-        eos_net_bad_handler(type, buffer, len);
-        return;
-    }
-
-    mtype = buffer[0];
-    idx = (mtype & EOS_CELL_MTYPE_MASK) >> 4;
-    if ((idx < EOS_CELL_MAX_MTYPE) && evt_handler[idx]) {
-        evt_handler[idx](mtype & ~EOS_CELL_MTYPE_MASK, buffer, len);
-    } else {
-        eos_net_bad_handler(type, buffer, len);
-    }
-}
-
-void eos_cell_netinit(void) {
-    int i;
-
-    for (i=0; i<EOS_CELL_MAX_MTYPE; i++) {
-        evt_handler[i] = NULL;
-    }
-    eos_net_set_handler(EOS_NET_MTYPE_CELL, cell_handle_msg);
-}
-
-void eos_cell_set_handler(unsigned char mtype, eos_evt_handler_t handler) {
-    unsigned char idx = (mtype & EOS_CELL_MTYPE_MASK) >> 4;
-
-    if (idx < EOS_CELL_MAX_MTYPE) evt_handler[idx] = handler;
-}
-
-eos_evt_handler_t eos_cell_get_handler(unsigned char mtype) {
-    unsigned char idx = (mtype & EOS_CELL_MTYPE_MASK) >> 4;
-
-    if (idx < EOS_CELL_MAX_MTYPE) return evt_handler[idx];
-    return NULL;
-}
diff --git a/fw/fe310/eos/cell.h b/fw/fe310/eos/cell.h
deleted file mode 100644
index b01d4cf..0000000
--- a/fw/fe310/eos/cell.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#include <stdint.h>
-#include "event.h"
-
-#define EOS_CELL_MTYPE_DEV              0x10
-#define EOS_CELL_MTYPE_VOICE            0x20
-#define EOS_CELL_MTYPE_SMS              0x30
-#define EOS_CELL_MTYPE_CBS              0x40
-#define EOS_CELL_MTYPE_USSD             0x50
-#define EOS_CELL_MTYPE_PDP              0x60
-
-#define EOS_CELL_MTYPE_MASK             0xf0
-#define EOS_CELL_MAX_MTYPE              8
-
-/* EOS_CELL_MTYPE_DEV subtypes */
-#define EOS_CELL_MTYPE_READY            1
-#define EOS_CELL_MTYPE_UART_DATA        2
-#define EOS_CELL_MTYPE_UART_TAKE        3
-#define EOS_CELL_MTYPE_UART_GIVE        4
-#define EOS_CELL_MTYPE_RESET            5
-
-#define EOS_CELL_MTYPE_VOICE_PCM        1
-#define EOS_CELL_MTYPE_VOICE_DIAL       2
-#define EOS_CELL_MTYPE_VOICE_RING       3
-#define EOS_CELL_MTYPE_VOICE_ANSWER     4
-#define EOS_CELL_MTYPE_VOICE_HANGUP     5
-#define EOS_CELL_MTYPE_VOICE_BEGIN      6
-#define EOS_CELL_MTYPE_VOICE_END        7
-#define EOS_CELL_MTYPE_VOICE_MISS       8
-#define EOS_CELL_MTYPE_VOICE_BUSY       9
-#define EOS_CELL_MTYPE_VOICE_ERR        10
-
-#define EOS_CELL_MTYPE_SMS_LIST         1
-#define EOS_CELL_MTYPE_SMS_SEND         2
-#define EOS_CELL_MTYPE_SMS_MSG_NEW      3
-#define EOS_CELL_MTYPE_SMS_MSG_ITEM     4
-
-#define EOS_CELL_MTYPE_USSD_REQUEST     1
-#define EOS_CELL_MTYPE_USSD_REPLY       2
-#define EOS_CELL_MTYPE_USSD_CANCEL      3
-
-#define EOS_CELL_MTYPE_PDP_CONFIG       1
-#define EOS_CELL_MTYPE_PDP_CONNECT      2
-#define EOS_CELL_MTYPE_PDP_DISCONNECT   3
-
-#define EOS_CELL_SMS_ADDRTYPE_INTL      1
-#define EOS_CELL_SMS_ADDRTYPE_ALPHA     2
-#define EOS_CELL_SMS_ADDRTYPE_OTHER     3
-
-void eos_cell_netinit(void);
-void eos_cell_set_handler(unsigned char mtype, eos_evt_handler_t handler);
-eos_evt_handler_t eos_cell_get_handler(unsigned char mtype);
\ No newline at end of file
diff --git a/fw/fe310/eos/dev/Makefile b/fw/fe310/eos/dev/Makefile
new file mode 100644
index 0000000..83cb1f5
--- /dev/null
+++ b/fw/fe310/eos/dev/Makefile
@@ -0,0 +1,16 @@
+include ../../common.mk
+CFLAGS += -I$(bsp_dir)/include
+
+obj = bq25895.o ov2640.o gt911.o
+
+
+%.o: %.c %.h
+	$(CC) $(CFLAGS) -c $<
+
+%.o: %.S
+	$(CC) $(CFLAGS) -c $<
+
+all: $(obj)
+
+clean:
+	rm -f *.o
diff --git a/fw/fe310/eos/dev/bq25895.c b/fw/fe310/eos/dev/bq25895.c
new file mode 100644
index 0000000..b290926
--- /dev/null
+++ b/fw/fe310/eos/dev/bq25895.c
@@ -0,0 +1,43 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "eos.h"
+#include "pwr.h"
+#include "i2c.h"
+#include "bq25895.h"
+
+static int reg_read(uint8_t reg, uint8_t *data) {
+    return eos_i2c_read8(BQ25895_ADDR, reg, data, 1);
+}
+
+static int reg_write(uint8_t reg, uint8_t data) {
+    return eos_i2c_write8(BQ25895_ADDR, reg, &data, 1);
+}
+
+int eos_bq25895_init(uint8_t wakeup_cause) {
+    int rst = (wakeup_cause == EOS_PWR_WAKE_RST);
+    int i, rv = EOS_OK;
+    uint8_t data = 0;
+
+    if (rst) {
+        rv = reg_write(0x14, 0x80);  // reset
+        if (rv) printf("I2C ERROR 0x14\n");
+        rv = reg_write(0x14, 0x00);  // disable watchdog
+        if (rv) printf("I2C ERROR 0x14\n");
+        rv = reg_write(0x07, 0x8d);  // disable watchdog
+        if (rv) printf("I2C ERROR 0x07\n");
+        rv = reg_write(0x00, 0x28);  // 2.1A input current
+        if (rv) printf("I2C ERROR 0x00\n");
+        rv = reg_write(0x02, 0x30);  // enable ICO, disaable MaxCharge and D+/D-
+        if (rv) printf("I2C ERROR 0x02\n");
+    }
+
+    printf("BQ25895:\n");
+    for (i=0; i<0x15; i++) {
+        rv = reg_read(i, &data);
+        if (!rv) printf("REG%02x: %02x\n", i, data);
+    }
+
+    return EOS_OK;
+}
diff --git a/fw/fe310/eos/dev/bq25895.h b/fw/fe310/eos/dev/bq25895.h
new file mode 100644
index 0000000..cbef36e
--- /dev/null
+++ b/fw/fe310/eos/dev/bq25895.h
@@ -0,0 +1,5 @@
+#include <stdint.h>
+
+#define BQ25895_ADDR        0x6A
+
+int eos_bq25895_init(uint8_t wakeup_cause);
diff --git a/fw/fe310/eos/dev/cam.c b/fw/fe310/eos/dev/cam.c
new file mode 100644
index 0000000..43293af
--- /dev/null
+++ b/fw/fe310/eos/dev/cam.c
@@ -0,0 +1,138 @@
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "eos.h"
+#include "spi.h"
+#include "cam.h"
+
+const int _eos_cam_resolution[][2] = {
+    {0,    0   },
+    // C/SIF Resolutions
+    {88,   72  },    /* QQCIF     */
+    {176,  144 },    /* QCIF      */
+    {352,  288 },    /* CIF       */
+    {88,   60  },    /* QQSIF     */
+    {176,  120 },    /* QSIF      */
+    {352,  240 },    /* SIF       */
+    // VGA Resolutions
+    {40,   30  },    /* QQQQVGA   */
+    {80,   60  },    /* QQQVGA    */
+    {160,  120 },    /* QQVGA     */
+    {320,  240 },    /* QVGA      */
+    {640,  480 },    /* VGA       */
+    {60,   40  },    /* HQQQVGA   */
+    {120,  80  },    /* HQQVGA    */
+    {240,  160 },    /* HQVGA     */
+    // FFT Resolutions
+    {64,   32  },    /* 64x32     */
+    {64,   64  },    /* 64x64     */
+    {128,  64  },    /* 128x64    */
+    {128,  128 },    /* 128x128   */
+    {320,  320 },    /* 128x128   */
+    // Other
+    {128,  160 },    /* LCD       */
+    {128,  160 },    /* QQVGA2    */
+    {720,  480 },    /* WVGA      */
+    {752,  480 },    /* WVGA2     */
+    {800,  600 },    /* SVGA      */
+    {1024, 768 },    /* XGA       */
+    {1280, 1024},    /* SXGA      */
+    {1600, 1200},    /* UXGA      */
+    {1280, 720 },    /* HD        */
+    {1920, 1080},    /* FHD       */
+    {2560, 1440},    /* QHD       */
+    {2048, 1536},    /* QXGA      */
+    {2560, 1600},    /* WQXGA     */
+    {2592, 1944},    /* WQXGA2    */
+};
+
+#define CAM_REG_CAPTURE_CTRL        0x01
+#define CAM_REG_FIFO_CTRL           0x04
+
+#define CAM_REG_GPIO_DIR            0x05
+#define CAM_REG_GPIO_WR             0x06
+#define CAM_REG_GPIO_RD             0x45
+
+#define CAM_REG_STATUS              0x41
+
+#define CAM_REG_VER                 0x40
+
+#define CAM_REG_READ_BURST          0x3c
+#define CAM_REG_READ_BYTE           0x3d
+
+#define CAM_REG_FIFO_SIZE1          0x42
+#define CAM_REG_FIFO_SIZE2          0x43
+#define CAM_REG_FIFO_SIZE3          0x44
+
+#define CAM_VAL_FIFO_CTRL_CLEAR     0x01
+#define CAM_VAL_FIFO_CTRL_START     0x02
+#define CAM_VAL_FIFO_CTRL_RSTWR     0x10
+#define CAM_VAL_FIFO_CTRL_RSTRD     0x20
+
+#define CAM_VAL_STATUS_VSYNC        0x01
+#define CAM_VAL_STATUS_SHUTTER      0x02
+#define CAM_VAL_STATUS_CPTDONE      0x08
+
+#define CAM_VAL_GPIO_RST            0x01
+#define CAM_VAL_GPIO_PWRDN          0x02
+#define CAM_VAL_GPIO_PWREN          0x04
+
+static uint8_t reg_read(uint8_t addr) {
+    uint8_t ret;
+
+    eos_spi_cs_set();
+    eos_spi_xchg8(addr, 0);
+    ret = eos_spi_xchg8(0, 0);
+    eos_spi_cs_clear();
+
+    return ret;
+}
+
+static void reg_write(uint8_t addr, uint8_t val) {
+    eos_spi_cs_set();
+    eos_spi_xchg8(addr | 0x80, 0);
+    eos_spi_xchg8(val, 0);
+    eos_spi_cs_clear();
+}
+
+void eos_cam_capture(void) {
+    reg_write(CAM_REG_FIFO_CTRL, CAM_VAL_FIFO_CTRL_START);
+}
+
+int eos_cam_capture_done(void) {
+    return !!(reg_read(CAM_REG_STATUS) & CAM_VAL_STATUS_CPTDONE);
+}
+
+void eos_cam_capture_wait(void) {
+    int done = 0;
+    
+    while (!done) {
+        done = eos_cam_capture_done();
+    }
+}
+
+uint32_t eos_cam_fbuf_size(void) {
+    uint32_t ret;
+    
+	ret = reg_read(CAM_REG_FIFO_SIZE1);
+    ret |= reg_read(CAM_REG_FIFO_SIZE2) << 8;
+    ret |= (reg_read(CAM_REG_FIFO_SIZE3) & 0x7f) << 16;
+    return ret;
+}
+
+void eos_cam_fbuf_read(uint8_t *buffer, uint16_t sz, int first) {
+    int i;
+    
+    eos_spi_cs_set();
+    eos_spi_xchg8(CAM_REG_READ_BURST, 0);
+    if (first) eos_spi_xchg8(0, 0);
+
+    for (i=0; i<sz; i++) {
+        buffer[i] = eos_spi_xchg8(0, 0);
+    }
+    eos_spi_cs_clear();
+}
+
+void eos_cam_fbuf_done(void) {
+    reg_write(CAM_REG_FIFO_CTRL, CAM_VAL_FIFO_CTRL_CLEAR);
+}
diff --git a/fw/fe310/eos/dev/cam.h b/fw/fe310/eos/dev/cam.h
new file mode 100644
index 0000000..f61757b
--- /dev/null
+++ b/fw/fe310/eos/dev/cam.h
@@ -0,0 +1,88 @@
+#include <stdint.h>
+
+typedef enum {
+    PIXFORMAT_INVALID = 0,
+    PIXFORMAT_BINARY,    // 1BPP/BINARY
+    PIXFORMAT_GRAYSCALE, // 1BPP/GRAYSCALE
+    PIXFORMAT_RGB565,    // 2BPP/RGB565
+    PIXFORMAT_YUV422,    // 2BPP/YUV422
+    PIXFORMAT_BAYER,     // 1BPP/RAW
+    PIXFORMAT_JPEG,      // JPEG/COMPRESSED
+} pixformat_t;
+
+typedef enum {
+    FRAMESIZE_INVALID = 0,
+    // C/SIF Resolutions
+    FRAMESIZE_QQCIF,    // 88x72
+    FRAMESIZE_QCIF,     // 176x144
+    FRAMESIZE_CIF,      // 352x288
+    FRAMESIZE_QQSIF,    // 88x60
+    FRAMESIZE_QSIF,     // 176x120
+    FRAMESIZE_SIF,      // 352x240
+    // VGA Resolutions
+    FRAMESIZE_QQQQVGA,  // 40x30
+    FRAMESIZE_QQQVGA,   // 80x60
+    FRAMESIZE_QQVGA,    // 160x120
+    FRAMESIZE_QVGA,     // 320x240
+    FRAMESIZE_VGA,      // 640x480
+    FRAMESIZE_HQQQVGA,  // 60x40
+    FRAMESIZE_HQQVGA,   // 120x80
+    FRAMESIZE_HQVGA,    // 240x160
+    // FFT Resolutions
+    FRAMESIZE_64X32,    // 64x32
+    FRAMESIZE_64X64,    // 64x64
+    FRAMESIZE_128X64,   // 128x64
+    FRAMESIZE_128X128,  // 128x128
+    FRAMESIZE_320X320,  // 320x320
+    // Other
+    FRAMESIZE_LCD,      // 128x160
+    FRAMESIZE_QQVGA2,   // 128x160
+    FRAMESIZE_WVGA,     // 720x480
+    FRAMESIZE_WVGA2,    // 752x480
+    FRAMESIZE_SVGA,     // 800x600
+    FRAMESIZE_XGA,      // 1024x768
+    FRAMESIZE_SXGA,     // 1280x1024
+    FRAMESIZE_UXGA,     // 1600x1200
+    FRAMESIZE_HD,       // 1280x720
+    FRAMESIZE_FHD,      // 1920x1080
+    FRAMESIZE_QHD,      // 2560x1440
+    FRAMESIZE_QXGA,     // 2048x1536
+    FRAMESIZE_WQXGA,    // 2560x1600
+    FRAMESIZE_WQXGA2,   // 2592x1944
+} framesize_t;
+
+typedef enum {
+    GAINCEILING_2X,
+    GAINCEILING_4X,
+    GAINCEILING_8X,
+    GAINCEILING_16X,
+    GAINCEILING_32X,
+    GAINCEILING_64X,
+    GAINCEILING_128X,
+} gainceiling_t;
+
+typedef enum {
+    SDE_NORMAL,
+    SDE_NEGATIVE,
+} sde_t;
+
+extern const int _eos_cam_resolution[][2];
+
+#define IM_LOG2_2(x)    (((x) &                0x2ULL) ? ( 2                        ) :             1) // NO ({ ... }) !
+#define IM_LOG2_4(x)    (((x) &                0xCULL) ? ( 2 +  IM_LOG2_2((x) >>  2)) :  IM_LOG2_2(x)) // NO ({ ... }) !
+#define IM_LOG2_8(x)    (((x) &               0xF0ULL) ? ( 4 +  IM_LOG2_4((x) >>  4)) :  IM_LOG2_4(x)) // NO ({ ... }) !
+#define IM_LOG2_16(x)   (((x) &             0xFF00ULL) ? ( 8 +  IM_LOG2_8((x) >>  8)) :  IM_LOG2_8(x)) // NO ({ ... }) !
+#define IM_LOG2_32(x)   (((x) &         0xFFFF0000ULL) ? (16 + IM_LOG2_16((x) >> 16)) : IM_LOG2_16(x)) // NO ({ ... }) !
+#define IM_LOG2(x)      (((x) & 0xFFFFFFFF00000000ULL) ? (32 + IM_LOG2_32((x) >> 32)) : IM_LOG2_32(x)) // NO ({ ... }) !
+
+#define IM_MAX(a,b)     ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a > _b ? _a : _b; })
+#define IM_MIN(a,b)     ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a < _b ? _a : _b; })
+#define IM_DIV(a,b)     ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _b ? (_a / _b) : 0; })
+#define IM_MOD(a,b)     ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _b ? (_a % _b) : 0; })
+
+void eos_cam_capture(void);
+int eos_cam_capture_done(void);
+void eos_cam_capture_wait(void);
+uint32_t eos_cam_fbuf_size(void);
+void eos_cam_fbuf_read(uint8_t *buffer, uint16_t sz, int first);
+void eos_cam_fbuf_done(void);
diff --git a/fw/fe310/eos/dev/drv2605.h b/fw/fe310/eos/dev/drv2605.h
new file mode 100644
index 0000000..fe90a9b
--- /dev/null
+++ b/fw/fe310/eos/dev/drv2605.h
@@ -0,0 +1,3 @@
+#include <stdint.h>
+
+#define DRV2605_ADDR        0x5A
diff --git a/fw/fe310/eos/dev/lcd.c b/fw/fe310/eos/dev/lcd.c
new file mode 100644
index 0000000..3080a13
--- /dev/null
+++ b/fw/fe310/eos/dev/lcd.c
@@ -0,0 +1,546 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "encoding.h"
+#include "platform.h"
+
+#include "eos.h"
+#include "timer.h"
+#include "i2s.h"
+#include "net.h"
+#include "spi_dev.h"
+#include "eve/eve.h"
+
+#include "board.h"
+
+#include "lcd.h"
+
+#define BIT_PUT(b, pin)     if (b) GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << (pin)); else GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << (pin));
+#define BIT_GET(pin)        ((GPIO_REG(GPIO_INPUT_VAL) & (1 << (pin))) >> (pin))
+
+#define SCK_UP              { GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << IOF_SPI1_SCK); }
+#define SCK_DN              { GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << IOF_SPI1_SCK); }
+
+static inline void _sleep(int n) {
+    volatile int x = n;
+
+    while(x) x--;
+}
+
+int eos_lcd_select(void) {
+    if (eos_i2s_running()) return EOS_ERR_BUSY;
+    if (eos_spi_dev() != EOS_SPI_DEV_NET) return EOS_ERR_BUSY;
+
+    eos_net_stop();
+
+    GPIO_REG(GPIO_OUTPUT_VAL)   &= ~(1 << LCD_PIN_CS);
+
+    GPIO_REG(GPIO_INPUT_EN)     &= ~(1 << LCD_PIN_CS);
+    GPIO_REG(GPIO_OUTPUT_EN)    |=  (1 << LCD_PIN_CS);
+
+    GPIO_REG(GPIO_IOF_EN)       &=  ~SPI_IOF_MASK;
+
+    return EOS_OK;
+}
+
+void eos_lcd_deselect(void) {
+    GPIO_REG(GPIO_IOF_EN) |= SPI_IOF_MASK;
+    eos_net_start();
+}
+
+void eos_lcd_cs_set(void) {
+    GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << LCD_PIN_CS);
+}
+
+void eos_lcd_cs_clear(void) {
+    GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << LCD_PIN_CS);
+}
+
+/* sck frequency for r/w operations is 0.8Mhz */
+void eos_lcd_write(uint8_t dc, uint8_t data) {
+    int i;
+
+    BIT_PUT(dc, IOF_SPI1_MOSI);
+    _sleep(10);
+    SCK_UP;
+    for (i=0; i<8; i++) {
+        _sleep(10);
+        SCK_DN;
+        BIT_PUT(data & 0x80, IOF_SPI1_MOSI);
+        _sleep(10);
+        SCK_UP;
+        data = data << 1;
+    }
+    _sleep(10);
+    SCK_DN;
+}
+
+void eos_lcd_read(uint8_t *data) {
+    int i;
+
+    *data = 0;
+    for (i=0; i<8; i++) {
+        _sleep(10);
+        *data = *data << 1;
+        *data |= BIT_GET(IOF_SPI1_MISO);
+        SCK_UP;
+        _sleep(10);
+        SCK_DN;
+    }
+}
+
+static int _init(void) {
+    int rv;
+    uint8_t chip_id[3];
+
+    rv = eos_lcd_select();
+    if (rv) return rv;
+    eos_lcd_cs_set();
+
+    /* LCD Setting */
+    eos_lcd_write(0, 0xFF);     // change to Page 1 CMD
+    eos_lcd_write(1, 0xFF);
+    eos_lcd_write(1, 0x98);
+    eos_lcd_write(1, 0x06);
+    eos_lcd_write(1, 0x04);
+    eos_lcd_write(1, 0x01);
+
+    // eos_lcd_write(0, 0x08);  // Output SDA
+    // eos_lcd_write(1, 0x10);
+
+    eos_lcd_write(0, 0xFE);     // enable read
+    eos_lcd_write(1, 0x81);
+
+    eos_lcd_write(0, 0x00);     // RDID4
+    eos_lcd_read(&chip_id[0]);
+
+    eos_lcd_write(0, 0x01);
+    eos_lcd_read(&chip_id[1]);
+
+    eos_lcd_write(0, 0x02);
+    eos_lcd_read(&chip_id[2]);
+
+    printf("LCD CHIP ID: %.2x%.2x%.2x\n", chip_id[0], chip_id[1], chip_id[2]);
+
+    eos_lcd_write(0, 0xFE);     // disable read
+    eos_lcd_write(1, 0x00);
+
+    if (memcmp(chip_id, "\x98\x06\x04", sizeof(chip_id))) {
+        return EOS_ERR_ABSENT;
+    }
+
+    eos_lcd_write(0, 0x20);     // set DE/VSYNC mode
+    eos_lcd_write(1, 0x00);
+
+    eos_lcd_write(0, 0x21);     // DE = 1 Active
+    eos_lcd_write(1, 0x01);
+
+    eos_lcd_write(0, 0x30);     // resolution setting 480 X 854
+    eos_lcd_write(1, 0x01);
+
+    eos_lcd_write(0, 0x31);     // inversion setting 2-dot
+    eos_lcd_write(1, 0x00);
+
+    eos_lcd_write(0, 0x40);     // BT AVDD,AVDD
+    eos_lcd_write(1, 0x16);
+
+    eos_lcd_write(0, 0x41);
+    eos_lcd_write(1, 0x33);     // 22
+
+    eos_lcd_write(0, 0x42);
+    eos_lcd_write(1, 0x03);     // VGL=DDVDH+VCIP-DDVDL, VGH=2DDVDL-VCIP
+
+    eos_lcd_write(0, 0x43);
+    eos_lcd_write(1, 0x09);     // set VGH clamp level
+
+    eos_lcd_write(0, 0x44);
+    eos_lcd_write(1, 0x06);     // set VGL clamp level
+
+    eos_lcd_write(0, 0x50);     // VREG1
+    eos_lcd_write(1, 0x88);
+
+    eos_lcd_write(0, 0x51);     // VREG2
+    eos_lcd_write(1, 0x88);
+
+    eos_lcd_write(0, 0x52);     // flicker MSB
+    eos_lcd_write(1, 0x00);
+
+    eos_lcd_write(0, 0x53);     // flicker LSB
+    eos_lcd_write(1, 0x49);     // VCOM
+
+    eos_lcd_write(0, 0x55);     // flicker
+    eos_lcd_write(1, 0x49);
+
+    eos_lcd_write(0, 0x60);
+    eos_lcd_write(1, 0x07);
+
+    eos_lcd_write(0, 0x61);
+    eos_lcd_write(1, 0x00);
+
+    eos_lcd_write(0, 0x62);
+    eos_lcd_write(1, 0x07);
+
+    eos_lcd_write(0, 0x63);
+    eos_lcd_write(1, 0x00);
+
+    /* Gamma Setting */
+    eos_lcd_write(0, 0xA0);     // positive Gamma
+    eos_lcd_write(1, 0x00);
+
+    eos_lcd_write(0, 0xA1);
+    eos_lcd_write(1, 0x09);
+
+    eos_lcd_write(0, 0xA2);
+    eos_lcd_write(1, 0x11);
+
+    eos_lcd_write(0, 0xA3);
+    eos_lcd_write(1, 0x0B);
+
+    eos_lcd_write(0, 0xA4);
+    eos_lcd_write(1, 0x05);
+
+    eos_lcd_write(0, 0xA5);
+    eos_lcd_write(1, 0x08);
+
+    eos_lcd_write(0, 0xA6);
+    eos_lcd_write(1, 0x06);
+
+    eos_lcd_write(0, 0xA7);
+    eos_lcd_write(1, 0x04);
+
+    eos_lcd_write(0, 0xA8);
+    eos_lcd_write(1, 0x09);
+
+    eos_lcd_write(0, 0xA9);
+    eos_lcd_write(1, 0x0C);
+
+    eos_lcd_write(0, 0xAA);
+    eos_lcd_write(1, 0x15);
+
+    eos_lcd_write(0, 0xAB);
+    eos_lcd_write(1, 0x08);
+
+    eos_lcd_write(0, 0xAC);
+    eos_lcd_write(1, 0x0F);
+
+    eos_lcd_write(0, 0xAD);
+    eos_lcd_write(1, 0x12);
+
+    eos_lcd_write(0, 0xAE);
+    eos_lcd_write(1, 0x09);
+
+    eos_lcd_write(0, 0xAF);
+    eos_lcd_write(1, 0x00);
+
+    eos_lcd_write(0, 0xC0);     // negative Gamma
+    eos_lcd_write(1, 0x00);
+
+    eos_lcd_write(0, 0xC1);
+    eos_lcd_write(1, 0x09);
+
+    eos_lcd_write(0, 0xC2);
+    eos_lcd_write(1, 0x10);
+
+    eos_lcd_write(0, 0xC3);
+    eos_lcd_write(1, 0x0C);
+
+    eos_lcd_write(0, 0xC4);
+    eos_lcd_write(1, 0x05);
+
+    eos_lcd_write(0, 0xC5);
+    eos_lcd_write(1, 0x08);
+
+    eos_lcd_write(0, 0xC6);
+    eos_lcd_write(1, 0x06);
+
+    eos_lcd_write(0, 0xC7);
+    eos_lcd_write(1, 0x04);
+
+    eos_lcd_write(0, 0xC8);
+    eos_lcd_write(1, 0x08);
+
+    eos_lcd_write(0, 0xC9);
+    eos_lcd_write(1, 0x0C);
+
+    eos_lcd_write(0, 0xCA);
+    eos_lcd_write(1, 0x14);
+
+    eos_lcd_write(0, 0xCB);
+    eos_lcd_write(1, 0x08);
+
+    eos_lcd_write(0, 0xCC);
+    eos_lcd_write(1, 0x0F);
+
+    eos_lcd_write(0, 0xCD);
+    eos_lcd_write(1, 0x11);
+
+    eos_lcd_write(0, 0xCE);
+    eos_lcd_write(1, 0x09);
+
+    eos_lcd_write(0, 0xCF);
+    eos_lcd_write(1, 0x00);
+
+    eos_lcd_write(0, 0xFF);     // change to Page 6 CMD for GIP timing
+    eos_lcd_write(1, 0xFF);
+    eos_lcd_write(1, 0x98);
+    eos_lcd_write(1, 0x06);
+    eos_lcd_write(1, 0x04);
+    eos_lcd_write(1, 0x06);
+
+    eos_lcd_write(0, 0x00);
+    eos_lcd_write(1, 0x20);
+
+    eos_lcd_write(0, 0x01);
+    eos_lcd_write(1, 0x0A);
+
+    eos_lcd_write(0, 0x02);
+    eos_lcd_write(1, 0x00);
+
+    eos_lcd_write(0, 0x03);
+    eos_lcd_write(1, 0x00);
+
+    eos_lcd_write(0, 0x04);
+    eos_lcd_write(1, 0x01);
+
+    eos_lcd_write(0, 0x05);
+    eos_lcd_write(1, 0x01);
+
+    eos_lcd_write(0, 0x06);
+    eos_lcd_write(1, 0x98);
+
+    eos_lcd_write(0, 0x07);
+    eos_lcd_write(1, 0x06);
+
+    eos_lcd_write(0, 0x08);
+    eos_lcd_write(1, 0x01);
+
+    eos_lcd_write(0, 0x09);
+    eos_lcd_write(1, 0x80);
+
+    eos_lcd_write(0, 0x0A);
+    eos_lcd_write(1, 0x00);
+
+    eos_lcd_write(0, 0x0B);
+    eos_lcd_write(1, 0x00);
+
+    eos_lcd_write(0, 0x0C);
+    eos_lcd_write(1, 0x01);
+
+    eos_lcd_write(0, 0x0D);
+    eos_lcd_write(1, 0x01);
+
+    eos_lcd_write(0, 0x0E);
+    eos_lcd_write(1, 0x05);
+
+    eos_lcd_write(0, 0x0F);
+    eos_lcd_write(1, 0x00);
+
+    eos_lcd_write(0, 0x10);
+    eos_lcd_write(1, 0xF0);
+
+    eos_lcd_write(0, 0x11);
+    eos_lcd_write(1, 0xF4);
+
+    eos_lcd_write(0, 0x12);
+    eos_lcd_write(1, 0x01);
+
+    eos_lcd_write(0, 0x13);
+    eos_lcd_write(1, 0x00);
+
+    eos_lcd_write(0, 0x14);
+    eos_lcd_write(1, 0x00);
+
+    eos_lcd_write(0, 0x15);
+    eos_lcd_write(1, 0xC0);
+
+    eos_lcd_write(0, 0x16);
+    eos_lcd_write(1, 0x08);
+
+    eos_lcd_write(0, 0x17);
+    eos_lcd_write(1, 0x00);
+
+    eos_lcd_write(0, 0x18);
+    eos_lcd_write(1, 0x00);
+
+    eos_lcd_write(0, 0x19);
+    eos_lcd_write(1, 0x00);
+
+    eos_lcd_write(0, 0x1A);
+    eos_lcd_write(1, 0x00);
+
+    eos_lcd_write(0, 0x1B);
+    eos_lcd_write(1, 0x00);
+
+    eos_lcd_write(0, 0x1C);
+    eos_lcd_write(1, 0x00);
+
+    eos_lcd_write(0, 0x1D);
+    eos_lcd_write(1, 0x00);
+
+    eos_lcd_write(0, 0x20);
+    eos_lcd_write(1, 0x01);
+
+    eos_lcd_write(0, 0x21);
+    eos_lcd_write(1, 0x23);
+
+    eos_lcd_write(0, 0x22);
+    eos_lcd_write(1, 0x45);
+
+    eos_lcd_write(0, 0x23);
+    eos_lcd_write(1, 0x67);
+
+    eos_lcd_write(0, 0x24);
+    eos_lcd_write(1, 0x01);
+
+    eos_lcd_write(0, 0x25);
+    eos_lcd_write(1, 0x23);
+
+    eos_lcd_write(0, 0x26);
+    eos_lcd_write(1, 0x45);
+
+    eos_lcd_write(0, 0x27);
+    eos_lcd_write(1, 0x67);
+
+    eos_lcd_write(0, 0x30);
+    eos_lcd_write(1, 0x11);
+
+    eos_lcd_write(0, 0x31);
+    eos_lcd_write(1, 0x11);
+
+    eos_lcd_write(0, 0x32);
+    eos_lcd_write(1, 0x00);
+
+    eos_lcd_write(0, 0x33);
+    eos_lcd_write(1, 0xEE);
+
+    eos_lcd_write(0, 0x34);
+    eos_lcd_write(1, 0xFF);
+
+    eos_lcd_write(0, 0x35);
+    eos_lcd_write(1, 0xBB);
+
+    eos_lcd_write(0, 0x36);
+    eos_lcd_write(1, 0xAA);
+
+    eos_lcd_write(0, 0x37);
+    eos_lcd_write(1, 0xDD);
+
+    eos_lcd_write(0, 0x38);
+    eos_lcd_write(1, 0xCC);
+
+    eos_lcd_write(0, 0x39);
+    eos_lcd_write(1, 0x66);
+
+    eos_lcd_write(0, 0x3A);
+    eos_lcd_write(1, 0x77);
+
+    eos_lcd_write(0, 0x3B);
+    eos_lcd_write(1, 0x22);
+
+    eos_lcd_write(0, 0x3C);
+    eos_lcd_write(1, 0x22);
+
+    eos_lcd_write(0, 0x3D);
+    eos_lcd_write(1, 0x22);
+
+    eos_lcd_write(0, 0x3E);
+    eos_lcd_write(1, 0x22);
+
+    eos_lcd_write(0, 0x3F);
+    eos_lcd_write(1, 0x22);
+
+    eos_lcd_write(0, 0x40);
+    eos_lcd_write(1, 0x22);
+
+    eos_lcd_write(0, 0xFF);     // change to Page 7 CMD for GIP timing
+    eos_lcd_write(1, 0xFF);
+    eos_lcd_write(1, 0x98);
+    eos_lcd_write(1, 0x06);
+    eos_lcd_write(1, 0x04);
+    eos_lcd_write(1, 0x07);
+
+    eos_lcd_write(0, 0x17);
+    eos_lcd_write(1, 0x22);
+
+    eos_lcd_write(0, 0x02);
+    eos_lcd_write(1, 0x77);
+
+    eos_lcd_write(0, 0x26);
+    eos_lcd_write(1, 0xB2);
+
+    eos_lcd_write(0, 0xFF);     // change to Page 0 CMD for normal command
+    eos_lcd_write(1, 0xFF);
+    eos_lcd_write(1, 0x98);
+    eos_lcd_write(1, 0x06);
+    eos_lcd_write(1, 0x04);
+    eos_lcd_write(1, 0x00);
+
+    eos_lcd_write(0, 0x3A);
+    eos_lcd_write(1, 0x70);     // 24BIT
+
+    eos_lcd_write(0, 0x11);
+    eos_time_sleep(120);
+    eos_lcd_write(0, 0x29);
+    eos_time_sleep(25);
+
+    eos_lcd_cs_clear();
+    eos_lcd_deselect();
+
+    return EOS_OK;
+}
+
+int eos_lcd_init(uint8_t wakeup_cause) {
+    eos_spi_select(EOS_SPI_DEV_EVE);
+    eve_gpio_set(EVE_GPIO_LCD_EN, 1);
+    eos_spi_deselect();
+    eos_time_sleep(200);
+
+    return _init();
+}
+
+int eos_lcd_sleep(void) {
+    int rv;
+
+    rv = eos_lcd_select();
+    if (rv) return rv;
+
+    eos_lcd_cs_set();
+
+    eos_lcd_write(0, 0x28);
+    eos_time_sleep(10);
+    eos_lcd_write(0, 0x10);
+
+    eos_lcd_cs_clear();
+    eos_lcd_deselect();
+
+    eos_spi_select(EOS_SPI_DEV_EVE);
+    eve_gpio_set(EVE_GPIO_LCD_EN, 0);
+    eos_spi_deselect();
+
+    return EOS_OK;
+}
+
+int eos_lcd_wake(void) {
+    int rv;
+
+    eos_spi_select(EOS_SPI_DEV_EVE);
+    eve_gpio_set(EVE_GPIO_LCD_EN, 1);
+    eos_spi_deselect();
+    eos_time_sleep(200);
+
+    rv = eos_lcd_select();
+    if (rv) return rv;
+
+    eos_lcd_cs_set();
+
+    eos_lcd_write(0, 0x11);
+    eos_time_sleep(120);
+    eos_lcd_write(0, 0x29);
+
+    eos_lcd_cs_clear();
+    eos_lcd_deselect();
+
+    return EOS_OK;
+}
diff --git a/fw/fe310/eos/dev/lcd.h b/fw/fe310/eos/dev/lcd.h
new file mode 100644
index 0000000..1bcb2cd
--- /dev/null
+++ b/fw/fe310/eos/dev/lcd.h
@@ -0,0 +1,12 @@
+#include <stdint.h>
+
+int eos_lcd_init(uint8_t wakeup_cause);
+int eos_lcd_select(void);
+void eos_lcd_deselect(void);
+void eos_lcd_cs_set(void);
+void eos_lcd_cs_clear(void);
+void eos_lcd_write(uint8_t dc, uint8_t data);
+void eos_lcd_read(uint8_t *data);
+
+int eos_lcd_sleep(void);
+int eos_lcd_wake(void);
\ No newline at end of file
diff --git a/fw/fe310/eos/dev/lsm9ds1.h b/fw/fe310/eos/dev/lsm9ds1.h
new file mode 100644
index 0000000..92220e7
--- /dev/null
+++ b/fw/fe310/eos/dev/lsm9ds1.h
@@ -0,0 +1,4 @@
+#include <stdint.h>
+
+#define LSM9DS1_ADDR_AG     0x1E
+#define LSM9DS1_ADDR_M      0x6B
diff --git a/fw/fe310/eos/dev/ov2640.c b/fw/fe310/eos/dev/ov2640.c
new file mode 100644
index 0000000..6e54f10
--- /dev/null
+++ b/fw/fe310/eos/dev/ov2640.c
@@ -0,0 +1,861 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <math.h>
+
+#include "eos.h"
+#include "timer.h"
+#include "cam.h"
+
+#include "i2c.h"
+#include "ov2640_regs.h"
+#include "ov2640.h"
+
+#define XCLK_FREQ       24000000
+//#define XCLK_FREQ       12000000
+
+#define CIF_WIDTH       (400)
+#define CIF_HEIGHT      (296)
+
+#define SVGA_WIDTH      (800)
+#define SVGA_HEIGHT     (600)
+
+#define UXGA_WIDTH      (1600)
+#define UXGA_HEIGHT     (1200)
+
+static const uint8_t default_regs[][2] = {
+
+// From Linux Driver.
+
+    {BANK_SEL,      BANK_SEL_DSP},
+    {0x2c,          0xff},
+    {0x2e,          0xdf},
+    {BANK_SEL,      BANK_SEL_SENSOR},
+    {0x3c,          0x32},
+//  {CLKRC,         CLKRC_DOUBLE | 0x02},
+    {CLKRC,         0x01},
+    {COM2,          COM2_OUT_DRIVE_3x},
+    {REG04,         REG04_SET(REG04_HFLIP_IMG | REG04_VFLIP_IMG | REG04_VREF_EN | REG04_HREF_EN)},
+    {COM8,          COM8_SET(COM8_BNDF_EN | COM8_AGC_EN | COM8_AEC_EN)},
+    {COM9,          COM9_AGC_SET(COM9_AGC_GAIN_8x)},
+    {0x2c,          0x0c},
+    {0x33,          0x78},
+    {0x3a,          0x33},
+    {0x3b,          0xfb},
+    {0x3e,          0x00},
+    {0x43,          0x11},
+    {0x16,          0x10},
+    {0x39,          0x02},
+    {0x35,          0x88},
+    {0x22,          0x0a},
+    {0x37,          0x40},
+    {0x23,          0x00},
+    {ARCOM2,        0xa0},
+    {0x06,          0x02},
+    {0x06,          0x88},
+    {0x07,          0xc0},
+    {0x0d,          0xb7},
+    {0x0e,          0x01},
+    {0x4c,          0x00},
+    {0x4a,          0x81},
+    {0x21,          0x99},
+    {AEW,           0x40},
+    {AEB,           0x38},
+    {VV,            VV_AGC_TH_SET(0x08, 0x02)},
+    {0x5c,          0x00},
+    {0x63,          0x00},
+    {FLL,           0x22},
+    {COM3,          COM3_BAND_SET(COM3_BAND_AUTO)},
+    {REG5D,         0x55},
+    {REG5E,         0x7d},
+    {REG5F,         0x7d},
+    {REG60,         0x55},
+    {HISTO_LOW,     0x70},
+    {HISTO_HIGH,    0x80},
+    {0x7c,          0x05},
+    {0x20,          0x80},
+    {0x28,          0x30},
+    {0x6c,          0x00},
+    {0x6d,          0x80},
+    {0x6e,          0x00},
+    {0x70,          0x02},
+    {0x71,          0x94},
+    {0x73,          0xc1},
+    {0x3d,          0x34},
+    {COM7,          COM7_RES_UXGA | COM7_ZOOM_EN},
+    {0x5a,          0x57},
+    {COM25,         0x00},
+    {BD50,          0xbb},
+    {BD60,          0x9c},
+    {BANK_SEL,      BANK_SEL_DSP},
+    {0xe5,          0x7f},
+    {MC_BIST,       MC_BIST_RESET | MC_BIST_BOOT_ROM_SEL},
+    {0x41,          0x24},
+    {RESET,         RESET_JPEG | RESET_DVP},
+    {0x76,          0xff},
+    {0x33,          0xa0},
+    {0x42,          0x20},
+    {0x43,          0x18},
+    {0x4c,          0x00},
+    {CTRL3,         CTRL3_BPC_EN | CTRL3_WPC_EN | 0x10},
+    {0x88,          0x3f},
+    {0xd7,          0x03},
+    {0xd9,          0x10},
+    {R_DVP_SP,      R_DVP_SP_AUTO_MODE | 0x2},
+    {0xc8,          0x08},
+    {0xc9,          0x80},
+    {BPADDR,        0x00},
+    {BPDATA,        0x00},
+    {BPADDR,        0x03},
+    {BPDATA,        0x48},
+    {BPDATA,        0x48},
+    {BPADDR,        0x08},
+    {BPDATA,        0x20},
+    {BPDATA,        0x10},
+    {BPDATA,        0x0e},
+    {0x90,          0x00},
+    {0x91,          0x0e},
+    {0x91,          0x1a},
+    {0x91,          0x31},
+    {0x91,          0x5a},
+    {0x91,          0x69},
+    {0x91,          0x75},
+    {0x91,          0x7e},
+    {0x91,          0x88},
+    {0x91,          0x8f},
+    {0x91,          0x96},
+    {0x91,          0xa3},
+    {0x91,          0xaf},
+    {0x91,          0xc4},
+    {0x91,          0xd7},
+    {0x91,          0xe8},
+    {0x91,          0x20},
+    {0x92,          0x00},
+    {0x93,          0x06},
+    {0x93,          0xe3},
+    {0x93,          0x03},
+    {0x93,          0x03},
+    {0x93,          0x00},
+    {0x93,          0x02},
+    {0x93,          0x00},
+    {0x93,          0x00},
+    {0x93,          0x00},
+    {0x93,          0x00},
+    {0x93,          0x00},
+    {0x93,          0x00},
+    {0x93,          0x00},
+    {0x96,          0x00},
+    {0x97,          0x08},
+    {0x97,          0x19},
+    {0x97,          0x02},
+    {0x97,          0x0c},
+    {0x97,          0x24},
+    {0x97,          0x30},
+    {0x97,          0x28},
+    {0x97,          0x26},
+    {0x97,          0x02},
+    {0x97,          0x98},
+    {0x97,          0x80},
+    {0x97,          0x00},
+    {0x97,          0x00},
+    {0xa4,          0x00},
+    {0xa8,          0x00},
+    {0xc5,          0x11},
+    {0xc6,          0x51},
+    {0xbf,          0x80},
+    {0xc7,          0x10},  /* simple AWB */
+    {0xb6,          0x66},
+    {0xb8,          0xA5},
+    {0xb7,          0x64},
+    {0xb9,          0x7C},
+    {0xb3,          0xaf},
+    {0xb4,          0x97},
+    {0xb5,          0xFF},
+    {0xb0,          0xC5},
+    {0xb1,          0x94},
+    {0xb2,          0x0f},
+    {0xc4,          0x5c},
+    {0xa6,          0x00},
+    {0xa7,          0x20},
+    {0xa7,          0xd8},
+    {0xa7,          0x1b},
+    {0xa7,          0x31},
+    {0xa7,          0x00},
+    {0xa7,          0x18},
+    {0xa7,          0x20},
+    {0xa7,          0xd8},
+    {0xa7,          0x19},
+    {0xa7,          0x31},
+    {0xa7,          0x00},
+    {0xa7,          0x18},
+    {0xa7,          0x20},
+    {0xa7,          0xd8},
+    {0xa7,          0x19},
+    {0xa7,          0x31},
+    {0xa7,          0x00},
+    {0xa7,          0x18},
+    {0x7f,          0x00},
+    {0xe5,          0x1f},
+    {0xe1,          0x77},
+    {0xdd,          0x7f},
+    {CTRL0,         CTRL0_YUV422 | CTRL0_YUV_EN | CTRL0_RGB_EN},
+
+// OpenMV Custom.
+
+    {BANK_SEL,      BANK_SEL_SENSOR},
+    {0x0f,          0x4b},
+    {COM1,          0x8f},
+
+// End.
+
+    {0xff,          0xff},
+};
+
+// Looks really bad.
+//static const uint8_t cif_regs[][2] = {
+//    {BANK_SEL,  BANK_SEL_SENSOR},
+//    {COM7,      COM7_RES_CIF},
+//    {COM1,      0x06 | 0x80},
+//    {HSTART,    0x11},
+//    {HSTOP,     0x43},
+//    {VSTART,    0x01}, // 0x01 fixes issue with garbage pixels in the image...
+//    {VSTOP,     0x97},
+//    {REG32,     0x09},
+//    {BANK_SEL,  BANK_SEL_DSP},
+//    {RESET,     RESET_DVP},
+//    {SIZEL,     SIZEL_HSIZE8_11_SET(CIF_WIDTH) | SIZEL_HSIZE8_SET(CIF_WIDTH) | SIZEL_VSIZE8_SET(CIF_HEIGHT)},
+//    {HSIZE8,    HSIZE8_SET(CIF_WIDTH)},
+//    {VSIZE8,    VSIZE8_SET(CIF_HEIGHT)},
+//    {CTRL2,     CTRL2_DCW_EN | CTRL2_SDE_EN | CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN},
+//    {0,         0},
+//};
+
+static const uint8_t svga_regs[][2] = {
+    {BANK_SEL,  BANK_SEL_SENSOR},
+    {COM7,      COM7_RES_SVGA},
+    {COM1,      0x0A | 0x80},
+    {HSTART,    0x11},
+    {HSTOP,     0x43},
+    {VSTART,    0x01}, // 0x01 fixes issue with garbage pixels in the image...
+    {VSTOP,     0x97},
+    {REG32,     0x09},
+    {BANK_SEL,  BANK_SEL_DSP},
+    {RESET,     RESET_DVP},
+    {SIZEL,     SIZEL_HSIZE8_11_SET(SVGA_WIDTH) | SIZEL_HSIZE8_SET(SVGA_WIDTH) | SIZEL_VSIZE8_SET(SVGA_HEIGHT)},
+    {HSIZE8,    HSIZE8_SET(SVGA_WIDTH)},
+    {VSIZE8,    VSIZE8_SET(SVGA_HEIGHT)},
+    {CTRL2,     CTRL2_DCW_EN | CTRL2_SDE_EN | CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN},
+    {0xff,      0xff},
+};
+
+static const uint8_t uxga_regs[][2] = {
+    {BANK_SEL,  BANK_SEL_SENSOR},
+    {COM7,      COM7_RES_UXGA},
+    {COM1,      0x0F | 0x80},
+    {HSTART,    0x11},
+    {HSTOP,     0x75},
+    {VSTART,    0x01},
+    {VSTOP,     0x97},
+    {REG32,     0x36},
+    {BANK_SEL,  BANK_SEL_DSP},
+    {RESET,     RESET_DVP},
+    {SIZEL,     SIZEL_HSIZE8_11_SET(UXGA_WIDTH) | SIZEL_HSIZE8_SET(UXGA_WIDTH) | SIZEL_VSIZE8_SET(UXGA_HEIGHT)},
+    {HSIZE8,    HSIZE8_SET(UXGA_WIDTH)},
+    {VSIZE8,    VSIZE8_SET(UXGA_HEIGHT)},
+    {CTRL2,     CTRL2_DCW_EN | CTRL2_SDE_EN | CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN},
+    {0xff,      0xff},
+};
+
+static const uint8_t yuv422_regs[][2] = {
+    {BANK_SEL,      BANK_SEL_DSP},
+    {R_BYPASS,      R_BYPASS_DSP_EN},
+    {IMAGE_MODE,    IMAGE_MODE_YUV422},
+    {0xd7,          0x03},
+    {0x33,          0xa0},
+    {0xe5,          0x1f},
+    {0xe1,          0x67},
+    {RESET,         0x00},
+    {R_BYPASS,      R_BYPASS_DSP_EN},
+    {0xff,          0xff},
+};
+
+static const uint8_t rgb565_regs[][2] = {
+    {BANK_SEL,      BANK_SEL_DSP},
+    {R_BYPASS,      R_BYPASS_DSP_EN},
+    {IMAGE_MODE,    IMAGE_MODE_RGB565},
+    {0xd7,          0x03},
+    {RESET,         0x00},
+    {R_BYPASS,      R_BYPASS_DSP_EN},
+    {0xff,          0xff},
+};
+
+static const uint8_t bayer_regs[][2] = {
+    {BANK_SEL,      BANK_SEL_DSP},
+    {R_BYPASS,      R_BYPASS_DSP_EN},
+    {IMAGE_MODE,    IMAGE_MODE_RAW10},
+    {0xd7,          0x03},
+    {RESET,         0x00},
+    {R_BYPASS,      R_BYPASS_DSP_EN},
+    {0xff,          0xff},
+};
+
+static const uint8_t jpeg_regs[][2] = {
+    {BANK_SEL,      BANK_SEL_DSP},
+    {R_BYPASS,      R_BYPASS_DSP_EN},
+    {IMAGE_MODE,    IMAGE_MODE_JPEG_EN},
+    {0xd7,          0x03},
+    {RESET,         0x00},
+    {R_BYPASS,      R_BYPASS_DSP_EN},
+    {0xff,          0xff},
+};
+
+#define NUM_BRIGHTNESS_LEVELS (5)
+static const uint8_t brightness_regs[NUM_BRIGHTNESS_LEVELS + 1][5] = {
+    {BPADDR, BPDATA, BPADDR, BPDATA, BPDATA},
+    {0x00, 0x04, 0x09, 0x00, 0x00}, /* -2 */
+    {0x00, 0x04, 0x09, 0x10, 0x00}, /* -1 */
+    {0x00, 0x04, 0x09, 0x20, 0x00}, /*  0 */
+    {0x00, 0x04, 0x09, 0x30, 0x00}, /* +1 */
+    {0x00, 0x04, 0x09, 0x40, 0x00}, /* +2 */
+};
+
+#define NUM_CONTRAST_LEVELS (5)
+static const uint8_t contrast_regs[NUM_CONTRAST_LEVELS + 1][7] = {
+    {BPADDR, BPDATA, BPADDR, BPDATA, BPDATA, BPDATA, BPDATA},
+    {0x00, 0x04, 0x07, 0x20, 0x18, 0x34, 0x06}, /* -2 */
+    {0x00, 0x04, 0x07, 0x20, 0x1c, 0x2a, 0x06}, /* -1 */
+    {0x00, 0x04, 0x07, 0x20, 0x20, 0x20, 0x06}, /*  0 */
+    {0x00, 0x04, 0x07, 0x20, 0x24, 0x16, 0x06}, /* +1 */
+    {0x00, 0x04, 0x07, 0x20, 0x28, 0x0c, 0x06}, /* +2 */
+};
+
+#define NUM_SATURATION_LEVELS (5)
+static const uint8_t saturation_regs[NUM_SATURATION_LEVELS + 1][5] = {
+    {BPADDR, BPDATA, BPADDR, BPDATA, BPDATA},
+    {0x00, 0x02, 0x03, 0x28, 0x28}, /* -2 */
+    {0x00, 0x02, 0x03, 0x38, 0x38}, /* -1 */
+    {0x00, 0x02, 0x03, 0x48, 0x48}, /*  0 */
+    {0x00, 0x02, 0x03, 0x58, 0x58}, /* +1 */
+    {0x00, 0x02, 0x03, 0x68, 0x68}, /* +2 */
+};
+
+static int reg_read(int8_t reg, uint8_t *data) {
+    return eos_i2c_read8(OV2640_ADDR, reg, data, 1);
+}
+
+static int reg_write(uint8_t reg, uint8_t data) {
+    return eos_i2c_write8(OV2640_ADDR, reg, &data, 1);
+}
+
+static int regarr_write(const uint8_t (*regs)[2]) {
+    int i, rv;
+
+    i = 0;
+    rv = EOS_OK;
+
+    while ((regs[i][0] != 0xff) || (regs[i][1] != 0xff)) {
+        if (!rv) rv = reg_write(regs[i][0], regs[i][1]);
+        i++;
+    }
+
+    return rv;
+}
+
+int eos_ov2640_init(void) {
+    int rv;
+
+    // Reset all registers
+    rv = reg_write(BANK_SEL, BANK_SEL_SENSOR);
+    if (rv) return rv;
+
+    rv = reg_write(COM7, COM7_SRST);
+    if (rv) return rv;
+
+    // Delay 5 ms
+    eos_time_sleep(5);
+
+    // Write default regsiters
+    rv = regarr_write(default_regs);
+    if (rv) return rv;
+
+    // Delay 300 ms
+    eos_time_sleep(300);
+
+    return EOS_OK;
+}
+
+int eos_ov2640_sleep(int enable) {
+    uint8_t reg;
+    int rv;
+
+    rv = reg_write(BANK_SEL, BANK_SEL_SENSOR);
+    if (rv) return rv;
+
+    rv = reg_read(COM2, &reg);
+    if (rv) return rv;
+
+    if (enable) {
+        reg |= COM2_STDBY;
+    } else {
+        reg &= ~COM2_STDBY;
+    }
+
+    // Write back register
+    return reg_write(COM2, reg);
+}
+
+int eos_ov2640_set_pixfmt(pixformat_t fmt) {
+    const uint8_t (*regs)[2];
+
+    switch (fmt) {
+        case PIXFORMAT_RGB565:
+            regs = rgb565_regs;
+            break;
+        case PIXFORMAT_YUV422:
+        case PIXFORMAT_GRAYSCALE:
+            regs = yuv422_regs;
+            break;
+        case PIXFORMAT_BAYER:
+            regs = bayer_regs;
+            break;
+        case PIXFORMAT_JPEG:
+            regs = jpeg_regs;
+            break;
+        default:
+            return EOS_ERR;
+    }
+
+    return regarr_write(regs);
+}
+
+int eos_ov2640_set_framesize(framesize_t framesize) {
+    const uint8_t (*regs)[2];
+    uint16_t sensor_w = 0;
+    uint16_t sensor_h = 0;
+    uint16_t w = _eos_cam_resolution[framesize][0];
+    uint16_t h = _eos_cam_resolution[framesize][1];
+    int rv;
+
+    if ((w % 4) || (h % 4) || (w > UXGA_WIDTH) || (h > UXGA_HEIGHT)) { // w/h must be divisble by 4
+        return EOS_ERR;
+    }
+
+    // Looks really bad.
+    /* if ((w <= CIF_WIDTH) && (h <= CIF_HEIGHT)) {
+        regs = cif_regs;
+        sensor_w = CIF_WIDTH;
+        sensor_h = CIF_HEIGHT;
+    } else */ if ((w <= SVGA_WIDTH) && (h <= SVGA_HEIGHT)) {
+        regs = svga_regs;
+        sensor_w = SVGA_WIDTH;
+        sensor_h = SVGA_HEIGHT;
+    } else {
+        regs = uxga_regs;
+        sensor_w = UXGA_WIDTH;
+        sensor_h = UXGA_HEIGHT;
+    }
+
+    // Write setup regsiters
+    rv = regarr_write(regs);
+    if (rv) return rv;
+
+    uint64_t tmp_div = IM_MIN(sensor_w / w, sensor_h / h);
+    uint16_t log_div = IM_MIN(IM_LOG2(tmp_div) - 1, 3);
+    uint16_t div = 1 << log_div;
+    uint16_t w_mul = w * div;
+    uint16_t h_mul = h * div;
+    uint16_t x_off = (sensor_w - w_mul) / 2;
+    uint16_t y_off = (sensor_h - h_mul) / 2;
+
+    rv = EOS_OK;
+    if (!rv) rv = reg_write(CTRLI, CTRLI_LP_DP | CTRLI_V_DIV_SET(log_div) | CTRLI_H_DIV_SET(log_div));
+    if (!rv) rv = reg_write(HSIZE, HSIZE_SET(w_mul));
+    if (!rv) rv = reg_write(VSIZE, VSIZE_SET(h_mul));
+    if (!rv) rv = reg_write(XOFFL, XOFFL_SET(x_off));
+    if (!rv) rv = reg_write(YOFFL, YOFFL_SET(y_off));
+    if (!rv) rv = reg_write(VHYX, VHYX_HSIZE_SET(w_mul) | VHYX_VSIZE_SET(h_mul) | VHYX_XOFF_SET(x_off) | VHYX_YOFF_SET(y_off));
+    if (!rv) rv = reg_write(TEST, TEST_HSIZE_SET(w_mul));
+    if (!rv) rv = reg_write(ZMOW, ZMOW_OUTW_SET(w));
+    if (!rv) rv = reg_write(ZMOH, ZMOH_OUTH_SET(h));
+    if (!rv) rv = reg_write(ZMHH, ZMHH_OUTW_SET(w) | ZMHH_OUTH_SET(h));
+    if (!rv) rv = reg_write(R_DVP_SP, div);
+    if (!rv) rv = reg_write(RESET, 0x00);
+
+    return rv;
+}
+
+int eos_ov2640_set_contrast(int level) {
+    int rv = EOS_OK;
+
+    level += (NUM_CONTRAST_LEVELS / 2) + 1;
+    if (level <= 0 || level > NUM_CONTRAST_LEVELS) {
+        return EOS_ERR;
+    }
+
+    /* Switch to DSP register bank */
+    rv = reg_write(BANK_SEL, BANK_SEL_DSP);
+
+    /* Write contrast registers */
+    for (int i=0; i<sizeof(contrast_regs[0])/sizeof(contrast_regs[0][0]); i++) {
+        if (!rv) rv = reg_write(contrast_regs[0][i], contrast_regs[level][i]);
+    }
+
+    return rv;
+}
+
+int eos_ov2640_set_brightness(int level) {
+    int rv = EOS_OK;
+
+    level += (NUM_BRIGHTNESS_LEVELS / 2) + 1;
+    if (level <= 0 || level > NUM_BRIGHTNESS_LEVELS) {
+        return EOS_ERR;
+    }
+
+    /* Switch to DSP register bank */
+    rv = reg_write(BANK_SEL, BANK_SEL_DSP);
+
+    /* Write brightness registers */
+    for (int i=0; i<sizeof(brightness_regs[0])/sizeof(brightness_regs[0][0]); i++) {
+        if (!rv) rv = reg_write(brightness_regs[0][i], brightness_regs[level][i]);
+    }
+
+    return rv;
+}
+
+int eos_ov2640_set_saturation(int level) {
+    int rv = EOS_OK;
+
+    level += (NUM_SATURATION_LEVELS / 2) + 1;
+    if (level <= 0 || level > NUM_SATURATION_LEVELS) {
+        return EOS_ERR;
+    }
+
+    /* Switch to DSP register bank */
+    rv = reg_write(BANK_SEL, BANK_SEL_DSP);
+
+    /* Write saturation registers */
+    for (int i=0; i<sizeof(saturation_regs[0])/sizeof(saturation_regs[0][0]); i++) {
+        if (!rv) rv = reg_write(saturation_regs[0][i], saturation_regs[level][i]);
+    }
+
+    return rv;
+}
+
+int eos_ov2640_set_gainceiling(gainceiling_t gainceiling) {
+    int rv = EOS_OK;
+
+    /* Switch to SENSOR register bank */
+    rv = reg_write(BANK_SEL, BANK_SEL_SENSOR);
+
+    /* Write gain ceiling register */
+    if (!rv) rv = reg_write(COM9, COM9_AGC_SET(gainceiling));
+
+    return rv;
+}
+
+int eos_ov2640_set_quality(int qs) {
+    int rv = EOS_OK;
+
+    /* Switch to DSP register bank */
+    rv = reg_write(BANK_SEL, BANK_SEL_DSP);
+
+    /* Write QS register */
+    if (!rv) rv = reg_write(QS, qs);
+
+    return rv;
+}
+
+int eos_ov2640_set_colorbar(int enable) {
+    int rv = EOS_OK;
+    uint8_t reg;
+
+    rv = reg_write(BANK_SEL, BANK_SEL_SENSOR);
+    if (rv) return rv;
+
+    rv = reg_read(COM7, &reg);
+    if (rv) return rv;
+
+    if (enable) {
+        reg |= COM7_COLOR_BAR;
+    } else {
+        reg &= ~COM7_COLOR_BAR;
+    }
+
+    return reg_write(COM7, reg);
+}
+
+int eos_ov2640_set_auto_gain(int enable, float gain_db, float gain_db_ceiling) {
+    int rv = EOS_OK;
+    uint8_t reg;
+
+    rv = reg_write(BANK_SEL, BANK_SEL_SENSOR);
+    if (rv) return rv;
+
+    rv = reg_read(COM8, &reg);
+    if (rv) return rv;
+
+    rv = reg_write(COM8, (reg & (~COM8_AGC_EN)) | (enable ? COM8_AGC_EN : 0));
+    if (rv) return rv;
+
+    rv = EOS_OK;
+    if (enable && (!isnanf(gain_db_ceiling)) && (!isinff(gain_db_ceiling))) {
+        float gain_ceiling = IM_MAX(IM_MIN(expf((gain_db_ceiling / 20.0) * logf(10.0)), 128.0), 2.0);
+
+        if (!rv) rv = reg_read(COM9, &reg);
+        if (!rv) rv = reg_write(COM9, (reg & 0x1F) | (((int)ceilf(log2f(gain_ceiling)) - 1) << 5));
+    }
+
+    if (!enable && (!isnanf(gain_db)) && (!isinff(gain_db))) {
+        float gain = IM_MAX(IM_MIN(expf((gain_db / 20.0) * logf(10.0)), 32.0), 1.0);
+
+        int gain_temp = roundf(log2f(IM_MAX(gain / 2.0, 1.0)));
+        int gain_hi = 0xF >> (4 - gain_temp);
+        int gain_lo = IM_MIN(roundf(((gain / (1 << gain_temp)) - 1.0) * 16.0), 15);
+
+        if (!rv) rv = reg_write(GAIN, (gain_hi << 4) | (gain_lo << 0));
+    }
+
+    return rv;
+}
+
+int eos_ov2640_get_gain_db(float *gain_db) {
+    int rv = EOS_OK;
+    uint8_t reg, gain;
+
+    rv = reg_write(BANK_SEL, BANK_SEL_SENSOR);
+    if (rv) return rv;
+
+    rv = reg_read(COM8, &reg);
+    if (rv) return rv;
+
+    // DISABLED
+    // if (reg & COM8_AGC_EN) {
+    //     rv = reg_write(COM8, reg & (~COM8_AGC_EN));
+    //     if (rv) return rv;
+    // }
+    // DISABLED
+
+    rv = reg_read(GAIN, &gain);
+    if (rv) return rv;
+
+    // DISABLED
+    // if (reg & COM8_AGC_EN) {
+    //     rv = reg_write(COM8, reg | COM8_AGC_EN);
+    //     if (rv) return rv;
+    // }
+    // DISABLED
+
+    int hi_gain = 1 << (((gain >> 7) & 1) + ((gain >> 6) & 1) + ((gain >> 5) & 1) + ((gain >> 4) & 1));
+    float lo_gain = 1.0 + (((gain >> 0) & 0xF) / 16.0);
+    *gain_db = 20.0 * (logf(hi_gain * lo_gain) / logf(10.0));
+
+    return EOS_OK;
+}
+
+int eos_ov2640_set_auto_exposure(int enable, int exposure_us) {
+    int rv = EOS_OK;
+    uint8_t reg;
+
+    rv = reg_write(BANK_SEL, BANK_SEL_SENSOR);
+    if (rv) return rv;
+
+    rv = reg_read(COM8, &reg);
+    if (rv) return rv;
+
+    rv = reg_write(COM8, COM8_SET_AEC(reg, (enable != 0)));
+    if (rv) return rv;
+
+    if (!enable && (exposure_us >= 0)) {
+        rv = reg_read(COM7, &reg);
+        if (rv) return rv;
+
+        int t_line = 0;
+
+        if (COM7_GET_RES(reg) == COM7_RES_UXGA) t_line = 1600 + 322;
+        if (COM7_GET_RES(reg) == COM7_RES_SVGA) t_line = 800 + 390;
+        if (COM7_GET_RES(reg) == COM7_RES_CIF) t_line = 400 + 195;
+
+        rv = reg_read(CLKRC, &reg);
+        if (rv) return rv;
+
+        int pll_mult = ((reg & CLKRC_DOUBLE) ? 2 : 1) * 3;
+        int clk_rc = (reg & CLKRC_DIVIDER_MASK) + 2;
+
+        rv = reg_write(BANK_SEL, BANK_SEL_DSP);
+        if (rv) return rv;
+
+        rv = reg_read(IMAGE_MODE, &reg);
+        if (rv) return rv;
+
+        int t_pclk = 0;
+
+        if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_YUV422) t_pclk = 2;
+        if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_RAW10) t_pclk = 1;
+        if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_RGB565) t_pclk = 2;
+
+        int exposure = IM_MAX(IM_MIN(((exposure_us*(((XCLK_FREQ/clk_rc)*pll_mult)/1000000))/t_pclk)/t_line,0xFFFF),0x0000);
+
+        if (!rv) rv = reg_write(BANK_SEL, BANK_SEL_SENSOR);
+
+        if (!rv) rv = reg_read(REG04, &reg);
+        if (!rv) rv = reg_write(REG04, (reg & 0xFC) | ((exposure >> 0) & 0x3));
+
+        if (!rv) rv = reg_read(AEC, &reg);
+        if (!rv) rv = reg_write(AEC, (reg & 0x00) | ((exposure >> 2) & 0xFF));
+
+        if (!rv) rv = reg_read(REG45, &reg);
+        if (!rv) rv = reg_write(REG45, (reg & 0xC0) | ((exposure >> 10) & 0x3F));
+    }
+
+    return rv;
+}
+
+int eos_ov2640_get_exposure_us(int *exposure_us) {
+    int rv = EOS_OK;
+    uint8_t reg, aec_10, aec_92, aec_1510;
+
+    rv = reg_write(BANK_SEL, BANK_SEL_SENSOR);
+    if (rv) return rv;
+
+    rv = reg_read(COM8, &reg);
+    if (rv) return rv;
+
+    // DISABLED
+    // if (reg & COM8_AEC_EN) {
+    //     rv = reg_write(COM8, reg & (~COM8_AEC_EN));
+    //     if (rv) return rv;
+    // }
+    // DISABLED
+
+    rv = reg_read(REG04, &aec_10);
+    if (rv) return rv;
+
+    rv = reg_read(AEC, &aec_92);
+    if (rv) return rv;
+
+    rv = reg_read(REG45, &aec_1510);
+    if (rv) return rv;
+
+    // DISABLED
+    // if (reg & COM8_AEC_EN) {
+    //     rv = reg_write(COM8, reg | COM8_AEC_EN);
+    //     if (rv) return rv;
+    // }
+    // DISABLED
+
+    rv = reg_read(COM7, &reg);
+    if (rv) return rv;
+
+    int t_line = 0;
+
+    if (COM7_GET_RES(reg) == COM7_RES_UXGA) t_line = 1600 + 322;
+    if (COM7_GET_RES(reg) == COM7_RES_SVGA) t_line = 800 + 390;
+    if (COM7_GET_RES(reg) == COM7_RES_CIF) t_line = 400 + 195;
+
+    rv = reg_read(CLKRC, &reg);
+    if (rv) return rv;
+
+    int pll_mult = ((reg & CLKRC_DOUBLE) ? 2 : 1) * 3;
+    int clk_rc = (reg & CLKRC_DIVIDER_MASK) + 2;
+
+    rv = reg_write(BANK_SEL, BANK_SEL_DSP);
+    if (rv) return rv;
+
+    rv = reg_read(IMAGE_MODE, &reg);
+    if (rv) return rv;
+
+    int t_pclk = 0;
+
+    if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_YUV422) t_pclk = 2;
+    if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_RAW10) t_pclk = 1;
+    if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_RGB565) t_pclk = 2;
+
+    uint16_t exposure = ((aec_1510 & 0x3F) << 10) + ((aec_92 & 0xFF) << 2) + ((aec_10 & 0x3) << 0);
+    *exposure_us = (exposure*t_line*t_pclk)/(((XCLK_FREQ/clk_rc)*pll_mult)/1000000);
+
+    return EOS_OK;
+}
+
+int eos_ov2640_set_auto_whitebal(int enable, float r_gain_db, float g_gain_db, float b_gain_db) {
+    int rv = EOS_OK;
+    uint8_t reg;
+
+    rv = reg_write(BANK_SEL, BANK_SEL_DSP);
+    if (rv) return rv;
+
+    rv = reg_read(CTRL1, &reg);
+    if (rv) return rv;
+
+    rv = reg_write(CTRL1, (reg & (~CTRL1_AWB)) | (enable ? CTRL1_AWB : 0));
+    if (rv) return rv;
+
+    if (!enable && (!isnanf(r_gain_db)) && (!isnanf(g_gain_db)) && (!isnanf(b_gain_db))
+                && (!isinff(r_gain_db)) && (!isinff(g_gain_db)) && (!isinff(b_gain_db))) {
+    }
+
+    return rv;
+}
+
+int eos_ov2640_set_hmirror(int enable) {
+    int rv = EOS_OK;
+    uint8_t reg;
+
+    rv = reg_write(BANK_SEL, BANK_SEL_SENSOR);
+    if (rv) return rv;
+
+    rv = reg_read(REG04, &reg);
+    if (rv) return rv;
+
+    if (!enable) { // Already mirrored.
+        reg |= REG04_HFLIP_IMG;
+    } else {
+        reg &= ~REG04_HFLIP_IMG;
+    }
+
+    return reg_write(REG04, reg);
+}
+
+int eos_ov2640_set_vflip(int enable) {
+    int rv = EOS_OK;
+    uint8_t reg;
+
+    rv = reg_write(BANK_SEL, BANK_SEL_SENSOR);
+    if (rv) return rv;
+
+    rv = reg_read(REG04, &reg);
+    if (rv) return rv;
+
+    if (!enable) { // Already flipped.
+        reg |= REG04_VFLIP_IMG | REG04_VREF_EN;
+    } else {
+        reg &= ~(REG04_VFLIP_IMG | REG04_VREF_EN);
+    }
+
+    return reg_write(REG04, reg);
+}
+
+int eos_ov2640_set_effect(sde_t sde) {
+    int rv = EOS_OK;
+
+    switch (sde) {
+        case SDE_NEGATIVE:
+            if (!rv) rv = reg_write(BANK_SEL, BANK_SEL_DSP);
+            if (!rv) rv = reg_write(BPADDR, 0x00);
+            if (!rv) rv = reg_write(BPDATA, 0x40);
+            if (!rv) rv = reg_write(BPADDR, 0x05);
+            if (!rv) rv = reg_write(BPDATA, 0x80);
+            if (!rv) rv = reg_write(BPDATA, 0x80);
+            break;
+        case SDE_NORMAL:
+            if (!rv) rv = reg_write(BANK_SEL, BANK_SEL_DSP);
+            if (!rv) rv = reg_write(BPADDR, 0x00);
+            if (!rv) rv = reg_write(BPDATA, 0x00);
+            if (!rv) rv = reg_write(BPADDR, 0x05);
+            if (!rv) rv = reg_write(BPDATA, 0x80);
+            if (!rv) rv = reg_write(BPDATA, 0x80);
+            break;
+        default:
+            return EOS_ERR;
+    }
+
+    return rv;
+}
diff --git a/fw/fe310/eos/dev/ov2640.h b/fw/fe310/eos/dev/ov2640.h
new file mode 100644
index 0000000..3d08c2a
--- /dev/null
+++ b/fw/fe310/eos/dev/ov2640.h
@@ -0,0 +1,8 @@
+#include <stdint.h>
+
+#define OV2640_ADDR     0x30
+
+int eos_ov2640_init(void);
+int eos_ov2640_sleep(int enable);
+int eos_ov2640_set_pixfmt(pixformat_t fmt);
+int eos_ov2640_set_framesize(framesize_t framesize);
diff --git a/fw/fe310/eos/dev/ov2640_regs.h b/fw/fe310/eos/dev/ov2640_regs.h
new file mode 100644
index 0000000..deb7521
--- /dev/null
+++ b/fw/fe310/eos/dev/ov2640_regs.h
@@ -0,0 +1,245 @@
+/*
+ * This file is part of the OpenMV project.
+ *
+ * Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
+ * Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
+ *
+ * This work is licensed under the MIT license, see the file LICENSE for details.
+ *
+ * OV2640 register definitions.
+ */
+#ifndef __REG_REGS_H__
+#define __REG_REGS_H__
+
+/* DSP register bank FF=0x00*/
+
+#define QS                      0x44
+#define HSIZE                   0x51
+#define VSIZE                   0x52
+#define XOFFL                   0x53
+#define YOFFL                   0x54
+#define VHYX                    0x55
+#define DPRP                    0x56
+#define TEST                    0x57
+#define ZMOW                    0x5A
+#define ZMOH                    0x5B
+#define ZMHH                    0x5C
+#define BPADDR                  0x7C
+#define BPDATA                  0x7D
+#define SIZEL                   0x8C
+#define HSIZE8                  0xC0
+#define VSIZE8                  0xC1
+#define CTRL1                   0xC3
+#define MS_SP                   0xF0
+#define SS_ID                   0xF7
+#define SS_CTRL                 0xF7
+#define MC_AL                   0xFA
+#define MC_AH                   0xFB
+#define MC_D                    0xFC
+#define P_CMD                   0xFD
+#define P_STATUS                0xFE
+
+#define CTRLI                   0x50
+#define CTRLI_LP_DP             0x80
+#define CTRLI_ROUND             0x40
+
+#define CTRL0                   0xC2
+#define CTRL0_AEC_EN            0x80
+#define CTRL0_AEC_SEL           0x40
+#define CTRL0_STAT_SEL          0x20
+#define CTRL0_VFIRST            0x10
+#define CTRL0_YUV422            0x08
+#define CTRL0_YUV_EN            0x04
+#define CTRL0_RGB_EN            0x02
+#define CTRL0_RAW_EN            0x01
+
+#define CTRL2                   0x86
+#define CTRL2_DCW_EN            0x20
+#define CTRL2_SDE_EN            0x10
+#define CTRL2_UV_ADJ_EN         0x08
+#define CTRL2_UV_AVG_EN         0x04
+#define CTRL2_CMX_EN            0x01
+
+#define CTRL3                   0x87
+#define CTRL3_BPC_EN            0x80
+#define CTRL3_WPC_EN            0x40
+#define R_DVP_SP                0xD3
+#define R_DVP_SP_AUTO_MODE      0x80
+
+#define R_BYPASS                0x05
+#define R_BYPASS_DSP_EN         0x00
+#define R_BYPASS_DSP_BYPAS      0x01
+
+#define IMAGE_MODE              0xDA
+#define IMAGE_MODE_Y8_DVP_EN    0x40
+#define IMAGE_MODE_JPEG_EN      0x10
+#define IMAGE_MODE_YUV422       0x00
+#define IMAGE_MODE_RAW10        0x04
+#define IMAGE_MODE_RGB565       0x09
+#define IMAGE_MODE_HREF_VSYNC   0x02
+#define IMAGE_MODE_LBYTE_FIRST  0x01
+#define IMAGE_MODE_GET_FMT(x)   ((x)&0xC)
+
+#define RESET                   0xE0
+#define RESET_MICROC            0x40
+#define RESET_SCCB              0x20
+#define RESET_JPEG              0x10
+#define RESET_DVP               0x04
+#define RESET_IPU               0x02
+#define RESET_CIF               0x01
+
+#define MC_BIST                 0xF9
+#define MC_BIST_RESET           0x80
+#define MC_BIST_BOOT_ROM_SEL    0x40
+#define MC_BIST_12KB_SEL        0x20
+#define MC_BIST_12KB_MASK       0x30
+#define MC_BIST_512KB_SEL       0x08
+#define MC_BIST_512KB_MASK      0x0C
+#define MC_BIST_BUSY_BIT_R      0x02
+#define MC_BIST_MC_RES_ONE_SH_W 0x02
+#define MC_BIST_LAUNCH          0x01
+
+#define BANK_SEL                0xFF
+#define BANK_SEL_DSP            0x00
+#define BANK_SEL_SENSOR         0x01
+
+/* Sensor register bank FF=0x01*/
+
+#define GAIN                0x00
+#define COM1                0x03
+#define REG_PID             0x0A
+#define REG_VER             0x0B
+#define COM4                0x0D
+#define AEC                 0x10
+
+#define CLKRC               0x11
+#define CLKRC_DOUBLE        0x80
+#define CLKRC_DIVIDER_MASK  0x3F
+
+#define COM10               0x15
+#define HSTART              0x17
+#define HSTOP               0x18
+#define VSTART              0x19
+#define VSTOP               0x1A
+#define MIDH                0x1C
+#define MIDL                0x1D
+#define AEW                 0x24
+#define AEB                 0x25
+#define REG2A               0x2A
+#define FRARL               0x2B
+#define ADDVSL              0x2D
+#define ADDVSH              0x2E
+#define YAVG                0x2F
+#define HSDY                0x30
+#define HEDY                0x31
+#define ARCOM2              0x34
+#define REG45               0x45
+#define FLL                 0x46
+#define FLH                 0x47
+#define COM19               0x48
+#define ZOOMS               0x49
+#define COM22               0x4B
+#define COM25               0x4E
+#define BD50                0x4F
+#define BD60                0x50
+#define REG5D               0x5D
+#define REG5E               0x5E
+#define REG5F               0x5F
+#define REG60               0x60
+#define HISTO_LOW           0x61
+#define HISTO_HIGH          0x62
+
+#define REG04               0x04
+#define REG04_DEFAULT       0x28
+#define REG04_HFLIP_IMG     0x80
+#define REG04_VFLIP_IMG     0x40
+#define REG04_VREF_EN       0x10
+#define REG04_HREF_EN       0x08
+#define REG04_SET(x)        (REG04_DEFAULT|x)
+
+#define REG08               0x08
+#define COM2                0x09
+#define COM2_STDBY          0x10
+#define COM2_OUT_DRIVE_1x   0x00
+#define COM2_OUT_DRIVE_2x   0x01
+#define COM2_OUT_DRIVE_3x   0x02
+#define COM2_OUT_DRIVE_4x   0x03
+
+#define COM3                0x0C
+#define COM3_DEFAULT        0x38
+#define COM3_BAND_50Hz      0x04
+#define COM3_BAND_60Hz      0x00
+#define COM3_BAND_AUTO      0x02
+#define COM3_BAND_SET(x)    (COM3_DEFAULT|x)
+
+#define COM7                0x12
+#define COM7_SRST           0x80
+#define COM7_RES_UXGA       0x00 /* UXGA */
+#define COM7_RES_SVGA       0x40 /* SVGA */
+#define COM7_RES_CIF        0x20 /* CIF  */
+#define COM7_ZOOM_EN        0x04 /* Enable Zoom */
+#define COM7_COLOR_BAR      0x02 /* Enable Color Bar Test */
+#define COM7_GET_RES(x)     ((x)&0x70)
+
+#define COM8                0x13
+#define COM8_DEFAULT        0xC0
+#define COM8_BNDF_EN        0x20 /* Enable Banding filter */
+#define COM8_AGC_EN         0x04 /* AGC Auto/Manual control selection */
+#define COM8_AEC_EN         0x01 /* Auto/Manual Exposure control */
+#define COM8_SET(x)         (COM8_DEFAULT|x)
+#define COM8_SET_AEC(r,x)   (((r)&0xFE)|((x)&1))
+
+#define COM9                0x14 /* AGC gain ceiling */
+#define COM9_DEFAULT        0x08
+#define COM9_AGC_GAIN_2x    0x00 /* AGC:    2x */
+#define COM9_AGC_GAIN_4x    0x01 /* AGC:    4x */
+#define COM9_AGC_GAIN_8x    0x02 /* AGC:    8x */
+#define COM9_AGC_GAIN_16x   0x03 /* AGC:   16x */
+#define COM9_AGC_GAIN_32x   0x04 /* AGC:   32x */
+#define COM9_AGC_GAIN_64x   0x05 /* AGC:   64x */
+#define COM9_AGC_GAIN_128x  0x06 /* AGC:  128x */
+#define COM9_AGC_SET(x)     (COM9_DEFAULT|(x<<5))
+
+#define CTRL1_AWB           0x08 /* Enable AWB */
+
+#define VV                  0x26
+#define VV_AGC_TH_SET(h,l)  ((h<<4)|(l&0x0F))
+
+#define REG32               0x32
+#define REG32_UXGA          0x36
+#define REG32_SVGA          0x09
+#define REG32_CIF           0x00
+
+#define VAL_SET(x, mask, rshift, lshift) ((((x) >> rshift) & mask) << lshift)
+
+#define CTRLI_V_DIV_SET(x)      VAL_SET(x, 0x3, 0, 3)
+#define CTRLI_H_DIV_SET(x)      VAL_SET(x, 0x3, 0, 0)
+
+#define SIZEL_HSIZE8_11_SET(x)  VAL_SET(x, 0x1, 11, 6)
+#define SIZEL_HSIZE8_SET(x)     VAL_SET(x, 0x7, 0, 3)
+#define SIZEL_VSIZE8_SET(x)     VAL_SET(x, 0x7, 0, 0)
+
+#define HSIZE8_SET(x)           VAL_SET(x, 0xFF, 3, 0)
+#define VSIZE8_SET(x)           VAL_SET(x, 0xFF, 3, 0)
+
+#define HSIZE_SET(x)            VAL_SET(x, 0xFF, 2, 0)
+#define VSIZE_SET(x)            VAL_SET(x, 0xFF, 2, 0)
+
+#define XOFFL_SET(x)            VAL_SET(x, 0xFF, 0, 0)
+#define YOFFL_SET(x)            VAL_SET(x, 0xFF, 0, 0)
+
+#define VHYX_VSIZE_SET(x)       VAL_SET(x, 0x1, (8+2), 7)
+#define VHYX_HSIZE_SET(x)       VAL_SET(x, 0x1, (8+2), 3)
+#define VHYX_YOFF_SET(x)        VAL_SET(x, 0x3, 8, 4)
+#define VHYX_XOFF_SET(x)        VAL_SET(x, 0x3, 8, 0)
+
+#define TEST_HSIZE_SET(x)       VAL_SET(x, 0x1, (9+2), 7)
+
+#define ZMOW_OUTW_SET(x)        VAL_SET(x, 0xFF, 2, 0)
+#define ZMOH_OUTH_SET(x)        VAL_SET(x, 0xFF, 2, 0)
+
+#define ZMHH_ZSPEED_SET(x)      VAL_SET(x, 0x0F, 0, 4)
+#define ZMHH_OUTH_SET(x)        VAL_SET(x, 0x1, (8+2), 2)
+#define ZMHH_OUTW_SET(x)        VAL_SET(x, 0x3, (8+2), 0)
+
+#endif //__REG_REGS_H__
diff --git a/fw/fe310/eos/dev/sdc_crypto.c b/fw/fe310/eos/dev/sdc_crypto.c
new file mode 100644
index 0000000..f0e935d
--- /dev/null
+++ b/fw/fe310/eos/dev/sdc_crypto.c
@@ -0,0 +1,51 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "sha/sha1.h"
+#include "sdc_crypto.h"
+
+#define SDC_CRYPTO_KEY_SIZE     16
+#define SDC_CRYPTO_BLK_SIZE     16
+#define SDC_CRYPTO_HASH_SIZE    20
+
+EOSSDCCrypto *sdc_crypto;
+
+void eos_sdcc_init(EOSSDCCrypto *crypto, uint8_t *key, void *ctx, eve_sdcc_init_t init, eve_sdcc_crypt_t enc, eve_sdcc_crypt_t dec, void *ctx_essiv, eve_sdcc_init_t init_essiv, eve_sdcc_essiv_t enc_essiv) {
+    char key_essiv[SDC_CRYPTO_HASH_SIZE];
+
+    sdc_crypto = crypto;
+
+    memset(key_essiv, 0, SDC_CRYPTO_HASH_SIZE);
+    init(ctx, key);
+    sdc_crypto->ctx = ctx;
+    sdc_crypto->enc = enc;
+    sdc_crypto->dec = dec;
+
+    SHA1(key_essiv, key, SDC_CRYPTO_KEY_SIZE);
+    init_essiv(ctx_essiv, key_essiv);
+    sdc_crypto->ctx_essiv = ctx_essiv;
+    sdc_crypto->enc_essiv = enc_essiv;
+}
+
+void eos_sdcc_encrypt(uint32_t sect, uint8_t *buffer) {
+    uint8_t iv[SDC_CRYPTO_BLK_SIZE];
+
+    if (sdc_crypto == NULL) return;
+
+    memset(iv, 0, SDC_CRYPTO_BLK_SIZE);
+    memcpy(iv, &sect, sizeof(sect));
+    sdc_crypto->enc_essiv(sdc_crypto->ctx_essiv, iv);
+    sdc_crypto->enc(sdc_crypto->ctx, iv, buffer, 512);
+}
+
+void eos_sdcc_decrypt(uint32_t sect, uint8_t *buffer) {
+    uint8_t iv[SDC_CRYPTO_BLK_SIZE];
+
+    if (sdc_crypto == NULL) return;
+
+    memset(iv, 0, SDC_CRYPTO_BLK_SIZE);
+    memcpy(iv, &sect, sizeof(sect));
+    sdc_crypto->enc_essiv(sdc_crypto->ctx_essiv, iv);
+    sdc_crypto->dec(sdc_crypto->ctx, iv, buffer, 512);
+}
diff --git a/fw/fe310/eos/dev/sdc_crypto.h b/fw/fe310/eos/dev/sdc_crypto.h
new file mode 100644
index 0000000..015bf8a
--- /dev/null
+++ b/fw/fe310/eos/dev/sdc_crypto.h
@@ -0,0 +1,18 @@
+#include <stddef.h>
+#include <stdint.h>
+
+typedef void (*eve_sdcc_init_t) (void *, uint8_t *);
+typedef void (*eve_sdcc_crypt_t) (void *, uint8_t *, uint8_t *, size_t);
+typedef void (*eve_sdcc_essiv_t) (void *, uint8_t *);
+
+typedef struct EOSSDCCrypto {
+    void *ctx;
+    eve_sdcc_crypt_t enc;
+    eve_sdcc_crypt_t dec;
+    void *ctx_essiv;
+    eve_sdcc_essiv_t enc_essiv;
+} EOSSDCCrypto;
+
+void eos_sdcc_init(EOSSDCCrypto *crypto, uint8_t *key, void *ctx, eve_sdcc_init_t init, eve_sdcc_crypt_t enc, eve_sdcc_crypt_t dec, void *ctx_essiv, eve_sdcc_init_t init_essiv, eve_sdcc_essiv_t enc_essiv);
+void eos_sdcc_encrypt(uint32_t sect, uint8_t *buffer);
+void eos_sdcc_decrypt(uint32_t sect, uint8_t *buffer);
\ No newline at end of file
diff --git a/fw/fe310/eos/dev/sdcard.c b/fw/fe310/eos/dev/sdcard.c
new file mode 100644
index 0000000..d081388
--- /dev/null
+++ b/fw/fe310/eos/dev/sdcard.c
@@ -0,0 +1,539 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "eos.h"
+#include "timer.h"
+
+#include "spi.h"
+#include "spi_dev.h"
+
+#include "sdc_crypto.h"
+#include "sdcard.h"
+
+#define SDC_TIMEOUT_CMD         500
+#define SDC_TIMEOUT_READ        200
+#define SDC_TIMEOUT_WRITE       500
+
+#define SDC_POLY_CRC7           0x09
+#define SDC_POLY_CRC16          0x1021
+
+#define SDC_CMD_FLAG_CRC        0x01
+#define SDC_CMD_FLAG_NOCS       0x02
+#define SDC_CMD_FLAG_NOWAIT     0x04
+#define SDC_CMD_FLAG_RSTUFF     0x08
+
+#define SDC_TOKEN_START_BLK     0xfe
+#define SDC_TOKEN_START_BLKM    0xfc
+#define SDC_TOKEN_STOP_TRAN     0xfd
+
+#define SDC_DRESP_MASK          0x1f
+#define SDC_DRESP_ACCEPT        0x05
+#define SDC_DRESP_ERR_CRC       0x0b
+#define SDC_DRESP_ERR_WRITE     0x0d
+
+#define SDC_R1_READY            0x00
+
+#define SDC_R1_IDLE_STATE       0x01
+#define SDC_R1_ERASE_RESET      0x02
+#define SDC_R1_ILLEGAL_CMD      0x04
+#define SDC_R1_ERR_CMD_CRC      0x08
+#define SDC_R1_ERR_ERASE_SEQ    0x10
+#define SDC_R1_ERR_ADDR         0x20
+#define SDC_R1_ERR_PARAM        0x40
+
+#define SDC_NCR                 10
+
+#define SDC_ERR(rv)             ((rv < 0) ? rv : EOS_ERR)
+
+/* CMD */
+#define GO_IDLE_STATE           0
+#define SEND_OP_COND            1
+#define SEND_IF_COND            8
+#define SEND_CSD                9
+#define STOP_TRANSMISSION       12
+#define SET_BLOCKLEN            16
+#define READ_SINGLE_BLOCK       17
+#define READ_MULTIPLE_BLOCK     18
+#define WRITE_BLOCK             24
+#define WRITE_MULTIPLE_BLOCK    25
+#define ERASE_WR_BLK_START      32
+#define ERASE_WR_BLK_END        33
+#define ERASE                   38
+#define APP_CMD                 55
+#define READ_OCR                58
+
+/* ACMD */
+#define SD_STATUS               13
+#define SET_WR_BLK_ERASE_COUNT  23
+#define SD_APP_OP_COND          41
+
+static uint8_t sdc_type = 0;
+
+static uint8_t sdc_crc7(uint8_t crc, uint8_t b) {
+    int i;
+
+    for (i=8; i--; b<<=1) {
+        crc <<= 1;
+        if ((b ^ crc) & 0x80) crc ^= SDC_POLY_CRC7;
+    }
+    return crc & 0x7f;
+}
+
+static uint16_t sdc_crc16(uint16_t crc, uint8_t b) {
+    int i;
+
+    crc = crc ^ ((uint16_t)b << 8);
+    for (i=8; i--;) {
+        if (crc & 0x8000) {
+            crc = (crc << 1) ^ SDC_POLY_CRC16;
+        } else {
+            crc <<= 1;
+        }
+    }
+    return crc;
+}
+
+static uint32_t sdc_nto(uint32_t start, uint32_t timeout) {
+    uint32_t d = eos_time_delta_ms(start);
+    return (d > timeout) ? 0 : timeout - d;
+}
+
+static uint8_t sdc_xchg8(uint8_t data) {
+    return eos_spi_xchg8(data, 0);
+}
+
+static uint16_t sdc_xchg16(uint16_t data) {
+    return eos_spi_xchg16(data, 0);
+}
+
+static uint32_t sdc_xchg32(uint32_t data) {
+    return eos_spi_xchg32(data, 0);
+}
+
+static void sdc_buf_send(unsigned char *buffer, uint16_t len) {
+    int i;
+
+    for (i=0; i<len; i++) {
+        sdc_xchg8(buffer[i]);
+    }
+}
+
+static void sdc_buf_recv(unsigned char *buffer, uint16_t len) {
+    int i;
+
+    for (i=0; i<len; i++) {
+        buffer[i] = sdc_xchg8(0xff);
+    }
+}
+
+static void sdc_select(void) {
+    eos_spi_cs_set();
+    eos_spi_xchg8(0xff, 0);
+}
+
+static void sdc_deselect(void) {
+    eos_spi_cs_clear();
+    eos_spi_xchg8(0xff, 0);
+}
+
+static int sdc_xchg_cmd(uint8_t cmd, uint32_t arg, uint8_t flags) {
+    int i;
+    uint8_t ret;
+    uint8_t crc = 0x7f;
+
+    cmd |= 0x40;
+    if (flags & SDC_CMD_FLAG_CRC) {
+        crc = sdc_crc7(0, cmd);
+        crc = sdc_crc7(crc, arg >> 24);
+        crc = sdc_crc7(crc, arg >> 16);
+        crc = sdc_crc7(crc, arg >> 8);
+        crc = sdc_crc7(crc, arg);
+    }
+    crc = (crc << 1) | 0x01;
+    sdc_xchg8(cmd);
+    sdc_xchg32(arg);
+    sdc_xchg8(crc);
+    if (flags & SDC_CMD_FLAG_RSTUFF) sdc_xchg8(0xff);
+
+    i = SDC_NCR;
+    do {
+        ret = sdc_xchg8(0xff);
+    } while ((ret & 0x80) && --i);
+    if (ret & 0x80) return EOS_ERR_BUSY;
+
+    return ret;
+}
+
+static int sdc_ready(uint32_t timeout) {
+    uint8_t d = 0;
+    uint32_t start;
+
+    if (timeout == 0) return EOS_ERR_BUSY;
+    start = eos_time_get_tick();
+    do {
+        if (eos_time_delta_ms(start) > timeout) break;
+        d = sdc_xchg8(0xff);
+    } while (d != 0xff);
+    if (d != 0xff) return EOS_ERR_BUSY;
+
+    return EOS_OK;
+}
+
+static int sdc_block_read(uint8_t *buffer, uint16_t len, uint32_t timeout) {
+    uint8_t token = 0xff;
+    uint32_t start;
+
+    if (timeout == 0) return EOS_ERR_BUSY;
+    start = eos_time_get_tick();
+    do {
+        if (eos_time_delta_ms(start) > timeout) break;
+        token = sdc_xchg8(0xff);
+    } while (token == 0xff);
+    if (token == 0xff) return EOS_ERR_BUSY;
+    if (token != SDC_TOKEN_START_BLK) return EOS_ERR;
+
+    sdc_buf_recv(buffer, len);
+    sdc_xchg16(0xffff); /* dummy CRC */
+
+    return EOS_OK;
+}
+
+static int sdc_block_write(uint8_t token, uint8_t *buffer, uint16_t len, uint32_t timeout) {
+    uint8_t d;
+    int rv;
+
+    rv = sdc_ready(timeout);
+    if (rv) return rv;
+
+    sdc_xchg8(token);
+    if (buffer && len) {
+        sdc_buf_send(buffer, len);
+        sdc_xchg16(0xffff); /* dummy CRC */
+
+        d = sdc_xchg8(0xff); /* Response */
+        if ((d & SDC_DRESP_MASK) != SDC_DRESP_ACCEPT) return EOS_ERR;
+    }
+
+    return EOS_OK;
+}
+
+static int sdc_cmd(uint8_t cmd, uint32_t arg, uint8_t flags, uint32_t timeout) {
+    int do_cs = !(flags & SDC_CMD_FLAG_NOCS);
+    int do_wait = !(flags & SDC_CMD_FLAG_NOWAIT);
+    int rv = EOS_OK;
+
+    if (do_cs) sdc_select();
+    if (do_wait) rv = sdc_ready(timeout);
+    if (rv) {
+        if (do_cs) sdc_deselect();
+        return rv;
+    }
+    rv = sdc_xchg_cmd(cmd, arg, flags);
+    if (do_cs) sdc_deselect();
+    return rv;
+}
+
+static int sdc_acmd(uint8_t cmd, uint32_t arg, uint8_t flags, uint32_t timeout) {
+    int rv;
+    uint32_t start;
+
+    start = eos_time_get_tick();
+    rv = sdc_cmd(APP_CMD, 0, flags, timeout);
+    if (rv & ~SDC_R1_IDLE_STATE) return rv;
+
+    if (flags & SDC_CMD_FLAG_NOCS) {
+        sdc_deselect();
+        sdc_select();
+    }
+    return sdc_cmd(cmd, arg, flags, sdc_nto(start, timeout));
+}
+
+static int sdc_init(uint32_t timeout) {
+    int rv, i;
+    uint8_t _type;
+    uint8_t ocr[4];
+    uint32_t start;
+    start = eos_time_get_tick();
+
+    eos_time_sleep(100);
+    for (i=10; i--;) sdc_xchg8(0xff);     /* 80 dummy cycles */
+
+    rv = sdc_cmd(GO_IDLE_STATE, 0, SDC_CMD_FLAG_CRC, SDC_TIMEOUT_CMD);
+    if (rv != SDC_R1_IDLE_STATE) return SDC_ERR(rv);
+
+    sdc_select();
+    rv = sdc_cmd(SEND_IF_COND, 0x1aa, SDC_CMD_FLAG_CRC | SDC_CMD_FLAG_NOCS, sdc_nto(start, timeout));
+    switch (rv) {
+        case SDC_R1_IDLE_STATE:
+            for (i=0; i<4; i++) {   /* R7 response */
+                ocr[i] = sdc_xchg8(0xff);
+            }
+            sdc_deselect();
+            if (ocr[2] == 0x01 && ocr[3] == 0xaa) {     /* Check voltage range: 2.7-3.6V */
+                do {
+                    rv = sdc_acmd(SD_APP_OP_COND, 0x40000000, 0, sdc_nto(start, timeout));
+                } while (rv == SDC_R1_IDLE_STATE);
+                if (rv != SDC_R1_READY) return SDC_ERR(rv);
+
+                sdc_select();
+                rv = sdc_cmd(READ_OCR, 0, SDC_CMD_FLAG_NOCS, sdc_nto(start, timeout));
+                if (rv == SDC_R1_READY) {
+                    for (i=0; i<4; i++) {   /* R7 response */
+                        ocr[i] = sdc_xchg8(0xff);
+                    }
+                    sdc_deselect();
+                } else {
+                    sdc_deselect();
+                    return SDC_ERR(rv);
+                }
+
+                _type = EOS_SDC_TYPE_SDC2;
+                if (ocr[0] & 0xc0) _type |= EOS_SDC_CAP_BLK;
+            }
+            break;
+
+        case SDC_R1_IDLE_STATE | SDC_R1_ILLEGAL_CMD:
+            sdc_deselect();
+            rv = sdc_acmd(SD_APP_OP_COND, 0, 0, sdc_nto(start, timeout));
+            switch (rv) {
+                case SDC_R1_IDLE_STATE:
+                    do  {
+                        rv = sdc_acmd(SD_APP_OP_COND, 0, 0, sdc_nto(start, timeout));
+                    } while (rv == SDC_R1_IDLE_STATE);
+                    if (rv != SDC_R1_READY) return SDC_ERR(rv);
+                case SDC_R1_READY:
+                    _type = EOS_SDC_TYPE_SDC1;
+                    break;
+
+                default:
+                    do {
+                        rv = sdc_cmd(SEND_OP_COND, 0, 0, sdc_nto(start, timeout));
+                    } while (rv == SDC_R1_IDLE_STATE);
+                    if (rv != SDC_R1_READY) return SDC_ERR(rv);
+                    _type = EOS_SDC_TYPE_MMC;
+                    break;
+
+            }
+            break;
+
+        default:
+            sdc_deselect();
+            return SDC_ERR(rv);
+    }
+
+    if (!(_type & EOS_SDC_CAP_BLK)) {
+        rv = sdc_cmd(SET_BLOCKLEN, 512, 0, sdc_nto(start, timeout));
+        if (rv != SDC_R1_READY) return SDC_ERR(rv);
+    }
+
+    if (_type & EOS_SDC_TYPE_SDC) {
+        uint8_t csd[16];
+
+        sdc_select();
+        rv = sdc_cmd(SEND_CSD, 0, SDC_CMD_FLAG_NOCS, sdc_nto(start, timeout));
+        if (rv == SDC_R1_READY) {
+            rv = sdc_block_read(csd, 16, sdc_nto(start, timeout));
+        } else {
+            rv = SDC_ERR(rv);
+        }
+        sdc_deselect();
+        if (rv) return rv;
+
+        for (i=0; i<16; i++) {
+            printf("%.2x ", csd[i]);
+        }
+        printf("\n");
+        if (csd[10] & 0x40) _type |= EOS_SDC_CAP_ERASE_EN;
+    }
+
+    eos_spi_set_div(EOS_SPI_DEV_SDC, 5);
+    sdc_type = _type;
+    return EOS_OK;
+}
+
+int eos_sdc_init(uint8_t wakeup_cause) {
+    int rv;
+
+    eos_spi_select(EOS_SPI_DEV_SDC);
+    rv = sdc_init(5000);
+    if (rv) {
+        printf("SDC ERROR\n");
+    } else {
+        printf("SDC OK:%x\n", sdc_type);
+    }
+    eos_spi_deselect();
+
+    return EOS_OK;
+}
+
+uint8_t eos_sdc_type(void) {
+    return sdc_type & EOS_SDC_TYPE_MASK;
+}
+
+uint8_t eos_sdc_cap(void) {
+    return sdc_type & EOS_SDC_CAP_MASK;
+}
+
+int eos_sdc_get_sect_count(uint32_t timeout, uint32_t *sectors) {
+    int rv;
+    uint8_t csd[16];
+    uint32_t start = eos_time_get_tick();
+
+    sdc_select();
+    rv = sdc_cmd(SEND_CSD, 0, SDC_CMD_FLAG_NOCS, timeout);
+    if (rv == SDC_R1_READY) {
+        rv = sdc_block_read(csd, 16, sdc_nto(start, timeout));
+    } else {
+        rv = SDC_ERR(rv);
+    }
+    sdc_deselect();
+    if (rv) return rv;
+
+    if ((csd[0] >> 6) == 1) {   /* SDCv2 */
+        *sectors = (csd[9] + (csd[8] << 8) + ((csd[7] & 0x3f) << 16) + 1) << 10;
+    } else {                    /* SDCv1 or MMC*/
+        uint8_t n = (csd[5] & 0x0f) + (csd[10] >> 7) + ((csd[9] & 0x03) << 1) + 2;
+        *sectors = (csd[8] >> 6) + (csd[7] << 2) + ((csd[6] & 0x03) << 10) + 1;
+        *sectors = *sectors << (n - 9);
+    }
+
+    return EOS_OK;
+}
+
+int eos_sdc_get_blk_size(uint32_t timeout, uint32_t *size) {
+    int rv;
+    uint8_t rbl[64];    /* SD Status or CSD register */
+    uint32_t start = eos_time_get_tick();
+
+    sdc_select();
+    if (sdc_type & EOS_SDC_TYPE_SDC2) {
+        rv = sdc_acmd(SD_STATUS, 0, SDC_CMD_FLAG_NOCS, timeout);
+        sdc_xchg8(0xff);    /* R2 response */
+    } else {
+        rv = sdc_cmd(SEND_CSD, 0, SDC_CMD_FLAG_NOCS, timeout);
+    }
+    if (rv == SDC_R1_READY) {
+        rv = sdc_block_read(rbl, (sdc_type & EOS_SDC_TYPE_SDC2) ? 64 : 16, sdc_nto(start, timeout));
+    } else {
+        rv = SDC_ERR(rv);
+    }
+    sdc_deselect();
+    if (rv) return rv;
+
+    if (sdc_type & EOS_SDC_TYPE_SDC2) {
+        *size = 16UL << (rbl[10] >> 4);
+    } else if (sdc_type & EOS_SDC_TYPE_SDC1) {
+        *size = (((rbl[10] & 0x3f) << 1) + (rbl[11] >> 7) + 1) << ((rbl[13] >> 6) - 1);
+    } else {
+        *size = (((rbl[10] & 0x7c) >> 2) + 1) * (((rbl[11] & 0x03) << 3) + (rbl[11] >> 5) + 1);
+    }
+
+    return EOS_OK;
+}
+
+int eos_sdc_sync(uint32_t timeout) {
+    int rv;
+
+    sdc_select();
+    rv = sdc_ready(timeout);
+    sdc_deselect();
+
+    return rv;
+}
+
+int eos_sdc_erase(uint32_t blk_start, uint32_t blk_end, uint32_t timeout) {
+    int rv;
+    uint32_t start;
+
+    if (!(sdc_type & EOS_SDC_TYPE_SDC)) return EOS_ERR;
+    if (!(sdc_type & EOS_SDC_CAP_ERASE_EN)) return EOS_ERR;
+    if (!(sdc_type & EOS_SDC_CAP_BLK)) {
+        blk_start *= 512;
+        blk_end *= 512;
+    }
+
+    start = eos_time_get_tick();
+    rv = sdc_cmd(ERASE_WR_BLK_START, blk_start, 0, timeout);
+    if (rv != SDC_R1_READY) return SDC_ERR(rv);
+
+    rv = sdc_cmd(ERASE_WR_BLK_END, blk_end, 0, sdc_nto(start, timeout));
+    if (rv != SDC_R1_READY) return SDC_ERR(rv);
+
+    rv = sdc_cmd(ERASE, 0, 0, sdc_nto(start, timeout));
+    if (rv != SDC_R1_READY) return SDC_ERR(rv);
+
+    return eos_sdc_sync(sdc_nto(start, timeout));
+}
+
+int eos_sdc_sect_read(uint32_t sect, unsigned int count, uint8_t *buffer) {
+    int rv;
+    uint8_t cmd = ((count == 1) ? READ_SINGLE_BLOCK : READ_MULTIPLE_BLOCK);
+
+    if (!(sdc_type & EOS_SDC_CAP_BLK)) sect *= 512;
+
+    sdc_select();
+    rv = sdc_cmd(cmd, sect, SDC_CMD_FLAG_NOCS, SDC_TIMEOUT_CMD);
+    if (rv == SDC_R1_READY) {
+        int _rv = SDC_R1_READY;
+
+        while (count) {
+            rv = sdc_block_read(buffer, 512, SDC_TIMEOUT_READ);
+            if (rv) break;
+            eos_sdcc_decrypt(sect, buffer);
+            buffer += 512;
+            count--;
+        }
+        if (cmd == READ_MULTIPLE_BLOCK) _rv = sdc_cmd(STOP_TRANSMISSION, 0, SDC_CMD_FLAG_NOCS | SDC_CMD_FLAG_NOWAIT | SDC_CMD_FLAG_RSTUFF, 0);
+        if (!rv && (_rv != SDC_R1_READY)) rv = SDC_ERR(_rv);
+    } else {
+        rv = SDC_ERR(rv);
+    }
+    sdc_deselect();
+
+    return rv;
+}
+
+int eos_sdc_sect_write(uint32_t sect, unsigned int count, uint8_t *buffer) {
+    int rv;
+
+    if (!(sdc_type & EOS_SDC_CAP_BLK)) sect *= 512;
+
+    if (count == 1) {
+        sdc_select();
+        rv = sdc_cmd(WRITE_BLOCK, sect, SDC_CMD_FLAG_NOCS, SDC_TIMEOUT_CMD);
+        if (rv == SDC_R1_READY) {
+            eos_sdcc_encrypt(sect, buffer);
+            rv = sdc_block_write(SDC_TOKEN_START_BLK, buffer, 512, SDC_TIMEOUT_WRITE);
+        } else {
+            rv = SDC_ERR(rv);
+        }
+        sdc_deselect();
+    } else {
+        if (sdc_type & EOS_SDC_TYPE_SDC) {
+            rv = sdc_acmd(SET_WR_BLK_ERASE_COUNT, count, 0, SDC_TIMEOUT_CMD);
+            if (rv != SDC_R1_READY) return SDC_ERR(rv);
+        }
+
+        sdc_select();
+        rv = sdc_cmd(WRITE_MULTIPLE_BLOCK, sect, SDC_CMD_FLAG_NOCS, SDC_TIMEOUT_CMD);
+        if (rv == SDC_R1_READY) {
+            int _rv;
+
+            while (count) {
+                eos_sdcc_encrypt(sect, buffer);
+                rv = sdc_block_write(SDC_TOKEN_START_BLKM, buffer, 512, SDC_TIMEOUT_WRITE);
+                if (rv) break;
+                buffer += 512;
+                count--;
+            }
+            _rv = sdc_block_write(SDC_TOKEN_STOP_TRAN, NULL, 0, SDC_TIMEOUT_WRITE);
+            if (!rv && (_rv != SDC_R1_READY)) rv = SDC_ERR(_rv);
+        } else {
+            rv = SDC_ERR(rv);
+        }
+        sdc_deselect();
+    }
+
+    return rv;
+}
diff --git a/fw/fe310/eos/dev/sdcard.h b/fw/fe310/eos/dev/sdcard.h
new file mode 100644
index 0000000..910a6e0
--- /dev/null
+++ b/fw/fe310/eos/dev/sdcard.h
@@ -0,0 +1,22 @@
+#include <stdint.h>
+
+#define EOS_SDC_TYPE_MMC            0x01
+
+#define EOS_SDC_TYPE_SDC1           0x04
+#define EOS_SDC_TYPE_SDC2           0x08
+#define EOS_SDC_TYPE_SDC            0x0c
+#define EOS_SDC_TYPE_MASK           0x0f
+
+#define EOS_SDC_CAP_BLK             0x10
+#define EOS_SDC_CAP_ERASE_EN        0x20
+#define EOS_SDC_CAP_MASK            0xf0
+
+int eos_sdc_init(uint8_t wakeup_cause);
+uint8_t eos_sdc_type(void);
+uint8_t eos_sdc_cap(void);
+int eos_sdc_get_sect_count(uint32_t timeout, uint32_t *sectors);
+int eos_sdc_get_blk_size(uint32_t timeout, uint32_t *size);
+int eos_sdc_sync(uint32_t timeout);
+int eos_sdc_erase(uint32_t blk_start, uint32_t blk_end, uint32_t timeout);
+int eos_sdc_sect_read(uint32_t sect, unsigned int count, uint8_t *buffer);
+int eos_sdc_sect_write(uint32_t sect, unsigned int count, uint8_t *buffer);
diff --git a/fw/fe310/eos/i2c.c b/fw/fe310/eos/i2c.c
deleted file mode 100644
index a507af1..0000000
--- a/fw/fe310/eos/i2c.c
+++ /dev/null
@@ -1,145 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-
-#include "encoding.h"
-#include "platform.h"
-#include "prci_driver.h"
-
-#include "eos.h"
-#include "i2s.h"
-#include "i2c.h"
-
-int eos_i2c_init(uint8_t wakeup_cause) {
-    eos_i2c_speed(EOS_I2C_SPEED);
-    // eos_i2c_start();
-
-    return EOS_OK;
-}
-
-void eos_i2c_start(void) {
-    I2C0_REGB(I2C_CONTROL)  |=  I2C_CONTROL_EN;
-    GPIO_REG(GPIO_IOF_SEL)  &= ~IOF0_I2C0_MASK;
-    GPIO_REG(GPIO_IOF_EN)   |=  IOF0_I2C0_MASK;
-}
-
-void eos_i2c_stop(void) {
-    GPIO_REG(GPIO_IOF_EN)   &= ~IOF0_I2C0_MASK;
-    I2C0_REGB(I2C_CONTROL)  &= ~I2C_CONTROL_EN;
-}
-
-void eos_i2c_speed(uint32_t baud_rate) {
-    unsigned long clock_rate = PRCI_get_cpu_freq();
-    uint16_t prescaler = (clock_rate / (baud_rate * 5)) - 1;
-
-    I2C0_REGB(I2C_PRESCALE_LOW) = prescaler & 0xFF;
-    I2C0_REGB(I2C_PRESCALE_HIGH) = (prescaler >> 8) & 0xFF;
-}
-
-
-static int i2c_read(uint8_t cmd) {
-    I2C0_REGB(I2C_COMMAND) = I2C_CMD_READ | cmd;
-    while (I2C0_REGB(I2C_STATUS) & I2C_STATUS_TIP);
-
-    return I2C0_REGB(I2C_RECEIVE);
-}
-
-static int i2c_write(uint8_t cmd, uint8_t b) {
-    I2C0_REGB(I2C_TRANSMIT) = b;
-    I2C0_REGB(I2C_COMMAND) = I2C_CMD_WRITE | cmd;
-    while (I2C0_REGB(I2C_STATUS) & I2C_STATUS_TIP);
-
-    if (I2C0_REGB(I2C_STATUS) & I2C_STATUS_RXACK) return EOS_ERR;
-    return EOS_OK;
-}
-
-static int i2c_addr(uint8_t addr, uint8_t rw_flag) {
-    return i2c_write(I2C_CMD_START, ((addr & 0x7F) << 1) | (rw_flag & 0x1));
-}
-
-int eos_i2c_read8(uint8_t addr, uint8_t reg, uint8_t *buffer, uint16_t len) {
-    int rv;
-    int i;
-
-    rv = i2c_addr(addr, I2C_WRITE);
-    if (rv) return rv;
-
-    rv = i2c_write(0, reg);
-    if (rv) return rv;
-
-    rv = i2c_addr(addr, I2C_READ);
-    if (rv) return rv;
-
-    for (i=0; i<len; i++) {
-        rv = i2c_read(i == (len - 1) ? (I2C_CMD_ACK | I2C_CMD_STOP) : 0);  /* Set NACK to end read, and generate STOP condition */
-        if (rv < 0) return rv;
-
-        buffer[i] = (uint8_t)rv;
-    }
-
-    return EOS_OK;
-}
-
-int eos_i2c_read16(uint8_t addr, uint16_t reg, uint8_t *buffer, uint16_t len) {
-    int rv;
-    int i;
-
-    rv = i2c_addr(addr, I2C_WRITE);
-    if (rv) return rv;
-
-    rv = i2c_write(0, reg >> 8);
-    if (rv) return rv;
-
-    rv = i2c_write(0, reg & 0xff);
-    if (rv) return rv;
-
-    rv = i2c_addr(addr, I2C_READ);
-    if (rv) return rv;
-
-    for (i=0; i<len; i++) {
-        rv = i2c_read(i == (len - 1) ? (I2C_CMD_ACK | I2C_CMD_STOP) : 0);  /* Set NACK to end read, and generate STOP condition */
-        if (rv < 0) return rv;
-
-        buffer[i] = (uint8_t)rv;
-    }
-
-    return EOS_OK;
-}
-
-int eos_i2c_write8(uint8_t addr, uint8_t reg, uint8_t *buffer, uint16_t len) {
-    int rv;
-    int i;
-
-    rv = i2c_addr(addr, I2C_WRITE);
-    if (rv) return rv;
-
-    rv = i2c_write(0, reg);
-    if (rv) return rv;
-
-    for (i=0; i<len; i++) {
-        rv = i2c_write(i == (len - 1) ? I2C_CMD_STOP : 0, buffer[i]);
-        if (rv) return rv;
-    }
-
-    return EOS_OK;
-}
-
-int eos_i2c_write16(uint8_t addr, uint16_t reg, uint8_t *buffer, uint16_t len) {
-    int rv;
-    int i;
-
-    rv = i2c_addr(addr, I2C_WRITE);
-    if (rv) return rv;
-
-    rv = i2c_write(0, reg >> 8);
-    if (rv) return rv;
-
-    rv = i2c_write(0, reg & 0xff);
-    if (rv) return rv;
-
-    for (i=0; i<len; i++) {
-        rv = i2c_write(i == (len - 1) ? I2C_CMD_STOP : 0, buffer[i]);
-        if (rv) return rv;
-    }
-
-    return EOS_OK;
-}
diff --git a/fw/fe310/eos/i2c.h b/fw/fe310/eos/i2c.h
deleted file mode 100644
index 20d3dc7..0000000
--- a/fw/fe310/eos/i2c.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#include <stdint.h>
-
-#define EOS_I2C_SPEED       100000
-
-int eos_i2c_init(uint8_t wakeup_cause);
-int eos_i2c_run(uint8_t wakeup_cause);
-void eos_i2c_start(void);
-void eos_i2c_stop(void);
-void eos_i2c_speed(uint32_t baud_rate);
-int eos_i2c_read8(uint8_t addr, uint8_t reg, uint8_t *buffer, uint16_t len);
-int eos_i2c_read16(uint8_t addr, uint16_t reg, uint8_t *buffer, uint16_t len);
-int eos_i2c_write8(uint8_t addr, uint8_t reg, uint8_t *buffer, uint16_t len);
-int eos_i2c_write16(uint8_t addr, uint16_t reg, uint8_t *buffer, uint16_t len);
diff --git a/fw/fe310/eos/i2c/Makefile b/fw/fe310/eos/i2c/Makefile
deleted file mode 100644
index 83cb1f5..0000000
--- a/fw/fe310/eos/i2c/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-include ../../common.mk
-CFLAGS += -I$(bsp_dir)/include
-
-obj = bq25895.o ov2640.o gt911.o
-
-
-%.o: %.c %.h
-	$(CC) $(CFLAGS) -c $<
-
-%.o: %.S
-	$(CC) $(CFLAGS) -c $<
-
-all: $(obj)
-
-clean:
-	rm -f *.o
diff --git a/fw/fe310/eos/i2c/bq25895.c b/fw/fe310/eos/i2c/bq25895.c
deleted file mode 100644
index b290926..0000000
--- a/fw/fe310/eos/i2c/bq25895.c
+++ /dev/null
@@ -1,43 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdio.h>
-
-#include "eos.h"
-#include "pwr.h"
-#include "i2c.h"
-#include "bq25895.h"
-
-static int reg_read(uint8_t reg, uint8_t *data) {
-    return eos_i2c_read8(BQ25895_ADDR, reg, data, 1);
-}
-
-static int reg_write(uint8_t reg, uint8_t data) {
-    return eos_i2c_write8(BQ25895_ADDR, reg, &data, 1);
-}
-
-int eos_bq25895_init(uint8_t wakeup_cause) {
-    int rst = (wakeup_cause == EOS_PWR_WAKE_RST);
-    int i, rv = EOS_OK;
-    uint8_t data = 0;
-
-    if (rst) {
-        rv = reg_write(0x14, 0x80);  // reset
-        if (rv) printf("I2C ERROR 0x14\n");
-        rv = reg_write(0x14, 0x00);  // disable watchdog
-        if (rv) printf("I2C ERROR 0x14\n");
-        rv = reg_write(0x07, 0x8d);  // disable watchdog
-        if (rv) printf("I2C ERROR 0x07\n");
-        rv = reg_write(0x00, 0x28);  // 2.1A input current
-        if (rv) printf("I2C ERROR 0x00\n");
-        rv = reg_write(0x02, 0x30);  // enable ICO, disaable MaxCharge and D+/D-
-        if (rv) printf("I2C ERROR 0x02\n");
-    }
-
-    printf("BQ25895:\n");
-    for (i=0; i<0x15; i++) {
-        rv = reg_read(i, &data);
-        if (!rv) printf("REG%02x: %02x\n", i, data);
-    }
-
-    return EOS_OK;
-}
diff --git a/fw/fe310/eos/i2c/bq25895.h b/fw/fe310/eos/i2c/bq25895.h
deleted file mode 100644
index cbef36e..0000000
--- a/fw/fe310/eos/i2c/bq25895.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#include <stdint.h>
-
-#define BQ25895_ADDR        0x6A
-
-int eos_bq25895_init(uint8_t wakeup_cause);
diff --git a/fw/fe310/eos/i2c/drv2605.h b/fw/fe310/eos/i2c/drv2605.h
deleted file mode 100644
index fe90a9b..0000000
--- a/fw/fe310/eos/i2c/drv2605.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#include <stdint.h>
-
-#define DRV2605_ADDR        0x5A
diff --git a/fw/fe310/eos/i2c/lsm9ds1.h b/fw/fe310/eos/i2c/lsm9ds1.h
deleted file mode 100644
index 92220e7..0000000
--- a/fw/fe310/eos/i2c/lsm9ds1.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#include <stdint.h>
-
-#define LSM9DS1_ADDR_AG     0x1E
-#define LSM9DS1_ADDR_M      0x6B
diff --git a/fw/fe310/eos/i2c/ov2640.c b/fw/fe310/eos/i2c/ov2640.c
deleted file mode 100644
index 6e54f10..0000000
--- a/fw/fe310/eos/i2c/ov2640.c
+++ /dev/null
@@ -1,861 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-#include <math.h>
-
-#include "eos.h"
-#include "timer.h"
-#include "cam.h"
-
-#include "i2c.h"
-#include "ov2640_regs.h"
-#include "ov2640.h"
-
-#define XCLK_FREQ       24000000
-//#define XCLK_FREQ       12000000
-
-#define CIF_WIDTH       (400)
-#define CIF_HEIGHT      (296)
-
-#define SVGA_WIDTH      (800)
-#define SVGA_HEIGHT     (600)
-
-#define UXGA_WIDTH      (1600)
-#define UXGA_HEIGHT     (1200)
-
-static const uint8_t default_regs[][2] = {
-
-// From Linux Driver.
-
-    {BANK_SEL,      BANK_SEL_DSP},
-    {0x2c,          0xff},
-    {0x2e,          0xdf},
-    {BANK_SEL,      BANK_SEL_SENSOR},
-    {0x3c,          0x32},
-//  {CLKRC,         CLKRC_DOUBLE | 0x02},
-    {CLKRC,         0x01},
-    {COM2,          COM2_OUT_DRIVE_3x},
-    {REG04,         REG04_SET(REG04_HFLIP_IMG | REG04_VFLIP_IMG | REG04_VREF_EN | REG04_HREF_EN)},
-    {COM8,          COM8_SET(COM8_BNDF_EN | COM8_AGC_EN | COM8_AEC_EN)},
-    {COM9,          COM9_AGC_SET(COM9_AGC_GAIN_8x)},
-    {0x2c,          0x0c},
-    {0x33,          0x78},
-    {0x3a,          0x33},
-    {0x3b,          0xfb},
-    {0x3e,          0x00},
-    {0x43,          0x11},
-    {0x16,          0x10},
-    {0x39,          0x02},
-    {0x35,          0x88},
-    {0x22,          0x0a},
-    {0x37,          0x40},
-    {0x23,          0x00},
-    {ARCOM2,        0xa0},
-    {0x06,          0x02},
-    {0x06,          0x88},
-    {0x07,          0xc0},
-    {0x0d,          0xb7},
-    {0x0e,          0x01},
-    {0x4c,          0x00},
-    {0x4a,          0x81},
-    {0x21,          0x99},
-    {AEW,           0x40},
-    {AEB,           0x38},
-    {VV,            VV_AGC_TH_SET(0x08, 0x02)},
-    {0x5c,          0x00},
-    {0x63,          0x00},
-    {FLL,           0x22},
-    {COM3,          COM3_BAND_SET(COM3_BAND_AUTO)},
-    {REG5D,         0x55},
-    {REG5E,         0x7d},
-    {REG5F,         0x7d},
-    {REG60,         0x55},
-    {HISTO_LOW,     0x70},
-    {HISTO_HIGH,    0x80},
-    {0x7c,          0x05},
-    {0x20,          0x80},
-    {0x28,          0x30},
-    {0x6c,          0x00},
-    {0x6d,          0x80},
-    {0x6e,          0x00},
-    {0x70,          0x02},
-    {0x71,          0x94},
-    {0x73,          0xc1},
-    {0x3d,          0x34},
-    {COM7,          COM7_RES_UXGA | COM7_ZOOM_EN},
-    {0x5a,          0x57},
-    {COM25,         0x00},
-    {BD50,          0xbb},
-    {BD60,          0x9c},
-    {BANK_SEL,      BANK_SEL_DSP},
-    {0xe5,          0x7f},
-    {MC_BIST,       MC_BIST_RESET | MC_BIST_BOOT_ROM_SEL},
-    {0x41,          0x24},
-    {RESET,         RESET_JPEG | RESET_DVP},
-    {0x76,          0xff},
-    {0x33,          0xa0},
-    {0x42,          0x20},
-    {0x43,          0x18},
-    {0x4c,          0x00},
-    {CTRL3,         CTRL3_BPC_EN | CTRL3_WPC_EN | 0x10},
-    {0x88,          0x3f},
-    {0xd7,          0x03},
-    {0xd9,          0x10},
-    {R_DVP_SP,      R_DVP_SP_AUTO_MODE | 0x2},
-    {0xc8,          0x08},
-    {0xc9,          0x80},
-    {BPADDR,        0x00},
-    {BPDATA,        0x00},
-    {BPADDR,        0x03},
-    {BPDATA,        0x48},
-    {BPDATA,        0x48},
-    {BPADDR,        0x08},
-    {BPDATA,        0x20},
-    {BPDATA,        0x10},
-    {BPDATA,        0x0e},
-    {0x90,          0x00},
-    {0x91,          0x0e},
-    {0x91,          0x1a},
-    {0x91,          0x31},
-    {0x91,          0x5a},
-    {0x91,          0x69},
-    {0x91,          0x75},
-    {0x91,          0x7e},
-    {0x91,          0x88},
-    {0x91,          0x8f},
-    {0x91,          0x96},
-    {0x91,          0xa3},
-    {0x91,          0xaf},
-    {0x91,          0xc4},
-    {0x91,          0xd7},
-    {0x91,          0xe8},
-    {0x91,          0x20},
-    {0x92,          0x00},
-    {0x93,          0x06},
-    {0x93,          0xe3},
-    {0x93,          0x03},
-    {0x93,          0x03},
-    {0x93,          0x00},
-    {0x93,          0x02},
-    {0x93,          0x00},
-    {0x93,          0x00},
-    {0x93,          0x00},
-    {0x93,          0x00},
-    {0x93,          0x00},
-    {0x93,          0x00},
-    {0x93,          0x00},
-    {0x96,          0x00},
-    {0x97,          0x08},
-    {0x97,          0x19},
-    {0x97,          0x02},
-    {0x97,          0x0c},
-    {0x97,          0x24},
-    {0x97,          0x30},
-    {0x97,          0x28},
-    {0x97,          0x26},
-    {0x97,          0x02},
-    {0x97,          0x98},
-    {0x97,          0x80},
-    {0x97,          0x00},
-    {0x97,          0x00},
-    {0xa4,          0x00},
-    {0xa8,          0x00},
-    {0xc5,          0x11},
-    {0xc6,          0x51},
-    {0xbf,          0x80},
-    {0xc7,          0x10},  /* simple AWB */
-    {0xb6,          0x66},
-    {0xb8,          0xA5},
-    {0xb7,          0x64},
-    {0xb9,          0x7C},
-    {0xb3,          0xaf},
-    {0xb4,          0x97},
-    {0xb5,          0xFF},
-    {0xb0,          0xC5},
-    {0xb1,          0x94},
-    {0xb2,          0x0f},
-    {0xc4,          0x5c},
-    {0xa6,          0x00},
-    {0xa7,          0x20},
-    {0xa7,          0xd8},
-    {0xa7,          0x1b},
-    {0xa7,          0x31},
-    {0xa7,          0x00},
-    {0xa7,          0x18},
-    {0xa7,          0x20},
-    {0xa7,          0xd8},
-    {0xa7,          0x19},
-    {0xa7,          0x31},
-    {0xa7,          0x00},
-    {0xa7,          0x18},
-    {0xa7,          0x20},
-    {0xa7,          0xd8},
-    {0xa7,          0x19},
-    {0xa7,          0x31},
-    {0xa7,          0x00},
-    {0xa7,          0x18},
-    {0x7f,          0x00},
-    {0xe5,          0x1f},
-    {0xe1,          0x77},
-    {0xdd,          0x7f},
-    {CTRL0,         CTRL0_YUV422 | CTRL0_YUV_EN | CTRL0_RGB_EN},
-
-// OpenMV Custom.
-
-    {BANK_SEL,      BANK_SEL_SENSOR},
-    {0x0f,          0x4b},
-    {COM1,          0x8f},
-
-// End.
-
-    {0xff,          0xff},
-};
-
-// Looks really bad.
-//static const uint8_t cif_regs[][2] = {
-//    {BANK_SEL,  BANK_SEL_SENSOR},
-//    {COM7,      COM7_RES_CIF},
-//    {COM1,      0x06 | 0x80},
-//    {HSTART,    0x11},
-//    {HSTOP,     0x43},
-//    {VSTART,    0x01}, // 0x01 fixes issue with garbage pixels in the image...
-//    {VSTOP,     0x97},
-//    {REG32,     0x09},
-//    {BANK_SEL,  BANK_SEL_DSP},
-//    {RESET,     RESET_DVP},
-//    {SIZEL,     SIZEL_HSIZE8_11_SET(CIF_WIDTH) | SIZEL_HSIZE8_SET(CIF_WIDTH) | SIZEL_VSIZE8_SET(CIF_HEIGHT)},
-//    {HSIZE8,    HSIZE8_SET(CIF_WIDTH)},
-//    {VSIZE8,    VSIZE8_SET(CIF_HEIGHT)},
-//    {CTRL2,     CTRL2_DCW_EN | CTRL2_SDE_EN | CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN},
-//    {0,         0},
-//};
-
-static const uint8_t svga_regs[][2] = {
-    {BANK_SEL,  BANK_SEL_SENSOR},
-    {COM7,      COM7_RES_SVGA},
-    {COM1,      0x0A | 0x80},
-    {HSTART,    0x11},
-    {HSTOP,     0x43},
-    {VSTART,    0x01}, // 0x01 fixes issue with garbage pixels in the image...
-    {VSTOP,     0x97},
-    {REG32,     0x09},
-    {BANK_SEL,  BANK_SEL_DSP},
-    {RESET,     RESET_DVP},
-    {SIZEL,     SIZEL_HSIZE8_11_SET(SVGA_WIDTH) | SIZEL_HSIZE8_SET(SVGA_WIDTH) | SIZEL_VSIZE8_SET(SVGA_HEIGHT)},
-    {HSIZE8,    HSIZE8_SET(SVGA_WIDTH)},
-    {VSIZE8,    VSIZE8_SET(SVGA_HEIGHT)},
-    {CTRL2,     CTRL2_DCW_EN | CTRL2_SDE_EN | CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN},
-    {0xff,      0xff},
-};
-
-static const uint8_t uxga_regs[][2] = {
-    {BANK_SEL,  BANK_SEL_SENSOR},
-    {COM7,      COM7_RES_UXGA},
-    {COM1,      0x0F | 0x80},
-    {HSTART,    0x11},
-    {HSTOP,     0x75},
-    {VSTART,    0x01},
-    {VSTOP,     0x97},
-    {REG32,     0x36},
-    {BANK_SEL,  BANK_SEL_DSP},
-    {RESET,     RESET_DVP},
-    {SIZEL,     SIZEL_HSIZE8_11_SET(UXGA_WIDTH) | SIZEL_HSIZE8_SET(UXGA_WIDTH) | SIZEL_VSIZE8_SET(UXGA_HEIGHT)},
-    {HSIZE8,    HSIZE8_SET(UXGA_WIDTH)},
-    {VSIZE8,    VSIZE8_SET(UXGA_HEIGHT)},
-    {CTRL2,     CTRL2_DCW_EN | CTRL2_SDE_EN | CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN},
-    {0xff,      0xff},
-};
-
-static const uint8_t yuv422_regs[][2] = {
-    {BANK_SEL,      BANK_SEL_DSP},
-    {R_BYPASS,      R_BYPASS_DSP_EN},
-    {IMAGE_MODE,    IMAGE_MODE_YUV422},
-    {0xd7,          0x03},
-    {0x33,          0xa0},
-    {0xe5,          0x1f},
-    {0xe1,          0x67},
-    {RESET,         0x00},
-    {R_BYPASS,      R_BYPASS_DSP_EN},
-    {0xff,          0xff},
-};
-
-static const uint8_t rgb565_regs[][2] = {
-    {BANK_SEL,      BANK_SEL_DSP},
-    {R_BYPASS,      R_BYPASS_DSP_EN},
-    {IMAGE_MODE,    IMAGE_MODE_RGB565},
-    {0xd7,          0x03},
-    {RESET,         0x00},
-    {R_BYPASS,      R_BYPASS_DSP_EN},
-    {0xff,          0xff},
-};
-
-static const uint8_t bayer_regs[][2] = {
-    {BANK_SEL,      BANK_SEL_DSP},
-    {R_BYPASS,      R_BYPASS_DSP_EN},
-    {IMAGE_MODE,    IMAGE_MODE_RAW10},
-    {0xd7,          0x03},
-    {RESET,         0x00},
-    {R_BYPASS,      R_BYPASS_DSP_EN},
-    {0xff,          0xff},
-};
-
-static const uint8_t jpeg_regs[][2] = {
-    {BANK_SEL,      BANK_SEL_DSP},
-    {R_BYPASS,      R_BYPASS_DSP_EN},
-    {IMAGE_MODE,    IMAGE_MODE_JPEG_EN},
-    {0xd7,          0x03},
-    {RESET,         0x00},
-    {R_BYPASS,      R_BYPASS_DSP_EN},
-    {0xff,          0xff},
-};
-
-#define NUM_BRIGHTNESS_LEVELS (5)
-static const uint8_t brightness_regs[NUM_BRIGHTNESS_LEVELS + 1][5] = {
-    {BPADDR, BPDATA, BPADDR, BPDATA, BPDATA},
-    {0x00, 0x04, 0x09, 0x00, 0x00}, /* -2 */
-    {0x00, 0x04, 0x09, 0x10, 0x00}, /* -1 */
-    {0x00, 0x04, 0x09, 0x20, 0x00}, /*  0 */
-    {0x00, 0x04, 0x09, 0x30, 0x00}, /* +1 */
-    {0x00, 0x04, 0x09, 0x40, 0x00}, /* +2 */
-};
-
-#define NUM_CONTRAST_LEVELS (5)
-static const uint8_t contrast_regs[NUM_CONTRAST_LEVELS + 1][7] = {
-    {BPADDR, BPDATA, BPADDR, BPDATA, BPDATA, BPDATA, BPDATA},
-    {0x00, 0x04, 0x07, 0x20, 0x18, 0x34, 0x06}, /* -2 */
-    {0x00, 0x04, 0x07, 0x20, 0x1c, 0x2a, 0x06}, /* -1 */
-    {0x00, 0x04, 0x07, 0x20, 0x20, 0x20, 0x06}, /*  0 */
-    {0x00, 0x04, 0x07, 0x20, 0x24, 0x16, 0x06}, /* +1 */
-    {0x00, 0x04, 0x07, 0x20, 0x28, 0x0c, 0x06}, /* +2 */
-};
-
-#define NUM_SATURATION_LEVELS (5)
-static const uint8_t saturation_regs[NUM_SATURATION_LEVELS + 1][5] = {
-    {BPADDR, BPDATA, BPADDR, BPDATA, BPDATA},
-    {0x00, 0x02, 0x03, 0x28, 0x28}, /* -2 */
-    {0x00, 0x02, 0x03, 0x38, 0x38}, /* -1 */
-    {0x00, 0x02, 0x03, 0x48, 0x48}, /*  0 */
-    {0x00, 0x02, 0x03, 0x58, 0x58}, /* +1 */
-    {0x00, 0x02, 0x03, 0x68, 0x68}, /* +2 */
-};
-
-static int reg_read(int8_t reg, uint8_t *data) {
-    return eos_i2c_read8(OV2640_ADDR, reg, data, 1);
-}
-
-static int reg_write(uint8_t reg, uint8_t data) {
-    return eos_i2c_write8(OV2640_ADDR, reg, &data, 1);
-}
-
-static int regarr_write(const uint8_t (*regs)[2]) {
-    int i, rv;
-
-    i = 0;
-    rv = EOS_OK;
-
-    while ((regs[i][0] != 0xff) || (regs[i][1] != 0xff)) {
-        if (!rv) rv = reg_write(regs[i][0], regs[i][1]);
-        i++;
-    }
-
-    return rv;
-}
-
-int eos_ov2640_init(void) {
-    int rv;
-
-    // Reset all registers
-    rv = reg_write(BANK_SEL, BANK_SEL_SENSOR);
-    if (rv) return rv;
-
-    rv = reg_write(COM7, COM7_SRST);
-    if (rv) return rv;
-
-    // Delay 5 ms
-    eos_time_sleep(5);
-
-    // Write default regsiters
-    rv = regarr_write(default_regs);
-    if (rv) return rv;
-
-    // Delay 300 ms
-    eos_time_sleep(300);
-
-    return EOS_OK;
-}
-
-int eos_ov2640_sleep(int enable) {
-    uint8_t reg;
-    int rv;
-
-    rv = reg_write(BANK_SEL, BANK_SEL_SENSOR);
-    if (rv) return rv;
-
-    rv = reg_read(COM2, &reg);
-    if (rv) return rv;
-
-    if (enable) {
-        reg |= COM2_STDBY;
-    } else {
-        reg &= ~COM2_STDBY;
-    }
-
-    // Write back register
-    return reg_write(COM2, reg);
-}
-
-int eos_ov2640_set_pixfmt(pixformat_t fmt) {
-    const uint8_t (*regs)[2];
-
-    switch (fmt) {
-        case PIXFORMAT_RGB565:
-            regs = rgb565_regs;
-            break;
-        case PIXFORMAT_YUV422:
-        case PIXFORMAT_GRAYSCALE:
-            regs = yuv422_regs;
-            break;
-        case PIXFORMAT_BAYER:
-            regs = bayer_regs;
-            break;
-        case PIXFORMAT_JPEG:
-            regs = jpeg_regs;
-            break;
-        default:
-            return EOS_ERR;
-    }
-
-    return regarr_write(regs);
-}
-
-int eos_ov2640_set_framesize(framesize_t framesize) {
-    const uint8_t (*regs)[2];
-    uint16_t sensor_w = 0;
-    uint16_t sensor_h = 0;
-    uint16_t w = _eos_cam_resolution[framesize][0];
-    uint16_t h = _eos_cam_resolution[framesize][1];
-    int rv;
-
-    if ((w % 4) || (h % 4) || (w > UXGA_WIDTH) || (h > UXGA_HEIGHT)) { // w/h must be divisble by 4
-        return EOS_ERR;
-    }
-
-    // Looks really bad.
-    /* if ((w <= CIF_WIDTH) && (h <= CIF_HEIGHT)) {
-        regs = cif_regs;
-        sensor_w = CIF_WIDTH;
-        sensor_h = CIF_HEIGHT;
-    } else */ if ((w <= SVGA_WIDTH) && (h <= SVGA_HEIGHT)) {
-        regs = svga_regs;
-        sensor_w = SVGA_WIDTH;
-        sensor_h = SVGA_HEIGHT;
-    } else {
-        regs = uxga_regs;
-        sensor_w = UXGA_WIDTH;
-        sensor_h = UXGA_HEIGHT;
-    }
-
-    // Write setup regsiters
-    rv = regarr_write(regs);
-    if (rv) return rv;
-
-    uint64_t tmp_div = IM_MIN(sensor_w / w, sensor_h / h);
-    uint16_t log_div = IM_MIN(IM_LOG2(tmp_div) - 1, 3);
-    uint16_t div = 1 << log_div;
-    uint16_t w_mul = w * div;
-    uint16_t h_mul = h * div;
-    uint16_t x_off = (sensor_w - w_mul) / 2;
-    uint16_t y_off = (sensor_h - h_mul) / 2;
-
-    rv = EOS_OK;
-    if (!rv) rv = reg_write(CTRLI, CTRLI_LP_DP | CTRLI_V_DIV_SET(log_div) | CTRLI_H_DIV_SET(log_div));
-    if (!rv) rv = reg_write(HSIZE, HSIZE_SET(w_mul));
-    if (!rv) rv = reg_write(VSIZE, VSIZE_SET(h_mul));
-    if (!rv) rv = reg_write(XOFFL, XOFFL_SET(x_off));
-    if (!rv) rv = reg_write(YOFFL, YOFFL_SET(y_off));
-    if (!rv) rv = reg_write(VHYX, VHYX_HSIZE_SET(w_mul) | VHYX_VSIZE_SET(h_mul) | VHYX_XOFF_SET(x_off) | VHYX_YOFF_SET(y_off));
-    if (!rv) rv = reg_write(TEST, TEST_HSIZE_SET(w_mul));
-    if (!rv) rv = reg_write(ZMOW, ZMOW_OUTW_SET(w));
-    if (!rv) rv = reg_write(ZMOH, ZMOH_OUTH_SET(h));
-    if (!rv) rv = reg_write(ZMHH, ZMHH_OUTW_SET(w) | ZMHH_OUTH_SET(h));
-    if (!rv) rv = reg_write(R_DVP_SP, div);
-    if (!rv) rv = reg_write(RESET, 0x00);
-
-    return rv;
-}
-
-int eos_ov2640_set_contrast(int level) {
-    int rv = EOS_OK;
-
-    level += (NUM_CONTRAST_LEVELS / 2) + 1;
-    if (level <= 0 || level > NUM_CONTRAST_LEVELS) {
-        return EOS_ERR;
-    }
-
-    /* Switch to DSP register bank */
-    rv = reg_write(BANK_SEL, BANK_SEL_DSP);
-
-    /* Write contrast registers */
-    for (int i=0; i<sizeof(contrast_regs[0])/sizeof(contrast_regs[0][0]); i++) {
-        if (!rv) rv = reg_write(contrast_regs[0][i], contrast_regs[level][i]);
-    }
-
-    return rv;
-}
-
-int eos_ov2640_set_brightness(int level) {
-    int rv = EOS_OK;
-
-    level += (NUM_BRIGHTNESS_LEVELS / 2) + 1;
-    if (level <= 0 || level > NUM_BRIGHTNESS_LEVELS) {
-        return EOS_ERR;
-    }
-
-    /* Switch to DSP register bank */
-    rv = reg_write(BANK_SEL, BANK_SEL_DSP);
-
-    /* Write brightness registers */
-    for (int i=0; i<sizeof(brightness_regs[0])/sizeof(brightness_regs[0][0]); i++) {
-        if (!rv) rv = reg_write(brightness_regs[0][i], brightness_regs[level][i]);
-    }
-
-    return rv;
-}
-
-int eos_ov2640_set_saturation(int level) {
-    int rv = EOS_OK;
-
-    level += (NUM_SATURATION_LEVELS / 2) + 1;
-    if (level <= 0 || level > NUM_SATURATION_LEVELS) {
-        return EOS_ERR;
-    }
-
-    /* Switch to DSP register bank */
-    rv = reg_write(BANK_SEL, BANK_SEL_DSP);
-
-    /* Write saturation registers */
-    for (int i=0; i<sizeof(saturation_regs[0])/sizeof(saturation_regs[0][0]); i++) {
-        if (!rv) rv = reg_write(saturation_regs[0][i], saturation_regs[level][i]);
-    }
-
-    return rv;
-}
-
-int eos_ov2640_set_gainceiling(gainceiling_t gainceiling) {
-    int rv = EOS_OK;
-
-    /* Switch to SENSOR register bank */
-    rv = reg_write(BANK_SEL, BANK_SEL_SENSOR);
-
-    /* Write gain ceiling register */
-    if (!rv) rv = reg_write(COM9, COM9_AGC_SET(gainceiling));
-
-    return rv;
-}
-
-int eos_ov2640_set_quality(int qs) {
-    int rv = EOS_OK;
-
-    /* Switch to DSP register bank */
-    rv = reg_write(BANK_SEL, BANK_SEL_DSP);
-
-    /* Write QS register */
-    if (!rv) rv = reg_write(QS, qs);
-
-    return rv;
-}
-
-int eos_ov2640_set_colorbar(int enable) {
-    int rv = EOS_OK;
-    uint8_t reg;
-
-    rv = reg_write(BANK_SEL, BANK_SEL_SENSOR);
-    if (rv) return rv;
-
-    rv = reg_read(COM7, &reg);
-    if (rv) return rv;
-
-    if (enable) {
-        reg |= COM7_COLOR_BAR;
-    } else {
-        reg &= ~COM7_COLOR_BAR;
-    }
-
-    return reg_write(COM7, reg);
-}
-
-int eos_ov2640_set_auto_gain(int enable, float gain_db, float gain_db_ceiling) {
-    int rv = EOS_OK;
-    uint8_t reg;
-
-    rv = reg_write(BANK_SEL, BANK_SEL_SENSOR);
-    if (rv) return rv;
-
-    rv = reg_read(COM8, &reg);
-    if (rv) return rv;
-
-    rv = reg_write(COM8, (reg & (~COM8_AGC_EN)) | (enable ? COM8_AGC_EN : 0));
-    if (rv) return rv;
-
-    rv = EOS_OK;
-    if (enable && (!isnanf(gain_db_ceiling)) && (!isinff(gain_db_ceiling))) {
-        float gain_ceiling = IM_MAX(IM_MIN(expf((gain_db_ceiling / 20.0) * logf(10.0)), 128.0), 2.0);
-
-        if (!rv) rv = reg_read(COM9, &reg);
-        if (!rv) rv = reg_write(COM9, (reg & 0x1F) | (((int)ceilf(log2f(gain_ceiling)) - 1) << 5));
-    }
-
-    if (!enable && (!isnanf(gain_db)) && (!isinff(gain_db))) {
-        float gain = IM_MAX(IM_MIN(expf((gain_db / 20.0) * logf(10.0)), 32.0), 1.0);
-
-        int gain_temp = roundf(log2f(IM_MAX(gain / 2.0, 1.0)));
-        int gain_hi = 0xF >> (4 - gain_temp);
-        int gain_lo = IM_MIN(roundf(((gain / (1 << gain_temp)) - 1.0) * 16.0), 15);
-
-        if (!rv) rv = reg_write(GAIN, (gain_hi << 4) | (gain_lo << 0));
-    }
-
-    return rv;
-}
-
-int eos_ov2640_get_gain_db(float *gain_db) {
-    int rv = EOS_OK;
-    uint8_t reg, gain;
-
-    rv = reg_write(BANK_SEL, BANK_SEL_SENSOR);
-    if (rv) return rv;
-
-    rv = reg_read(COM8, &reg);
-    if (rv) return rv;
-
-    // DISABLED
-    // if (reg & COM8_AGC_EN) {
-    //     rv = reg_write(COM8, reg & (~COM8_AGC_EN));
-    //     if (rv) return rv;
-    // }
-    // DISABLED
-
-    rv = reg_read(GAIN, &gain);
-    if (rv) return rv;
-
-    // DISABLED
-    // if (reg & COM8_AGC_EN) {
-    //     rv = reg_write(COM8, reg | COM8_AGC_EN);
-    //     if (rv) return rv;
-    // }
-    // DISABLED
-
-    int hi_gain = 1 << (((gain >> 7) & 1) + ((gain >> 6) & 1) + ((gain >> 5) & 1) + ((gain >> 4) & 1));
-    float lo_gain = 1.0 + (((gain >> 0) & 0xF) / 16.0);
-    *gain_db = 20.0 * (logf(hi_gain * lo_gain) / logf(10.0));
-
-    return EOS_OK;
-}
-
-int eos_ov2640_set_auto_exposure(int enable, int exposure_us) {
-    int rv = EOS_OK;
-    uint8_t reg;
-
-    rv = reg_write(BANK_SEL, BANK_SEL_SENSOR);
-    if (rv) return rv;
-
-    rv = reg_read(COM8, &reg);
-    if (rv) return rv;
-
-    rv = reg_write(COM8, COM8_SET_AEC(reg, (enable != 0)));
-    if (rv) return rv;
-
-    if (!enable && (exposure_us >= 0)) {
-        rv = reg_read(COM7, &reg);
-        if (rv) return rv;
-
-        int t_line = 0;
-
-        if (COM7_GET_RES(reg) == COM7_RES_UXGA) t_line = 1600 + 322;
-        if (COM7_GET_RES(reg) == COM7_RES_SVGA) t_line = 800 + 390;
-        if (COM7_GET_RES(reg) == COM7_RES_CIF) t_line = 400 + 195;
-
-        rv = reg_read(CLKRC, &reg);
-        if (rv) return rv;
-
-        int pll_mult = ((reg & CLKRC_DOUBLE) ? 2 : 1) * 3;
-        int clk_rc = (reg & CLKRC_DIVIDER_MASK) + 2;
-
-        rv = reg_write(BANK_SEL, BANK_SEL_DSP);
-        if (rv) return rv;
-
-        rv = reg_read(IMAGE_MODE, &reg);
-        if (rv) return rv;
-
-        int t_pclk = 0;
-
-        if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_YUV422) t_pclk = 2;
-        if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_RAW10) t_pclk = 1;
-        if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_RGB565) t_pclk = 2;
-
-        int exposure = IM_MAX(IM_MIN(((exposure_us*(((XCLK_FREQ/clk_rc)*pll_mult)/1000000))/t_pclk)/t_line,0xFFFF),0x0000);
-
-        if (!rv) rv = reg_write(BANK_SEL, BANK_SEL_SENSOR);
-
-        if (!rv) rv = reg_read(REG04, &reg);
-        if (!rv) rv = reg_write(REG04, (reg & 0xFC) | ((exposure >> 0) & 0x3));
-
-        if (!rv) rv = reg_read(AEC, &reg);
-        if (!rv) rv = reg_write(AEC, (reg & 0x00) | ((exposure >> 2) & 0xFF));
-
-        if (!rv) rv = reg_read(REG45, &reg);
-        if (!rv) rv = reg_write(REG45, (reg & 0xC0) | ((exposure >> 10) & 0x3F));
-    }
-
-    return rv;
-}
-
-int eos_ov2640_get_exposure_us(int *exposure_us) {
-    int rv = EOS_OK;
-    uint8_t reg, aec_10, aec_92, aec_1510;
-
-    rv = reg_write(BANK_SEL, BANK_SEL_SENSOR);
-    if (rv) return rv;
-
-    rv = reg_read(COM8, &reg);
-    if (rv) return rv;
-
-    // DISABLED
-    // if (reg & COM8_AEC_EN) {
-    //     rv = reg_write(COM8, reg & (~COM8_AEC_EN));
-    //     if (rv) return rv;
-    // }
-    // DISABLED
-
-    rv = reg_read(REG04, &aec_10);
-    if (rv) return rv;
-
-    rv = reg_read(AEC, &aec_92);
-    if (rv) return rv;
-
-    rv = reg_read(REG45, &aec_1510);
-    if (rv) return rv;
-
-    // DISABLED
-    // if (reg & COM8_AEC_EN) {
-    //     rv = reg_write(COM8, reg | COM8_AEC_EN);
-    //     if (rv) return rv;
-    // }
-    // DISABLED
-
-    rv = reg_read(COM7, &reg);
-    if (rv) return rv;
-
-    int t_line = 0;
-
-    if (COM7_GET_RES(reg) == COM7_RES_UXGA) t_line = 1600 + 322;
-    if (COM7_GET_RES(reg) == COM7_RES_SVGA) t_line = 800 + 390;
-    if (COM7_GET_RES(reg) == COM7_RES_CIF) t_line = 400 + 195;
-
-    rv = reg_read(CLKRC, &reg);
-    if (rv) return rv;
-
-    int pll_mult = ((reg & CLKRC_DOUBLE) ? 2 : 1) * 3;
-    int clk_rc = (reg & CLKRC_DIVIDER_MASK) + 2;
-
-    rv = reg_write(BANK_SEL, BANK_SEL_DSP);
-    if (rv) return rv;
-
-    rv = reg_read(IMAGE_MODE, &reg);
-    if (rv) return rv;
-
-    int t_pclk = 0;
-
-    if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_YUV422) t_pclk = 2;
-    if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_RAW10) t_pclk = 1;
-    if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_RGB565) t_pclk = 2;
-
-    uint16_t exposure = ((aec_1510 & 0x3F) << 10) + ((aec_92 & 0xFF) << 2) + ((aec_10 & 0x3) << 0);
-    *exposure_us = (exposure*t_line*t_pclk)/(((XCLK_FREQ/clk_rc)*pll_mult)/1000000);
-
-    return EOS_OK;
-}
-
-int eos_ov2640_set_auto_whitebal(int enable, float r_gain_db, float g_gain_db, float b_gain_db) {
-    int rv = EOS_OK;
-    uint8_t reg;
-
-    rv = reg_write(BANK_SEL, BANK_SEL_DSP);
-    if (rv) return rv;
-
-    rv = reg_read(CTRL1, &reg);
-    if (rv) return rv;
-
-    rv = reg_write(CTRL1, (reg & (~CTRL1_AWB)) | (enable ? CTRL1_AWB : 0));
-    if (rv) return rv;
-
-    if (!enable && (!isnanf(r_gain_db)) && (!isnanf(g_gain_db)) && (!isnanf(b_gain_db))
-                && (!isinff(r_gain_db)) && (!isinff(g_gain_db)) && (!isinff(b_gain_db))) {
-    }
-
-    return rv;
-}
-
-int eos_ov2640_set_hmirror(int enable) {
-    int rv = EOS_OK;
-    uint8_t reg;
-
-    rv = reg_write(BANK_SEL, BANK_SEL_SENSOR);
-    if (rv) return rv;
-
-    rv = reg_read(REG04, &reg);
-    if (rv) return rv;
-
-    if (!enable) { // Already mirrored.
-        reg |= REG04_HFLIP_IMG;
-    } else {
-        reg &= ~REG04_HFLIP_IMG;
-    }
-
-    return reg_write(REG04, reg);
-}
-
-int eos_ov2640_set_vflip(int enable) {
-    int rv = EOS_OK;
-    uint8_t reg;
-
-    rv = reg_write(BANK_SEL, BANK_SEL_SENSOR);
-    if (rv) return rv;
-
-    rv = reg_read(REG04, &reg);
-    if (rv) return rv;
-
-    if (!enable) { // Already flipped.
-        reg |= REG04_VFLIP_IMG | REG04_VREF_EN;
-    } else {
-        reg &= ~(REG04_VFLIP_IMG | REG04_VREF_EN);
-    }
-
-    return reg_write(REG04, reg);
-}
-
-int eos_ov2640_set_effect(sde_t sde) {
-    int rv = EOS_OK;
-
-    switch (sde) {
-        case SDE_NEGATIVE:
-            if (!rv) rv = reg_write(BANK_SEL, BANK_SEL_DSP);
-            if (!rv) rv = reg_write(BPADDR, 0x00);
-            if (!rv) rv = reg_write(BPDATA, 0x40);
-            if (!rv) rv = reg_write(BPADDR, 0x05);
-            if (!rv) rv = reg_write(BPDATA, 0x80);
-            if (!rv) rv = reg_write(BPDATA, 0x80);
-            break;
-        case SDE_NORMAL:
-            if (!rv) rv = reg_write(BANK_SEL, BANK_SEL_DSP);
-            if (!rv) rv = reg_write(BPADDR, 0x00);
-            if (!rv) rv = reg_write(BPDATA, 0x00);
-            if (!rv) rv = reg_write(BPADDR, 0x05);
-            if (!rv) rv = reg_write(BPDATA, 0x80);
-            if (!rv) rv = reg_write(BPDATA, 0x80);
-            break;
-        default:
-            return EOS_ERR;
-    }
-
-    return rv;
-}
diff --git a/fw/fe310/eos/i2c/ov2640.h b/fw/fe310/eos/i2c/ov2640.h
deleted file mode 100644
index 3d08c2a..0000000
--- a/fw/fe310/eos/i2c/ov2640.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#include <stdint.h>
-
-#define OV2640_ADDR     0x30
-
-int eos_ov2640_init(void);
-int eos_ov2640_sleep(int enable);
-int eos_ov2640_set_pixfmt(pixformat_t fmt);
-int eos_ov2640_set_framesize(framesize_t framesize);
diff --git a/fw/fe310/eos/i2c/ov2640_regs.h b/fw/fe310/eos/i2c/ov2640_regs.h
deleted file mode 100644
index deb7521..0000000
--- a/fw/fe310/eos/i2c/ov2640_regs.h
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * This file is part of the OpenMV project.
- *
- * Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
- * Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
- *
- * This work is licensed under the MIT license, see the file LICENSE for details.
- *
- * OV2640 register definitions.
- */
-#ifndef __REG_REGS_H__
-#define __REG_REGS_H__
-
-/* DSP register bank FF=0x00*/
-
-#define QS                      0x44
-#define HSIZE                   0x51
-#define VSIZE                   0x52
-#define XOFFL                   0x53
-#define YOFFL                   0x54
-#define VHYX                    0x55
-#define DPRP                    0x56
-#define TEST                    0x57
-#define ZMOW                    0x5A
-#define ZMOH                    0x5B
-#define ZMHH                    0x5C
-#define BPADDR                  0x7C
-#define BPDATA                  0x7D
-#define SIZEL                   0x8C
-#define HSIZE8                  0xC0
-#define VSIZE8                  0xC1
-#define CTRL1                   0xC3
-#define MS_SP                   0xF0
-#define SS_ID                   0xF7
-#define SS_CTRL                 0xF7
-#define MC_AL                   0xFA
-#define MC_AH                   0xFB
-#define MC_D                    0xFC
-#define P_CMD                   0xFD
-#define P_STATUS                0xFE
-
-#define CTRLI                   0x50
-#define CTRLI_LP_DP             0x80
-#define CTRLI_ROUND             0x40
-
-#define CTRL0                   0xC2
-#define CTRL0_AEC_EN            0x80
-#define CTRL0_AEC_SEL           0x40
-#define CTRL0_STAT_SEL          0x20
-#define CTRL0_VFIRST            0x10
-#define CTRL0_YUV422            0x08
-#define CTRL0_YUV_EN            0x04
-#define CTRL0_RGB_EN            0x02
-#define CTRL0_RAW_EN            0x01
-
-#define CTRL2                   0x86
-#define CTRL2_DCW_EN            0x20
-#define CTRL2_SDE_EN            0x10
-#define CTRL2_UV_ADJ_EN         0x08
-#define CTRL2_UV_AVG_EN         0x04
-#define CTRL2_CMX_EN            0x01
-
-#define CTRL3                   0x87
-#define CTRL3_BPC_EN            0x80
-#define CTRL3_WPC_EN            0x40
-#define R_DVP_SP                0xD3
-#define R_DVP_SP_AUTO_MODE      0x80
-
-#define R_BYPASS                0x05
-#define R_BYPASS_DSP_EN         0x00
-#define R_BYPASS_DSP_BYPAS      0x01
-
-#define IMAGE_MODE              0xDA
-#define IMAGE_MODE_Y8_DVP_EN    0x40
-#define IMAGE_MODE_JPEG_EN      0x10
-#define IMAGE_MODE_YUV422       0x00
-#define IMAGE_MODE_RAW10        0x04
-#define IMAGE_MODE_RGB565       0x09
-#define IMAGE_MODE_HREF_VSYNC   0x02
-#define IMAGE_MODE_LBYTE_FIRST  0x01
-#define IMAGE_MODE_GET_FMT(x)   ((x)&0xC)
-
-#define RESET                   0xE0
-#define RESET_MICROC            0x40
-#define RESET_SCCB              0x20
-#define RESET_JPEG              0x10
-#define RESET_DVP               0x04
-#define RESET_IPU               0x02
-#define RESET_CIF               0x01
-
-#define MC_BIST                 0xF9
-#define MC_BIST_RESET           0x80
-#define MC_BIST_BOOT_ROM_SEL    0x40
-#define MC_BIST_12KB_SEL        0x20
-#define MC_BIST_12KB_MASK       0x30
-#define MC_BIST_512KB_SEL       0x08
-#define MC_BIST_512KB_MASK      0x0C
-#define MC_BIST_BUSY_BIT_R      0x02
-#define MC_BIST_MC_RES_ONE_SH_W 0x02
-#define MC_BIST_LAUNCH          0x01
-
-#define BANK_SEL                0xFF
-#define BANK_SEL_DSP            0x00
-#define BANK_SEL_SENSOR         0x01
-
-/* Sensor register bank FF=0x01*/
-
-#define GAIN                0x00
-#define COM1                0x03
-#define REG_PID             0x0A
-#define REG_VER             0x0B
-#define COM4                0x0D
-#define AEC                 0x10
-
-#define CLKRC               0x11
-#define CLKRC_DOUBLE        0x80
-#define CLKRC_DIVIDER_MASK  0x3F
-
-#define COM10               0x15
-#define HSTART              0x17
-#define HSTOP               0x18
-#define VSTART              0x19
-#define VSTOP               0x1A
-#define MIDH                0x1C
-#define MIDL                0x1D
-#define AEW                 0x24
-#define AEB                 0x25
-#define REG2A               0x2A
-#define FRARL               0x2B
-#define ADDVSL              0x2D
-#define ADDVSH              0x2E
-#define YAVG                0x2F
-#define HSDY                0x30
-#define HEDY                0x31
-#define ARCOM2              0x34
-#define REG45               0x45
-#define FLL                 0x46
-#define FLH                 0x47
-#define COM19               0x48
-#define ZOOMS               0x49
-#define COM22               0x4B
-#define COM25               0x4E
-#define BD50                0x4F
-#define BD60                0x50
-#define REG5D               0x5D
-#define REG5E               0x5E
-#define REG5F               0x5F
-#define REG60               0x60
-#define HISTO_LOW           0x61
-#define HISTO_HIGH          0x62
-
-#define REG04               0x04
-#define REG04_DEFAULT       0x28
-#define REG04_HFLIP_IMG     0x80
-#define REG04_VFLIP_IMG     0x40
-#define REG04_VREF_EN       0x10
-#define REG04_HREF_EN       0x08
-#define REG04_SET(x)        (REG04_DEFAULT|x)
-
-#define REG08               0x08
-#define COM2                0x09
-#define COM2_STDBY          0x10
-#define COM2_OUT_DRIVE_1x   0x00
-#define COM2_OUT_DRIVE_2x   0x01
-#define COM2_OUT_DRIVE_3x   0x02
-#define COM2_OUT_DRIVE_4x   0x03
-
-#define COM3                0x0C
-#define COM3_DEFAULT        0x38
-#define COM3_BAND_50Hz      0x04
-#define COM3_BAND_60Hz      0x00
-#define COM3_BAND_AUTO      0x02
-#define COM3_BAND_SET(x)    (COM3_DEFAULT|x)
-
-#define COM7                0x12
-#define COM7_SRST           0x80
-#define COM7_RES_UXGA       0x00 /* UXGA */
-#define COM7_RES_SVGA       0x40 /* SVGA */
-#define COM7_RES_CIF        0x20 /* CIF  */
-#define COM7_ZOOM_EN        0x04 /* Enable Zoom */
-#define COM7_COLOR_BAR      0x02 /* Enable Color Bar Test */
-#define COM7_GET_RES(x)     ((x)&0x70)
-
-#define COM8                0x13
-#define COM8_DEFAULT        0xC0
-#define COM8_BNDF_EN        0x20 /* Enable Banding filter */
-#define COM8_AGC_EN         0x04 /* AGC Auto/Manual control selection */
-#define COM8_AEC_EN         0x01 /* Auto/Manual Exposure control */
-#define COM8_SET(x)         (COM8_DEFAULT|x)
-#define COM8_SET_AEC(r,x)   (((r)&0xFE)|((x)&1))
-
-#define COM9                0x14 /* AGC gain ceiling */
-#define COM9_DEFAULT        0x08
-#define COM9_AGC_GAIN_2x    0x00 /* AGC:    2x */
-#define COM9_AGC_GAIN_4x    0x01 /* AGC:    4x */
-#define COM9_AGC_GAIN_8x    0x02 /* AGC:    8x */
-#define COM9_AGC_GAIN_16x   0x03 /* AGC:   16x */
-#define COM9_AGC_GAIN_32x   0x04 /* AGC:   32x */
-#define COM9_AGC_GAIN_64x   0x05 /* AGC:   64x */
-#define COM9_AGC_GAIN_128x  0x06 /* AGC:  128x */
-#define COM9_AGC_SET(x)     (COM9_DEFAULT|(x<<5))
-
-#define CTRL1_AWB           0x08 /* Enable AWB */
-
-#define VV                  0x26
-#define VV_AGC_TH_SET(h,l)  ((h<<4)|(l&0x0F))
-
-#define REG32               0x32
-#define REG32_UXGA          0x36
-#define REG32_SVGA          0x09
-#define REG32_CIF           0x00
-
-#define VAL_SET(x, mask, rshift, lshift) ((((x) >> rshift) & mask) << lshift)
-
-#define CTRLI_V_DIV_SET(x)      VAL_SET(x, 0x3, 0, 3)
-#define CTRLI_H_DIV_SET(x)      VAL_SET(x, 0x3, 0, 0)
-
-#define SIZEL_HSIZE8_11_SET(x)  VAL_SET(x, 0x1, 11, 6)
-#define SIZEL_HSIZE8_SET(x)     VAL_SET(x, 0x7, 0, 3)
-#define SIZEL_VSIZE8_SET(x)     VAL_SET(x, 0x7, 0, 0)
-
-#define HSIZE8_SET(x)           VAL_SET(x, 0xFF, 3, 0)
-#define VSIZE8_SET(x)           VAL_SET(x, 0xFF, 3, 0)
-
-#define HSIZE_SET(x)            VAL_SET(x, 0xFF, 2, 0)
-#define VSIZE_SET(x)            VAL_SET(x, 0xFF, 2, 0)
-
-#define XOFFL_SET(x)            VAL_SET(x, 0xFF, 0, 0)
-#define YOFFL_SET(x)            VAL_SET(x, 0xFF, 0, 0)
-
-#define VHYX_VSIZE_SET(x)       VAL_SET(x, 0x1, (8+2), 7)
-#define VHYX_HSIZE_SET(x)       VAL_SET(x, 0x1, (8+2), 3)
-#define VHYX_YOFF_SET(x)        VAL_SET(x, 0x3, 8, 4)
-#define VHYX_XOFF_SET(x)        VAL_SET(x, 0x3, 8, 0)
-
-#define TEST_HSIZE_SET(x)       VAL_SET(x, 0x1, (9+2), 7)
-
-#define ZMOW_OUTW_SET(x)        VAL_SET(x, 0xFF, 2, 0)
-#define ZMOH_OUTH_SET(x)        VAL_SET(x, 0xFF, 2, 0)
-
-#define ZMHH_ZSPEED_SET(x)      VAL_SET(x, 0x0F, 0, 4)
-#define ZMHH_OUTH_SET(x)        VAL_SET(x, 0x1, (8+2), 2)
-#define ZMHH_OUTW_SET(x)        VAL_SET(x, 0x3, (8+2), 0)
-
-#endif //__REG_REGS_H__
diff --git a/fw/fe310/eos/i2s.c b/fw/fe310/eos/i2s.c
deleted file mode 100644
index 9cc9d9c..0000000
--- a/fw/fe310/eos/i2s.c
+++ /dev/null
@@ -1,477 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-
-#include "encoding.h"
-#include "platform.h"
-#include "prci_driver.h"
-
-#include "eos.h"
-#include "interrupt.h"
-#include "event.h"
-
-#include "board.h"
-
-#include "i2s.h"
-#include "i2s_priv.h"
-
-#define I2S_REG_CK(o)       _REG32(I2S_CTRL_ADDR_CK, o)
-#define I2S_REG_WS_MIC(o)   _REG32(I2S_CTRL_ADDR_WS_MIC, o)
-#define I2S_REG_WS_SPK(o)   _REG32(I2S_CTRL_ADDR_WS_SPK, o)
-
-#define I2S_PIN_PWM         ((1 << I2S_PIN_CK) | (1 << I2S_PIN_CK_SW) | (1 << I2S_PIN_WS_MIC) | (1 << I2S_PIN_WS_SPK))
-
-#define MIN(X, Y)           (((X) < (Y)) ? (X) : (Y))
-#define MAX(X, Y)           (((X) > (Y)) ? (X) : (Y))
-
-#define EOS_ABUF_IDX_MASK(IDX, SIZE)  ((IDX) & ((SIZE) - 1))
-
-EOSABuf i2s_mic_buf;
-EOSABuf i2s_spk_buf;
-
-static eos_i2s_handler_t i2s_mic_handler = NULL;
-static eos_i2s_handler_t i2s_spk_handler = NULL;
-static uint32_t i2s_clk_period;
-static uint8_t i2s_mic_volume = 0;      /* 0 - 8 */
-static uint8_t i2s_spk_volume = 16;     /* 0 - 16 */
-
-uint32_t _eos_i2s_drvr[] = {
-    0,                      /* I2S_MIC_BUF  */
-    0,                      /* I2S_SPK_BUF  */
-    EOS_I2S_FMT_PCM16,      /* I2S_FMT      */
-    EOS_I2S_MODE_STEREO,    /* I2S_MODE     */
-    0,                      /* I2S_MIC_WM   */
-    0,                      /* I2S_SPK_WM   */
-    0,                      /* I2S_MIC_EVT  */
-    0,                      /* I2S_SPK_EVT  */
-    0,                      /* I2S_MIC_CMP2 */
-    0,                      /* I2S_MIC_CMP3 */
-    0,                      /* I2S_SAMPLE */
-};
-
-#define I2S_MIC_BUF     0
-#define I2S_SPK_BUF     1
-#define I2S_FMT         2
-#define I2S_MODE        3
-#define I2S_MIC_WM      4
-#define I2S_SPK_WM      5
-#define I2S_MIC_EVT     6
-#define I2S_SPK_EVT     7
-#define I2S_MIC_CMP2    8
-#define I2S_MIC_CMP3    9
-#define I2S_SAMPLE      10
-
-static void _abuf_init(EOSABuf *buf, uint8_t *array, uint16_t size) {
-    buf->idx_r = 0;
-    buf->idx_w = 0;
-    buf->size = size;
-    buf->array = array;
-}
-
-static int _abuf_push8(EOSABuf *buf, uint8_t sample) {
-    if ((uint16_t)(buf->idx_w - buf->idx_r) == buf->size) return EOS_ERR_FULL;
-
-    buf->array[EOS_ABUF_IDX_MASK(buf->idx_w, buf->size)] = sample;
-    buf->idx_w++;
-    return EOS_OK;
-}
-
-static int _abuf_push16(EOSABuf *buf, uint16_t sample) {
-    if ((uint16_t)(buf->idx_w - buf->idx_r) == buf->size) return EOS_ERR_FULL;
-
-    buf->array[EOS_ABUF_IDX_MASK(buf->idx_w, buf->size)] = sample >> 8;
-    buf->array[EOS_ABUF_IDX_MASK(buf->idx_w + 1, buf->size)] = sample & 0xFF;
-    buf->idx_w += 2;
-    return EOS_OK;
-}
-
-static int _abuf_pop8(EOSABuf *buf, uint8_t *sample) {
-    if (buf->idx_r == buf->idx_w) {
-        return EOS_ERR_EMPTY;
-    } else {
-        *sample = buf->array[EOS_ABUF_IDX_MASK(buf->idx_r, buf->size)];
-        buf->idx_r++;
-        return EOS_OK;
-    }
-}
-
-static int _abuf_pop16(EOSABuf *buf, uint16_t *sample) {
-    if (buf->idx_r == buf->idx_w) {
-        return EOS_ERR_EMPTY;
-    } else {
-        *sample = buf->array[EOS_ABUF_IDX_MASK(buf->idx_r, buf->size)] << 8;
-        *sample |= buf->array[EOS_ABUF_IDX_MASK(buf->idx_r + 1, buf->size)];
-        buf->idx_r += 2;
-        return EOS_OK;
-    }
-}
-
-static void _abuf_flush(EOSABuf *buf) {
-    buf->idx_r = 0;
-    buf->idx_w = 0;
-}
-
-static uint16_t _abuf_len(EOSABuf *buf) {
-    return buf->idx_w - buf->idx_r;
-}
-
-static void i2s_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) {
-    switch(type & ~EOS_EVT_MASK) {
-        case EOS_I2S_ETYPE_MIC:
-            if (i2s_mic_handler) {
-                i2s_mic_handler(type);
-                clear_csr(mstatus, MSTATUS_MIE);
-                _eos_i2s_drvr[I2S_MIC_EVT] = 1;
-                set_csr(mstatus, MSTATUS_MIE);
-            }
-            break;
-
-        case EOS_I2S_ETYPE_SPK:
-            if (i2s_spk_handler) {
-                i2s_spk_handler(type);
-                clear_csr(mstatus, MSTATUS_MIE);
-                _eos_i2s_drvr[I2S_SPK_EVT] = 1;
-                set_csr(mstatus, MSTATUS_MIE);
-            }
-            break;
-
-        default:
-            eos_evtq_bad_handler(type, buffer, len);
-            break;
-    }
-}
-
-#define PLIC_PRIORITY     0x0C000000
-
-static void i2s_cmp_set(void) {
-    int c = 7;    /* interrupt will trigger c i2s clocks before spk ws */
-    int spk_ws_offset = i2s_spk_volume - 16 + i2s_mic_volume;
-    volatile  uint32_t *p = (uint32_t *)PLIC_PRIORITY+I2S_IRQ_SD_ID;
-
-    /* interrupt trigger - will start with left channel */
-    if (spk_ws_offset - c < 0) {
-        I2S_REG_WS_SPK(PWM_CMP3) = i2s_clk_period * (64 + spk_ws_offset - c);
-    } else {
-        I2S_REG_WS_SPK(PWM_CMP3) = i2s_clk_period * (spk_ws_offset - c);
-    }
-
-    /* disable interrupt for this cycle */
-    *p = 0;
-
-    /* empty buffers */
-    // i2s_mic_buf.idx_r = i2s_mic_buf.idx_w;
-    // i2s_spk_buf.idx_w = i2s_spk_buf.idx_r;
-
-    /* adjust spk ws relative to mic ws */
-    if (spk_ws_offset <= 0) {
-        spk_ws_offset += 32;
-        GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << I2S_PIN_WS_SPK);
-    } else {
-        GPIO_REG(GPIO_OUTPUT_XOR) |=  (1 << I2S_PIN_WS_SPK);
-    }
-    I2S_REG_WS_SPK(PWM_CMP1) = i2s_clk_period * spk_ws_offset;
-    I2S_REG_WS_SPK(PWM_CMP2) = i2s_clk_period * (32 + spk_ws_offset);
-
-    /* mic cmp2 relative to interrupt trigger */
-    _eos_i2s_drvr[I2S_MIC_CMP2] = (17 + c - i2s_spk_volume) * i2s_clk_period;   /* (17 + c - i2s_spk_volume) == (1 + i2s_mic_volume) - (spk_ws_offset - c) */
-    _eos_i2s_drvr[I2S_MIC_CMP3] = 16 * i2s_clk_period;
-}
-
-extern void _eos_i2s_start_pwm(void);
-
-int eos_i2s_init(uint8_t wakeup_cause) {
-    eos_evtq_set_handler(EOS_EVT_I2S, i2s_handle_evt);
-
-    I2S_REG_CK(PWM_CFG)         = 0;
-    I2S_REG_WS_MIC(PWM_CFG)     = 0;
-    I2S_REG_WS_SPK(PWM_CFG)     = 0;
-
-    eos_i2s_init_mux();
-
-    GPIO_REG(GPIO_OUTPUT_VAL)   |=  (1 << I2S_PIN_CK_SW);
-    GPIO_REG(GPIO_OUTPUT_VAL)   &= ~(1 << I2S_PIN_CK_SR);
-
-    GPIO_REG(GPIO_INPUT_EN)     &= ~(1 << I2S_PIN_CK_SW);
-    GPIO_REG(GPIO_OUTPUT_EN)    |=  (1 << I2S_PIN_CK_SW);
-
-    GPIO_REG(GPIO_INPUT_EN)     &= ~(1 << I2S_PIN_CK_SR);
-    GPIO_REG(GPIO_OUTPUT_EN)    |=  (1 << I2S_PIN_CK_SR);
-
-    return EOS_OK;
-}
-
-void eos_i2s_init_mux(void) {
-    GPIO_REG(GPIO_OUTPUT_VAL)   &= ~((1 << I2S_PIN_CK) | (1 << I2S_PIN_WS_MIC) | (1 << I2S_PIN_WS_SPK));
-
-    GPIO_REG(GPIO_INPUT_EN)     &= ~(1 << I2S_PIN_CK);
-    GPIO_REG(GPIO_OUTPUT_EN)    |=  (1 << I2S_PIN_CK);
-
-    GPIO_REG(GPIO_INPUT_EN)     &= ~(1 << I2S_PIN_WS_MIC);
-    GPIO_REG(GPIO_OUTPUT_EN)    |=  (1 << I2S_PIN_WS_MIC);
-
-    GPIO_REG(GPIO_INPUT_EN)     &= ~(1 << I2S_PIN_WS_SPK);
-    GPIO_REG(GPIO_OUTPUT_EN)    |=  (1 << I2S_PIN_WS_SPK);
-
-    GPIO_REG(GPIO_INPUT_EN)     |=  (1 << I2S_PIN_SD_IN);
-    GPIO_REG(GPIO_OUTPUT_EN)    &= ~(1 << I2S_PIN_SD_IN);
-
-    GPIO_REG(GPIO_INPUT_EN)     &= ~(1 << I2S_PIN_SD_OUT);
-    GPIO_REG(GPIO_OUTPUT_EN)    &= ~(1 << I2S_PIN_SD_OUT);
-}
-
-void eos_i2s_start(uint32_t sample_rate) {
-    i2s_clk_period = ((PRCI_get_cpu_freq() / (sample_rate * 64)) & ~I2S_PWM_SCALE_CK_MASK) + 1;
-
-    GPIO_REG(GPIO_INPUT_EN)     |=  (1 << I2S_PIN_SD_IN);
-    GPIO_REG(GPIO_OUTPUT_EN)    &= ~(1 << I2S_PIN_SD_IN);
-
-    GPIO_REG(GPIO_INPUT_EN)     &= ~(1 << I2S_PIN_SD_OUT);
-    GPIO_REG(GPIO_OUTPUT_EN)    &= ~(1 << I2S_PIN_SD_OUT);
-
-    I2S_REG_CK(PWM_CMP0)        = i2s_clk_period >> I2S_PWM_SCALE_CK;
-    I2S_REG_CK(PWM_CMP1)        = I2S_REG_CK(PWM_CMP0) / 2;
-    I2S_REG_CK(PWM_CMP2)        = 0;
-    I2S_REG_CK(PWM_CMP3)        = 0;
-
-    I2S_REG_WS_MIC(PWM_CMP0)    = i2s_clk_period * 64 - 1;
-    I2S_REG_WS_MIC(PWM_CMP1)    = i2s_clk_period * 32;
-
-    I2S_REG_WS_SPK(PWM_CMP0)    = i2s_clk_period * 64 - 1;
-    i2s_cmp_set();
-
-    I2S_REG_CK(PWM_COUNT)       = 0;
-    I2S_REG_WS_MIC(PWM_COUNT)   = 0;
-    I2S_REG_WS_SPK(PWM_COUNT)   = i2s_clk_period / 2;
-
-    if (i2s_mic_buf.array && i2s_mic_buf.size) {
-        _eos_i2s_drvr[I2S_MIC_BUF] = (uint32_t)&i2s_mic_buf;
-        if (_eos_i2s_drvr[I2S_MIC_WM] == 0) {
-            _eos_i2s_drvr[I2S_MIC_WM] = i2s_mic_buf.size / 2;
-        }
-    }
-    if (i2s_spk_buf.array && i2s_spk_buf.size) {
-        _eos_i2s_drvr[I2S_SPK_BUF] = (uint32_t)&i2s_spk_buf;
-        if (_eos_i2s_drvr[I2S_SPK_WM] == 0) {
-            _eos_i2s_drvr[I2S_SPK_WM] = i2s_spk_buf.size / 2;
-        }
-    }
-    if (i2s_mic_handler) _eos_i2s_drvr[I2S_MIC_EVT] = 1;
-    if (i2s_spk_handler) _eos_i2s_drvr[I2S_SPK_EVT] = 1;
-
-    eos_intr_set_priority(I2S_IRQ_SD_ID, IRQ_PRIORITY_I2S_SD);
-    eos_intr_set_priority(I2S_IRQ_WS_ID, IRQ_PRIORITY_I2S_WS);
-    eos_intr_enable(I2S_IRQ_SD_ID);
-    eos_intr_enable(I2S_IRQ_WS_ID);
-
-    _eos_i2s_start_pwm();
-    /*
-    I2S_REG_CK(PWM_CFG)         = PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | I2S_PWM_SCALE_CK;
-    I2S_REG_WS_MIC(PWM_CFG)     = PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | PWM_CFG_CMP2GANG;
-    I2S_REG_WS_SPK(PWM_CFG)     = PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | PWM_CFG_CMP1GANG;
-    */
-
-    GPIO_REG(GPIO_OUTPUT_VAL)   |=  (1 << I2S_PIN_WS_MIC);
-    GPIO_REG(GPIO_INPUT_EN)     &= ~(1 << I2S_PIN_WS_MIC);
-    GPIO_REG(GPIO_OUTPUT_EN)    |=  (1 << I2S_PIN_WS_MIC);
-
-    GPIO_REG(GPIO_OUTPUT_VAL)   |=  (1 << I2S_PIN_CK_SR);
-    GPIO_REG(GPIO_IOF_SEL)      |=  I2S_PIN_PWM;
-    GPIO_REG(GPIO_IOF_EN)       |=  I2S_PIN_PWM;
-}
-
-void eos_i2s_stop(void) {
-    I2S_REG_CK(PWM_CFG)         = 0;
-    I2S_REG_WS_MIC(PWM_CFG)     = 0;
-    I2S_REG_WS_SPK(PWM_CFG)     = 0;
-    I2S_REG_CK(PWM_COUNT)       = 0;
-    I2S_REG_WS_MIC(PWM_COUNT)   = 0;
-    I2S_REG_WS_SPK(PWM_COUNT)   = 0;
-
-    _eos_i2s_drvr[I2S_MIC_BUF]  = 0;
-    _eos_i2s_drvr[I2S_MIC_EVT]  = 0;
-    _eos_i2s_drvr[I2S_MIC_WM]   = 0;
-
-    _eos_i2s_drvr[I2S_SPK_BUF]  = 0;
-    _eos_i2s_drvr[I2S_SPK_EVT]  = 0;
-    _eos_i2s_drvr[I2S_SPK_WM]   = 0;
-
-    eos_intr_disable(I2S_IRQ_WS_ID);
-    eos_intr_disable(I2S_IRQ_SD_ID);
-
-    GPIO_REG(GPIO_OUTPUT_VAL)   |=  (1 << I2S_PIN_CK_SW);
-    GPIO_REG(GPIO_OUTPUT_VAL)   &= ~(1 << I2S_PIN_CK_SR);
-
-    GPIO_REG(GPIO_OUTPUT_XOR)   &= ~(1 << I2S_PIN_WS_SPK);
-    GPIO_REG(GPIO_IOF_EN)       &= ~I2S_PIN_PWM;
-
-    eos_i2s_mic_set_wm(0);
-    eos_i2s_spk_set_wm(0);
-}
-
-int eos_i2s_running(void) {
-    return !!(GPIO_REG(GPIO_IOF_EN) & (1 << I2S_PIN_CK));
-}
-
-void eos_i2s_set_fmt(unsigned char fmt) {
-    _eos_i2s_drvr[I2S_FMT] = fmt;
-}
-
-void eos_i2s_set_mode(unsigned char mode) {
-    _eos_i2s_drvr[I2S_MODE] = mode;
-}
-
-void eos_i2s_mic_init(uint8_t *mic_arr, uint16_t mic_arr_size) {
-    clear_csr(mstatus, MSTATUS_MIE);
-    _abuf_init(&i2s_mic_buf, mic_arr, mic_arr_size);
-    set_csr(mstatus, MSTATUS_MIE);
-}
-
-void eos_i2s_mic_set_handler(eos_i2s_handler_t wm_handler) {
-    clear_csr(mstatus, MSTATUS_MIE);
-    i2s_mic_handler = wm_handler;
-    set_csr(mstatus, MSTATUS_MIE);
-}
-
-void eos_i2s_mic_set_wm(uint16_t wm) {
-    clear_csr(mstatus, MSTATUS_MIE);
-    _eos_i2s_drvr[I2S_MIC_WM] = wm;
-    set_csr(mstatus, MSTATUS_MIE);
-
-}
-
-uint16_t eos_i2s_mic_len(void) {
-    clear_csr(mstatus, MSTATUS_MIE);
-    uint16_t ret = _abuf_len(&i2s_mic_buf);
-    set_csr(mstatus, MSTATUS_MIE);
-    return ret;
-}
-
-uint16_t eos_i2s_mic_read(uint8_t *sample, uint16_t ssize) {
-    uint16_t i;
-    uint16_t _ssize = 0;
-
-    clear_csr(mstatus, MSTATUS_MIE);
-    _ssize = MIN(ssize, _abuf_len(&i2s_mic_buf));
-    set_csr(mstatus, MSTATUS_MIE);
-
-    for (i=0; i<_ssize; i++) {
-        sample[i] = i2s_mic_buf.array[EOS_ABUF_IDX_MASK(i2s_mic_buf.idx_r + i, i2s_mic_buf.size)];
-    }
-
-    clear_csr(mstatus, MSTATUS_MIE);
-    i2s_mic_buf.idx_r += _ssize;
-    set_csr(mstatus, MSTATUS_MIE);
-
-    return _ssize;
-}
-
-int eos_i2s_mic_pop8(uint8_t *sample) {
-    int ret;
-
-    clear_csr(mstatus, MSTATUS_MIE);
-    ret = _abuf_pop8(&i2s_mic_buf, sample);
-    set_csr(mstatus, MSTATUS_MIE);
-
-    return ret;
-}
-
-int eos_i2s_mic_pop16(uint16_t *sample) {
-    int ret;
-
-    clear_csr(mstatus, MSTATUS_MIE);
-    ret = _abuf_pop16(&i2s_mic_buf, sample);
-    set_csr(mstatus, MSTATUS_MIE);
-
-    return ret;
-}
-
-int eos_i2s_mic_vol_get(void) {
-    return i2s_mic_volume;
-}
-
-void eos_i2s_mic_vol_set(int vol) {
-    if ((vol < 0) || (vol > 8)) return;
-
-    i2s_mic_volume = vol;
-
-    clear_csr(mstatus, MSTATUS_MIE);
-    i2s_cmp_set();
-    set_csr(mstatus, MSTATUS_MIE);
-}
-
-void eos_i2s_spk_init(uint8_t *spk_arr, uint16_t spk_arr_size) {
-    clear_csr(mstatus, MSTATUS_MIE);
-    _abuf_init(&i2s_spk_buf, spk_arr, spk_arr_size);
-    set_csr(mstatus, MSTATUS_MIE);
-}
-
-void eos_i2s_spk_set_handler(eos_i2s_handler_t wm_handler) {
-    clear_csr(mstatus, MSTATUS_MIE);
-    i2s_spk_handler = wm_handler;
-    set_csr(mstatus, MSTATUS_MIE);
-}
-
-void eos_i2s_spk_set_wm(uint16_t wm) {
-    clear_csr(mstatus, MSTATUS_MIE);
-    _eos_i2s_drvr[I2S_SPK_WM] = wm;
-    set_csr(mstatus, MSTATUS_MIE);
-}
-
-uint16_t eos_i2s_spk_len(void) {
-    clear_csr(mstatus, MSTATUS_MIE);
-    uint16_t ret = _abuf_len(&i2s_spk_buf);
-    set_csr(mstatus, MSTATUS_MIE);
-    return ret;
-}
-
-uint16_t eos_i2s_spk_write(uint8_t *sample, uint16_t ssize) {
-    uint16_t i;
-    uint16_t _ssize = 0;
-
-    clear_csr(mstatus, MSTATUS_MIE);
-    _ssize = MIN(ssize, i2s_spk_buf.size - _abuf_len(&i2s_spk_buf));
-    set_csr(mstatus, MSTATUS_MIE);
-
-    for (i=0; i<_ssize; i++) {
-        i2s_spk_buf.array[EOS_ABUF_IDX_MASK(i2s_spk_buf.idx_w + i, i2s_spk_buf.size)] = sample[i];
-    }
-
-    clear_csr(mstatus, MSTATUS_MIE);
-    i2s_spk_buf.idx_w += _ssize;
-    set_csr(mstatus, MSTATUS_MIE);
-
-    return _ssize;
-}
-
-int eos_i2s_spk_push8(uint8_t sample) {
-    int ret;
-
-    clear_csr(mstatus, MSTATUS_MIE);
-    ret = _abuf_push8(&i2s_spk_buf, sample);
-    set_csr(mstatus, MSTATUS_MIE);
-
-    return ret;
-}
-
-int eos_i2s_spk_push16(uint16_t sample) {
-    int ret;
-
-    clear_csr(mstatus, MSTATUS_MIE);
-    ret = _abuf_push16(&i2s_spk_buf, sample);
-    set_csr(mstatus, MSTATUS_MIE);
-
-    return ret;
-}
-
-int eos_i2s_spk_vol_get(void) {
-    return i2s_spk_volume;
-}
-
-void eos_i2s_spk_vol_set(int vol) {
-    if ((vol < 0) || (vol > 16)) return;
-
-    i2s_spk_volume = vol;
-
-    clear_csr(mstatus, MSTATUS_MIE);
-    i2s_cmp_set();
-    set_csr(mstatus, MSTATUS_MIE);
-}
diff --git a/fw/fe310/eos/i2s.h b/fw/fe310/eos/i2s.h
deleted file mode 100644
index 81b4ade..0000000
--- a/fw/fe310/eos/i2s.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#include <stdint.h>
-
-#include "i2s_def.h"
-
-typedef struct EOSABuf {
-    uint16_t idx_r;
-    uint16_t idx_w;
-    uint16_t size;
-    uint8_t *array;
-} EOSABuf;
-
-typedef void (*eos_i2s_handler_t) (unsigned char);
-
-int eos_i2s_init(uint8_t wakeup_cause);
-void eos_i2s_init_mux(void);
-void eos_i2s_start(uint32_t sample_rate);
-void eos_i2s_stop(void);
-int eos_i2s_running(void);
-void eos_i2s_set_fmt(unsigned char fmt);
-void eos_i2s_set_mode(unsigned char mode);
-void eos_i2s_mic_init(uint8_t *mic_arr, uint16_t mic_arr_size);
-void eos_i2s_mic_set_handler(eos_i2s_handler_t wm_handler);
-void eos_i2s_mic_set_wm(uint16_t wm);
-uint16_t eos_i2s_mic_len(void);
-uint16_t eos_i2s_mic_read(uint8_t *sample, uint16_t ssize);
-int eos_i2s_mic_pop8(uint8_t *sample);
-int eos_i2s_mic_pop16(uint16_t *sample);
-int eos_i2s_mic_vol_get(void);
-void eos_i2s_mic_vol_set(int vol);
-void eos_i2s_spk_init(uint8_t *mic_arr, uint16_t mic_arr_size);
-void eos_i2s_spk_set_handler(eos_i2s_handler_t wm_handler);
-void eos_i2s_spk_set_wm(uint16_t wm);
-uint16_t eos_i2s_spk_len(void);
-uint16_t eos_i2s_spk_write(uint8_t *sample, uint16_t ssize);
-int eos_i2s_spk_push8(uint8_t sample);
-int eos_i2s_spk_push16(uint16_t sample);
-int eos_i2s_spk_vol_get(void);
-void eos_i2s_spk_vol_set(int vol);
diff --git a/fw/fe310/eos/i2s_def.h b/fw/fe310/eos/i2s_def.h
deleted file mode 100644
index 3529be1..0000000
--- a/fw/fe310/eos/i2s_def.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#define EOS_I2S_FMT_PCM16       0
-#define EOS_I2S_FMT_ALAW        1
-
-#define EOS_I2S_MODE_STEREO     0
-#define EOS_I2S_MODE_MONO     	1
-
-#define EOS_I2S_ETYPE_MIC       1
-#define EOS_I2S_ETYPE_SPK       2
diff --git a/fw/fe310/eos/i2s_priv.h b/fw/fe310/eos/i2s_priv.h
deleted file mode 100644
index 25237c3..0000000
--- a/fw/fe310/eos/i2s_priv.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#define I2S_PWM_SCALE_CK        2
-#define I2S_PWM_SCALE_CK_MASK   0x0003
-
-/* asm */
-#define I2S_ABUF_OFF_IDXR       0
-#define I2S_ABUF_OFF_IDXW       2
-#define I2S_ABUF_OFF_SIZE       4
-#define I2S_ABUF_OFF_ARRAY      8
diff --git a/fw/fe310/eos/interrupt.c b/fw/fe310/eos/interrupt.c
deleted file mode 100644
index dab6fab..0000000
--- a/fw/fe310/eos/interrupt.c
+++ /dev/null
@@ -1,75 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <stdio.h>
-
-#include "encoding.h"
-#include "platform.h"
-#include "plic_driver.h"
-
-#include "eos.h"
-#include "interrupt.h"
-
-// Global Instance data for the PLIC
-// for use by the PLIC Driver.
-static plic_instance_t plic;
-
-static eos_intr_handler_t ext_interrupt_handler[PLIC_NUM_INTERRUPTS];
-
-uintptr_t eos_intr_handle(uintptr_t int_num) {
-    if ((int_num >=1) && (int_num <= PLIC_NUM_INTERRUPTS) && (ext_interrupt_handler[int_num-1])) {
-        ext_interrupt_handler[int_num-1]();
-    } else {
-        printf("INTR ERROR:%d\n", int_num);
-        exit(int_num);
-    }
-    return int_num;
-}
-
-int eos_intr_init(uint8_t wakeup_cause) {
-    for (int i = 0; i < PLIC_NUM_INTERRUPTS; i++){
-        ext_interrupt_handler[i] = NULL;
-    }
-
-    /**************************************************************************
-    * Set up the PLIC
-    **************************************************************************/
-    PLIC_init(&plic,
- 	    PLIC_CTRL_ADDR,
- 	    PLIC_NUM_INTERRUPTS,
- 	    PLIC_NUM_PRIORITIES);
-
-    // Enable Global (PLIC) interrupts.
-    set_csr(mie, MIP_MEIP);
-
-    // Enable all interrupts
-    set_csr(mstatus, MSTATUS_MIE);
-
-    return EOS_OK;
-}
-
-void eos_intr_set(uint8_t int_num, uint8_t priority, eos_intr_handler_t handler) {
-    ext_interrupt_handler[int_num-1] = handler;
-    PLIC_set_priority(&plic, int_num, priority);
-    PLIC_enable_interrupt(&plic, int_num);
-}
-
-void eos_intr_set_handler(uint8_t int_num, eos_intr_handler_t handler) {
-    ext_interrupt_handler[int_num-1] = handler;
-}
-
-void eos_intr_set_priority(uint8_t int_num, uint8_t priority) {
-    PLIC_set_priority(&plic, int_num, priority);
-}
-
-void eos_intr_enable(uint8_t int_num) {
-    PLIC_enable_interrupt(&plic, int_num);
-}
-
-void eos_intr_disable(uint8_t int_num) {
-    PLIC_disable_interrupt(&plic, int_num);
-}
-
-void eos_intr_mask(uint8_t priority) {
-    PLIC_set_threshold(&plic, priority);
-}
diff --git a/fw/fe310/eos/interrupt.h b/fw/fe310/eos/interrupt.h
deleted file mode 100644
index a239934..0000000
--- a/fw/fe310/eos/interrupt.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#include <stdint.h>
-
-#include "irq_def.h"
-
-typedef void (*eos_intr_handler_t) (void);
-
-int eos_intr_init(uint8_t wakeup_cause);
-void eos_intr_set(uint8_t int_num, uint8_t priority, eos_intr_handler_t handler);
-void eos_intr_set_handler(uint8_t int_num, eos_intr_handler_t handler);
-void eos_intr_set_priority(uint8_t int_num, uint8_t priority);
-void eos_intr_enable(uint8_t int_num);
-void eos_intr_disable(uint8_t int_num);
-void eos_intr_mask(uint8_t priority);
\ No newline at end of file
diff --git a/fw/fe310/eos/lcd.c b/fw/fe310/eos/lcd.c
deleted file mode 100644
index 3080a13..0000000
--- a/fw/fe310/eos/lcd.c
+++ /dev/null
@@ -1,546 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <stdio.h>
-
-#include "encoding.h"
-#include "platform.h"
-
-#include "eos.h"
-#include "timer.h"
-#include "i2s.h"
-#include "net.h"
-#include "spi_dev.h"
-#include "eve/eve.h"
-
-#include "board.h"
-
-#include "lcd.h"
-
-#define BIT_PUT(b, pin)     if (b) GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << (pin)); else GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << (pin));
-#define BIT_GET(pin)        ((GPIO_REG(GPIO_INPUT_VAL) & (1 << (pin))) >> (pin))
-
-#define SCK_UP              { GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << IOF_SPI1_SCK); }
-#define SCK_DN              { GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << IOF_SPI1_SCK); }
-
-static inline void _sleep(int n) {
-    volatile int x = n;
-
-    while(x) x--;
-}
-
-int eos_lcd_select(void) {
-    if (eos_i2s_running()) return EOS_ERR_BUSY;
-    if (eos_spi_dev() != EOS_SPI_DEV_NET) return EOS_ERR_BUSY;
-
-    eos_net_stop();
-
-    GPIO_REG(GPIO_OUTPUT_VAL)   &= ~(1 << LCD_PIN_CS);
-
-    GPIO_REG(GPIO_INPUT_EN)     &= ~(1 << LCD_PIN_CS);
-    GPIO_REG(GPIO_OUTPUT_EN)    |=  (1 << LCD_PIN_CS);
-
-    GPIO_REG(GPIO_IOF_EN)       &=  ~SPI_IOF_MASK;
-
-    return EOS_OK;
-}
-
-void eos_lcd_deselect(void) {
-    GPIO_REG(GPIO_IOF_EN) |= SPI_IOF_MASK;
-    eos_net_start();
-}
-
-void eos_lcd_cs_set(void) {
-    GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << LCD_PIN_CS);
-}
-
-void eos_lcd_cs_clear(void) {
-    GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << LCD_PIN_CS);
-}
-
-/* sck frequency for r/w operations is 0.8Mhz */
-void eos_lcd_write(uint8_t dc, uint8_t data) {
-    int i;
-
-    BIT_PUT(dc, IOF_SPI1_MOSI);
-    _sleep(10);
-    SCK_UP;
-    for (i=0; i<8; i++) {
-        _sleep(10);
-        SCK_DN;
-        BIT_PUT(data & 0x80, IOF_SPI1_MOSI);
-        _sleep(10);
-        SCK_UP;
-        data = data << 1;
-    }
-    _sleep(10);
-    SCK_DN;
-}
-
-void eos_lcd_read(uint8_t *data) {
-    int i;
-
-    *data = 0;
-    for (i=0; i<8; i++) {
-        _sleep(10);
-        *data = *data << 1;
-        *data |= BIT_GET(IOF_SPI1_MISO);
-        SCK_UP;
-        _sleep(10);
-        SCK_DN;
-    }
-}
-
-static int _init(void) {
-    int rv;
-    uint8_t chip_id[3];
-
-    rv = eos_lcd_select();
-    if (rv) return rv;
-    eos_lcd_cs_set();
-
-    /* LCD Setting */
-    eos_lcd_write(0, 0xFF);     // change to Page 1 CMD
-    eos_lcd_write(1, 0xFF);
-    eos_lcd_write(1, 0x98);
-    eos_lcd_write(1, 0x06);
-    eos_lcd_write(1, 0x04);
-    eos_lcd_write(1, 0x01);
-
-    // eos_lcd_write(0, 0x08);  // Output SDA
-    // eos_lcd_write(1, 0x10);
-
-    eos_lcd_write(0, 0xFE);     // enable read
-    eos_lcd_write(1, 0x81);
-
-    eos_lcd_write(0, 0x00);     // RDID4
-    eos_lcd_read(&chip_id[0]);
-
-    eos_lcd_write(0, 0x01);
-    eos_lcd_read(&chip_id[1]);
-
-    eos_lcd_write(0, 0x02);
-    eos_lcd_read(&chip_id[2]);
-
-    printf("LCD CHIP ID: %.2x%.2x%.2x\n", chip_id[0], chip_id[1], chip_id[2]);
-
-    eos_lcd_write(0, 0xFE);     // disable read
-    eos_lcd_write(1, 0x00);
-
-    if (memcmp(chip_id, "\x98\x06\x04", sizeof(chip_id))) {
-        return EOS_ERR_ABSENT;
-    }
-
-    eos_lcd_write(0, 0x20);     // set DE/VSYNC mode
-    eos_lcd_write(1, 0x00);
-
-    eos_lcd_write(0, 0x21);     // DE = 1 Active
-    eos_lcd_write(1, 0x01);
-
-    eos_lcd_write(0, 0x30);     // resolution setting 480 X 854
-    eos_lcd_write(1, 0x01);
-
-    eos_lcd_write(0, 0x31);     // inversion setting 2-dot
-    eos_lcd_write(1, 0x00);
-
-    eos_lcd_write(0, 0x40);     // BT AVDD,AVDD
-    eos_lcd_write(1, 0x16);
-
-    eos_lcd_write(0, 0x41);
-    eos_lcd_write(1, 0x33);     // 22
-
-    eos_lcd_write(0, 0x42);
-    eos_lcd_write(1, 0x03);     // VGL=DDVDH+VCIP-DDVDL, VGH=2DDVDL-VCIP
-
-    eos_lcd_write(0, 0x43);
-    eos_lcd_write(1, 0x09);     // set VGH clamp level
-
-    eos_lcd_write(0, 0x44);
-    eos_lcd_write(1, 0x06);     // set VGL clamp level
-
-    eos_lcd_write(0, 0x50);     // VREG1
-    eos_lcd_write(1, 0x88);
-
-    eos_lcd_write(0, 0x51);     // VREG2
-    eos_lcd_write(1, 0x88);
-
-    eos_lcd_write(0, 0x52);     // flicker MSB
-    eos_lcd_write(1, 0x00);
-
-    eos_lcd_write(0, 0x53);     // flicker LSB
-    eos_lcd_write(1, 0x49);     // VCOM
-
-    eos_lcd_write(0, 0x55);     // flicker
-    eos_lcd_write(1, 0x49);
-
-    eos_lcd_write(0, 0x60);
-    eos_lcd_write(1, 0x07);
-
-    eos_lcd_write(0, 0x61);
-    eos_lcd_write(1, 0x00);
-
-    eos_lcd_write(0, 0x62);
-    eos_lcd_write(1, 0x07);
-
-    eos_lcd_write(0, 0x63);
-    eos_lcd_write(1, 0x00);
-
-    /* Gamma Setting */
-    eos_lcd_write(0, 0xA0);     // positive Gamma
-    eos_lcd_write(1, 0x00);
-
-    eos_lcd_write(0, 0xA1);
-    eos_lcd_write(1, 0x09);
-
-    eos_lcd_write(0, 0xA2);
-    eos_lcd_write(1, 0x11);
-
-    eos_lcd_write(0, 0xA3);
-    eos_lcd_write(1, 0x0B);
-
-    eos_lcd_write(0, 0xA4);
-    eos_lcd_write(1, 0x05);
-
-    eos_lcd_write(0, 0xA5);
-    eos_lcd_write(1, 0x08);
-
-    eos_lcd_write(0, 0xA6);
-    eos_lcd_write(1, 0x06);
-
-    eos_lcd_write(0, 0xA7);
-    eos_lcd_write(1, 0x04);
-
-    eos_lcd_write(0, 0xA8);
-    eos_lcd_write(1, 0x09);
-
-    eos_lcd_write(0, 0xA9);
-    eos_lcd_write(1, 0x0C);
-
-    eos_lcd_write(0, 0xAA);
-    eos_lcd_write(1, 0x15);
-
-    eos_lcd_write(0, 0xAB);
-    eos_lcd_write(1, 0x08);
-
-    eos_lcd_write(0, 0xAC);
-    eos_lcd_write(1, 0x0F);
-
-    eos_lcd_write(0, 0xAD);
-    eos_lcd_write(1, 0x12);
-
-    eos_lcd_write(0, 0xAE);
-    eos_lcd_write(1, 0x09);
-
-    eos_lcd_write(0, 0xAF);
-    eos_lcd_write(1, 0x00);
-
-    eos_lcd_write(0, 0xC0);     // negative Gamma
-    eos_lcd_write(1, 0x00);
-
-    eos_lcd_write(0, 0xC1);
-    eos_lcd_write(1, 0x09);
-
-    eos_lcd_write(0, 0xC2);
-    eos_lcd_write(1, 0x10);
-
-    eos_lcd_write(0, 0xC3);
-    eos_lcd_write(1, 0x0C);
-
-    eos_lcd_write(0, 0xC4);
-    eos_lcd_write(1, 0x05);
-
-    eos_lcd_write(0, 0xC5);
-    eos_lcd_write(1, 0x08);
-
-    eos_lcd_write(0, 0xC6);
-    eos_lcd_write(1, 0x06);
-
-    eos_lcd_write(0, 0xC7);
-    eos_lcd_write(1, 0x04);
-
-    eos_lcd_write(0, 0xC8);
-    eos_lcd_write(1, 0x08);
-
-    eos_lcd_write(0, 0xC9);
-    eos_lcd_write(1, 0x0C);
-
-    eos_lcd_write(0, 0xCA);
-    eos_lcd_write(1, 0x14);
-
-    eos_lcd_write(0, 0xCB);
-    eos_lcd_write(1, 0x08);
-
-    eos_lcd_write(0, 0xCC);
-    eos_lcd_write(1, 0x0F);
-
-    eos_lcd_write(0, 0xCD);
-    eos_lcd_write(1, 0x11);
-
-    eos_lcd_write(0, 0xCE);
-    eos_lcd_write(1, 0x09);
-
-    eos_lcd_write(0, 0xCF);
-    eos_lcd_write(1, 0x00);
-
-    eos_lcd_write(0, 0xFF);     // change to Page 6 CMD for GIP timing
-    eos_lcd_write(1, 0xFF);
-    eos_lcd_write(1, 0x98);
-    eos_lcd_write(1, 0x06);
-    eos_lcd_write(1, 0x04);
-    eos_lcd_write(1, 0x06);
-
-    eos_lcd_write(0, 0x00);
-    eos_lcd_write(1, 0x20);
-
-    eos_lcd_write(0, 0x01);
-    eos_lcd_write(1, 0x0A);
-
-    eos_lcd_write(0, 0x02);
-    eos_lcd_write(1, 0x00);
-
-    eos_lcd_write(0, 0x03);
-    eos_lcd_write(1, 0x00);
-
-    eos_lcd_write(0, 0x04);
-    eos_lcd_write(1, 0x01);
-
-    eos_lcd_write(0, 0x05);
-    eos_lcd_write(1, 0x01);
-
-    eos_lcd_write(0, 0x06);
-    eos_lcd_write(1, 0x98);
-
-    eos_lcd_write(0, 0x07);
-    eos_lcd_write(1, 0x06);
-
-    eos_lcd_write(0, 0x08);
-    eos_lcd_write(1, 0x01);
-
-    eos_lcd_write(0, 0x09);
-    eos_lcd_write(1, 0x80);
-
-    eos_lcd_write(0, 0x0A);
-    eos_lcd_write(1, 0x00);
-
-    eos_lcd_write(0, 0x0B);
-    eos_lcd_write(1, 0x00);
-
-    eos_lcd_write(0, 0x0C);
-    eos_lcd_write(1, 0x01);
-
-    eos_lcd_write(0, 0x0D);
-    eos_lcd_write(1, 0x01);
-
-    eos_lcd_write(0, 0x0E);
-    eos_lcd_write(1, 0x05);
-
-    eos_lcd_write(0, 0x0F);
-    eos_lcd_write(1, 0x00);
-
-    eos_lcd_write(0, 0x10);
-    eos_lcd_write(1, 0xF0);
-
-    eos_lcd_write(0, 0x11);
-    eos_lcd_write(1, 0xF4);
-
-    eos_lcd_write(0, 0x12);
-    eos_lcd_write(1, 0x01);
-
-    eos_lcd_write(0, 0x13);
-    eos_lcd_write(1, 0x00);
-
-    eos_lcd_write(0, 0x14);
-    eos_lcd_write(1, 0x00);
-
-    eos_lcd_write(0, 0x15);
-    eos_lcd_write(1, 0xC0);
-
-    eos_lcd_write(0, 0x16);
-    eos_lcd_write(1, 0x08);
-
-    eos_lcd_write(0, 0x17);
-    eos_lcd_write(1, 0x00);
-
-    eos_lcd_write(0, 0x18);
-    eos_lcd_write(1, 0x00);
-
-    eos_lcd_write(0, 0x19);
-    eos_lcd_write(1, 0x00);
-
-    eos_lcd_write(0, 0x1A);
-    eos_lcd_write(1, 0x00);
-
-    eos_lcd_write(0, 0x1B);
-    eos_lcd_write(1, 0x00);
-
-    eos_lcd_write(0, 0x1C);
-    eos_lcd_write(1, 0x00);
-
-    eos_lcd_write(0, 0x1D);
-    eos_lcd_write(1, 0x00);
-
-    eos_lcd_write(0, 0x20);
-    eos_lcd_write(1, 0x01);
-
-    eos_lcd_write(0, 0x21);
-    eos_lcd_write(1, 0x23);
-
-    eos_lcd_write(0, 0x22);
-    eos_lcd_write(1, 0x45);
-
-    eos_lcd_write(0, 0x23);
-    eos_lcd_write(1, 0x67);
-
-    eos_lcd_write(0, 0x24);
-    eos_lcd_write(1, 0x01);
-
-    eos_lcd_write(0, 0x25);
-    eos_lcd_write(1, 0x23);
-
-    eos_lcd_write(0, 0x26);
-    eos_lcd_write(1, 0x45);
-
-    eos_lcd_write(0, 0x27);
-    eos_lcd_write(1, 0x67);
-
-    eos_lcd_write(0, 0x30);
-    eos_lcd_write(1, 0x11);
-
-    eos_lcd_write(0, 0x31);
-    eos_lcd_write(1, 0x11);
-
-    eos_lcd_write(0, 0x32);
-    eos_lcd_write(1, 0x00);
-
-    eos_lcd_write(0, 0x33);
-    eos_lcd_write(1, 0xEE);
-
-    eos_lcd_write(0, 0x34);
-    eos_lcd_write(1, 0xFF);
-
-    eos_lcd_write(0, 0x35);
-    eos_lcd_write(1, 0xBB);
-
-    eos_lcd_write(0, 0x36);
-    eos_lcd_write(1, 0xAA);
-
-    eos_lcd_write(0, 0x37);
-    eos_lcd_write(1, 0xDD);
-
-    eos_lcd_write(0, 0x38);
-    eos_lcd_write(1, 0xCC);
-
-    eos_lcd_write(0, 0x39);
-    eos_lcd_write(1, 0x66);
-
-    eos_lcd_write(0, 0x3A);
-    eos_lcd_write(1, 0x77);
-
-    eos_lcd_write(0, 0x3B);
-    eos_lcd_write(1, 0x22);
-
-    eos_lcd_write(0, 0x3C);
-    eos_lcd_write(1, 0x22);
-
-    eos_lcd_write(0, 0x3D);
-    eos_lcd_write(1, 0x22);
-
-    eos_lcd_write(0, 0x3E);
-    eos_lcd_write(1, 0x22);
-
-    eos_lcd_write(0, 0x3F);
-    eos_lcd_write(1, 0x22);
-
-    eos_lcd_write(0, 0x40);
-    eos_lcd_write(1, 0x22);
-
-    eos_lcd_write(0, 0xFF);     // change to Page 7 CMD for GIP timing
-    eos_lcd_write(1, 0xFF);
-    eos_lcd_write(1, 0x98);
-    eos_lcd_write(1, 0x06);
-    eos_lcd_write(1, 0x04);
-    eos_lcd_write(1, 0x07);
-
-    eos_lcd_write(0, 0x17);
-    eos_lcd_write(1, 0x22);
-
-    eos_lcd_write(0, 0x02);
-    eos_lcd_write(1, 0x77);
-
-    eos_lcd_write(0, 0x26);
-    eos_lcd_write(1, 0xB2);
-
-    eos_lcd_write(0, 0xFF);     // change to Page 0 CMD for normal command
-    eos_lcd_write(1, 0xFF);
-    eos_lcd_write(1, 0x98);
-    eos_lcd_write(1, 0x06);
-    eos_lcd_write(1, 0x04);
-    eos_lcd_write(1, 0x00);
-
-    eos_lcd_write(0, 0x3A);
-    eos_lcd_write(1, 0x70);     // 24BIT
-
-    eos_lcd_write(0, 0x11);
-    eos_time_sleep(120);
-    eos_lcd_write(0, 0x29);
-    eos_time_sleep(25);
-
-    eos_lcd_cs_clear();
-    eos_lcd_deselect();
-
-    return EOS_OK;
-}
-
-int eos_lcd_init(uint8_t wakeup_cause) {
-    eos_spi_select(EOS_SPI_DEV_EVE);
-    eve_gpio_set(EVE_GPIO_LCD_EN, 1);
-    eos_spi_deselect();
-    eos_time_sleep(200);
-
-    return _init();
-}
-
-int eos_lcd_sleep(void) {
-    int rv;
-
-    rv = eos_lcd_select();
-    if (rv) return rv;
-
-    eos_lcd_cs_set();
-
-    eos_lcd_write(0, 0x28);
-    eos_time_sleep(10);
-    eos_lcd_write(0, 0x10);
-
-    eos_lcd_cs_clear();
-    eos_lcd_deselect();
-
-    eos_spi_select(EOS_SPI_DEV_EVE);
-    eve_gpio_set(EVE_GPIO_LCD_EN, 0);
-    eos_spi_deselect();
-
-    return EOS_OK;
-}
-
-int eos_lcd_wake(void) {
-    int rv;
-
-    eos_spi_select(EOS_SPI_DEV_EVE);
-    eve_gpio_set(EVE_GPIO_LCD_EN, 1);
-    eos_spi_deselect();
-    eos_time_sleep(200);
-
-    rv = eos_lcd_select();
-    if (rv) return rv;
-
-    eos_lcd_cs_set();
-
-    eos_lcd_write(0, 0x11);
-    eos_time_sleep(120);
-    eos_lcd_write(0, 0x29);
-
-    eos_lcd_cs_clear();
-    eos_lcd_deselect();
-
-    return EOS_OK;
-}
diff --git a/fw/fe310/eos/lcd.h b/fw/fe310/eos/lcd.h
deleted file mode 100644
index 1bcb2cd..0000000
--- a/fw/fe310/eos/lcd.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#include <stdint.h>
-
-int eos_lcd_init(uint8_t wakeup_cause);
-int eos_lcd_select(void);
-void eos_lcd_deselect(void);
-void eos_lcd_cs_set(void);
-void eos_lcd_cs_clear(void);
-void eos_lcd_write(uint8_t dc, uint8_t data);
-void eos_lcd_read(uint8_t *data);
-
-int eos_lcd_sleep(void);
-int eos_lcd_wake(void);
\ No newline at end of file
diff --git a/fw/fe310/eos/net.c b/fw/fe310/eos/net.c
deleted file mode 100644
index 33b71c2..0000000
--- a/fw/fe310/eos/net.c
+++ /dev/null
@@ -1,602 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-
-#include "encoding.h"
-#include "platform.h"
-
-#include "eos.h"
-#include "msgq.h"
-#include "interrupt.h"
-#include "event.h"
-#include "timer.h"
-#include "pwr.h"
-
-#include "board.h"
-
-#include "spi.h"
-#include "spi_priv.h"
-#include "spi_dev.h"
-
-#include "net.h"
-
-#define NET_SIZE_HDR            3
-#define NET_STATE_FLAG_RUN      0x01
-#define NET_STATE_FLAG_INIT     0x02
-#define NET_STATE_FLAG_XCHG     0x04
-#define NET_STATE_FLAG_ONEW     0x10
-#define NET_STATE_FLAG_SYNC     0x20
-#define NET_STATE_FLAG_RTS      0x40
-#define NET_STATE_FLAG_CTS      0x80
-
-#define MIN(X, Y)               (((X) < (Y)) ? (X) : (Y))
-#define MAX(X, Y)               (((X) > (Y)) ? (X) : (Y))
-
-static EOSBufQ net_buf_q;
-static unsigned char *net_bufq_array[EOS_NET_SIZE_BUFQ];
-static unsigned char net_bufq_buffer[EOS_NET_SIZE_BUFQ][EOS_NET_SIZE_BUF];
-
-static EOSMsgQ net_send_q;
-static EOSMsgItem net_sndq_array[EOS_NET_SIZE_BUFQ];
-
-static volatile uint8_t net_state_flags = 0;
-static unsigned char net_state_type = 0;
-static uint32_t net_state_len_tx = 0;
-static uint32_t net_state_len_rx = 0;
-unsigned char *net_state_buf = NULL;
-
-static uint8_t net_state_next_cnt = 0;
-static unsigned char *net_state_next_buf = NULL;
-
-static eos_evt_handler_t net_handler[EOS_NET_MAX_MTYPE];
-static uint16_t net_wrapper_acq[EOS_EVT_MAX_EVT];
-static uint16_t net_flags_acq[EOS_EVT_MAX_EVT];
-
-static int net_xchg_sleep(void) {
-    int i;
-    int rv = EOS_OK;
-    volatile uint32_t x = 0;
-    net_state_flags &= ~NET_STATE_FLAG_CTS;
-
-    SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD;
-
-    SPI1_REG(SPI_REG_TXFIFO) = 0xFF;
-    while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
-    if (x & 0xFF) rv = EOS_ERR_BUSY;
-
-    for (i=0; i<7; i++) {
-        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
-        SPI1_REG(SPI_REG_TXFIFO) = 0;
-        while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
-    }
-
-    SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO;
-
-    return rv;
-}
-
-static void net_xchg_wake(void) {
-    int i;
-    volatile uint32_t x = 0;
-    net_state_flags &= ~NET_STATE_FLAG_CTS;
-
-    SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD;
-
-    for (i=0; i<8; i++) {
-        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
-        SPI1_REG(SPI_REG_TXFIFO) = 0;
-        while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
-    }
-
-    SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO;
-}
-
-static void net_xchg_reset(void) {
-    volatile uint32_t x = 0;
-    net_state_flags &= ~NET_STATE_FLAG_CTS;
-
-    SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD;
-
-    SPI1_REG(SPI_REG_TXFIFO) = 0;
-    while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
-
-    SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO;
-}
-
-static void net_xchg_start(unsigned char type, unsigned char *buffer, uint16_t len) {
-    net_state_flags &= ~NET_STATE_FLAG_CTS;
-    net_state_flags |= (NET_STATE_FLAG_INIT | NET_STATE_FLAG_XCHG);
-
-    if (net_state_next_cnt && (net_state_next_buf == NULL)) type |= EOS_NET_MTYPE_FLAG_ONEW;
-    if (type & EOS_NET_MTYPE_FLAG_ONEW) net_state_flags |= NET_STATE_FLAG_ONEW;
-
-    net_state_type = type;
-    net_state_len_tx = len;
-    net_state_len_rx = 0;
-    net_state_buf = buffer;
-
-    SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD;
-    SPI1_REG(SPI_REG_TXFIFO) = type;
-    SPI1_REG(SPI_REG_TXFIFO) = (len >> 8) & 0xFF;
-    SPI1_REG(SPI_REG_TXFIFO) = (len & 0xFF);
-    SPI1_REG(SPI_REG_RXCTRL) = SPI_RXWM(2);
-    SPI1_REG(SPI_REG_IE) = SPI_IP_RXWM;
-}
-
-static int net_xchg_next(unsigned char *_buffer) {
-    unsigned char type;
-    unsigned char *buffer = NULL;
-    uint16_t len;
-    int ret = _buffer ? 1 : 0;
-
-    eos_msgq_pop(&net_send_q, &type, &buffer, &len);
-    if (type) {
-        net_xchg_start(type, buffer, len);
-    } else if (net_state_flags & NET_STATE_FLAG_RTS) {
-        if (_buffer) {
-            buffer = _buffer;
-            ret = 0;
-        } else {
-            buffer = eos_bufq_pop(&net_buf_q);
-        }
-        if (buffer) net_xchg_start(0, buffer, 0);
-    }
-
-    return ret;
-}
-
-static void net_handle_xchg(void) {
-    volatile uint32_t r1, r2, r3;
-    uint32_t len;
-
-    if (net_state_flags & NET_STATE_FLAG_INIT) {
-        net_state_flags &= ~NET_STATE_FLAG_INIT;
-
-        r1 = SPI1_REG(SPI_REG_RXFIFO);
-        r2 = SPI1_REG(SPI_REG_RXFIFO);
-        r3 = SPI1_REG(SPI_REG_RXFIFO);
-
-        if (net_state_flags & NET_STATE_FLAG_ONEW) {
-            r1 = 0;
-            r2 = 0;
-            r3 = 0;
-        }
-
-        net_state_type    = (r1 & 0xFF);
-        net_state_len_rx  = (r2 & 0xFF) << 8;
-        net_state_len_rx |= (r3 & 0xFF);
-        len = MAX(net_state_len_tx, net_state_len_rx);
-
-        if (len > EOS_NET_MTU) {
-            net_state_flags &= ~NET_STATE_FLAG_XCHG;
-            SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO;
-            SPI1_REG(SPI_REG_IE) = 0x0;
-            return;
-        }
-
-        // esp32 dma workaraund
-        if (len < 8 - NET_SIZE_HDR) {
-            len = 8 - NET_SIZE_HDR;
-        } else if ((len + NET_SIZE_HDR) % 4 != 0) {
-            len = ((len + NET_SIZE_HDR)/4 + 1) * 4 - NET_SIZE_HDR;
-        }
-
-        _eos_spi_xchg_init(net_state_buf, len, 0);
-        SPI1_REG(SPI_REG_TXCTRL) = SPI_TXWM(SPI_SIZE_WM);
-        SPI1_REG(SPI_REG_IE) = SPI_IP_TXWM;
-        return;
-    }
-
-    eos_spi_handle_xchg();
-    if (SPI1_REG(SPI_REG_CSMODE) == SPI_CSMODE_AUTO) {  // exchange done
-        if (!(net_state_flags & NET_STATE_FLAG_SYNC)) {
-            if (net_state_type) {
-                int r = eos_evtq_push_isr(EOS_EVT_NET | net_state_type, net_state_buf, net_state_len_rx);
-                if (r) eos_bufq_push(&net_buf_q, net_state_buf);
-            } else if (((net_state_flags & NET_STATE_FLAG_ONEW) || net_state_next_cnt) && (net_state_next_buf == NULL)) {
-                net_state_next_buf = net_state_buf;
-            } else {
-                eos_bufq_push(&net_buf_q, net_state_buf);
-            }
-        }
-        net_state_flags &= ~(NET_STATE_FLAG_ONEW | NET_STATE_FLAG_XCHG);
-    }
-}
-
-static void net_handle_cts(void) {
-    GPIO_REG(GPIO_RISE_IP) = (1 << NET_PIN_CTS);
-    net_state_flags |= NET_STATE_FLAG_CTS;
-
-    if (net_state_flags & NET_STATE_FLAG_RUN) {
-        net_xchg_next(NULL);
-    }
-}
-
-static void net_handle_rts(void) {
-    uint32_t rts_offset = (1 << NET_PIN_RTS);
-
-    if (GPIO_REG(GPIO_RISE_IP) & rts_offset) {
-        GPIO_REG(GPIO_RISE_IP) = rts_offset;
-        net_state_flags |= NET_STATE_FLAG_RTS;
-        if ((net_state_flags & NET_STATE_FLAG_RUN) && (net_state_flags & NET_STATE_FLAG_CTS)) {
-            net_xchg_reset();
-        }
-    } else if (GPIO_REG(GPIO_FALL_IP) & rts_offset) {
-        GPIO_REG(GPIO_FALL_IP) = rts_offset;
-        net_state_flags &= ~NET_STATE_FLAG_RTS;
-    }
-}
-
-static void net_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) {
-    unsigned char idx = (type & ~EOS_EVT_MASK) - 1;
-
-    if (idx < EOS_NET_MAX_MTYPE) {
-        net_handler[idx](type, buffer, len);
-    } else {
-        eos_net_bad_handler(type, buffer, len);
-    }
-}
-
-static int net_acquire(unsigned char reserved) {
-    int ret = 0;
-
-    if (reserved) {
-        while (!ret) {
-            clear_csr(mstatus, MSTATUS_MIE);
-            if (net_state_next_buf) {
-                ret = 1;
-                net_state_next_cnt--;
-            } else {
-                asm volatile ("wfi");
-            }
-            set_csr(mstatus, MSTATUS_MIE);
-        }
-    } else {
-        clear_csr(mstatus, MSTATUS_MIE);
-        if (net_state_next_buf == NULL) net_state_next_buf = eos_bufq_pop(&net_buf_q);
-        ret = (net_state_next_buf != NULL);
-        if (!ret) net_state_next_cnt++;
-        set_csr(mstatus, MSTATUS_MIE);
-    }
-    return ret;
-}
-
-static void evt_handler_wrapper(unsigned char type, unsigned char *buffer, uint16_t len, unsigned char idx, uint16_t flag) {
-    int ok;
-
-    ok = net_acquire(net_wrapper_acq[idx] & flag);
-    if (ok) {
-        eos_evtq_get_handler(type)(type, buffer, len);
-        eos_net_release();
-        net_wrapper_acq[idx] &= ~flag;
-    } else {
-        net_wrapper_acq[idx] |= flag;
-        eos_evtq_push(type, buffer, len);
-    }
-}
-
-static void evt_handler(unsigned char type, unsigned char *buffer, uint16_t len) {
-    unsigned char idx = (type & EOS_EVT_MASK) >> 4;
-
-    if (idx && (idx <= EOS_EVT_MAX_EVT)) {
-        uint16_t flag = (uint16_t)1 << (type & ~EOS_EVT_MASK);
-
-        idx--;
-        if (flag & net_flags_acq[idx]) {
-            evt_handler_wrapper(type, buffer, len, idx, flag);
-        } else {
-            eos_evtq_get_handler(type)(type, buffer, len);
-        }
-    } else {
-        eos_evtq_bad_handler(type, buffer, len);
-    }
-}
-
-static void net_pause(void) {
-    net_state_flags &= ~NET_STATE_FLAG_RUN;
-}
-
-static void net_resume(void) {
-    net_state_flags |= NET_STATE_FLAG_RUN;
-    if (net_state_flags & NET_STATE_FLAG_CTS) {
-        net_xchg_next(NULL);
-    }
-}
-
-static void net_start(void) {
-    eos_intr_set_handler(INT_SPI1_BASE, net_handle_xchg);
-    SPI1_REG(SPI_REG_SCKDIV) = eos_spi_div(EOS_SPI_DEV_NET);
-    SPI1_REG(SPI_REG_CSID) = eos_spi_csid(EOS_SPI_DEV_NET);
-}
-
-static void net_stop(void) {
-    eos_intr_set_handler(INT_SPI1_BASE, NULL);
-}
-
-int eos_net_init(uint8_t wakeup_cause) {
-    int i;
-
-    eos_msgq_init(&net_send_q, net_sndq_array, EOS_NET_SIZE_BUFQ);
-    eos_bufq_init(&net_buf_q, net_bufq_array, EOS_NET_SIZE_BUFQ);
-    for (i=0; i<EOS_NET_SIZE_BUFQ; i++) {
-        eos_bufq_push(&net_buf_q, net_bufq_buffer[i]);
-    }
-
-    for (i=0; i<EOS_NET_MAX_MTYPE; i++) {
-        net_handler[i] = eos_net_bad_handler;
-    }
-    eos_evtq_set_handler(0, evt_handler);
-    eos_evtq_set_handler(EOS_EVT_NET, net_handle_evt);
-
-    GPIO_REG(GPIO_INPUT_EN)     |=  (1 << NET_PIN_CTS);
-    GPIO_REG(GPIO_OUTPUT_EN)    &= ~(1 << NET_PIN_CTS);
-
-    GPIO_REG(GPIO_RISE_IE)      |=  (1 << NET_PIN_CTS);
-    eos_intr_set(INT_GPIO_BASE + NET_PIN_CTS, IRQ_PRIORITY_NET_CTS, net_handle_cts);
-
-    GPIO_REG(GPIO_INPUT_EN)     |=  (1 << NET_PIN_RTS);
-    GPIO_REG(GPIO_OUTPUT_EN)    &= ~(1 << NET_PIN_RTS);
-
-    GPIO_REG(GPIO_RISE_IE)      |=  (1 << NET_PIN_RTS);
-    GPIO_REG(GPIO_FALL_IE)      |=  (1 << NET_PIN_RTS);
-    eos_intr_set(INT_GPIO_BASE + NET_PIN_RTS, IRQ_PRIORITY_NET_RTS, net_handle_rts);
-
-    /* set initial state */
-    clear_csr(mstatus, MSTATUS_MIE);
-    if (GPIO_REG(GPIO_INPUT_VAL) & (1 << NET_PIN_CTS)) net_state_flags |= NET_STATE_FLAG_CTS;
-    if (GPIO_REG(GPIO_INPUT_VAL) & (1 << NET_PIN_RTS)) net_state_flags |= NET_STATE_FLAG_RTS;
-    set_csr(mstatus, MSTATUS_MIE);
-
-    return EOS_OK;
-}
-
-int eos_net_run(uint8_t wakeup_cause) {
-    net_start();
-
-    clear_csr(mstatus, MSTATUS_MIE);
-    if (wakeup_cause != EOS_PWR_WAKE_RST) {
-        if (wakeup_cause != EOS_PWR_WAKE_BTN) {
-            net_xchg_wake();
-        }
-        if (!(net_state_flags & NET_STATE_FLAG_CTS)) {
-            while (!(GPIO_REG(GPIO_RISE_IP) & (1 << NET_PIN_CTS))) {
-                asm volatile ("wfi");
-            }
-            GPIO_REG(GPIO_RISE_IP) = (1 << NET_PIN_CTS);
-        }
-        net_xchg_reset();
-    }
-    net_resume();
-    set_csr(mstatus, MSTATUS_MIE);
-
-    return EOS_OK;
-}
-
-void eos_net_start(void) {
-    net_start();
-
-    clear_csr(mstatus, MSTATUS_MIE);
-    net_resume();
-    set_csr(mstatus, MSTATUS_MIE);
-}
-
-void eos_net_stop(void) {
-    uint8_t done = 0;
-
-    clear_csr(mstatus, MSTATUS_MIE);
-    if (net_state_flags & NET_STATE_FLAG_RUN) {
-        net_state_flags &= ~NET_STATE_FLAG_RUN;
-        done = !(net_state_flags & NET_STATE_FLAG_XCHG);
-    } else {
-        done = 1;
-    }
-    set_csr(mstatus, MSTATUS_MIE);
-
-    while (!done) {
-        clear_csr(mstatus, MSTATUS_MIE);
-        done = !(net_state_flags & NET_STATE_FLAG_XCHG);
-        if (!done) asm volatile ("wfi");
-        set_csr(mstatus, MSTATUS_MIE);
-    }
-    net_stop();
-}
-
-int eos_net_sleep(uint32_t timeout) {
-    volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME);
-    uint64_t then_ms = timeout + *mtime * 1000 / EOS_TIMER_RTC_FREQ;
-    uint8_t done = 0;
-    int rv = EOS_OK;
-
-    clear_csr(mstatus, MSTATUS_MIE);
-    if (!(net_state_flags & NET_STATE_FLAG_RUN)) rv = EOS_ERR;
-    set_csr(mstatus, MSTATUS_MIE);
-
-    if (rv) return rv;
-
-    do {
-        if (*mtime * 1000 / EOS_TIMER_RTC_FREQ > then_ms) return EOS_ERR_TIMEOUT;
-        clear_csr(mstatus, MSTATUS_MIE);
-        eos_evtq_flush_isr();
-        done = (eos_msgq_len(&net_send_q) == 0);
-        done = done && (!(net_state_flags & NET_STATE_FLAG_RTS) && (net_state_flags & NET_STATE_FLAG_CTS));
-        if (done) done = (net_xchg_sleep() == EOS_OK);
-        if (!done) {
-            asm volatile ("wfi");
-            set_csr(mstatus, MSTATUS_MIE);
-        }
-    } while (!done);
-
-    while (!(GPIO_REG(GPIO_RISE_IP) & (1 << NET_PIN_CTS))) {
-        if (*mtime * 1000 / EOS_TIMER_RTC_FREQ > then_ms) {
-            rv = EOS_ERR_TIMEOUT;
-            break;
-        }
-        asm volatile ("wfi");
-    }
-
-    if (!rv) {
-        GPIO_REG(GPIO_RISE_IP) = (1 << NET_PIN_CTS);
-        net_state_flags &= ~NET_STATE_FLAG_RUN;
-    }
-
-    set_csr(mstatus, MSTATUS_MIE);
-
-    return rv;
-}
-
-void eos_net_bad_handler(unsigned char type, unsigned char *buffer, uint16_t len) {
-    eos_evtq_bad_handler(type, buffer, len);
-    if (buffer) eos_net_free(buffer, 0);
-}
-
-void eos_net_set_handler(unsigned char mtype, eos_evt_handler_t handler) {
-    if (handler == NULL) handler = eos_net_bad_handler;
-    if (mtype && (mtype <= EOS_NET_MAX_MTYPE)) net_handler[mtype - 1] = handler;
-}
-
-void eos_net_acquire_for_evt(unsigned char type, char acq) {
-    unsigned char idx = (type & EOS_EVT_MASK) >> 4;
-    uint16_t flag = type & ~EOS_EVT_MASK ? (uint16_t)1 << (type & ~EOS_EVT_MASK) : 0xFFFF;
-
-    if (idx && (idx <= EOS_EVT_MAX_EVT)) {
-        idx--;
-        net_flags_acq[idx] &= ~flag;
-        if (acq) net_flags_acq[idx] |= flag;
-    }
-}
-
-void eos_net_acquire(void) {
-    unsigned char acq = net_acquire(0);
-    if (!acq) net_acquire(1);
-}
-
-void eos_net_release(void) {
-    clear_csr(mstatus, MSTATUS_MIE);
-    if (!net_state_next_cnt && net_state_next_buf) {
-        eos_bufq_push(&net_buf_q, net_state_next_buf);
-        net_state_next_buf = NULL;
-    }
-    set_csr(mstatus, MSTATUS_MIE);
-}
-
-unsigned char *eos_net_alloc(void) {
-    unsigned char *ret = NULL;
-
-    while (!ret) {
-        clear_csr(mstatus, MSTATUS_MIE);
-        if (net_state_next_buf) {
-            ret = net_state_next_buf;
-            net_state_next_buf = NULL;
-        } else {
-            asm volatile ("wfi");
-        }
-        set_csr(mstatus, MSTATUS_MIE);
-    }
-
-    return ret;
-}
-
-void eos_net_free(unsigned char *buffer, unsigned char more) {
-    uint8_t do_release = 1;
-
-    clear_csr(mstatus, MSTATUS_MIE);
-    if ((more || net_state_next_cnt) && (net_state_next_buf == NULL)) {
-        net_state_next_buf = buffer;
-    } else {
-        if ((net_state_flags & NET_STATE_FLAG_RUN) && (net_state_flags & NET_STATE_FLAG_CTS)) {
-            do_release = net_xchg_next(buffer);
-        }
-        if (do_release) {
-            eos_bufq_push(&net_buf_q, buffer);
-        }
-    }
-    set_csr(mstatus, MSTATUS_MIE);
-}
-
-static int net_xchg(unsigned char *type, unsigned char *buffer, uint16_t *len, unsigned char flags) {
-    int rv = EOS_OK;
-    int _sync = 0;
-    unsigned char _type = *type;
-    uint16_t _len = *len;
-    uint8_t spi_dev = EOS_SPI_DEV_NET;
-
-    if (flags & EOS_NET_FLAG_ONEW) _type |= EOS_NET_MTYPE_FLAG_ONEW;
-    if (flags & EOS_NET_FLAG_REPL) _type |= EOS_NET_MTYPE_FLAG_REPL;
-    if (flags & EOS_NET_FLAG_SYNC) _sync = 1;
-
-    clear_csr(mstatus, MSTATUS_MIE);
-    if ((flags & EOS_NET_FLAG_ONEW) && !(net_state_flags & NET_STATE_FLAG_RUN)) _sync = 1;
-
-    if (_sync && !(net_state_flags & NET_STATE_FLAG_RUN)) {
-        int _rv;
-
-        set_csr(mstatus, MSTATUS_MIE);
-        spi_dev = eos_spi_dev();
-        _rv = eos_spi_deselect();
-        if (_rv) return _rv;
-        clear_csr(mstatus, MSTATUS_MIE);
-    }
-
-    if (_sync) {
-        net_pause();
-        while (!(net_state_flags & NET_STATE_FLAG_CTS)) {
-            asm volatile ("wfi");
-            set_csr(mstatus, MSTATUS_MIE);
-            clear_csr(mstatus, MSTATUS_MIE);
-        }
-        if (flags & EOS_NET_FLAG_SYNC) {
-            net_state_flags |= NET_STATE_FLAG_SYNC;
-        }
-        net_xchg_start(_type, buffer, _len);
-        if (flags & EOS_NET_FLAG_SYNC) {
-            if (flags & EOS_NET_FLAG_REPL) {
-                while (!(net_state_flags & NET_STATE_FLAG_CTS)) {
-                    asm volatile ("wfi");
-                    set_csr(mstatus, MSTATUS_MIE);
-                    clear_csr(mstatus, MSTATUS_MIE);
-                }
-                net_xchg_start(0, buffer, 0);
-            }
-            while (net_state_flags & NET_STATE_FLAG_XCHG) {
-                asm volatile ("wfi");
-                set_csr(mstatus, MSTATUS_MIE);
-                clear_csr(mstatus, MSTATUS_MIE);
-            }
-            net_state_flags &= ~NET_STATE_FLAG_SYNC;
-            *type = net_state_type;
-            *len = net_state_len_rx;
-        }
-        net_resume();
-    } else {
-        if ((net_state_flags & NET_STATE_FLAG_RUN) && (net_state_flags & NET_STATE_FLAG_CTS)) {
-            net_xchg_start(_type, buffer, _len);
-        } else {
-            rv = eos_msgq_push(&net_send_q, _type, buffer, _len);
-            if (rv) eos_bufq_push(&net_buf_q, buffer);
-        }
-    }
-
-    set_csr(mstatus, MSTATUS_MIE);
-    if (spi_dev != EOS_SPI_DEV_NET) eos_spi_select(spi_dev);
-
-    return rv;
-}
-
-int eos_net_xchg(unsigned char *type, unsigned char *buffer, uint16_t *len) {
-    return net_xchg(type, buffer, len, (EOS_NET_FLAG_ONEW | EOS_NET_FLAG_SYNC | EOS_NET_FLAG_REPL));
-}
-
-int eos_net_send(unsigned char type, unsigned char *buffer, uint16_t len) {
-    return net_xchg(&type, buffer, &len, (EOS_NET_FLAG_ONEW | EOS_NET_FLAG_SYNC));
-}
-
-int eos_net_send_async(unsigned char type, unsigned char *buffer, uint16_t len, unsigned char more) {
-    return net_xchg(&type, buffer, &len, more ? EOS_NET_FLAG_ONEW : 0);
-}
-
-int _eos_net_send(unsigned char type, unsigned char *buffer, uint16_t len, unsigned char async, unsigned char more) {
-    if (async) {
-        eos_net_send_async(type, buffer, len, more);
-    } else {
-        eos_net_send(type, buffer, len);
-    }
-}
diff --git a/fw/fe310/eos/net.h b/fw/fe310/eos/net.h
deleted file mode 100644
index 79caf4b..0000000
--- a/fw/fe310/eos/net.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#include <stdint.h>
-#include "event.h"
-
-/* common */
-#define EOS_NET_MTU                 1500
-#define EOS_NET_SIZE_BUF            EOS_NET_MTU
-
-#define EOS_NET_MTYPE_SOCK          1
-#define EOS_NET_MTYPE_RNG         	3
-#define EOS_NET_MTYPE_POWER         4
-
-#define EOS_NET_MTYPE_WIFI          5
-#define EOS_NET_MTYPE_CELL          6
-#define EOS_NET_MTYPE_SIP           7
-#define EOS_NET_MTYPE_APP           8
-
-#define EOS_NET_MAX_MTYPE           8
-
-#define EOS_NET_MTYPE_FLAG_ONEW     0x40
-#define EOS_NET_MTYPE_FLAG_REPL     0x80
-#define EOS_NET_MTYPE_FLAG_MASK     0xc0
-
-/* fe310 specific */
-#define EOS_NET_SIZE_BUFQ           2
-
-#define EOS_NET_FLAG_ONEW           0x1
-#define EOS_NET_FLAG_SYNC           0x2
-#define EOS_NET_FLAG_REPL           0x4
-
-int eos_net_init(uint8_t wakeup_cause);
-int eos_net_run(uint8_t wakeup_cause);
-void eos_net_start(void);
-void eos_net_stop(void);
-int eos_net_sleep(uint32_t timeout);
-
-void eos_net_bad_handler(unsigned char type, unsigned char *buffer, uint16_t len);
-void eos_net_set_handler(unsigned char type, eos_evt_handler_t handler);
-void eos_net_acquire_for_evt(unsigned char type, char acq);
-
-void eos_net_acquire(void);
-void eos_net_release(void);
-unsigned char *eos_net_alloc(void);
-void eos_net_free(unsigned char *buffer, unsigned char more);
-int eos_net_xchg(unsigned char *type, unsigned char *buffer, uint16_t *len);
-int eos_net_send(unsigned char type, unsigned char *buffer, uint16_t len);
-int eos_net_send_async(unsigned char type, unsigned char *buffer, uint16_t len, unsigned char more);
-int _eos_net_send(unsigned char type, unsigned char *buffer, uint16_t len, unsigned char async, unsigned char more);
diff --git a/fw/fe310/eos/net/cell.c b/fw/fe310/eos/net/cell.c
new file mode 100644
index 0000000..20a9f42
--- /dev/null
+++ b/fw/fe310/eos/net/cell.c
@@ -0,0 +1,51 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "eos.h"
+#include "event.h"
+#include "net.h"
+
+#include "cell.h"
+
+static eos_evt_handler_t evt_handler[EOS_CELL_MAX_MTYPE];
+
+static void cell_handle_msg(unsigned char type, unsigned char *buffer, uint16_t len) {
+    unsigned char mtype;
+    unsigned char idx;
+
+    if ((buffer == NULL) || (len < 1)) {
+        eos_net_bad_handler(type, buffer, len);
+        return;
+    }
+
+    mtype = buffer[0];
+    idx = (mtype & EOS_CELL_MTYPE_MASK) >> 4;
+    if ((idx < EOS_CELL_MAX_MTYPE) && evt_handler[idx]) {
+        evt_handler[idx](mtype & ~EOS_CELL_MTYPE_MASK, buffer, len);
+    } else {
+        eos_net_bad_handler(type, buffer, len);
+    }
+}
+
+void eos_cell_netinit(void) {
+    int i;
+
+    for (i=0; i<EOS_CELL_MAX_MTYPE; i++) {
+        evt_handler[i] = NULL;
+    }
+    eos_net_set_handler(EOS_NET_MTYPE_CELL, cell_handle_msg);
+}
+
+void eos_cell_set_handler(unsigned char mtype, eos_evt_handler_t handler) {
+    unsigned char idx = (mtype & EOS_CELL_MTYPE_MASK) >> 4;
+
+    if (idx < EOS_CELL_MAX_MTYPE) evt_handler[idx] = handler;
+}
+
+eos_evt_handler_t eos_cell_get_handler(unsigned char mtype) {
+    unsigned char idx = (mtype & EOS_CELL_MTYPE_MASK) >> 4;
+
+    if (idx < EOS_CELL_MAX_MTYPE) return evt_handler[idx];
+    return NULL;
+}
diff --git a/fw/fe310/eos/net/cell.h b/fw/fe310/eos/net/cell.h
new file mode 100644
index 0000000..b01d4cf
--- /dev/null
+++ b/fw/fe310/eos/net/cell.h
@@ -0,0 +1,51 @@
+#include <stdint.h>
+#include "event.h"
+
+#define EOS_CELL_MTYPE_DEV              0x10
+#define EOS_CELL_MTYPE_VOICE            0x20
+#define EOS_CELL_MTYPE_SMS              0x30
+#define EOS_CELL_MTYPE_CBS              0x40
+#define EOS_CELL_MTYPE_USSD             0x50
+#define EOS_CELL_MTYPE_PDP              0x60
+
+#define EOS_CELL_MTYPE_MASK             0xf0
+#define EOS_CELL_MAX_MTYPE              8
+
+/* EOS_CELL_MTYPE_DEV subtypes */
+#define EOS_CELL_MTYPE_READY            1
+#define EOS_CELL_MTYPE_UART_DATA        2
+#define EOS_CELL_MTYPE_UART_TAKE        3
+#define EOS_CELL_MTYPE_UART_GIVE        4
+#define EOS_CELL_MTYPE_RESET            5
+
+#define EOS_CELL_MTYPE_VOICE_PCM        1
+#define EOS_CELL_MTYPE_VOICE_DIAL       2
+#define EOS_CELL_MTYPE_VOICE_RING       3
+#define EOS_CELL_MTYPE_VOICE_ANSWER     4
+#define EOS_CELL_MTYPE_VOICE_HANGUP     5
+#define EOS_CELL_MTYPE_VOICE_BEGIN      6
+#define EOS_CELL_MTYPE_VOICE_END        7
+#define EOS_CELL_MTYPE_VOICE_MISS       8
+#define EOS_CELL_MTYPE_VOICE_BUSY       9
+#define EOS_CELL_MTYPE_VOICE_ERR        10
+
+#define EOS_CELL_MTYPE_SMS_LIST         1
+#define EOS_CELL_MTYPE_SMS_SEND         2
+#define EOS_CELL_MTYPE_SMS_MSG_NEW      3
+#define EOS_CELL_MTYPE_SMS_MSG_ITEM     4
+
+#define EOS_CELL_MTYPE_USSD_REQUEST     1
+#define EOS_CELL_MTYPE_USSD_REPLY       2
+#define EOS_CELL_MTYPE_USSD_CANCEL      3
+
+#define EOS_CELL_MTYPE_PDP_CONFIG       1
+#define EOS_CELL_MTYPE_PDP_CONNECT      2
+#define EOS_CELL_MTYPE_PDP_DISCONNECT   3
+
+#define EOS_CELL_SMS_ADDRTYPE_INTL      1
+#define EOS_CELL_SMS_ADDRTYPE_ALPHA     2
+#define EOS_CELL_SMS_ADDRTYPE_OTHER     3
+
+void eos_cell_netinit(void);
+void eos_cell_set_handler(unsigned char mtype, eos_evt_handler_t handler);
+eos_evt_handler_t eos_cell_get_handler(unsigned char mtype);
\ No newline at end of file
diff --git a/fw/fe310/eos/net/rng.c b/fw/fe310/eos/net/rng.c
new file mode 100644
index 0000000..317941d
--- /dev/null
+++ b/fw/fe310/eos/net/rng.c
@@ -0,0 +1,27 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "net.h"
+
+int getentropy(unsigned char *b, size_t sz) {
+    unsigned char type;
+    unsigned char *buffer;
+    uint16_t len;
+    int rv;
+
+    buffer = eos_net_alloc();
+
+    type = EOS_NET_MTYPE_RNG;
+    len = sizeof(uint16_t);
+    buffer[0] = sz >> 8;
+    buffer[1] = sz;
+
+    rv = eos_net_xchg(&type, buffer, &len);
+    if (rv || (len != sz)) rv = -1;
+
+    if (!rv) memcpy(b, buffer, sz);
+    eos_net_free(buffer, 1);
+
+    return rv;
+}
diff --git a/fw/fe310/eos/net/rng.h b/fw/fe310/eos/net/rng.h
new file mode 100644
index 0000000..27bbf74
--- /dev/null
+++ b/fw/fe310/eos/net/rng.h
@@ -0,0 +1,5 @@
+#include <stdlib.h>
+
+int getentropy(unsigned char *b, size_t sz);
+int arc4random_alloc(void **rsp, size_t rsp_size, void **rsxp, size_t rsxp_size);
+void arc4random_close(void **rsp, void **rsxp);
\ No newline at end of file
diff --git a/fw/fe310/eos/net/sock.c b/fw/fe310/eos/net/sock.c
new file mode 100644
index 0000000..7365c97
--- /dev/null
+++ b/fw/fe310/eos/net/sock.c
@@ -0,0 +1,154 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "eos.h"
+#include "event.h"
+#include "net.h"
+
+#include "sock.h"
+
+static eos_evt_handler_t evt_handler[EOS_SOCK_MAX_SOCK];
+
+static void sock_handle_msg(unsigned char type, unsigned char *buffer, uint16_t len) {
+    unsigned char sock;
+
+    if ((buffer == NULL) || (len < 2)) {
+        eos_net_bad_handler(type, buffer, len);
+        return;
+    }
+
+    sock = buffer[1];
+    if ((sock == 0) || (sock > EOS_SOCK_MAX_SOCK) || (evt_handler[sock - 1] == NULL)) {
+        eos_net_bad_handler(type, buffer, len);
+        return;
+    }
+
+    switch(buffer[0]) {
+        case EOS_SOCK_MTYPE_PKT:
+            evt_handler[sock - 1](type, buffer, len);
+            break;
+        default:
+            eos_net_bad_handler(type, buffer, len);
+            break;
+    }
+}
+
+void eos_sock_netinit(void) {
+    int i;
+
+    for (i=0; i<EOS_SOCK_MAX_SOCK; i++) {
+        evt_handler[i] = NULL;
+    }
+    eos_net_set_handler(EOS_NET_MTYPE_SOCK, sock_handle_msg);
+}
+
+void eos_sock_set_handler(unsigned char sock, eos_evt_handler_t handler) {
+    if (sock && (sock <= EOS_SOCK_MAX_SOCK)) evt_handler[sock - 1] = handler;
+}
+
+eos_evt_handler_t eos_sock_get_handler(unsigned char sock) {
+    if (sock && (sock <= EOS_SOCK_MAX_SOCK)) return evt_handler[sock - 1];
+    return NULL;
+}
+
+int eos_sock_open_udp(eos_evt_handler_t handler, unsigned char *buffer) {
+    unsigned char type;
+    uint16_t len;
+    int do_release;
+    int rv, sock;
+
+    do_release = 0;
+    if (buffer == NULL) {
+        buffer = eos_net_alloc();
+        do_release = 1;
+    }
+
+    type = EOS_NET_MTYPE_SOCK;
+    len = 1;
+    buffer[0] = EOS_SOCK_MTYPE_OPEN_DGRAM;
+
+    rv = eos_net_xchg(&type, buffer, &len);
+    if (rv) return rv;
+
+    if (type != EOS_NET_MTYPE_SOCK) return EOS_ERR_NET;
+    if (len < 2) return EOS_ERR_SIZE;
+
+    sock = buffer[1];
+    if (sock == 0) return EOS_ERR_NET;
+
+    if (do_release) {
+        eos_net_free(buffer, 1);
+    }
+    eos_sock_set_handler(sock, handler);
+
+    return sock;
+}
+
+void eos_sock_close(unsigned char sock, unsigned char *buffer) {
+    int async;
+
+    async = 0;
+    if (buffer == NULL) {
+        buffer = eos_net_alloc();
+        async = 1;
+    }
+    buffer[0] = EOS_SOCK_MTYPE_CLOSE;
+    buffer[1] = sock;
+    _eos_net_send(EOS_NET_MTYPE_SOCK, buffer, 2, async, 1);
+    eos_sock_set_handler(sock, NULL);
+}
+
+static int sock_send(unsigned char sock, unsigned char *msg, uint16_t msg_len, EOSNetAddr *addr, unsigned char *buffer) {
+    buffer[0] = EOS_SOCK_MTYPE_PKT;
+    buffer[1] = sock;
+    buffer += 2;
+    memcpy(buffer, addr->host, sizeof(addr->host));
+    buffer += sizeof(addr->host);
+    buffer[0] = addr->port >> 8;
+    buffer[1] = addr->port;
+    buffer += sizeof(addr->port);
+    if (msg) {
+        if (msg_len + EOS_SOCK_SIZE_UDP_HDR > EOS_NET_MTU) return EOS_ERR_SIZE;
+        memcpy(buffer, msg, msg_len);
+    }
+
+    return EOS_OK;
+}
+
+int eos_sock_sendto(unsigned char sock, unsigned char *msg, size_t msg_len, EOSNetAddr *addr, unsigned char *buffer) {
+    int rv;
+
+    rv = sock_send(sock, msg, msg_len, addr, buffer);
+    if (rv) return rv;
+
+    return eos_net_send(EOS_NET_MTYPE_SOCK, buffer, msg_len + EOS_SOCK_SIZE_UDP_HDR);
+}
+
+int eos_sock_sendto_async(unsigned char sock, unsigned char *msg, size_t msg_len, EOSNetAddr *addr, unsigned char *buffer, unsigned char more) {
+    int rv;
+
+    rv = sock_send(sock, msg, msg_len, addr, buffer);
+    if (rv) return rv;
+
+    return eos_net_send_async(EOS_NET_MTYPE_SOCK, buffer, msg_len + EOS_SOCK_SIZE_UDP_HDR, more);
+}
+
+int eos_sock_recvfrom(unsigned char *buffer, uint16_t len, unsigned char *msg, size_t msg_size, EOSNetAddr *addr) {
+    if (len < EOS_SOCK_SIZE_UDP_HDR) return EOS_ERR_SIZE;
+
+    if (buffer[0] != EOS_SOCK_MTYPE_PKT) return EOS_ERR_NET;
+
+    buffer += 2;
+    memcpy(addr->host, buffer, sizeof(addr->host));
+    buffer += sizeof(addr->host);
+    addr->port  = (uint16_t)buffer[0] << 8;
+    addr->port |= (uint16_t)buffer[1];
+    buffer += sizeof(addr->port);
+    if (msg) {
+        if (msg_size < len - EOS_SOCK_SIZE_UDP_HDR) return EOS_ERR_SIZE;
+        memcpy(msg, buffer, len - EOS_SOCK_SIZE_UDP_HDR);
+    }
+
+    return EOS_OK;
+}
diff --git a/fw/fe310/eos/net/sock.h b/fw/fe310/eos/net/sock.h
new file mode 100644
index 0000000..5ef42e3
--- /dev/null
+++ b/fw/fe310/eos/net/sock.h
@@ -0,0 +1,28 @@
+#include <stdint.h>
+#include "event.h"
+
+#define EOS_SOCK_MTYPE_PKT          0
+#define EOS_SOCK_MTYPE_OPEN_DGRAM   1
+#define EOS_SOCK_MTYPE_CLOSE        127
+
+#define EOS_SOCK_MAX_SOCK           2
+
+#define EOS_SOCK_SIZE_UDP_HDR       8
+
+#define EOS_IPv4_ADDR_SIZE          4
+
+typedef struct EOSNetAddr {
+    unsigned char host[EOS_IPv4_ADDR_SIZE];
+    uint16_t port;
+} EOSNetAddr;
+
+void eos_sock_netinit(void);
+void eos_sock_set_handler(unsigned char sock, eos_evt_handler_t handler);
+eos_evt_handler_t eos_sock_get_handler(unsigned char sock);
+
+int eos_sock_open_udp(eos_evt_handler_t handler, unsigned char *buffer);
+void eos_sock_close(unsigned char sock, unsigned char *buffer);
+
+int eos_sock_sendto(unsigned char sock, unsigned char *msg, size_t msg_len, EOSNetAddr *addr, unsigned char *buffer);
+int eos_sock_sendto_async(unsigned char sock, unsigned char *msg, size_t msg_len, EOSNetAddr *addr, unsigned char *buffer, unsigned char more);
+int eos_sock_recvfrom(unsigned char *buffer, uint16_t len, unsigned char *msg, size_t msg_size, EOSNetAddr *addr);
diff --git a/fw/fe310/eos/net/wifi.c b/fw/fe310/eos/net/wifi.c
new file mode 100644
index 0000000..0663582
--- /dev/null
+++ b/fw/fe310/eos/net/wifi.c
@@ -0,0 +1,106 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "eos.h"
+#include "event.h"
+#include "net.h"
+
+#include "wifi.h"
+
+static eos_evt_handler_t evt_handler[EOS_WIFI_MAX_MTYPE];
+
+static void wifi_handle_msg(unsigned char type, unsigned char *buffer, uint16_t len) {
+    unsigned char mtype;
+
+    if ((buffer == NULL) || (len < 1)) {
+        eos_net_bad_handler(type, buffer, len);
+        return;
+    }
+
+    mtype = buffer[0];
+    if ((mtype < EOS_WIFI_MAX_MTYPE) && evt_handler[mtype]) {
+        evt_handler[mtype](mtype, buffer, len);
+    } else {
+        eos_net_bad_handler(type, buffer, len);
+    }
+}
+
+void eos_wifi_netinit(void) {
+    int i;
+
+    for (i=0; i<EOS_WIFI_MAX_MTYPE; i++) {
+        evt_handler[i] = NULL;
+    }
+    eos_net_set_handler(EOS_NET_MTYPE_WIFI, wifi_handle_msg);
+}
+
+void eos_wifi_set_handler(unsigned char mtype, eos_evt_handler_t handler) {
+    if (mtype < EOS_WIFI_MAX_MTYPE) evt_handler[mtype] = handler;
+}
+
+eos_evt_handler_t eos_wifi_get_handler(unsigned char mtype) {
+    if (mtype < EOS_WIFI_MAX_MTYPE) return evt_handler[mtype];
+    return NULL;
+}
+
+int eos_wifi_scan(unsigned char *buffer) {
+    int async;
+
+    async = 0;
+    if (buffer == NULL) {
+        buffer = eos_net_alloc();
+        async = 1;
+    }
+    buffer[0] = EOS_WIFI_MTYPE_SCAN;
+    return _eos_net_send(EOS_NET_MTYPE_WIFI, buffer, 1, async, 1);
+}
+
+int eos_wifi_auth(const char *ssid, const char *pass, unsigned char *buffer) {
+    unsigned char *buf;
+    size_t ssid_len, pass_len;
+    int async;
+
+    async = 0;
+    if (buffer == NULL) {
+        buffer = eos_net_alloc();
+        async = 1;
+    }
+    ssid_len = strlen(ssid) + 1;
+    pass_len = strlen(pass) + 1;
+    if ((1 + ssid_len + pass_len) > EOS_NET_MTU) return EOS_ERR_SIZE;
+
+    buf = buffer;
+    buf[0] = EOS_WIFI_MTYPE_AUTH;
+    buf++;
+    strcpy(buf, ssid);
+    buf += ssid_len;
+    strcpy(buf, pass);
+    buf += pass_len;
+
+    return _eos_net_send(EOS_NET_MTYPE_WIFI, buffer, 1 + ssid_len + pass_len, async, 1);
+}
+
+int eos_wifi_connect(unsigned char *buffer) {
+    int async;
+
+    async = 0;
+    if (buffer == NULL) {
+        buffer = eos_net_alloc();
+        async = 1;
+    }
+    buffer[0] = EOS_WIFI_MTYPE_CONNECT;
+    return _eos_net_send(EOS_NET_MTYPE_WIFI, buffer, 1, async, 1);
+}
+
+int eos_wifi_disconnect(unsigned char *buffer) {
+    int async;
+
+    async = 0;
+    if (buffer == NULL) {
+        buffer = eos_net_alloc();
+        async = 1;
+    }
+    buffer[0] = EOS_WIFI_MTYPE_DISCONNECT;
+    return _eos_net_send(EOS_NET_MTYPE_WIFI, buffer, 1, async, 1);
+}
diff --git a/fw/fe310/eos/net/wifi.h b/fw/fe310/eos/net/wifi.h
new file mode 100644
index 0000000..4a49518
--- /dev/null
+++ b/fw/fe310/eos/net/wifi.h
@@ -0,0 +1,18 @@
+#include <stdint.h>
+#include "event.h"
+
+#define EOS_WIFI_MTYPE_SCAN         1
+#define EOS_WIFI_MTYPE_AUTH         2
+#define EOS_WIFI_MTYPE_CONNECT      3
+#define EOS_WIFI_MTYPE_DISCONNECT   4
+
+#define EOS_WIFI_MAX_MTYPE          5
+
+void eos_wifi_netinit(void);
+void eos_wifi_set_handler(unsigned char mtype, eos_evt_handler_t handler);
+eos_evt_handler_t eos_wifi_get_handler(unsigned char mtype);
+
+int eos_wifi_scan(unsigned char *buffer);
+int eos_wifi_auth(const char *ssid, const char *pass, unsigned char *buffer);
+int eos_wifi_connect(unsigned char *buffer);
+int eos_wifi_disconnect(unsigned char *buffer);
diff --git a/fw/fe310/eos/pwr.c b/fw/fe310/eos/pwr.c
deleted file mode 100644
index 802e593..0000000
--- a/fw/fe310/eos/pwr.c
+++ /dev/null
@@ -1,133 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-
-#include "encoding.h"
-#include "platform.h"
-
-#include "eos.h"
-#include "event.h"
-#include "timer.h"
-#include "spi.h"
-#include "spi_dev.h"
-#include "net.h"
-#include "lcd.h"
-#include "eve/eve.h"
-
-#include "pwr.h"
-
-#define PWR_RTC_SCALE   15
-#define PWR_RTC_SFREQ   (EOS_TIMER_RTC_FREQ >> PWR_RTC_SCALE)
-
-static eos_evt_handler_t evt_handler[EOS_PWR_MAX_MTYPE];
-static unsigned char power_btn_down;
-
-int eos_pwr_init(uint8_t wakeup_cause) {
-    AON_REG(AON_PMUKEY) = 0x51F15E;
-    AON_REG(AON_PMUIE) = 0x5;
-
-    AON_REG(AON_RTCCMP) = 0xFFFFFFFF;
-    AON_REG(AON_RTCCFG) = PWR_RTC_SCALE;
-    AON_REG(AON_RTCHI) = 0;
-    AON_REG(AON_RTCLO) = 0;
-
-    return EOS_OK;
-}
-
-uint8_t eos_pwr_wakeup_cause(void) {
-    return AON_REG(AON_PMUCAUSE) & 0xff;
-}
-
-uint8_t eos_pwr_reset_cause(void) {
-    return (AON_REG(AON_PMUCAUSE) >> 8) & 0xff;
-}
-
-int eos_pwr_sleep(void) {
-    int rv;
-
-    rv = eos_lcd_sleep();
-    if (rv) return rv;
-
-    eos_spi_select(EOS_SPI_DEV_EVE);
-    eve_pwr_sleep();
-    eos_spi_deselect();
-
-    rv = eos_net_sleep(1000);
-    if (rv) return rv;
-
-    AON_REG(AON_PMUKEY) = 0x51F15E;
-    AON_REG(AON_PMUSLEEP) = 1;
-
-    return EOS_OK;
-}
-
-void eos_pwr_wake_at(uint32_t msec) {
-    uint32_t pmuie;
-
-    AON_REG(AON_RTCCFG) |= AON_RTCCFG_ENALWAYS;
-    AON_REG(AON_RTCCMP) = msec * PWR_RTC_SFREQ / 1000;
-
-    pmuie = AON_REG(AON_PMUIE) | 0x2;
-    AON_REG(AON_PMUKEY) = 0x51F15E;
-    AON_REG(AON_PMUIE) = pmuie;
-}
-
-void eos_pwr_wake_disable(void) {
-    uint32_t pmuie;
-
-    AON_REG(AON_RTCCMP) = 0xFFFFFFFF;
-    AON_REG(AON_RTCCFG) &= ~AON_RTCCFG_ENALWAYS;
-    AON_REG(AON_RTCHI) = 0;
-    AON_REG(AON_RTCLO) = 0;
-
-    pmuie = AON_REG(AON_PMUIE) & ~0x2;
-    AON_REG(AON_PMUKEY) = 0x51F15E;
-    AON_REG(AON_PMUIE) = pmuie;
-}
-
-static void pwr_handle_msg(unsigned char type, unsigned char *buffer, uint16_t len) {
-    unsigned char mtype;
-
-    if ((buffer == NULL) || (len < 1)) {
-        eos_net_bad_handler(type, buffer, len);
-        return;
-    }
-
-    mtype = buffer[0];
-    if ((mtype < EOS_PWR_MAX_MTYPE) && evt_handler[mtype]) {
-        evt_handler[mtype](mtype, buffer, len);
-    } else {
-        eos_net_bad_handler(type, buffer, len);
-    }
-}
-
-static void pwr_handle_btn(unsigned char type, unsigned char *buffer, uint16_t len) {
-    unsigned char level = buffer[1];
-
-    eos_net_free(buffer, 0);
-    if (!level) {
-        power_btn_down = 1;
-        return;
-    }
-    if (!power_btn_down) return;
-
-    eos_pwr_sleep();
-}
-
-void eos_pwr_netinit(void) {
-    int i;
-
-    for (i=0; i<EOS_PWR_MAX_MTYPE; i++) {
-        evt_handler[i] = NULL;
-    }
-    eos_net_set_handler(EOS_NET_MTYPE_POWER, pwr_handle_msg);
-    eos_pwr_set_handler(EOS_PWR_MTYPE_BUTTON, pwr_handle_btn);
-}
-
-void eos_pwr_set_handler(unsigned char mtype, eos_evt_handler_t handler) {
-    if (mtype < EOS_PWR_MAX_MTYPE) evt_handler[mtype] = handler;
-}
-
-eos_evt_handler_t eos_pwr_get_handler(unsigned char mtype) {
-    if (mtype < EOS_PWR_MAX_MTYPE) return evt_handler[mtype];
-    return NULL;
-}
diff --git a/fw/fe310/eos/pwr.h b/fw/fe310/eos/pwr.h
deleted file mode 100644
index 264436b..0000000
--- a/fw/fe310/eos/pwr.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#include <stdint.h>
-#include "event.h"
-
-#define EOS_PWR_MTYPE_BUTTON    1
-
-#define EOS_PWR_MAX_MTYPE       2
-
-#define EOS_PWR_WAKE_RST        0
-#define EOS_PWR_WAKE_RTC        1
-#define EOS_PWR_WAKE_BTN        2
-
-#define EOS_PWR_RST_PWRON       0
-#define EOS_PWR_RST_EXT         1
-#define EOS_PWR_RST_WDOG        2
-
-int eos_pwr_init(uint8_t wakeup_cause);
-uint8_t eos_pwr_wakeup_cause(void);
-uint8_t eos_pwr_reset_cause(void);
-int eos_pwr_sleep(void);
-void eos_pwr_wake_at(uint32_t msec);
-void eos_pwr_wake_disable(void);
-
-void eos_pwr_netinit(void);
-void eos_pwr_set_handler(unsigned char mtype, eos_evt_handler_t handler);
-eos_evt_handler_t eos_pwr_get_handler(unsigned char mtype);
\ No newline at end of file
diff --git a/fw/fe310/eos/rng.c b/fw/fe310/eos/rng.c
deleted file mode 100644
index 317941d..0000000
--- a/fw/fe310/eos/rng.c
+++ /dev/null
@@ -1,27 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-
-#include "net.h"
-
-int getentropy(unsigned char *b, size_t sz) {
-    unsigned char type;
-    unsigned char *buffer;
-    uint16_t len;
-    int rv;
-
-    buffer = eos_net_alloc();
-
-    type = EOS_NET_MTYPE_RNG;
-    len = sizeof(uint16_t);
-    buffer[0] = sz >> 8;
-    buffer[1] = sz;
-
-    rv = eos_net_xchg(&type, buffer, &len);
-    if (rv || (len != sz)) rv = -1;
-
-    if (!rv) memcpy(b, buffer, sz);
-    eos_net_free(buffer, 1);
-
-    return rv;
-}
diff --git a/fw/fe310/eos/rng.h b/fw/fe310/eos/rng.h
deleted file mode 100644
index 27bbf74..0000000
--- a/fw/fe310/eos/rng.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#include <stdlib.h>
-
-int getentropy(unsigned char *b, size_t sz);
-int arc4random_alloc(void **rsp, size_t rsp_size, void **rsxp, size_t rsxp_size);
-void arc4random_close(void **rsp, void **rsxp);
\ No newline at end of file
diff --git a/fw/fe310/eos/sdc_crypto.c b/fw/fe310/eos/sdc_crypto.c
deleted file mode 100644
index f0e935d..0000000
--- a/fw/fe310/eos/sdc_crypto.c
+++ /dev/null
@@ -1,51 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-
-#include "sha/sha1.h"
-#include "sdc_crypto.h"
-
-#define SDC_CRYPTO_KEY_SIZE     16
-#define SDC_CRYPTO_BLK_SIZE     16
-#define SDC_CRYPTO_HASH_SIZE    20
-
-EOSSDCCrypto *sdc_crypto;
-
-void eos_sdcc_init(EOSSDCCrypto *crypto, uint8_t *key, void *ctx, eve_sdcc_init_t init, eve_sdcc_crypt_t enc, eve_sdcc_crypt_t dec, void *ctx_essiv, eve_sdcc_init_t init_essiv, eve_sdcc_essiv_t enc_essiv) {
-    char key_essiv[SDC_CRYPTO_HASH_SIZE];
-
-    sdc_crypto = crypto;
-
-    memset(key_essiv, 0, SDC_CRYPTO_HASH_SIZE);
-    init(ctx, key);
-    sdc_crypto->ctx = ctx;
-    sdc_crypto->enc = enc;
-    sdc_crypto->dec = dec;
-
-    SHA1(key_essiv, key, SDC_CRYPTO_KEY_SIZE);
-    init_essiv(ctx_essiv, key_essiv);
-    sdc_crypto->ctx_essiv = ctx_essiv;
-    sdc_crypto->enc_essiv = enc_essiv;
-}
-
-void eos_sdcc_encrypt(uint32_t sect, uint8_t *buffer) {
-    uint8_t iv[SDC_CRYPTO_BLK_SIZE];
-
-    if (sdc_crypto == NULL) return;
-
-    memset(iv, 0, SDC_CRYPTO_BLK_SIZE);
-    memcpy(iv, &sect, sizeof(sect));
-    sdc_crypto->enc_essiv(sdc_crypto->ctx_essiv, iv);
-    sdc_crypto->enc(sdc_crypto->ctx, iv, buffer, 512);
-}
-
-void eos_sdcc_decrypt(uint32_t sect, uint8_t *buffer) {
-    uint8_t iv[SDC_CRYPTO_BLK_SIZE];
-
-    if (sdc_crypto == NULL) return;
-
-    memset(iv, 0, SDC_CRYPTO_BLK_SIZE);
-    memcpy(iv, &sect, sizeof(sect));
-    sdc_crypto->enc_essiv(sdc_crypto->ctx_essiv, iv);
-    sdc_crypto->dec(sdc_crypto->ctx, iv, buffer, 512);
-}
diff --git a/fw/fe310/eos/sdc_crypto.h b/fw/fe310/eos/sdc_crypto.h
deleted file mode 100644
index 015bf8a..0000000
--- a/fw/fe310/eos/sdc_crypto.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#include <stddef.h>
-#include <stdint.h>
-
-typedef void (*eve_sdcc_init_t) (void *, uint8_t *);
-typedef void (*eve_sdcc_crypt_t) (void *, uint8_t *, uint8_t *, size_t);
-typedef void (*eve_sdcc_essiv_t) (void *, uint8_t *);
-
-typedef struct EOSSDCCrypto {
-    void *ctx;
-    eve_sdcc_crypt_t enc;
-    eve_sdcc_crypt_t dec;
-    void *ctx_essiv;
-    eve_sdcc_essiv_t enc_essiv;
-} EOSSDCCrypto;
-
-void eos_sdcc_init(EOSSDCCrypto *crypto, uint8_t *key, void *ctx, eve_sdcc_init_t init, eve_sdcc_crypt_t enc, eve_sdcc_crypt_t dec, void *ctx_essiv, eve_sdcc_init_t init_essiv, eve_sdcc_essiv_t enc_essiv);
-void eos_sdcc_encrypt(uint32_t sect, uint8_t *buffer);
-void eos_sdcc_decrypt(uint32_t sect, uint8_t *buffer);
\ No newline at end of file
diff --git a/fw/fe310/eos/sdcard.c b/fw/fe310/eos/sdcard.c
deleted file mode 100644
index d081388..0000000
--- a/fw/fe310/eos/sdcard.c
+++ /dev/null
@@ -1,539 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdio.h>
-
-#include "eos.h"
-#include "timer.h"
-
-#include "spi.h"
-#include "spi_dev.h"
-
-#include "sdc_crypto.h"
-#include "sdcard.h"
-
-#define SDC_TIMEOUT_CMD         500
-#define SDC_TIMEOUT_READ        200
-#define SDC_TIMEOUT_WRITE       500
-
-#define SDC_POLY_CRC7           0x09
-#define SDC_POLY_CRC16          0x1021
-
-#define SDC_CMD_FLAG_CRC        0x01
-#define SDC_CMD_FLAG_NOCS       0x02
-#define SDC_CMD_FLAG_NOWAIT     0x04
-#define SDC_CMD_FLAG_RSTUFF     0x08
-
-#define SDC_TOKEN_START_BLK     0xfe
-#define SDC_TOKEN_START_BLKM    0xfc
-#define SDC_TOKEN_STOP_TRAN     0xfd
-
-#define SDC_DRESP_MASK          0x1f
-#define SDC_DRESP_ACCEPT        0x05
-#define SDC_DRESP_ERR_CRC       0x0b
-#define SDC_DRESP_ERR_WRITE     0x0d
-
-#define SDC_R1_READY            0x00
-
-#define SDC_R1_IDLE_STATE       0x01
-#define SDC_R1_ERASE_RESET      0x02
-#define SDC_R1_ILLEGAL_CMD      0x04
-#define SDC_R1_ERR_CMD_CRC      0x08
-#define SDC_R1_ERR_ERASE_SEQ    0x10
-#define SDC_R1_ERR_ADDR         0x20
-#define SDC_R1_ERR_PARAM        0x40
-
-#define SDC_NCR                 10
-
-#define SDC_ERR(rv)             ((rv < 0) ? rv : EOS_ERR)
-
-/* CMD */
-#define GO_IDLE_STATE           0
-#define SEND_OP_COND            1
-#define SEND_IF_COND            8
-#define SEND_CSD                9
-#define STOP_TRANSMISSION       12
-#define SET_BLOCKLEN            16
-#define READ_SINGLE_BLOCK       17
-#define READ_MULTIPLE_BLOCK     18
-#define WRITE_BLOCK             24
-#define WRITE_MULTIPLE_BLOCK    25
-#define ERASE_WR_BLK_START      32
-#define ERASE_WR_BLK_END        33
-#define ERASE                   38
-#define APP_CMD                 55
-#define READ_OCR                58
-
-/* ACMD */
-#define SD_STATUS               13
-#define SET_WR_BLK_ERASE_COUNT  23
-#define SD_APP_OP_COND          41
-
-static uint8_t sdc_type = 0;
-
-static uint8_t sdc_crc7(uint8_t crc, uint8_t b) {
-    int i;
-
-    for (i=8; i--; b<<=1) {
-        crc <<= 1;
-        if ((b ^ crc) & 0x80) crc ^= SDC_POLY_CRC7;
-    }
-    return crc & 0x7f;
-}
-
-static uint16_t sdc_crc16(uint16_t crc, uint8_t b) {
-    int i;
-
-    crc = crc ^ ((uint16_t)b << 8);
-    for (i=8; i--;) {
-        if (crc & 0x8000) {
-            crc = (crc << 1) ^ SDC_POLY_CRC16;
-        } else {
-            crc <<= 1;
-        }
-    }
-    return crc;
-}
-
-static uint32_t sdc_nto(uint32_t start, uint32_t timeout) {
-    uint32_t d = eos_time_delta_ms(start);
-    return (d > timeout) ? 0 : timeout - d;
-}
-
-static uint8_t sdc_xchg8(uint8_t data) {
-    return eos_spi_xchg8(data, 0);
-}
-
-static uint16_t sdc_xchg16(uint16_t data) {
-    return eos_spi_xchg16(data, 0);
-}
-
-static uint32_t sdc_xchg32(uint32_t data) {
-    return eos_spi_xchg32(data, 0);
-}
-
-static void sdc_buf_send(unsigned char *buffer, uint16_t len) {
-    int i;
-
-    for (i=0; i<len; i++) {
-        sdc_xchg8(buffer[i]);
-    }
-}
-
-static void sdc_buf_recv(unsigned char *buffer, uint16_t len) {
-    int i;
-
-    for (i=0; i<len; i++) {
-        buffer[i] = sdc_xchg8(0xff);
-    }
-}
-
-static void sdc_select(void) {
-    eos_spi_cs_set();
-    eos_spi_xchg8(0xff, 0);
-}
-
-static void sdc_deselect(void) {
-    eos_spi_cs_clear();
-    eos_spi_xchg8(0xff, 0);
-}
-
-static int sdc_xchg_cmd(uint8_t cmd, uint32_t arg, uint8_t flags) {
-    int i;
-    uint8_t ret;
-    uint8_t crc = 0x7f;
-
-    cmd |= 0x40;
-    if (flags & SDC_CMD_FLAG_CRC) {
-        crc = sdc_crc7(0, cmd);
-        crc = sdc_crc7(crc, arg >> 24);
-        crc = sdc_crc7(crc, arg >> 16);
-        crc = sdc_crc7(crc, arg >> 8);
-        crc = sdc_crc7(crc, arg);
-    }
-    crc = (crc << 1) | 0x01;
-    sdc_xchg8(cmd);
-    sdc_xchg32(arg);
-    sdc_xchg8(crc);
-    if (flags & SDC_CMD_FLAG_RSTUFF) sdc_xchg8(0xff);
-
-    i = SDC_NCR;
-    do {
-        ret = sdc_xchg8(0xff);
-    } while ((ret & 0x80) && --i);
-    if (ret & 0x80) return EOS_ERR_BUSY;
-
-    return ret;
-}
-
-static int sdc_ready(uint32_t timeout) {
-    uint8_t d = 0;
-    uint32_t start;
-
-    if (timeout == 0) return EOS_ERR_BUSY;
-    start = eos_time_get_tick();
-    do {
-        if (eos_time_delta_ms(start) > timeout) break;
-        d = sdc_xchg8(0xff);
-    } while (d != 0xff);
-    if (d != 0xff) return EOS_ERR_BUSY;
-
-    return EOS_OK;
-}
-
-static int sdc_block_read(uint8_t *buffer, uint16_t len, uint32_t timeout) {
-    uint8_t token = 0xff;
-    uint32_t start;
-
-    if (timeout == 0) return EOS_ERR_BUSY;
-    start = eos_time_get_tick();
-    do {
-        if (eos_time_delta_ms(start) > timeout) break;
-        token = sdc_xchg8(0xff);
-    } while (token == 0xff);
-    if (token == 0xff) return EOS_ERR_BUSY;
-    if (token != SDC_TOKEN_START_BLK) return EOS_ERR;
-
-    sdc_buf_recv(buffer, len);
-    sdc_xchg16(0xffff); /* dummy CRC */
-
-    return EOS_OK;
-}
-
-static int sdc_block_write(uint8_t token, uint8_t *buffer, uint16_t len, uint32_t timeout) {
-    uint8_t d;
-    int rv;
-
-    rv = sdc_ready(timeout);
-    if (rv) return rv;
-
-    sdc_xchg8(token);
-    if (buffer && len) {
-        sdc_buf_send(buffer, len);
-        sdc_xchg16(0xffff); /* dummy CRC */
-
-        d = sdc_xchg8(0xff); /* Response */
-        if ((d & SDC_DRESP_MASK) != SDC_DRESP_ACCEPT) return EOS_ERR;
-    }
-
-    return EOS_OK;
-}
-
-static int sdc_cmd(uint8_t cmd, uint32_t arg, uint8_t flags, uint32_t timeout) {
-    int do_cs = !(flags & SDC_CMD_FLAG_NOCS);
-    int do_wait = !(flags & SDC_CMD_FLAG_NOWAIT);
-    int rv = EOS_OK;
-
-    if (do_cs) sdc_select();
-    if (do_wait) rv = sdc_ready(timeout);
-    if (rv) {
-        if (do_cs) sdc_deselect();
-        return rv;
-    }
-    rv = sdc_xchg_cmd(cmd, arg, flags);
-    if (do_cs) sdc_deselect();
-    return rv;
-}
-
-static int sdc_acmd(uint8_t cmd, uint32_t arg, uint8_t flags, uint32_t timeout) {
-    int rv;
-    uint32_t start;
-
-    start = eos_time_get_tick();
-    rv = sdc_cmd(APP_CMD, 0, flags, timeout);
-    if (rv & ~SDC_R1_IDLE_STATE) return rv;
-
-    if (flags & SDC_CMD_FLAG_NOCS) {
-        sdc_deselect();
-        sdc_select();
-    }
-    return sdc_cmd(cmd, arg, flags, sdc_nto(start, timeout));
-}
-
-static int sdc_init(uint32_t timeout) {
-    int rv, i;
-    uint8_t _type;
-    uint8_t ocr[4];
-    uint32_t start;
-    start = eos_time_get_tick();
-
-    eos_time_sleep(100);
-    for (i=10; i--;) sdc_xchg8(0xff);     /* 80 dummy cycles */
-
-    rv = sdc_cmd(GO_IDLE_STATE, 0, SDC_CMD_FLAG_CRC, SDC_TIMEOUT_CMD);
-    if (rv != SDC_R1_IDLE_STATE) return SDC_ERR(rv);
-
-    sdc_select();
-    rv = sdc_cmd(SEND_IF_COND, 0x1aa, SDC_CMD_FLAG_CRC | SDC_CMD_FLAG_NOCS, sdc_nto(start, timeout));
-    switch (rv) {
-        case SDC_R1_IDLE_STATE:
-            for (i=0; i<4; i++) {   /* R7 response */
-                ocr[i] = sdc_xchg8(0xff);
-            }
-            sdc_deselect();
-            if (ocr[2] == 0x01 && ocr[3] == 0xaa) {     /* Check voltage range: 2.7-3.6V */
-                do {
-                    rv = sdc_acmd(SD_APP_OP_COND, 0x40000000, 0, sdc_nto(start, timeout));
-                } while (rv == SDC_R1_IDLE_STATE);
-                if (rv != SDC_R1_READY) return SDC_ERR(rv);
-
-                sdc_select();
-                rv = sdc_cmd(READ_OCR, 0, SDC_CMD_FLAG_NOCS, sdc_nto(start, timeout));
-                if (rv == SDC_R1_READY) {
-                    for (i=0; i<4; i++) {   /* R7 response */
-                        ocr[i] = sdc_xchg8(0xff);
-                    }
-                    sdc_deselect();
-                } else {
-                    sdc_deselect();
-                    return SDC_ERR(rv);
-                }
-
-                _type = EOS_SDC_TYPE_SDC2;
-                if (ocr[0] & 0xc0) _type |= EOS_SDC_CAP_BLK;
-            }
-            break;
-
-        case SDC_R1_IDLE_STATE | SDC_R1_ILLEGAL_CMD:
-            sdc_deselect();
-            rv = sdc_acmd(SD_APP_OP_COND, 0, 0, sdc_nto(start, timeout));
-            switch (rv) {
-                case SDC_R1_IDLE_STATE:
-                    do  {
-                        rv = sdc_acmd(SD_APP_OP_COND, 0, 0, sdc_nto(start, timeout));
-                    } while (rv == SDC_R1_IDLE_STATE);
-                    if (rv != SDC_R1_READY) return SDC_ERR(rv);
-                case SDC_R1_READY:
-                    _type = EOS_SDC_TYPE_SDC1;
-                    break;
-
-                default:
-                    do {
-                        rv = sdc_cmd(SEND_OP_COND, 0, 0, sdc_nto(start, timeout));
-                    } while (rv == SDC_R1_IDLE_STATE);
-                    if (rv != SDC_R1_READY) return SDC_ERR(rv);
-                    _type = EOS_SDC_TYPE_MMC;
-                    break;
-
-            }
-            break;
-
-        default:
-            sdc_deselect();
-            return SDC_ERR(rv);
-    }
-
-    if (!(_type & EOS_SDC_CAP_BLK)) {
-        rv = sdc_cmd(SET_BLOCKLEN, 512, 0, sdc_nto(start, timeout));
-        if (rv != SDC_R1_READY) return SDC_ERR(rv);
-    }
-
-    if (_type & EOS_SDC_TYPE_SDC) {
-        uint8_t csd[16];
-
-        sdc_select();
-        rv = sdc_cmd(SEND_CSD, 0, SDC_CMD_FLAG_NOCS, sdc_nto(start, timeout));
-        if (rv == SDC_R1_READY) {
-            rv = sdc_block_read(csd, 16, sdc_nto(start, timeout));
-        } else {
-            rv = SDC_ERR(rv);
-        }
-        sdc_deselect();
-        if (rv) return rv;
-
-        for (i=0; i<16; i++) {
-            printf("%.2x ", csd[i]);
-        }
-        printf("\n");
-        if (csd[10] & 0x40) _type |= EOS_SDC_CAP_ERASE_EN;
-    }
-
-    eos_spi_set_div(EOS_SPI_DEV_SDC, 5);
-    sdc_type = _type;
-    return EOS_OK;
-}
-
-int eos_sdc_init(uint8_t wakeup_cause) {
-    int rv;
-
-    eos_spi_select(EOS_SPI_DEV_SDC);
-    rv = sdc_init(5000);
-    if (rv) {
-        printf("SDC ERROR\n");
-    } else {
-        printf("SDC OK:%x\n", sdc_type);
-    }
-    eos_spi_deselect();
-
-    return EOS_OK;
-}
-
-uint8_t eos_sdc_type(void) {
-    return sdc_type & EOS_SDC_TYPE_MASK;
-}
-
-uint8_t eos_sdc_cap(void) {
-    return sdc_type & EOS_SDC_CAP_MASK;
-}
-
-int eos_sdc_get_sect_count(uint32_t timeout, uint32_t *sectors) {
-    int rv;
-    uint8_t csd[16];
-    uint32_t start = eos_time_get_tick();
-
-    sdc_select();
-    rv = sdc_cmd(SEND_CSD, 0, SDC_CMD_FLAG_NOCS, timeout);
-    if (rv == SDC_R1_READY) {
-        rv = sdc_block_read(csd, 16, sdc_nto(start, timeout));
-    } else {
-        rv = SDC_ERR(rv);
-    }
-    sdc_deselect();
-    if (rv) return rv;
-
-    if ((csd[0] >> 6) == 1) {   /* SDCv2 */
-        *sectors = (csd[9] + (csd[8] << 8) + ((csd[7] & 0x3f) << 16) + 1) << 10;
-    } else {                    /* SDCv1 or MMC*/
-        uint8_t n = (csd[5] & 0x0f) + (csd[10] >> 7) + ((csd[9] & 0x03) << 1) + 2;
-        *sectors = (csd[8] >> 6) + (csd[7] << 2) + ((csd[6] & 0x03) << 10) + 1;
-        *sectors = *sectors << (n - 9);
-    }
-
-    return EOS_OK;
-}
-
-int eos_sdc_get_blk_size(uint32_t timeout, uint32_t *size) {
-    int rv;
-    uint8_t rbl[64];    /* SD Status or CSD register */
-    uint32_t start = eos_time_get_tick();
-
-    sdc_select();
-    if (sdc_type & EOS_SDC_TYPE_SDC2) {
-        rv = sdc_acmd(SD_STATUS, 0, SDC_CMD_FLAG_NOCS, timeout);
-        sdc_xchg8(0xff);    /* R2 response */
-    } else {
-        rv = sdc_cmd(SEND_CSD, 0, SDC_CMD_FLAG_NOCS, timeout);
-    }
-    if (rv == SDC_R1_READY) {
-        rv = sdc_block_read(rbl, (sdc_type & EOS_SDC_TYPE_SDC2) ? 64 : 16, sdc_nto(start, timeout));
-    } else {
-        rv = SDC_ERR(rv);
-    }
-    sdc_deselect();
-    if (rv) return rv;
-
-    if (sdc_type & EOS_SDC_TYPE_SDC2) {
-        *size = 16UL << (rbl[10] >> 4);
-    } else if (sdc_type & EOS_SDC_TYPE_SDC1) {
-        *size = (((rbl[10] & 0x3f) << 1) + (rbl[11] >> 7) + 1) << ((rbl[13] >> 6) - 1);
-    } else {
-        *size = (((rbl[10] & 0x7c) >> 2) + 1) * (((rbl[11] & 0x03) << 3) + (rbl[11] >> 5) + 1);
-    }
-
-    return EOS_OK;
-}
-
-int eos_sdc_sync(uint32_t timeout) {
-    int rv;
-
-    sdc_select();
-    rv = sdc_ready(timeout);
-    sdc_deselect();
-
-    return rv;
-}
-
-int eos_sdc_erase(uint32_t blk_start, uint32_t blk_end, uint32_t timeout) {
-    int rv;
-    uint32_t start;
-
-    if (!(sdc_type & EOS_SDC_TYPE_SDC)) return EOS_ERR;
-    if (!(sdc_type & EOS_SDC_CAP_ERASE_EN)) return EOS_ERR;
-    if (!(sdc_type & EOS_SDC_CAP_BLK)) {
-        blk_start *= 512;
-        blk_end *= 512;
-    }
-
-    start = eos_time_get_tick();
-    rv = sdc_cmd(ERASE_WR_BLK_START, blk_start, 0, timeout);
-    if (rv != SDC_R1_READY) return SDC_ERR(rv);
-
-    rv = sdc_cmd(ERASE_WR_BLK_END, blk_end, 0, sdc_nto(start, timeout));
-    if (rv != SDC_R1_READY) return SDC_ERR(rv);
-
-    rv = sdc_cmd(ERASE, 0, 0, sdc_nto(start, timeout));
-    if (rv != SDC_R1_READY) return SDC_ERR(rv);
-
-    return eos_sdc_sync(sdc_nto(start, timeout));
-}
-
-int eos_sdc_sect_read(uint32_t sect, unsigned int count, uint8_t *buffer) {
-    int rv;
-    uint8_t cmd = ((count == 1) ? READ_SINGLE_BLOCK : READ_MULTIPLE_BLOCK);
-
-    if (!(sdc_type & EOS_SDC_CAP_BLK)) sect *= 512;
-
-    sdc_select();
-    rv = sdc_cmd(cmd, sect, SDC_CMD_FLAG_NOCS, SDC_TIMEOUT_CMD);
-    if (rv == SDC_R1_READY) {
-        int _rv = SDC_R1_READY;
-
-        while (count) {
-            rv = sdc_block_read(buffer, 512, SDC_TIMEOUT_READ);
-            if (rv) break;
-            eos_sdcc_decrypt(sect, buffer);
-            buffer += 512;
-            count--;
-        }
-        if (cmd == READ_MULTIPLE_BLOCK) _rv = sdc_cmd(STOP_TRANSMISSION, 0, SDC_CMD_FLAG_NOCS | SDC_CMD_FLAG_NOWAIT | SDC_CMD_FLAG_RSTUFF, 0);
-        if (!rv && (_rv != SDC_R1_READY)) rv = SDC_ERR(_rv);
-    } else {
-        rv = SDC_ERR(rv);
-    }
-    sdc_deselect();
-
-    return rv;
-}
-
-int eos_sdc_sect_write(uint32_t sect, unsigned int count, uint8_t *buffer) {
-    int rv;
-
-    if (!(sdc_type & EOS_SDC_CAP_BLK)) sect *= 512;
-
-    if (count == 1) {
-        sdc_select();
-        rv = sdc_cmd(WRITE_BLOCK, sect, SDC_CMD_FLAG_NOCS, SDC_TIMEOUT_CMD);
-        if (rv == SDC_R1_READY) {
-            eos_sdcc_encrypt(sect, buffer);
-            rv = sdc_block_write(SDC_TOKEN_START_BLK, buffer, 512, SDC_TIMEOUT_WRITE);
-        } else {
-            rv = SDC_ERR(rv);
-        }
-        sdc_deselect();
-    } else {
-        if (sdc_type & EOS_SDC_TYPE_SDC) {
-            rv = sdc_acmd(SET_WR_BLK_ERASE_COUNT, count, 0, SDC_TIMEOUT_CMD);
-            if (rv != SDC_R1_READY) return SDC_ERR(rv);
-        }
-
-        sdc_select();
-        rv = sdc_cmd(WRITE_MULTIPLE_BLOCK, sect, SDC_CMD_FLAG_NOCS, SDC_TIMEOUT_CMD);
-        if (rv == SDC_R1_READY) {
-            int _rv;
-
-            while (count) {
-                eos_sdcc_encrypt(sect, buffer);
-                rv = sdc_block_write(SDC_TOKEN_START_BLKM, buffer, 512, SDC_TIMEOUT_WRITE);
-                if (rv) break;
-                buffer += 512;
-                count--;
-            }
-            _rv = sdc_block_write(SDC_TOKEN_STOP_TRAN, NULL, 0, SDC_TIMEOUT_WRITE);
-            if (!rv && (_rv != SDC_R1_READY)) rv = SDC_ERR(_rv);
-        } else {
-            rv = SDC_ERR(rv);
-        }
-        sdc_deselect();
-    }
-
-    return rv;
-}
diff --git a/fw/fe310/eos/sdcard.h b/fw/fe310/eos/sdcard.h
deleted file mode 100644
index 910a6e0..0000000
--- a/fw/fe310/eos/sdcard.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#include <stdint.h>
-
-#define EOS_SDC_TYPE_MMC            0x01
-
-#define EOS_SDC_TYPE_SDC1           0x04
-#define EOS_SDC_TYPE_SDC2           0x08
-#define EOS_SDC_TYPE_SDC            0x0c
-#define EOS_SDC_TYPE_MASK           0x0f
-
-#define EOS_SDC_CAP_BLK             0x10
-#define EOS_SDC_CAP_ERASE_EN        0x20
-#define EOS_SDC_CAP_MASK            0xf0
-
-int eos_sdc_init(uint8_t wakeup_cause);
-uint8_t eos_sdc_type(void);
-uint8_t eos_sdc_cap(void);
-int eos_sdc_get_sect_count(uint32_t timeout, uint32_t *sectors);
-int eos_sdc_get_blk_size(uint32_t timeout, uint32_t *size);
-int eos_sdc_sync(uint32_t timeout);
-int eos_sdc_erase(uint32_t blk_start, uint32_t blk_end, uint32_t timeout);
-int eos_sdc_sect_read(uint32_t sect, unsigned int count, uint8_t *buffer);
-int eos_sdc_sect_write(uint32_t sect, unsigned int count, uint8_t *buffer);
diff --git a/fw/fe310/eos/soc/i2c.c b/fw/fe310/eos/soc/i2c.c
new file mode 100644
index 0000000..a507af1
--- /dev/null
+++ b/fw/fe310/eos/soc/i2c.c
@@ -0,0 +1,145 @@
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "encoding.h"
+#include "platform.h"
+#include "prci_driver.h"
+
+#include "eos.h"
+#include "i2s.h"
+#include "i2c.h"
+
+int eos_i2c_init(uint8_t wakeup_cause) {
+    eos_i2c_speed(EOS_I2C_SPEED);
+    // eos_i2c_start();
+
+    return EOS_OK;
+}
+
+void eos_i2c_start(void) {
+    I2C0_REGB(I2C_CONTROL)  |=  I2C_CONTROL_EN;
+    GPIO_REG(GPIO_IOF_SEL)  &= ~IOF0_I2C0_MASK;
+    GPIO_REG(GPIO_IOF_EN)   |=  IOF0_I2C0_MASK;
+}
+
+void eos_i2c_stop(void) {
+    GPIO_REG(GPIO_IOF_EN)   &= ~IOF0_I2C0_MASK;
+    I2C0_REGB(I2C_CONTROL)  &= ~I2C_CONTROL_EN;
+}
+
+void eos_i2c_speed(uint32_t baud_rate) {
+    unsigned long clock_rate = PRCI_get_cpu_freq();
+    uint16_t prescaler = (clock_rate / (baud_rate * 5)) - 1;
+
+    I2C0_REGB(I2C_PRESCALE_LOW) = prescaler & 0xFF;
+    I2C0_REGB(I2C_PRESCALE_HIGH) = (prescaler >> 8) & 0xFF;
+}
+
+
+static int i2c_read(uint8_t cmd) {
+    I2C0_REGB(I2C_COMMAND) = I2C_CMD_READ | cmd;
+    while (I2C0_REGB(I2C_STATUS) & I2C_STATUS_TIP);
+
+    return I2C0_REGB(I2C_RECEIVE);
+}
+
+static int i2c_write(uint8_t cmd, uint8_t b) {
+    I2C0_REGB(I2C_TRANSMIT) = b;
+    I2C0_REGB(I2C_COMMAND) = I2C_CMD_WRITE | cmd;
+    while (I2C0_REGB(I2C_STATUS) & I2C_STATUS_TIP);
+
+    if (I2C0_REGB(I2C_STATUS) & I2C_STATUS_RXACK) return EOS_ERR;
+    return EOS_OK;
+}
+
+static int i2c_addr(uint8_t addr, uint8_t rw_flag) {
+    return i2c_write(I2C_CMD_START, ((addr & 0x7F) << 1) | (rw_flag & 0x1));
+}
+
+int eos_i2c_read8(uint8_t addr, uint8_t reg, uint8_t *buffer, uint16_t len) {
+    int rv;
+    int i;
+
+    rv = i2c_addr(addr, I2C_WRITE);
+    if (rv) return rv;
+
+    rv = i2c_write(0, reg);
+    if (rv) return rv;
+
+    rv = i2c_addr(addr, I2C_READ);
+    if (rv) return rv;
+
+    for (i=0; i<len; i++) {
+        rv = i2c_read(i == (len - 1) ? (I2C_CMD_ACK | I2C_CMD_STOP) : 0);  /* Set NACK to end read, and generate STOP condition */
+        if (rv < 0) return rv;
+
+        buffer[i] = (uint8_t)rv;
+    }
+
+    return EOS_OK;
+}
+
+int eos_i2c_read16(uint8_t addr, uint16_t reg, uint8_t *buffer, uint16_t len) {
+    int rv;
+    int i;
+
+    rv = i2c_addr(addr, I2C_WRITE);
+    if (rv) return rv;
+
+    rv = i2c_write(0, reg >> 8);
+    if (rv) return rv;
+
+    rv = i2c_write(0, reg & 0xff);
+    if (rv) return rv;
+
+    rv = i2c_addr(addr, I2C_READ);
+    if (rv) return rv;
+
+    for (i=0; i<len; i++) {
+        rv = i2c_read(i == (len - 1) ? (I2C_CMD_ACK | I2C_CMD_STOP) : 0);  /* Set NACK to end read, and generate STOP condition */
+        if (rv < 0) return rv;
+
+        buffer[i] = (uint8_t)rv;
+    }
+
+    return EOS_OK;
+}
+
+int eos_i2c_write8(uint8_t addr, uint8_t reg, uint8_t *buffer, uint16_t len) {
+    int rv;
+    int i;
+
+    rv = i2c_addr(addr, I2C_WRITE);
+    if (rv) return rv;
+
+    rv = i2c_write(0, reg);
+    if (rv) return rv;
+
+    for (i=0; i<len; i++) {
+        rv = i2c_write(i == (len - 1) ? I2C_CMD_STOP : 0, buffer[i]);
+        if (rv) return rv;
+    }
+
+    return EOS_OK;
+}
+
+int eos_i2c_write16(uint8_t addr, uint16_t reg, uint8_t *buffer, uint16_t len) {
+    int rv;
+    int i;
+
+    rv = i2c_addr(addr, I2C_WRITE);
+    if (rv) return rv;
+
+    rv = i2c_write(0, reg >> 8);
+    if (rv) return rv;
+
+    rv = i2c_write(0, reg & 0xff);
+    if (rv) return rv;
+
+    for (i=0; i<len; i++) {
+        rv = i2c_write(i == (len - 1) ? I2C_CMD_STOP : 0, buffer[i]);
+        if (rv) return rv;
+    }
+
+    return EOS_OK;
+}
diff --git a/fw/fe310/eos/soc/i2c.h b/fw/fe310/eos/soc/i2c.h
new file mode 100644
index 0000000..20d3dc7
--- /dev/null
+++ b/fw/fe310/eos/soc/i2c.h
@@ -0,0 +1,13 @@
+#include <stdint.h>
+
+#define EOS_I2C_SPEED       100000
+
+int eos_i2c_init(uint8_t wakeup_cause);
+int eos_i2c_run(uint8_t wakeup_cause);
+void eos_i2c_start(void);
+void eos_i2c_stop(void);
+void eos_i2c_speed(uint32_t baud_rate);
+int eos_i2c_read8(uint8_t addr, uint8_t reg, uint8_t *buffer, uint16_t len);
+int eos_i2c_read16(uint8_t addr, uint16_t reg, uint8_t *buffer, uint16_t len);
+int eos_i2c_write8(uint8_t addr, uint8_t reg, uint8_t *buffer, uint16_t len);
+int eos_i2c_write16(uint8_t addr, uint16_t reg, uint8_t *buffer, uint16_t len);
diff --git a/fw/fe310/eos/soc/i2s.c b/fw/fe310/eos/soc/i2s.c
new file mode 100644
index 0000000..9cc9d9c
--- /dev/null
+++ b/fw/fe310/eos/soc/i2s.c
@@ -0,0 +1,477 @@
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "encoding.h"
+#include "platform.h"
+#include "prci_driver.h"
+
+#include "eos.h"
+#include "interrupt.h"
+#include "event.h"
+
+#include "board.h"
+
+#include "i2s.h"
+#include "i2s_priv.h"
+
+#define I2S_REG_CK(o)       _REG32(I2S_CTRL_ADDR_CK, o)
+#define I2S_REG_WS_MIC(o)   _REG32(I2S_CTRL_ADDR_WS_MIC, o)
+#define I2S_REG_WS_SPK(o)   _REG32(I2S_CTRL_ADDR_WS_SPK, o)
+
+#define I2S_PIN_PWM         ((1 << I2S_PIN_CK) | (1 << I2S_PIN_CK_SW) | (1 << I2S_PIN_WS_MIC) | (1 << I2S_PIN_WS_SPK))
+
+#define MIN(X, Y)           (((X) < (Y)) ? (X) : (Y))
+#define MAX(X, Y)           (((X) > (Y)) ? (X) : (Y))
+
+#define EOS_ABUF_IDX_MASK(IDX, SIZE)  ((IDX) & ((SIZE) - 1))
+
+EOSABuf i2s_mic_buf;
+EOSABuf i2s_spk_buf;
+
+static eos_i2s_handler_t i2s_mic_handler = NULL;
+static eos_i2s_handler_t i2s_spk_handler = NULL;
+static uint32_t i2s_clk_period;
+static uint8_t i2s_mic_volume = 0;      /* 0 - 8 */
+static uint8_t i2s_spk_volume = 16;     /* 0 - 16 */
+
+uint32_t _eos_i2s_drvr[] = {
+    0,                      /* I2S_MIC_BUF  */
+    0,                      /* I2S_SPK_BUF  */
+    EOS_I2S_FMT_PCM16,      /* I2S_FMT      */
+    EOS_I2S_MODE_STEREO,    /* I2S_MODE     */
+    0,                      /* I2S_MIC_WM   */
+    0,                      /* I2S_SPK_WM   */
+    0,                      /* I2S_MIC_EVT  */
+    0,                      /* I2S_SPK_EVT  */
+    0,                      /* I2S_MIC_CMP2 */
+    0,                      /* I2S_MIC_CMP3 */
+    0,                      /* I2S_SAMPLE */
+};
+
+#define I2S_MIC_BUF     0
+#define I2S_SPK_BUF     1
+#define I2S_FMT         2
+#define I2S_MODE        3
+#define I2S_MIC_WM      4
+#define I2S_SPK_WM      5
+#define I2S_MIC_EVT     6
+#define I2S_SPK_EVT     7
+#define I2S_MIC_CMP2    8
+#define I2S_MIC_CMP3    9
+#define I2S_SAMPLE      10
+
+static void _abuf_init(EOSABuf *buf, uint8_t *array, uint16_t size) {
+    buf->idx_r = 0;
+    buf->idx_w = 0;
+    buf->size = size;
+    buf->array = array;
+}
+
+static int _abuf_push8(EOSABuf *buf, uint8_t sample) {
+    if ((uint16_t)(buf->idx_w - buf->idx_r) == buf->size) return EOS_ERR_FULL;
+
+    buf->array[EOS_ABUF_IDX_MASK(buf->idx_w, buf->size)] = sample;
+    buf->idx_w++;
+    return EOS_OK;
+}
+
+static int _abuf_push16(EOSABuf *buf, uint16_t sample) {
+    if ((uint16_t)(buf->idx_w - buf->idx_r) == buf->size) return EOS_ERR_FULL;
+
+    buf->array[EOS_ABUF_IDX_MASK(buf->idx_w, buf->size)] = sample >> 8;
+    buf->array[EOS_ABUF_IDX_MASK(buf->idx_w + 1, buf->size)] = sample & 0xFF;
+    buf->idx_w += 2;
+    return EOS_OK;
+}
+
+static int _abuf_pop8(EOSABuf *buf, uint8_t *sample) {
+    if (buf->idx_r == buf->idx_w) {
+        return EOS_ERR_EMPTY;
+    } else {
+        *sample = buf->array[EOS_ABUF_IDX_MASK(buf->idx_r, buf->size)];
+        buf->idx_r++;
+        return EOS_OK;
+    }
+}
+
+static int _abuf_pop16(EOSABuf *buf, uint16_t *sample) {
+    if (buf->idx_r == buf->idx_w) {
+        return EOS_ERR_EMPTY;
+    } else {
+        *sample = buf->array[EOS_ABUF_IDX_MASK(buf->idx_r, buf->size)] << 8;
+        *sample |= buf->array[EOS_ABUF_IDX_MASK(buf->idx_r + 1, buf->size)];
+        buf->idx_r += 2;
+        return EOS_OK;
+    }
+}
+
+static void _abuf_flush(EOSABuf *buf) {
+    buf->idx_r = 0;
+    buf->idx_w = 0;
+}
+
+static uint16_t _abuf_len(EOSABuf *buf) {
+    return buf->idx_w - buf->idx_r;
+}
+
+static void i2s_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) {
+    switch(type & ~EOS_EVT_MASK) {
+        case EOS_I2S_ETYPE_MIC:
+            if (i2s_mic_handler) {
+                i2s_mic_handler(type);
+                clear_csr(mstatus, MSTATUS_MIE);
+                _eos_i2s_drvr[I2S_MIC_EVT] = 1;
+                set_csr(mstatus, MSTATUS_MIE);
+            }
+            break;
+
+        case EOS_I2S_ETYPE_SPK:
+            if (i2s_spk_handler) {
+                i2s_spk_handler(type);
+                clear_csr(mstatus, MSTATUS_MIE);
+                _eos_i2s_drvr[I2S_SPK_EVT] = 1;
+                set_csr(mstatus, MSTATUS_MIE);
+            }
+            break;
+
+        default:
+            eos_evtq_bad_handler(type, buffer, len);
+            break;
+    }
+}
+
+#define PLIC_PRIORITY     0x0C000000
+
+static void i2s_cmp_set(void) {
+    int c = 7;    /* interrupt will trigger c i2s clocks before spk ws */
+    int spk_ws_offset = i2s_spk_volume - 16 + i2s_mic_volume;
+    volatile  uint32_t *p = (uint32_t *)PLIC_PRIORITY+I2S_IRQ_SD_ID;
+
+    /* interrupt trigger - will start with left channel */
+    if (spk_ws_offset - c < 0) {
+        I2S_REG_WS_SPK(PWM_CMP3) = i2s_clk_period * (64 + spk_ws_offset - c);
+    } else {
+        I2S_REG_WS_SPK(PWM_CMP3) = i2s_clk_period * (spk_ws_offset - c);
+    }
+
+    /* disable interrupt for this cycle */
+    *p = 0;
+
+    /* empty buffers */
+    // i2s_mic_buf.idx_r = i2s_mic_buf.idx_w;
+    // i2s_spk_buf.idx_w = i2s_spk_buf.idx_r;
+
+    /* adjust spk ws relative to mic ws */
+    if (spk_ws_offset <= 0) {
+        spk_ws_offset += 32;
+        GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << I2S_PIN_WS_SPK);
+    } else {
+        GPIO_REG(GPIO_OUTPUT_XOR) |=  (1 << I2S_PIN_WS_SPK);
+    }
+    I2S_REG_WS_SPK(PWM_CMP1) = i2s_clk_period * spk_ws_offset;
+    I2S_REG_WS_SPK(PWM_CMP2) = i2s_clk_period * (32 + spk_ws_offset);
+
+    /* mic cmp2 relative to interrupt trigger */
+    _eos_i2s_drvr[I2S_MIC_CMP2] = (17 + c - i2s_spk_volume) * i2s_clk_period;   /* (17 + c - i2s_spk_volume) == (1 + i2s_mic_volume) - (spk_ws_offset - c) */
+    _eos_i2s_drvr[I2S_MIC_CMP3] = 16 * i2s_clk_period;
+}
+
+extern void _eos_i2s_start_pwm(void);
+
+int eos_i2s_init(uint8_t wakeup_cause) {
+    eos_evtq_set_handler(EOS_EVT_I2S, i2s_handle_evt);
+
+    I2S_REG_CK(PWM_CFG)         = 0;
+    I2S_REG_WS_MIC(PWM_CFG)     = 0;
+    I2S_REG_WS_SPK(PWM_CFG)     = 0;
+
+    eos_i2s_init_mux();
+
+    GPIO_REG(GPIO_OUTPUT_VAL)   |=  (1 << I2S_PIN_CK_SW);
+    GPIO_REG(GPIO_OUTPUT_VAL)   &= ~(1 << I2S_PIN_CK_SR);
+
+    GPIO_REG(GPIO_INPUT_EN)     &= ~(1 << I2S_PIN_CK_SW);
+    GPIO_REG(GPIO_OUTPUT_EN)    |=  (1 << I2S_PIN_CK_SW);
+
+    GPIO_REG(GPIO_INPUT_EN)     &= ~(1 << I2S_PIN_CK_SR);
+    GPIO_REG(GPIO_OUTPUT_EN)    |=  (1 << I2S_PIN_CK_SR);
+
+    return EOS_OK;
+}
+
+void eos_i2s_init_mux(void) {
+    GPIO_REG(GPIO_OUTPUT_VAL)   &= ~((1 << I2S_PIN_CK) | (1 << I2S_PIN_WS_MIC) | (1 << I2S_PIN_WS_SPK));
+
+    GPIO_REG(GPIO_INPUT_EN)     &= ~(1 << I2S_PIN_CK);
+    GPIO_REG(GPIO_OUTPUT_EN)    |=  (1 << I2S_PIN_CK);
+
+    GPIO_REG(GPIO_INPUT_EN)     &= ~(1 << I2S_PIN_WS_MIC);
+    GPIO_REG(GPIO_OUTPUT_EN)    |=  (1 << I2S_PIN_WS_MIC);
+
+    GPIO_REG(GPIO_INPUT_EN)     &= ~(1 << I2S_PIN_WS_SPK);
+    GPIO_REG(GPIO_OUTPUT_EN)    |=  (1 << I2S_PIN_WS_SPK);
+
+    GPIO_REG(GPIO_INPUT_EN)     |=  (1 << I2S_PIN_SD_IN);
+    GPIO_REG(GPIO_OUTPUT_EN)    &= ~(1 << I2S_PIN_SD_IN);
+
+    GPIO_REG(GPIO_INPUT_EN)     &= ~(1 << I2S_PIN_SD_OUT);
+    GPIO_REG(GPIO_OUTPUT_EN)    &= ~(1 << I2S_PIN_SD_OUT);
+}
+
+void eos_i2s_start(uint32_t sample_rate) {
+    i2s_clk_period = ((PRCI_get_cpu_freq() / (sample_rate * 64)) & ~I2S_PWM_SCALE_CK_MASK) + 1;
+
+    GPIO_REG(GPIO_INPUT_EN)     |=  (1 << I2S_PIN_SD_IN);
+    GPIO_REG(GPIO_OUTPUT_EN)    &= ~(1 << I2S_PIN_SD_IN);
+
+    GPIO_REG(GPIO_INPUT_EN)     &= ~(1 << I2S_PIN_SD_OUT);
+    GPIO_REG(GPIO_OUTPUT_EN)    &= ~(1 << I2S_PIN_SD_OUT);
+
+    I2S_REG_CK(PWM_CMP0)        = i2s_clk_period >> I2S_PWM_SCALE_CK;
+    I2S_REG_CK(PWM_CMP1)        = I2S_REG_CK(PWM_CMP0) / 2;
+    I2S_REG_CK(PWM_CMP2)        = 0;
+    I2S_REG_CK(PWM_CMP3)        = 0;
+
+    I2S_REG_WS_MIC(PWM_CMP0)    = i2s_clk_period * 64 - 1;
+    I2S_REG_WS_MIC(PWM_CMP1)    = i2s_clk_period * 32;
+
+    I2S_REG_WS_SPK(PWM_CMP0)    = i2s_clk_period * 64 - 1;
+    i2s_cmp_set();
+
+    I2S_REG_CK(PWM_COUNT)       = 0;
+    I2S_REG_WS_MIC(PWM_COUNT)   = 0;
+    I2S_REG_WS_SPK(PWM_COUNT)   = i2s_clk_period / 2;
+
+    if (i2s_mic_buf.array && i2s_mic_buf.size) {
+        _eos_i2s_drvr[I2S_MIC_BUF] = (uint32_t)&i2s_mic_buf;
+        if (_eos_i2s_drvr[I2S_MIC_WM] == 0) {
+            _eos_i2s_drvr[I2S_MIC_WM] = i2s_mic_buf.size / 2;
+        }
+    }
+    if (i2s_spk_buf.array && i2s_spk_buf.size) {
+        _eos_i2s_drvr[I2S_SPK_BUF] = (uint32_t)&i2s_spk_buf;
+        if (_eos_i2s_drvr[I2S_SPK_WM] == 0) {
+            _eos_i2s_drvr[I2S_SPK_WM] = i2s_spk_buf.size / 2;
+        }
+    }
+    if (i2s_mic_handler) _eos_i2s_drvr[I2S_MIC_EVT] = 1;
+    if (i2s_spk_handler) _eos_i2s_drvr[I2S_SPK_EVT] = 1;
+
+    eos_intr_set_priority(I2S_IRQ_SD_ID, IRQ_PRIORITY_I2S_SD);
+    eos_intr_set_priority(I2S_IRQ_WS_ID, IRQ_PRIORITY_I2S_WS);
+    eos_intr_enable(I2S_IRQ_SD_ID);
+    eos_intr_enable(I2S_IRQ_WS_ID);
+
+    _eos_i2s_start_pwm();
+    /*
+    I2S_REG_CK(PWM_CFG)         = PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | I2S_PWM_SCALE_CK;
+    I2S_REG_WS_MIC(PWM_CFG)     = PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | PWM_CFG_CMP2GANG;
+    I2S_REG_WS_SPK(PWM_CFG)     = PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | PWM_CFG_CMP1GANG;
+    */
+
+    GPIO_REG(GPIO_OUTPUT_VAL)   |=  (1 << I2S_PIN_WS_MIC);
+    GPIO_REG(GPIO_INPUT_EN)     &= ~(1 << I2S_PIN_WS_MIC);
+    GPIO_REG(GPIO_OUTPUT_EN)    |=  (1 << I2S_PIN_WS_MIC);
+
+    GPIO_REG(GPIO_OUTPUT_VAL)   |=  (1 << I2S_PIN_CK_SR);
+    GPIO_REG(GPIO_IOF_SEL)      |=  I2S_PIN_PWM;
+    GPIO_REG(GPIO_IOF_EN)       |=  I2S_PIN_PWM;
+}
+
+void eos_i2s_stop(void) {
+    I2S_REG_CK(PWM_CFG)         = 0;
+    I2S_REG_WS_MIC(PWM_CFG)     = 0;
+    I2S_REG_WS_SPK(PWM_CFG)     = 0;
+    I2S_REG_CK(PWM_COUNT)       = 0;
+    I2S_REG_WS_MIC(PWM_COUNT)   = 0;
+    I2S_REG_WS_SPK(PWM_COUNT)   = 0;
+
+    _eos_i2s_drvr[I2S_MIC_BUF]  = 0;
+    _eos_i2s_drvr[I2S_MIC_EVT]  = 0;
+    _eos_i2s_drvr[I2S_MIC_WM]   = 0;
+
+    _eos_i2s_drvr[I2S_SPK_BUF]  = 0;
+    _eos_i2s_drvr[I2S_SPK_EVT]  = 0;
+    _eos_i2s_drvr[I2S_SPK_WM]   = 0;
+
+    eos_intr_disable(I2S_IRQ_WS_ID);
+    eos_intr_disable(I2S_IRQ_SD_ID);
+
+    GPIO_REG(GPIO_OUTPUT_VAL)   |=  (1 << I2S_PIN_CK_SW);
+    GPIO_REG(GPIO_OUTPUT_VAL)   &= ~(1 << I2S_PIN_CK_SR);
+
+    GPIO_REG(GPIO_OUTPUT_XOR)   &= ~(1 << I2S_PIN_WS_SPK);
+    GPIO_REG(GPIO_IOF_EN)       &= ~I2S_PIN_PWM;
+
+    eos_i2s_mic_set_wm(0);
+    eos_i2s_spk_set_wm(0);
+}
+
+int eos_i2s_running(void) {
+    return !!(GPIO_REG(GPIO_IOF_EN) & (1 << I2S_PIN_CK));
+}
+
+void eos_i2s_set_fmt(unsigned char fmt) {
+    _eos_i2s_drvr[I2S_FMT] = fmt;
+}
+
+void eos_i2s_set_mode(unsigned char mode) {
+    _eos_i2s_drvr[I2S_MODE] = mode;
+}
+
+void eos_i2s_mic_init(uint8_t *mic_arr, uint16_t mic_arr_size) {
+    clear_csr(mstatus, MSTATUS_MIE);
+    _abuf_init(&i2s_mic_buf, mic_arr, mic_arr_size);
+    set_csr(mstatus, MSTATUS_MIE);
+}
+
+void eos_i2s_mic_set_handler(eos_i2s_handler_t wm_handler) {
+    clear_csr(mstatus, MSTATUS_MIE);
+    i2s_mic_handler = wm_handler;
+    set_csr(mstatus, MSTATUS_MIE);
+}
+
+void eos_i2s_mic_set_wm(uint16_t wm) {
+    clear_csr(mstatus, MSTATUS_MIE);
+    _eos_i2s_drvr[I2S_MIC_WM] = wm;
+    set_csr(mstatus, MSTATUS_MIE);
+
+}
+
+uint16_t eos_i2s_mic_len(void) {
+    clear_csr(mstatus, MSTATUS_MIE);
+    uint16_t ret = _abuf_len(&i2s_mic_buf);
+    set_csr(mstatus, MSTATUS_MIE);
+    return ret;
+}
+
+uint16_t eos_i2s_mic_read(uint8_t *sample, uint16_t ssize) {
+    uint16_t i;
+    uint16_t _ssize = 0;
+
+    clear_csr(mstatus, MSTATUS_MIE);
+    _ssize = MIN(ssize, _abuf_len(&i2s_mic_buf));
+    set_csr(mstatus, MSTATUS_MIE);
+
+    for (i=0; i<_ssize; i++) {
+        sample[i] = i2s_mic_buf.array[EOS_ABUF_IDX_MASK(i2s_mic_buf.idx_r + i, i2s_mic_buf.size)];
+    }
+
+    clear_csr(mstatus, MSTATUS_MIE);
+    i2s_mic_buf.idx_r += _ssize;
+    set_csr(mstatus, MSTATUS_MIE);
+
+    return _ssize;
+}
+
+int eos_i2s_mic_pop8(uint8_t *sample) {
+    int ret;
+
+    clear_csr(mstatus, MSTATUS_MIE);
+    ret = _abuf_pop8(&i2s_mic_buf, sample);
+    set_csr(mstatus, MSTATUS_MIE);
+
+    return ret;
+}
+
+int eos_i2s_mic_pop16(uint16_t *sample) {
+    int ret;
+
+    clear_csr(mstatus, MSTATUS_MIE);
+    ret = _abuf_pop16(&i2s_mic_buf, sample);
+    set_csr(mstatus, MSTATUS_MIE);
+
+    return ret;
+}
+
+int eos_i2s_mic_vol_get(void) {
+    return i2s_mic_volume;
+}
+
+void eos_i2s_mic_vol_set(int vol) {
+    if ((vol < 0) || (vol > 8)) return;
+
+    i2s_mic_volume = vol;
+
+    clear_csr(mstatus, MSTATUS_MIE);
+    i2s_cmp_set();
+    set_csr(mstatus, MSTATUS_MIE);
+}
+
+void eos_i2s_spk_init(uint8_t *spk_arr, uint16_t spk_arr_size) {
+    clear_csr(mstatus, MSTATUS_MIE);
+    _abuf_init(&i2s_spk_buf, spk_arr, spk_arr_size);
+    set_csr(mstatus, MSTATUS_MIE);
+}
+
+void eos_i2s_spk_set_handler(eos_i2s_handler_t wm_handler) {
+    clear_csr(mstatus, MSTATUS_MIE);
+    i2s_spk_handler = wm_handler;
+    set_csr(mstatus, MSTATUS_MIE);
+}
+
+void eos_i2s_spk_set_wm(uint16_t wm) {
+    clear_csr(mstatus, MSTATUS_MIE);
+    _eos_i2s_drvr[I2S_SPK_WM] = wm;
+    set_csr(mstatus, MSTATUS_MIE);
+}
+
+uint16_t eos_i2s_spk_len(void) {
+    clear_csr(mstatus, MSTATUS_MIE);
+    uint16_t ret = _abuf_len(&i2s_spk_buf);
+    set_csr(mstatus, MSTATUS_MIE);
+    return ret;
+}
+
+uint16_t eos_i2s_spk_write(uint8_t *sample, uint16_t ssize) {
+    uint16_t i;
+    uint16_t _ssize = 0;
+
+    clear_csr(mstatus, MSTATUS_MIE);
+    _ssize = MIN(ssize, i2s_spk_buf.size - _abuf_len(&i2s_spk_buf));
+    set_csr(mstatus, MSTATUS_MIE);
+
+    for (i=0; i<_ssize; i++) {
+        i2s_spk_buf.array[EOS_ABUF_IDX_MASK(i2s_spk_buf.idx_w + i, i2s_spk_buf.size)] = sample[i];
+    }
+
+    clear_csr(mstatus, MSTATUS_MIE);
+    i2s_spk_buf.idx_w += _ssize;
+    set_csr(mstatus, MSTATUS_MIE);
+
+    return _ssize;
+}
+
+int eos_i2s_spk_push8(uint8_t sample) {
+    int ret;
+
+    clear_csr(mstatus, MSTATUS_MIE);
+    ret = _abuf_push8(&i2s_spk_buf, sample);
+    set_csr(mstatus, MSTATUS_MIE);
+
+    return ret;
+}
+
+int eos_i2s_spk_push16(uint16_t sample) {
+    int ret;
+
+    clear_csr(mstatus, MSTATUS_MIE);
+    ret = _abuf_push16(&i2s_spk_buf, sample);
+    set_csr(mstatus, MSTATUS_MIE);
+
+    return ret;
+}
+
+int eos_i2s_spk_vol_get(void) {
+    return i2s_spk_volume;
+}
+
+void eos_i2s_spk_vol_set(int vol) {
+    if ((vol < 0) || (vol > 16)) return;
+
+    i2s_spk_volume = vol;
+
+    clear_csr(mstatus, MSTATUS_MIE);
+    i2s_cmp_set();
+    set_csr(mstatus, MSTATUS_MIE);
+}
diff --git a/fw/fe310/eos/soc/i2s.h b/fw/fe310/eos/soc/i2s.h
new file mode 100644
index 0000000..81b4ade
--- /dev/null
+++ b/fw/fe310/eos/soc/i2s.h
@@ -0,0 +1,38 @@
+#include <stdint.h>
+
+#include "i2s_def.h"
+
+typedef struct EOSABuf {
+    uint16_t idx_r;
+    uint16_t idx_w;
+    uint16_t size;
+    uint8_t *array;
+} EOSABuf;
+
+typedef void (*eos_i2s_handler_t) (unsigned char);
+
+int eos_i2s_init(uint8_t wakeup_cause);
+void eos_i2s_init_mux(void);
+void eos_i2s_start(uint32_t sample_rate);
+void eos_i2s_stop(void);
+int eos_i2s_running(void);
+void eos_i2s_set_fmt(unsigned char fmt);
+void eos_i2s_set_mode(unsigned char mode);
+void eos_i2s_mic_init(uint8_t *mic_arr, uint16_t mic_arr_size);
+void eos_i2s_mic_set_handler(eos_i2s_handler_t wm_handler);
+void eos_i2s_mic_set_wm(uint16_t wm);
+uint16_t eos_i2s_mic_len(void);
+uint16_t eos_i2s_mic_read(uint8_t *sample, uint16_t ssize);
+int eos_i2s_mic_pop8(uint8_t *sample);
+int eos_i2s_mic_pop16(uint16_t *sample);
+int eos_i2s_mic_vol_get(void);
+void eos_i2s_mic_vol_set(int vol);
+void eos_i2s_spk_init(uint8_t *mic_arr, uint16_t mic_arr_size);
+void eos_i2s_spk_set_handler(eos_i2s_handler_t wm_handler);
+void eos_i2s_spk_set_wm(uint16_t wm);
+uint16_t eos_i2s_spk_len(void);
+uint16_t eos_i2s_spk_write(uint8_t *sample, uint16_t ssize);
+int eos_i2s_spk_push8(uint8_t sample);
+int eos_i2s_spk_push16(uint16_t sample);
+int eos_i2s_spk_vol_get(void);
+void eos_i2s_spk_vol_set(int vol);
diff --git a/fw/fe310/eos/soc/i2s_def.h b/fw/fe310/eos/soc/i2s_def.h
new file mode 100644
index 0000000..3529be1
--- /dev/null
+++ b/fw/fe310/eos/soc/i2s_def.h
@@ -0,0 +1,8 @@
+#define EOS_I2S_FMT_PCM16       0
+#define EOS_I2S_FMT_ALAW        1
+
+#define EOS_I2S_MODE_STEREO     0
+#define EOS_I2S_MODE_MONO     	1
+
+#define EOS_I2S_ETYPE_MIC       1
+#define EOS_I2S_ETYPE_SPK       2
diff --git a/fw/fe310/eos/soc/i2s_priv.h b/fw/fe310/eos/soc/i2s_priv.h
new file mode 100644
index 0000000..25237c3
--- /dev/null
+++ b/fw/fe310/eos/soc/i2s_priv.h
@@ -0,0 +1,8 @@
+#define I2S_PWM_SCALE_CK        2
+#define I2S_PWM_SCALE_CK_MASK   0x0003
+
+/* asm */
+#define I2S_ABUF_OFF_IDXR       0
+#define I2S_ABUF_OFF_IDXW       2
+#define I2S_ABUF_OFF_SIZE       4
+#define I2S_ABUF_OFF_ARRAY      8
diff --git a/fw/fe310/eos/soc/interrupt.c b/fw/fe310/eos/soc/interrupt.c
new file mode 100644
index 0000000..dab6fab
--- /dev/null
+++ b/fw/fe310/eos/soc/interrupt.c
@@ -0,0 +1,75 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include "encoding.h"
+#include "platform.h"
+#include "plic_driver.h"
+
+#include "eos.h"
+#include "interrupt.h"
+
+// Global Instance data for the PLIC
+// for use by the PLIC Driver.
+static plic_instance_t plic;
+
+static eos_intr_handler_t ext_interrupt_handler[PLIC_NUM_INTERRUPTS];
+
+uintptr_t eos_intr_handle(uintptr_t int_num) {
+    if ((int_num >=1) && (int_num <= PLIC_NUM_INTERRUPTS) && (ext_interrupt_handler[int_num-1])) {
+        ext_interrupt_handler[int_num-1]();
+    } else {
+        printf("INTR ERROR:%d\n", int_num);
+        exit(int_num);
+    }
+    return int_num;
+}
+
+int eos_intr_init(uint8_t wakeup_cause) {
+    for (int i = 0; i < PLIC_NUM_INTERRUPTS; i++){
+        ext_interrupt_handler[i] = NULL;
+    }
+
+    /**************************************************************************
+    * Set up the PLIC
+    **************************************************************************/
+    PLIC_init(&plic,
+ 	    PLIC_CTRL_ADDR,
+ 	    PLIC_NUM_INTERRUPTS,
+ 	    PLIC_NUM_PRIORITIES);
+
+    // Enable Global (PLIC) interrupts.
+    set_csr(mie, MIP_MEIP);
+
+    // Enable all interrupts
+    set_csr(mstatus, MSTATUS_MIE);
+
+    return EOS_OK;
+}
+
+void eos_intr_set(uint8_t int_num, uint8_t priority, eos_intr_handler_t handler) {
+    ext_interrupt_handler[int_num-1] = handler;
+    PLIC_set_priority(&plic, int_num, priority);
+    PLIC_enable_interrupt(&plic, int_num);
+}
+
+void eos_intr_set_handler(uint8_t int_num, eos_intr_handler_t handler) {
+    ext_interrupt_handler[int_num-1] = handler;
+}
+
+void eos_intr_set_priority(uint8_t int_num, uint8_t priority) {
+    PLIC_set_priority(&plic, int_num, priority);
+}
+
+void eos_intr_enable(uint8_t int_num) {
+    PLIC_enable_interrupt(&plic, int_num);
+}
+
+void eos_intr_disable(uint8_t int_num) {
+    PLIC_disable_interrupt(&plic, int_num);
+}
+
+void eos_intr_mask(uint8_t priority) {
+    PLIC_set_threshold(&plic, priority);
+}
diff --git a/fw/fe310/eos/soc/interrupt.h b/fw/fe310/eos/soc/interrupt.h
new file mode 100644
index 0000000..a239934
--- /dev/null
+++ b/fw/fe310/eos/soc/interrupt.h
@@ -0,0 +1,13 @@
+#include <stdint.h>
+
+#include "irq_def.h"
+
+typedef void (*eos_intr_handler_t) (void);
+
+int eos_intr_init(uint8_t wakeup_cause);
+void eos_intr_set(uint8_t int_num, uint8_t priority, eos_intr_handler_t handler);
+void eos_intr_set_handler(uint8_t int_num, eos_intr_handler_t handler);
+void eos_intr_set_priority(uint8_t int_num, uint8_t priority);
+void eos_intr_enable(uint8_t int_num);
+void eos_intr_disable(uint8_t int_num);
+void eos_intr_mask(uint8_t priority);
\ No newline at end of file
diff --git a/fw/fe310/eos/soc/net.c b/fw/fe310/eos/soc/net.c
new file mode 100644
index 0000000..33b71c2
--- /dev/null
+++ b/fw/fe310/eos/soc/net.c
@@ -0,0 +1,602 @@
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "encoding.h"
+#include "platform.h"
+
+#include "eos.h"
+#include "msgq.h"
+#include "interrupt.h"
+#include "event.h"
+#include "timer.h"
+#include "pwr.h"
+
+#include "board.h"
+
+#include "spi.h"
+#include "spi_priv.h"
+#include "spi_dev.h"
+
+#include "net.h"
+
+#define NET_SIZE_HDR            3
+#define NET_STATE_FLAG_RUN      0x01
+#define NET_STATE_FLAG_INIT     0x02
+#define NET_STATE_FLAG_XCHG     0x04
+#define NET_STATE_FLAG_ONEW     0x10
+#define NET_STATE_FLAG_SYNC     0x20
+#define NET_STATE_FLAG_RTS      0x40
+#define NET_STATE_FLAG_CTS      0x80
+
+#define MIN(X, Y)               (((X) < (Y)) ? (X) : (Y))
+#define MAX(X, Y)               (((X) > (Y)) ? (X) : (Y))
+
+static EOSBufQ net_buf_q;
+static unsigned char *net_bufq_array[EOS_NET_SIZE_BUFQ];
+static unsigned char net_bufq_buffer[EOS_NET_SIZE_BUFQ][EOS_NET_SIZE_BUF];
+
+static EOSMsgQ net_send_q;
+static EOSMsgItem net_sndq_array[EOS_NET_SIZE_BUFQ];
+
+static volatile uint8_t net_state_flags = 0;
+static unsigned char net_state_type = 0;
+static uint32_t net_state_len_tx = 0;
+static uint32_t net_state_len_rx = 0;
+unsigned char *net_state_buf = NULL;
+
+static uint8_t net_state_next_cnt = 0;
+static unsigned char *net_state_next_buf = NULL;
+
+static eos_evt_handler_t net_handler[EOS_NET_MAX_MTYPE];
+static uint16_t net_wrapper_acq[EOS_EVT_MAX_EVT];
+static uint16_t net_flags_acq[EOS_EVT_MAX_EVT];
+
+static int net_xchg_sleep(void) {
+    int i;
+    int rv = EOS_OK;
+    volatile uint32_t x = 0;
+    net_state_flags &= ~NET_STATE_FLAG_CTS;
+
+    SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD;
+
+    SPI1_REG(SPI_REG_TXFIFO) = 0xFF;
+    while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+    if (x & 0xFF) rv = EOS_ERR_BUSY;
+
+    for (i=0; i<7; i++) {
+        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+        SPI1_REG(SPI_REG_TXFIFO) = 0;
+        while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+    }
+
+    SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO;
+
+    return rv;
+}
+
+static void net_xchg_wake(void) {
+    int i;
+    volatile uint32_t x = 0;
+    net_state_flags &= ~NET_STATE_FLAG_CTS;
+
+    SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD;
+
+    for (i=0; i<8; i++) {
+        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+        SPI1_REG(SPI_REG_TXFIFO) = 0;
+        while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+    }
+
+    SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO;
+}
+
+static void net_xchg_reset(void) {
+    volatile uint32_t x = 0;
+    net_state_flags &= ~NET_STATE_FLAG_CTS;
+
+    SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD;
+
+    SPI1_REG(SPI_REG_TXFIFO) = 0;
+    while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+
+    SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO;
+}
+
+static void net_xchg_start(unsigned char type, unsigned char *buffer, uint16_t len) {
+    net_state_flags &= ~NET_STATE_FLAG_CTS;
+    net_state_flags |= (NET_STATE_FLAG_INIT | NET_STATE_FLAG_XCHG);
+
+    if (net_state_next_cnt && (net_state_next_buf == NULL)) type |= EOS_NET_MTYPE_FLAG_ONEW;
+    if (type & EOS_NET_MTYPE_FLAG_ONEW) net_state_flags |= NET_STATE_FLAG_ONEW;
+
+    net_state_type = type;
+    net_state_len_tx = len;
+    net_state_len_rx = 0;
+    net_state_buf = buffer;
+
+    SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD;
+    SPI1_REG(SPI_REG_TXFIFO) = type;
+    SPI1_REG(SPI_REG_TXFIFO) = (len >> 8) & 0xFF;
+    SPI1_REG(SPI_REG_TXFIFO) = (len & 0xFF);
+    SPI1_REG(SPI_REG_RXCTRL) = SPI_RXWM(2);
+    SPI1_REG(SPI_REG_IE) = SPI_IP_RXWM;
+}
+
+static int net_xchg_next(unsigned char *_buffer) {
+    unsigned char type;
+    unsigned char *buffer = NULL;
+    uint16_t len;
+    int ret = _buffer ? 1 : 0;
+
+    eos_msgq_pop(&net_send_q, &type, &buffer, &len);
+    if (type) {
+        net_xchg_start(type, buffer, len);
+    } else if (net_state_flags & NET_STATE_FLAG_RTS) {
+        if (_buffer) {
+            buffer = _buffer;
+            ret = 0;
+        } else {
+            buffer = eos_bufq_pop(&net_buf_q);
+        }
+        if (buffer) net_xchg_start(0, buffer, 0);
+    }
+
+    return ret;
+}
+
+static void net_handle_xchg(void) {
+    volatile uint32_t r1, r2, r3;
+    uint32_t len;
+
+    if (net_state_flags & NET_STATE_FLAG_INIT) {
+        net_state_flags &= ~NET_STATE_FLAG_INIT;
+
+        r1 = SPI1_REG(SPI_REG_RXFIFO);
+        r2 = SPI1_REG(SPI_REG_RXFIFO);
+        r3 = SPI1_REG(SPI_REG_RXFIFO);
+
+        if (net_state_flags & NET_STATE_FLAG_ONEW) {
+            r1 = 0;
+            r2 = 0;
+            r3 = 0;
+        }
+
+        net_state_type    = (r1 & 0xFF);
+        net_state_len_rx  = (r2 & 0xFF) << 8;
+        net_state_len_rx |= (r3 & 0xFF);
+        len = MAX(net_state_len_tx, net_state_len_rx);
+
+        if (len > EOS_NET_MTU) {
+            net_state_flags &= ~NET_STATE_FLAG_XCHG;
+            SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO;
+            SPI1_REG(SPI_REG_IE) = 0x0;
+            return;
+        }
+
+        // esp32 dma workaraund
+        if (len < 8 - NET_SIZE_HDR) {
+            len = 8 - NET_SIZE_HDR;
+        } else if ((len + NET_SIZE_HDR) % 4 != 0) {
+            len = ((len + NET_SIZE_HDR)/4 + 1) * 4 - NET_SIZE_HDR;
+        }
+
+        _eos_spi_xchg_init(net_state_buf, len, 0);
+        SPI1_REG(SPI_REG_TXCTRL) = SPI_TXWM(SPI_SIZE_WM);
+        SPI1_REG(SPI_REG_IE) = SPI_IP_TXWM;
+        return;
+    }
+
+    eos_spi_handle_xchg();
+    if (SPI1_REG(SPI_REG_CSMODE) == SPI_CSMODE_AUTO) {  // exchange done
+        if (!(net_state_flags & NET_STATE_FLAG_SYNC)) {
+            if (net_state_type) {
+                int r = eos_evtq_push_isr(EOS_EVT_NET | net_state_type, net_state_buf, net_state_len_rx);
+                if (r) eos_bufq_push(&net_buf_q, net_state_buf);
+            } else if (((net_state_flags & NET_STATE_FLAG_ONEW) || net_state_next_cnt) && (net_state_next_buf == NULL)) {
+                net_state_next_buf = net_state_buf;
+            } else {
+                eos_bufq_push(&net_buf_q, net_state_buf);
+            }
+        }
+        net_state_flags &= ~(NET_STATE_FLAG_ONEW | NET_STATE_FLAG_XCHG);
+    }
+}
+
+static void net_handle_cts(void) {
+    GPIO_REG(GPIO_RISE_IP) = (1 << NET_PIN_CTS);
+    net_state_flags |= NET_STATE_FLAG_CTS;
+
+    if (net_state_flags & NET_STATE_FLAG_RUN) {
+        net_xchg_next(NULL);
+    }
+}
+
+static void net_handle_rts(void) {
+    uint32_t rts_offset = (1 << NET_PIN_RTS);
+
+    if (GPIO_REG(GPIO_RISE_IP) & rts_offset) {
+        GPIO_REG(GPIO_RISE_IP) = rts_offset;
+        net_state_flags |= NET_STATE_FLAG_RTS;
+        if ((net_state_flags & NET_STATE_FLAG_RUN) && (net_state_flags & NET_STATE_FLAG_CTS)) {
+            net_xchg_reset();
+        }
+    } else if (GPIO_REG(GPIO_FALL_IP) & rts_offset) {
+        GPIO_REG(GPIO_FALL_IP) = rts_offset;
+        net_state_flags &= ~NET_STATE_FLAG_RTS;
+    }
+}
+
+static void net_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) {
+    unsigned char idx = (type & ~EOS_EVT_MASK) - 1;
+
+    if (idx < EOS_NET_MAX_MTYPE) {
+        net_handler[idx](type, buffer, len);
+    } else {
+        eos_net_bad_handler(type, buffer, len);
+    }
+}
+
+static int net_acquire(unsigned char reserved) {
+    int ret = 0;
+
+    if (reserved) {
+        while (!ret) {
+            clear_csr(mstatus, MSTATUS_MIE);
+            if (net_state_next_buf) {
+                ret = 1;
+                net_state_next_cnt--;
+            } else {
+                asm volatile ("wfi");
+            }
+            set_csr(mstatus, MSTATUS_MIE);
+        }
+    } else {
+        clear_csr(mstatus, MSTATUS_MIE);
+        if (net_state_next_buf == NULL) net_state_next_buf = eos_bufq_pop(&net_buf_q);
+        ret = (net_state_next_buf != NULL);
+        if (!ret) net_state_next_cnt++;
+        set_csr(mstatus, MSTATUS_MIE);
+    }
+    return ret;
+}
+
+static void evt_handler_wrapper(unsigned char type, unsigned char *buffer, uint16_t len, unsigned char idx, uint16_t flag) {
+    int ok;
+
+    ok = net_acquire(net_wrapper_acq[idx] & flag);
+    if (ok) {
+        eos_evtq_get_handler(type)(type, buffer, len);
+        eos_net_release();
+        net_wrapper_acq[idx] &= ~flag;
+    } else {
+        net_wrapper_acq[idx] |= flag;
+        eos_evtq_push(type, buffer, len);
+    }
+}
+
+static void evt_handler(unsigned char type, unsigned char *buffer, uint16_t len) {
+    unsigned char idx = (type & EOS_EVT_MASK) >> 4;
+
+    if (idx && (idx <= EOS_EVT_MAX_EVT)) {
+        uint16_t flag = (uint16_t)1 << (type & ~EOS_EVT_MASK);
+
+        idx--;
+        if (flag & net_flags_acq[idx]) {
+            evt_handler_wrapper(type, buffer, len, idx, flag);
+        } else {
+            eos_evtq_get_handler(type)(type, buffer, len);
+        }
+    } else {
+        eos_evtq_bad_handler(type, buffer, len);
+    }
+}
+
+static void net_pause(void) {
+    net_state_flags &= ~NET_STATE_FLAG_RUN;
+}
+
+static void net_resume(void) {
+    net_state_flags |= NET_STATE_FLAG_RUN;
+    if (net_state_flags & NET_STATE_FLAG_CTS) {
+        net_xchg_next(NULL);
+    }
+}
+
+static void net_start(void) {
+    eos_intr_set_handler(INT_SPI1_BASE, net_handle_xchg);
+    SPI1_REG(SPI_REG_SCKDIV) = eos_spi_div(EOS_SPI_DEV_NET);
+    SPI1_REG(SPI_REG_CSID) = eos_spi_csid(EOS_SPI_DEV_NET);
+}
+
+static void net_stop(void) {
+    eos_intr_set_handler(INT_SPI1_BASE, NULL);
+}
+
+int eos_net_init(uint8_t wakeup_cause) {
+    int i;
+
+    eos_msgq_init(&net_send_q, net_sndq_array, EOS_NET_SIZE_BUFQ);
+    eos_bufq_init(&net_buf_q, net_bufq_array, EOS_NET_SIZE_BUFQ);
+    for (i=0; i<EOS_NET_SIZE_BUFQ; i++) {
+        eos_bufq_push(&net_buf_q, net_bufq_buffer[i]);
+    }
+
+    for (i=0; i<EOS_NET_MAX_MTYPE; i++) {
+        net_handler[i] = eos_net_bad_handler;
+    }
+    eos_evtq_set_handler(0, evt_handler);
+    eos_evtq_set_handler(EOS_EVT_NET, net_handle_evt);
+
+    GPIO_REG(GPIO_INPUT_EN)     |=  (1 << NET_PIN_CTS);
+    GPIO_REG(GPIO_OUTPUT_EN)    &= ~(1 << NET_PIN_CTS);
+
+    GPIO_REG(GPIO_RISE_IE)      |=  (1 << NET_PIN_CTS);
+    eos_intr_set(INT_GPIO_BASE + NET_PIN_CTS, IRQ_PRIORITY_NET_CTS, net_handle_cts);
+
+    GPIO_REG(GPIO_INPUT_EN)     |=  (1 << NET_PIN_RTS);
+    GPIO_REG(GPIO_OUTPUT_EN)    &= ~(1 << NET_PIN_RTS);
+
+    GPIO_REG(GPIO_RISE_IE)      |=  (1 << NET_PIN_RTS);
+    GPIO_REG(GPIO_FALL_IE)      |=  (1 << NET_PIN_RTS);
+    eos_intr_set(INT_GPIO_BASE + NET_PIN_RTS, IRQ_PRIORITY_NET_RTS, net_handle_rts);
+
+    /* set initial state */
+    clear_csr(mstatus, MSTATUS_MIE);
+    if (GPIO_REG(GPIO_INPUT_VAL) & (1 << NET_PIN_CTS)) net_state_flags |= NET_STATE_FLAG_CTS;
+    if (GPIO_REG(GPIO_INPUT_VAL) & (1 << NET_PIN_RTS)) net_state_flags |= NET_STATE_FLAG_RTS;
+    set_csr(mstatus, MSTATUS_MIE);
+
+    return EOS_OK;
+}
+
+int eos_net_run(uint8_t wakeup_cause) {
+    net_start();
+
+    clear_csr(mstatus, MSTATUS_MIE);
+    if (wakeup_cause != EOS_PWR_WAKE_RST) {
+        if (wakeup_cause != EOS_PWR_WAKE_BTN) {
+            net_xchg_wake();
+        }
+        if (!(net_state_flags & NET_STATE_FLAG_CTS)) {
+            while (!(GPIO_REG(GPIO_RISE_IP) & (1 << NET_PIN_CTS))) {
+                asm volatile ("wfi");
+            }
+            GPIO_REG(GPIO_RISE_IP) = (1 << NET_PIN_CTS);
+        }
+        net_xchg_reset();
+    }
+    net_resume();
+    set_csr(mstatus, MSTATUS_MIE);
+
+    return EOS_OK;
+}
+
+void eos_net_start(void) {
+    net_start();
+
+    clear_csr(mstatus, MSTATUS_MIE);
+    net_resume();
+    set_csr(mstatus, MSTATUS_MIE);
+}
+
+void eos_net_stop(void) {
+    uint8_t done = 0;
+
+    clear_csr(mstatus, MSTATUS_MIE);
+    if (net_state_flags & NET_STATE_FLAG_RUN) {
+        net_state_flags &= ~NET_STATE_FLAG_RUN;
+        done = !(net_state_flags & NET_STATE_FLAG_XCHG);
+    } else {
+        done = 1;
+    }
+    set_csr(mstatus, MSTATUS_MIE);
+
+    while (!done) {
+        clear_csr(mstatus, MSTATUS_MIE);
+        done = !(net_state_flags & NET_STATE_FLAG_XCHG);
+        if (!done) asm volatile ("wfi");
+        set_csr(mstatus, MSTATUS_MIE);
+    }
+    net_stop();
+}
+
+int eos_net_sleep(uint32_t timeout) {
+    volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME);
+    uint64_t then_ms = timeout + *mtime * 1000 / EOS_TIMER_RTC_FREQ;
+    uint8_t done = 0;
+    int rv = EOS_OK;
+
+    clear_csr(mstatus, MSTATUS_MIE);
+    if (!(net_state_flags & NET_STATE_FLAG_RUN)) rv = EOS_ERR;
+    set_csr(mstatus, MSTATUS_MIE);
+
+    if (rv) return rv;
+
+    do {
+        if (*mtime * 1000 / EOS_TIMER_RTC_FREQ > then_ms) return EOS_ERR_TIMEOUT;
+        clear_csr(mstatus, MSTATUS_MIE);
+        eos_evtq_flush_isr();
+        done = (eos_msgq_len(&net_send_q) == 0);
+        done = done && (!(net_state_flags & NET_STATE_FLAG_RTS) && (net_state_flags & NET_STATE_FLAG_CTS));
+        if (done) done = (net_xchg_sleep() == EOS_OK);
+        if (!done) {
+            asm volatile ("wfi");
+            set_csr(mstatus, MSTATUS_MIE);
+        }
+    } while (!done);
+
+    while (!(GPIO_REG(GPIO_RISE_IP) & (1 << NET_PIN_CTS))) {
+        if (*mtime * 1000 / EOS_TIMER_RTC_FREQ > then_ms) {
+            rv = EOS_ERR_TIMEOUT;
+            break;
+        }
+        asm volatile ("wfi");
+    }
+
+    if (!rv) {
+        GPIO_REG(GPIO_RISE_IP) = (1 << NET_PIN_CTS);
+        net_state_flags &= ~NET_STATE_FLAG_RUN;
+    }
+
+    set_csr(mstatus, MSTATUS_MIE);
+
+    return rv;
+}
+
+void eos_net_bad_handler(unsigned char type, unsigned char *buffer, uint16_t len) {
+    eos_evtq_bad_handler(type, buffer, len);
+    if (buffer) eos_net_free(buffer, 0);
+}
+
+void eos_net_set_handler(unsigned char mtype, eos_evt_handler_t handler) {
+    if (handler == NULL) handler = eos_net_bad_handler;
+    if (mtype && (mtype <= EOS_NET_MAX_MTYPE)) net_handler[mtype - 1] = handler;
+}
+
+void eos_net_acquire_for_evt(unsigned char type, char acq) {
+    unsigned char idx = (type & EOS_EVT_MASK) >> 4;
+    uint16_t flag = type & ~EOS_EVT_MASK ? (uint16_t)1 << (type & ~EOS_EVT_MASK) : 0xFFFF;
+
+    if (idx && (idx <= EOS_EVT_MAX_EVT)) {
+        idx--;
+        net_flags_acq[idx] &= ~flag;
+        if (acq) net_flags_acq[idx] |= flag;
+    }
+}
+
+void eos_net_acquire(void) {
+    unsigned char acq = net_acquire(0);
+    if (!acq) net_acquire(1);
+}
+
+void eos_net_release(void) {
+    clear_csr(mstatus, MSTATUS_MIE);
+    if (!net_state_next_cnt && net_state_next_buf) {
+        eos_bufq_push(&net_buf_q, net_state_next_buf);
+        net_state_next_buf = NULL;
+    }
+    set_csr(mstatus, MSTATUS_MIE);
+}
+
+unsigned char *eos_net_alloc(void) {
+    unsigned char *ret = NULL;
+
+    while (!ret) {
+        clear_csr(mstatus, MSTATUS_MIE);
+        if (net_state_next_buf) {
+            ret = net_state_next_buf;
+            net_state_next_buf = NULL;
+        } else {
+            asm volatile ("wfi");
+        }
+        set_csr(mstatus, MSTATUS_MIE);
+    }
+
+    return ret;
+}
+
+void eos_net_free(unsigned char *buffer, unsigned char more) {
+    uint8_t do_release = 1;
+
+    clear_csr(mstatus, MSTATUS_MIE);
+    if ((more || net_state_next_cnt) && (net_state_next_buf == NULL)) {
+        net_state_next_buf = buffer;
+    } else {
+        if ((net_state_flags & NET_STATE_FLAG_RUN) && (net_state_flags & NET_STATE_FLAG_CTS)) {
+            do_release = net_xchg_next(buffer);
+        }
+        if (do_release) {
+            eos_bufq_push(&net_buf_q, buffer);
+        }
+    }
+    set_csr(mstatus, MSTATUS_MIE);
+}
+
+static int net_xchg(unsigned char *type, unsigned char *buffer, uint16_t *len, unsigned char flags) {
+    int rv = EOS_OK;
+    int _sync = 0;
+    unsigned char _type = *type;
+    uint16_t _len = *len;
+    uint8_t spi_dev = EOS_SPI_DEV_NET;
+
+    if (flags & EOS_NET_FLAG_ONEW) _type |= EOS_NET_MTYPE_FLAG_ONEW;
+    if (flags & EOS_NET_FLAG_REPL) _type |= EOS_NET_MTYPE_FLAG_REPL;
+    if (flags & EOS_NET_FLAG_SYNC) _sync = 1;
+
+    clear_csr(mstatus, MSTATUS_MIE);
+    if ((flags & EOS_NET_FLAG_ONEW) && !(net_state_flags & NET_STATE_FLAG_RUN)) _sync = 1;
+
+    if (_sync && !(net_state_flags & NET_STATE_FLAG_RUN)) {
+        int _rv;
+
+        set_csr(mstatus, MSTATUS_MIE);
+        spi_dev = eos_spi_dev();
+        _rv = eos_spi_deselect();
+        if (_rv) return _rv;
+        clear_csr(mstatus, MSTATUS_MIE);
+    }
+
+    if (_sync) {
+        net_pause();
+        while (!(net_state_flags & NET_STATE_FLAG_CTS)) {
+            asm volatile ("wfi");
+            set_csr(mstatus, MSTATUS_MIE);
+            clear_csr(mstatus, MSTATUS_MIE);
+        }
+        if (flags & EOS_NET_FLAG_SYNC) {
+            net_state_flags |= NET_STATE_FLAG_SYNC;
+        }
+        net_xchg_start(_type, buffer, _len);
+        if (flags & EOS_NET_FLAG_SYNC) {
+            if (flags & EOS_NET_FLAG_REPL) {
+                while (!(net_state_flags & NET_STATE_FLAG_CTS)) {
+                    asm volatile ("wfi");
+                    set_csr(mstatus, MSTATUS_MIE);
+                    clear_csr(mstatus, MSTATUS_MIE);
+                }
+                net_xchg_start(0, buffer, 0);
+            }
+            while (net_state_flags & NET_STATE_FLAG_XCHG) {
+                asm volatile ("wfi");
+                set_csr(mstatus, MSTATUS_MIE);
+                clear_csr(mstatus, MSTATUS_MIE);
+            }
+            net_state_flags &= ~NET_STATE_FLAG_SYNC;
+            *type = net_state_type;
+            *len = net_state_len_rx;
+        }
+        net_resume();
+    } else {
+        if ((net_state_flags & NET_STATE_FLAG_RUN) && (net_state_flags & NET_STATE_FLAG_CTS)) {
+            net_xchg_start(_type, buffer, _len);
+        } else {
+            rv = eos_msgq_push(&net_send_q, _type, buffer, _len);
+            if (rv) eos_bufq_push(&net_buf_q, buffer);
+        }
+    }
+
+    set_csr(mstatus, MSTATUS_MIE);
+    if (spi_dev != EOS_SPI_DEV_NET) eos_spi_select(spi_dev);
+
+    return rv;
+}
+
+int eos_net_xchg(unsigned char *type, unsigned char *buffer, uint16_t *len) {
+    return net_xchg(type, buffer, len, (EOS_NET_FLAG_ONEW | EOS_NET_FLAG_SYNC | EOS_NET_FLAG_REPL));
+}
+
+int eos_net_send(unsigned char type, unsigned char *buffer, uint16_t len) {
+    return net_xchg(&type, buffer, &len, (EOS_NET_FLAG_ONEW | EOS_NET_FLAG_SYNC));
+}
+
+int eos_net_send_async(unsigned char type, unsigned char *buffer, uint16_t len, unsigned char more) {
+    return net_xchg(&type, buffer, &len, more ? EOS_NET_FLAG_ONEW : 0);
+}
+
+int _eos_net_send(unsigned char type, unsigned char *buffer, uint16_t len, unsigned char async, unsigned char more) {
+    if (async) {
+        eos_net_send_async(type, buffer, len, more);
+    } else {
+        eos_net_send(type, buffer, len);
+    }
+}
diff --git a/fw/fe310/eos/soc/net.h b/fw/fe310/eos/soc/net.h
new file mode 100644
index 0000000..79caf4b
--- /dev/null
+++ b/fw/fe310/eos/soc/net.h
@@ -0,0 +1,47 @@
+#include <stdint.h>
+#include "event.h"
+
+/* common */
+#define EOS_NET_MTU                 1500
+#define EOS_NET_SIZE_BUF            EOS_NET_MTU
+
+#define EOS_NET_MTYPE_SOCK          1
+#define EOS_NET_MTYPE_RNG         	3
+#define EOS_NET_MTYPE_POWER         4
+
+#define EOS_NET_MTYPE_WIFI          5
+#define EOS_NET_MTYPE_CELL          6
+#define EOS_NET_MTYPE_SIP           7
+#define EOS_NET_MTYPE_APP           8
+
+#define EOS_NET_MAX_MTYPE           8
+
+#define EOS_NET_MTYPE_FLAG_ONEW     0x40
+#define EOS_NET_MTYPE_FLAG_REPL     0x80
+#define EOS_NET_MTYPE_FLAG_MASK     0xc0
+
+/* fe310 specific */
+#define EOS_NET_SIZE_BUFQ           2
+
+#define EOS_NET_FLAG_ONEW           0x1
+#define EOS_NET_FLAG_SYNC           0x2
+#define EOS_NET_FLAG_REPL           0x4
+
+int eos_net_init(uint8_t wakeup_cause);
+int eos_net_run(uint8_t wakeup_cause);
+void eos_net_start(void);
+void eos_net_stop(void);
+int eos_net_sleep(uint32_t timeout);
+
+void eos_net_bad_handler(unsigned char type, unsigned char *buffer, uint16_t len);
+void eos_net_set_handler(unsigned char type, eos_evt_handler_t handler);
+void eos_net_acquire_for_evt(unsigned char type, char acq);
+
+void eos_net_acquire(void);
+void eos_net_release(void);
+unsigned char *eos_net_alloc(void);
+void eos_net_free(unsigned char *buffer, unsigned char more);
+int eos_net_xchg(unsigned char *type, unsigned char *buffer, uint16_t *len);
+int eos_net_send(unsigned char type, unsigned char *buffer, uint16_t len);
+int eos_net_send_async(unsigned char type, unsigned char *buffer, uint16_t len, unsigned char more);
+int _eos_net_send(unsigned char type, unsigned char *buffer, uint16_t len, unsigned char async, unsigned char more);
diff --git a/fw/fe310/eos/soc/pwr.c b/fw/fe310/eos/soc/pwr.c
new file mode 100644
index 0000000..802e593
--- /dev/null
+++ b/fw/fe310/eos/soc/pwr.c
@@ -0,0 +1,133 @@
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "encoding.h"
+#include "platform.h"
+
+#include "eos.h"
+#include "event.h"
+#include "timer.h"
+#include "spi.h"
+#include "spi_dev.h"
+#include "net.h"
+#include "lcd.h"
+#include "eve/eve.h"
+
+#include "pwr.h"
+
+#define PWR_RTC_SCALE   15
+#define PWR_RTC_SFREQ   (EOS_TIMER_RTC_FREQ >> PWR_RTC_SCALE)
+
+static eos_evt_handler_t evt_handler[EOS_PWR_MAX_MTYPE];
+static unsigned char power_btn_down;
+
+int eos_pwr_init(uint8_t wakeup_cause) {
+    AON_REG(AON_PMUKEY) = 0x51F15E;
+    AON_REG(AON_PMUIE) = 0x5;
+
+    AON_REG(AON_RTCCMP) = 0xFFFFFFFF;
+    AON_REG(AON_RTCCFG) = PWR_RTC_SCALE;
+    AON_REG(AON_RTCHI) = 0;
+    AON_REG(AON_RTCLO) = 0;
+
+    return EOS_OK;
+}
+
+uint8_t eos_pwr_wakeup_cause(void) {
+    return AON_REG(AON_PMUCAUSE) & 0xff;
+}
+
+uint8_t eos_pwr_reset_cause(void) {
+    return (AON_REG(AON_PMUCAUSE) >> 8) & 0xff;
+}
+
+int eos_pwr_sleep(void) {
+    int rv;
+
+    rv = eos_lcd_sleep();
+    if (rv) return rv;
+
+    eos_spi_select(EOS_SPI_DEV_EVE);
+    eve_pwr_sleep();
+    eos_spi_deselect();
+
+    rv = eos_net_sleep(1000);
+    if (rv) return rv;
+
+    AON_REG(AON_PMUKEY) = 0x51F15E;
+    AON_REG(AON_PMUSLEEP) = 1;
+
+    return EOS_OK;
+}
+
+void eos_pwr_wake_at(uint32_t msec) {
+    uint32_t pmuie;
+
+    AON_REG(AON_RTCCFG) |= AON_RTCCFG_ENALWAYS;
+    AON_REG(AON_RTCCMP) = msec * PWR_RTC_SFREQ / 1000;
+
+    pmuie = AON_REG(AON_PMUIE) | 0x2;
+    AON_REG(AON_PMUKEY) = 0x51F15E;
+    AON_REG(AON_PMUIE) = pmuie;
+}
+
+void eos_pwr_wake_disable(void) {
+    uint32_t pmuie;
+
+    AON_REG(AON_RTCCMP) = 0xFFFFFFFF;
+    AON_REG(AON_RTCCFG) &= ~AON_RTCCFG_ENALWAYS;
+    AON_REG(AON_RTCHI) = 0;
+    AON_REG(AON_RTCLO) = 0;
+
+    pmuie = AON_REG(AON_PMUIE) & ~0x2;
+    AON_REG(AON_PMUKEY) = 0x51F15E;
+    AON_REG(AON_PMUIE) = pmuie;
+}
+
+static void pwr_handle_msg(unsigned char type, unsigned char *buffer, uint16_t len) {
+    unsigned char mtype;
+
+    if ((buffer == NULL) || (len < 1)) {
+        eos_net_bad_handler(type, buffer, len);
+        return;
+    }
+
+    mtype = buffer[0];
+    if ((mtype < EOS_PWR_MAX_MTYPE) && evt_handler[mtype]) {
+        evt_handler[mtype](mtype, buffer, len);
+    } else {
+        eos_net_bad_handler(type, buffer, len);
+    }
+}
+
+static void pwr_handle_btn(unsigned char type, unsigned char *buffer, uint16_t len) {
+    unsigned char level = buffer[1];
+
+    eos_net_free(buffer, 0);
+    if (!level) {
+        power_btn_down = 1;
+        return;
+    }
+    if (!power_btn_down) return;
+
+    eos_pwr_sleep();
+}
+
+void eos_pwr_netinit(void) {
+    int i;
+
+    for (i=0; i<EOS_PWR_MAX_MTYPE; i++) {
+        evt_handler[i] = NULL;
+    }
+    eos_net_set_handler(EOS_NET_MTYPE_POWER, pwr_handle_msg);
+    eos_pwr_set_handler(EOS_PWR_MTYPE_BUTTON, pwr_handle_btn);
+}
+
+void eos_pwr_set_handler(unsigned char mtype, eos_evt_handler_t handler) {
+    if (mtype < EOS_PWR_MAX_MTYPE) evt_handler[mtype] = handler;
+}
+
+eos_evt_handler_t eos_pwr_get_handler(unsigned char mtype) {
+    if (mtype < EOS_PWR_MAX_MTYPE) return evt_handler[mtype];
+    return NULL;
+}
diff --git a/fw/fe310/eos/soc/pwr.h b/fw/fe310/eos/soc/pwr.h
new file mode 100644
index 0000000..264436b
--- /dev/null
+++ b/fw/fe310/eos/soc/pwr.h
@@ -0,0 +1,25 @@
+#include <stdint.h>
+#include "event.h"
+
+#define EOS_PWR_MTYPE_BUTTON    1
+
+#define EOS_PWR_MAX_MTYPE       2
+
+#define EOS_PWR_WAKE_RST        0
+#define EOS_PWR_WAKE_RTC        1
+#define EOS_PWR_WAKE_BTN        2
+
+#define EOS_PWR_RST_PWRON       0
+#define EOS_PWR_RST_EXT         1
+#define EOS_PWR_RST_WDOG        2
+
+int eos_pwr_init(uint8_t wakeup_cause);
+uint8_t eos_pwr_wakeup_cause(void);
+uint8_t eos_pwr_reset_cause(void);
+int eos_pwr_sleep(void);
+void eos_pwr_wake_at(uint32_t msec);
+void eos_pwr_wake_disable(void);
+
+void eos_pwr_netinit(void);
+void eos_pwr_set_handler(unsigned char mtype, eos_evt_handler_t handler);
+eos_evt_handler_t eos_pwr_get_handler(unsigned char mtype);
\ No newline at end of file
diff --git a/fw/fe310/eos/soc/spi.c b/fw/fe310/eos/soc/spi.c
new file mode 100644
index 0000000..05c9448
--- /dev/null
+++ b/fw/fe310/eos/soc/spi.c
@@ -0,0 +1,350 @@
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "encoding.h"
+#include "platform.h"
+
+#include "eos.h"
+#include "msgq.h"
+#include "interrupt.h"
+#include "event.h"
+
+#include "board.h"
+
+#include "spi.h"
+#include "spi_priv.h"
+
+#define SPI_MODE0               0x00
+#define SPI_MODE1               0x01
+#define SPI_MODE2               0x02
+#define SPI_MODE3               0x03
+
+#define SPI_FLAG_XCHG           0x10
+
+#define MIN(X, Y)               (((X) < (Y)) ? (X) : (Y))
+#define MAX(X, Y)               (((X) > (Y)) ? (X) : (Y))
+
+static uint8_t spi_cspin;
+static volatile uint8_t spi_state_flags;
+static unsigned char spi_evt;
+static unsigned char spi_in_xchg;
+
+static uint32_t spi_state_len = 0;
+static uint32_t spi_state_idx_tx = 0;
+static uint32_t spi_state_idx_rx = 0;
+static unsigned char *spi_state_buf = NULL;
+
+static eos_evt_handler_t evt_handler[EOS_SPI_MAX_EVT];
+
+static void spi_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) {
+    unsigned char idx = (type & ~EOS_EVT_MASK) - 1;
+    if (idx < EOS_SPI_MAX_EVT) {
+        evt_handler[idx](type, buffer, len);
+    } else {
+        eos_evtq_bad_handler(type, buffer, len);
+    }
+}
+
+int eos_spi_init(uint8_t wakeup_cause) {
+    int i;
+
+    for (i=0; i<EOS_SPI_MAX_EVT; i++) {
+        evt_handler[i] = eos_evtq_bad_handler;
+    }
+    eos_evtq_set_handler(EOS_EVT_SPI, spi_handle_evt);
+    eos_intr_set(INT_SPI1_BASE, IRQ_PRIORITY_SPI_XCHG, NULL);
+
+    GPIO_REG(GPIO_OUTPUT_VAL)   &= ~(1 << IOF_SPI1_SCK);
+    GPIO_REG(GPIO_OUTPUT_VAL)   |=  (1 << IOF_SPI1_MOSI);
+
+    GPIO_REG(GPIO_INPUT_EN)     &= ~(1 << IOF_SPI1_SCK);
+    GPIO_REG(GPIO_OUTPUT_EN)    |=  (1 << IOF_SPI1_SCK);
+
+    GPIO_REG(GPIO_INPUT_EN)     &= ~(1 << IOF_SPI1_MOSI);
+    GPIO_REG(GPIO_OUTPUT_EN)    |=  (1 << IOF_SPI1_MOSI);
+
+    GPIO_REG(GPIO_INPUT_EN)     |=  (1 << IOF_SPI1_MISO);
+    GPIO_REG(GPIO_OUTPUT_EN)    &= ~(1 << IOF_SPI1_MISO);
+
+    SPI1_REG(SPI_REG_SCKMODE) = SPI_MODE0;
+    SPI1_REG(SPI_REG_FMT) = SPI_FMT_PROTO(SPI_PROTO_S) |
+      SPI_FMT_ENDIAN(SPI_ENDIAN_MSB) |
+      SPI_FMT_DIR(SPI_DIR_RX) |
+      SPI_FMT_LEN(8);
+
+    GPIO_REG(GPIO_IOF_SEL)      &= ~SPI_IOF_MASK;
+    GPIO_REG(GPIO_IOF_EN)       |=  SPI_IOF_MASK;
+
+    // There is no way here to change the CS polarity.
+    // SPI1_REG(SPI_REG_CSDEF) = 0xFFFF;
+    return EOS_OK;
+}
+
+void eos_spi_start(uint16_t div, uint8_t csid, uint8_t cspin, unsigned char evt) {
+    spi_state_flags = 0;
+    spi_evt = evt;
+    SPI1_REG(SPI_REG_SCKDIV) = div;
+    SPI1_REG(SPI_REG_CSID) = csid;
+    if (csid != SPI_CSID_NONE) {
+        SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO;
+    } else {
+        spi_cspin = cspin;
+        SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_OFF;
+    }
+    eos_intr_set_handler(INT_SPI1_BASE, eos_spi_handle_xchg);
+}
+
+void eos_spi_stop(void) {
+    eos_spi_flush();
+    eos_intr_set_handler(INT_SPI1_BASE, NULL);
+    spi_evt = 0;
+}
+
+void eos_spi_set_handler(unsigned char evt, eos_evt_handler_t handler) {
+    if (handler == NULL) handler = eos_evtq_bad_handler;
+    if (evt && (evt <= EOS_SPI_MAX_EVT)) evt_handler[evt - 1] = handler;
+}
+
+void _eos_spi_xchg_init(unsigned char *buffer, uint16_t len, uint8_t flags) {
+    spi_state_flags &= 0xF0;
+    spi_state_flags |= (SPI_FLAG_XCHG | flags);
+    spi_state_buf = buffer;
+    spi_state_len = len;
+    spi_state_idx_tx = 0;
+    spi_state_idx_rx = 0;
+}
+
+static void spi_xchg_finish(void) {
+    uint8_t done = 0;
+
+    while (!done) {
+        clear_csr(mstatus, MSTATUS_MIE);
+        done = !(spi_state_flags & SPI_FLAG_XCHG);
+        if (!done) asm volatile ("wfi");
+        set_csr(mstatus, MSTATUS_MIE);
+    }
+    spi_in_xchg = 0;
+}
+
+void eos_spi_xchg(unsigned char *buffer, uint16_t len, uint8_t flags) {
+    if (spi_in_xchg) spi_xchg_finish();
+
+    spi_in_xchg = 1;
+    _eos_spi_xchg_init(buffer, len, flags);
+
+    eos_spi_cs_set();
+    SPI1_REG(SPI_REG_TXCTRL) = SPI_TXWM(SPI_SIZE_WM);
+    SPI1_REG(SPI_REG_IE) = SPI_IP_TXWM;
+}
+
+void eos_spi_handle_xchg(void) {
+    int i;
+    uint16_t sz_chunk = MIN(spi_state_len - spi_state_idx_tx, SPI_SIZE_CHUNK);
+
+    for (i=0; i<sz_chunk; i++) {
+        volatile uint32_t x = SPI1_REG(SPI_REG_TXFIFO);
+        if (x & SPI_TXFIFO_FULL) break;
+        SPI1_REG(SPI_REG_TXFIFO) = spi_state_buf[spi_state_idx_tx+i];
+    }
+    spi_state_idx_tx += i;
+
+    for (i=0; i<spi_state_idx_tx - spi_state_idx_rx; i++) {
+        volatile uint32_t x = SPI1_REG(SPI_REG_RXFIFO);
+        if (x & SPI_RXFIFO_EMPTY) break;
+        spi_state_buf[spi_state_idx_rx+i] = x & 0xFF;
+    }
+    spi_state_idx_rx += i;
+
+    if (spi_state_idx_tx == spi_state_len) {
+        if ((spi_state_idx_rx == spi_state_len) || (spi_state_flags & EOS_SPI_FLAG_TX)) {
+            spi_state_flags &= ~SPI_FLAG_XCHG;
+            if (!(spi_state_flags & EOS_SPI_FLAG_MORE)) eos_spi_cs_clear();
+            SPI1_REG(SPI_REG_IE) = 0x0;
+            if (spi_evt) eos_evtq_push_isr(EOS_EVT_SPI | spi_evt, spi_state_buf, spi_state_len);
+        } else {
+            SPI1_REG(SPI_REG_RXCTRL) = SPI_RXWM(MIN(spi_state_len - spi_state_idx_rx - 1, SPI_SIZE_WM - 1));
+            SPI1_REG(SPI_REG_IE) = SPI_IP_RXWM;
+        }
+    }
+}
+
+void eos_spi_cs_set(void) {
+	/* cs low */
+    if (SPI1_REG(SPI_REG_CSMODE) == SPI_CSMODE_OFF) {
+        GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << spi_cspin);
+    } else {
+        SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD;
+    }
+}
+
+void eos_spi_cs_clear(void) {
+	/* cs high */
+    if (SPI1_REG(SPI_REG_CSMODE) == SPI_CSMODE_OFF) {
+        GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << spi_cspin);
+    } else {
+        SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO;
+    }
+}
+
+uint8_t eos_spi_xchg8(uint8_t data, uint8_t flags) {
+    volatile uint32_t x = 0;
+    uint8_t rx = !(flags & EOS_SPI_FLAG_TX);
+
+    spi_state_flags &= 0xF0;
+    spi_state_flags |= flags;
+
+    while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+    SPI1_REG(SPI_REG_TXFIFO) = data;
+
+    if (rx) {
+        while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+    }
+
+    return x & 0xFF;
+}
+
+uint16_t eos_spi_xchg16(uint16_t data, uint8_t flags) {
+    volatile uint32_t x = 0;
+    uint8_t rx = !(flags & EOS_SPI_FLAG_TX);
+    uint16_t r = 0;
+
+    spi_state_flags &= 0xF0;
+    spi_state_flags |= flags;
+
+    if (flags & EOS_SPI_FLAG_BSWAP) {
+        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x00FF);
+        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+        SPI1_REG(SPI_REG_TXFIFO) = (data & 0xFF00) >> 8;
+    } else {
+        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+        SPI1_REG(SPI_REG_TXFIFO) = (data & 0xFF00) >> 8;
+        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x00FF);
+    }
+
+    if (rx) {
+        if (flags & EOS_SPI_FLAG_BSWAP) {
+            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+            r |= (x & 0xFF);
+            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+            r |= (x & 0xFF) << 8;
+        } else {
+            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+            r |= (x & 0xFF) << 8;
+            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+            r |= (x & 0xFF);
+        }
+    }
+
+    return r;
+}
+
+uint32_t eos_spi_xchg24(uint32_t data, uint8_t flags) {
+    volatile uint32_t x = 0;
+    uint8_t rx = !(flags & EOS_SPI_FLAG_TX);
+    uint32_t r = 0;
+
+    spi_state_flags &= 0xF0;
+    spi_state_flags |= flags;
+
+    if (flags & EOS_SPI_FLAG_BSWAP) {
+        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x000000FF);
+        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x0000FF00) >> 8;
+        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x00FF0000) >> 16;
+    } else {
+        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x00FF0000) >> 16;
+        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x0000FF00) >> 8;
+        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x000000FF);
+    }
+
+    if (rx) {
+        if (flags & EOS_SPI_FLAG_BSWAP) {
+            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+            r |= (x & 0xFF);
+            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+            r |= (x & 0xFF) << 8;
+            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+            r |= (x & 0xFF) << 16;
+        } else {
+            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+            r |= (x & 0xFF) << 16;
+            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+            r |= (x & 0xFF) << 8;
+            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+            r |= (x & 0xFF);
+        }
+    }
+
+    return r;
+}
+
+uint32_t eos_spi_xchg32(uint32_t data, uint8_t flags) {
+    volatile uint32_t x = 0;
+    uint8_t rx = !(flags & EOS_SPI_FLAG_TX);
+    uint32_t r = 0;
+
+    spi_state_flags &= 0xF0;
+    spi_state_flags |= flags;
+
+    if (flags & EOS_SPI_FLAG_BSWAP) {
+        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x000000FF);
+        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x0000FF00) >> 8;
+        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x00FF0000) >> 16;
+        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+        SPI1_REG(SPI_REG_TXFIFO) = (data & 0xFF000000) >> 24;
+    } else {
+        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+        SPI1_REG(SPI_REG_TXFIFO) = (data & 0xFF000000) >> 24;
+        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x00FF0000) >> 16;
+        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x0000FF00) >> 8;
+        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x000000FF);
+    }
+
+    if (rx) {
+        if (flags & EOS_SPI_FLAG_BSWAP) {
+            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+            r |= (x & 0xFF);
+            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+            r |= (x & 0xFF) << 8;
+            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+            r |= (x & 0xFF) << 16;
+            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+            r |= (x & 0xFF) << 24;
+        } else {
+            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+            r |= (x & 0xFF) << 24;
+            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+            r |= (x & 0xFF) << 16;
+            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+            r |= (x & 0xFF) << 8;
+            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+            r |= (x & 0xFF);
+        }
+    }
+
+    return r;
+}
+
+void eos_spi_flush(void) {
+    volatile uint32_t x = 0;
+
+    if (spi_in_xchg) spi_xchg_finish();
+
+    SPI1_REG(SPI_REG_TXCTRL) = SPI_TXWM(1);
+    while (!x) {
+        if (SPI1_REG(SPI_REG_IP) & SPI_IP_TXWM) x = SPI1_REG(SPI_REG_RXFIFO) & SPI_RXFIFO_EMPTY;
+    }
+}
diff --git a/fw/fe310/eos/soc/spi.h b/fw/fe310/eos/soc/spi.h
new file mode 100644
index 0000000..a23a235
--- /dev/null
+++ b/fw/fe310/eos/soc/spi.h
@@ -0,0 +1,28 @@
+#include <stdint.h>
+#include "event.h"
+
+#define EOS_SPI_FLAG_TX         0x01
+#define EOS_SPI_FLAG_MORE       0x02
+#define EOS_SPI_FLAG_BSWAP      0x04
+
+#define EOS_SPI_EVT_SDC         1
+#define EOS_SPI_EVT_CAM         2
+
+#define EOS_SPI_MAX_EVT         2
+
+int eos_spi_init(uint8_t wakeup_cause);
+void eos_spi_start(uint16_t div, uint8_t csid, uint8_t cspin, unsigned char evt);
+void eos_spi_stop(void);
+void eos_spi_set_handler(unsigned char evt, eos_evt_handler_t handler);
+
+void _eos_spi_xchg_init(unsigned char *buffer, uint16_t len, uint8_t flags);
+void eos_spi_xchg(unsigned char *buffer, uint16_t len, uint8_t flags);
+void eos_spi_handle_xchg(void);
+
+void eos_spi_cs_set(void);
+void eos_spi_cs_clear(void);
+uint8_t eos_spi_xchg8(uint8_t data, uint8_t flags);
+uint16_t eos_spi_xchg16(uint16_t data, uint8_t flags);
+uint32_t eos_spi_xchg24(uint32_t data, uint8_t flags);
+uint32_t eos_spi_xchg32(uint32_t data, uint8_t flags);
+void eos_spi_flush(void);
diff --git a/fw/fe310/eos/soc/spi_cfg.h b/fw/fe310/eos/soc/spi_cfg.h
new file mode 100644
index 0000000..84ab8bb
--- /dev/null
+++ b/fw/fe310/eos/soc/spi_cfg.h
@@ -0,0 +1,37 @@
+#include <stdint.h>
+
+#define EOS_SPI_MAX_DEV         4
+
+typedef struct {
+    uint16_t div;
+    uint8_t csid;
+    uint8_t cspin;
+    unsigned char evt;
+} SPIConfig;
+
+static const SPIConfig spi_cfg[EOS_SPI_MAX_DEV] = {
+    {   // DEV_NET
+        .div = SPI_DIV_NET,
+        .csid = SPI_CSID_NET,
+        .cspin = SPI_CSPIN_NET,
+        .evt = 0,   // Not SPI event
+    },
+    {   // DEV_EVE
+        .div = SPI_DIV_EVE,
+        .csid = SPI_CSID_EVE,
+        .cspin = SPI_CSPIN_EVE,
+        .evt = 0,
+    },
+    {   // DEV_SDC
+        .div = SPI_DIV_SDC,
+        .csid = SPI_CSID_SDC,
+        .cspin = SPI_CSPIN_SDC,
+        .evt = EOS_SPI_EVT_SDC,
+    },
+    {   // DEV_CAM
+        .div = SPI_DIV_CAM,
+        .csid = SPI_CSID_CAM,
+        .cspin = SPI_CSPIN_CAM,
+        .evt = EOS_SPI_EVT_CAM,
+    },
+};
diff --git a/fw/fe310/eos/soc/spi_dev.c b/fw/fe310/eos/soc/spi_dev.c
new file mode 100644
index 0000000..c0c21b0
--- /dev/null
+++ b/fw/fe310/eos/soc/spi_dev.c
@@ -0,0 +1,97 @@
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "encoding.h"
+#include "platform.h"
+
+#include "eos.h"
+#include "msgq.h"
+#include "interrupt.h"
+#include "event.h"
+
+#include "board.h"
+
+#include "net.h"
+#include "spi.h"
+#include "spi_priv.h"
+#include "spi_cfg.h"
+#include "spi_dev.h"
+
+static uint8_t spi_dev;
+static uint8_t spi_lock;
+static uint16_t spi_div[EOS_SPI_MAX_DEV];
+
+int eos_spi_dev_init(uint8_t wakeup_cause) {
+    int i;
+
+    for (i=0; i<EOS_SPI_MAX_DEV; i++) {
+        spi_div[i] = spi_cfg[i].div;
+        if (spi_cfg[i].cspin != SPI_CSPIN_NONE) {
+            GPIO_REG(GPIO_OUTPUT_VAL)   |=  (1 << spi_cfg[i].cspin);
+
+            GPIO_REG(GPIO_INPUT_EN)     &= ~(1 << spi_cfg[i].cspin);
+            GPIO_REG(GPIO_OUTPUT_EN)    |=  (1 << spi_cfg[i].cspin);
+        }
+    }
+
+    return EOS_OK;
+}
+
+int eos_spi_select(unsigned char dev) {
+    if (spi_lock) return EOS_ERR_BUSY;
+
+    if (spi_dev == EOS_SPI_DEV_NET) {
+        eos_net_stop();
+    } else {
+        eos_spi_stop();
+    }
+
+    spi_dev = dev;
+    if (dev == EOS_SPI_DEV_NET) {
+        eos_net_start();
+    } else {
+        eos_spi_start(spi_div[dev], spi_cfg[dev].csid, spi_cfg[dev].cspin, spi_cfg[dev].evt);
+    }
+
+    return EOS_OK;
+}
+
+int eos_spi_deselect(void) {
+    if (spi_lock) return EOS_ERR_BUSY;
+    if (spi_dev == EOS_SPI_DEV_NET) return EOS_ERR;
+
+    eos_spi_stop();
+
+    spi_dev = EOS_SPI_DEV_NET;
+    eos_net_start();
+
+    return EOS_OK;
+}
+
+uint8_t eos_spi_dev(void) {
+    return spi_dev;
+}
+
+uint16_t eos_spi_div(unsigned char dev) {
+    return spi_div[dev];
+}
+
+uint8_t eos_spi_csid(unsigned char dev) {
+    return spi_cfg[dev].csid;
+}
+
+uint8_t eos_spi_cspin(unsigned char dev) {
+    return spi_cfg[dev].cspin;
+}
+
+void eos_spi_lock(void) {
+    spi_lock = 1;
+}
+
+void eos_spi_unlock(void) {
+    spi_lock = 0;
+}
+
+void eos_spi_set_div(unsigned char dev, uint16_t div) {
+    spi_div[dev] = div;
+}
diff --git a/fw/fe310/eos/soc/spi_dev.h b/fw/fe310/eos/soc/spi_dev.h
new file mode 100644
index 0000000..e801f7e
--- /dev/null
+++ b/fw/fe310/eos/soc/spi_dev.h
@@ -0,0 +1,19 @@
+#include <stdint.h>
+
+#define EOS_SPI_DEV_NET         0
+#define EOS_SPI_DEV_EVE         1
+#define EOS_SPI_DEV_SDC         2
+#define EOS_SPI_DEV_CAM         3
+
+int eos_spi_dev_init(uint8_t wakeup_cause);
+int eos_spi_select(unsigned char dev);
+int eos_spi_deselect(void);
+
+uint8_t eos_spi_dev(void);
+uint16_t eos_spi_div(unsigned char dev);
+uint8_t eos_spi_csid(unsigned char dev);
+uint8_t eos_spi_cspin(unsigned char dev);
+
+void eos_spi_lock(void);
+void eos_spi_unlock(void);
+void eos_spi_set_div(unsigned char dev, uint16_t div);
diff --git a/fw/fe310/eos/soc/spi_priv.h b/fw/fe310/eos/soc/spi_priv.h
new file mode 100644
index 0000000..72c2dae
--- /dev/null
+++ b/fw/fe310/eos/soc/spi_priv.h
@@ -0,0 +1,8 @@
+#include <stdint.h>
+
+#define SPI_CSID_NONE           1
+#define SPI_CSPIN_NONE          0xff
+
+/* DO NOT TOUCH THEESE */
+#define SPI_SIZE_CHUNK          4
+#define SPI_SIZE_WM             2
diff --git a/fw/fe310/eos/soc/timer.c b/fw/fe310/eos/soc/timer.c
new file mode 100644
index 0000000..91861a3
--- /dev/null
+++ b/fw/fe310/eos/soc/timer.c
@@ -0,0 +1,137 @@
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "encoding.h"
+#include "platform.h"
+
+#include "eos.h"
+#include "msgq.h"
+#include "event.h"
+#include "timer.h"
+
+#define MIN(X, Y)               (((X) < (Y)) ? (X) : (Y))
+#define MAX(X, Y)               (((X) > (Y)) ? (X) : (Y))
+
+static eos_timer_handler_t timer_handler[EOS_TIMER_MAX_ETYPE + 1];
+static uint64_t timer_next[EOS_TIMER_MAX_ETYPE + 1];
+
+static void timer_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) {
+    unsigned char idx = (type & ~EOS_EVT_MASK);
+
+    if (idx && (idx <= EOS_TIMER_MAX_ETYPE) && timer_handler[idx]) {
+        timer_handler[idx](type);
+    } else {
+        eos_evtq_bad_handler(type, buffer, len);
+    }
+}
+
+void _eos_timer_handle(void) {
+    int i;
+    volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME);
+    uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
+    uint64_t now = *mtime;
+    uint64_t next = 0;
+
+    for (i=0; i<=EOS_TIMER_MAX_ETYPE; i++) {
+        if (timer_next[i] && (timer_next[i] <= now)) {
+            timer_next[i] = 0;
+            if (i == 0) {
+                timer_handler[0](0);
+            } else {
+                eos_evtq_push_isr(EOS_EVT_TIMER | i, NULL, 0);
+            }
+        }
+        next = next && timer_next[i] ? MIN(next, timer_next[i]) : (next ? next : timer_next[i]);
+    }
+    *mtimecmp = next;
+    if (*mtimecmp == 0) clear_csr(mie, MIP_MTIP);
+}
+
+int eos_timer_init(uint8_t wakeup_cause) {
+    int i;
+    uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
+
+    clear_csr(mie, MIP_MTIP);
+    *mtimecmp = 0;
+    for (i=0; i<=EOS_TIMER_MAX_ETYPE; i++) {
+        timer_next[i] = 0;
+        timer_handler[i] = NULL;
+    }
+    eos_evtq_set_handler(EOS_EVT_TIMER, timer_handle_evt);
+
+    return EOS_OK;
+}
+
+void eos_timer_set_handler(unsigned char evt, eos_timer_handler_t handler) {
+    uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
+
+    if (!evt && (*mtimecmp != 0)) clear_csr(mie, MIP_MTIP);
+    timer_handler[evt] = handler;
+    if (!evt && (*mtimecmp != 0)) set_csr(mie, MIP_MTIP);
+}
+
+uint32_t eos_timer_get(unsigned char evt) {
+    volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME);
+    uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
+    uint64_t now;
+    uint32_t ret;
+
+    if (*mtimecmp != 0) clear_csr(mie, MIP_MTIP);
+    now = *mtime;
+    if (timer_next[evt]) {
+        ret = (timer_next[evt] > now) ? (timer_next[evt] - now) * 1000 / EOS_TIMER_RTC_FREQ : 0;
+    } else {
+        ret = EOS_TIMER_NONE;
+    }
+    if (*mtimecmp != 0) set_csr(mie, MIP_MTIP);
+
+    return ret;
+}
+
+void eos_timer_set(unsigned char evt, uint32_t msec) {
+    int i;
+    volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME);
+    uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
+    uint64_t tick = *mtime + msec * (uint64_t)EOS_TIMER_RTC_FREQ / 1000;
+    uint64_t next = 0;
+
+    if (*mtimecmp != 0) clear_csr(mie, MIP_MTIP);
+    timer_next[evt] = tick;
+    for (i=0; i<=EOS_TIMER_MAX_ETYPE; i++) {
+        next = next && timer_next[i] ? MIN(next, timer_next[i]) : (next ? next : timer_next[i]);
+    }
+    *mtimecmp = next;
+    if (*mtimecmp != 0) set_csr(mie, MIP_MTIP);
+}
+
+void eos_timer_clear(unsigned char evt) {
+    int i;
+    uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
+    uint64_t next = 0;
+
+    if (*mtimecmp != 0) clear_csr(mie, MIP_MTIP);
+    if (timer_next[evt]) {
+        timer_next[evt] = 0;
+        for (i=0; i<=EOS_TIMER_MAX_ETYPE; i++) {
+            next = next && timer_next[i] ? MIN(next, timer_next[i]) : (next ? next : timer_next[i]);
+        }
+        *mtimecmp = next;
+    }
+    if (*mtimecmp != 0) set_csr(mie, MIP_MTIP);
+}
+
+void eos_time_sleep(uint32_t msec) {
+    volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME);
+    uint64_t mtime0 = *mtime;
+
+    while ((*mtime - mtime0) < (msec * EOS_TIMER_RTC_FREQ / 1000 + 1));
+}
+
+uint64_t eos_time_get_tick(void) {
+    volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME);
+    return *mtime;
+}
+
+uint32_t eos_time_delta_ms(uint32_t tick) {
+    return ((uint32_t)eos_time_get_tick() - tick) * 1000 / EOS_TIMER_RTC_FREQ;
+}
diff --git a/fw/fe310/eos/soc/timer.h b/fw/fe310/eos/soc/timer.h
new file mode 100644
index 0000000..0309454
--- /dev/null
+++ b/fw/fe310/eos/soc/timer.h
@@ -0,0 +1,23 @@
+#include <stdint.h>
+
+#define EOS_TIMER_ETYPE_UI      1
+#define EOS_TIMER_ETYPE_ECP     2
+#define EOS_TIMER_ETYPE_USER    4
+
+#define EOS_TIMER_MAX_ETYPE     4
+
+#define EOS_TIMER_NONE          -1
+#define EOS_TIMER_RTC_FREQ      32768
+
+typedef void (*eos_timer_handler_t) (unsigned char);
+
+int eos_timer_init(uint8_t wakeup_cause);
+void eos_timer_set_handler(unsigned char evt, eos_timer_handler_t handler);
+
+uint32_t eos_timer_get(unsigned char evt);
+void eos_timer_set(unsigned char evt, uint32_t msec);
+void eos_timer_clear(unsigned char evt);
+
+void eos_time_sleep(uint32_t msec);
+uint64_t eos_time_get_tick(void);
+uint32_t eos_time_delta_ms(uint32_t tick);
diff --git a/fw/fe310/eos/soc/trap_entry.S b/fw/fe310/eos/soc/trap_entry.S
new file mode 100644
index 0000000..fb2b121
--- /dev/null
+++ b/fw/fe310/eos/soc/trap_entry.S
@@ -0,0 +1,554 @@
+#include "encoding.h"
+#include "sifive/bits.h"
+
+#define MCAUSE_INT        0x80000000
+#define MCAUSE_EXT        (MCAUSE_INT | IRQ_M_EXT)
+#define MCAUSE_TIMER      (MCAUSE_INT | IRQ_M_TIMER)
+
+#define PLIC_PRIORITY     0x0C000000
+#define PLIC_THRESHOLD    0x0C200000
+#define PLIC_CLAIM        0x0C200004
+
+#define PWM0_CTRL_ADDR    0x10015000
+#define PWM1_CTRL_ADDR    0x10025000
+#define PWM2_CTRL_ADDR    0x10035000
+#include "sifive/devices/pwm.h"
+
+#define GPIO_CTRL_ADDR    0x10012000
+#include "sifive/devices/gpio.h"
+
+#define SPI0_CTRL_ADDR    0x10014000
+#define SPI1_CTRL_ADDR    0x10024000
+#include "sifive/devices/spi.h"
+
+#define INT_PWM0_BASE     40
+#define INT_PWM1_BASE     44
+#define INT_PWM2_BASE     48
+
+#define I2S_MIC_BUF     (0*4)
+#define I2S_SPK_BUF     (1*4)
+#define I2S_FMT         (2*4)
+#define I2S_MODE        (3*4)
+#define I2S_MIC_WM      (4*4)
+#define I2S_SPK_WM      (5*4)
+#define I2S_MIC_EVT     (6*4)
+#define I2S_SPK_EVT     (7*4)
+#define I2S_MIC_CMP2    (8*4)
+#define I2S_MIC_CMP3    (9*4)
+#define I2S_SAMPLE      (10*4)
+
+#include "board.h"
+#include "irq_def.h"
+#include "evt_def.h"
+#include "i2s_def.h"
+#include "i2s_priv.h"
+#include "msgq_priv.h"
+
+  .section      .data.entry
+  .align 4
+
+.global eos_trap_entry
+eos_trap_entry:
+  addi sp, sp, -12*REGBYTES
+  STORE x8, 0*REGBYTES(sp)
+  STORE x9, 1*REGBYTES(sp)
+  STORE x18, 2*REGBYTES(sp)
+  STORE x19, 3*REGBYTES(sp)
+  STORE x20, 4*REGBYTES(sp)
+  STORE x21, 5*REGBYTES(sp)
+  STORE x22, 6*REGBYTES(sp)
+  STORE x23, 7*REGBYTES(sp)
+  STORE x24, 8*REGBYTES(sp)     # format:   0 - PCM16;  1 - ALAW
+  STORE x25, 9*REGBYTES(sp)     # mode:     0 - stereo; 1 - mono
+  STORE x26, 10*REGBYTES(sp)    # channel:  0 - left;   1 - right
+  STORE x27, 11*REGBYTES(sp)    # _eos_event_q addr
+
+  csrr x8, mcause
+  li x18, MCAUSE_EXT
+  bne x8, x18, handle_intr
+  li x18, PLIC_CLAIM
+  lw x9, 0(x18)
+  li x18, I2S_IRQ_WS_ID
+  beq x9, x18, i2s_handle_ws
+  li x18, I2S_IRQ_SD_ID
+  beq x9, x18, i2s_handle_sd
+  j handle_intr
+
+evtq_push:
+  la x9, _eos_event_q
+  lbu x18, MSGQ_OFF_IDXR(x9)
+  lbu x19, MSGQ_OFF_IDXW(x9)
+  lbu x20, MSGQ_OFF_SIZE(x9)
+
+  sub x18, x19, x18
+  andi x18, x18, 0xff
+  beq x18, x20, 0f
+
+  addi x20, x20, -1
+  and x20, x20, x19
+  li x18, MSGQ_ITEM_SIZE
+  mul x20, x20, x18
+  lw x21, MSGQ_OFF_ARRAY(x9)
+  add x21, x21, x20
+
+  addi x19, x19, 1
+  sb x19, MSGQ_OFF_IDXW(x9)
+  jalr x0, x22
+
+0:
+  mv x20, x0
+  jalr x0, x21
+
+i2s_handle_sd:
+  li x8, I2S_CTRL_ADDR_WS_SPK
+  lw x18, PWM_COUNT(x8)
+  lw x19, PWM_CMP3(x8)
+
+  # exit if too early
+  bltu x18, x19, i2s_sd_exit
+
+  la x27, _eos_i2s_drvr
+
+  # move CMPs for next channel and store channel bit to x26
+  lw x20, I2S_MIC_CMP2(x27)
+  lw x21, I2S_MIC_CMP3(x27) # 16-bit period
+
+  add x23, x19, x20
+  add x24, x23, x21
+  slli x20, x21, 1      # 32-bit period
+  slli x21, x20, 1      # 64-bit period
+  bltu x24, x21, 0f
+  neg x21, x21
+  add x23, x23, x21
+  add x24, x24, x21
+0:
+  li x26, 0
+  bltu x23, x20, 0f
+  li x26, 1
+0:
+  bltu x19, x20, 0f
+  neg x20, x20
+  li x18, PLIC_PRIORITY
+  sw x0, 4*I2S_IRQ_SD_ID(x18)
+0:
+  add x19, x19, x20
+
+  li x9, I2S_CTRL_ADDR_WS_MIC
+  sw x19, PWM_CMP3(x8)
+  sw x23, PWM_CMP2(x9)
+  sw x24, PWM_CMP3(x9)
+
+  lw x24, I2S_FMT(x27)
+  lw x25, I2S_MODE(x27)
+
+i2s_abuf_pop:
+  and x8, x25, x26
+  beqz x8, 0f
+
+  lw x8, I2S_SAMPLE(x27)
+  j i2s_sd_xchg
+0:
+  # pop from spk buf -> x8
+  lw x9, I2S_SPK_BUF(x27)
+  beqz x9, i2s_sd_xchg
+  lhu x18, I2S_ABUF_OFF_IDXR(x9)
+  lhu x19, I2S_ABUF_OFF_IDXW(x9)
+  lhu x20, I2S_ABUF_OFF_SIZE(x9)
+
+  beq x18, x19, 2f
+
+  addi x20, x20, -1
+  and x20, x20, x18
+  lw x21, I2S_ABUF_OFF_ARRAY(x9)
+  add x21, x21, x20
+  beqz x24, 0f
+  lbu x8, 0(x21)
+  addi x18, x18, 1
+  j 1f
+0:
+  lb x8, 0(x21)
+  lbu x20, 1(x21)
+  slli x8, x8, 8
+  or x8, x8, x20
+  addi x18, x18, 2
+1:
+  sh x18, I2S_ABUF_OFF_IDXR(x9)
+
+2:
+  li x21, 0xffff
+  sub x18, x19, x18
+  and x18, x18, x21
+
+  # check for push to event queue
+  lw x9, I2S_SPK_WM(x27)
+  bgtu x18, x9, i2s_decode
+
+  lw x9, I2S_SPK_EVT(x27)
+  beqz x9, i2s_decode
+  sw x0, I2S_SPK_EVT(x27)
+
+  # push to event queue
+  jal x22, evtq_push
+  beqz x21, i2s_decode
+  li x18, (EOS_EVT_I2S | EOS_I2S_ETYPE_SPK)
+  sb x18, MSGQ_ITEM_OFF_TYPE(x21)
+
+i2s_decode:
+  beqz x24, 3f
+  # aLaw decode -> x8
+  xori x8, x8, 0x55
+  andi x9, x8, 0x80
+  beqz x9, 0f
+  li x9, 1
+  slli x9, x9, 7
+  not x9, x9
+  and x8, x8, x9
+  li x9, -1
+0:
+  andi x18, x8, 0xf0
+  srli x18, x18, 4
+  addi x18, x18, 4
+
+  li x19, 4
+  beq x18, x19, 1f
+
+  andi x8, x8, 0x0f
+  addi x19, x18, -4
+  sll x8, x8, x19
+
+  li x19, 1
+  sll x19, x19, x18
+  or x8, x8, x19
+
+  li x19, 1
+  addi x18, x18, -5
+  sll x19, x19, x18
+  or x8, x8, x19
+  j 2f
+1:
+  slli x8, x8, 1
+  ori x8, x8, 1
+2:
+  beqz x9, 3f
+  mul x8, x8, x9
+3:
+  beqz x25, i2s_sd_xchg
+  sw x8, I2S_SAMPLE(x27)
+
+i2s_sd_xchg:
+  # read/write shift reg: x8 -> sr -> x8
+  li x18, GPIO_CTRL_ADDR
+  li x19, (0x1 << I2S_PIN_SD_IN)
+  li x20, (0x1 << I2S_PIN_SD_OUT)
+  li x21, (0x1 << I2S_PIN_CK_SR)
+  lw x22, GPIO_OUTPUT_VAL(x18)
+
+  lw x9, GPIO_OUTPUT_EN(x18)
+  or x9, x9, x20
+  sw x9, GPIO_OUTPUT_EN(x18)
+
+  not x20, x20
+  xor x22, x22, x21
+
+  li x23, 16
+0:
+  # write bit
+  li x9, 1
+  slli x9, x9, 15
+  and x9, x8, x9
+  slli x8, x8, 1
+#if I2S_PIN_SD_OUT > 15
+  slli x9, x9, (I2S_PIN_SD_OUT - 15)
+#else
+  srli x9, x9, (15 - I2S_PIN_SD_OUT)
+#endif
+  and x22, x22, x20
+  or x22, x22, x9
+
+  # read bit
+  lw x9, GPIO_INPUT_VAL(x18)
+  and x9, x9, x19
+  srli x9, x9, I2S_PIN_SD_IN
+  or x8, x8, x9
+
+  # 74HC595 ck low (I2S_PIN_CK_SR high)
+  xor x22, x22, x21
+  sw x22, GPIO_OUTPUT_VAL(x18)
+
+  # idle
+  li x9, I2S_IDLE_CYCLES
+1:
+  addi x9, x9, -1
+  bnez x9, 1b
+
+  # 74HC595 ck high (I2S_PIN_CK_SR low)
+  xor x22, x22, x21
+  sw x22, GPIO_OUTPUT_VAL(x18)
+
+  addi x23, x23, -1
+  bnez x23, 0b
+
+  # idle
+  li x9, I2S_IDLE_CYCLES
+1:
+  addi x9, x9, -1
+  bnez x9, 1b
+
+  # 74HC595 ck low (I2S_PIN_CK_SR high)
+  xor x22, x22, x21
+  sw x22, GPIO_OUTPUT_VAL(x18)
+
+  lw x9, GPIO_OUTPUT_EN(x18)
+  and x9, x9, x20
+  sw x9, GPIO_OUTPUT_EN(x18)
+
+  slli x8, x8, 16
+  srai x8, x8, 16
+
+i2s_encode:
+  beqz x24, i2s_abuf_push
+  # aLaw encode -> x8
+  li x18, 0x800
+  li x19, 7
+  bgez x8, 0f
+  neg x8, x8
+  lui x9, 0x80000
+  or x8, x8, x9
+0:
+  and x9, x8, x18
+  beq x9, x18, 1f
+  beqz x19, 1f
+  srli x18, x18, 1
+  addi x19, x19, -1
+  j 0b
+1:
+  mv x9, x19
+  bnez x9, 2f
+  addi x9, x9, 1
+2:
+  sra x8, x8, x9
+  li x9, 0x8000000f
+  and x8, x8, x9
+  slli x19, x19, 4
+  or x8, x8, x19
+  bgez x8, 3f
+  ori x8, x8, 0x80
+3:
+  xori x8, x8, 0x55
+  andi x8, x8, 0xff
+
+i2s_abuf_push:
+  # check channel
+  # bnez x26, i2s_sd_exit
+
+  # push to mic buf
+  lw x9, I2S_MIC_BUF(x27)
+  beqz x9, i2s_sd_exit
+  lhu x18, I2S_ABUF_OFF_IDXR(x9)
+  lhu x19, I2S_ABUF_OFF_IDXW(x9)
+  lhu x20, I2S_ABUF_OFF_SIZE(x9)
+  li x21, 0xffff
+
+  sub x18, x19, x18
+  and x18, x18, x21
+  beq x18, x20, 2f
+
+  addi x20, x20, -1
+  and x20, x20, x19
+  lw x21, I2S_ABUF_OFF_ARRAY(x9)
+  add x21, x21, x20
+  beqz x24, 0f
+  sb x8, 0(x21)
+  addi x19, x19, 1
+  addi x18, x18, 1
+  j 1f
+0:
+  sb x8, 1(x21)
+  srli x8, x8, 8
+  sb x8, 0(x21)
+  addi x19, x19, 2
+  addi x18, x18, 2
+1:
+  sh x19, I2S_ABUF_OFF_IDXW(x9)
+
+2:
+  # check for push to event queue
+  lw x9, I2S_MIC_WM(x27)
+  bltu x18, x9, i2s_sd_exit
+
+  lw x9, I2S_MIC_EVT(x27)
+  beqz x9, i2s_sd_exit
+  sw x0, I2S_MIC_EVT(x27)
+
+  # push to event queue
+  jal x22, evtq_push
+  beqz x21, i2s_sd_exit
+  li x18, (EOS_EVT_I2S | EOS_I2S_ETYPE_MIC)
+  sb x18, MSGQ_ITEM_OFF_TYPE(x21)
+
+i2s_sd_exit:
+  # complete
+  li x18, I2S_IRQ_SD_ID
+  li x19, PLIC_CLAIM
+  sw x18, 0(x19)
+
+  # exit
+  j trap_exit_data
+
+i2s_handle_ws:
+  # enable sd irq
+  li x18, PLIC_PRIORITY
+  li x19, IRQ_PRIORITY_I2S_SD
+  sw x19, 4*I2S_IRQ_SD_ID(x18)
+
+  # complete
+  li x18, I2S_IRQ_WS_ID
+  li x19, PLIC_CLAIM
+  sw x18, 0(x19)
+
+  # exit
+  j trap_exit_data
+
+.global _eos_i2s_start_pwm
+_eos_i2s_start_pwm:
+  addi sp, sp, -8*REGBYTES
+  STORE x8, 0*REGBYTES(sp)
+  STORE x9, 1*REGBYTES(sp)
+  STORE x18, 2*REGBYTES(sp)
+  STORE x19, 3*REGBYTES(sp)
+  STORE x20, 4*REGBYTES(sp)
+  STORE x21, 5*REGBYTES(sp)
+  STORE x22, 6*REGBYTES(sp)
+  STORE x23, 7*REGBYTES(sp)
+
+  li x18, I2S_CTRL_ADDR_CK
+  li x19, I2S_CTRL_ADDR_WS_MIC
+  li x20, I2S_CTRL_ADDR_WS_SPK
+  li x21, PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | I2S_PWM_SCALE_CK
+  li x22, PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | PWM_CFG_CMP2GANG
+  li x23, PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | PWM_CFG_CMP1GANG
+  sw x21, PWM_CFG(x18)
+  sw x22, PWM_CFG(x19)
+  sw x23, PWM_CFG(x20)
+
+  LOAD x8, 0*REGBYTES(sp)
+  LOAD x9, 1*REGBYTES(sp)
+  LOAD x18, 2*REGBYTES(sp)
+  LOAD x19, 3*REGBYTES(sp)
+  LOAD x20, 4*REGBYTES(sp)
+  LOAD x21, 5*REGBYTES(sp)
+  LOAD x22, 6*REGBYTES(sp)
+  LOAD x23, 7*REGBYTES(sp)
+  addi sp, sp, 8*REGBYTES
+
+  ret
+
+trap_exit_data:
+  # Remain in M-mode after mret
+  li x18, MSTATUS_MPP
+  csrs mstatus, x18
+
+  LOAD x8, 0*REGBYTES(sp)
+  LOAD x9, 1*REGBYTES(sp)
+  LOAD x18, 2*REGBYTES(sp)
+  LOAD x19, 3*REGBYTES(sp)
+  LOAD x20, 4*REGBYTES(sp)
+  LOAD x21, 5*REGBYTES(sp)
+  LOAD x22, 6*REGBYTES(sp)
+  LOAD x23, 7*REGBYTES(sp)
+  LOAD x24, 8*REGBYTES(sp)
+  LOAD x25, 9*REGBYTES(sp)
+  LOAD x26, 10*REGBYTES(sp)
+  LOAD x27, 11*REGBYTES(sp)
+  addi sp, sp, 12*REGBYTES
+
+  mret
+
+handle_intr:
+  lui x18,       %hi(trap_entry_text)
+  addi x18, x18, %lo(trap_entry_text)
+  jalr x0, x18
+
+  .section      .text.entry
+  .align 4
+
+trap_entry_text:
+  addi sp, sp, -20*REGBYTES
+
+  STORE x1, 0*REGBYTES(sp)
+  STORE x2, 1*REGBYTES(sp)
+  STORE x3, 2*REGBYTES(sp)
+  STORE x4, 3*REGBYTES(sp)
+  STORE x5, 4*REGBYTES(sp)
+  STORE x6, 5*REGBYTES(sp)
+  STORE x7, 6*REGBYTES(sp)
+  STORE x10, 7*REGBYTES(sp)
+  STORE x11, 8*REGBYTES(sp)
+  STORE x12, 9*REGBYTES(sp)
+  STORE x13, 10*REGBYTES(sp)
+  STORE x14, 11*REGBYTES(sp)
+  STORE x15, 12*REGBYTES(sp)
+  STORE x16, 13*REGBYTES(sp)
+  STORE x17, 14*REGBYTES(sp)
+  STORE x28, 15*REGBYTES(sp)
+  STORE x29, 16*REGBYTES(sp)
+  STORE x30, 17*REGBYTES(sp)
+  STORE x31, 18*REGBYTES(sp)
+
+  li x18, MCAUSE_TIMER
+  beq x8, x18, handle_timer
+  li x18, MCAUSE_EXT
+  beq x8, x18, handle_ext
+  mv a0, x8
+  call _exit
+
+handle_timer:
+  call _eos_timer_handle
+  j trap_exit_text
+
+handle_ext:
+  mv a0, x9
+  call eos_intr_handle
+  li x18, PLIC_CLAIM
+  sw a0, 0(x18)
+
+trap_exit_text:
+  # Remain in M-mode after mret
+  li t0, MSTATUS_MPP
+  csrs mstatus, t0
+
+  LOAD x1, 0*REGBYTES(sp)
+  LOAD x2, 1*REGBYTES(sp)
+  LOAD x3, 2*REGBYTES(sp)
+  LOAD x4, 3*REGBYTES(sp)
+  LOAD x5, 4*REGBYTES(sp)
+  LOAD x6, 5*REGBYTES(sp)
+  LOAD x7, 6*REGBYTES(sp)
+  LOAD x10, 7*REGBYTES(sp)
+  LOAD x11, 8*REGBYTES(sp)
+  LOAD x12, 9*REGBYTES(sp)
+  LOAD x13, 10*REGBYTES(sp)
+  LOAD x14, 11*REGBYTES(sp)
+  LOAD x15, 12*REGBYTES(sp)
+  LOAD x16, 13*REGBYTES(sp)
+  LOAD x17, 14*REGBYTES(sp)
+  LOAD x28, 15*REGBYTES(sp)
+  LOAD x29, 16*REGBYTES(sp)
+  LOAD x30, 17*REGBYTES(sp)
+  LOAD x31, 18*REGBYTES(sp)
+
+  LOAD x8, 20*REGBYTES(sp)
+  LOAD x9, 21*REGBYTES(sp)
+  LOAD x18, 22*REGBYTES(sp)
+  LOAD x19, 23*REGBYTES(sp)
+  LOAD x20, 24*REGBYTES(sp)
+  LOAD x21, 25*REGBYTES(sp)
+  LOAD x22, 26*REGBYTES(sp)
+  LOAD x23, 27*REGBYTES(sp)
+  LOAD x24, 28*REGBYTES(sp)
+  LOAD x25, 29*REGBYTES(sp)
+  LOAD x26, 30*REGBYTES(sp)
+  LOAD x27, 31*REGBYTES(sp)
+
+  addi sp, sp, 32*REGBYTES
+  mret
diff --git a/fw/fe310/eos/soc/uart.c b/fw/fe310/eos/soc/uart.c
new file mode 100644
index 0000000..30f76d9
--- /dev/null
+++ b/fw/fe310/eos/soc/uart.c
@@ -0,0 +1,114 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "encoding.h"
+#include "platform.h"
+#include "prci_driver.h"
+
+#include "eos.h"
+#include "interrupt.h"
+#include "event.h"
+
+#include "uart.h"
+
+static eos_uart_handler_t uart_handler[EOS_UART_MAX_ETYPE];
+
+static void uart_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) {
+    unsigned char idx = (type & ~EOS_EVT_MASK) - 1;
+
+    if ((idx < EOS_UART_MAX_ETYPE) && uart_handler[idx]) {
+        uart_handler[idx](type);
+    } else {
+        eos_evtq_bad_handler(type, buffer, len);
+    }
+}
+
+static void uart_handle_intr(void) {
+    if (UART0_REG(UART_REG_IP) & UART_IP_TXWM) {
+        UART0_REG(UART_REG_IE) &= ~UART_IP_TXWM;
+        eos_evtq_push_isr(EOS_EVT_UART | EOS_UART_ETYPE_TX, NULL, 0);
+    }
+    if (UART0_REG(UART_REG_IP) & UART_IP_RXWM) {
+        UART0_REG(UART_REG_IE) &= ~UART_IP_RXWM;
+        eos_evtq_push_isr(EOS_EVT_UART | EOS_UART_ETYPE_RX, NULL, 0);
+    }
+}
+
+int eos_uart_init(uint8_t wakeup_cause) {
+    int i;
+
+    for (i=0; i<EOS_UART_MAX_ETYPE; i++) {
+        uart_handler[i] = NULL;
+    }
+    eos_evtq_set_handler(EOS_EVT_UART, uart_handle_evt);
+    eos_intr_set(INT_UART0_BASE, IRQ_PRIORITY_UART, uart_handle_intr);
+
+    UART0_REG(UART_REG_TXCTRL)  |=  UART_TXEN;
+    UART0_REG(UART_REG_RXCTRL)  |=  UART_RXEN;
+
+    eos_uart_speed(EOS_UART_SPEED);
+    eos_uart_start();
+
+    return EOS_OK;
+}
+
+void eos_uart_start(void) {
+    GPIO_REG(GPIO_IOF_SEL)      &= ~IOF0_UART0_MASK;
+    GPIO_REG(GPIO_IOF_EN)       |=  IOF0_UART0_MASK;
+}
+
+void eos_uart_stop(void) {
+    GPIO_REG(GPIO_IOF_EN)       &= ~IOF0_UART0_MASK;
+}
+
+void eos_uart_speed(uint32_t baud_rate) {
+    UART0_REG(UART_REG_DIV) = PRCI_get_cpu_freq() / baud_rate - 1;
+}
+
+void eos_uart_set_handler(unsigned char type, eos_uart_handler_t handler) {
+    if (type && (type <= EOS_UART_MAX_ETYPE)) uart_handler[type - 1] = handler;
+}
+
+void eos_uart_txwm_set(uint8_t wm) {
+    UART0_REG(UART_REG_TXCTRL)  &= ~UART_TXWM(0xFFFF);
+    UART0_REG(UART_REG_TXCTRL)  |=  UART_TXWM(wm);
+    UART0_REG(UART_REG_IE)      |=  UART_IP_TXWM;
+}
+
+void eos_uart_txwm_clear(void) {
+    UART0_REG(UART_REG_IE)      &= ~UART_IP_TXWM;
+}
+
+void eos_uart_rxwm_set(uint8_t wm) {
+    UART0_REG(UART_REG_RXCTRL)  &= ~UART_RXWM(0xFFFF);
+    UART0_REG(UART_REG_RXCTRL)  |=  UART_RXWM(wm);
+    UART0_REG(UART_REG_IE)      |=  UART_IP_RXWM;
+}
+
+void eos_uart_rxwm_clear(void) {
+    UART0_REG(UART_REG_IE)      &= ~UART_IP_RXWM;
+}
+
+int eos_uart_putc(int c, char b) {
+    if (b) {
+        while (UART0_REG(UART_REG_TXFIFO) & 0x80000000);
+        UART0_REG(UART_REG_TXFIFO) = c & 0xff;
+    } else {
+        if (UART0_REG(UART_REG_TXFIFO) & 0x80000000) return EOS_ERR_FULL;
+        UART0_REG(UART_REG_TXFIFO) = c & 0xff;
+    }
+    return EOS_OK;
+}
+
+int eos_uart_getc(char b) {
+    volatile uint32_t r;
+
+    if (b) {
+        while ((r = UART0_REG(UART_REG_RXFIFO)) & 0x80000000);
+    } else {
+        r = UART0_REG(UART_REG_RXFIFO);
+        if (r & 0x80000000) return EOS_ERR_EMPTY;
+    }
+    return r & 0xff;
+}
\ No newline at end of file
diff --git a/fw/fe310/eos/soc/uart.h b/fw/fe310/eos/soc/uart.h
new file mode 100644
index 0000000..94999e6
--- /dev/null
+++ b/fw/fe310/eos/soc/uart.h
@@ -0,0 +1,24 @@
+#include <stdint.h>
+
+#define EOS_UART_ETYPE_TX       1
+#define EOS_UART_ETYPE_RX       2
+
+#define EOS_UART_MAX_ETYPE      2
+
+#define EOS_UART_SPEED          115200
+
+typedef void (*eos_uart_handler_t) (unsigned char);
+
+int eos_uart_init(uint8_t wakeup_cause);
+void eos_uart_start(void);
+void eos_uart_stop(void);
+void eos_uart_speed(uint32_t baud_rate);
+
+void eos_uart_set_handler(unsigned char type, eos_uart_handler_t handler);
+
+void eos_uart_txwm_set(uint8_t wm);
+void eos_uart_txwm_clear(void);
+void eos_uart_rxwm_set(uint8_t wm);
+void eos_uart_rxwm_clear(void);
+int eos_uart_putc(int c, char b);
+int eos_uart_getc(char b);
\ No newline at end of file
diff --git a/fw/fe310/eos/sock.c b/fw/fe310/eos/sock.c
deleted file mode 100644
index 7365c97..0000000
--- a/fw/fe310/eos/sock.c
+++ /dev/null
@@ -1,154 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-
-#include "eos.h"
-#include "event.h"
-#include "net.h"
-
-#include "sock.h"
-
-static eos_evt_handler_t evt_handler[EOS_SOCK_MAX_SOCK];
-
-static void sock_handle_msg(unsigned char type, unsigned char *buffer, uint16_t len) {
-    unsigned char sock;
-
-    if ((buffer == NULL) || (len < 2)) {
-        eos_net_bad_handler(type, buffer, len);
-        return;
-    }
-
-    sock = buffer[1];
-    if ((sock == 0) || (sock > EOS_SOCK_MAX_SOCK) || (evt_handler[sock - 1] == NULL)) {
-        eos_net_bad_handler(type, buffer, len);
-        return;
-    }
-
-    switch(buffer[0]) {
-        case EOS_SOCK_MTYPE_PKT:
-            evt_handler[sock - 1](type, buffer, len);
-            break;
-        default:
-            eos_net_bad_handler(type, buffer, len);
-            break;
-    }
-}
-
-void eos_sock_netinit(void) {
-    int i;
-
-    for (i=0; i<EOS_SOCK_MAX_SOCK; i++) {
-        evt_handler[i] = NULL;
-    }
-    eos_net_set_handler(EOS_NET_MTYPE_SOCK, sock_handle_msg);
-}
-
-void eos_sock_set_handler(unsigned char sock, eos_evt_handler_t handler) {
-    if (sock && (sock <= EOS_SOCK_MAX_SOCK)) evt_handler[sock - 1] = handler;
-}
-
-eos_evt_handler_t eos_sock_get_handler(unsigned char sock) {
-    if (sock && (sock <= EOS_SOCK_MAX_SOCK)) return evt_handler[sock - 1];
-    return NULL;
-}
-
-int eos_sock_open_udp(eos_evt_handler_t handler, unsigned char *buffer) {
-    unsigned char type;
-    uint16_t len;
-    int do_release;
-    int rv, sock;
-
-    do_release = 0;
-    if (buffer == NULL) {
-        buffer = eos_net_alloc();
-        do_release = 1;
-    }
-
-    type = EOS_NET_MTYPE_SOCK;
-    len = 1;
-    buffer[0] = EOS_SOCK_MTYPE_OPEN_DGRAM;
-
-    rv = eos_net_xchg(&type, buffer, &len);
-    if (rv) return rv;
-
-    if (type != EOS_NET_MTYPE_SOCK) return EOS_ERR_NET;
-    if (len < 2) return EOS_ERR_SIZE;
-
-    sock = buffer[1];
-    if (sock == 0) return EOS_ERR_NET;
-
-    if (do_release) {
-        eos_net_free(buffer, 1);
-    }
-    eos_sock_set_handler(sock, handler);
-
-    return sock;
-}
-
-void eos_sock_close(unsigned char sock, unsigned char *buffer) {
-    int async;
-
-    async = 0;
-    if (buffer == NULL) {
-        buffer = eos_net_alloc();
-        async = 1;
-    }
-    buffer[0] = EOS_SOCK_MTYPE_CLOSE;
-    buffer[1] = sock;
-    _eos_net_send(EOS_NET_MTYPE_SOCK, buffer, 2, async, 1);
-    eos_sock_set_handler(sock, NULL);
-}
-
-static int sock_send(unsigned char sock, unsigned char *msg, uint16_t msg_len, EOSNetAddr *addr, unsigned char *buffer) {
-    buffer[0] = EOS_SOCK_MTYPE_PKT;
-    buffer[1] = sock;
-    buffer += 2;
-    memcpy(buffer, addr->host, sizeof(addr->host));
-    buffer += sizeof(addr->host);
-    buffer[0] = addr->port >> 8;
-    buffer[1] = addr->port;
-    buffer += sizeof(addr->port);
-    if (msg) {
-        if (msg_len + EOS_SOCK_SIZE_UDP_HDR > EOS_NET_MTU) return EOS_ERR_SIZE;
-        memcpy(buffer, msg, msg_len);
-    }
-
-    return EOS_OK;
-}
-
-int eos_sock_sendto(unsigned char sock, unsigned char *msg, size_t msg_len, EOSNetAddr *addr, unsigned char *buffer) {
-    int rv;
-
-    rv = sock_send(sock, msg, msg_len, addr, buffer);
-    if (rv) return rv;
-
-    return eos_net_send(EOS_NET_MTYPE_SOCK, buffer, msg_len + EOS_SOCK_SIZE_UDP_HDR);
-}
-
-int eos_sock_sendto_async(unsigned char sock, unsigned char *msg, size_t msg_len, EOSNetAddr *addr, unsigned char *buffer, unsigned char more) {
-    int rv;
-
-    rv = sock_send(sock, msg, msg_len, addr, buffer);
-    if (rv) return rv;
-
-    return eos_net_send_async(EOS_NET_MTYPE_SOCK, buffer, msg_len + EOS_SOCK_SIZE_UDP_HDR, more);
-}
-
-int eos_sock_recvfrom(unsigned char *buffer, uint16_t len, unsigned char *msg, size_t msg_size, EOSNetAddr *addr) {
-    if (len < EOS_SOCK_SIZE_UDP_HDR) return EOS_ERR_SIZE;
-
-    if (buffer[0] != EOS_SOCK_MTYPE_PKT) return EOS_ERR_NET;
-
-    buffer += 2;
-    memcpy(addr->host, buffer, sizeof(addr->host));
-    buffer += sizeof(addr->host);
-    addr->port  = (uint16_t)buffer[0] << 8;
-    addr->port |= (uint16_t)buffer[1];
-    buffer += sizeof(addr->port);
-    if (msg) {
-        if (msg_size < len - EOS_SOCK_SIZE_UDP_HDR) return EOS_ERR_SIZE;
-        memcpy(msg, buffer, len - EOS_SOCK_SIZE_UDP_HDR);
-    }
-
-    return EOS_OK;
-}
diff --git a/fw/fe310/eos/sock.h b/fw/fe310/eos/sock.h
deleted file mode 100644
index 5ef42e3..0000000
--- a/fw/fe310/eos/sock.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#include <stdint.h>
-#include "event.h"
-
-#define EOS_SOCK_MTYPE_PKT          0
-#define EOS_SOCK_MTYPE_OPEN_DGRAM   1
-#define EOS_SOCK_MTYPE_CLOSE        127
-
-#define EOS_SOCK_MAX_SOCK           2
-
-#define EOS_SOCK_SIZE_UDP_HDR       8
-
-#define EOS_IPv4_ADDR_SIZE          4
-
-typedef struct EOSNetAddr {
-    unsigned char host[EOS_IPv4_ADDR_SIZE];
-    uint16_t port;
-} EOSNetAddr;
-
-void eos_sock_netinit(void);
-void eos_sock_set_handler(unsigned char sock, eos_evt_handler_t handler);
-eos_evt_handler_t eos_sock_get_handler(unsigned char sock);
-
-int eos_sock_open_udp(eos_evt_handler_t handler, unsigned char *buffer);
-void eos_sock_close(unsigned char sock, unsigned char *buffer);
-
-int eos_sock_sendto(unsigned char sock, unsigned char *msg, size_t msg_len, EOSNetAddr *addr, unsigned char *buffer);
-int eos_sock_sendto_async(unsigned char sock, unsigned char *msg, size_t msg_len, EOSNetAddr *addr, unsigned char *buffer, unsigned char more);
-int eos_sock_recvfrom(unsigned char *buffer, uint16_t len, unsigned char *msg, size_t msg_size, EOSNetAddr *addr);
diff --git a/fw/fe310/eos/spi.c b/fw/fe310/eos/spi.c
deleted file mode 100644
index 05c9448..0000000
--- a/fw/fe310/eos/spi.c
+++ /dev/null
@@ -1,350 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-
-#include "encoding.h"
-#include "platform.h"
-
-#include "eos.h"
-#include "msgq.h"
-#include "interrupt.h"
-#include "event.h"
-
-#include "board.h"
-
-#include "spi.h"
-#include "spi_priv.h"
-
-#define SPI_MODE0               0x00
-#define SPI_MODE1               0x01
-#define SPI_MODE2               0x02
-#define SPI_MODE3               0x03
-
-#define SPI_FLAG_XCHG           0x10
-
-#define MIN(X, Y)               (((X) < (Y)) ? (X) : (Y))
-#define MAX(X, Y)               (((X) > (Y)) ? (X) : (Y))
-
-static uint8_t spi_cspin;
-static volatile uint8_t spi_state_flags;
-static unsigned char spi_evt;
-static unsigned char spi_in_xchg;
-
-static uint32_t spi_state_len = 0;
-static uint32_t spi_state_idx_tx = 0;
-static uint32_t spi_state_idx_rx = 0;
-static unsigned char *spi_state_buf = NULL;
-
-static eos_evt_handler_t evt_handler[EOS_SPI_MAX_EVT];
-
-static void spi_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) {
-    unsigned char idx = (type & ~EOS_EVT_MASK) - 1;
-    if (idx < EOS_SPI_MAX_EVT) {
-        evt_handler[idx](type, buffer, len);
-    } else {
-        eos_evtq_bad_handler(type, buffer, len);
-    }
-}
-
-int eos_spi_init(uint8_t wakeup_cause) {
-    int i;
-
-    for (i=0; i<EOS_SPI_MAX_EVT; i++) {
-        evt_handler[i] = eos_evtq_bad_handler;
-    }
-    eos_evtq_set_handler(EOS_EVT_SPI, spi_handle_evt);
-    eos_intr_set(INT_SPI1_BASE, IRQ_PRIORITY_SPI_XCHG, NULL);
-
-    GPIO_REG(GPIO_OUTPUT_VAL)   &= ~(1 << IOF_SPI1_SCK);
-    GPIO_REG(GPIO_OUTPUT_VAL)   |=  (1 << IOF_SPI1_MOSI);
-
-    GPIO_REG(GPIO_INPUT_EN)     &= ~(1 << IOF_SPI1_SCK);
-    GPIO_REG(GPIO_OUTPUT_EN)    |=  (1 << IOF_SPI1_SCK);
-
-    GPIO_REG(GPIO_INPUT_EN)     &= ~(1 << IOF_SPI1_MOSI);
-    GPIO_REG(GPIO_OUTPUT_EN)    |=  (1 << IOF_SPI1_MOSI);
-
-    GPIO_REG(GPIO_INPUT_EN)     |=  (1 << IOF_SPI1_MISO);
-    GPIO_REG(GPIO_OUTPUT_EN)    &= ~(1 << IOF_SPI1_MISO);
-
-    SPI1_REG(SPI_REG_SCKMODE) = SPI_MODE0;
-    SPI1_REG(SPI_REG_FMT) = SPI_FMT_PROTO(SPI_PROTO_S) |
-      SPI_FMT_ENDIAN(SPI_ENDIAN_MSB) |
-      SPI_FMT_DIR(SPI_DIR_RX) |
-      SPI_FMT_LEN(8);
-
-    GPIO_REG(GPIO_IOF_SEL)      &= ~SPI_IOF_MASK;
-    GPIO_REG(GPIO_IOF_EN)       |=  SPI_IOF_MASK;
-
-    // There is no way here to change the CS polarity.
-    // SPI1_REG(SPI_REG_CSDEF) = 0xFFFF;
-    return EOS_OK;
-}
-
-void eos_spi_start(uint16_t div, uint8_t csid, uint8_t cspin, unsigned char evt) {
-    spi_state_flags = 0;
-    spi_evt = evt;
-    SPI1_REG(SPI_REG_SCKDIV) = div;
-    SPI1_REG(SPI_REG_CSID) = csid;
-    if (csid != SPI_CSID_NONE) {
-        SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO;
-    } else {
-        spi_cspin = cspin;
-        SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_OFF;
-    }
-    eos_intr_set_handler(INT_SPI1_BASE, eos_spi_handle_xchg);
-}
-
-void eos_spi_stop(void) {
-    eos_spi_flush();
-    eos_intr_set_handler(INT_SPI1_BASE, NULL);
-    spi_evt = 0;
-}
-
-void eos_spi_set_handler(unsigned char evt, eos_evt_handler_t handler) {
-    if (handler == NULL) handler = eos_evtq_bad_handler;
-    if (evt && (evt <= EOS_SPI_MAX_EVT)) evt_handler[evt - 1] = handler;
-}
-
-void _eos_spi_xchg_init(unsigned char *buffer, uint16_t len, uint8_t flags) {
-    spi_state_flags &= 0xF0;
-    spi_state_flags |= (SPI_FLAG_XCHG | flags);
-    spi_state_buf = buffer;
-    spi_state_len = len;
-    spi_state_idx_tx = 0;
-    spi_state_idx_rx = 0;
-}
-
-static void spi_xchg_finish(void) {
-    uint8_t done = 0;
-
-    while (!done) {
-        clear_csr(mstatus, MSTATUS_MIE);
-        done = !(spi_state_flags & SPI_FLAG_XCHG);
-        if (!done) asm volatile ("wfi");
-        set_csr(mstatus, MSTATUS_MIE);
-    }
-    spi_in_xchg = 0;
-}
-
-void eos_spi_xchg(unsigned char *buffer, uint16_t len, uint8_t flags) {
-    if (spi_in_xchg) spi_xchg_finish();
-
-    spi_in_xchg = 1;
-    _eos_spi_xchg_init(buffer, len, flags);
-
-    eos_spi_cs_set();
-    SPI1_REG(SPI_REG_TXCTRL) = SPI_TXWM(SPI_SIZE_WM);
-    SPI1_REG(SPI_REG_IE) = SPI_IP_TXWM;
-}
-
-void eos_spi_handle_xchg(void) {
-    int i;
-    uint16_t sz_chunk = MIN(spi_state_len - spi_state_idx_tx, SPI_SIZE_CHUNK);
-
-    for (i=0; i<sz_chunk; i++) {
-        volatile uint32_t x = SPI1_REG(SPI_REG_TXFIFO);
-        if (x & SPI_TXFIFO_FULL) break;
-        SPI1_REG(SPI_REG_TXFIFO) = spi_state_buf[spi_state_idx_tx+i];
-    }
-    spi_state_idx_tx += i;
-
-    for (i=0; i<spi_state_idx_tx - spi_state_idx_rx; i++) {
-        volatile uint32_t x = SPI1_REG(SPI_REG_RXFIFO);
-        if (x & SPI_RXFIFO_EMPTY) break;
-        spi_state_buf[spi_state_idx_rx+i] = x & 0xFF;
-    }
-    spi_state_idx_rx += i;
-
-    if (spi_state_idx_tx == spi_state_len) {
-        if ((spi_state_idx_rx == spi_state_len) || (spi_state_flags & EOS_SPI_FLAG_TX)) {
-            spi_state_flags &= ~SPI_FLAG_XCHG;
-            if (!(spi_state_flags & EOS_SPI_FLAG_MORE)) eos_spi_cs_clear();
-            SPI1_REG(SPI_REG_IE) = 0x0;
-            if (spi_evt) eos_evtq_push_isr(EOS_EVT_SPI | spi_evt, spi_state_buf, spi_state_len);
-        } else {
-            SPI1_REG(SPI_REG_RXCTRL) = SPI_RXWM(MIN(spi_state_len - spi_state_idx_rx - 1, SPI_SIZE_WM - 1));
-            SPI1_REG(SPI_REG_IE) = SPI_IP_RXWM;
-        }
-    }
-}
-
-void eos_spi_cs_set(void) {
-	/* cs low */
-    if (SPI1_REG(SPI_REG_CSMODE) == SPI_CSMODE_OFF) {
-        GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << spi_cspin);
-    } else {
-        SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD;
-    }
-}
-
-void eos_spi_cs_clear(void) {
-	/* cs high */
-    if (SPI1_REG(SPI_REG_CSMODE) == SPI_CSMODE_OFF) {
-        GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << spi_cspin);
-    } else {
-        SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO;
-    }
-}
-
-uint8_t eos_spi_xchg8(uint8_t data, uint8_t flags) {
-    volatile uint32_t x = 0;
-    uint8_t rx = !(flags & EOS_SPI_FLAG_TX);
-
-    spi_state_flags &= 0xF0;
-    spi_state_flags |= flags;
-
-    while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
-    SPI1_REG(SPI_REG_TXFIFO) = data;
-
-    if (rx) {
-        while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
-    }
-
-    return x & 0xFF;
-}
-
-uint16_t eos_spi_xchg16(uint16_t data, uint8_t flags) {
-    volatile uint32_t x = 0;
-    uint8_t rx = !(flags & EOS_SPI_FLAG_TX);
-    uint16_t r = 0;
-
-    spi_state_flags &= 0xF0;
-    spi_state_flags |= flags;
-
-    if (flags & EOS_SPI_FLAG_BSWAP) {
-        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
-        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x00FF);
-        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
-        SPI1_REG(SPI_REG_TXFIFO) = (data & 0xFF00) >> 8;
-    } else {
-        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
-        SPI1_REG(SPI_REG_TXFIFO) = (data & 0xFF00) >> 8;
-        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
-        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x00FF);
-    }
-
-    if (rx) {
-        if (flags & EOS_SPI_FLAG_BSWAP) {
-            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
-            r |= (x & 0xFF);
-            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
-            r |= (x & 0xFF) << 8;
-        } else {
-            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
-            r |= (x & 0xFF) << 8;
-            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
-            r |= (x & 0xFF);
-        }
-    }
-
-    return r;
-}
-
-uint32_t eos_spi_xchg24(uint32_t data, uint8_t flags) {
-    volatile uint32_t x = 0;
-    uint8_t rx = !(flags & EOS_SPI_FLAG_TX);
-    uint32_t r = 0;
-
-    spi_state_flags &= 0xF0;
-    spi_state_flags |= flags;
-
-    if (flags & EOS_SPI_FLAG_BSWAP) {
-        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
-        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x000000FF);
-        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
-        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x0000FF00) >> 8;
-        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
-        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x00FF0000) >> 16;
-    } else {
-        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
-        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x00FF0000) >> 16;
-        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
-        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x0000FF00) >> 8;
-        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
-        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x000000FF);
-    }
-
-    if (rx) {
-        if (flags & EOS_SPI_FLAG_BSWAP) {
-            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
-            r |= (x & 0xFF);
-            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
-            r |= (x & 0xFF) << 8;
-            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
-            r |= (x & 0xFF) << 16;
-        } else {
-            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
-            r |= (x & 0xFF) << 16;
-            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
-            r |= (x & 0xFF) << 8;
-            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
-            r |= (x & 0xFF);
-        }
-    }
-
-    return r;
-}
-
-uint32_t eos_spi_xchg32(uint32_t data, uint8_t flags) {
-    volatile uint32_t x = 0;
-    uint8_t rx = !(flags & EOS_SPI_FLAG_TX);
-    uint32_t r = 0;
-
-    spi_state_flags &= 0xF0;
-    spi_state_flags |= flags;
-
-    if (flags & EOS_SPI_FLAG_BSWAP) {
-        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
-        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x000000FF);
-        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
-        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x0000FF00) >> 8;
-        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
-        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x00FF0000) >> 16;
-        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
-        SPI1_REG(SPI_REG_TXFIFO) = (data & 0xFF000000) >> 24;
-    } else {
-        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
-        SPI1_REG(SPI_REG_TXFIFO) = (data & 0xFF000000) >> 24;
-        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
-        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x00FF0000) >> 16;
-        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
-        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x0000FF00) >> 8;
-        while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
-        SPI1_REG(SPI_REG_TXFIFO) = (data & 0x000000FF);
-    }
-
-    if (rx) {
-        if (flags & EOS_SPI_FLAG_BSWAP) {
-            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
-            r |= (x & 0xFF);
-            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
-            r |= (x & 0xFF) << 8;
-            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
-            r |= (x & 0xFF) << 16;
-            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
-            r |= (x & 0xFF) << 24;
-        } else {
-            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
-            r |= (x & 0xFF) << 24;
-            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
-            r |= (x & 0xFF) << 16;
-            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
-            r |= (x & 0xFF) << 8;
-            while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
-            r |= (x & 0xFF);
-        }
-    }
-
-    return r;
-}
-
-void eos_spi_flush(void) {
-    volatile uint32_t x = 0;
-
-    if (spi_in_xchg) spi_xchg_finish();
-
-    SPI1_REG(SPI_REG_TXCTRL) = SPI_TXWM(1);
-    while (!x) {
-        if (SPI1_REG(SPI_REG_IP) & SPI_IP_TXWM) x = SPI1_REG(SPI_REG_RXFIFO) & SPI_RXFIFO_EMPTY;
-    }
-}
diff --git a/fw/fe310/eos/spi.h b/fw/fe310/eos/spi.h
deleted file mode 100644
index a23a235..0000000
--- a/fw/fe310/eos/spi.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#include <stdint.h>
-#include "event.h"
-
-#define EOS_SPI_FLAG_TX         0x01
-#define EOS_SPI_FLAG_MORE       0x02
-#define EOS_SPI_FLAG_BSWAP      0x04
-
-#define EOS_SPI_EVT_SDC         1
-#define EOS_SPI_EVT_CAM         2
-
-#define EOS_SPI_MAX_EVT         2
-
-int eos_spi_init(uint8_t wakeup_cause);
-void eos_spi_start(uint16_t div, uint8_t csid, uint8_t cspin, unsigned char evt);
-void eos_spi_stop(void);
-void eos_spi_set_handler(unsigned char evt, eos_evt_handler_t handler);
-
-void _eos_spi_xchg_init(unsigned char *buffer, uint16_t len, uint8_t flags);
-void eos_spi_xchg(unsigned char *buffer, uint16_t len, uint8_t flags);
-void eos_spi_handle_xchg(void);
-
-void eos_spi_cs_set(void);
-void eos_spi_cs_clear(void);
-uint8_t eos_spi_xchg8(uint8_t data, uint8_t flags);
-uint16_t eos_spi_xchg16(uint16_t data, uint8_t flags);
-uint32_t eos_spi_xchg24(uint32_t data, uint8_t flags);
-uint32_t eos_spi_xchg32(uint32_t data, uint8_t flags);
-void eos_spi_flush(void);
diff --git a/fw/fe310/eos/spi_cfg.h b/fw/fe310/eos/spi_cfg.h
deleted file mode 100644
index 84ab8bb..0000000
--- a/fw/fe310/eos/spi_cfg.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#include <stdint.h>
-
-#define EOS_SPI_MAX_DEV         4
-
-typedef struct {
-    uint16_t div;
-    uint8_t csid;
-    uint8_t cspin;
-    unsigned char evt;
-} SPIConfig;
-
-static const SPIConfig spi_cfg[EOS_SPI_MAX_DEV] = {
-    {   // DEV_NET
-        .div = SPI_DIV_NET,
-        .csid = SPI_CSID_NET,
-        .cspin = SPI_CSPIN_NET,
-        .evt = 0,   // Not SPI event
-    },
-    {   // DEV_EVE
-        .div = SPI_DIV_EVE,
-        .csid = SPI_CSID_EVE,
-        .cspin = SPI_CSPIN_EVE,
-        .evt = 0,
-    },
-    {   // DEV_SDC
-        .div = SPI_DIV_SDC,
-        .csid = SPI_CSID_SDC,
-        .cspin = SPI_CSPIN_SDC,
-        .evt = EOS_SPI_EVT_SDC,
-    },
-    {   // DEV_CAM
-        .div = SPI_DIV_CAM,
-        .csid = SPI_CSID_CAM,
-        .cspin = SPI_CSPIN_CAM,
-        .evt = EOS_SPI_EVT_CAM,
-    },
-};
diff --git a/fw/fe310/eos/spi_dev.c b/fw/fe310/eos/spi_dev.c
deleted file mode 100644
index c0c21b0..0000000
--- a/fw/fe310/eos/spi_dev.c
+++ /dev/null
@@ -1,97 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-
-#include "encoding.h"
-#include "platform.h"
-
-#include "eos.h"
-#include "msgq.h"
-#include "interrupt.h"
-#include "event.h"
-
-#include "board.h"
-
-#include "net.h"
-#include "spi.h"
-#include "spi_priv.h"
-#include "spi_cfg.h"
-#include "spi_dev.h"
-
-static uint8_t spi_dev;
-static uint8_t spi_lock;
-static uint16_t spi_div[EOS_SPI_MAX_DEV];
-
-int eos_spi_dev_init(uint8_t wakeup_cause) {
-    int i;
-
-    for (i=0; i<EOS_SPI_MAX_DEV; i++) {
-        spi_div[i] = spi_cfg[i].div;
-        if (spi_cfg[i].cspin != SPI_CSPIN_NONE) {
-            GPIO_REG(GPIO_OUTPUT_VAL)   |=  (1 << spi_cfg[i].cspin);
-
-            GPIO_REG(GPIO_INPUT_EN)     &= ~(1 << spi_cfg[i].cspin);
-            GPIO_REG(GPIO_OUTPUT_EN)    |=  (1 << spi_cfg[i].cspin);
-        }
-    }
-
-    return EOS_OK;
-}
-
-int eos_spi_select(unsigned char dev) {
-    if (spi_lock) return EOS_ERR_BUSY;
-
-    if (spi_dev == EOS_SPI_DEV_NET) {
-        eos_net_stop();
-    } else {
-        eos_spi_stop();
-    }
-
-    spi_dev = dev;
-    if (dev == EOS_SPI_DEV_NET) {
-        eos_net_start();
-    } else {
-        eos_spi_start(spi_div[dev], spi_cfg[dev].csid, spi_cfg[dev].cspin, spi_cfg[dev].evt);
-    }
-
-    return EOS_OK;
-}
-
-int eos_spi_deselect(void) {
-    if (spi_lock) return EOS_ERR_BUSY;
-    if (spi_dev == EOS_SPI_DEV_NET) return EOS_ERR;
-
-    eos_spi_stop();
-
-    spi_dev = EOS_SPI_DEV_NET;
-    eos_net_start();
-
-    return EOS_OK;
-}
-
-uint8_t eos_spi_dev(void) {
-    return spi_dev;
-}
-
-uint16_t eos_spi_div(unsigned char dev) {
-    return spi_div[dev];
-}
-
-uint8_t eos_spi_csid(unsigned char dev) {
-    return spi_cfg[dev].csid;
-}
-
-uint8_t eos_spi_cspin(unsigned char dev) {
-    return spi_cfg[dev].cspin;
-}
-
-void eos_spi_lock(void) {
-    spi_lock = 1;
-}
-
-void eos_spi_unlock(void) {
-    spi_lock = 0;
-}
-
-void eos_spi_set_div(unsigned char dev, uint16_t div) {
-    spi_div[dev] = div;
-}
diff --git a/fw/fe310/eos/spi_dev.h b/fw/fe310/eos/spi_dev.h
deleted file mode 100644
index e801f7e..0000000
--- a/fw/fe310/eos/spi_dev.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#include <stdint.h>
-
-#define EOS_SPI_DEV_NET         0
-#define EOS_SPI_DEV_EVE         1
-#define EOS_SPI_DEV_SDC         2
-#define EOS_SPI_DEV_CAM         3
-
-int eos_spi_dev_init(uint8_t wakeup_cause);
-int eos_spi_select(unsigned char dev);
-int eos_spi_deselect(void);
-
-uint8_t eos_spi_dev(void);
-uint16_t eos_spi_div(unsigned char dev);
-uint8_t eos_spi_csid(unsigned char dev);
-uint8_t eos_spi_cspin(unsigned char dev);
-
-void eos_spi_lock(void);
-void eos_spi_unlock(void);
-void eos_spi_set_div(unsigned char dev, uint16_t div);
diff --git a/fw/fe310/eos/spi_priv.h b/fw/fe310/eos/spi_priv.h
deleted file mode 100644
index 72c2dae..0000000
--- a/fw/fe310/eos/spi_priv.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#include <stdint.h>
-
-#define SPI_CSID_NONE           1
-#define SPI_CSPIN_NONE          0xff
-
-/* DO NOT TOUCH THEESE */
-#define SPI_SIZE_CHUNK          4
-#define SPI_SIZE_WM             2
diff --git a/fw/fe310/eos/timer.c b/fw/fe310/eos/timer.c
deleted file mode 100644
index 91861a3..0000000
--- a/fw/fe310/eos/timer.c
+++ /dev/null
@@ -1,137 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-
-#include "encoding.h"
-#include "platform.h"
-
-#include "eos.h"
-#include "msgq.h"
-#include "event.h"
-#include "timer.h"
-
-#define MIN(X, Y)               (((X) < (Y)) ? (X) : (Y))
-#define MAX(X, Y)               (((X) > (Y)) ? (X) : (Y))
-
-static eos_timer_handler_t timer_handler[EOS_TIMER_MAX_ETYPE + 1];
-static uint64_t timer_next[EOS_TIMER_MAX_ETYPE + 1];
-
-static void timer_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) {
-    unsigned char idx = (type & ~EOS_EVT_MASK);
-
-    if (idx && (idx <= EOS_TIMER_MAX_ETYPE) && timer_handler[idx]) {
-        timer_handler[idx](type);
-    } else {
-        eos_evtq_bad_handler(type, buffer, len);
-    }
-}
-
-void _eos_timer_handle(void) {
-    int i;
-    volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME);
-    uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
-    uint64_t now = *mtime;
-    uint64_t next = 0;
-
-    for (i=0; i<=EOS_TIMER_MAX_ETYPE; i++) {
-        if (timer_next[i] && (timer_next[i] <= now)) {
-            timer_next[i] = 0;
-            if (i == 0) {
-                timer_handler[0](0);
-            } else {
-                eos_evtq_push_isr(EOS_EVT_TIMER | i, NULL, 0);
-            }
-        }
-        next = next && timer_next[i] ? MIN(next, timer_next[i]) : (next ? next : timer_next[i]);
-    }
-    *mtimecmp = next;
-    if (*mtimecmp == 0) clear_csr(mie, MIP_MTIP);
-}
-
-int eos_timer_init(uint8_t wakeup_cause) {
-    int i;
-    uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
-
-    clear_csr(mie, MIP_MTIP);
-    *mtimecmp = 0;
-    for (i=0; i<=EOS_TIMER_MAX_ETYPE; i++) {
-        timer_next[i] = 0;
-        timer_handler[i] = NULL;
-    }
-    eos_evtq_set_handler(EOS_EVT_TIMER, timer_handle_evt);
-
-    return EOS_OK;
-}
-
-void eos_timer_set_handler(unsigned char evt, eos_timer_handler_t handler) {
-    uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
-
-    if (!evt && (*mtimecmp != 0)) clear_csr(mie, MIP_MTIP);
-    timer_handler[evt] = handler;
-    if (!evt && (*mtimecmp != 0)) set_csr(mie, MIP_MTIP);
-}
-
-uint32_t eos_timer_get(unsigned char evt) {
-    volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME);
-    uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
-    uint64_t now;
-    uint32_t ret;
-
-    if (*mtimecmp != 0) clear_csr(mie, MIP_MTIP);
-    now = *mtime;
-    if (timer_next[evt]) {
-        ret = (timer_next[evt] > now) ? (timer_next[evt] - now) * 1000 / EOS_TIMER_RTC_FREQ : 0;
-    } else {
-        ret = EOS_TIMER_NONE;
-    }
-    if (*mtimecmp != 0) set_csr(mie, MIP_MTIP);
-
-    return ret;
-}
-
-void eos_timer_set(unsigned char evt, uint32_t msec) {
-    int i;
-    volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME);
-    uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
-    uint64_t tick = *mtime + msec * (uint64_t)EOS_TIMER_RTC_FREQ / 1000;
-    uint64_t next = 0;
-
-    if (*mtimecmp != 0) clear_csr(mie, MIP_MTIP);
-    timer_next[evt] = tick;
-    for (i=0; i<=EOS_TIMER_MAX_ETYPE; i++) {
-        next = next && timer_next[i] ? MIN(next, timer_next[i]) : (next ? next : timer_next[i]);
-    }
-    *mtimecmp = next;
-    if (*mtimecmp != 0) set_csr(mie, MIP_MTIP);
-}
-
-void eos_timer_clear(unsigned char evt) {
-    int i;
-    uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
-    uint64_t next = 0;
-
-    if (*mtimecmp != 0) clear_csr(mie, MIP_MTIP);
-    if (timer_next[evt]) {
-        timer_next[evt] = 0;
-        for (i=0; i<=EOS_TIMER_MAX_ETYPE; i++) {
-            next = next && timer_next[i] ? MIN(next, timer_next[i]) : (next ? next : timer_next[i]);
-        }
-        *mtimecmp = next;
-    }
-    if (*mtimecmp != 0) set_csr(mie, MIP_MTIP);
-}
-
-void eos_time_sleep(uint32_t msec) {
-    volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME);
-    uint64_t mtime0 = *mtime;
-
-    while ((*mtime - mtime0) < (msec * EOS_TIMER_RTC_FREQ / 1000 + 1));
-}
-
-uint64_t eos_time_get_tick(void) {
-    volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME);
-    return *mtime;
-}
-
-uint32_t eos_time_delta_ms(uint32_t tick) {
-    return ((uint32_t)eos_time_get_tick() - tick) * 1000 / EOS_TIMER_RTC_FREQ;
-}
diff --git a/fw/fe310/eos/timer.h b/fw/fe310/eos/timer.h
deleted file mode 100644
index 0309454..0000000
--- a/fw/fe310/eos/timer.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#include <stdint.h>
-
-#define EOS_TIMER_ETYPE_UI      1
-#define EOS_TIMER_ETYPE_ECP     2
-#define EOS_TIMER_ETYPE_USER    4
-
-#define EOS_TIMER_MAX_ETYPE     4
-
-#define EOS_TIMER_NONE          -1
-#define EOS_TIMER_RTC_FREQ      32768
-
-typedef void (*eos_timer_handler_t) (unsigned char);
-
-int eos_timer_init(uint8_t wakeup_cause);
-void eos_timer_set_handler(unsigned char evt, eos_timer_handler_t handler);
-
-uint32_t eos_timer_get(unsigned char evt);
-void eos_timer_set(unsigned char evt, uint32_t msec);
-void eos_timer_clear(unsigned char evt);
-
-void eos_time_sleep(uint32_t msec);
-uint64_t eos_time_get_tick(void);
-uint32_t eos_time_delta_ms(uint32_t tick);
diff --git a/fw/fe310/eos/trap_entry.S b/fw/fe310/eos/trap_entry.S
deleted file mode 100644
index fb2b121..0000000
--- a/fw/fe310/eos/trap_entry.S
+++ /dev/null
@@ -1,554 +0,0 @@
-#include "encoding.h"
-#include "sifive/bits.h"
-
-#define MCAUSE_INT        0x80000000
-#define MCAUSE_EXT        (MCAUSE_INT | IRQ_M_EXT)
-#define MCAUSE_TIMER      (MCAUSE_INT | IRQ_M_TIMER)
-
-#define PLIC_PRIORITY     0x0C000000
-#define PLIC_THRESHOLD    0x0C200000
-#define PLIC_CLAIM        0x0C200004
-
-#define PWM0_CTRL_ADDR    0x10015000
-#define PWM1_CTRL_ADDR    0x10025000
-#define PWM2_CTRL_ADDR    0x10035000
-#include "sifive/devices/pwm.h"
-
-#define GPIO_CTRL_ADDR    0x10012000
-#include "sifive/devices/gpio.h"
-
-#define SPI0_CTRL_ADDR    0x10014000
-#define SPI1_CTRL_ADDR    0x10024000
-#include "sifive/devices/spi.h"
-
-#define INT_PWM0_BASE     40
-#define INT_PWM1_BASE     44
-#define INT_PWM2_BASE     48
-
-#define I2S_MIC_BUF     (0*4)
-#define I2S_SPK_BUF     (1*4)
-#define I2S_FMT         (2*4)
-#define I2S_MODE        (3*4)
-#define I2S_MIC_WM      (4*4)
-#define I2S_SPK_WM      (5*4)
-#define I2S_MIC_EVT     (6*4)
-#define I2S_SPK_EVT     (7*4)
-#define I2S_MIC_CMP2    (8*4)
-#define I2S_MIC_CMP3    (9*4)
-#define I2S_SAMPLE      (10*4)
-
-#include "board.h"
-#include "irq_def.h"
-#include "evt_def.h"
-#include "i2s_def.h"
-#include "i2s_priv.h"
-#include "msgq_priv.h"
-
-  .section      .data.entry
-  .align 4
-
-.global eos_trap_entry
-eos_trap_entry:
-  addi sp, sp, -12*REGBYTES
-  STORE x8, 0*REGBYTES(sp)
-  STORE x9, 1*REGBYTES(sp)
-  STORE x18, 2*REGBYTES(sp)
-  STORE x19, 3*REGBYTES(sp)
-  STORE x20, 4*REGBYTES(sp)
-  STORE x21, 5*REGBYTES(sp)
-  STORE x22, 6*REGBYTES(sp)
-  STORE x23, 7*REGBYTES(sp)
-  STORE x24, 8*REGBYTES(sp)     # format:   0 - PCM16;  1 - ALAW
-  STORE x25, 9*REGBYTES(sp)     # mode:     0 - stereo; 1 - mono
-  STORE x26, 10*REGBYTES(sp)    # channel:  0 - left;   1 - right
-  STORE x27, 11*REGBYTES(sp)    # _eos_event_q addr
-
-  csrr x8, mcause
-  li x18, MCAUSE_EXT
-  bne x8, x18, handle_intr
-  li x18, PLIC_CLAIM
-  lw x9, 0(x18)
-  li x18, I2S_IRQ_WS_ID
-  beq x9, x18, i2s_handle_ws
-  li x18, I2S_IRQ_SD_ID
-  beq x9, x18, i2s_handle_sd
-  j handle_intr
-
-evtq_push:
-  la x9, _eos_event_q
-  lbu x18, MSGQ_OFF_IDXR(x9)
-  lbu x19, MSGQ_OFF_IDXW(x9)
-  lbu x20, MSGQ_OFF_SIZE(x9)
-
-  sub x18, x19, x18
-  andi x18, x18, 0xff
-  beq x18, x20, 0f
-
-  addi x20, x20, -1
-  and x20, x20, x19
-  li x18, MSGQ_ITEM_SIZE
-  mul x20, x20, x18
-  lw x21, MSGQ_OFF_ARRAY(x9)
-  add x21, x21, x20
-
-  addi x19, x19, 1
-  sb x19, MSGQ_OFF_IDXW(x9)
-  jalr x0, x22
-
-0:
-  mv x20, x0
-  jalr x0, x21
-
-i2s_handle_sd:
-  li x8, I2S_CTRL_ADDR_WS_SPK
-  lw x18, PWM_COUNT(x8)
-  lw x19, PWM_CMP3(x8)
-
-  # exit if too early
-  bltu x18, x19, i2s_sd_exit
-
-  la x27, _eos_i2s_drvr
-
-  # move CMPs for next channel and store channel bit to x26
-  lw x20, I2S_MIC_CMP2(x27)
-  lw x21, I2S_MIC_CMP3(x27) # 16-bit period
-
-  add x23, x19, x20
-  add x24, x23, x21
-  slli x20, x21, 1      # 32-bit period
-  slli x21, x20, 1      # 64-bit period
-  bltu x24, x21, 0f
-  neg x21, x21
-  add x23, x23, x21
-  add x24, x24, x21
-0:
-  li x26, 0
-  bltu x23, x20, 0f
-  li x26, 1
-0:
-  bltu x19, x20, 0f
-  neg x20, x20
-  li x18, PLIC_PRIORITY
-  sw x0, 4*I2S_IRQ_SD_ID(x18)
-0:
-  add x19, x19, x20
-
-  li x9, I2S_CTRL_ADDR_WS_MIC
-  sw x19, PWM_CMP3(x8)
-  sw x23, PWM_CMP2(x9)
-  sw x24, PWM_CMP3(x9)
-
-  lw x24, I2S_FMT(x27)
-  lw x25, I2S_MODE(x27)
-
-i2s_abuf_pop:
-  and x8, x25, x26
-  beqz x8, 0f
-
-  lw x8, I2S_SAMPLE(x27)
-  j i2s_sd_xchg
-0:
-  # pop from spk buf -> x8
-  lw x9, I2S_SPK_BUF(x27)
-  beqz x9, i2s_sd_xchg
-  lhu x18, I2S_ABUF_OFF_IDXR(x9)
-  lhu x19, I2S_ABUF_OFF_IDXW(x9)
-  lhu x20, I2S_ABUF_OFF_SIZE(x9)
-
-  beq x18, x19, 2f
-
-  addi x20, x20, -1
-  and x20, x20, x18
-  lw x21, I2S_ABUF_OFF_ARRAY(x9)
-  add x21, x21, x20
-  beqz x24, 0f
-  lbu x8, 0(x21)
-  addi x18, x18, 1
-  j 1f
-0:
-  lb x8, 0(x21)
-  lbu x20, 1(x21)
-  slli x8, x8, 8
-  or x8, x8, x20
-  addi x18, x18, 2
-1:
-  sh x18, I2S_ABUF_OFF_IDXR(x9)
-
-2:
-  li x21, 0xffff
-  sub x18, x19, x18
-  and x18, x18, x21
-
-  # check for push to event queue
-  lw x9, I2S_SPK_WM(x27)
-  bgtu x18, x9, i2s_decode
-
-  lw x9, I2S_SPK_EVT(x27)
-  beqz x9, i2s_decode
-  sw x0, I2S_SPK_EVT(x27)
-
-  # push to event queue
-  jal x22, evtq_push
-  beqz x21, i2s_decode
-  li x18, (EOS_EVT_I2S | EOS_I2S_ETYPE_SPK)
-  sb x18, MSGQ_ITEM_OFF_TYPE(x21)
-
-i2s_decode:
-  beqz x24, 3f
-  # aLaw decode -> x8
-  xori x8, x8, 0x55
-  andi x9, x8, 0x80
-  beqz x9, 0f
-  li x9, 1
-  slli x9, x9, 7
-  not x9, x9
-  and x8, x8, x9
-  li x9, -1
-0:
-  andi x18, x8, 0xf0
-  srli x18, x18, 4
-  addi x18, x18, 4
-
-  li x19, 4
-  beq x18, x19, 1f
-
-  andi x8, x8, 0x0f
-  addi x19, x18, -4
-  sll x8, x8, x19
-
-  li x19, 1
-  sll x19, x19, x18
-  or x8, x8, x19
-
-  li x19, 1
-  addi x18, x18, -5
-  sll x19, x19, x18
-  or x8, x8, x19
-  j 2f
-1:
-  slli x8, x8, 1
-  ori x8, x8, 1
-2:
-  beqz x9, 3f
-  mul x8, x8, x9
-3:
-  beqz x25, i2s_sd_xchg
-  sw x8, I2S_SAMPLE(x27)
-
-i2s_sd_xchg:
-  # read/write shift reg: x8 -> sr -> x8
-  li x18, GPIO_CTRL_ADDR
-  li x19, (0x1 << I2S_PIN_SD_IN)
-  li x20, (0x1 << I2S_PIN_SD_OUT)
-  li x21, (0x1 << I2S_PIN_CK_SR)
-  lw x22, GPIO_OUTPUT_VAL(x18)
-
-  lw x9, GPIO_OUTPUT_EN(x18)
-  or x9, x9, x20
-  sw x9, GPIO_OUTPUT_EN(x18)
-
-  not x20, x20
-  xor x22, x22, x21
-
-  li x23, 16
-0:
-  # write bit
-  li x9, 1
-  slli x9, x9, 15
-  and x9, x8, x9
-  slli x8, x8, 1
-#if I2S_PIN_SD_OUT > 15
-  slli x9, x9, (I2S_PIN_SD_OUT - 15)
-#else
-  srli x9, x9, (15 - I2S_PIN_SD_OUT)
-#endif
-  and x22, x22, x20
-  or x22, x22, x9
-
-  # read bit
-  lw x9, GPIO_INPUT_VAL(x18)
-  and x9, x9, x19
-  srli x9, x9, I2S_PIN_SD_IN
-  or x8, x8, x9
-
-  # 74HC595 ck low (I2S_PIN_CK_SR high)
-  xor x22, x22, x21
-  sw x22, GPIO_OUTPUT_VAL(x18)
-
-  # idle
-  li x9, I2S_IDLE_CYCLES
-1:
-  addi x9, x9, -1
-  bnez x9, 1b
-
-  # 74HC595 ck high (I2S_PIN_CK_SR low)
-  xor x22, x22, x21
-  sw x22, GPIO_OUTPUT_VAL(x18)
-
-  addi x23, x23, -1
-  bnez x23, 0b
-
-  # idle
-  li x9, I2S_IDLE_CYCLES
-1:
-  addi x9, x9, -1
-  bnez x9, 1b
-
-  # 74HC595 ck low (I2S_PIN_CK_SR high)
-  xor x22, x22, x21
-  sw x22, GPIO_OUTPUT_VAL(x18)
-
-  lw x9, GPIO_OUTPUT_EN(x18)
-  and x9, x9, x20
-  sw x9, GPIO_OUTPUT_EN(x18)
-
-  slli x8, x8, 16
-  srai x8, x8, 16
-
-i2s_encode:
-  beqz x24, i2s_abuf_push
-  # aLaw encode -> x8
-  li x18, 0x800
-  li x19, 7
-  bgez x8, 0f
-  neg x8, x8
-  lui x9, 0x80000
-  or x8, x8, x9
-0:
-  and x9, x8, x18
-  beq x9, x18, 1f
-  beqz x19, 1f
-  srli x18, x18, 1
-  addi x19, x19, -1
-  j 0b
-1:
-  mv x9, x19
-  bnez x9, 2f
-  addi x9, x9, 1
-2:
-  sra x8, x8, x9
-  li x9, 0x8000000f
-  and x8, x8, x9
-  slli x19, x19, 4
-  or x8, x8, x19
-  bgez x8, 3f
-  ori x8, x8, 0x80
-3:
-  xori x8, x8, 0x55
-  andi x8, x8, 0xff
-
-i2s_abuf_push:
-  # check channel
-  # bnez x26, i2s_sd_exit
-
-  # push to mic buf
-  lw x9, I2S_MIC_BUF(x27)
-  beqz x9, i2s_sd_exit
-  lhu x18, I2S_ABUF_OFF_IDXR(x9)
-  lhu x19, I2S_ABUF_OFF_IDXW(x9)
-  lhu x20, I2S_ABUF_OFF_SIZE(x9)
-  li x21, 0xffff
-
-  sub x18, x19, x18
-  and x18, x18, x21
-  beq x18, x20, 2f
-
-  addi x20, x20, -1
-  and x20, x20, x19
-  lw x21, I2S_ABUF_OFF_ARRAY(x9)
-  add x21, x21, x20
-  beqz x24, 0f
-  sb x8, 0(x21)
-  addi x19, x19, 1
-  addi x18, x18, 1
-  j 1f
-0:
-  sb x8, 1(x21)
-  srli x8, x8, 8
-  sb x8, 0(x21)
-  addi x19, x19, 2
-  addi x18, x18, 2
-1:
-  sh x19, I2S_ABUF_OFF_IDXW(x9)
-
-2:
-  # check for push to event queue
-  lw x9, I2S_MIC_WM(x27)
-  bltu x18, x9, i2s_sd_exit
-
-  lw x9, I2S_MIC_EVT(x27)
-  beqz x9, i2s_sd_exit
-  sw x0, I2S_MIC_EVT(x27)
-
-  # push to event queue
-  jal x22, evtq_push
-  beqz x21, i2s_sd_exit
-  li x18, (EOS_EVT_I2S | EOS_I2S_ETYPE_MIC)
-  sb x18, MSGQ_ITEM_OFF_TYPE(x21)
-
-i2s_sd_exit:
-  # complete
-  li x18, I2S_IRQ_SD_ID
-  li x19, PLIC_CLAIM
-  sw x18, 0(x19)
-
-  # exit
-  j trap_exit_data
-
-i2s_handle_ws:
-  # enable sd irq
-  li x18, PLIC_PRIORITY
-  li x19, IRQ_PRIORITY_I2S_SD
-  sw x19, 4*I2S_IRQ_SD_ID(x18)
-
-  # complete
-  li x18, I2S_IRQ_WS_ID
-  li x19, PLIC_CLAIM
-  sw x18, 0(x19)
-
-  # exit
-  j trap_exit_data
-
-.global _eos_i2s_start_pwm
-_eos_i2s_start_pwm:
-  addi sp, sp, -8*REGBYTES
-  STORE x8, 0*REGBYTES(sp)
-  STORE x9, 1*REGBYTES(sp)
-  STORE x18, 2*REGBYTES(sp)
-  STORE x19, 3*REGBYTES(sp)
-  STORE x20, 4*REGBYTES(sp)
-  STORE x21, 5*REGBYTES(sp)
-  STORE x22, 6*REGBYTES(sp)
-  STORE x23, 7*REGBYTES(sp)
-
-  li x18, I2S_CTRL_ADDR_CK
-  li x19, I2S_CTRL_ADDR_WS_MIC
-  li x20, I2S_CTRL_ADDR_WS_SPK
-  li x21, PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | I2S_PWM_SCALE_CK
-  li x22, PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | PWM_CFG_CMP2GANG
-  li x23, PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | PWM_CFG_CMP1GANG
-  sw x21, PWM_CFG(x18)
-  sw x22, PWM_CFG(x19)
-  sw x23, PWM_CFG(x20)
-
-  LOAD x8, 0*REGBYTES(sp)
-  LOAD x9, 1*REGBYTES(sp)
-  LOAD x18, 2*REGBYTES(sp)
-  LOAD x19, 3*REGBYTES(sp)
-  LOAD x20, 4*REGBYTES(sp)
-  LOAD x21, 5*REGBYTES(sp)
-  LOAD x22, 6*REGBYTES(sp)
-  LOAD x23, 7*REGBYTES(sp)
-  addi sp, sp, 8*REGBYTES
-
-  ret
-
-trap_exit_data:
-  # Remain in M-mode after mret
-  li x18, MSTATUS_MPP
-  csrs mstatus, x18
-
-  LOAD x8, 0*REGBYTES(sp)
-  LOAD x9, 1*REGBYTES(sp)
-  LOAD x18, 2*REGBYTES(sp)
-  LOAD x19, 3*REGBYTES(sp)
-  LOAD x20, 4*REGBYTES(sp)
-  LOAD x21, 5*REGBYTES(sp)
-  LOAD x22, 6*REGBYTES(sp)
-  LOAD x23, 7*REGBYTES(sp)
-  LOAD x24, 8*REGBYTES(sp)
-  LOAD x25, 9*REGBYTES(sp)
-  LOAD x26, 10*REGBYTES(sp)
-  LOAD x27, 11*REGBYTES(sp)
-  addi sp, sp, 12*REGBYTES
-
-  mret
-
-handle_intr:
-  lui x18,       %hi(trap_entry_text)
-  addi x18, x18, %lo(trap_entry_text)
-  jalr x0, x18
-
-  .section      .text.entry
-  .align 4
-
-trap_entry_text:
-  addi sp, sp, -20*REGBYTES
-
-  STORE x1, 0*REGBYTES(sp)
-  STORE x2, 1*REGBYTES(sp)
-  STORE x3, 2*REGBYTES(sp)
-  STORE x4, 3*REGBYTES(sp)
-  STORE x5, 4*REGBYTES(sp)
-  STORE x6, 5*REGBYTES(sp)
-  STORE x7, 6*REGBYTES(sp)
-  STORE x10, 7*REGBYTES(sp)
-  STORE x11, 8*REGBYTES(sp)
-  STORE x12, 9*REGBYTES(sp)
-  STORE x13, 10*REGBYTES(sp)
-  STORE x14, 11*REGBYTES(sp)
-  STORE x15, 12*REGBYTES(sp)
-  STORE x16, 13*REGBYTES(sp)
-  STORE x17, 14*REGBYTES(sp)
-  STORE x28, 15*REGBYTES(sp)
-  STORE x29, 16*REGBYTES(sp)
-  STORE x30, 17*REGBYTES(sp)
-  STORE x31, 18*REGBYTES(sp)
-
-  li x18, MCAUSE_TIMER
-  beq x8, x18, handle_timer
-  li x18, MCAUSE_EXT
-  beq x8, x18, handle_ext
-  mv a0, x8
-  call _exit
-
-handle_timer:
-  call _eos_timer_handle
-  j trap_exit_text
-
-handle_ext:
-  mv a0, x9
-  call eos_intr_handle
-  li x18, PLIC_CLAIM
-  sw a0, 0(x18)
-
-trap_exit_text:
-  # Remain in M-mode after mret
-  li t0, MSTATUS_MPP
-  csrs mstatus, t0
-
-  LOAD x1, 0*REGBYTES(sp)
-  LOAD x2, 1*REGBYTES(sp)
-  LOAD x3, 2*REGBYTES(sp)
-  LOAD x4, 3*REGBYTES(sp)
-  LOAD x5, 4*REGBYTES(sp)
-  LOAD x6, 5*REGBYTES(sp)
-  LOAD x7, 6*REGBYTES(sp)
-  LOAD x10, 7*REGBYTES(sp)
-  LOAD x11, 8*REGBYTES(sp)
-  LOAD x12, 9*REGBYTES(sp)
-  LOAD x13, 10*REGBYTES(sp)
-  LOAD x14, 11*REGBYTES(sp)
-  LOAD x15, 12*REGBYTES(sp)
-  LOAD x16, 13*REGBYTES(sp)
-  LOAD x17, 14*REGBYTES(sp)
-  LOAD x28, 15*REGBYTES(sp)
-  LOAD x29, 16*REGBYTES(sp)
-  LOAD x30, 17*REGBYTES(sp)
-  LOAD x31, 18*REGBYTES(sp)
-
-  LOAD x8, 20*REGBYTES(sp)
-  LOAD x9, 21*REGBYTES(sp)
-  LOAD x18, 22*REGBYTES(sp)
-  LOAD x19, 23*REGBYTES(sp)
-  LOAD x20, 24*REGBYTES(sp)
-  LOAD x21, 25*REGBYTES(sp)
-  LOAD x22, 26*REGBYTES(sp)
-  LOAD x23, 27*REGBYTES(sp)
-  LOAD x24, 28*REGBYTES(sp)
-  LOAD x25, 29*REGBYTES(sp)
-  LOAD x26, 30*REGBYTES(sp)
-  LOAD x27, 31*REGBYTES(sp)
-
-  addi sp, sp, 32*REGBYTES
-  mret
diff --git a/fw/fe310/eos/uart.c b/fw/fe310/eos/uart.c
deleted file mode 100644
index 30f76d9..0000000
--- a/fw/fe310/eos/uart.c
+++ /dev/null
@@ -1,114 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-
-#include "encoding.h"
-#include "platform.h"
-#include "prci_driver.h"
-
-#include "eos.h"
-#include "interrupt.h"
-#include "event.h"
-
-#include "uart.h"
-
-static eos_uart_handler_t uart_handler[EOS_UART_MAX_ETYPE];
-
-static void uart_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) {
-    unsigned char idx = (type & ~EOS_EVT_MASK) - 1;
-
-    if ((idx < EOS_UART_MAX_ETYPE) && uart_handler[idx]) {
-        uart_handler[idx](type);
-    } else {
-        eos_evtq_bad_handler(type, buffer, len);
-    }
-}
-
-static void uart_handle_intr(void) {
-    if (UART0_REG(UART_REG_IP) & UART_IP_TXWM) {
-        UART0_REG(UART_REG_IE) &= ~UART_IP_TXWM;
-        eos_evtq_push_isr(EOS_EVT_UART | EOS_UART_ETYPE_TX, NULL, 0);
-    }
-    if (UART0_REG(UART_REG_IP) & UART_IP_RXWM) {
-        UART0_REG(UART_REG_IE) &= ~UART_IP_RXWM;
-        eos_evtq_push_isr(EOS_EVT_UART | EOS_UART_ETYPE_RX, NULL, 0);
-    }
-}
-
-int eos_uart_init(uint8_t wakeup_cause) {
-    int i;
-
-    for (i=0; i<EOS_UART_MAX_ETYPE; i++) {
-        uart_handler[i] = NULL;
-    }
-    eos_evtq_set_handler(EOS_EVT_UART, uart_handle_evt);
-    eos_intr_set(INT_UART0_BASE, IRQ_PRIORITY_UART, uart_handle_intr);
-
-    UART0_REG(UART_REG_TXCTRL)  |=  UART_TXEN;
-    UART0_REG(UART_REG_RXCTRL)  |=  UART_RXEN;
-
-    eos_uart_speed(EOS_UART_SPEED);
-    eos_uart_start();
-
-    return EOS_OK;
-}
-
-void eos_uart_start(void) {
-    GPIO_REG(GPIO_IOF_SEL)      &= ~IOF0_UART0_MASK;
-    GPIO_REG(GPIO_IOF_EN)       |=  IOF0_UART0_MASK;
-}
-
-void eos_uart_stop(void) {
-    GPIO_REG(GPIO_IOF_EN)       &= ~IOF0_UART0_MASK;
-}
-
-void eos_uart_speed(uint32_t baud_rate) {
-    UART0_REG(UART_REG_DIV) = PRCI_get_cpu_freq() / baud_rate - 1;
-}
-
-void eos_uart_set_handler(unsigned char type, eos_uart_handler_t handler) {
-    if (type && (type <= EOS_UART_MAX_ETYPE)) uart_handler[type - 1] = handler;
-}
-
-void eos_uart_txwm_set(uint8_t wm) {
-    UART0_REG(UART_REG_TXCTRL)  &= ~UART_TXWM(0xFFFF);
-    UART0_REG(UART_REG_TXCTRL)  |=  UART_TXWM(wm);
-    UART0_REG(UART_REG_IE)      |=  UART_IP_TXWM;
-}
-
-void eos_uart_txwm_clear(void) {
-    UART0_REG(UART_REG_IE)      &= ~UART_IP_TXWM;
-}
-
-void eos_uart_rxwm_set(uint8_t wm) {
-    UART0_REG(UART_REG_RXCTRL)  &= ~UART_RXWM(0xFFFF);
-    UART0_REG(UART_REG_RXCTRL)  |=  UART_RXWM(wm);
-    UART0_REG(UART_REG_IE)      |=  UART_IP_RXWM;
-}
-
-void eos_uart_rxwm_clear(void) {
-    UART0_REG(UART_REG_IE)      &= ~UART_IP_RXWM;
-}
-
-int eos_uart_putc(int c, char b) {
-    if (b) {
-        while (UART0_REG(UART_REG_TXFIFO) & 0x80000000);
-        UART0_REG(UART_REG_TXFIFO) = c & 0xff;
-    } else {
-        if (UART0_REG(UART_REG_TXFIFO) & 0x80000000) return EOS_ERR_FULL;
-        UART0_REG(UART_REG_TXFIFO) = c & 0xff;
-    }
-    return EOS_OK;
-}
-
-int eos_uart_getc(char b) {
-    volatile uint32_t r;
-
-    if (b) {
-        while ((r = UART0_REG(UART_REG_RXFIFO)) & 0x80000000);
-    } else {
-        r = UART0_REG(UART_REG_RXFIFO);
-        if (r & 0x80000000) return EOS_ERR_EMPTY;
-    }
-    return r & 0xff;
-}
\ No newline at end of file
diff --git a/fw/fe310/eos/uart.h b/fw/fe310/eos/uart.h
deleted file mode 100644
index 94999e6..0000000
--- a/fw/fe310/eos/uart.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#include <stdint.h>
-
-#define EOS_UART_ETYPE_TX       1
-#define EOS_UART_ETYPE_RX       2
-
-#define EOS_UART_MAX_ETYPE      2
-
-#define EOS_UART_SPEED          115200
-
-typedef void (*eos_uart_handler_t) (unsigned char);
-
-int eos_uart_init(uint8_t wakeup_cause);
-void eos_uart_start(void);
-void eos_uart_stop(void);
-void eos_uart_speed(uint32_t baud_rate);
-
-void eos_uart_set_handler(unsigned char type, eos_uart_handler_t handler);
-
-void eos_uart_txwm_set(uint8_t wm);
-void eos_uart_txwm_clear(void);
-void eos_uart_rxwm_set(uint8_t wm);
-void eos_uart_rxwm_clear(void);
-int eos_uart_putc(int c, char b);
-int eos_uart_getc(char b);
\ No newline at end of file
diff --git a/fw/fe310/eos/wifi.c b/fw/fe310/eos/wifi.c
deleted file mode 100644
index 0663582..0000000
--- a/fw/fe310/eos/wifi.c
+++ /dev/null
@@ -1,106 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-
-#include "eos.h"
-#include "event.h"
-#include "net.h"
-
-#include "wifi.h"
-
-static eos_evt_handler_t evt_handler[EOS_WIFI_MAX_MTYPE];
-
-static void wifi_handle_msg(unsigned char type, unsigned char *buffer, uint16_t len) {
-    unsigned char mtype;
-
-    if ((buffer == NULL) || (len < 1)) {
-        eos_net_bad_handler(type, buffer, len);
-        return;
-    }
-
-    mtype = buffer[0];
-    if ((mtype < EOS_WIFI_MAX_MTYPE) && evt_handler[mtype]) {
-        evt_handler[mtype](mtype, buffer, len);
-    } else {
-        eos_net_bad_handler(type, buffer, len);
-    }
-}
-
-void eos_wifi_netinit(void) {
-    int i;
-
-    for (i=0; i<EOS_WIFI_MAX_MTYPE; i++) {
-        evt_handler[i] = NULL;
-    }
-    eos_net_set_handler(EOS_NET_MTYPE_WIFI, wifi_handle_msg);
-}
-
-void eos_wifi_set_handler(unsigned char mtype, eos_evt_handler_t handler) {
-    if (mtype < EOS_WIFI_MAX_MTYPE) evt_handler[mtype] = handler;
-}
-
-eos_evt_handler_t eos_wifi_get_handler(unsigned char mtype) {
-    if (mtype < EOS_WIFI_MAX_MTYPE) return evt_handler[mtype];
-    return NULL;
-}
-
-int eos_wifi_scan(unsigned char *buffer) {
-    int async;
-
-    async = 0;
-    if (buffer == NULL) {
-        buffer = eos_net_alloc();
-        async = 1;
-    }
-    buffer[0] = EOS_WIFI_MTYPE_SCAN;
-    return _eos_net_send(EOS_NET_MTYPE_WIFI, buffer, 1, async, 1);
-}
-
-int eos_wifi_auth(const char *ssid, const char *pass, unsigned char *buffer) {
-    unsigned char *buf;
-    size_t ssid_len, pass_len;
-    int async;
-
-    async = 0;
-    if (buffer == NULL) {
-        buffer = eos_net_alloc();
-        async = 1;
-    }
-    ssid_len = strlen(ssid) + 1;
-    pass_len = strlen(pass) + 1;
-    if ((1 + ssid_len + pass_len) > EOS_NET_MTU) return EOS_ERR_SIZE;
-
-    buf = buffer;
-    buf[0] = EOS_WIFI_MTYPE_AUTH;
-    buf++;
-    strcpy(buf, ssid);
-    buf += ssid_len;
-    strcpy(buf, pass);
-    buf += pass_len;
-
-    return _eos_net_send(EOS_NET_MTYPE_WIFI, buffer, 1 + ssid_len + pass_len, async, 1);
-}
-
-int eos_wifi_connect(unsigned char *buffer) {
-    int async;
-
-    async = 0;
-    if (buffer == NULL) {
-        buffer = eos_net_alloc();
-        async = 1;
-    }
-    buffer[0] = EOS_WIFI_MTYPE_CONNECT;
-    return _eos_net_send(EOS_NET_MTYPE_WIFI, buffer, 1, async, 1);
-}
-
-int eos_wifi_disconnect(unsigned char *buffer) {
-    int async;
-
-    async = 0;
-    if (buffer == NULL) {
-        buffer = eos_net_alloc();
-        async = 1;
-    }
-    buffer[0] = EOS_WIFI_MTYPE_DISCONNECT;
-    return _eos_net_send(EOS_NET_MTYPE_WIFI, buffer, 1, async, 1);
-}
diff --git a/fw/fe310/eos/wifi.h b/fw/fe310/eos/wifi.h
deleted file mode 100644
index 4a49518..0000000
--- a/fw/fe310/eos/wifi.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#include <stdint.h>
-#include "event.h"
-
-#define EOS_WIFI_MTYPE_SCAN         1
-#define EOS_WIFI_MTYPE_AUTH         2
-#define EOS_WIFI_MTYPE_CONNECT      3
-#define EOS_WIFI_MTYPE_DISCONNECT   4
-
-#define EOS_WIFI_MAX_MTYPE          5
-
-void eos_wifi_netinit(void);
-void eos_wifi_set_handler(unsigned char mtype, eos_evt_handler_t handler);
-eos_evt_handler_t eos_wifi_get_handler(unsigned char mtype);
-
-int eos_wifi_scan(unsigned char *buffer);
-int eos_wifi_auth(const char *ssid, const char *pass, unsigned char *buffer);
-int eos_wifi_connect(unsigned char *buffer);
-int eos_wifi_disconnect(unsigned char *buffer);
-- 
cgit v1.2.3