Browse Source

[BSP] Add fh8620 bsp from Shanghai Fullhan Microelectronics Co., Ltd.

FH8620 BSP
Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd.
All rights reserved
Bernard Xiong 9 years ago
parent
commit
43f68131ce
100 changed files with 23246 additions and 0 deletions
  1. 14 0
      bsp/fh8620/SConscript
  2. 33 0
      bsp/fh8620/SConstruct
  3. 11 0
      bsp/fh8620/applications/SConscript
  4. 45 0
      bsp/fh8620/applications/main.c
  5. 9 0
      bsp/fh8620/drivers/SConscript
  6. 1386 0
      bsp/fh8620/drivers/acw.c
  7. 232 0
      bsp/fh8620/drivers/acw.h
  8. 170 0
      bsp/fh8620/drivers/dma.c
  9. 107 0
      bsp/fh8620/drivers/dma.h
  10. 122 0
      bsp/fh8620/drivers/dma_mem.c
  11. 76 0
      bsp/fh8620/drivers/dma_mem.h
  12. 1618 0
      bsp/fh8620/drivers/fh_dma.c
  13. 254 0
      bsp/fh8620/drivers/fh_dma.h
  14. 450 0
      bsp/fh8620/drivers/gpio.c
  15. 188 0
      bsp/fh8620/drivers/gpio.h
  16. 520 0
      bsp/fh8620/drivers/i2c.c
  17. 56 0
      bsp/fh8620/drivers/i2c.h
  18. 216 0
      bsp/fh8620/drivers/interrupt.c
  19. 40 0
      bsp/fh8620/drivers/interrupt.h
  20. 87 0
      bsp/fh8620/drivers/mem_process.c
  21. 710 0
      bsp/fh8620/drivers/mmc.c
  22. 51 0
      bsp/fh8620/drivers/mmc.h
  23. 226 0
      bsp/fh8620/drivers/pwm.c
  24. 57 0
      bsp/fh8620/drivers/pwm.h
  25. 416 0
      bsp/fh8620/drivers/sadc.c
  26. 109 0
      bsp/fh8620/drivers/sadc.h
  27. 212 0
      bsp/fh8620/drivers/spi_fh_adapt.c
  28. 71 0
      bsp/fh8620/drivers/spi_fh_adapt.h
  29. 878 0
      bsp/fh8620/drivers/ssi.c
  30. 134 0
      bsp/fh8620/drivers/ssi.h
  31. 197 0
      bsp/fh8620/drivers/trap.c
  32. 292 0
      bsp/fh8620/drivers/uart.c
  33. 33 0
      bsp/fh8620/drivers/uart.h
  34. 269 0
      bsp/fh8620/drivers/wdt.c
  35. 46 0
      bsp/fh8620/drivers/wdt.h
  36. 14 0
      bsp/fh8620/libraries/SConscript
  37. 9 0
      bsp/fh8620/libraries/driverlib/SConscript
  38. 27 0
      bsp/fh8620/libraries/driverlib/fh_gpio.c
  39. 311 0
      bsp/fh8620/libraries/driverlib/fh_i2c.c
  40. 69 0
      bsp/fh8620/libraries/driverlib/fh_ictl.c
  41. 413 0
      bsp/fh8620/libraries/driverlib/fh_mmc.c
  42. 42 0
      bsp/fh8620/libraries/driverlib/fh_pwm.c
  43. 2085 0
      bsp/fh8620/libraries/driverlib/fh_sdio.c
  44. 164 0
      bsp/fh8620/libraries/driverlib/fh_spi.c
  45. 144 0
      bsp/fh8620/libraries/driverlib/fh_timer.c
  46. 278 0
      bsp/fh8620/libraries/driverlib/fh_uart.c
  47. 58 0
      bsp/fh8620/libraries/driverlib/fh_wdt.c
  48. 39 0
      bsp/fh8620/libraries/inc/fh_driverlib.h
  49. 54 0
      bsp/fh8620/libraries/inc/fh_gpio.h
  50. 226 0
      bsp/fh8620/libraries/inc/fh_i2c.h
  51. 58 0
      bsp/fh8620/libraries/inc/fh_ictl.h
  52. 225 0
      bsp/fh8620/libraries/inc/fh_mmc.h
  53. 44 0
      bsp/fh8620/libraries/inc/fh_pwm.h
  54. 356 0
      bsp/fh8620/libraries/inc/fh_sdio.h
  55. 148 0
      bsp/fh8620/libraries/inc/fh_spi.h
  56. 100 0
      bsp/fh8620/libraries/inc/fh_timer.h
  57. 245 0
      bsp/fh8620/libraries/inc/fh_uart.h
  58. 65 0
      bsp/fh8620/libraries/inc/fh_wdt.h
  59. 10 0
      bsp/fh8620/libraries/startup/SConscript
  60. 416 0
      bsp/fh8620/libraries/startup/gcc/start_gcc.S
  61. 96 0
      bsp/fh8620/link.ld
  62. 15 0
      bsp/fh8620/platform/SConscript
  63. 33 0
      bsp/fh8620/platform/board.h
  64. 83 0
      bsp/fh8620/platform/board_info.h
  65. 8 0
      bsp/fh8620/platform/common/SConscript
  66. 250 0
      bsp/fh8620/platform/common/board_info.c
  67. 120 0
      bsp/fh8620/platform/common/chkenv.c
  68. 15 0
      bsp/fh8620/platform/fh8620/SConscript
  69. 117 0
      bsp/fh8620/platform/fh8620/arch.h
  70. 9 0
      bsp/fh8620/platform/fh8620/iot_cam/SConscript
  71. 692 0
      bsp/fh8620/platform/fh8620/iot_cam/board.c
  72. 106 0
      bsp/fh8620/platform/fh8620/iot_cam/board_def.h
  73. 668 0
      bsp/fh8620/platform/fh8620/iot_cam/iomux.c
  74. 4 0
      bsp/fh8620/platform/fh8620/iot_cam/readme
  75. 123 0
      bsp/fh8620/platform/fh8620/iot_cam/startup.c
  76. 44 0
      bsp/fh8620/platform/fh_arch.h
  77. 90 0
      bsp/fh8620/platform/fh_def.h
  78. 13 0
      bsp/fh8620/platform/plat-v2/SConscript
  79. 116 0
      bsp/fh8620/platform/plat-v2/arch.h
  80. 2658 0
      bsp/fh8620/platform/plat-v2/clock.c
  81. 62 0
      bsp/fh8620/platform/plat-v2/clock.h
  82. 62 0
      bsp/fh8620/platform/plat-v2/fh_pmu.c
  83. 59 0
      bsp/fh8620/platform/plat-v2/fh_pmu.h
  84. 284 0
      bsp/fh8620/platform/plat-v2/iomux.c
  85. 314 0
      bsp/fh8620/platform/plat-v2/iomux.h
  86. 50 0
      bsp/fh8620/platform/plat-v2/reset.c
  87. 109 0
      bsp/fh8620/platform/plat-v2/timer.c
  88. 36 0
      bsp/fh8620/platform/plat-v2/timer.h
  89. 81 0
      bsp/fh8620/platform/platform_def.h
  90. 208 0
      bsp/fh8620/rtconfig.h
  91. 44 0
      bsp/fh8620/rtconfig.py
  92. 145 0
      libcpu/arm/armv6/arm_entry_gcc.S
  93. 107 0
      libcpu/arm/armv6/armv6.h
  94. 122 0
      libcpu/arm/armv6/context_gcc.S
  95. 248 0
      libcpu/arm/armv6/cpuport.c
  96. 562 0
      libcpu/arm/armv6/mmu.c
  97. 208 0
      libcpu/arm/armv6/mmu.h
  98. 79 0
      libcpu/arm/armv6/stack.c
  99. 161 0
      libcpu/arm/armv6/vfp.c
  100. 110 0
      libcpu/arm/armv6/vfp.h

+ 14 - 0
bsp/fh8620/SConscript

@@ -0,0 +1,14 @@
+# for module compiling
+import os
+Import('RTT_ROOT')
+
+cwd = str(Dir('#'))
+objs = []
+list = os.listdir(cwd)
+
+for d in list:
+    path = os.path.join(cwd, d)
+    if os.path.isfile(os.path.join(path, 'SConscript')):
+        objs = objs + SConscript(os.path.join(d, 'SConscript'))
+
+Return('objs')

+ 33 - 0
bsp/fh8620/SConstruct

@@ -0,0 +1,33 @@
+import os
+import sys
+import rtconfig
+
+if os.getenv('RTT_ROOT'):
+    RTT_ROOT = os.getenv('RTT_ROOT')
+else:
+    RTT_ROOT = os.path.normpath(os.getcwd() + '/../..')
+
+sys.path = sys.path + [os.path.join(RTT_ROOT, 'tools')]
+from building import *
+
+TARGET = rtconfig.OUTPUT_NAME + rtconfig.TARGET_EXT
+
+# add rtconfig.h path to the assembler
+rtconfig.AFLAGS += ' -I' + str(Dir('#')) +' -I' + RTT_ROOT + '/libcpu/arm/armv6'
+
+env = Environment(tools = ['mingw'],
+        AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS,
+        CC = rtconfig.CC, CCFLAGS = rtconfig.CFLAGS,
+        CXX = rtconfig.CXX, CXXFLAGS = rtconfig.CXXFLAGS,
+        AR = rtconfig.AR, ARFLAGS = '-rc',
+        LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS)
+env.PrependENVPath('PATH', rtconfig.EXEC_PATH)
+
+Export('RTT_ROOT')
+Export('rtconfig')
+
+# prepare building environment
+objs = PrepareBuilding(env, RTT_ROOT)
+
+# make a building
+DoBuilding(TARGET, objs)

+ 11 - 0
bsp/fh8620/applications/SConscript

@@ -0,0 +1,11 @@
+import rtconfig
+Import('RTT_ROOT')
+from building import *
+
+cwd = GetCurrentDir()
+src = Glob('*.c')
+
+CPPPATH = [cwd, str(Dir('#'))]
+group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH)
+
+Return('group')

+ 45 - 0
bsp/fh8620/applications/main.c

@@ -0,0 +1,45 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+#include <rtthread.h>
+#include <components.h>
+
+void init_thread(void *parameter)
+{
+	rt_components_init();
+
+	return ;
+}
+
+int rt_application_init(void)
+{
+	rt_thread_t tid;
+
+	tid = rt_thread_create("init", init_thread, RT_NULL, 
+		4096, RT_THREAD_PRIORITY_MAX/3, 20);
+	if (tid) rt_thread_startup(tid);
+
+	return 0;
+}

+ 9 - 0
bsp/fh8620/drivers/SConscript

@@ -0,0 +1,9 @@
+from building import *
+
+cwd     = GetCurrentDir()
+src     = Glob('*.c')
+CPPPATH = [cwd]
+
+group = DefineGroup('drivers', src, depend = [''], CPPPATH = CPPPATH)
+
+Return('group')

+ 1386 - 0
bsp/fh8620/drivers/acw.c

@@ -0,0 +1,1386 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "acw.h"
+#include "fh_def.h"
+#include "fh_dma.h"
+#include "dma.h"
+#ifdef RT_USING_FH_ACW
+#if 1
+typedef struct 
+{
+	unsigned int 			base;
+	void 					*vbase;
+	unsigned int 			size;
+	unsigned int 			align;
+}MEM_DESC;
+#define ACW_SELFTEST 0
+int buffer_malloc_withname(MEM_DESC *mem, int size, int align,  char* name);
+#endif
+
+#define NR_DESCS_PER_CHANNEL 64
+
+#define FIX_SAMPLE_BIT       32
+
+#define ACW_HW_NUM_RX  0
+#define ACW_HW_NUM_TX  1
+#define ACW_DMA_CAP_CHANNEL 3
+#define ACW_DMA_PAY_CHANNEL 2
+
+#define ACW_CTRL                         0x0
+#define ACW_TXFIFO_CTRL         0x4
+#define ACW_RXFIFO_CTRL         0x8
+#define ACW_STATUS                     0x0c
+#define ACW_DIG_IF_CTRL          0x10
+#define ACW_ADC_PATH_CTRL      0x14
+#define ACW_ADC_ALC_CTRL      0x18
+#define ACW_DAC_PATH_CTRL     0x1c
+#define ACW_MISC_CTRL              0x20
+#define ACW_TXFIFO                      0xf0a00100
+#define ACW_RXFIFO                      0xf0a00200
+typedef char bool;
+#define AUDIO_DMA_PREALLOC_SIZE 128*1024
+
+#define ACW_INTR_RX_UNDERFLOW   0x10000
+#define ACW_INTR_RX_OVERFLOW    0x20000
+#define ACW_INTR_TX_UNDERFLOW   0x40000
+#define ACW_INTR_TX_OVERFLOW    0x80000
+#define PAGE_SIZE 0x1000
+
+enum audio_type
+{
+    capture = 0,
+    playback,
+};
+
+enum audio_state
+{
+    normal = 0,
+    xrun,
+    stopping,
+    running,
+};
+
+struct infor_record_t
+{
+    int record_pid;
+    int play_pid;
+}; // infor_record;
+
+struct audio_config_t {
+    int rate;
+    int volume;
+    enum io_select io_type;
+    int frame_bit;
+    int channels;
+    int buffer_size;
+    int period_size;
+    int buffer_bytes;
+    int period_bytes;
+    int start_threshold;
+    int stop_threshold;
+};
+
+struct audio_ptr_t
+{
+    struct audio_config_t cfg;
+    enum audio_state state;
+    long size;
+    int hw_ptr;
+    int appl_ptr;
+    struct rt_mutex lock;
+    struct device_acw dev;
+    void *area; /*virtual pointer*/
+    dma_addr_t addr; /*physical address*/
+    unsigned char * mmap_addr;
+};
+
+struct fh_audio_cfg
+{
+    struct rt_dma_device *capture_dma;
+    struct rt_dma_device *playback_dma;
+    struct dma_transfer *capture_trans;
+    struct dma_transfer *plauback_trans;
+    struct audio_ptr_t capture;
+    struct audio_ptr_t playback;
+    wait_queue_head_t readqueue;
+    wait_queue_head_t writequeue;
+    struct rt_semaphore sem_capture;
+    struct rt_semaphore sem_playback;
+};
+typedef int            s32;
+typedef s32            dma_cookie_t;
+struct fh_dma_chan
+{
+    struct dma_chan     *chan;
+    void    *ch_regs;
+    unsigned char          mask;
+    unsigned char          priority;
+    bool           paused;
+    bool                initialized;
+    struct rt_mutex      lock;
+    /* these other elements are all protected by lock */
+    unsigned long       flags;
+    dma_cookie_t        completed;
+    struct list_head    active_list;
+    struct list_head    queue;
+    struct list_head    free_list;
+    struct fh_cyclic_desc   *cdesc;
+    unsigned int        descs_allocated;
+};
+
+struct fh_acw_dma_transfer
+{
+    struct dma_chan *chan;
+    struct dma_transfer cfg;
+    struct scatterlist sgl;
+    struct dma_async_tx_descriptor *desc;
+};
+
+struct channel_assign
+{
+    int capture_channel;
+    int playback_channel;
+};
+
+struct audio_dev_mod
+{
+    int reg_base;
+    struct channel_assign channel_assign;
+    struct fh_audio_cfg   *audio_config;
+
+}audio_dev;
+static struct work_struct playback_wq;
+#define WORK_QUEUE_STACK_SIZE         512
+#if ACW_SELFTEST
+#define WORK_QUEUE_PRIORITY           (12)
+#else
+#define WORK_QUEUE_PRIORITY           (128+12)
+#endif
+static struct rt_workqueue* playback_queue;
+
+
+void audio_prealloc_dma_buffer(int aiaotype,struct fh_audio_cfg  *audio_config);
+#if ACW_SELFTEST
+#define BUFF_SIZE            1024*8
+#define TEST_PER_NO         1024
+#endif
+static void audio_callback(){
+    rt_kprintf("# \n");
+}
+
+static void audio_callback_capture(){
+    rt_kprintf("$ \n");
+}
+
+
+static struct audio_param_store_t
+{
+    int input_volume;
+    enum io_select input_io_type;
+} audio_param_store;
+void reset_dma_buff(enum audio_type type, struct fh_audio_cfg *audio_config);
+static void fh_acw_tx_dma_done(void *arg);
+static void fh_acw_rx_dma_done(struct fh_audio_cfg *arg);
+static bool  fh_acw_dma_chan_filter(struct dma_chan *chan, void *filter_param);
+#define writel(v,a)  SET_REG(a,v)
+void fh_acw_stop_playback(struct fh_audio_cfg *audio_config)
+{
+    if(audio_config->playback.state == stopping)
+    {
+        return;
+    }
+
+    unsigned int rx_status;
+    rx_status = readl( audio_dev.reg_base + ACW_TXFIFO_CTRL);//clear rx fifo
+    rx_status =  rx_status|(1<<4);
+    writel(rx_status,audio_dev.reg_base + ACW_TXFIFO_CTRL);
+
+    audio_config->playback.state = stopping;
+    writel(0, audio_dev.reg_base + ACW_TXFIFO_CTRL);//tx fifo disable
+    if(audio_config->plauback_trans->channel_number != ACW_PLY_DMA_CHAN)
+    	goto free_mem;
+    if(!audio_config->plauback_trans->first_lli)
+    	goto free_channel;
+    audio_config->playback_dma->ops->control(audio_config->playback_dma,RT_DEVICE_CTRL_DMA_CYCLIC_STOP,audio_config->plauback_trans);
+    audio_config->playback_dma->ops->control(audio_config->playback_dma,RT_DEVICE_CTRL_DMA_CYCLIC_FREE,audio_config->plauback_trans);
+free_channel:
+    audio_config->playback_dma->ops->control(audio_config->playback_dma,RT_DEVICE_CTRL_DMA_RELEASE_CHANNEL,audio_config->plauback_trans);
+    if(&audio_config->sem_playback)
+    rt_sem_release(&audio_config->sem_playback);
+    if(&audio_config->playback.lock)
+    rt_mutex_release(&audio_config->playback.lock);
+    if(&playback_wq)
+    rt_workqueue_cancel_work(playback_queue,&playback_wq);
+    if(playback_queue)
+    rt_workqueue_destroy(playback_queue);
+free_mem:
+    if(audio_config->playback.area)
+    fh_dma_mem_free(audio_config->playback.area);
+
+}
+
+void fh_acw_stop_capture(struct fh_audio_cfg *audio_config)
+{
+    unsigned int rx_status;
+
+    if(audio_config->capture.state == stopping)
+    {
+          rt_kprintf(" capture is stopped \n");
+        return;
+    }
+    rx_status = readl( audio_dev.reg_base + ACW_RXFIFO_CTRL);//clear rx fifo
+    rx_status =  rx_status|(1<<4);
+    writel(rx_status,audio_dev.reg_base + ACW_RXFIFO_CTRL);
+    audio_config->capture.state = stopping;
+
+    writel(0, audio_dev.reg_base + 8);//rx fifo disable
+    if(audio_config->capture_trans->channel_number != ACW_CAP_DMA_CHAN)
+    	goto free_mem;
+    if(!audio_config->capture_trans->first_lli)
+    	goto free_channel;
+    audio_config->capture_dma->ops->control(audio_config->capture_dma,RT_DEVICE_CTRL_DMA_CYCLIC_STOP,audio_config->capture_trans);
+
+    audio_config->capture_dma->ops->control(audio_config->capture_dma,RT_DEVICE_CTRL_DMA_CYCLIC_FREE,audio_config->capture_trans);
+free_channel:
+    audio_config->capture_dma->ops->control(audio_config->capture_dma,RT_DEVICE_CTRL_DMA_RELEASE_CHANNEL,audio_config->capture_trans);
+    if(&audio_config->sem_capture)
+    rt_sem_release(&audio_config->sem_capture);
+    if(&audio_config->capture.lock)
+    rt_mutex_release(&audio_config->capture.lock);
+free_mem:
+    if(audio_config->capture.area)
+    fh_dma_mem_free( audio_config->capture.area);
+}
+
+void switch_io_type(enum audio_type type, enum io_select io_type)
+{
+    int reg;
+    if (capture == type)
+    {
+        reg = readl(audio_dev.reg_base + ACW_ADC_PATH_CTRL);
+        if (mic_in == io_type)
+        {
+            rt_kprintf("audio input changed to mic_in\n");
+            writel( reg & (~(1<<1)),audio_dev.reg_base + ACW_ADC_PATH_CTRL);
+        	reg = readl(audio_dev.reg_base + ACW_ADC_PATH_CTRL);
+       	    reg = reg & (~(1<<3));
+       	    reg |=(0x1<<3);
+       	    writel(reg, audio_dev.reg_base + ACW_ADC_PATH_CTRL);
+        }
+        else if (line_in == io_type)
+        {
+            rt_kprintf("audio input changed to line_in\n");
+            writel(reg | (1<<1), audio_dev.reg_base + ACW_ADC_PATH_CTRL);
+        }
+    }
+    else
+    {
+        reg = readl(audio_dev.reg_base + ACW_DAC_PATH_CTRL);
+        if (speaker_out == io_type)
+        {
+            rt_kprintf("audio output changed to speaker_out\n");
+            reg = reg & (~(3<<21));
+            reg = reg & (~(3<<30));
+            writel(reg, audio_dev.reg_base + ACW_DAC_PATH_CTRL);
+            reg = reg | (1<<21);
+            writel(reg,audio_dev.reg_base + ACW_DAC_PATH_CTRL);
+            reg = reg | (1<<18);
+            writel(reg, audio_dev.reg_base + ACW_DAC_PATH_CTRL);/*unmute speaker*/
+            reg = reg | (3<<30);
+            writel(reg,audio_dev.reg_base + ACW_DAC_PATH_CTRL);/*mute line out*/
+        }
+        else if (line_out == io_type)
+        {
+            rt_kprintf("audio output changed to line_out\n");
+            reg = reg & (~(3<<21));
+            writel(reg, audio_dev.reg_base + ACW_DAC_PATH_CTRL);/*mute speaker*/
+            reg = reg & (~(3<<30));
+            writel(reg, audio_dev.reg_base + ACW_DAC_PATH_CTRL);/*unmute line out*/
+        }
+    }
+}
+
+int get_factor_from_table(int rate)
+{
+    int factor;
+    switch(rate)
+    {
+        case 8000:
+            factor = 4;
+            break;
+        case 16000:
+            factor = 1;
+            break;
+        case 32000:
+            factor = 0;
+            break;
+        case 44100:
+            factor = 13;
+            break;
+        case 48000:
+            factor = 6;
+            break;
+        default:
+            factor = -EFAULT;
+            break;
+    }
+    return factor;
+}
+
+void switch_rate(enum audio_type type, int rate)
+{
+    int reg, factor;
+    factor = get_factor_from_table(rate);
+    if (factor < 0)
+    {
+        rt_kprintf( "unsupported sample rate\n");
+        return;
+    }
+    reg = readl(audio_dev.reg_base + ACW_DIG_IF_CTRL);
+    if (capture == type)
+    {
+        rt_kprintf("capture rate set to %d\n", rate);
+        reg = reg & (~(0xf<<0));
+        writel(reg, audio_dev.reg_base + ACW_DIG_IF_CTRL);/*adc and dac sample rate*/
+        reg = reg | (factor<<0);
+        writel(reg,audio_dev.reg_base + ACW_DIG_IF_CTRL);
+    }
+    else
+    {
+        rt_kprintf("playback rate set to %d\n", rate);
+        reg = reg & (~(0xf<<8));
+        writel(reg, audio_dev.reg_base + ACW_DIG_IF_CTRL);/*adc and dac sample rate*/
+        reg = reg | (factor<<8);
+        writel(reg, audio_dev.reg_base + ACW_DIG_IF_CTRL);
+    }
+}
+
+int get_param_from_volume(int volume)
+{
+    if(volume < 0)
+        volume = 0;
+    else if(volume > 100)
+        volume = 100;
+
+    volume = volume * 63 / 100;
+    return volume;
+
+}
+
+void switch_input_volume(int volume)
+{
+    int reg, param;
+    param = get_param_from_volume(volume);
+    if (param < 0)
+    {
+    	rt_kprintf("capture volume error\n");
+        return;
+    }
+
+    reg = readl(audio_dev.reg_base + ACW_ADC_PATH_CTRL);
+    reg = reg & (~(0x3f<<8));
+    writel(reg, audio_dev.reg_base + ACW_ADC_PATH_CTRL);
+    reg = reg | (param<<8);
+    writel(reg,audio_dev.reg_base + ACW_ADC_PATH_CTRL);
+}
+
+void init_audio(enum audio_type type,struct fh_audio_cfg  *audio_config)
+{
+    int reg;
+    reg = readl(audio_dev.reg_base + ACW_CTRL);
+    if ((reg & 0x80000000) == 0)
+    {
+        writel(0x80000000, audio_dev.reg_base + ACW_CTRL);/*enable audio*/
+    }
+    reg = readl(audio_dev.reg_base + ACW_MISC_CTRL);
+    if (0x40400 != reg)
+    {
+        writel(0x40400,audio_dev.reg_base + ACW_MISC_CTRL);/*misc ctl*/
+    }
+    if (capture == type)
+    {
+        writel(0x61141b06,audio_dev.reg_base + ACW_ADC_PATH_CTRL);/*adc cfg*/
+        writel(0x167f2307, audio_dev.reg_base + ACW_ADC_ALC_CTRL);/*adc alc*/
+        writel(0, audio_dev.reg_base + ACW_RXFIFO_CTRL);/*rx fifo disable*/
+        switch_input_volume(audio_config->capture.cfg.volume);
+        switch_rate(capture, audio_config->capture.cfg.rate);
+        switch_io_type(capture, audio_config->capture.cfg.io_type);
+    }
+    else
+    {
+        writel(0x3b403f09, audio_dev.reg_base + ACW_DAC_PATH_CTRL);/*dac cfg*/
+        writel(0, audio_dev.reg_base + ACW_TXFIFO_CTRL);/*tx fifo disable*/
+        switch_rate(playback, audio_config->playback.cfg.rate);
+        switch_io_type(playback, audio_config->playback.cfg.io_type);
+    }
+
+}
+
+static inline long bytes_to_frames(int frame_bit, int bytes)
+{
+    return bytes * 8 /frame_bit;
+}
+
+static inline long  frames_to_bytes(int frame_bit, int frames)
+{
+    return frames * frame_bit / 8;
+}
+
+int avail_data_len(enum audio_type type,struct fh_audio_cfg *stream)
+{
+    int delta;
+    if (capture == type)
+    {
+
+
+        delta = stream->capture.hw_ptr - stream->capture.appl_ptr;
+
+        if (delta < 0)
+        {
+            delta += stream->capture.size;
+        }
+        return delta;
+    }
+    else
+    {
+
+
+        delta = stream->playback.appl_ptr - stream->playback.hw_ptr;
+
+        if (delta < 0)
+        {
+            delta += stream->playback.size;
+        }
+        return stream->playback.size - delta;
+    }
+}
+
+static rt_err_t fh_audio_close(rt_device_t dev)
+{
+    struct fh_audio_cfg  *audio_config = dev->user_data;
+    unsigned int reg;
+
+    //disable interrupts
+    reg = readl(audio_dev.reg_base + ACW_CTRL);
+    reg &= ~(0x3ff);
+    writel(reg, audio_dev.reg_base + ACW_CTRL);
+
+        fh_acw_stop_playback(audio_config);
+
+        fh_acw_stop_capture(audio_config);
+
+}
+
+int register_tx_dma(struct fh_audio_cfg  *audio_config)
+{
+    int ret;
+    struct dma_transfer *playback_trans;
+    playback_trans = audio_config->plauback_trans;
+    struct rt_dma_device *rt_dma_dev;
+    rt_dma_dev = audio_config->playback_dma;
+    if ((audio_config->playback.cfg.buffer_bytes < audio_config->playback.cfg.period_bytes) ||
+        (audio_config->playback.cfg.buffer_bytes <= 0) || (audio_config->playback.cfg.period_bytes <= 0))
+    {
+        rt_kprintf( "buffer_size and  period_size are invalid\n");
+        return RT_ERROR;
+    }
+
+    if(playback_trans->channel_number == ACW_PLY_DMA_CHAN){
+
+    	ret = rt_dma_dev->ops->control(rt_dma_dev,RT_DEVICE_CTRL_DMA_CYCLIC_PREPARE,playback_trans);
+    	if(ret){
+    		rt_kprintf("can't playback cyclic prepare \n");
+    		return RT_ERROR;
+    	}
+    	ret = 	rt_dma_dev->ops->control(rt_dma_dev,RT_DEVICE_CTRL_DMA_CYCLIC_START,playback_trans);
+    	if(ret){
+    		rt_kprintf("can't playback cyclic start \n");
+    		return RT_ERROR;
+    	}
+    }
+    else
+    	return RT_ERROR;
+    return 0;
+}
+
+int register_rx_dma( struct fh_audio_cfg  *audio_config)
+{
+	int ret;
+    struct dma_transfer *capture_slave;
+    capture_slave = audio_config->capture_trans;
+    struct rt_dma_device *rt_dma_dev;
+    rt_dma_dev = audio_config->capture_dma;
+    if (!capture_slave)
+    {
+        return -ENOMEM;
+    }
+
+    if ((audio_config->capture.cfg.buffer_bytes < audio_config->capture.cfg.period_bytes) ||
+       (audio_config->capture.cfg.buffer_bytes <= 0) ||(audio_config->capture.cfg.period_bytes <= 0) )
+    {
+        rt_kprintf( "buffer_size and  period_size are invalid\n");
+        return RT_ERROR;
+    }
+    if(capture_slave->channel_number==ACW_CAP_DMA_CHAN){
+    	ret = rt_dma_dev->ops->control(rt_dma_dev,RT_DEVICE_CTRL_DMA_CYCLIC_PREPARE,capture_slave);
+    	if(ret){
+    		rt_kprintf("can't capture cyclic prepare \n");
+    		return RT_ERROR;
+    	}
+    	ret = rt_dma_dev->ops->control(rt_dma_dev,RT_DEVICE_CTRL_DMA_CYCLIC_START,capture_slave);
+    	if(ret){
+    		rt_kprintf("can't capture cyclic start \n");
+    		return RT_ERROR;
+    	}
+    }
+    else
+    	return RT_ERROR;
+    writel(0x11,audio_dev.reg_base  + ACW_RXFIFO_CTRL);//clear rx fifo
+    writel(0x30029,audio_dev.reg_base + ACW_RXFIFO_CTRL);/*enable rx fifo*/
+
+    return 0;
+
+}
+
+
+void playback_start_wq_handler(struct work_struct *work)
+{
+    int avail;
+    unsigned int rx_status;
+    while(1)
+    {
+        if (stopping == audio_dev.audio_config->playback.state)
+        {
+            return;
+        }
+        avail = avail_data_len(playback, audio_dev.audio_config);
+        if (avail < audio_dev.audio_config->playback.cfg.period_bytes)
+        {
+            rt_thread_sleep(0);
+        }
+        else
+        {
+            rx_status = readl( audio_dev.reg_base + ACW_TXFIFO_CTRL);//clear rx fifo
+            rx_status =  rx_status|(1<<4);
+            writel(rx_status,audio_dev.reg_base + ACW_TXFIFO_CTRL);
+            writel(0x30029, audio_dev.reg_base + ACW_TXFIFO_CTRL);
+            break;
+        }
+    }
+}
+
+int fh_acw_start_playback(struct fh_audio_cfg *audio_config)
+{
+    int ret;
+
+    if(audio_config->playback.state == running)
+    {
+        rt_kprintf("playback is running \n");
+        return 0;
+    }
+
+    if (audio_config->playback.cfg.buffer_bytes >= AUDIO_DMA_PREALLOC_SIZE)
+    {
+        rt_kprintf("DMA prealloc buffer is smaller than  audio_config->buffer_bytes %x\n",audio_config->playback.cfg.buffer_bytes);
+        return -ENOMEM;
+    }
+    reset_dma_buff(playback,audio_config);
+    rt_memset(audio_config->playback.area, 0, audio_config->playback.cfg.buffer_bytes);
+    audio_config->playback.size = audio_config->playback.cfg.buffer_bytes;
+    audio_config->playback.state = running;
+    ret =  audio_request_playback_channel(audio_config);
+    if(ret){
+    	rt_kprintf("can't request playback channel\n");
+    	return ret;
+    }
+    ret = register_tx_dma(audio_config);
+    if (ret < 0)
+    {
+    	rt_kprintf("can't register tx dma\n");
+        return ret;
+    }
+    rt_list_init(&(playback_wq.list));
+    playback_wq.work_func = (void *)playback_start_wq_handler;
+    playback_wq.work_data = RT_NULL;
+    playback_queue = rt_workqueue_create("play_workqueue",WORK_QUEUE_STACK_SIZE,WORK_QUEUE_PRIORITY);
+    if(!playback_queue){
+
+        rt_kprintf("init work_queue error....\n");
+        return -1;
+    }
+    rt_workqueue_dowork(playback_queue,&playback_wq);
+    return 0;
+}
+
+int fh_acw_start_capture(struct fh_audio_cfg *audio_config)
+{
+	int ret;
+    if(audio_config->capture.state == running)
+    {
+        return 0;
+    }
+    if (audio_config->capture.cfg.buffer_bytes >= AUDIO_DMA_PREALLOC_SIZE)
+    {
+        rt_kprintf("DMA prealloc buffer is smaller than  audio_config->buffer_bytes %x\n",audio_config->capture.cfg.buffer_bytes);
+        return -ENOMEM;
+    }
+    reset_dma_buff(capture,audio_config);
+    rt_memset(audio_config->capture.area, 0, audio_config->capture.cfg.buffer_bytes);
+    audio_config->capture.size = audio_config->capture.cfg.buffer_bytes;
+    audio_config->capture.state = running;
+    ret = audio_request_capture_channel(audio_config);
+    if(ret){
+    	rt_kprintf("can't request capture channel \n");
+    	return ret;
+    }
+
+    return register_rx_dma(audio_config);
+}
+
+static void fh_acw_rx_dma_done(struct fh_audio_cfg *arg)
+{
+#if 1
+    struct fh_audio_cfg *audio_config;
+    audio_config = arg;
+
+    audio_config->capture.hw_ptr += audio_config->capture.cfg.period_bytes;
+
+    if (audio_config->capture.hw_ptr > audio_config->capture.size ) // TBD_WAIT ...
+    {
+        audio_config->capture.hw_ptr = audio_config->capture.hw_ptr - audio_config->capture.size;
+
+    }
+
+    int avail = avail_data_len(capture,audio_config);
+    if (avail > audio_config->capture.cfg.period_bytes)
+    {
+        rt_sem_release(&audio_config->sem_capture);
+    }
+#endif
+}
+
+static void fh_acw_tx_dma_done(void *arg)
+{
+#if 1
+    struct fh_audio_cfg *audio_config;
+    audio_config = ( struct fh_audio_cfg *)arg;
+
+
+    audio_config->playback.hw_ptr +=  audio_config->playback.cfg.period_bytes;
+
+    if (audio_config->playback.hw_ptr > audio_config->playback.size )
+    {
+
+        audio_config->playback.hw_ptr = audio_config->playback.hw_ptr - audio_config->playback.size;
+    }
+
+	int avail = avail_data_len(playback,audio_config);
+	if (avail > audio_config->playback.cfg.period_bytes)
+	{
+
+		rt_sem_release(&audio_config->sem_playback);
+	}
+
+#endif
+}
+
+bool  fh_acw_dma_chan_filter(struct dma_chan *chan, void *filter_param)
+{
+
+}
+
+int arg_config_support(struct fh_audio_cfg_arg * cfg)
+{
+    int ret;
+
+    ret = get_param_from_volume(cfg->volume);
+    if (ret < 0) {
+    	rt_kprintf("invalid volume\n");
+        return -EINVAL;
+    }
+    ret = get_factor_from_table(cfg->rate);
+    if (ret < 0) {
+    	rt_kprintf("invalid rate\n");
+        return -EINVAL;
+    }
+    return 0;
+}
+
+void reset_dma_buff(enum audio_type type, struct fh_audio_cfg *audio_config)
+{
+    if (capture == type)
+    {
+        audio_config->capture.appl_ptr = 0;
+        audio_config->capture.hw_ptr = 0;
+    }
+    else
+    {
+        audio_config->playback.appl_ptr = 0;
+        audio_config->playback.hw_ptr = 0;
+    }
+}
+
+
+static rt_err_t fh_audio_ioctl(rt_device_t dev, rt_uint8_t cmd, void *arg)
+{
+    struct fh_audio_cfg_arg *cfg;
+
+    struct fh_audio_cfg  *audio_config = (struct fh_audio_cfg *)dev->user_data;
+    int ret;
+    int reg;
+    int value,pid;
+    int  *p = (int  *)arg;
+    int rx_status,tx_status;
+
+    switch (cmd)
+    {
+        case AC_INIT_CAPTURE_MEM:
+
+            cfg = (struct fh_audio_cfg_arg *)arg;
+            if (0 == arg_config_support(cfg))
+            {
+                audio_config->capture.cfg.io_type = cfg->io_type;
+                audio_config->capture.cfg.volume = cfg->volume;
+                audio_config->capture.cfg.rate = cfg->rate;
+                audio_config->capture.cfg.channels = cfg->channels;
+                audio_config->capture.cfg.buffer_size = cfg->buffer_size;
+                audio_config->capture.cfg.frame_bit = FIX_SAMPLE_BIT;
+                audio_config->capture.cfg.period_size = cfg->period_size;
+                audio_config->capture.cfg.buffer_bytes = frames_to_bytes(audio_config->capture.cfg.frame_bit,audio_config->capture.cfg.buffer_size);
+                audio_config->capture.cfg.period_bytes = frames_to_bytes(audio_config->capture.cfg.frame_bit,audio_config->capture.cfg.period_size);
+                audio_config->capture.cfg.start_threshold =audio_config->capture.cfg.buffer_bytes;
+                audio_config->capture.cfg.stop_threshold = audio_config->capture.cfg.buffer_bytes;
+                audio_prealloc_dma_buffer((int)cfg->io_type,audio_config);
+                reset_dma_buff(capture, audio_config);
+
+                rt_mutex_init(&audio_config->capture.lock, "audio_c", RT_IPC_FLAG_PRIO);
+                init_audio(capture, audio_config);
+                audio_param_store.input_io_type = audio_config->capture.cfg.io_type;
+                audio_param_store.input_volume = audio_config->capture.cfg.volume;
+
+            }
+            else
+            {
+                return -EINVAL;
+            }
+
+            break;
+        case AC_INIT_PLAYBACK_MEM:
+            cfg = arg;
+
+            if (0 == arg_config_support(cfg))
+            {
+                audio_config->playback.cfg.io_type = cfg->io_type;
+                audio_config->playback.cfg.volume = cfg->volume;
+                audio_config->playback.cfg.rate = cfg->rate;
+                audio_config->playback.cfg.channels = cfg->channels;
+                audio_config->playback.cfg.buffer_size = cfg->buffer_size;
+                audio_config->playback.cfg.frame_bit = FIX_SAMPLE_BIT;
+                audio_config->playback.cfg.period_size = cfg->period_size;
+                audio_config->playback.cfg.buffer_bytes = frames_to_bytes(audio_config->playback.cfg.frame_bit,audio_config->playback.cfg.buffer_size);
+                audio_config->playback.cfg.period_bytes = frames_to_bytes(audio_config->playback.cfg.frame_bit,audio_config->playback.cfg.period_size);
+                audio_config->playback.cfg.start_threshold =audio_config->playback.cfg.buffer_bytes;
+                audio_config->playback.cfg.stop_threshold = audio_config->playback.cfg.buffer_bytes;
+                audio_prealloc_dma_buffer((int)cfg->io_type,audio_config); // TBD_WAIT ...
+                reset_dma_buff(playback, audio_config);
+
+                rt_mutex_init(&audio_config->playback.lock, "audio_p", RT_IPC_FLAG_PRIO);
+
+                init_audio(playback, audio_config);
+
+            }
+            else
+            {
+                return -EINVAL;
+            }
+            break;
+        case AC_AI_EN:
+            return fh_acw_start_capture(audio_config);
+        case AC_AO_EN:
+            rt_kprintf("ao en \n");
+            return fh_acw_start_playback(audio_config);
+
+        case AC_SET_VOL:
+            value = *(rt_uint32_t *)arg;
+            ret = get_param_from_volume(value);
+            if (ret < 0) {
+                return -EINVAL;
+            }
+            audio_param_store.input_volume = value;
+            switch_input_volume(audio_param_store.input_volume);
+            break;
+        case AC_SET_INPUT_MODE:
+
+            value = *(rt_uint32_t *)arg;
+            if (value != mic_in && value != line_in) {
+                return -EINVAL;
+            }
+            audio_param_store.input_io_type = value;
+            switch_io_type(capture, audio_param_store.input_io_type);
+            break;
+        case AC_SET_OUTPUT_MODE:
+            value = *(rt_uint32_t *)arg;
+
+            if (value != speaker_out && value != line_out) {
+                return -EINVAL;
+            }
+            switch_io_type(playback, value);
+            break;
+        case AC_AI_DISABLE:
+            rt_kprintf(" AC_AI_DISABLE\n");
+
+            fh_acw_stop_capture(audio_config);
+            if (audio_config->capture_trans != RT_NULL)
+            {
+                rt_free(audio_config->capture_trans);
+                audio_config->capture_trans = NULL;
+            }
+            break;
+        case AC_AO_DISABLE:
+            rt_kprintf("[ac_driver]AC_AO_DISABLE\n");
+
+            fh_acw_stop_playback(audio_config);
+            if (audio_config->plauback_trans != RT_NULL)
+            {
+                rt_free(audio_config->plauback_trans);
+                audio_config->plauback_trans = NULL;
+            }
+            rt_kprintf(" AC_AO_DISABLE\n");
+            break;
+        case AC_AI_PAUSE:
+
+            rt_kprintf( "capture pause\n");
+            rx_status = readl(audio_dev.reg_base + ACW_RXFIFO_CTRL);/*rx fifo disable*/
+            rx_status =  rx_status&(~(1<<0));
+            writel(rx_status, audio_dev.reg_base + ACW_RXFIFO_CTRL);/*rx fifo disable*/
+            break;
+        case AC_AI_RESUME:
+
+            rt_kprintf( "capture resume\n");
+            rx_status = readl( audio_dev.reg_base + ACW_RXFIFO_CTRL);//clear rx fifo
+            rx_status =  rx_status|(1<<4);
+            writel(rx_status,audio_dev.reg_base+ ACW_RXFIFO_CTRL);/*enable rx fifo*/
+            rx_status =  rx_status&(~(1<<4));
+            rx_status =  rx_status|(1<<0);
+            writel(rx_status,audio_dev.reg_base + ACW_RXFIFO_CTRL);/*enable rx fifo*/
+            break;
+        case AC_AO_PAUSE:
+
+            rt_kprintf( "playback pause\n");
+            tx_status = readl(audio_dev.reg_base + ACW_TXFIFO_CTRL);/*rx fifo disable*/
+            tx_status =  tx_status&(~(1<<0));
+            writel(tx_status, audio_dev.reg_base + ACW_TXFIFO_CTRL);/*tx fifo disable*/
+            break;
+        case AC_AO_RESUME:
+
+            rt_kprintf( "playback resume\n");
+            tx_status = readl( audio_dev.reg_base + ACW_TXFIFO_CTRL);//clear rx fifo
+            tx_status =  tx_status|(1<<0);
+            writel(tx_status,audio_dev.reg_base + ACW_TXFIFO_CTRL); //enable tx fifo read enable
+            break;
+        default:
+            return -ENOTTY;
+    }
+    return 0;
+}
+
+static rt_err_t fh_audio_open(rt_device_t dev, rt_uint16_t oflag)
+{
+
+    unsigned int reg;
+    struct fh_audio_cfg  *audio_config = dev->user_data;
+    //enable interrupts
+    reg = readl(audio_dev.reg_base + ACW_CTRL);
+    reg |= 0xa;
+    writel(reg, audio_dev.reg_base + ACW_CTRL);
+
+    return 0;
+}
+
+static rt_err_t fh_audio_tx_poll(rt_device_t dev, void *buffer){
+    struct fh_audio_cfg  *audio_config = dev->user_data;
+      unsigned int mask = 0;
+        long avail;
+
+        if (running == audio_config->playback.state)
+        {
+
+            rt_sem_take(&audio_config->sem_playback, RT_WAITING_FOREVER);
+            avail = avail_data_len(playback, audio_config);
+            if (avail >  audio_config->playback.cfg.period_bytes)
+            {
+                mask |=  POLLOUT | POLLWRNORM;
+            }
+        }
+
+        return mask;
+}
+
+static rt_err_t fh_audio_rx_poll(rt_device_t dev, rt_size_t size){
+
+    struct fh_audio_cfg  *audio_config = dev->user_data;
+      unsigned int mask = 0;
+        long avail;
+        if (running == audio_config->capture.state)
+        {
+            rt_sem_take(&audio_config->sem_capture, RT_WAITING_FOREVER);
+            avail = avail_data_len(capture, audio_config);
+            if (avail >  audio_config->capture.cfg.period_bytes)
+            {
+                mask |=  POLLIN | POLLRDNORM;
+            }
+        }
+        return mask;
+}
+static dma_complete_callback mem_complete(void *p){
+
+    struct rt_completion *completion = (struct rt_completion *)p;
+
+    rt_completion_done(completion);
+}
+
+static rt_size_t fh_audio_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
+{
+
+    int ret;
+    struct fh_audio_cfg  *audio_config = dev->user_data;
+    int after,left;
+    int pid,avail;
+
+
+
+    avail = avail_data_len(capture, audio_config);
+    if (avail > size)
+    {
+        avail = size;
+    }
+    after = avail + audio_config->capture.appl_ptr;
+    if(after  > audio_config->capture.size)
+    {
+        left = avail - (audio_config->capture.size - audio_config->capture.appl_ptr);
+        rt_memcpy(buffer, audio_config->capture.area+audio_config->capture.appl_ptr, audio_config->capture.size-audio_config->capture.appl_ptr);
+        rt_memcpy(buffer+audio_config->capture.size-audio_config->capture.appl_ptr,audio_config->capture.area,left);
+        rt_mutex_take(&audio_config->capture.lock, RT_WAITING_FOREVER);
+        audio_config->capture.appl_ptr = left;
+        rt_mutex_release(&audio_config->capture.lock);
+
+    }
+    else
+    {
+        rt_memcpy(buffer,audio_config->capture.area+audio_config->capture.appl_ptr,avail);
+        rt_mutex_take(&audio_config->capture.lock, RT_WAITING_FOREVER);
+        audio_config->capture.appl_ptr += avail;
+        rt_mutex_release(&audio_config->capture.lock);
+
+    }
+    return avail;
+
+}
+
+static rt_size_t fh_audio_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
+{
+
+    struct fh_audio_cfg  *audio_config = dev->user_data;
+    int  ret;
+    int after,left;
+    int pid,avail;
+
+    avail = avail_data_len(playback,audio_config);
+    if (0 == avail)
+    {
+        return 0;
+    }
+    if (avail > size)
+    {
+        avail = size;
+    }
+    after = avail+audio_config->playback.appl_ptr;
+    if(after  > audio_config->playback.size)
+    {
+        left = avail - (audio_config->playback.size-audio_config->playback.appl_ptr);
+        rt_memcpy(audio_config->playback.area+audio_config->playback.appl_ptr,buffer,audio_config->playback.size-audio_config->playback.appl_ptr);
+        rt_memcpy(audio_config->playback.area,buffer+audio_config->playback.size-audio_config->playback.appl_ptr,left);
+        rt_mutex_take(&audio_config->playback.lock, RT_WAITING_FOREVER);
+        audio_config->playback.appl_ptr = left;
+        rt_mutex_release(&audio_config->playback.lock);
+
+    }
+    else
+    {
+        rt_memcpy(audio_config->playback.area+audio_config->playback.appl_ptr,buffer,avail);
+        rt_mutex_take(&audio_config->playback.lock, RT_WAITING_FOREVER);
+        audio_config->playback.appl_ptr += avail;
+        rt_mutex_release(&audio_config->playback.lock);
+    }
+     return avail;
+}
+
+static void fh_audio_interrupt(int irq, void *param)
+{
+    unsigned int interrupts, reg;
+    struct fh_audio_cfg  *audio_config = audio_dev.audio_config;
+
+    interrupts = readl(audio_dev.reg_base + ACW_CTRL);
+    writel(interrupts, audio_dev.reg_base + ACW_CTRL);
+
+    if(interrupts & ACW_INTR_RX_UNDERFLOW)
+    {
+        fh_acw_stop_capture(audio_config);
+        fh_acw_start_capture(audio_config);
+        rt_kprintf("ACW_INTR_RX_UNDERFLOW\n");
+    }
+
+    if(interrupts & ACW_INTR_RX_OVERFLOW)
+    {
+        fh_acw_stop_capture(audio_config);
+        fh_acw_start_capture(audio_config);
+        rt_kprintf("ACW_INTR_RX_OVERFLOW\n");
+    }
+
+    if(interrupts & ACW_INTR_TX_UNDERFLOW)
+    {
+        fh_acw_stop_capture(audio_config);
+        fh_acw_start_capture(audio_config);
+        rt_kprintf("ACW_INTR_TX_UNDERFLOW\n");
+    }
+
+    if(interrupts & ACW_INTR_TX_OVERFLOW)
+    {
+        fh_acw_stop_capture(audio_config);
+        fh_acw_start_capture(audio_config);
+        rt_kprintf("ACW_INTR_TX_OVERFLOW\n");
+    }
+
+    rt_kprintf("interrupts: 0x%x\n", interrupts);
+
+
+}
+
+
+void audio_prealloc_dma_buffer(int aiaotype,struct fh_audio_cfg  *audio_config)
+{
+
+	 if(aiaotype == mic_in || aiaotype == line_in){
+    audio_config->capture.area  = (void *)fh_dma_mem_malloc(audio_config->capture.cfg.buffer_bytes \
+            + audio_config->capture.cfg.period_bytes);
+
+    if (!audio_config->capture.area)
+    {
+        rt_kprintf("no enough mem for capture  buffer alloc\n");
+        return ;
+    }
+	 }
+	 if(aiaotype == speaker_out || aiaotype == line_out){
+    audio_config->playback.area  = (void *)fh_dma_mem_malloc(audio_config->playback.cfg.buffer_bytes \
+            + audio_config->playback.cfg.period_bytes);
+
+    if (!audio_config->playback.area)
+    {
+        rt_kprintf("no enough mem for  playback buffer alloc\n");
+        return ;
+    }}
+
+}
+
+void audio_free_prealloc_dma_buffer(struct fh_audio_cfg  *audio_config)
+{
+
+    rt_free( audio_config->capture.area);
+    rt_free( audio_config->playback.area);
+}
+
+static void init_audio_mutex(struct fh_audio_cfg  *audio_config)
+{
+    rt_sem_init(&audio_config->sem_capture, "sem_capture", 0, RT_IPC_FLAG_FIFO);
+    rt_sem_init(&audio_config->sem_playback, "sem_playback", 0, RT_IPC_FLAG_FIFO);
+}
+int audio_request_capture_channel(struct fh_audio_cfg  *audio_config){
+    struct rt_dma_device *rt_dma_dev;
+    /*request audio rx dma channel*/
+    struct dma_transfer *dma_rx_transfer;
+    int ret;
+    dma_rx_transfer = rt_malloc(sizeof(struct dma_transfer));
+
+    if (!dma_rx_transfer)
+    {
+        rt_kprintf("alloc  dma_rx_transfer failed\n");
+        return RT_ENOMEM;
+    }
+
+    rt_memset(dma_rx_transfer, 0, sizeof(struct dma_transfer));
+    rt_dma_dev = (struct rt_dma_device *)rt_device_find("fh81_dma");
+
+    if(rt_dma_dev == RT_NULL){
+        rt_kprintf("can't find dma dev\n");
+
+        return -1;
+    }
+    audio_config->capture_dma = rt_dma_dev;
+    audio_config->capture_trans = dma_rx_transfer;
+    rt_dma_dev->ops->init(rt_dma_dev);
+
+    dma_rx_transfer->channel_number = ACW_CAP_DMA_CHAN;
+
+    dma_rx_transfer->dma_number = 0;
+
+    dma_rx_transfer->dst_add = (rt_uint32_t)audio_config->capture.area;//audio_config->capture.area;//(rt_uint32_t)&tx_buff[0];
+    dma_rx_transfer->dst_inc_mode = DW_DMA_SLAVE_INC;
+    dma_rx_transfer->dst_msize = DW_DMA_SLAVE_MSIZE_32;
+
+    dma_rx_transfer->dst_width = DW_DMA_SLAVE_WIDTH_32BIT;
+    dma_rx_transfer->fc_mode = DMA_P2M;
+
+    dma_rx_transfer->src_add = (rt_uint32_t)ACW_RXFIFO;
+
+    dma_rx_transfer->src_inc_mode = DW_DMA_SLAVE_FIX;
+    dma_rx_transfer->src_msize = DW_DMA_SLAVE_MSIZE_32;
+    dma_rx_transfer->src_hs = DMA_HW_HANDSHAKING;
+    dma_rx_transfer->src_width = DW_DMA_SLAVE_WIDTH_32BIT;
+    dma_rx_transfer->trans_len = (audio_config->capture.cfg.buffer_bytes / 4); // DW_DMA_SLAVE_WIDTH_32BIT BUFF_SIZE;
+    dma_rx_transfer->src_per =ACODEC_RX;
+    dma_rx_transfer->period_len = audio_config->capture.cfg.period_bytes / 4;// (audio_config->capture.cfg.period_bytes / 4); // TEST_PER_NO;
+    dma_rx_transfer->complete_callback =(dma_complete_callback)fh_acw_rx_dma_done;
+    dma_rx_transfer->complete_para = audio_config;
+
+    rt_dma_dev->ops->control(rt_dma_dev,RT_DEVICE_CTRL_DMA_OPEN,dma_rx_transfer);
+    ret = rt_dma_dev->ops->control(rt_dma_dev,RT_DEVICE_CTRL_DMA_REQUEST_CHANNEL,dma_rx_transfer);
+    if(ret){
+    	rt_kprintf("can't request capture channel\n");
+    	dma_rx_transfer->channel_number =0xff;
+    	return -ret;
+    }
+
+}
+
+int audio_request_playback_channel(struct fh_audio_cfg  *audio_config)
+{
+    struct rt_dma_device *rt_dma_dev;
+    int ret;
+    struct dma_transfer *dma_tx_transfer;
+    dma_tx_transfer = rt_malloc(sizeof(struct dma_transfer));
+    if (!dma_tx_transfer)
+    {
+        rt_kprintf("alloc  dma_tx_transfer failed\n");
+        return RT_ENOMEM;
+
+    }
+    audio_config->plauback_trans = dma_tx_transfer;
+    rt_dma_dev = (struct rt_dma_device *)rt_device_find("fh81_dma");
+
+    if(rt_dma_dev == RT_NULL){
+        rt_kprintf("can't find dma dev\n");
+        return -1;
+    }
+    rt_dma_dev->ops->init(rt_dma_dev);
+    audio_config->playback_dma = rt_dma_dev;
+
+    rt_memset(dma_tx_transfer, 0, sizeof(struct dma_transfer));
+    dma_tx_transfer->channel_number = ACW_PLY_DMA_CHAN;
+    dma_tx_transfer->dma_number = 0;
+    dma_tx_transfer->dst_add = (rt_uint32_t)ACW_TXFIFO;
+    dma_tx_transfer->dst_hs = DMA_HW_HANDSHAKING;
+    dma_tx_transfer->dst_inc_mode = DW_DMA_SLAVE_FIX;
+    dma_tx_transfer->dst_msize = DW_DMA_SLAVE_MSIZE_32;
+    dma_tx_transfer->dst_per = ACODEC_TX;
+    dma_tx_transfer->dst_width = DW_DMA_SLAVE_WIDTH_32BIT;
+    dma_tx_transfer->fc_mode = DMA_M2P;
+    dma_tx_transfer->src_add = (rt_uint32_t)audio_config->playback.area;
+    dma_tx_transfer->src_inc_mode = DW_DMA_SLAVE_INC;
+    dma_tx_transfer->src_msize = DW_DMA_SLAVE_MSIZE_32;
+    dma_tx_transfer->src_width = DW_DMA_SLAVE_WIDTH_32BIT;
+    dma_tx_transfer->trans_len = (audio_config->playback.cfg.buffer_bytes / 4);// BUFF_SIZE;
+    dma_tx_transfer->period_len =  (audio_config->playback.cfg.period_bytes / 4); // TEST_PER_NO;
+    dma_tx_transfer->complete_callback =(dma_complete_callback)fh_acw_tx_dma_done;
+    dma_tx_transfer->complete_para = audio_config;
+    rt_dma_dev->ops->control(rt_dma_dev,RT_DEVICE_CTRL_DMA_OPEN,dma_tx_transfer);
+    ret = rt_dma_dev->ops->control(rt_dma_dev,RT_DEVICE_CTRL_DMA_REQUEST_CHANNEL,dma_tx_transfer);
+    if(ret){
+    	rt_kprintf("can't request playbak channel\n");
+    	dma_tx_transfer->channel_number = 0xff;
+    	return -ret;
+    }
+    return 0;
+
+}
+
+void audio_release_dma_channel(struct fh_audio_cfg  *audio_config)
+{
+
+    if (audio_config->plauback_trans != RT_NULL)
+    {
+        audio_config->playback_dma->ops->control(audio_config->playback_dma,RT_DEVICE_CTRL_DMA_RELEASE_CHANNEL,audio_config->plauback_trans);
+        rt_free(audio_config->plauback_trans);
+        audio_config->plauback_trans = NULL;
+    }
+
+
+    if (audio_config->capture_trans != RT_NULL)
+    {
+        audio_config->capture_dma->ops->control(audio_config->capture_dma,RT_DEVICE_CTRL_DMA_RELEASE_CHANNEL,audio_config->capture_trans);
+        rt_free(audio_config->capture_trans);
+        audio_config->capture_trans = NULL;
+    }
+
+
+}
+
+void  fh_audio_init(void)
+{
+
+     struct fh_audio_cfg  *audio_config;
+     audio_config = rt_malloc(sizeof(struct fh_audio_cfg));
+     memset(audio_config,0,sizeof(struct fh_audio_cfg)); // new add
+
+     audio_dev.reg_base = 0xf0a00000;
+     init_audio_mutex(audio_config);
+
+     rt_device_t audio ;
+     audio = rt_malloc(sizeof(struct rt_device));
+     if (audio == RT_NULL){
+         rt_kprintf("%s no mem \n",__func__);
+     }
+
+     audio->user_data = audio_config;
+     audio->open =fh_audio_open;
+     audio->read = fh_audio_read;
+     audio->write = fh_audio_write;
+     audio->close = fh_audio_close;
+     audio->control = fh_audio_ioctl;
+     audio->rx_indicate =fh_audio_rx_poll;
+     audio->tx_complete=fh_audio_tx_poll;
+     audio_dev.audio_config = audio_config; // TBD_WAIT 2015.09.17 add
+
+     rt_device_register(audio, "audio", RT_DEVICE_FLAG_RDWR);
+
+}
+
+
+
+#if ACW_SELFTEST
+
+#define TEST_FN        "/audio.dat"
+
+static rt_uint32_t rx_buff[BUFF_SIZE] __attribute__((aligned(32))) ;
+static const rt_uint32_t tx_buff[BUFF_SIZE*2] __attribute__((aligned(32)))= {
+        0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,
+        0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,
+        0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,
+        0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,
+        0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,
+
+};
+
+
+
+
+
+ struct fh_audio_cfg_arg cfg;
+
+void fh_acw_test(){
+    rt_device_t acw_dev ;
+    int i;
+    int output=3;
+    int select;
+    int select_rx_status =0;
+    int select_tx_status =0;
+    int fd;
+    int index, length;
+    int mic_boost=1;
+    int ret;
+    acw_dev = ( rt_device_t )rt_device_find("audio");
+    for(i=0;i<BUFF_SIZE;i++)
+        rx_buff[i] = i*0x500;
+    acw_dev->open(acw_dev,0);
+    cfg.buffer_size = BUFF_SIZE;
+    cfg.channels =0;
+    cfg.frame_bit = 16;
+
+    cfg.io_type = mic_in;
+    
+    cfg.period_size = BUFF_SIZE/8;
+    cfg.rate = 8000;
+    cfg.volume = 80;
+
+//    for(i=0;i<100;i++){
+//    acw_dev->control(acw_dev,AC_INIT_CAPTURE_MEM,&cfg);
+//
+//    acw_dev->control(acw_dev,AC_AI_EN,&cfg);
+//    cfg.io_type = line_out;
+//    acw_dev->control(acw_dev,AC_INIT_PLAYBACK_MEM,&cfg);
+//    acw_dev->control(acw_dev,AC_AO_EN,&cfg);
+//    acw_dev->control(acw_dev,AC_SET_OUTPUT_MODE,&output);
+//    acw_dev->control(acw_dev,AC_AI_DISABLE,&cfg);
+//
+//    acw_dev->control(acw_dev,AC_AO_DISABLE,&cfg);
+//    rt_kprintf(" %d \n",i);
+//    }
+
+    cfg.io_type = mic_in;
+    acw_dev->control(acw_dev,AC_INIT_CAPTURE_MEM,&cfg);
+
+    ret = acw_dev->control(acw_dev,AC_AI_EN,&cfg);
+    if(ret)
+    	acw_dev->control(acw_dev,AC_AI_DISABLE,&cfg);
+    cfg.io_type = line_out;
+    acw_dev->control(acw_dev,AC_INIT_PLAYBACK_MEM,&cfg);
+    ret = acw_dev->control(acw_dev,AC_AO_EN,&cfg);
+    if(ret){
+    	acw_dev->control(acw_dev,AC_AO_DISABLE,&cfg);
+   // acw_dev->control(acw_dev,AC_SET_OUTPUT_MODE,&output);
+    	return ;
+    }
+
+
+	 for(i=0;i<100;i++)
+ {
+
+rx:
+        select = acw_dev->rx_indicate(acw_dev,RT_NULL);
+        if(!select)
+        goto rx;
+
+
+        acw_dev->read(acw_dev,0,&rx_buff[0],1024*8);
+
+tx:
+        select = acw_dev->tx_complete(acw_dev , RT_NULL);
+        if(!select)
+        goto tx;
+
+        acw_dev->write(acw_dev,0,&rx_buff[0],1024*8);
+
+    }
+ 	acw_dev->close(acw_dev);
+
+}
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+FINSH_FUNCTION_EXPORT(fh_acw_test, fh_acw_test);
+#endif
+#endif
+#endif
+

+ 232 - 0
bsp/fh8620/drivers/acw.h

@@ -0,0 +1,232 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef ACW_H_
+#define ACW_H_
+#include <rtthread.h>
+#include <rtdevice.h>
+#ifdef RT_USING_DFS
+#include <dfs_fs.h>
+#endif
+#include <rthw.h>
+#define ACW_CAP_DMA_CHAN 2
+#define ACW_PLY_DMA_CHAN 3
+typedef unsigned long long dma_addr_t;
+struct scatterlist {
+#ifdef CONFIG_DEBUG_SG
+	unsigned long	sg_magic;
+#endif
+	unsigned long	page_link;
+	unsigned int	offset;
+	unsigned int	length;
+	dma_addr_t	dma_address;
+#ifdef CONFIG_NEED_SG_DMA_LENGTH
+	unsigned int	dma_length;
+#endif
+};
+#define readl(a)          (*(volatile rt_uint32_t   *)(a))
+#define rkqueue_struct		rt_workqueue
+#define work_struct				rt_work
+#define INIT_WORK(work,func)	rt_work_init(work,func,RT_NULL);
+#define queue_work				rt_workqueue_dowork
+
+
+//timer
+#define timer_list				rt_timer
+#define wait_queue_head_t				struct rt_event
+#define init_waitqueue_head(event_t) 		rt_event_init(event_t, "audio_event", RT_IPC_FLAG_FIFO)
+typedef enum{
+	AC_SR_8K   = 8000,
+	AC_SR_16K  = 16000,
+	AC_SR_32K  = 32000,
+	AC_SR_441K = 44100,
+	AC_SR_48K  = 48000,
+} FH_AC_SAMPLE_RATE_E;
+
+typedef enum{
+	AC_BW_8  = 8,
+	AC_BW_16 = 16,
+	AC_BW_24 = 24,
+} FH_AC_BIT_WIDTH_E;
+
+enum io_select{
+	mic_in = 0,
+	line_in = 1,
+	speaker_out = 2,
+	line_out = 3,
+};
+
+struct fh_audio_cfg_arg{
+	enum io_select io_type;
+	int volume;
+	int rate;
+	int frame_bit;
+	int channels;
+	int buffer_size;
+	int period_size;
+};
+typedef struct{
+	unsigned int len;
+	unsigned char *data;
+}FH_AC_FRAME_S;
+
+typedef enum{
+	FH_AC_MIC_IN = 0,
+	FH_AC_LINE_IN = 1,
+	FH_AC_SPK_OUT = 2,
+	FH_AC_LINE_OUT = 3
+}FH_AC_IO_TYPE_E;
+
+
+typedef struct {
+	FH_AC_IO_TYPE_E io_type;
+	FH_AC_SAMPLE_RATE_E sample_rate;
+	FH_AC_BIT_WIDTH_E bit_width;
+	unsigned int channels;
+	unsigned int period_size;
+	unsigned int volume;
+} FH_AC_CONFIG;
+
+struct device_dma_parameters {
+	/*
+	 * a low level driver may set these to teach IOMMU code about
+	 * sg limitations.
+	 */
+	unsigned int max_segment_size;
+	unsigned long segment_boundary_mask;
+};
+
+struct list_head {
+    struct list_head *next;
+    struct list_head *prev;
+};
+struct dma_coherent_mem {
+	void		*virt_base;
+	dma_addr_t	device_base;
+	int		size;
+	int		flags;
+	unsigned long	*bitmap;
+};
+struct device_acw{
+	unsigned long long		*dma_mask;	/* dma mask (if dma'able device) */
+	unsigned long long		coherent_dma_mask;/* Like dma_mask, but for
+					     alloc_coherent mappings as
+					     not all hardware supports
+					     64 bit addresses for consistent
+					     allocations such descriptors. */
+	struct device_dma_parameters *dma_parms;
+
+	struct list_head	dma_pools;
+
+	struct dma_coherent_mem	*dma_mem;
+};
+#define false 0
+#define true  1
+
+
+
+#define	AC_INIT_CAPTURE_MEM    	    0x10
+#define	AC_INIT_PLAYBACK_MEM        0x11
+
+
+#define AC_SET_VOL                  0x12
+#define AC_SET_INPUT_MODE           0x13
+#define AC_SET_OUTPUT_MODE          0x14
+
+
+#define AC_AI_EN                    0x15
+#define AC_AO_EN                    0x16
+#define AC_AI_DISABLE               0x17
+#define AC_AO_DISABLE       		0x18
+#define AC_AI_PAUSE               	0x19
+#define AC_AI_RESUME          		0x1a
+#define AC_AO_PAUSE              	0x1b
+#define AC_AO_RESUME          		0x1c
+#define AC_MIC_BOOST          		0x1d
+
+#define POLLIN		0x001		/* There is data to read.  */
+#define POLLPRI		0x002		/* There is urgent data to read.  */
+#define POLLOUT		0x004		/* Writing now will not block.  */
+
+
+/* These values are defined in XPG4.2.  */
+# define POLLRDNORM	0x040		/* Normal data may be read.  */
+# define POLLRDBAND	0x080		/* Priority data may be read.  */
+# define POLLWRNORM	0x100		/* Writing now will not block.  */
+# define POLLWRBAND	0x200		/* Priority data may be written.  */
+
+
+
+/* These are extensions for Linux.  */
+# define POLLMSG	0x400
+# define POLLREMOVE	0x1000
+# define POLLRDHUP	0x2000
+
+
+/* Event types always implicitly polled for.  These bits need not be set in
+   `events', but they will appear in `revents' to indicate the status of
+   the file descriptor.  */
+#define POLLERR		0x008		/* Error condition.  */
+#define POLLHUP		0x010		/* Hung up.  */
+#define POLLNVAL	0x020		/* Invalid polling request.  */
+
+#define	EPERM		 1	/* Operation not permitted */
+#define	ENOENT		 2	/* No such file or directory */
+#define	ESRCH		 3	/* No such process */
+#define	EINTR		 4	/* Interrupted system call */
+#define	EIO		 5	/* I/O error */
+#define	ENXIO		 6	/* No such device or address */
+#define	E2BIG		 7	/* Argument list too long */
+#define	ENOEXEC		 8	/* Exec format error */
+#define	EBADF		 9	/* Bad file number */
+#define	ECHILD		10	/* No child processes */
+#define	EAGAIN		11	/* Try again */
+#define	ENOMEM		12	/* Out of memory */
+#define	EACCES		13	/* Permission denied */
+#define	EFAULT		14	/* Bad address */
+#define	ENOTBLK		15	/* Block device required */
+#define	EBUSY		16	/* Device or resource busy */
+#define	EEXIST		17	/* File exists */
+#define	EXDEV		18	/* Cross-device link */
+#define	ENODEV		19	/* No such device */
+#define	ENOTDIR		20	/* Not a directory */
+#define	EISDIR		21	/* Is a directory */
+#define	EINVAL		22	/* Invalid argument */
+#define	ENFILE		23	/* File table overflow */
+#define	EMFILE		24	/* Too many open files */
+#define	ENOTTY		25	/* Not a typewriter */
+#define	ETXTBSY		26	/* Text file busy */
+#define	EFBIG		27	/* File too large */
+#define	ENOSPC		28	/* No space left on device */
+#define	ESPIPE		29	/* Illegal seek */
+#define	EROFS		30	/* Read-only file system */
+#define	EMLINK		31	/* Too many links */
+#define	EPIPE		32	/* Broken pipe */
+#define	EDOM		33	/* Math argument out of domain of func */
+#define	ERANGE		34	/* Math result not representable */
+extern void  fh_audio_init(void);
+extern void fh_acw_test();
+#endif

+ 170 - 0
bsp/fh8620/drivers/dma.c

@@ -0,0 +1,170 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+/*****************************************************************************
+ *  Include Section
+ *  add all #include here
+ *****************************************************************************/
+#include "drivers/dma.h"
+/*****************************************************************************
+ * Define section
+ * add all #define here
+ *****************************************************************************/
+
+
+/****************************************************************************
+ * ADT section
+ *  add definition of user defined Data Type that only be used in this file  here
+ ***************************************************************************/
+
+
+/******************************************************************************
+ * Function prototype section
+ * add prototypes for all functions called by this file,execepting those
+ * declared in header file
+ *****************************************************************************/
+
+
+/*****************************************************************************
+ * Global variables section - Exported
+ * add declaration of global variables that will be exported here
+ * e.g.
+ *  int8_t foo;
+ ****************************************************************************/
+
+
+/*****************************************************************************
+
+ *  static fun;
+ *****************************************************************************/
+static rt_err_t rt_dma_init(struct rt_device *dev);
+static rt_err_t rt_dma_open(struct rt_device *dev, rt_uint16_t oflag);
+static rt_err_t rt_dma_close(struct rt_device *dev);
+static rt_err_t rt_dma_control(struct rt_device *dev,
+                                    rt_uint8_t        cmd,
+                                    void             *args);
+/*****************************************************************************
+ * Global variables section - Local
+ * define global variables(will be refered only in this file) here,
+ * static keyword should be used to limit scope of local variable to this file
+ * e.g.
+ *  static uint8_t ufoo;
+ *****************************************************************************/
+
+
+
+
+ /* function body */
+/*****************************************************************************
+ * Description:
+ *      add funtion description here
+ * Parameters:
+ *      description for each argument, new argument starts at new line
+ * Return:
+ *      what does this function returned?
+ *****************************************************************************/
+static rt_err_t rt_dma_init(struct rt_device *dev)
+{
+	struct rt_dma_device *dma;
+
+    RT_ASSERT(dev != RT_NULL);
+    dma = (struct rt_dma_device *)dev;
+    if (dma->ops->init)
+    {
+        return (dma->ops->init(dma));
+    }
+
+    return (-RT_ENOSYS);
+}
+
+static rt_err_t rt_dma_open(struct rt_device *dev, rt_uint16_t oflag)
+{
+    return (RT_EOK);
+}
+
+static rt_err_t rt_dma_close(struct rt_device *dev)
+{
+	struct rt_dma_device *dma;
+
+    RT_ASSERT(dev != RT_NULL);
+    dma = (struct rt_dma_device *)dev;
+
+    if (dma->ops->control(dma, RT_DEVICE_CTRL_DMA_CLOSE, RT_NULL) != RT_EOK)
+    {
+        return (-RT_ERROR);
+    }
+
+    return (RT_EOK);
+}
+
+static rt_err_t rt_dma_control(struct rt_device *dev,
+                                    rt_uint8_t        cmd,
+                                    void             *args)
+{
+	struct rt_dma_device *dma;
+
+    RT_ASSERT(dev != RT_NULL);
+    dma = (struct rt_dma_device *)dev;
+
+    //args is the private data for the soc!!
+    return (dma->ops->control(dma, cmd, args));
+}
+
+/**
+ * This function register a dma device
+ */
+rt_err_t rt_hw_dma_register(struct rt_dma_device *dma,
+                                 const char                *name,
+                                 rt_uint32_t                flag,
+                                 void                      *data)
+{
+	rt_uint32_t ret;
+    struct rt_device *device;
+    RT_ASSERT(dma != RT_NULL);
+
+    device = &(dma->parent);
+
+    device->type        = RT_Device_Class_Miscellaneous;
+    device->rx_indicate = RT_NULL;
+    device->tx_complete = RT_NULL;
+
+    device->init        = rt_dma_init;
+    device->open        = rt_dma_open;
+    device->close       = rt_dma_close;
+    device->read        = RT_NULL;
+    device->write       = RT_NULL;
+    device->control     = rt_dma_control;
+    device->user_data   = data;
+
+    /* register a character device */
+    ret = rt_device_register(device, name, flag);
+    rt_kprintf("dma ret is :%x\n",ret);
+    return ret;
+}
+
+
+
+

+ 107 - 0
bsp/fh8620/drivers/dma.h

@@ -0,0 +1,107 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#ifndef DMA_H_
+#define DMA_H_
+#include <rtthread.h>
+/****************************************************************************
+* #include section
+*	add #include here if any
+***************************************************************************/
+
+
+/****************************************************************************
+* #define section
+*	add constant #define here if any
+***************************************************************************/
+#define RT_DEVICE_CTRL_DMA_OPEN						(1)
+#define RT_DEVICE_CTRL_DMA_CLOSE					(2)
+#define RT_DEVICE_CTRL_DMA_REQUEST_CHANNEL    		(3)
+#define RT_DEVICE_CTRL_DMA_RELEASE_CHANNEL   	 	(4)
+#define RT_DEVICE_CTRL_DMA_SINGLE_TRANSFER			(5)
+
+
+//cyclic add func below....
+
+
+#define RT_DEVICE_CTRL_DMA_CYCLIC_PREPARE			(6)
+#define RT_DEVICE_CTRL_DMA_CYCLIC_START				(7)
+#define RT_DEVICE_CTRL_DMA_CYCLIC_STOP				(8)
+#define RT_DEVICE_CTRL_DMA_CYCLIC_FREE				(9)
+
+
+//#define RT_DEVICE_CTRL_  	 (3) /* get the left time before reboot(in seconds) */
+//#define RT_DEVICE_CTRL_      (4) /* refresh watchdog */
+//#define RT_DEVICE_CTRL_      (5) /* start watchdog */
+//#define RT_DEVICE_CTRL_      (6) /* stop watchdog */
+
+
+
+
+
+/****************************************************************************
+* ADT section
+*	add Abstract Data Type definition here
+***************************************************************************/
+
+struct rt_dma_ops;
+struct rt_dma_device
+{
+	// the parent must be the fitst para..
+    struct rt_device parent;
+    struct rt_dma_ops *ops;
+};
+
+
+struct rt_dma_ops
+{
+    rt_err_t (*init)(struct rt_dma_device *dma);
+    rt_err_t (*control)(struct rt_dma_device *dma, int cmd, void *arg);
+};
+
+
+
+
+/****************************************************************************
+*  extern variable declaration section
+***************************************************************************/
+
+/****************************************************************************
+*  section
+*	add function prototype here if any
+***************************************************************************/
+rt_err_t rt_hw_dma_register(struct rt_dma_device *dma,
+                                 const char    *name,
+                                 rt_uint32_t    flag,
+                                 void          *data);
+
+/********************************End Of File********************************/
+
+
+
+
+#endif
+

+ 122 - 0
bsp/fh8620/drivers/dma_mem.c

@@ -0,0 +1,122 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+/*****************************************************************************
+ *  Include Section
+ *  add all #include here
+ *****************************************************************************/
+
+
+#include "dma_mem.h"
+#ifdef RT_USING_DMA_MEM
+
+/*****************************************************************************
+ * Define section
+ * add all #define here
+ *****************************************************************************/
+//#define FH_TEST_DMA_MEM
+
+/****************************************************************************
+ * ADT section
+ *  add definition of user defined Data Type that only be used in this file  here
+ ***************************************************************************/
+
+
+/******************************************************************************
+ * Function prototype section
+ * add prototypes for all functions called by this file,execepting those
+ * declared in header file
+ *****************************************************************************/
+
+
+/*****************************************************************************
+ * Global variables section - Exported
+ * add declaration of global variables that will be exported here
+ * e.g.
+ *  int8_t foo;
+ ****************************************************************************/
+
+
+/*****************************************************************************
+
+ *  static fun;
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Global variables section - Local
+ * define global variables(will be refered only in this file) here,
+ * static keyword should be used to limit scope of local variable to this file
+ * e.g.
+ *  static uint8_t ufoo;
+ *****************************************************************************/
+
+static struct rt_memheap dma_heap = {0};
+
+
+ /* function body */
+/*****************************************************************************
+ * Description:
+ *      add funtion description here
+ * Parameters:
+ *      description for each argument, new argument starts at new line
+ * Return:
+ *      what does this function returned?
+ *****************************************************************************/
+rt_err_t fh_dma_mem_init(rt_uint32_t *mem_start,rt_uint32_t size){
+	return rt_memheap_init(&dma_heap,"dma_heap",mem_start,size);
+}
+
+
+void *fh_dma_mem_malloc(rt_uint32_t size){
+	return rt_memheap_alloc(&dma_heap, size);
+}
+
+
+void fh_dma_mem_free(void *ptr){
+	rt_memheap_free(ptr);
+}
+
+#ifdef FH_TEST_DMA_MEM
+int dma_mem_debug(void *ptr){
+	//rt_memheap_free(ptr);
+	rt_kprintf("dma mem start 0x%08x\n",(rt_uint32_t)dma_heap.start_addr);
+	rt_kprintf("dma mem total size 0x%08x\n",dma_heap.pool_size);
+	rt_kprintf("dma mem left size 0x%08x\n",dma_heap.available_size);
+	rt_kprintf("dma mem max use size 0x%08x\n",dma_heap.max_used_size);
+	return 0;
+}
+#endif
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+#ifdef FH_TEST_DMA_MEM
+FINSH_FUNCTION_EXPORT(dma_mem_debug, dma_start & left size & max_use);
+#endif
+#endif
+
+
+#endif
+

+ 76 - 0
bsp/fh8620/drivers/dma_mem.h

@@ -0,0 +1,76 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef DMA_MEM_H_
+#define DMA_MEM_H_
+
+
+
+#ifndef RT_USING_MEMHEAP
+#define RT_USING_MEMHEAP
+#endif
+
+#include <rtthread.h>
+/****************************************************************************
+* #include section
+*	add #include here if any
+***************************************************************************/
+
+
+/****************************************************************************
+* #define section
+*	add constant #define here if any
+***************************************************************************/
+
+
+
+/****************************************************************************
+* ADT section
+*	add Abstract Data Type definition here
+***************************************************************************/
+
+
+
+
+/****************************************************************************
+*  extern variable declaration section
+***************************************************************************/
+
+/****************************************************************************
+*  section
+*	add function prototype here if any
+***************************************************************************/
+#ifdef RT_USING_DMA_MEM
+rt_err_t fh_dma_mem_init(rt_uint32_t *mem_start,rt_uint32_t size);
+void *fh_dma_mem_malloc(rt_uint32_t size);
+void fh_dma_mem_free(void *ptr);
+/********************************End Of File********************************/
+
+
+#endif
+
+#endif
+

+ 1618 - 0
bsp/fh8620/drivers/fh_dma.c

@@ -0,0 +1,1618 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+/*****************************************************************************
+ *  Include Section
+ *  add all #include here
+ *****************************************************************************/
+//#include "drivers/fh_dma.h"
+#include "fh_dma.h"
+#include "mmu.h"
+#include "drivers/dma.h"
+#include <stdint.h>
+#include <rtdevice.h>
+#include <rthw.h>
+#include "fh_arch.h"
+#include "mmu.h"
+#include "fh_def.h"
+/*****************************************************************************
+ * Define section
+ * add all #define here
+ *****************************************************************************/
+//#define DMA_DEBUG
+#ifdef DMA_DEBUG
+
+#define FH_DMA_DEBUG(fmt, args...)	    		\
+			rt_kprintf(fmt,##args);
+#else
+#define FH_DMA_DEBUG(fmt, args...)
+#endif
+
+
+#define		DMA_REG_BASE		(0xEE000000)
+#define 	DMA_CONTROLLER_NUMBER		(1)
+
+
+
+#define WORK_QUEUE_STACK_SIZE		512
+#define WORK_QUEUE_PRIORITY			12
+
+
+#define TEST_PER_NO			(10)
+
+#define DESC_MAX_SIZE			(20)
+/*********************************
+ *
+ * copy from the linux core start
+ *
+ *********************************/
+//this is the ip reg offset....don't change!!!!!!!
+#define DW_DMA_MAX_NR_CHANNELS	8
+
+/*
+ * Redefine this macro to handle differences between 32- and 64-bit
+ * addressing, big vs. little endian, etc.
+ */
+#define DW_REG(name)		rt_uint32_t name; rt_uint32_t __pad_##name
+
+/* Hardware register definitions. */
+struct dw_dma_chan_regs {
+	DW_REG(SAR);		/* Source Address Register */
+	DW_REG(DAR);		/* Destination Address Register */
+	DW_REG(LLP);		/* Linked List Pointer */
+	rt_uint32_t	CTL_LO;		/* Control Register Low */
+	rt_uint32_t	CTL_HI;		/* Control Register High */
+	DW_REG(SSTAT);
+	DW_REG(DSTAT);
+	DW_REG(SSTATAR);
+	DW_REG(DSTATAR);
+	rt_uint32_t	CFG_LO;		/* Configuration Register Low */
+	rt_uint32_t	CFG_HI;		/* Configuration Register High */
+	DW_REG(SGR);
+	DW_REG(DSR);
+};
+
+struct dw_dma_irq_regs {
+	DW_REG(XFER);
+	DW_REG(BLOCK);
+	DW_REG(SRC_TRAN);
+	DW_REG(DST_TRAN);
+	DW_REG(ERROR);
+};
+
+struct dw_dma_regs {
+	/* per-channel registers */
+	struct dw_dma_chan_regs	CHAN[DW_DMA_MAX_NR_CHANNELS];
+
+	/* irq handling */
+	struct dw_dma_irq_regs	RAW;		/* r */
+	struct dw_dma_irq_regs	STATUS;		/* r (raw & mask) */
+	struct dw_dma_irq_regs	MASK;		/* rw (set = irq enabled) */
+	struct dw_dma_irq_regs	CLEAR;		/* w (ack, affects "raw") */
+
+	DW_REG(STATUS_INT);			/* r */
+
+	/* software handshaking */
+	DW_REG(REQ_SRC);
+	DW_REG(REQ_DST);
+	DW_REG(SGL_REQ_SRC);
+	DW_REG(SGL_REQ_DST);
+	DW_REG(LAST_SRC);
+	DW_REG(LAST_DST);
+
+	/* miscellaneous */
+	DW_REG(CFG);
+	DW_REG(CH_EN);
+	DW_REG(ID);
+	DW_REG(TEST);
+
+	/* optional encoded params, 0x3c8..0x3 */
+};
+
+
+
+
+/* Bitfields in CTL_LO */
+#define DWC_CTLL_INT_EN			(1 << 0)	/* irqs enabled? */
+#define DWC_CTLL_DST_WIDTH(n)	((n)<<1)	/* bytes per element */
+#define DWC_CTLL_SRC_WIDTH(n)	((n)<<4)
+
+#define DWC_CTLL_DST_INC_MODE(n) ((n)<<7)
+
+#define DWC_CTLL_DST_INC		(0<<7)		/* DAR update/not */
+#define DWC_CTLL_DST_DEC		(1<<7)
+#define DWC_CTLL_DST_FIX		(2<<7)
+
+
+#define DWC_CTLL_SRC_INC_MODE(n) ((n)<<9)
+
+
+#define DWC_CTLL_SRC_INC		(0<<9)		/* SAR update/not */
+#define DWC_CTLL_SRC_DEC		(1<<9)
+#define DWC_CTLL_SRC_FIX		(2<<9)
+#define DWC_CTLL_DST_MSIZE(n)	((n)<<11)	/* burst, #elements */
+#define DWC_CTLL_SRC_MSIZE(n)	((n)<<14)
+#define DWC_CTLL_S_GATH_EN		(1 << 17)	/* src gather, !FIX */
+#define DWC_CTLL_D_SCAT_EN		(1 << 18)	/* dst scatter, !FIX */
+#define DWC_CTLL_FC(n)			((n) << 20)
+#define DWC_CTLL_FC_M2M			(0 << 20)	/* mem-to-mem */
+#define DWC_CTLL_FC_M2P			(1 << 20)	/* mem-to-periph */
+#define DWC_CTLL_FC_P2M			(2 << 20)	/* periph-to-mem */
+#define DWC_CTLL_FC_P2P			(3 << 20)	/* periph-to-periph */
+/* plus 4 transfer types for peripheral-as-flow-controller */
+#define DWC_CTLL_DMS(n)			((n)<<23)	/* dst master select */
+#define DWC_CTLL_SMS(n)			((n)<<25)	/* src master select */
+#define DWC_CTLL_LLP_D_EN		(1 << 27)	/* dest block chain */
+#define DWC_CTLL_LLP_S_EN		(1 << 28)	/* src block chain */
+
+/* Bitfields in CTL_HI */
+#define DWC_CTLH_DONE			0x00001000
+#define DWC_CTLH_BLOCK_TS_MASK	0x00000fff
+
+/* Bitfields in CFG_LO. Platform-configurable bits are in <linux/dw_dmac.h> */
+#define DWC_CFGL_CH_PRIOR_MASK	(0x7 << 5)	/* priority mask */
+#define DWC_CFGL_CH_PRIOR(x)	((x) << 5)	/* priority */
+#define DWC_CFGL_CH_SUSP		(1 << 8)	/* pause xfer */
+#define DWC_CFGL_FIFO_EMPTY		(1 << 9)	/* pause xfer */
+
+
+#define DWC_CFGL_HS_DST			(1 << 10)	/* handshake w/dst */
+#define DWC_CFGL_HS_SRC			(1 << 11)	/* handshake w/src */
+#define DWC_CFGL_MAX_BURST(x)	((x) << 20)
+#define DWC_CFGL_RELOAD_SAR		(1 << 30)
+#define DWC_CFGL_RELOAD_DAR		(1 << 31)
+
+/* Bitfields in CFG_HI. Platform-configurable bits are in <linux/dw_dmac.h> */
+#define DWC_CFGH_DS_UPD_EN		(1 << 5)
+#define DWC_CFGH_SS_UPD_EN		(1 << 6)
+
+/* Bitfields in SGR */
+#define DWC_SGR_SGI(x)			((x) << 0)
+#define DWC_SGR_SGC(x)			((x) << 20)
+
+/* Bitfields in DSR */
+#define DWC_DSR_DSI(x)			((x) << 0)
+#define DWC_DSR_DSC(x)			((x) << 20)
+
+/* Bitfields in CFG */
+#define DW_CFG_DMA_EN			(1 << 0)
+
+#define DW_REGLEN				0x400
+
+
+/* Platform-configurable bits in CFG_HI */
+#define DWC_CFGH_FCMODE		(1 << 0)
+#define DWC_CFGH_FIFO_MODE	(1 << 1)
+#define DWC_CFGH_PROTCTL(x)	((x) << 2)
+#define DWC_CFGH_SRC_PER(x)	((x) << 7)
+#define DWC_CFGH_DST_PER(x)	((x) << 11)
+
+/* Platform-configurable bits in CFG_LO */
+#define DWC_CFGL_LOCK_CH_XFER	(0 << 12)	/* scope of LOCK_CH */
+#define DWC_CFGL_LOCK_CH_BLOCK	(1 << 12)
+#define DWC_CFGL_LOCK_CH_XACT	(2 << 12)
+#define DWC_CFGL_LOCK_BUS_XFER	(0 << 14)	/* scope of LOCK_BUS */
+#define DWC_CFGL_LOCK_BUS_BLOCK	(1 << 14)
+#define DWC_CFGL_LOCK_BUS_XACT	(2 << 14)
+#define DWC_CFGL_LOCK_CH	(1 << 15)	/* channel lockout */
+#define DWC_CFGL_LOCK_BUS	(1 << 16)	/* busmaster lockout */
+#define DWC_CFGL_HS_DST_POL	(1 << 18)	/* dst handshake active low */
+#define DWC_CFGL_HS_SRC_POL	(1 << 19)	/* src handshake active low */
+
+
+
+
+#define lift_shift_bit_num(bit_num)			(1<<bit_num)
+
+
+#define __raw_writeb(v,a)       (*(volatile unsigned char  *)(a) = (v))
+#define __raw_writew(v,a)       (*(volatile unsigned short *)(a) = (v))
+#define __raw_writel(v,a)       (*(volatile unsigned int   *)(a) = (v))
+
+#define __raw_readb(a)          (*(volatile unsigned char  *)(a))
+#define __raw_readw(a)          (*(volatile unsigned short *)(a))
+#define __raw_readl(a)          (*(volatile unsigned int   *)(a))
+
+#define min(a,b) (((a)<(b))?(a):(b))
+#define max(a,b) (((a)>(b))?(a):(b))
+
+
+
+
+#define dw_readl(dw, name) \
+	__raw_readl(&(((struct dw_dma_regs *)dw->regs)->name))
+#define dw_writel(dw, name, val) \
+	__raw_writel((val), &(((struct dw_dma_regs *)dw->regs)->name))
+#define dw_readw(dw, name) \
+	__raw_readw(&(((struct dw_dma_regs *)dw->regs)->name))
+#define dw_writew(dw, name, val) \
+	__raw_writew((val), &(((struct dw_dma_regs *)dw->regs)->name))
+
+
+
+
+
+
+#define CHANNEL0		(lift_shift_bit_num(0))
+#define CHANNEL1		(lift_shift_bit_num(1))
+#define CHANNEL2		(lift_shift_bit_num(2))
+#define CHANNEL3		(lift_shift_bit_num(3))
+
+#define channel_set_bit(dw, reg, mask) \
+	dw_writel(dw, reg, ((mask) << 8) | (mask))
+#define channel_clear_bit(dw, reg, mask) \
+	dw_writel(dw, reg, ((mask) << 8) | 0)
+
+
+
+
+/****************************************************************************
+ * ADT section
+ *  add definition of user defined Data Type that only be used in this file  here
+ ***************************************************************************/
+
+struct dw_dma{
+	//vadd
+	void 				*regs;
+	//padd
+	rt_uint32_t			paddr;
+	rt_uint32_t			irq;
+	rt_uint32_t			channel_max_number;
+
+#define CONTROLLER_STATUS_CLOSED		(0)
+#define CONTROLLER_STATUS_OPEN			(1)
+	rt_uint32_t			controller_status;
+#define FH81_DMA_INIT_NOT_YET		(0)
+#define FH81_DMA_INIT_ALREADY		(1)
+	rt_uint32_t			init;
+	rt_uint32_t			id;
+	char	 *name;
+	rt_uint32_t channel_work_done;
+};
+
+
+struct dma_channel {
+#define CHANNEL_STATUS_CLOSED	(0)
+#define CHANNEL_STATUS_OPEN		(1)
+#define CHANNEL_STATUS_IDLE		(2)
+#define CHANNEL_STATUS_BUSY		(3)
+
+	rt_uint32_t channel_status;	//open, busy ,closed
+	rt_uint32_t	desc_trans_size;
+
+	//isr will set it complete.
+	struct rt_completion transfer_completion;
+	//add lock,when set the channel.lock it
+	struct rt_semaphore channel_lock;
+	//struct rt_mutex                 lock;
+	//rt_enter_critical();
+	rt_list_t queue;
+	//active transfer now!!!
+	struct dma_transfer *active_trans;
+
+#define SINGLE_TRANSFER			(0)
+#define CYCLIC_TRANSFER			(1)
+#define DEFAULT_TRANSFER		SINGLE_TRANSFER
+	rt_uint32_t open_flag;
+	//
+
+
+
+	//new add para...
+	rt_uint32_t desc_total_no;
+	rt_uint32_t free_index;
+	rt_uint32_t used_index;
+	rt_uint32_t desc_left_cnt;
+
+	rt_uint32_t allign_malloc;
+	struct dw_lli *base_lli;
+};
+
+
+struct fh81_dma{
+	//core use ,this must be the first para!!!!
+	struct rt_dma_device parent;
+	//myown
+	struct dw_dma dwc;
+	//channel obj
+	struct dma_channel dma_channel[FH81_MAX_CHANNEL];
+
+	//struct rt_workqueue* isr_workqueue;
+	//struct rt_work *isr_work;
+
+};
+
+
+
+#define list_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = rt_list_entry((head)->next, typeof(*pos), member),	\
+		n = rt_list_entry(pos->member.next, typeof(*pos), member);	\
+	     &pos->member != (head); 					\
+	     pos = n, n = rt_list_entry(n->member.next, typeof(*n), member))
+
+
+/******************************************************************************
+ * Function prototype section
+ * add prototypes for all functions called by this file,execepting those
+ * declared in header file
+ *****************************************************************************/
+
+
+/*****************************************************************************
+ * Global variables section - Exported
+ * add declaration of global variables that will be exported here
+ * e.g.
+ *  int8_t foo;
+ ****************************************************************************/
+
+
+/*****************************************************************************
+
+ *  static fun;
+ *****************************************************************************/
+static rt_err_t init (struct rt_dma_device *dma);
+static rt_err_t control (struct rt_dma_device *dma, int cmd, void *arg);
+
+
+static void rt_fh_dma_cyclic_stop(struct dma_transfer *p);
+static void rt_fh_dma_cyclic_start(struct dma_transfer *p);
+static void rt_fh_dma_cyclic_prep(struct fh81_dma * fh81_dma_p,struct dma_transfer *p);
+static void rt_fh_dma_cyclic_free(struct dma_transfer *p);
+
+static struct rt_dma_ops fh81_dma_ops =
+{
+		init,
+		control
+};
+
+
+
+
+/*****************************************************************************
+ * Global variables section - Local
+ * define global variables(will be refered only in this file) here,
+ * static keyword should be used to limit scope of local variable to this file
+ * e.g.
+ *  static uint8_t ufoo;
+ *****************************************************************************/
+static struct fh81_dma	fh81_dma_controller[DMA_CONTROLLER_NUMBER] = {0};
+
+/* function body */
+/*****************************************************************************
+ * Description:
+ *      add funtion description here
+ * Parameters:
+ *      description for each argument, new argument starts at new line
+ * Return:
+ *      what does this function returned?
+ *****************************************************************************/
+
+static rt_uint32_t allign_func(rt_uint32_t in_addr,rt_uint32_t allign_size){
+	return (in_addr + allign_size-1) & (~(allign_size - 1));
+}
+
+
+struct dw_lli * get_desc(struct fh81_dma  *p_dma,struct dma_transfer *p_transfer,rt_uint32_t lli_size){
+	struct dw_lli * ret_lli;
+	rt_uint32_t free_index;
+	rt_uint32_t allign_left;
+	rt_uint32_t totoal_desc;
+	rt_uint32_t actual_get_desc;
+	rt_uint32_t totoal_free_desc;
+	totoal_free_desc = p_dma->dma_channel[p_transfer->channel_number].desc_left_cnt;
+	free_index = p_dma->dma_channel[p_transfer->channel_number].free_index;
+	totoal_desc = p_dma->dma_channel[p_transfer->channel_number].desc_total_no;
+	allign_left = totoal_desc - free_index;
+
+	//check first..
+	if(totoal_free_desc < lli_size){
+		rt_kprintf("not enough desc to get...\n");
+		rt_kprintf("get size is %d,left is %d\n",lli_size,totoal_free_desc);
+		return RT_NULL;
+	}
+	//rt_kprintf("get desc in...\n");
+
+	//rt_kprintf("lli size is %d\n",lli_size);
+	if(lli_size > allign_left){
+		//if allign desc not enough...just reset null....
+		if((totoal_free_desc - allign_left) < lli_size){
+			rt_kprintf("not enough desc to get...\n");
+			rt_kprintf("app need size is %d, totoal left is %d, allign left is %d\n",lli_size,totoal_free_desc,allign_left);
+			rt_kprintf("from head to get desc size is %d, actual get is %d\n",(totoal_free_desc - allign_left),(allign_left +lli_size));
+			return RT_NULL;
+		}
+		else{
+			actual_get_desc = allign_left +lli_size;
+			free_index = 0;
+		}
+	}
+
+
+	//ret_lli = &p_dma->dma_channel[p_transfer->channel_number].base_lli[free_index];
+
+	ret_lli = &p_dma->dma_channel[p_transfer->channel_number].base_lli[free_index];
+//	rt_kprintf("get desc base index addr:%08x\n",(rt_uint32_t)&p_dma->dma_channel[p_transfer->channel_number].base_lli[0]);
+//	rt_kprintf("get desc free index addr:%08x\n",(rt_uint32_t)ret_lli);
+//	rt_kprintf("get desc request size:%08x\n",lli_size);
+//	rt_kprintf("get desc total size:%08x\n",p_dma->dma_channel[p_transfer->channel_number].desc_total_no);
+//	rt_kprintf("one desc size is:%08x\n",sizeof(	struct dw_lli));
+
+	p_dma->dma_channel[p_transfer->channel_number].free_index += actual_get_desc;
+
+	//rt_kprintf("get desc free index addr:%08x\n",(rt_uint32_t)&p_dma->dma_channel[p_transfer->channel_number].base_lli[p_dma->dma_channel[p_transfer->channel_number].free_index]);
+
+	p_dma->dma_channel[p_transfer->channel_number].free_index %= p_dma->dma_channel[p_transfer->channel_number].desc_total_no;
+	p_dma->dma_channel[p_transfer->channel_number].desc_left_cnt -= actual_get_desc;
+	p_transfer->lli_size = lli_size;
+	p_transfer->actual_lli_size = actual_get_desc;
+	return ret_lli;
+}
+
+
+rt_uint32_t put_desc(struct fh81_dma  *p_dma,struct dma_transfer *p_transfer){
+	struct dw_lli * ret_lli;
+	rt_uint32_t used_index;
+	rt_uint32_t lli_size;
+	//rt_kprintf("put desc in...\n");
+	used_index = p_dma->dma_channel[p_transfer->channel_number].used_index;
+	lli_size = p_transfer->actual_lli_size;
+	p_dma->dma_channel[p_transfer->channel_number].used_index += lli_size;
+	p_dma->dma_channel[p_transfer->channel_number].used_index %= p_dma->dma_channel[p_transfer->channel_number].desc_total_no;
+	p_dma->dma_channel[p_transfer->channel_number].desc_left_cnt += lli_size;
+	p_transfer->lli_size  = 0;
+	p_transfer->actual_lli_size = 0;
+	return 0;
+}
+
+/*****************************************************************************
+ * Description:
+ *      add funtion description here
+ * Parameters:
+ *      description for each argument, new argument starts at new line
+ * Return:
+ *      what does this function returned?
+ *****************************************************************************/
+
+static rt_err_t init (struct rt_dma_device *dma){
+
+
+	//init the clk table
+
+
+	struct fh81_dma *my_own = (struct  fh81_dma *)dma->parent.user_data;
+
+	FH_DMA_DEBUG("my_own value:0x%x\n",(rt_uint32_t)my_own);
+
+	//check the user data
+	RT_ASSERT(my_own != RT_NULL);
+
+	return RT_EOK;
+
+}
+
+
+
+
+
+/*****************************************************************************
+ * Description:
+ *      add funtion description here
+ * Parameters:
+ *      description for each argument, new argument starts at new line
+ * Return:
+ *      what does this function returned?
+ *****************************************************************************/
+
+static void handle_dma_open(struct fh81_dma  *p_dma){
+
+	rt_uint32_t i;
+	struct dw_dma *temp_dwc;
+	temp_dwc = &p_dma->dwc;
+
+	dw_writel(temp_dwc, CFG, 1);
+	p_dma->dwc.controller_status = CONTROLLER_STATUS_OPEN;
+
+}
+
+
+/*****************************************************************************
+ * Description:
+ *      add funtion description here
+ * Parameters:
+ *      description for each argument, new argument starts at new line
+ * Return:
+ *      what does this function returned?
+ *****************************************************************************/
+static void handle_dma_close(struct fh81_dma  *p_dma){
+
+
+	rt_uint32_t i;
+	struct dw_dma *temp_dwc;
+	temp_dwc = &p_dma->dwc;
+
+	//take lock
+	for(i=0;i<p_dma->dwc.channel_max_number;i++){
+		rt_sem_take(&p_dma->dma_channel[i].channel_lock, RT_WAITING_FOREVER);
+
+		channel_clear_bit(temp_dwc, CH_EN, lift_shift_bit_num(i));
+		p_dma->dma_channel[i].channel_status = CHANNEL_STATUS_CLOSED;
+	}
+	dw_writel(temp_dwc, CFG, 0);
+	p_dma->dwc.controller_status = CONTROLLER_STATUS_CLOSED;
+
+	//release lock
+	for(i=0;i<p_dma->dwc.channel_max_number;i++){
+		rt_sem_release(&p_dma->dma_channel[i].channel_lock);
+	}
+
+	//destroy the workqueue..
+	//rt_workqueue_destroy(p_dma->isr_workqueue);
+
+
+}
+
+
+/*****************************************************************************
+ * Description:
+ *      add funtion description here
+ * Parameters:
+ *      description for each argument, new argument starts at new line
+ * Return:
+ *      what does this function returned?
+ *****************************************************************************/
+
+#define CHANNEL_REAL_FREE			(0)
+#define CHANNEL_NOT_FREE			(1)
+
+static rt_uint32_t check_channel_real_free(struct fh81_dma  *p_dma,rt_uint32_t channel_number){
+
+
+	struct dw_dma *temp_dwc;
+	temp_dwc = &p_dma->dwc;
+	rt_uint32_t ret_status;
+
+
+	RT_ASSERT(channel_number < p_dma->dwc.channel_max_number);
+
+	ret_status = dw_readl(temp_dwc, CH_EN);
+	if(ret_status & lift_shift_bit_num(channel_number)){
+		//the channel is still busy!!!error here
+		//FH_DMA_DEBUG("auto request channel error\n");
+		return CHANNEL_NOT_FREE;
+	}
+	return CHANNEL_REAL_FREE;
+
+}
+
+
+
+/*****************************************************************************
+ * Description:
+ *      add funtion description here
+ * Parameters:
+ *      description for each argument, new argument starts at new line
+ * Return:
+ *      what does this function returned?
+ *****************************************************************************/
+
+static rt_err_t handle_request_channel(struct fh81_dma  *p_dma,struct dma_transfer *p_transfer){
+
+	rt_uint32_t i;
+	struct dw_dma *temp_dwc;
+	temp_dwc = &p_dma->dwc;
+	rt_err_t ret_status = RT_EOK;
+
+	//handle if auto check channel...
+	if(p_transfer->channel_number == AUTO_FIND_CHANNEL){
+		//check each channel lock,find a free channel...
+		for(i=0;i<p_dma->dwc.channel_max_number;i++){
+			ret_status = rt_sem_trytake(&p_dma->dma_channel[i].channel_lock);
+			if(ret_status == RT_EOK){
+				break;
+			}
+		}
+
+		if(i < p_dma->dwc.channel_max_number){
+			ret_status = check_channel_real_free(p_dma,i);
+			if(ret_status!= CHANNEL_REAL_FREE){
+				FH_DMA_DEBUG("auto request channel error\n");
+				RT_ASSERT(ret_status == CHANNEL_REAL_FREE);
+			}
+			//caution : channel is already locked here....
+			p_transfer->channel_number = i;
+			//bind to the controller.
+			//p_transfer->dma_controller = p_dma;
+			p_dma->dma_channel[i].channel_status = CHANNEL_STATUS_OPEN;
+		}
+		else
+			return -RT_ENOMEM;
+
+	}
+
+	// request channel by user
+	else{
+		//
+
+		RT_ASSERT(p_transfer->channel_number < p_dma->dwc.channel_max_number);
+		ret_status = rt_sem_take(&p_dma->dma_channel[p_transfer->channel_number].channel_lock, RT_TICK_PER_SECOND*50);
+		if(ret_status != RT_EOK)
+			return -RT_ENOMEM;
+		//rt_enter_critical();
+		ret_status = check_channel_real_free(p_dma,p_transfer->channel_number);
+		if(ret_status!= CHANNEL_REAL_FREE){
+			FH_DMA_DEBUG("user request channel error\n");
+			RT_ASSERT(ret_status == CHANNEL_REAL_FREE);
+		}
+
+		//bind to the controller
+		//p_transfer->dma_controller = p_dma;
+		p_dma->dma_channel[p_transfer->channel_number].channel_status = CHANNEL_STATUS_OPEN;
+		//rt_exit_critical();
+	}
+
+
+	//malloc desc for this one channel...
+	//fix me....
+
+	p_dma->dma_channel[p_transfer->channel_number].allign_malloc =	(rt_uint32_t) rt_malloc(
+			(p_dma->dma_channel[p_transfer->channel_number].desc_total_no
+					* sizeof(struct dw_lli)) + CACHE_LINE_SIZE);
+
+
+	if(!p_dma->dma_channel[p_transfer->channel_number].allign_malloc){
+		//release channel
+		rt_kprintf("[dma]: no mem to malloc channel%d desc..\n",p_transfer->channel_number);
+		p_dma->dma_channel[p_transfer->channel_number].channel_status = CHANNEL_STATUS_CLOSED;
+		rt_sem_release(&p_dma->dma_channel[p_transfer->channel_number].channel_lock);
+		return -RT_ENOMEM;
+	}
+
+
+	p_dma->dma_channel[p_transfer->channel_number].base_lli =
+			(struct dw_lli *) allign_func(
+					p_dma->dma_channel[p_transfer->channel_number].allign_malloc,
+					CACHE_LINE_SIZE);
+
+	FH_DMA_DEBUG("dma desc addr is %x\n",(rt_uint32_t)p_dma->dma_channel[p_transfer->channel_number].base_lli);
+	//t1 = (UINT32)rt_malloc(GMAC_TX_RING_SIZE * sizeof(Gmac_Tx_DMA_Descriptors) + CACHE_LINE_SIZE);
+
+
+	if(!p_dma->dma_channel[p_transfer->channel_number].base_lli){
+		FH_DMA_DEBUG("request desc failed..\n");
+		RT_ASSERT(p_dma->dma_channel[p_transfer->channel_number].base_lli != RT_NULL);
+	}
+
+	if((rt_uint32_t)p_dma->dma_channel[p_transfer->channel_number].base_lli % 32){
+		rt_kprintf("malloc is not cache allign..");
+
+	}
+
+
+
+	//rt_memset((void *)dma_trans_desc->first_lli, 0, lli_size * sizeof(struct dw_lli));
+	rt_memset((void *) p_dma->dma_channel[p_transfer->channel_number].base_lli,
+			0,
+			p_dma->dma_channel[p_transfer->channel_number].desc_total_no
+					* sizeof(struct dw_lli));
+
+	p_dma->dma_channel[p_transfer->channel_number].desc_left_cnt = p_dma->dma_channel[p_transfer->channel_number].desc_total_no;
+	p_dma->dma_channel[p_transfer->channel_number].free_index = 0;
+	p_dma->dma_channel[p_transfer->channel_number].used_index = 0;
+
+
+	return RT_EOK;
+
+}
+
+
+
+
+
+
+
+
+
+/*****************************************************************************
+ * Description:
+ *      add funtion description here
+ * Parameters:
+ *      description for each argument, new argument starts at new line
+ * Return:
+ *      what does this function returned?
+ *****************************************************************************/
+
+static rt_uint32_t handle_release_channel(struct fh81_dma  *p_dma,struct dma_transfer *p_transfer){
+
+
+	rt_uint32_t i;
+	struct dw_dma *temp_dwc;
+	temp_dwc = &p_dma->dwc;
+	rt_uint32_t ret_status;
+
+	//rt_enter_critical();
+	ret_status = p_dma->dma_channel[p_transfer->channel_number].channel_status;
+
+
+	RT_ASSERT(p_transfer->channel_number < p_dma->dwc.channel_max_number);
+
+
+	if(ret_status == CHANNEL_STATUS_CLOSED){
+		FH_DMA_DEBUG("release channel error,reason: release a closed channel!!\n");
+		RT_ASSERT(ret_status != CHANNEL_STATUS_CLOSED);
+	}
+
+	channel_clear_bit(temp_dwc, CH_EN, lift_shift_bit_num(p_transfer->channel_number));
+	rt_sem_release(&p_dma->dma_channel[p_transfer->channel_number].channel_lock);
+	//p_transfer->dma_controller = RT_NULL;
+	p_dma->dma_channel[p_transfer->channel_number].channel_status = CHANNEL_STATUS_CLOSED;
+	p_dma->dma_channel[p_transfer->channel_number].open_flag = DEFAULT_TRANSFER;
+	//rt_exit_critical();
+
+	//release this channel malloc mem...
+	//fix me.....
+	rt_free((void *)p_dma->dma_channel[p_transfer->channel_number].allign_malloc);
+	p_dma->dma_channel[p_transfer->channel_number].allign_malloc = RT_NULL;
+	p_dma->dma_channel[p_transfer->channel_number].base_lli = RT_NULL;
+	p_dma->dma_channel[p_transfer->channel_number].desc_left_cnt = p_dma->dma_channel[p_transfer->channel_number].desc_total_no;
+	p_dma->dma_channel[p_transfer->channel_number].free_index = 0;
+	p_dma->dma_channel[p_transfer->channel_number].used_index = 0;
+
+	return RT_EOK;
+
+
+}
+
+
+
+static rt_uint32_t cal_lli_size(struct dma_transfer *p_transfer){
+	RT_ASSERT(p_transfer != RT_NULL);
+	RT_ASSERT(p_transfer->dma_controller != RT_NULL);
+	RT_ASSERT(p_transfer->src_width <= DW_DMA_SLAVE_WIDTH_32BIT);
+	rt_uint32_t lli_number = 0;
+	rt_uint32_t channel_max_trans_per_lli = 0;
+	channel_max_trans_per_lli = p_transfer->dma_controller->dma_channel[p_transfer->channel_number].desc_trans_size;
+
+
+	lli_number = (p_transfer->trans_len % channel_max_trans_per_lli) ? 1:0;
+	lli_number += p_transfer->trans_len / channel_max_trans_per_lli;
+
+	return lli_number;
+
+}
+
+
+static void dump_lli(struct dw_lli *p_lli){
+	FH_DMA_DEBUG("link_mem padd:0x%x\n sar:0x%x\n dar:0x%x\n llp:0x%x\n ctllo:0x%x\n ctlhi:0x%x\n sstat:0x%x\n dstat:0x%x\n",
+			(rt_uint32_t)p_lli,p_lli->sar, p_lli->dar, p_lli->llp,
+			p_lli->ctllo, p_lli->ctlhi,p_lli->sstat,p_lli->dstat);
+}
+/*****************************************************************************
+ * Description:
+ *      add funtion description here
+ * Parameters:
+ *      description for each argument, new argument starts at new line
+ * Return:
+ *      what does this function returned?
+ *****************************************************************************/
+static void handle_single_transfer(struct fh81_dma  *p_dma,struct dma_transfer *p_transfer){
+
+
+	rt_uint32_t i;
+	struct dw_dma *temp_dwc;
+	temp_dwc = &p_dma->dwc;
+	volatile rt_uint32_t ret_status;
+	rt_list_t *p_controller_list;
+	rt_uint32_t lli_size,max_trans_size;
+	struct dw_lli  *p_lli = RT_NULL;
+	struct dma_transfer *dma_trans_desc;
+	struct dma_transfer *_dma_trans_desc;
+
+
+	rt_uint32_t temp_src_add;
+	rt_uint32_t temp_dst_add;
+	rt_uint32_t trans_total_len = 0;
+	rt_uint32_t temp_trans_size = 0;
+	//rt_uint32_t dma_channl_no = 0;
+
+	RT_ASSERT(p_transfer->channel_number < p_dma->dwc.channel_max_number);
+	RT_ASSERT(p_transfer->dma_number < DMA_CONTROLLER_NUMBER);
+	RT_ASSERT(&fh81_dma_controller[p_transfer->dma_number] == p_dma);
+	//when the dma transfer....the lock should be 0!!!!
+	//or user may not request the channel...
+	RT_ASSERT(p_dma->dma_channel[p_transfer->channel_number].channel_lock.value == 0);
+
+
+	ret_status = p_dma->dma_channel[p_transfer->channel_number].channel_status;
+	if(ret_status == CHANNEL_STATUS_CLOSED){
+		FH_DMA_DEBUG("transfer error,reason: use a closed channel..\n");
+		RT_ASSERT(ret_status != CHANNEL_STATUS_CLOSED);
+	}
+	p_transfer->dma_controller = p_dma;
+
+
+
+	rt_list_init(&p_transfer->transfer_list);
+	max_trans_size = p_transfer->dma_controller->dma_channel[p_transfer->channel_number].desc_trans_size;
+	//add transfer to the controller's queue list
+	//here should  insert before and handle after....this could be a fifo...
+	rt_list_insert_before(&p_dma->dma_channel[p_transfer->channel_number].queue , &p_transfer->transfer_list);
+
+
+	p_controller_list = &p_dma->dma_channel[p_transfer->channel_number].queue;
+
+
+	//here the driver could make a queue to cache the transfer and kick a thread to handle the queue~~~
+	//but now,this is a easy version...,just handle the transfer now!!!
+	list_for_each_entry_safe(dma_trans_desc, _dma_trans_desc, p_controller_list, transfer_list) {
+
+		//the dma controller could see the active transfer .....
+		p_transfer->dma_controller->dma_channel[p_transfer->channel_number].active_trans = dma_trans_desc;
+
+
+		trans_total_len = p_transfer->trans_len;
+
+
+		//handle desc
+		//step1:cal lli size...
+		lli_size = cal_lli_size(dma_trans_desc);
+		//step2:malloc lli_size  mem
+		//dma_trans_desc->first_lli = (struct dw_lli *)rt_malloc(lli_size * sizeof(struct dw_lli));
+
+		dma_trans_desc->first_lli = get_desc(p_dma,p_transfer,lli_size);
+
+		//not enough mem..
+		if(dma_trans_desc->first_lli == RT_NULL){
+
+			FH_DMA_DEBUG("transfer error,reason: not enough mem..\n");
+			RT_ASSERT(dma_trans_desc->first_lli != RT_NULL);
+		}
+
+
+		//bug here....
+		rt_memset((void *)dma_trans_desc->first_lli, 0, lli_size * sizeof(struct dw_lli));
+
+		p_lli = dma_trans_desc->first_lli;
+
+		//warnning!!!!must check if the add is 32bits ally...
+		RT_ASSERT(((rt_uint32_t)p_lli & 0x03) == 0);
+
+		RT_ASSERT(dma_trans_desc->dst_inc_mode <=DW_DMA_SLAVE_FIX);
+		RT_ASSERT(dma_trans_desc->src_inc_mode <=DW_DMA_SLAVE_FIX);
+		//step3: set the mem..
+		for(i=0;i<lli_size;i++){
+			//parse trans para...
+			//para add:
+
+			switch(dma_trans_desc->dst_inc_mode){
+			case DW_DMA_SLAVE_INC:
+				temp_dst_add = dma_trans_desc->dst_add + i * max_trans_size * (1<<dma_trans_desc->dst_width);
+				break;
+			case DW_DMA_SLAVE_DEC:
+				temp_dst_add = dma_trans_desc->dst_add - i * max_trans_size * (1<<dma_trans_desc->dst_width);
+				break;
+			case DW_DMA_SLAVE_FIX:
+				temp_dst_add = dma_trans_desc->dst_add;
+				break;
+
+			}
+
+
+			switch(dma_trans_desc->src_inc_mode){
+			case DW_DMA_SLAVE_INC:
+				temp_src_add = dma_trans_desc->src_add + i * max_trans_size * (1<<dma_trans_desc->src_width);
+				break;
+			case DW_DMA_SLAVE_DEC:
+				temp_src_add = dma_trans_desc->src_add - i * max_trans_size * (1<<dma_trans_desc->src_width);
+				break;
+			case DW_DMA_SLAVE_FIX:
+				temp_src_add = dma_trans_desc->src_add ;
+				break;
+
+			}
+
+
+			p_lli[i].sar = temp_src_add;
+			p_lli[i].dar = temp_dst_add;
+
+			//para ctl
+			temp_trans_size = (trans_total_len / max_trans_size)? max_trans_size : (trans_total_len % max_trans_size);
+			trans_total_len -= temp_trans_size;
+
+			RT_ASSERT(dma_trans_desc->dst_width <=DW_DMA_SLAVE_WIDTH_32BIT);
+			RT_ASSERT(dma_trans_desc->src_width <=DW_DMA_SLAVE_WIDTH_32BIT);
+
+			RT_ASSERT(dma_trans_desc->dst_msize <=DW_DMA_SLAVE_MSIZE_256);
+			RT_ASSERT(dma_trans_desc->src_msize <=DW_DMA_SLAVE_MSIZE_256);
+			RT_ASSERT(dma_trans_desc->fc_mode <=DMA_P2P);
+
+
+
+			p_lli[i].ctllo = DWC_CTLL_INT_EN|DWC_CTLL_DST_WIDTH(dma_trans_desc->dst_width)|DWC_CTLL_SRC_WIDTH(dma_trans_desc->src_width)
+					|DWC_CTLL_DST_INC_MODE(dma_trans_desc->dst_inc_mode)|DWC_CTLL_SRC_INC_MODE(dma_trans_desc->src_inc_mode)
+					|DWC_CTLL_DST_MSIZE(dma_trans_desc->dst_msize)|DWC_CTLL_SRC_MSIZE(dma_trans_desc->src_msize)|DWC_CTLL_FC(dma_trans_desc->fc_mode)
+					|DWC_CTLL_DMS(0)|DWC_CTLL_SMS(0);
+			//block size
+			p_lli[i].ctlhi = temp_trans_size;
+
+
+			if(trans_total_len > 0){
+				p_lli[i].llp = (rt_uint32_t)&p_lli[i+1];
+				p_lli[i].ctllo |= DWC_CTLL_LLP_D_EN|DWC_CTLL_LLP_S_EN;
+			}
+
+			//flush cache to mem
+			mmu_clean_invalidated_dcache((rt_uint32_t)&p_lli[i],sizeof(struct dw_lli));
+
+			dump_lli(&p_lli[i]);
+		}
+
+		//clear the isr status
+
+
+
+
+		//set the dma config reg
+		//clear cfg reload reg
+		//ret_status = dw_readl(temp_dwc,CHAN[dma_trans_desc->channel_number].CFG_LO);
+		//ret_status &= ~(DWC_CFGL_RELOAD_SAR|DWC_CFGL_RELOAD_DAR);
+		dw_writel(temp_dwc,CHAN[dma_trans_desc->channel_number].CFG_LO,0);
+
+		//set the first link add
+		//ret_status = dw_readl(temp_dwc,CHAN[dma_trans_desc->channel_number].LLP);
+		ret_status = 0;
+		ret_status = (rt_uint32_t)&p_lli[0];
+		dw_writel(temp_dwc,CHAN[dma_trans_desc->channel_number].LLP,ret_status);
+
+		//set link enable
+		//ret_status = dw_readl(temp_dwc,CHAN[dma_trans_desc->channel_number].CTL_LO);
+		ret_status = 0;
+		ret_status =DWC_CTLL_LLP_D_EN|DWC_CTLL_LLP_S_EN;
+		dw_writel(temp_dwc,CHAN[dma_trans_desc->channel_number].CTL_LO,ret_status);
+
+		dw_writel(temp_dwc,CHAN[dma_trans_desc->channel_number].CTL_HI,0);
+		//set handshaking
+
+		RT_ASSERT(dma_trans_desc->dst_hs <=	DMA_SW_HANDSHAKING);
+		RT_ASSERT(dma_trans_desc->src_hs <=	DMA_SW_HANDSHAKING);
+
+		if(dma_trans_desc->dst_hs == DMA_SW_HANDSHAKING){
+			ret_status = dw_readl(temp_dwc,CHAN[dma_trans_desc->channel_number].CFG_LO);
+			ret_status |= DWC_CFGL_HS_DST;
+			dw_writel(temp_dwc,CHAN[dma_trans_desc->channel_number].CFG_LO,ret_status);
+		}
+		else{
+			ret_status = dw_readl(temp_dwc,CHAN[dma_trans_desc->channel_number].CFG_LO);
+			ret_status &= ~DWC_CFGL_HS_DST;
+			dw_writel(temp_dwc,CHAN[dma_trans_desc->channel_number].CFG_LO,ret_status);
+		}
+
+		if(dma_trans_desc->src_hs == DMA_SW_HANDSHAKING){
+			ret_status = dw_readl(temp_dwc,CHAN[dma_trans_desc->channel_number].CFG_LO);
+			ret_status |= DWC_CFGL_HS_SRC;
+			dw_writel(temp_dwc,CHAN[dma_trans_desc->channel_number].CFG_LO,ret_status);
+		}
+		else{
+			ret_status = dw_readl(temp_dwc,CHAN[dma_trans_desc->channel_number].CFG_LO);
+			ret_status &= ~DWC_CFGL_HS_SRC;
+			dw_writel(temp_dwc,CHAN[dma_trans_desc->channel_number].CFG_LO,ret_status);
+		}
+
+
+		//only hw handshaking need this..
+		switch(dma_trans_desc->fc_mode){
+		case	DMA_M2M:
+			break;
+		case	DMA_M2P:
+			//set dst per...
+			RT_ASSERT(dma_trans_desc->dst_per <	DMA_HW_HS_END);
+
+			ret_status = dw_readl(temp_dwc,CHAN[dma_trans_desc->channel_number].CFG_HI);
+
+			//clear 43 ~ 46 bit
+			ret_status &= ~0x7800;
+
+			ret_status |= DWC_CFGH_DST_PER(dma_trans_desc->dst_per);
+			dw_writel(temp_dwc,CHAN[dma_trans_desc->channel_number].CFG_HI,ret_status);
+			//DWC_CFGH_SRC_PER
+
+
+			break;
+		case 	DMA_P2M:
+			//set src per...
+			RT_ASSERT(dma_trans_desc->src_per <	DMA_HW_HS_END);
+
+
+			ret_status = dw_readl(temp_dwc,CHAN[dma_trans_desc->channel_number].CFG_HI);
+
+			//clear 39 ~ 42 bit
+			ret_status &= ~0x780;
+
+
+			ret_status |= DWC_CFGH_SRC_PER(dma_trans_desc->src_per);
+			dw_writel(temp_dwc,CHAN[dma_trans_desc->channel_number].CFG_HI,ret_status);
+
+			break;
+		case 	DMA_P2P:
+			//set src and dst..
+			RT_ASSERT(dma_trans_desc->dst_per <	DMA_HW_HS_END);
+			RT_ASSERT(dma_trans_desc->src_per <	DMA_HW_HS_END);
+
+			ret_status = dw_readl(temp_dwc,CHAN[dma_trans_desc->channel_number].CFG_HI);
+			ret_status &= ~0x7800;
+			ret_status &= ~0x780;
+			ret_status |= DWC_CFGH_SRC_PER(dma_trans_desc->src_per) | DWC_CFGH_DST_PER(dma_trans_desc->dst_per);
+			dw_writel(temp_dwc,CHAN[dma_trans_desc->channel_number].CFG_HI,ret_status);
+
+			break;
+		default:
+			break;
+		}
+
+
+		dma_trans_desc->dma_controller->dma_channel[dma_trans_desc->channel_number].channel_status = CHANNEL_STATUS_BUSY;
+		//enable isr...
+		channel_set_bit(temp_dwc, MASK.XFER, lift_shift_bit_num(dma_trans_desc->channel_number));
+		channel_set_bit(temp_dwc, MASK.ERROR, lift_shift_bit_num(dma_trans_desc->channel_number));
+		//close
+		channel_clear_bit(temp_dwc, MASK.BLOCK, lift_shift_bit_num(dma_trans_desc->channel_number));
+
+		dw_writel(temp_dwc, CLEAR.XFER, 1<<(dma_trans_desc->channel_number));
+		dw_writel(temp_dwc, CLEAR.BLOCK, 1<<(dma_trans_desc->channel_number));
+		dw_writel(temp_dwc, CLEAR.SRC_TRAN, 1<<(dma_trans_desc->channel_number));
+		dw_writel(temp_dwc, CLEAR.DST_TRAN, 1<<(dma_trans_desc->channel_number));
+		dw_writel(temp_dwc, CLEAR.ERROR, 1<<(dma_trans_desc->channel_number));
+
+
+		ret_status = dw_readl(temp_dwc,CHAN[dma_trans_desc->channel_number].CFG_HI);
+		FH_DMA_DEBUG("cfg_hi value:0x%x\n",ret_status);
+
+		ret_status = dw_readl(temp_dwc,CHAN[dma_trans_desc->channel_number].CFG_LO);
+		FH_DMA_DEBUG("cfg_low value:0x%x\n",ret_status);
+
+
+		ret_status = dw_readl(temp_dwc, MASK.BLOCK);
+		FH_DMA_DEBUG("mask block value:0x%x\n",ret_status);
+
+		ret_status = dw_readl(temp_dwc, MASK.XFER);
+		FH_DMA_DEBUG("mask xfer value:0x%x\n",ret_status);
+
+
+
+		if(dma_trans_desc->prepare_callback){
+				dma_trans_desc->prepare_callback(dma_trans_desc->prepare_para);
+		}
+		//enable the channle to transfer
+		channel_set_bit(temp_dwc, CH_EN, lift_shift_bit_num(dma_trans_desc->channel_number));
+
+
+
+	}
+
+}
+
+/*****************************************************************************
+ * Description:
+ *      add funtion description here
+ * Parameters:
+ *      description for each argument, new argument starts at new line
+ * Return:
+ *      what does this function returned?
+ *****************************************************************************/
+static rt_err_t control (struct rt_dma_device *dma, int cmd, void *arg){
+
+
+	struct fh81_dma *my_own = (struct fh81_dma *)dma->parent.user_data;
+	rt_uint32_t i;
+	struct dw_dma *dwc;
+	dwc = &my_own->dwc;
+
+	rt_err_t ret = RT_EOK;
+
+	struct dma_transfer *p_dma_transfer = (struct dma_transfer *)arg;
+
+	//FH_DMA_DEBUG("p_dma_transfer value:0x%x\n",(rt_uint32_t)p_dma_transfer);
+
+
+	RT_ASSERT(my_own != RT_NULL);
+	RT_ASSERT(dwc != RT_NULL);
+
+
+
+	switch(cmd){
+	case RT_DEVICE_CTRL_DMA_OPEN:
+
+		//open the controller..
+		handle_dma_open(my_own);
+		break;
+	case RT_DEVICE_CTRL_DMA_CLOSE:
+
+		//close the controller..
+		handle_dma_close(my_own);
+		break;
+	case RT_DEVICE_CTRL_DMA_REQUEST_CHANNEL:
+		//request a channel for the user
+		RT_ASSERT(p_dma_transfer != RT_NULL);
+		ret = handle_request_channel(my_own,p_dma_transfer);
+
+		break;
+	case RT_DEVICE_CTRL_DMA_RELEASE_CHANNEL:
+		//release a channel
+		RT_ASSERT(p_dma_transfer != RT_NULL);
+
+		ret = handle_release_channel(my_own,p_dma_transfer);
+
+
+		break;
+
+	case RT_DEVICE_CTRL_DMA_SINGLE_TRANSFER:
+		//make a channel to transfer data.
+		RT_ASSERT(p_dma_transfer != RT_NULL);
+		//check if the dma channel is open,or return error.
+
+		my_own->dma_channel[p_dma_transfer->channel_number].open_flag = SINGLE_TRANSFER;
+		handle_single_transfer(my_own,p_dma_transfer);
+		//then wait for the channel is complete..
+		//caution that::we should be in the "rt_enter_critical()"when set the dma to work.
+		break;
+
+
+	case RT_DEVICE_CTRL_DMA_CYCLIC_PREPARE:
+		RT_ASSERT(p_dma_transfer != RT_NULL);
+		my_own->dma_channel[p_dma_transfer->channel_number].open_flag = CYCLIC_TRANSFER;
+		rt_fh_dma_cyclic_prep(my_own,p_dma_transfer);
+		break;
+
+	case RT_DEVICE_CTRL_DMA_CYCLIC_START:
+		rt_fh_dma_cyclic_start(p_dma_transfer);
+		break;
+
+	case RT_DEVICE_CTRL_DMA_CYCLIC_STOP:
+		rt_fh_dma_cyclic_stop(p_dma_transfer);
+		break;
+
+	case RT_DEVICE_CTRL_DMA_CYCLIC_FREE:
+		rt_fh_dma_cyclic_free(p_dma_transfer);
+		break;
+
+	default:
+		break;
+
+	}
+
+	return ret;
+
+
+}
+
+
+
+static void rt_fh81_dma_isr(int irq, void *param)
+{
+
+
+	RT_ASSERT(irq == DMAC_IRQn);
+	rt_uint32_t isr_channel_x,i,error,isr_channel_b;
+	struct fh81_dma *my_own = (struct fh81_dma *)param;
+	struct dw_dma *dwc;
+	struct dma_transfer *p_transfer;
+	dwc = &my_own->dwc;
+	//p_transfer =
+	//rt_kprintf("dma isr get in~~~\n");
+	error = dw_readl(dwc,STATUS.ERROR);
+	if(error != 0){
+		FH_DMA_DEBUG("dma isr error!!!!\n");
+		RT_ASSERT(error == RT_NULL);
+	}
+
+	isr_channel_x = dw_readl(dwc,STATUS.XFER);
+	isr_channel_b = dw_readl(dwc,STATUS.BLOCK);
+	//for single check the transfer status
+	//check which channel...
+
+	for(i=0;i<my_own->dwc.channel_max_number;i++){
+
+		if(my_own->dma_channel[i].open_flag == SINGLE_TRANSFER){
+			if(isr_channel_x & 1<<i){
+				dw_writel(dwc, CLEAR.XFER, 1<<i);
+
+				p_transfer = my_own->dma_channel[i].active_trans;
+
+				if(p_transfer->complete_callback){
+						p_transfer->complete_callback(p_transfer->complete_para);
+				}
+				p_transfer->dma_controller->dma_channel[p_transfer->channel_number].channel_status = CHANNEL_STATUS_IDLE;
+				//here is a bug...do not free here
+				//rt_free(p_transfer->first_lli);
+				put_desc(my_own,p_transfer);
+				rt_list_remove(&p_transfer->transfer_list);
+			}
+
+		}
+
+		else if(my_own->dma_channel[i].open_flag == CYCLIC_TRANSFER){
+			if(isr_channel_b & 1<<i){
+				p_transfer = my_own->dma_channel[i].active_trans;
+				dw_writel(dwc, CLEAR.BLOCK, 1<<(p_transfer->channel_number));
+				if(p_transfer->complete_callback){
+						p_transfer->complete_callback(p_transfer->complete_para);
+				}
+			}
+		}
+	}
+
+
+}
+
+
+
+/*****************************************************************************
+ * Description:
+ *      add funtion description here
+ * Parameters:
+ *      description for each argument, new argument starts at new line
+ * Return:
+ *      what does this function returned?
+ *****************************************************************************/
+
+const char *channel_lock_name[FH81_MAX_CHANNEL] = {
+		"channel_0_lock",
+		"channel_1_lock",
+		"channel_2_lock",
+		"channel_3_lock",
+};
+
+rt_err_t fh81_dma_register(struct fh81_dma * fh81_dma_p,
+                             char * dma_name){
+
+	rt_uint32_t i;
+
+	RT_ASSERT(fh81_dma_p != RT_NULL);
+	RT_ASSERT(dma_name != RT_NULL);
+	//RT_ASSERT(fh81_dma_p->dwc.init != FH81_DMA_INIT_ALREADY);
+
+
+	if(fh81_dma_p->dwc.init == FH81_DMA_INIT_ALREADY)
+		return 0;
+
+	struct rt_dma_device *rt_dma;
+	rt_dma = &fh81_dma_p->parent;
+	rt_dma->ops = &fh81_dma_ops;
+
+
+	//soc para set
+	fh81_dma_p->dwc.name = dma_name;
+	fh81_dma_p->dwc.regs =(void *)DMA_REG_BASE;
+	fh81_dma_p->dwc.paddr =	DMA_REG_BASE;
+	fh81_dma_p->dwc.irq = DMAC_IRQn;
+	fh81_dma_p->dwc.channel_max_number = FH81_MAX_CHANNEL;
+	fh81_dma_p->dwc.controller_status = CONTROLLER_STATUS_CLOSED;
+	fh81_dma_p->dwc.init = FH81_DMA_INIT_ALREADY;
+	fh81_dma_p->dwc.id = 0;
+	//channel set
+	for(i=0;i<FH81_MAX_CHANNEL;i++){
+		fh81_dma_p->dma_channel[i].channel_status = CHANNEL_STATUS_CLOSED;
+		fh81_dma_p->dma_channel[i].desc_total_no = DESC_MAX_SIZE;
+		//rt_completion_init(&(fh81_dma_p->dma_channel[i].transfer_completion));
+		rt_list_init(&(fh81_dma_p->dma_channel[i].queue));
+		fh81_dma_p->dma_channel[i].desc_trans_size = FH81_CHANNEL_MAX_TRANSFER_SIZE;
+		rt_sem_init(&fh81_dma_p->dma_channel[i].channel_lock, channel_lock_name[i], 1, RT_IPC_FLAG_FIFO);
+	}
+
+	//isr
+	rt_hw_interrupt_install(fh81_dma_p->dwc.irq, rt_fh81_dma_isr,
+							(void *)fh81_dma_p, "dma_isr");
+	rt_hw_interrupt_umask(fh81_dma_p->dwc.irq);
+
+	return	rt_hw_dma_register(rt_dma,dma_name,RT_DEVICE_FLAG_RDWR,fh81_dma_p);
+
+
+}
+
+
+static void rt_fh_dma_cyclic_stop(struct dma_transfer *p){
+
+	struct fh81_dma *my_own = p->dma_controller;
+	struct dw_dma *dwc;
+	dwc = &my_own->dwc;
+	channel_clear_bit(dwc, CH_EN, 1<<(p->channel_number));
+}
+
+
+
+
+static void rt_fh_dma_cyclic_start(struct dma_transfer *p){
+
+	struct fh81_dma *my_own = p->dma_controller;
+	struct dw_dma *dwc;
+	dwc = &my_own->dwc;
+	volatile uint32_t ret_status;
+	struct dw_lli  *p_lli = RT_NULL;
+	p_lli = p->first_lli;
+
+	//32bit ally
+	RT_ASSERT(((uint32_t)p_lli & 0x03) == 0);
+
+	dw_writel(dwc, CLEAR.XFER, 1<<(p->channel_number));
+	dw_writel(dwc, CLEAR.BLOCK, 1<<(p->channel_number));
+	dw_writel(dwc, CLEAR.ERROR, 1<<(p->channel_number));
+
+
+	//enable isr
+	channel_set_bit(dwc, MASK.BLOCK, lift_shift_bit_num(p->channel_number));
+	//disable isr
+	channel_clear_bit(dwc, MASK.XFER, lift_shift_bit_num(p->channel_number));
+
+	ret_status = dw_readl(dwc,CHAN[p->channel_number].CFG_LO);
+	ret_status &= ~(DWC_CFGL_RELOAD_SAR|DWC_CFGL_RELOAD_DAR);
+	dw_writel(dwc,CHAN[p->channel_number].CFG_LO,ret_status);
+
+	//set the first link add
+	ret_status = dw_readl(dwc,CHAN[p->channel_number].LLP);
+	ret_status = (uint32_t)&p_lli[0];
+	dw_writel(dwc,CHAN[p->channel_number].LLP,ret_status);
+
+	//set link enable
+	//ret_status = dw_readl(dwc,CHAN[p->channel_number].CTL_LO);
+	ret_status =DWC_CTLL_LLP_D_EN|DWC_CTLL_LLP_S_EN;
+	dw_writel(dwc,CHAN[p->channel_number].CTL_LO,ret_status);
+
+	//clear ctl_hi
+	dw_writel(dwc,CHAN[p->channel_number].CTL_HI,0);
+
+	//enable channle
+	channel_set_bit(dwc, CH_EN, 1<<(p->channel_number));
+
+
+}
+
+
+static void rt_fh_dma_cyclic_prep(struct fh81_dma * fh81_dma_p,struct dma_transfer *p) {
+
+	//bind the controller to the transfer
+	p->dma_controller = fh81_dma_p;
+	//bind active transfer
+	fh81_dma_p->dma_channel[p->channel_number].active_trans = p;
+	//p_transfer->dma_controller->dma_channel[p_transfer->channel_number].active_trans = dma_trans_desc;
+	struct fh81_dma *my_own = p->dma_controller;
+	struct dw_dma *dwc;
+	dwc = &my_own->dwc;
+	volatile uint32_t ret_status;
+	struct dw_lli  *p_lli = RT_NULL;
+	uint32_t periods,i;
+	uint32_t temp_src_add;
+	uint32_t temp_dst_add;
+	uint32_t buf_len = p->trans_len;
+	uint32_t period_len = p->period_len;
+
+	struct dma_transfer * dma_trans_desc = p;
+	//check first...
+	RT_ASSERT(buf_len % period_len == 0);
+
+	//cal the periods...
+	periods = buf_len / period_len;
+
+
+	//get desc....
+	//dma_trans_desc->first_lli = (struct dw_lli *)rt_malloc(periods * sizeof(struct dw_lli));
+	dma_trans_desc->first_lli  = get_desc(fh81_dma_p,dma_trans_desc,periods);
+
+	if(dma_trans_desc->first_lli == RT_NULL){
+
+		FH_DMA_DEBUG("transfer error,reason: not enough mem..\n");
+		RT_ASSERT(dma_trans_desc->first_lli != RT_NULL);
+	}
+
+	rt_memset((void *)dma_trans_desc->first_lli, 0, periods * sizeof(struct dw_lli));
+	p_lli = dma_trans_desc->first_lli;
+
+	RT_ASSERT(((uint32_t)p_lli & 0x03) == 0);
+
+
+	RT_ASSERT(dma_trans_desc->dst_inc_mode <=DW_DMA_SLAVE_FIX);
+	RT_ASSERT(dma_trans_desc->src_inc_mode <=DW_DMA_SLAVE_FIX);
+	//step3: set the mem..
+	for(i=0;i<periods;i++){
+		//parse trans para...
+		//para add:
+		switch(dma_trans_desc->dst_inc_mode){
+		case DW_DMA_SLAVE_INC:
+			temp_dst_add = dma_trans_desc->dst_add + i * period_len * (1<<dma_trans_desc->dst_width);
+			break;
+		case DW_DMA_SLAVE_DEC:
+			temp_dst_add = dma_trans_desc->dst_add - i * period_len * (1<<dma_trans_desc->dst_width);
+			break;
+		case DW_DMA_SLAVE_FIX:
+			temp_dst_add = dma_trans_desc->dst_add;
+			break;
+
+		}
+
+
+		switch(dma_trans_desc->src_inc_mode){
+		case DW_DMA_SLAVE_INC:
+			temp_src_add = dma_trans_desc->src_add + i * period_len * (1<<dma_trans_desc->src_width);
+			break;
+		case DW_DMA_SLAVE_DEC:
+			temp_src_add = dma_trans_desc->src_add - i * period_len * (1<<dma_trans_desc->src_width);
+			break;
+		case DW_DMA_SLAVE_FIX:
+			temp_src_add = dma_trans_desc->src_add ;
+			break;
+
+		}
+
+
+		p_lli[i].sar = temp_src_add;
+		p_lli[i].dar = temp_dst_add;
+
+		//para ctl
+
+
+		RT_ASSERT(dma_trans_desc->dst_width <=DW_DMA_SLAVE_WIDTH_32BIT);
+		RT_ASSERT(dma_trans_desc->src_width <=DW_DMA_SLAVE_WIDTH_32BIT);
+
+		RT_ASSERT(dma_trans_desc->dst_msize <=DW_DMA_SLAVE_MSIZE_256);
+		RT_ASSERT(dma_trans_desc->src_msize <=DW_DMA_SLAVE_MSIZE_256);
+		RT_ASSERT(dma_trans_desc->fc_mode <=DMA_P2P);
+
+
+
+		p_lli[i].ctllo = DWC_CTLL_INT_EN|DWC_CTLL_DST_WIDTH(dma_trans_desc->dst_width)|DWC_CTLL_SRC_WIDTH(dma_trans_desc->src_width)
+				|DWC_CTLL_DST_INC_MODE(dma_trans_desc->dst_inc_mode)|DWC_CTLL_SRC_INC_MODE(dma_trans_desc->src_inc_mode)
+				|DWC_CTLL_DST_MSIZE(dma_trans_desc->dst_msize)|DWC_CTLL_SRC_MSIZE(dma_trans_desc->src_msize)|DWC_CTLL_FC(dma_trans_desc->fc_mode)
+				|DWC_CTLL_DMS(0)|DWC_CTLL_SMS(0);
+		//block size
+		p_lli[i].ctlhi = period_len;
+
+
+
+		p_lli[i].llp = (uint32_t)&p_lli[i+1];
+		p_lli[i].ctllo |= DWC_CTLL_LLP_D_EN|DWC_CTLL_LLP_S_EN;
+
+
+		//flush cache to mem
+		mmu_clean_invalidated_dcache((uint32_t)&p_lli[i],sizeof(struct dw_lli));
+
+		dump_lli(&p_lli[i]);
+	}
+	//make a ring here
+	p_lli[periods -1 ].llp = (uint32_t)&p_lli[0];
+
+	mmu_clean_invalidated_dcache((uint32_t)&p_lli[periods -1 ],sizeof(struct dw_lli));
+
+
+
+	//parse the handshake
+	RT_ASSERT(dma_trans_desc->dst_hs <=	DMA_SW_HANDSHAKING);
+	RT_ASSERT(dma_trans_desc->src_hs <=	DMA_SW_HANDSHAKING);
+
+	//dst handshake
+	dw_writel(dwc,CHAN[dma_trans_desc->channel_number].CFG_LO,0);
+	ret_status = 0;
+	if(dma_trans_desc->dst_hs == DMA_SW_HANDSHAKING){
+		ret_status |= DWC_CFGL_HS_DST;
+	}
+	else{
+		ret_status &= ~DWC_CFGL_HS_DST;
+	}
+	dw_writel(dwc,CHAN[dma_trans_desc->channel_number].CFG_LO,ret_status);
+
+
+
+	//src handshake
+	ret_status = dw_readl(dwc,CHAN[dma_trans_desc->channel_number].CFG_LO);
+	if(dma_trans_desc->src_hs == DMA_SW_HANDSHAKING){
+		ret_status |= DWC_CFGL_HS_SRC;
+	}
+	else{
+		ret_status &= ~DWC_CFGL_HS_SRC;
+	}
+	dw_writel(dwc,CHAN[dma_trans_desc->channel_number].CFG_LO,ret_status);
+
+
+	//only hw handshaking need this..
+	switch(dma_trans_desc->fc_mode){
+	case	DMA_M2M:
+		break;
+	case	DMA_M2P:
+		//set dst per...
+		RT_ASSERT(dma_trans_desc->dst_per <	DMA_HW_HS_END);
+		ret_status = dw_readl(dwc,CHAN[dma_trans_desc->channel_number].CFG_HI);
+		//clear 43 ~ 46 bit
+		ret_status &= ~0x7800;
+		ret_status |= DWC_CFGH_DST_PER(dma_trans_desc->dst_per);
+		dw_writel(dwc,CHAN[dma_trans_desc->channel_number].CFG_HI,ret_status);
+		//DWC_CFGH_SRC_PER
+
+		break;
+	case 	DMA_P2M:
+		//set src per...
+		RT_ASSERT(dma_trans_desc->src_per <	DMA_HW_HS_END);
+		ret_status = dw_readl(dwc,CHAN[dma_trans_desc->channel_number].CFG_HI);
+		//clear 39 ~ 42 bit
+		ret_status &= ~0x780;
+		ret_status |= DWC_CFGH_SRC_PER(dma_trans_desc->src_per);
+		dw_writel(dwc,CHAN[dma_trans_desc->channel_number].CFG_HI,ret_status);
+
+		break;
+	case 	DMA_P2P:
+		//set src and dst..
+		RT_ASSERT(dma_trans_desc->dst_per <	DMA_HW_HS_END);
+		RT_ASSERT(dma_trans_desc->src_per <	DMA_HW_HS_END);
+
+		ret_status = dw_readl(dwc,CHAN[dma_trans_desc->channel_number].CFG_HI);
+		ret_status &= ~0x7800;
+		ret_status &= ~0x780;
+		ret_status |= DWC_CFGH_SRC_PER(dma_trans_desc->src_per) | DWC_CFGH_DST_PER(dma_trans_desc->dst_per);
+		dw_writel(dwc,CHAN[dma_trans_desc->channel_number].CFG_HI,ret_status);
+
+		break;
+	default:
+		break;
+	}
+
+	dma_trans_desc->dma_controller->dma_channel[dma_trans_desc->channel_number].channel_status = CHANNEL_STATUS_BUSY;
+
+	if(dma_trans_desc->prepare_callback){
+			dma_trans_desc->prepare_callback(dma_trans_desc->prepare_para);
+	}
+
+}
+
+
+static void rt_fh_dma_cyclic_free(struct dma_transfer *p){
+
+	struct fh81_dma *my_own = p->dma_controller;
+	struct dw_dma *dwc;
+	dwc = &my_own->dwc;
+	volatile uint32_t ret_status;
+	struct dw_lli  *p_lli = RT_NULL;
+	p_lli = p->first_lli;
+
+
+	//close channel first..
+	channel_clear_bit(dwc, CH_EN, 1<<(p->channel_number));
+
+	//check if close really
+	while (dw_readl(dwc, CH_EN) & 1<<(p->channel_number));
+
+	dw_writel(dwc, CLEAR.XFER, 1<<(p->channel_number));
+	dw_writel(dwc, CLEAR.BLOCK, 1<<(p->channel_number));
+	dw_writel(dwc, CLEAR.ERROR, 1<<(p->channel_number));
+
+
+
+
+	//rt_free(p->first_lli);
+	put_desc(my_own,p);
+
+}
+
+
+void rt_fh_dma_init(void){
+	fh81_dma_register(&fh81_dma_controller[0],"fh81_dma");
+
+}

+ 254 - 0
bsp/fh8620/drivers/fh_dma.h

@@ -0,0 +1,254 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef FH_DMA_H_
+#define FH_DMA_H_
+
+
+/****************************************************************************
+* #include section
+*	add #include here if any
+***************************************************************************/
+
+#include <rtthread.h>
+
+
+/*********************************
+ *
+ * DMA SOC define start
+ *
+ *********************************/
+
+
+#define FH81_MAX_CHANNEL					(4)
+#define FH81_CHANNEL_MAX_TRANSFER_SIZE		(4095)
+
+
+
+
+enum DMA_HW_HS_MAP{
+	ACODEC_RX = 0,
+	ACODEC_TX,
+	SPI0_RX,
+	SPI0_TX,
+	SPI1_RX,
+	SPI1_TX,
+	UART0_RX,
+	UART0_TX,
+	UART1_RX,
+	UART1_TX,
+	DMA_HW_HS_END,
+};
+
+/*********************************
+ *
+ * DMA SOC define end
+ *
+ *********************************/
+
+//user use the dma could use callback function,when the dma make the work done...
+typedef void (*dma_complete_callback)(void *complete_para);
+
+typedef void (*user_prepare)(void *prepare_para);
+
+
+
+/****************************		i'm cut-off line		************************************/
+
+
+
+
+
+
+//controller private para...
+struct fh81_dma;
+
+
+struct dw_lli {
+	/* values that are not changed by hardware */
+	rt_uint32_t	sar;
+	rt_uint32_t	dar;
+	rt_uint32_t	llp;		/* chain to next lli */
+	rt_uint32_t		ctllo;
+	/* values that may get written back: */
+	rt_uint32_t		ctlhi;
+	/* sstat and dstat can snapshot peripheral register state.
+	 * silicon config may discard either or both...
+	 */
+	rt_uint32_t		sstat;
+	rt_uint32_t		dstat;
+	rt_uint32_t reserve;
+
+};
+
+//transfer use below
+struct dma_transfer{
+	//this is private for the dma drive....app don't touch it,the driver will manger it
+	//link interface for more transfer to the controller...
+	rt_list_t transfer_list;
+	struct fh81_dma *dma_controller;
+	//this the mem add....the dma controller will load the setting to move data ....
+	//user don't touch it
+	struct dw_lli *first_lli;
+	rt_uint32_t lli_size;
+	//new add for allign get desc...
+	rt_uint32_t actual_lli_size;
+
+
+	//user could set paras below~~~
+#define AUTO_FIND_CHANNEL		(0xff)
+	//transfer with which dma channel...if the data is 0xff, the driver will auto find a free channel.
+	rt_uint32_t		channel_number;
+	//which dma you want to use...for fh81....only 0!!!
+	rt_uint32_t		dma_number;
+
+
+	//user should set the para below
+#define	DMA_M2M 			(0)		//	MEM <=> MEM
+#define	DMA_M2P 			(1)		//	MEM => peripheral A
+#define	DMA_P2M 			(2)		//	MEM <= peripheral A
+#define	DMA_P2P 			(3)		//	peripheral A <=> peripheral B
+	rt_uint32_t			fc_mode;//ip->mem. mem->mem. mem->ip
+
+
+
+
+#define DMA_HW_HANDSHAKING	(0)
+#define DMA_SW_HANDSHAKING	(1)
+	rt_uint32_t			src_hs;			//src
+	//if use hw handshaking ,you need to set the hw handshaking number, this SOC defined
+	rt_uint32_t			src_per;		//src hw handshake number
+	//rt_uint32_t			irq_mode;//for each transfer,irq maybe not same. suggest for the default(transfer isr)
+
+#define	DW_DMA_SLAVE_WIDTH_8BIT 	(0)
+#define	DW_DMA_SLAVE_WIDTH_16BIT 	(1)
+#define	DW_DMA_SLAVE_WIDTH_32BIT 	(2)
+	rt_uint32_t			src_width;
+
+	//the user should reference the hw handshaking watermark..
+#define DW_DMA_SLAVE_MSIZE_1		 (0)
+#define DW_DMA_SLAVE_MSIZE_4		 (1)
+#define DW_DMA_SLAVE_MSIZE_8		 (2)
+#define DW_DMA_SLAVE_MSIZE_16		 (3)
+#define DW_DMA_SLAVE_MSIZE_32		 (4)
+#define DW_DMA_SLAVE_MSIZE_64		 (5)
+#define DW_DMA_SLAVE_MSIZE_128		 (6)
+#define DW_DMA_SLAVE_MSIZE_256		 (7)
+	rt_uint32_t			src_msize;
+	rt_uint32_t			src_add;
+#define DW_DMA_SLAVE_INC		(0)
+#define DW_DMA_SLAVE_DEC		(1)
+#define DW_DMA_SLAVE_FIX		(2)
+	rt_uint32_t			src_inc_mode;	//increase mode: increase or not change
+
+
+//#define DMA_DST_HW_HANDSHAKING	(0)
+//#define DMA_DST_SW_HANDSHAKING	(1)
+	rt_uint32_t			dst_hs;			//src
+	//if use hw handshaking ,you need to set the hw handshaking number, this SOC defined
+	rt_uint32_t			dst_per;		//dst hw handshake number
+//#define	DW_DMA_SLAVE_WIDTH_8BIT 	(0)
+//#define	DW_DMA_SLAVE_WIDTH_16BIT 	(1)
+//#define	DW_DMA_SLAVE_WIDTH_32BIT 	(2)
+	rt_uint32_t			dst_width;
+//#define DW_DMA_SLAVE_MSIZE_1		 (0)
+//#define DW_DMA_SLAVE_MSIZE_4		 (1)
+//#define DW_DMA_SLAVE_MSIZE_8		 (2)
+//#define DW_DMA_SLAVE_MSIZE_16		 (3)
+//#define DW_DMA_SLAVE_MSIZE_32		 (4)
+//#define DW_DMA_SLAVE_MSIZE_64		 (5)
+//#define DW_DMA_SLAVE_MSIZE_128		 (6)
+//#define DW_DMA_SLAVE_MSIZE_256		 (7)
+	rt_uint32_t			dst_msize;
+	rt_uint32_t			dst_add;
+//#define DW_DMA_SLAVE_INC		(0)
+//#define DW_DMA_SLAVE_DEC		(1)
+//#define DW_DMA_SLAVE_FIX		(2)
+	rt_uint32_t			dst_inc_mode;	//increase mode: increase or not change
+
+
+	//total sizes, unit: src_width/DW_DMA_SLAVE_WIDTH_8BIT...
+	//exg: src_width = DW_DMA_SLAVE_WIDTH_32BIT. trans_len = 2...means that: the dma will transfer 2*4 bytes..
+	//exg: src_width = DW_DMA_SLAVE_WIDTH_8BIT. trans_len = 6...means that: the dma will transfer 1*6 bytes..
+	rt_uint32_t			trans_len;
+
+
+
+	//this is used when dma finish transfer job
+	dma_complete_callback complete_callback;
+	void				*complete_para; //for the driver data use the dma driver.
+
+
+	//this is used when dma before work..the user maybe need to set his own private para..
+	user_prepare	prepare_callback;
+	void				*prepare_para;
+
+
+	//add cyclic para...
+	//period len..
+	rt_uint32_t period_len;
+
+
+};
+
+
+
+
+
+
+
+
+/****************************************************************************
+* #define section
+*	add constant #define here if any
+***************************************************************************/
+
+
+/****************************************************************************
+* ADT section
+*	add Abstract Data Type definition here
+***************************************************************************/
+
+
+
+/****************************************************************************
+*  extern variable declaration section
+***************************************************************************/
+
+/****************************************************************************
+*  section
+*	add function prototype here if any
+***************************************************************************/
+rt_err_t fh81_dma_register(struct fh81_dma * fh81_dma_p,
+                             char * dma_name);
+void rt_fh_dma_init(void);
+/********************************End Of File********************************/
+
+
+
+
+#endif /* FH81_DMA_H_ */
+

+ 450 - 0
bsp/fh8620/drivers/gpio.c

@@ -0,0 +1,450 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "fh_def.h"
+#include "gpio.h"
+#include "Libraries/inc/fh_gpio.h"
+#include "interrupt.h"
+#include "board_info.h"
+#include <rtdevice.h>
+#include "fh_arch.h"
+//#define FH_GPIO_DEBUG
+
+#ifdef FH_GPIO_DEBUG
+#define PRINT_GPIO_DBG(fmt, args...)     \
+    do                                  \
+    {                                   \
+        rt_kprintf("FH_GPIO_DEBUG: ");   \
+        rt_kprintf(fmt, ## args);       \
+    }                                   \
+    while(0)
+#else
+#define PRINT_GPIO_DBG(fmt, args...)  do { } while (0)
+#endif
+
+int gpio_available[NUM_OF_GPIO];
+extern struct rt_irq_desc irq_desc[];
+
+static inline rt_uint32_t gpio_to_base(rt_uint32_t gpio)
+{
+    if (gpio >= 32 && gpio < 64)
+    {
+        return GPIO1_REG_BASE;
+    }
+    else if(gpio < 32)
+    {
+        return GPIO0_REG_BASE;
+    }
+    else
+    {
+        rt_kprintf("ERROR: %s, incorrect GPIO num\n", __func__);
+        return -RT_ERROR;
+    }
+}
+
+static inline rt_uint32_t irq_to_base(rt_uint32_t irq)
+{
+    return (irq-NR_INTERNAL_IRQS > 32) ? GPIO1_REG_BASE : GPIO0_REG_BASE;
+}
+
+static inline rt_uint32_t irq_to_bit(rt_uint32_t irq)
+{
+    if(irq >= NR_INTERNAL_IRQS && irq < NR_INTERNAL_IRQS + 32)
+        return 0;
+    else
+        return 32;
+}
+
+rt_uint32_t gpio_to_irq(rt_uint32_t gpio)
+{
+    return (gpio + NR_INTERNAL_IRQS);
+}
+
+void gpio_enable_debounce(rt_uint32_t gpio)
+{
+    rt_uint32_t tmp, base, offset;
+
+    offset = gpio % 32;
+    base = gpio_to_base(gpio);
+
+    tmp = GET_REG(base + REG_GPIO_DEBOUNCE);
+
+    tmp |= BIT(offset);
+
+    SET_REG(base + REG_GPIO_DEBOUNCE, tmp);
+}
+
+void gpio_disable_debounce(rt_uint32_t gpio)
+{
+    rt_uint32_t tmp, base, offset;
+
+    offset = gpio % 32;
+    base = gpio_to_base(gpio);
+
+    tmp = GET_REG(base + REG_GPIO_DEBOUNCE);
+
+    tmp &= ~BIT(offset);
+
+    SET_REG(base + REG_GPIO_DEBOUNCE, tmp);
+}
+
+int gpio_get_value(rt_uint32_t gpio)
+{
+    rt_uint32_t tmp, base, offset;
+
+    offset = gpio % 32;
+    base = gpio_to_base(gpio);
+
+    tmp = GET_REG(base + REG_GPIO_SWPORTA_DDR);
+    tmp &= BIT(offset);
+
+    if (tmp) {
+        tmp = GET_REG(base + REG_GPIO_SWPORTA_DR);
+    } else {
+        tmp = GET_REG(base + REG_GPIO_EXT_PORTA);
+    }
+    tmp &= BIT(offset);
+    tmp = tmp >> offset;
+    return tmp;
+}
+
+void gpio_set_value(rt_uint32_t gpio, int val)
+{
+    rt_uint32_t tmp, base, offset;
+
+    offset = gpio % 32;
+    base = gpio_to_base(gpio);
+
+    tmp = GET_REG(base + REG_GPIO_SWPORTA_DR);
+
+    if(val)
+        tmp |= BIT(offset);
+    else
+        tmp &= ~BIT(offset);
+
+    SET_REG(base + REG_GPIO_SWPORTA_DR, tmp);
+
+}
+
+
+int gpio_get_direction(rt_uint32_t gpio)
+{
+    rt_uint32_t tmp, base, offset;
+
+    offset = gpio % 32;
+    base = gpio_to_base(gpio);
+
+    tmp = GET_REG(base + REG_GPIO_SWPORTA_DDR);
+
+    tmp &= BIT(offset);
+    tmp = tmp >> offset;
+    return tmp;
+}
+
+void gpio_set_direction(rt_uint32_t gpio, rt_uint32_t direction)
+{
+    rt_uint32_t tmp, base, offset;
+
+    offset = gpio % 32;
+    base = gpio_to_base(gpio);
+
+    tmp = GET_REG(base + REG_GPIO_SWPORTA_DDR);
+
+    if(direction == GPIO_DIR_OUTPUT)
+        tmp |= BIT(offset);
+    else
+        tmp &= ~BIT(offset);
+
+    SET_REG(base + REG_GPIO_SWPORTA_DDR, tmp);
+}
+
+
+int gpio_set_irq_type(rt_uint32_t gpio, rt_uint32_t type)
+{
+    rt_uint32_t int_type, int_polarity;
+    rt_uint32_t bit = gpio % 32;
+    rt_uint32_t base;
+    base = gpio_to_base(gpio);
+
+    int_type = GET_REG(base + REG_GPIO_INTTYPE_LEVEL);
+    int_polarity = GET_REG(base + REG_GPIO_INT_POLARITY);
+
+    switch (type & IRQ_TYPE_TRIGGER_MASK) {
+    case IRQ_TYPE_EDGE_BOTH:
+        int_type |= BIT(bit);
+        // toggle trigger
+        if (gpio_get_value(gpio))
+            int_polarity &= ~BIT(bit);
+        else
+            int_polarity |= BIT(bit);
+        break;
+    case IRQ_TYPE_EDGE_RISING:
+        int_type |= BIT(bit);
+        int_polarity |= BIT(bit);
+        break;
+    case IRQ_TYPE_EDGE_FALLING:
+        int_type |= BIT(bit);
+        int_polarity &= ~BIT(bit);
+        break;
+    case IRQ_TYPE_LEVEL_HIGH:
+        int_type &= ~BIT(bit);
+        int_polarity |= BIT(bit);
+        break;
+    case IRQ_TYPE_LEVEL_LOW:
+        int_type &= ~BIT(bit);
+        int_polarity &= ~BIT(bit);
+        break;
+    case IRQ_TYPE_NONE:
+        return 0;
+    default:
+        return -RT_ERROR;
+    }
+    SET_REG(base + REG_GPIO_INTTYPE_LEVEL, int_type);
+    SET_REG(base + REG_GPIO_INT_POLARITY, int_polarity);
+    return 0;
+}
+
+int gpio_irq_mask(rt_uint32_t irq)
+{
+    rt_uint32_t tmp, base, bit;
+
+    base = irq_to_base(irq);
+    bit = irq_to_bit(irq);
+
+    tmp = GET_REG(base + REG_GPIO_INTMASK);
+    tmp |= BIT(irq - NR_INTERNAL_IRQS - bit);
+    SET_REG(base + REG_GPIO_INTMASK, tmp);
+    return 0;
+}
+
+int gpio_irq_unmask(rt_uint32_t irq)
+{
+    rt_uint32_t tmp, base, bit;
+
+    base = irq_to_base(irq);
+    bit = irq_to_bit(irq);
+
+    tmp = GET_REG(base + REG_GPIO_INTMASK);
+    tmp &= ~BIT((irq - NR_INTERNAL_IRQS - bit));
+    SET_REG(base + REG_GPIO_INTMASK, tmp);
+    return 0;
+}
+
+void gpio_irq_enable(rt_uint32_t irq)
+{
+    rt_uint32_t tmp, base, bit;
+
+    base = irq_to_base(irq);
+    bit = irq_to_bit(irq);
+
+    tmp = GET_REG(base + REG_GPIO_INTEN);
+    tmp |= BIT(irq - NR_INTERNAL_IRQS - bit);
+    SET_REG(base + REG_GPIO_INTEN, tmp);
+}
+
+void gpio_irq_disable(rt_uint32_t irq)
+{
+    rt_uint32_t tmp, base, bit;
+
+    base = irq_to_base(irq);
+    bit = irq_to_bit(irq);
+
+    tmp = GET_REG(base + REG_GPIO_INTEN);
+    tmp &= ~BIT((irq - NR_INTERNAL_IRQS - bit));
+    SET_REG(base + REG_GPIO_INTEN, tmp);
+}
+
+static void fh_gpio_interrupt(int irq, void *param)
+{
+    rt_uint32_t irq_status;
+    int gpio_num, gpio;
+    rt_uint32_t base;
+    struct fh_gpio_obj *gpio_obj = (struct fh_gpio_obj *)param;
+
+    //rt_kprintf("fh_gpio_interrupt start\n");
+
+    //fixme: spin lock???
+    base = (irq==40) ? GPIO0_REG_BASE : GPIO1_REG_BASE;
+
+    irq_status = GET_REG(base + REG_GPIO_INTSTATUS);
+
+    if (irq_status == 0) {
+        rt_kprintf("gpio irq status is zero.\n");
+        return;
+    }
+
+    /* temporarily mask (level sensitive) parent IRQ */
+    gpio_irq_mask(irq);
+
+    gpio_num = __rt_ffs(irq_status) - 1;
+
+    SET_REG(base + REG_GPIO_PORTA_EOI, BIT(gpio_num));
+
+    gpio = gpio_num + ((irq==40) ? 0 : 32);
+
+    //generic_handle_irq(gpio_to_irq(gpio));
+    if(irq_desc[gpio_to_irq(gpio)].handler)
+        irq_desc[gpio_to_irq(gpio)].handler(gpio_to_irq(gpio), irq_desc[gpio_to_irq(gpio)].param);
+
+    gpio_irq_mask(irq);
+    /* now it may re-trigger */
+}
+
+
+int gpio_direction_input(rt_uint32_t gpio)
+{
+    rt_uint32_t reg, base;
+
+    if(gpio > NUM_OF_GPIO)
+    {
+        rt_kprintf("ERROR: %s, incorrect GPIO num\n", __func__);
+        return -RT_ERROR;
+    }
+
+    if(!gpio_available[gpio])
+    {
+        rt_kprintf("ERROR: %s, GPIO %d is not available\n", __func__, gpio);
+        return -RT_EBUSY;
+    }
+
+    base = gpio_to_base(gpio);
+    gpio = gpio % 32;
+
+
+    //fixme: lock
+    //spin_lock_irqsave(&chip->lock, flags);
+    reg = GET_REG(base + REG_GPIO_SWPORTA_DDR);
+    reg &= ~(1 << gpio);
+    SET_REG(base + REG_GPIO_SWPORTA_DDR, reg);
+    //spin_unlock_irqrestore(&chip->lock, flags);
+
+    return 0;
+}
+
+int gpio_direction_output(rt_uint32_t gpio, rt_uint32_t val)
+{
+    rt_uint32_t reg, base;
+
+    if(gpio > NUM_OF_GPIO)
+    {
+        rt_kprintf("ERROR: %s, incorrect GPIO num\n", __func__);
+        return -RT_ERROR;
+    }
+
+    if(!gpio_available[gpio])
+    {
+        rt_kprintf("ERROR: %s, GPIO %d is not available\n", __func__, gpio);
+        return -RT_EBUSY;
+    }
+
+    base = gpio_to_base(gpio);
+    gpio = gpio % 32;
+
+    //fixme: lock
+    //spin_lock_irqsave(&chip->lock, flags);
+    reg = GET_REG(base + REG_GPIO_SWPORTA_DDR);
+    reg |= (1 << gpio);
+    SET_REG(base + REG_GPIO_SWPORTA_DDR, reg);
+
+    reg = GET_REG(base + REG_GPIO_SWPORTA_DR);
+
+    if(val)
+        reg |= (1 << gpio);
+    else
+        reg &= ~(1 << gpio);
+    SET_REG(base + REG_GPIO_SWPORTA_DR, reg);
+
+    //spin_unlock_irqrestore(&chip->lock, flags);
+
+    return 0;
+}
+
+int gpio_request(rt_uint32_t gpio)
+{
+    if(gpio > NUM_OF_GPIO)
+    {
+        rt_kprintf("ERROR: %s, incorrect GPIO num\n", __func__);
+        return -RT_ERROR;
+    }
+    gpio_available[gpio] = 1;
+    return 0;
+}
+
+int gpio_release(rt_uint32_t gpio)
+{
+    if(gpio > NUM_OF_GPIO)
+    {
+        rt_kprintf("ERROR: %s, incorrect GPIO num\n", __func__);
+        return -RT_ERROR;
+    }
+    gpio_available[gpio] = 0;
+    return 0;
+}
+
+int fh_gpio_probe(void *priv_data)
+{
+    struct fh_gpio_obj *gpio_obj = (struct fh_gpio_obj *)priv_data;
+    int i;
+
+    if(gpio_obj->id == 0){
+    	  rt_hw_interrupt_install(gpio_obj->irq, fh_gpio_interrupt, (void *)gpio_obj, "gpio_0");
+    }
+    else if(gpio_obj->id == 1){
+    	rt_hw_interrupt_install(gpio_obj->irq, fh_gpio_interrupt, (void *)gpio_obj, "gpio_1");
+    }
+
+
+
+    rt_hw_interrupt_umask(gpio_obj->irq);
+
+    for(i=0; i<32; i++)
+    {
+        irq_desc[NR_INTERNAL_IRQS + 32 * gpio_obj->id + i].param = gpio_obj;
+    }
+
+    return 0;
+}
+
+int fh_gpio_exit(void *priv_data)
+{
+    return 0;
+}
+
+struct fh_board_ops gpio_driver_ops =
+{
+        .probe = fh_gpio_probe,
+        .exit = fh_gpio_exit,
+};
+
+void rt_hw_gpio_init(void)
+{
+    PRINT_GPIO_DBG("%s start\n", __func__);
+    rt_memset(gpio_available, 0, sizeof(int) * NUM_OF_GPIO);
+    fh_board_driver_register("gpio", &gpio_driver_ops);
+    PRINT_GPIO_DBG("%s end\n", __func__);
+}
+
+

+ 188 - 0
bsp/fh8620/drivers/gpio.h

@@ -0,0 +1,188 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef GPIO_H_
+#define GPIO_H_
+
+#include <rtdef.h>
+
+/**
+ * GPIO interrupt trigger type macro,
+ * each represent an interrupt trigger mode
+ *
+ * @see gpio_set_irq_type();
+ */
+enum
+{
+    IRQ_TYPE_NONE       = 0x00000000,                                       /**< none*/
+    IRQ_TYPE_EDGE_RISING    = 0x00000001,                                   /**< rising edge*/
+    IRQ_TYPE_EDGE_FALLING   = 0x00000002,                                   /**< falling edge*/
+    IRQ_TYPE_EDGE_BOTH  = (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING),
+    IRQ_TYPE_LEVEL_HIGH = 0x00000004,                                       /**< high level*/
+    IRQ_TYPE_LEVEL_LOW  = 0x00000008,                                       /**< low level*/
+    IRQ_TYPE_LEVEL_MASK = (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH),
+    IRQ_TYPE_TRIGGER_MASK   = (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW | \
+            IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING),
+};
+
+/**
+ * GPIO direction macro,
+ * each represent a direction
+ *
+ * @see gpio_get_direction();
+ * @see gpio_set_direction();
+ */
+#define GPIO_DIR_OUTPUT 1       /**< output*/
+#define GPIO_DIR_INPUT  0       /**< input*/
+
+/**
+ * convert GPIO number to IRQ number
+ * @param gpio GPIO number to be converted
+ * @return IRQ number
+ */
+rt_uint32_t gpio_to_irq(rt_uint32_t gpio);
+
+/**
+ * disable GPIO's debounce mode
+ * controls whether an external signal that is the source
+ * of an interrupt needs to be debounced to remove any
+ * spurious glitches.
+ * @param gpio GPIO number
+ */
+void gpio_disable_debounce(rt_uint32_t gpio);
+
+/**
+ * enable GPIO's debounce mode
+ * controls whether an external signal that is the source
+ * of an interrupt needs to be debounced to remove any
+ * spurious glitches.
+ * @param gpio GPIO number
+ */
+void gpio_enable_debounce(rt_uint32_t gpio);
+
+/**
+ * allows each GPIO to be configured for interrupts
+ * it configures the corresponding GPIO to become an interrupt
+ * @param gpio GPIO number
+ */
+void gpio_irq_enable(rt_uint32_t irq);
+
+/**
+ * GPIO operates as a normal GPIO signal
+ * interrupts are disabled
+ * @param gpio GPIO number
+ */
+void gpio_irq_disable(rt_uint32_t irq);
+
+/**
+ * it configures the interrupt type to be
+ * falling-edge or active-low sensitive
+ * rising-edge or active-high sensitive.
+ * @param gpio GPIO number
+ * @param type interrupt type
+ * @return 0 if OK
+ */
+int gpio_set_irq_type(rt_uint32_t gpio, rt_uint32_t type);
+
+/**
+ * mask the interrupt
+ * @param gpio GPIO number
+ * @return 0 if OK
+ */
+int gpio_irq_mask(rt_uint32_t irq);
+
+/**
+ * unmask the interrupt
+ * @param gpio GPIO number
+ * @return 0 if OK
+ */
+int gpio_irq_unmask(rt_uint32_t irq);
+
+/**
+ * get corresponding GPIO's direction
+ * @param gpio GPIO number
+ * @return 0 - input
+ *         1 - output
+ */
+int gpio_get_direction(rt_uint32_t gpio);
+
+/**
+ * set corresponding GPIO's direction
+ * @param gpio GPIO number
+ * @return 0 - input
+ *         1 - output
+ */
+void gpio_set_direction(rt_uint32_t gpio, rt_uint32_t direction);
+
+/**
+ * get corresponding GPIO's value
+ * @param gpio GPIO number
+ * @return GPIO value
+ */
+int gpio_get_value(rt_uint32_t gpio);
+
+/**
+ * set corresponding GPIO's value
+ * @param gpio GPIO number
+ * @param val GPIO value
+ */
+void gpio_set_value(rt_uint32_t gpio, int val);
+
+/**
+ * set corresponding GPIO's direction to input
+ * @param gpio GPIO number
+ * @return 0 if OK
+ */
+int gpio_direction_input(rt_uint32_t gpio);
+
+/**
+ * set corresponding GPIO's value and set direction to output
+ * @param gpio GPIO number
+ * @param val GPIO value
+ * @return 0 if OK
+ */
+int gpio_direction_output(rt_uint32_t gpio, rt_uint32_t val);
+
+/**
+ * request a GPIO
+ * @param gpio GPIO number
+ * @return 0 if OK
+ */
+int gpio_request(rt_uint32_t gpio);
+
+/**
+ * release a GPIO
+ * @param gpio GPIO number
+ * @return 0 if OK
+ */
+int gpio_release(rt_uint32_t gpio);
+
+/**
+ * initialize GPIO driver
+ */
+void rt_hw_gpio_init(void);
+
+#endif /* GPIO_H_ */

+ 520 - 0
bsp/fh8620/drivers/i2c.c

@@ -0,0 +1,520 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#include <rtdevice.h>
+#include <rthw.h>
+#include "i2c.h"
+#include "inc/fh_driverlib.h"
+#include "board_info.h"
+
+//#define FH_I2C_DEBUG
+
+#ifdef FH_I2C_DEBUG
+#define PRINT_I2C_DBG(fmt, args...)     \
+    do                                  \
+    {                                   \
+        rt_kprintf("FH_I2C_DEBUG: ");   \
+        rt_kprintf(fmt, ## args);       \
+    }                                   \
+    while(0)
+#else
+#define PRINT_I2C_DBG(fmt, args...)  do { } while (0)
+#endif
+
+
+
+static void fh_i2c_xfer_init(struct rt_i2c_bus_device *dev, struct rt_i2c_msg msgs[], rt_uint32_t num)
+{
+    struct i2c_driver *i2c_drv = (struct i2c_driver *)dev->priv;
+    struct fh_i2c_obj *i2c_obj = (struct fh_i2c_obj *)i2c_drv->priv;
+	rt_uint32_t ic_con;
+
+	/* if the slave address is ten bit address, ERROR*/
+    if (msgs[i2c_drv->msg_write_idx].flags & I2C_M_TEN)
+    {
+        rt_kprintf("ERROR: %s, ten bit address is NOT supported\n", __func__);
+        return;
+    }
+
+	/* Disable the adapter */
+	I2C_WaitMasterIdle(i2c_obj);
+
+	I2C_Enable(i2c_obj, RT_FALSE);
+
+	/* set the slave (target) address */
+	I2C_SetSlaveAddress(i2c_obj, msgs[i2c_drv->msg_write_idx].addr);
+
+	/* Enable interrupts */
+	I2C_SetInterruptMask(i2c_obj, DW_IC_INTR_DEFAULT_MASK);
+
+    /* Enable the adapter */
+    I2C_Enable(i2c_obj, RT_TRUE);
+}
+
+
+static rt_size_t fh_i2c_xfer(struct rt_i2c_bus_device *dev,
+		struct rt_i2c_msg msgs[], rt_uint32_t num)
+{
+    struct i2c_driver *i2c_drv = (struct i2c_driver *)dev->priv;
+    struct fh_i2c_obj *i2c_obj = (struct fh_i2c_obj *)i2c_drv->priv;
+    int ret;
+	struct rt_i2c_msg *pmsg = RT_NULL;
+
+	PRINT_I2C_DBG(">>>>>>>>>>>>>%s start\n", __func__);
+
+    rt_completion_init(&i2c_drv->transfer_completion);
+
+	ret = rt_mutex_take(i2c_drv->lock, RT_WAITING_FOREVER );
+
+	i2c_drv->msgs = msgs;
+	i2c_drv->msgs_num = num;
+	i2c_drv->msg_read_idx = 0;
+	i2c_drv->msg_write_idx = 0;
+	i2c_drv->cmd_err = 0;
+	i2c_drv->msg_err = 0;
+	i2c_drv->status = STATUS_IDLE;
+	i2c_obj->abort_source = 0;
+
+    ret = I2C_WaitDeviceIdle(i2c_obj);
+    if (ret < 0)
+    {
+        //I2C_SetDataCmd(i2c_obj, 0x200);
+        //goto done;
+    }
+
+	fh_i2c_xfer_init(dev, msgs, num);
+
+	ret = rt_completion_wait(&i2c_drv->transfer_completion, RT_TICK_PER_SECOND);
+	PRINT_I2C_DBG("%s transfer finished\n", "rt_completion_wait");
+    if(ret)
+	{
+        rt_kprintf("ERROR: %s, transfer timeout\n", __func__);
+        I2C_SetDataCmd(i2c_obj, 0x200);
+        I2C_Init(i2c_obj);
+		ret = -RT_ETIMEOUT;
+		goto done;
+	}
+
+	if (i2c_drv->msg_err)
+	{
+		rt_kprintf("i2c_priv->msg_err: %d\n", i2c_drv->msg_err);
+		ret = i2c_drv->msg_err;
+		goto done;
+	}
+
+	/* no error */
+	if (!i2c_drv->cmd_err)
+	{
+		/* Disable the adapter */
+	    I2C_WaitMasterIdle(i2c_obj);
+	    I2C_Enable(i2c_obj, RT_FALSE);
+		ret = num;
+		goto done;
+	}
+
+	/* We have an error */
+	if (i2c_drv->cmd_err == DW_IC_ERR_TX_ABRT)
+	{
+		rt_kprintf("ERROR: %s, i2c_priv>cmd_err == DW_IC_ERR_TX_ABRT\n", __func__);
+		ret = I2C_HandleTxAbort(i2c_obj);
+		goto done;
+	}
+
+	ret = 1;
+
+done:
+    I2C_Enable(i2c_obj, RT_FALSE);
+    rt_mutex_release(i2c_drv->lock);
+    PRINT_I2C_DBG(">>>>>>>>>>>>>%s end\n", __func__);
+	return ret;
+
+}
+
+
+/*
+ * Initiate (and continue) low level master read/write transaction.
+ * This function is only called from i2c_fh_isr, and pumping i2c_msg
+ * messages into the tx buffer.  Even if the size of i2c_msg data is
+ * longer than the size of the tx buffer, it handles everything.
+ */
+static void i2c_fh_xfer_msg(struct rt_i2c_bus_device *dev)
+{
+    struct i2c_driver *i2c_drv = (struct i2c_driver *)dev->priv;
+    struct fh_i2c_obj *i2c_obj = (struct fh_i2c_obj *)i2c_drv->priv;
+	struct rt_i2c_msg *msgs = i2c_drv->msgs;
+	rt_uint32_t intr_mask, cmd;
+	int tx_limit, rx_limit;
+	rt_uint32_t addr = msgs[i2c_drv->msg_write_idx].addr;
+	rt_uint32_t buf_len = i2c_drv->tx_buf_len;
+	rt_uint8_t *buf = i2c_drv->tx_buf;
+
+	PRINT_I2C_DBG("%s start, msgs_num: %d, write_idx: %d\n", __func__, i2c_drv->msgs_num, i2c_drv->msg_write_idx);
+
+	intr_mask = DW_IC_INTR_DEFAULT_MASK;
+
+	for (; i2c_drv->msg_write_idx < i2c_drv->msgs_num; i2c_drv->msg_write_idx++)
+	{
+		/*
+		 * if target address has changed, we need to
+		 * reprogram the target address in the i2c
+		 * adapter when we are done with this transfer
+		 */
+		if (msgs[i2c_drv->msg_write_idx].addr != addr) {
+			rt_kprintf(
+					"ERROR: %s, invalid target address\n", __func__);
+			i2c_drv->msg_err = 1;
+			break;
+		}
+
+		if (msgs[i2c_drv->msg_write_idx].len == 0) {
+			rt_kprintf(
+					"ERROR: %s, invalid message length\n", __func__);
+			i2c_drv->msg_err = 1;
+			break;
+		}
+
+		if (!(i2c_drv->status & STATUS_WRITE_IN_PROGRESS))
+		{
+			/* new i2c_msg */
+			buf = msgs[i2c_drv->msg_write_idx].buf;
+			buf_len = msgs[i2c_drv->msg_write_idx].len;
+
+			PRINT_I2C_DBG("new msg: len: %d, buf: 0x%x\n", buf_len, buf[0]);
+		}
+
+		tx_limit = i2c_obj->config.tx_fifo_depth - I2C_GetTransmitFifoLevel(i2c_obj);
+		rx_limit = i2c_obj->config.rx_fifo_depth - I2C_GetReceiveFifoLevel(i2c_obj);
+
+		while (buf_len > 0 && tx_limit > 0 && rx_limit > 0)
+		{
+			if (msgs[i2c_drv->msg_write_idx].flags & RT_I2C_RD)
+			{
+				cmd = 0x100;
+				rx_limit--;
+			}
+			else
+			{
+				cmd = *buf++;
+			}
+
+			tx_limit--; buf_len--;
+
+			if(!buf_len)
+			{
+			    //2015-11-8 ar0130 bug fixed
+			    while(I2C_GetTransmitFifoLevel(i2c_obj));
+			    cmd |= 0x200;
+			}
+
+			I2C_SetDataCmd(i2c_obj, cmd);
+		}
+
+		i2c_drv->tx_buf = buf;
+		i2c_drv->tx_buf_len = buf_len;
+
+		if (buf_len > 0)
+		{
+			/* more bytes to be written */
+		    i2c_drv->status |= STATUS_WRITE_IN_PROGRESS;
+			break;
+		}
+		else
+		{
+		    i2c_drv->status &= ~STATUS_WRITE_IN_PROGRESS;
+		}
+	}
+
+	/*
+	 * If i2c_msg index search is completed, we don't need TX_EMPTY
+	 * interrupt any more.
+	 */
+
+	if (i2c_drv->msg_write_idx == i2c_drv->msgs_num)
+	    intr_mask &= ~DW_IC_INTR_TX_EMPTY;
+
+	if (i2c_drv->msg_err)
+	{
+	    rt_kprintf("ERROR: %s, msg_err: %d\n", __func__, i2c_drv->msg_err);
+	    intr_mask = 0;
+	}
+
+	I2C_SetInterruptMask(i2c_obj, intr_mask);
+
+	PRINT_I2C_DBG("%s end\n", __func__);
+}
+
+static void i2c_fh_read(struct rt_i2c_bus_device *dev)
+{
+	struct i2c_driver *i2c_drv = (struct i2c_driver *)dev->priv;
+	struct fh_i2c_obj *i2c_obj = (struct fh_i2c_obj *)i2c_drv->priv;
+	struct rt_i2c_msg *msgs = i2c_drv->msgs;
+	int rx_valid;
+
+	PRINT_I2C_DBG("%s start, msgs_num: %d, read_idx: %d\n", __func__, i2c_drv->msgs_num, i2c_drv->msg_read_idx);
+
+	for (; i2c_drv->msg_read_idx < i2c_drv->msgs_num; i2c_drv->msg_read_idx++)
+	{
+		rt_uint32_t len;
+		rt_uint8_t *buf;
+
+		if (!(msgs[i2c_drv->msg_read_idx].flags & RT_I2C_RD))
+		    continue;
+
+		if (!(i2c_drv->status & STATUS_READ_IN_PROGRESS))
+		{
+			len = msgs[i2c_drv->msg_read_idx].len;
+			buf = msgs[i2c_drv->msg_read_idx].buf;
+		}
+		else
+		{
+		    PRINT_I2C_DBG("STATUS_READ_IN_PROGRESS\n");
+			len = i2c_drv->rx_buf_len;
+			buf = i2c_drv->rx_buf;
+		}
+
+		rx_valid = I2C_GetReceiveFifoLevel(i2c_obj);
+
+		if(rx_valid == 0)
+		{
+			rt_kprintf("ERROR: %s, rx_valid == 0\n", __func__);
+		}
+		PRINT_I2C_DBG("%s, len=%d, rx_valid=%d\n", __func__, len, rx_valid);
+		for (; len > 0 && rx_valid > 0; len--, rx_valid--)
+		{
+			*buf++ = I2C_GetData(i2c_obj);
+		}
+
+		PRINT_I2C_DBG("i2c_fh_read, len: %d, buf[0]: 0x%x\n", msgs[i2c_drv->msg_read_idx].len, msgs[i2c_drv->msg_read_idx].buf[0]);
+
+		if (len > 0)
+		{
+		    PRINT_I2C_DBG("len > 0\n");
+			i2c_drv->status |= STATUS_READ_IN_PROGRESS;
+			i2c_drv->rx_buf_len = len;
+			i2c_drv->rx_buf = buf;
+			return;
+		}
+		else
+		    i2c_drv->status &= ~STATUS_READ_IN_PROGRESS;
+	}
+
+	PRINT_I2C_DBG("%s end\n", __func__);
+}
+
+/*
+ * Interrupt service routine. This gets called whenever an I2C interrupt
+ * occurs.
+ */
+static void fh_i2c_interrupt(int this_irq, void *dev_id)
+{
+    struct i2c_driver *i2c_drv = dev_id;
+    struct rt_i2c_bus_device *i2c_bus_dev = i2c_drv->i2c_bus_dev;
+    struct fh_i2c_obj *i2c_obj = (struct fh_i2c_obj *)i2c_drv->priv;
+	rt_uint32_t stat;
+
+	stat = I2C_ClearAndGetInterrupts(i2c_obj);
+	PRINT_I2C_DBG("status: 0x%x, mask: 0x%x\n", stat, I2C_GetInterruptMask(i2c_obj));
+
+	if (stat & DW_IC_INTR_TX_ABRT)
+	{
+	    PRINT_I2C_DBG("DW_IC_INTR_TX_ABRT\n");
+		i2c_drv->cmd_err |= DW_IC_ERR_TX_ABRT;
+		i2c_drv->status = STATUS_IDLE;
+
+		/*
+		 * Anytime TX_ABRT is set, the contents of the tx/rx
+		 * buffers are flushed.  Make sure to skip them.
+		 */
+		I2C_SetInterruptMask(i2c_obj, 0);
+		goto tx_aborted;
+	}
+
+	if (stat & DW_IC_INTR_RX_FULL)
+	{
+		i2c_fh_read(i2c_bus_dev);
+	}
+
+	if (stat & DW_IC_INTR_TX_EMPTY)
+	{
+		i2c_fh_xfer_msg(i2c_bus_dev);
+	}
+
+	/*
+	 * No need to modify or disable the interrupt mask here.
+	 * i2c_fh_xfer_msg() will take care of it according to
+	 * the current transmit status.
+	 */
+
+tx_aborted:
+	if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || i2c_drv->msg_err)
+	    rt_completion_done(&i2c_drv->transfer_completion);
+
+}
+
+static const struct rt_i2c_bus_device_ops fh_i2c_ops =
+{
+    .master_xfer = fh_i2c_xfer,
+};
+
+int fh_i2c_probe(void *priv_data)
+{
+    int ret;
+    struct i2c_driver *i2c_drv;
+    struct rt_i2c_bus_device *i2c_bus_dev;
+    struct fh_i2c_obj *i2c_obj = (struct fh_i2c_obj *)priv_data;
+    char i2c_dev_name[5] = {0};
+
+    PRINT_I2C_DBG("%s start\n", __func__);
+
+    i2c_bus_dev = (struct rt_i2c_bus_device*)rt_malloc(sizeof(struct rt_i2c_bus_device));
+    rt_memset(i2c_bus_dev, 0, sizeof(struct rt_i2c_bus_device));
+    i2c_bus_dev->ops = &fh_i2c_ops;
+
+    rt_sprintf(i2c_dev_name, "%s%d", "i2c", i2c_obj->id);
+    ret = rt_i2c_bus_device_register(i2c_bus_dev, i2c_dev_name);
+
+    if (ret != RT_EOK)
+    {
+        rt_kprintf("ERROR:rt_spi_bus_register failed, ret=%d\n", ret);
+        return -RT_ENOMEM;
+    }
+
+    //priv struct init
+    i2c_drv = (struct i2c_driver*)rt_malloc(sizeof(struct i2c_driver));
+    rt_memset(i2c_drv, 0, sizeof(struct i2c_driver));
+
+    i2c_drv->i2c_bus_dev = i2c_bus_dev;
+    i2c_drv->priv = priv_data;
+    i2c_bus_dev->priv = i2c_drv;
+
+    i2c_drv->lock = rt_mutex_create("i2c_mux", RT_IPC_FLAG_FIFO);
+    if(i2c_obj->id == 0){
+        rt_hw_interrupt_install(i2c_obj->irq, fh_i2c_interrupt,
+                                (void *)i2c_drv, "i2c_0");
+    }
+    else if(i2c_obj->id == 1){
+        rt_hw_interrupt_install(i2c_obj->irq, fh_i2c_interrupt,
+                                (void *)i2c_drv, "i2c_1");
+    }
+
+    rt_hw_interrupt_umask(i2c_obj->irq);
+
+    //fixme: get from clk tree
+    i2c_obj->input_clock = 15000;
+
+    I2C_Init(i2c_obj);
+
+    PRINT_I2C_DBG("%s end\n", __func__);
+    return ret;
+
+}
+
+int fh_i2c_exit(void *priv_data)
+{
+    return 0;
+}
+
+struct fh_board_ops i2c_driver_ops =
+{
+    .probe = fh_i2c_probe,
+    .exit = fh_i2c_exit,
+};
+
+void rt_hw_i2c_init(void)
+{
+    int ret;
+
+    PRINT_I2C_DBG("%s start\n", __func__);
+    fh_board_driver_register("i2c", &i2c_driver_ops);
+    PRINT_I2C_DBG("%s end\n", __func__);
+    //fixme: never release?
+}
+
+static rt_err_t fh_i2c_read_reg(struct rt_i2c_bus_device *fh81_i2c,
+		rt_uint16_t reg, rt_uint8_t *data) {
+	struct rt_i2c_msg msg[2];
+	rt_uint8_t send_buf[2];
+	rt_uint8_t recv_buf[1] = {0};
+
+	PRINT_I2C_DBG("%s start\n", __func__);
+
+	//  send_buf[0] = ((reg >> 8) & 0xff);
+	send_buf[0] = (reg & 0xFF);
+
+	msg[0].addr = 0x51;
+	msg[0].flags = RT_I2C_WR;
+	msg[0].len = 1;
+	msg[0].buf = send_buf;
+
+	msg[1].addr = 0x51;
+	msg[1].flags = RT_I2C_RD;
+	msg[1].len = 1;
+	msg[1].buf = recv_buf;
+
+	rt_i2c_transfer(fh81_i2c, msg, 2);
+	*data = recv_buf[0];
+	return RT_EOK;
+}
+static rt_err_t fh_i2c_write_reg(struct rt_i2c_bus_device *fh81_i2c,
+		rt_uint16_t reg, rt_uint8_t data) {
+	struct rt_i2c_msg msg;
+	rt_uint8_t send_buf[3];
+
+	PRINT_I2C_DBG("%s start\n", __func__);
+
+	// send_buf[0] = ((reg >> 8) & 0xff);
+	send_buf[1] = (reg & 0xFF);
+	send_buf[2] = data;
+
+	msg.addr = 0x51;
+	msg.flags = RT_I2C_WR;
+	msg.len = 2;
+	msg.buf = send_buf;
+
+	rt_i2c_transfer(fh81_i2c, &msg, 1);
+	PRINT_I2C_DBG("%s end\n", __func__);
+	return RT_EOK;
+}
+
+void i2c_test_sensor() {
+	struct rt_i2c_bus_device *fh81_i2c;
+	struct rt_i2c_msg msg[2];
+	rt_uint8_t data[1] = { 0x00 };
+
+	fh81_i2c = rt_i2c_bus_device_find("i2c1");
+
+	fh_i2c_write_reg(fh81_i2c, 0x04, 0x02);
+
+	fh_i2c_read_reg(fh81_i2c, 0x02, data);
+
+	rt_kprintf("data read from 0x3038 is 0x%x\r\n", data[0]);
+	PRINT_I2C_DBG("%s end\n", __func__);
+}
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+FINSH_FUNCTION_EXPORT(i2c_test_sensor, sensor i2c test);
+#endif
+

+ 56 - 0
bsp/fh8620/drivers/i2c.h

@@ -0,0 +1,56 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#ifndef __FH81_I2C_H__
+#define __FH81_I2C_H__
+
+
+#include <rtthread.h>
+
+struct i2c_driver
+{
+    int cmd_err;
+    int msg_err;
+    rt_uint32_t status;
+
+    struct rt_i2c_msg *msgs;
+    int msgs_num;
+    int msg_write_idx;
+    rt_uint32_t tx_buf_len;
+    rt_uint8_t *tx_buf;
+    int msg_read_idx;
+    rt_uint32_t rx_buf_len;
+    rt_uint8_t *rx_buf;
+
+    struct rt_i2c_bus_device *i2c_bus_dev;
+    struct rt_completion transfer_completion;
+    rt_mutex_t lock;
+    void*  priv;
+};
+
+void rt_hw_i2c_init(void);
+
+#endif

+ 216 - 0
bsp/fh8620/drivers/interrupt.c

@@ -0,0 +1,216 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+/*****************************************************************************
+ *  Include Section
+ *  add all #include here
+ *****************************************************************************/
+
+#include "interrupt.h"
+#include "fh_def.h"
+#include "fh_arch.h"
+#include "Libraries/inc/fh_ictl.h"
+
+/*****************************************************************************
+ * Define section
+ * add all #define here
+ *****************************************************************************/
+#define MAX_HANDLERS    (NR_INTERNAL_IRQS+NR_EXTERNAL_IRQS)
+
+
+/****************************************************************************
+ * ADT section
+ *  add definition of user defined Data Type that only be used in this file  here
+ ***************************************************************************/
+
+/******************************************************************************
+ * Function prototype section
+ * add prototypes for all functions called by this file,execepting those
+ * declared in header file
+ *****************************************************************************/
+
+
+
+/*****************************************************************************
+ * Global variables section - Exported
+ * add declaration of global variables that will be exported here
+ * e.g.
+ *  int8_t foo;
+ ****************************************************************************/
+extern rt_uint32_t rt_interrupt_nest;
+struct rt_irq_desc irq_desc[MAX_HANDLERS];
+rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
+rt_uint32_t rt_thread_switch_interrupt_flag;
+/*****************************************************************************
+ * Global variables section - Local
+ * define global variables(will be refered only in this file) here,
+ * static keyword should be used to limit scope of local variable to this file
+ * e.g.
+ *  static uint8_t ufoo;
+ *****************************************************************************/
+
+
+
+ /* function body */
+
+
+
+
+
+
+/*****************************************************************************
+ * Description:
+ *      add funtion description here
+ * Parameters:
+ *      description for each argument, new argument starts at new line
+ * Return:
+ *      what does this function returned?
+ *****************************************************************************/
+rt_isr_handler_t rt_hw_interrupt_handle(rt_uint32_t vector, void *param)
+{
+    rt_kprintf("Unhandled interrupt %d occured!!!\n", vector);
+    return RT_NULL;
+}
+
+
+
+
+/**
+ * This function will initialize hardware interrupt
+ */
+void rt_hw_interrupt_init(void)
+{
+    rt_int32_t i;
+    register rt_uint32_t idx;
+	fh_intc *p = (fh_intc *)INTC_REG_BASE;
+
+
+	ictl_close_all_isr(p);
+    /* init exceptions table */
+    for(idx=0; idx < MAX_HANDLERS; idx++)
+    {
+
+        irq_desc[idx].handler = (rt_isr_handler_t)rt_hw_interrupt_handle;
+        irq_desc[idx].param = RT_NULL;
+#ifdef RT_USING_INTERRUPT_INFO
+        rt_snprintf(irq_desc[idx].name, RT_NAME_MAX - 1, "default");
+        irq_desc[idx].counter = 0;
+#endif
+
+    }
+
+    /* init interrupt nest, and context in thread sp */
+    rt_interrupt_nest = 0;
+    rt_interrupt_from_thread = 0;
+    rt_interrupt_to_thread = 0;
+    rt_thread_switch_interrupt_flag = 0;
+
+}
+
+/**
+ * This function will mask a interrupt.
+ * @param vector the interrupt number
+ */
+void rt_hw_interrupt_mask(int irq)
+{
+
+	fh_intc *p = (fh_intc *)INTC_REG_BASE;
+    /* Disable irq on AIC */
+	ictl_mask_isr(p,irq);
+
+//	if (irq < 32)
+//    	p->IRQ_EN_L &= ~(1 << irq);
+//	else
+//		p->IRQ_EN_H &= ~(1 << (irq - 32));
+}
+
+
+void rt_hw_interrupt_umask(int irq)
+{
+
+	fh_intc *p = (fh_intc *)INTC_REG_BASE;
+    /* Enable irq on AIC */
+	ictl_unmask_isr(p,irq);
+//    if (irq < 32)
+//    	p->IRQ_EN_L |= 1 << irq;
+//	else
+//		p->IRQ_EN_H |= 1 << (irq - 32);
+}
+
+/**
+ * This function will install a interrupt service routine to a interrupt.
+ * @param vector the interrupt number
+ * @param handler the interrupt service routine to be installed
+ * @param param the interrupt service function parameter
+ * @param name the interrupt name
+ * @return old handler
+ */
+rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, 
+                                    void *param, char *name)
+{
+    rt_isr_handler_t old_handler = RT_NULL;
+
+    if(vector < MAX_HANDLERS)
+    {
+        old_handler = irq_desc[vector].handler;
+        if (handler != RT_NULL)
+        {
+            irq_desc[vector].handler = (rt_isr_handler_t)handler;
+            irq_desc[vector].param = param;
+#ifdef RT_USING_INTERRUPT_INFO
+            rt_snprintf(irq_desc[vector].name, RT_NAME_MAX - 1, "%s", name);
+			irq_desc[vector].counter = 0;
+#endif
+        }
+    }
+
+    return old_handler;
+}
+
+#ifdef RT_USING_FINSH
+void list_irq(void)
+{
+
+#ifdef RT_USING_INTERRUPT_INFO
+	int irq;
+    rt_kprintf("number\tcount\tname\n");
+    for (irq = 0; irq < MAX_HANDLERS; irq++)
+    {
+        if (rt_strncmp(irq_desc[irq].name, "default", sizeof("default")))
+        {
+            rt_kprintf("%02ld: %10ld  %s\n", irq, irq_desc[irq].counter, irq_desc[irq].name);
+        }
+    }
+#else
+    rt_kprintf("please open 'RT_USING_INTERRUPT_INFO'\n");
+
+#endif
+}
+#include <finsh.h>
+FINSH_FUNCTION_EXPORT(list_irq, list system irq);
+
+#endif
+

+ 40 - 0
bsp/fh8620/drivers/interrupt.h

@@ -0,0 +1,40 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#ifndef INTERRUPT_H_
+#define INTERRUPT_H_
+#include <rthw.h>
+
+#define NR_INTERNAL_IRQS 56
+#define NR_EXTERNAL_IRQS 64
+
+void rt_hw_interrupt_init(void);
+void rt_hw_interrupt_mask(int irq);
+void rt_hw_interrupt_umask(int irq);
+rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
+		void *param, char *name);
+
+#endif /* INTERRUPT_H_ */

+ 87 - 0
bsp/fh8620/drivers/mem_process.c

@@ -0,0 +1,87 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include <rtthread.h>
+#include <rtdevice.h>
+#include "mmu.h"
+
+#define CHANGLINE_SIZE		(1)
+
+//#define FH_DBG_MEM_PROCESS
+
+#ifdef FH_DBG_MEM_PROCESS
+void mem_input(rt_uint32_t t_addr, rt_uint32_t t_size, rt_uint8_t t_value) {
+
+	rt_kprintf("mem process add:%x \tsize:%x\tvalue:%x\n", t_addr, t_size,
+			t_value);
+
+	rt_memset((void *) t_addr, t_value, t_size);
+
+	mmu_clean_invalidated_dcache(t_addr, t_size);
+
+}
+
+void mem_output(rt_uint32_t t_addr, rt_uint32_t t_size) {
+
+	rt_uint32_t i;
+	rt_uint32_t cnt = 0;
+	rt_uint32_t value;
+	rt_uint32_t addr, size;
+
+	addr = t_addr;
+	if (t_size % 4) {
+		rt_kprintf("mem must be alligned\n");
+	}
+	size = t_size / 4;
+	rt_int32_t *p = (rt_uint32_t *) t_addr;
+
+	//mmu_clean_invalidated_dcache(addr,t_size);
+	rt_kprintf("mem process add:0x%x \tsize:0x%x\n", addr, t_size);
+	rt_kprintf("0x%08x:", addr);
+	for (i = 0; i < size; i++) {
+		value = *p++;
+		if ((cnt / CHANGLINE_SIZE) && (cnt % CHANGLINE_SIZE == 0)) {
+			rt_kprintf("\n");
+		}
+		if (cnt / CHANGLINE_SIZE && (cnt % CHANGLINE_SIZE) == 0) {
+			rt_kprintf("0x%08x:", addr + i * 4);
+		}
+		rt_kprintf("\t%08x", value);
+		cnt++;
+
+	}
+	rt_kprintf("\n");
+
+}
+#endif
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+#ifdef FH_DBG_MEM_PROCESS
+FINSH_FUNCTION_EXPORT(mem_input, mem_input(addr,size,value));
+FINSH_FUNCTION_EXPORT(mem_output, mem_output(add,size));
+#endif
+#endif

+ 710 - 0
bsp/fh8620/drivers/mmc.c

@@ -0,0 +1,710 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "board_info.h"
+#include <rtdef.h>
+#include <rtdevice.h>
+#include <drivers/mmcsd_core.h>
+#include "mmc.h"
+
+//#define FH_MMC_DEBUG
+#define MMC_USE_INTERNAL_BUF
+
+#ifdef FH_MMC_DEBUG
+#define PRINT_MMC_DBG(fmt, args...)     \
+    do                                  \
+    {                                   \
+        rt_kprintf("FH_MMC_DEBUG: tick-%d, ", rt_tick_get());   \
+        rt_kprintf(fmt, ## args);       \
+    }                                   \
+    while(0)
+#else
+#define PRINT_MMC_DBG(fmt, args...)  do { } while (0)
+#endif
+
+#define PRINT_MMC_REGS(base)                                        \
+    do                                                              \
+    {                                                               \
+        int i_for_marco;                                            \
+        rt_uint32_t addr;                                           \
+        for(i_for_marco=0; i_for_marco<20; i_for_marco++)           \
+        {                                                           \
+            addr = base + i_for_marco*4*4;                          \
+            rt_kprintf("0x%x: 0x%x, 0x%x, 0x%x, 0x%x\n", addr,      \
+                    GET_REG(addr+0x0),                              \
+                    GET_REG(addr+0x4),                              \
+                    GET_REG(addr+0x8),                              \
+                    GET_REG(addr+0xc));                             \
+        }                                                           \
+    }                                                               \
+    while(0)
+
+
+#define MMC_INTERNAL_DMA_BUF_SIZE (32*1024)
+static rt_uint32_t *g_mmc_dma_buf;
+
+static int fh_mmc_write_pio(struct mmc_driver *mmc_drv)
+{
+    struct fh_mmc_obj *mmc_obj = (struct fh_mmc_obj *)mmc_drv->priv;
+    struct rt_mmcsd_cmd *cmd = mmc_drv->cmd;
+    struct rt_mmcsd_data *data = RT_NULL;
+    rt_uint32_t size;
+
+    if(cmd)
+        data = cmd->data;
+
+    if(!data)
+    {
+        rt_kprintf("ERROR: %s, data is NULL\n", __func__);
+        return -RT_EIO;
+    }
+
+    size = data->blks * data->blksize;
+    PRINT_MMC_DBG("%s, Send %d bytes\n", __func__, size);
+    MMC_WriteData(mmc_obj, data->buf, size);
+    MMC_ResetFifo(mmc_obj);
+
+    return 0;
+}
+
+static int fh_mmc_read_pio(struct mmc_driver *mmc_drv)
+{
+    struct fh_mmc_obj *mmc_obj = (struct fh_mmc_obj *)mmc_drv->priv;
+    struct rt_mmcsd_cmd *cmd = mmc_drv->cmd;
+    struct rt_mmcsd_data *data = RT_NULL;
+    rt_uint32_t size;
+    int ret;
+
+    if(cmd)
+        data = cmd->data;
+
+    if(!data)
+    {
+        rt_kprintf("ERROR: %s, data is NULL\n", __func__);
+        return -RT_EIO;
+    }
+
+    size = data->blks * data->blksize;
+    PRINT_MMC_DBG("%s, read %d bytes\n", __func__, size);
+    ret = MMC_ReadData(mmc_obj, data->buf, size);
+    if(ret)
+    {
+        rt_kprintf("ERROR: %s, fifo IO error, ret: %d\n", __func__, ret);
+        return -RT_EIO;
+    }
+
+    MMC_ResetFifo(mmc_obj);
+
+    return 0;
+}
+
+
+static void fh_mmc_set_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
+{
+    rt_uint32_t clkdiv;
+    struct mmc_driver *mmc_drv = host->private_data;
+    struct fh_mmc_obj *mmc_obj = (struct fh_mmc_obj *)mmc_drv->priv;
+
+    PRINT_MMC_DBG("%s start\n", __func__);
+
+    //fixme: read from PMU
+    //why io_cfg->clock == 0 ?
+    if(io_cfg->clock)
+    {
+        clkdiv = MMC_CLOCK_IN / io_cfg->clock / 2;
+        MMC_UpdateClockRegister(mmc_obj, clkdiv);
+        PRINT_MMC_DBG("io_cfg->clock: %lu, clock in: %lu, clkdiv: %d\n", io_cfg->clock, MMC_CLOCK_IN, clkdiv);
+    }
+
+    if (io_cfg->bus_width == MMCSD_BUS_WIDTH_4)
+    {
+        MMC_SetCardWidth(mmc_obj, MMC_CARD_WIDTH_4BIT);
+        PRINT_MMC_DBG("set to 4-bit mode\n", MMC_CLOCK_IN, clkdiv);
+    }
+    else
+    {
+        MMC_SetCardWidth(mmc_obj, MMC_CARD_WIDTH_1BIT);
+        PRINT_MMC_DBG("set to 1-bit mode\n", MMC_CLOCK_IN, clkdiv);
+    }
+
+
+    /* maybe switch power to the card */
+    switch (io_cfg->power_mode)
+    {
+        case MMCSD_POWER_OFF:
+            break;
+        case MMCSD_POWER_UP:
+            break;
+        case MMCSD_POWER_ON:
+            break;
+        default:
+            rt_kprintf("ERROR: %s, unknown power_mode %d\n", __func__, io_cfg->power_mode);
+            break;
+    }
+    PRINT_MMC_DBG("%s end\n", __func__);
+}
+
+static void fh_mmc_enable_sdio_irq(struct rt_mmcsd_host *host, rt_int32_t enable)
+{
+    struct mmc_driver *mmc_drv = host->private_data;
+    struct fh_mmc_obj *mmc_obj = (struct fh_mmc_obj *)mmc_drv->priv;
+    rt_uint32_t reg;
+
+    PRINT_MMC_DBG("%s start\n", __func__);
+
+    if (enable)
+    {
+        MMC_ClearRawInterrupt(mmc_obj, MMC_INT_STATUS_SDIO);
+        reg = MMC_GetInterruptMask(mmc_obj);
+        reg |= MMC_INT_STATUS_SDIO;
+        MMC_SetInterruptMask(mmc_obj, reg);
+    }
+    else
+    {
+        reg = MMC_GetInterruptMask(mmc_obj);
+        reg &= ~MMC_INT_STATUS_SDIO;
+        MMC_SetInterruptMask(mmc_obj, reg);
+    }
+
+}
+
+static rt_int32_t fh_mmc_get_card_status(struct rt_mmcsd_host *host)
+{
+    PRINT_MMC_DBG("%s, start\n", __func__);
+    PRINT_MMC_DBG("%s, end\n", __func__);
+    return 0;
+}
+
+static void fh_mmc_send_command(struct mmc_driver *mmc_drv, struct rt_mmcsd_cmd *cmd)
+{
+    struct fh_mmc_obj *mmc_obj = (struct fh_mmc_obj *)mmc_drv->priv;
+    struct rt_mmcsd_host *host = mmc_drv->host;
+    struct rt_mmcsd_req *req = mmc_drv->req;
+    //fixme: cmd->data or req->data
+    struct rt_mmcsd_data *data = cmd->data;
+    int ret;
+
+    rt_uint32_t retries = 0;
+    rt_uint32_t cmd_flags = 0;
+
+    PRINT_MMC_DBG("%s, start\n", __func__);
+
+    if (!cmd)
+    {
+        //fixme: stop dma
+        rt_kprintf("ERROR: %s, cmd is NULL\n", __func__);
+        return;
+    }
+
+    if (data)
+    {
+        cmd_flags |= MMC_CMD_FLAG_DATA_EXPECTED;
+        /* always set data start - also set direction flag for read */
+        if (data->flags & DATA_DIR_WRITE)
+            cmd_flags |= MMC_CMD_FLAG_WRITE_TO_CARD;
+
+        if (data->flags & DATA_STREAM)
+            cmd_flags |= MMC_CMD_FLAG_DATA_STREAM;
+    }
+
+    if (cmd == req->stop)
+        cmd_flags |= MMC_CMD_FLAG_STOP_TRANSFER;
+    else
+        cmd_flags |= MMC_CMD_FLAG_WAIT_PREV_DATA;
+
+    switch (resp_type(cmd))
+    {
+        case RESP_NONE:
+            break;
+        case RESP_R1:
+        case RESP_R5:
+        case RESP_R6:
+        case RESP_R7:
+        case RESP_R1B:
+            cmd_flags |= MMC_CMD_FLAG_RESPONSE_EXPECTED;
+            cmd_flags |= MMC_CMD_FLAG_CHECK_RESP_CRC;
+            break;
+        case RESP_R2:
+            cmd_flags |= MMC_CMD_FLAG_RESPONSE_EXPECTED;
+            cmd_flags |= MMC_CMD_FLAG_CHECK_RESP_CRC;
+            cmd_flags |= MMC_CMD_FLAG_LONG_RESPONSE;
+            break;
+        case RESP_R3:
+        case RESP_R4:
+            cmd_flags |= MMC_CMD_FLAG_RESPONSE_EXPECTED;
+            break;
+        default:
+            rt_kprintf("ERROR: %s, unknown cmd type %x\n", __func__, resp_type(cmd));
+            return;
+    }
+
+    if (cmd->cmd_code == GO_IDLE_STATE)
+        cmd_flags |= MMC_CMD_FLAG_SEND_INIT;
+
+    /* CMD 11 check switch voltage */
+    if (cmd->cmd_code == READ_DAT_UNTIL_STOP)
+        cmd_flags |= MMC_CMD_FLAG_SWITCH_VOLTAGE;
+
+    PRINT_MMC_DBG("cmd code: %d, args: 0x%x, resp type: 0x%x, flag: 0x%x\n", cmd->cmd_code, cmd->arg, resp_type(cmd), cmd_flags);
+    ret = MMC_SendCommand(mmc_obj, cmd->cmd_code, cmd->arg, cmd_flags);
+
+    if(ret)
+    {
+        rt_kprintf("ERROR: %s, Send command timeout, cmd: %d, status: 0x%x\n", __func__, cmd->cmd_code, MMC_GetStatus(mmc_obj));
+    }
+
+}
+static void fh_mmc_perpare_data(struct mmc_driver *mmc_drv)
+{
+    struct rt_mmcsd_cmd *cmd = mmc_drv->cmd;
+    struct rt_mmcsd_data *data = cmd->data;
+    struct fh_mmc_obj *mmc_obj = (struct fh_mmc_obj *)mmc_drv->priv;
+    rt_uint32_t data_size;
+    int i;
+
+    if(!data)
+    {
+        MMC_SetBlockSize(mmc_obj, 0);
+        MMC_SetByteCount(mmc_obj, 0);
+        return;
+    }
+
+    PRINT_MMC_DBG("%s, start\n", __func__);
+
+    if(MMC_ResetFifo(mmc_obj))
+    {
+        return;
+    }
+
+    data_size = data->blks * data->blksize;
+
+    MMC_SetBlockSize(mmc_obj, data->blksize);
+
+    if(data_size % 4)
+    {
+        rt_kprintf("ERROR: data_size should be a multiple of 4, but now is %d\n", data_size);
+    }
+    MMC_SetByteCount(mmc_obj, data_size);
+
+    PRINT_MMC_DBG("%s, set blk size: 0x%x, byte count: 0x%x\n", __func__, data->blksize, data_size);
+
+    if(data_size > MMC_DMA_DESC_BUFF_SIZE * mmc_drv->max_desc)
+    {
+        rt_kprintf("ERROR: %s, given buffer is too big, size: 0x%x, max: 0x%x\n", __func__, data_size, MMC_DMA_DESC_BUFF_SIZE * mmc_drv->max_desc);
+        return;
+    }
+
+    if (data_size > MMC_INTERNAL_DMA_BUF_SIZE)
+    {
+        rt_kprintf("ERROR: please increase MMC_INTERNAL_DMA_BUF_SIZE.\n");
+        return;
+    }
+
+#ifdef MMC_USE_DMA
+#ifdef MMC_USE_INTERNAL_BUF
+    if (data->flags & DATA_DIR_WRITE)
+    {
+        rt_memcpy(g_mmc_dma_buf, data->buf, data_size);
+        mmu_clean_invalidated_dcache(g_mmc_dma_buf, data_size);
+    }
+    else
+    {
+        mmu_invalidate_dcache(g_mmc_dma_buf, data_size);
+    }
+    MMC_InitDescriptors(mmc_obj, (rt_uint32_t*)g_mmc_dma_buf, data_size);
+    mmu_clean_invalidated_dcache(mmc_obj->descriptors, sizeof(MMC_DMA_Descriptors) * mmc_drv->max_desc);
+    MMC_StartDma(mmc_obj);
+#else
+    MMC_InitDescriptors(mmc_obj, data->buf, data_size);
+    mmu_clean_invalidated_dcache(mmc_obj->descriptors, sizeof(MMC_DMA_Descriptors) * mmc_drv->max_desc);
+    mmu_clean_invalidated_dcache(data->buf, data_size);
+    MMC_StartDma(mmc_obj);
+#endif
+#endif
+    PRINT_MMC_DBG("%s, end\n", __func__);
+}
+
+int fh_mmc_wait_card_idle(struct fh_mmc_obj *mmc_obj)
+{
+    rt_uint32_t tick, timeout;
+
+    tick = rt_tick_get();
+    timeout = tick + RT_TICK_PER_SECOND / 2; //500ms
+
+    while(MMC_GetStatus(mmc_obj) & MMC_STATUS_DATA_BUSY)
+    {
+        tick = rt_tick_get();
+        if(tick > timeout)
+        {
+            return -RT_ETIMEOUT;
+        }
+    }
+
+    return 0;
+}
+
+static int fh_mmc_get_response(struct mmc_driver *mmc_drv, struct rt_mmcsd_cmd *cmd)
+{
+    int i;
+    rt_uint32_t tick, timeout, status;
+    struct fh_mmc_obj *mmc_obj = (struct fh_mmc_obj *)mmc_drv->priv;
+
+    cmd->resp[0] = 0;
+    cmd->resp[1] = 0;
+    cmd->resp[2] = 0;
+    cmd->resp[3] = 0;
+
+    tick = rt_tick_get();
+    timeout = tick + RT_TICK_PER_SECOND / 2; //500ms
+
+    //fixme: spin_lock_irqsave?
+    do
+    {
+        status = MMC_GetRawInterrupt(mmc_obj);
+        tick = rt_tick_get();
+        if(tick > timeout)
+        {
+            PRINT_MMC_DBG("ERROR: %s, get response timeout(cmd is not received by card), RINTSTS: 0x%x, cmd: %d\n", __func__, status, cmd->cmd_code);
+            return -RT_ETIMEOUT;
+        }
+    }
+    while(!(status & MMC_INT_STATUS_CMD_DONE));
+
+    MMC_ClearRawInterrupt(mmc_obj, MMC_INT_STATUS_CMD_DONE);
+
+    for (i = 0; i < 4; i++)
+    {
+        if (resp_type(cmd) == RESP_R2)
+        {
+            cmd->resp[i] = MMC_GetResponse(mmc_obj, 3 - i);
+            //fixme : R2 must delay some time here ,when use UHI card, need check why
+            //1ms
+            //rt_thread_sleep(RT_TICK_PER_SECOND / 100);
+        }
+        else
+        {
+            cmd->resp[i] = MMC_GetResponse(mmc_obj, i);
+        }
+    }
+
+    PRINT_MMC_DBG("resp: 0x%x, 0x%x, 0x%x, 0x%x\n", cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
+
+    if (status & MMC_INT_STATUS_RESPONSE_TIMEOUT)
+    {
+        MMC_ClearRawInterrupt(mmc_obj, MMC_INT_STATUS_RESPONSE_TIMEOUT);
+        PRINT_MMC_DBG("ERROR: %s, get response timeout, RINTSTS: 0x%x\n", __func__, status);
+        return -RT_ETIMEOUT;
+    }
+
+    else if (status & (MMC_INT_STATUS_RESP_CRC_ERROR | MMC_INT_STATUS_RESPONSE_ERROR))
+    {
+        MMC_ClearRawInterrupt(mmc_obj, MMC_INT_STATUS_RESP_CRC_ERROR | MMC_INT_STATUS_RESPONSE_ERROR);
+        rt_kprintf("ERROR: %s, response error or response crc error, RINTSTS: 0x%x\n", __func__, status);
+        //return -RT_ERROR;
+    }
+
+    return 0;
+}
+
+static int fh_mmc_start_transfer(struct mmc_driver *mmc_drv)
+{
+    struct fh_mmc_obj *mmc_obj = (struct fh_mmc_obj *)mmc_drv->priv;
+    struct rt_mmcsd_host *host = mmc_drv->host;
+    struct rt_mmcsd_req *req = mmc_drv->req;
+    struct rt_mmcsd_cmd *cmd = mmc_drv->cmd;
+    struct rt_mmcsd_data *data = RT_NULL;
+    int ret;
+    rt_uint32_t interrupt, status, reg;
+
+    if(cmd)
+        data = cmd->data;
+
+    if(!data)
+    {
+        return 0;
+    }
+
+    PRINT_MMC_DBG("%s, start\n", __func__);
+
+    //fixme: spin_lock_irqsave(&host->lock, flags);
+    //open data interrupts
+    reg = MMC_GetInterruptMask(mmc_obj);
+    reg |= MMC_INT_STATUS_DATA;
+    MMC_SetInterruptMask(mmc_obj, reg);
+
+    //fixme: spin_unlock_irqrestore(&host->lock, flags);
+    ret = rt_completion_wait(&mmc_drv->transfer_completion, RT_TICK_PER_SECOND * 5);
+
+    reg = MMC_GetInterruptMask(mmc_obj);
+    reg &= ~MMC_INT_STATUS_DATA;
+    MMC_SetInterruptMask(mmc_obj, reg);
+
+    if(ret)
+    {
+        //fixme: error handle
+        cmd->err = ret;
+        interrupt = MMC_GetRawInterrupt(mmc_obj);
+        status = MMC_GetStatus(mmc_obj);
+        rt_kprintf("ERROR: %s, transfer timeout, ret: %d, RINTSTS: 0x%x, STATUS: 0x%x\n", __func__, ret, interrupt, status);
+        //PRINT_MMC_REGS(mmc_obj->base);
+        return -RT_ETIMEOUT;
+    }
+
+    data->bytes_xfered = data->blks * data->blksize;
+
+#ifdef MMC_USE_INTERNAL_BUF
+    if (!(data->flags & DATA_DIR_WRITE))
+    {
+        rt_memcpy(data->buf, g_mmc_dma_buf, data->bytes_xfered);
+        mmu_invalidate_dcache(g_mmc_dma_buf, data->bytes_xfered);
+    }
+#endif
+
+    return 0;
+}
+
+static void fh_mmc_complete_request(struct mmc_driver *mmc_drv)
+{
+    struct fh_mmc_obj *mmc_obj = (struct fh_mmc_obj *)mmc_drv->priv;
+#ifdef MMC_USE_DMA
+    MMC_StopDma(mmc_obj);
+#endif
+    mmc_drv->cmd = RT_NULL;
+    mmc_drv->req = RT_NULL;
+    mmc_drv->data = RT_NULL;
+
+    rt_memset(mmc_obj->descriptors, 0, 4096);
+
+    MMC_SetBlockSize(mmc_obj, 0);
+    MMC_SetByteCount(mmc_obj, 0);
+
+    mmcsd_req_complete(mmc_drv->host);
+}
+
+static void fh_mmc_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
+{
+    int ret;
+    struct mmc_driver *mmc_drv = host->private_data;
+    struct rt_mmcsd_cmd *cmd = req->cmd;
+    struct fh_mmc_obj *mmc_obj = (struct fh_mmc_obj *)mmc_drv->priv;
+
+    PRINT_MMC_DBG("%s start\n", __func__);
+
+    mmc_drv->req = req;
+    mmc_drv->cmd = cmd;
+
+    rt_completion_init(&mmc_drv->transfer_completion);
+
+    ret = fh_mmc_wait_card_idle(mmc_obj);
+
+    if (ret)
+    {
+        rt_kprintf("ERROR: %s, data transfer timeout, status: 0x%x\n", __func__, MMC_GetStatus(mmc_obj));
+        return;
+    }
+
+    fh_mmc_perpare_data(mmc_drv);
+    fh_mmc_send_command(mmc_drv, cmd);
+    ret = fh_mmc_get_response(mmc_drv, cmd);
+    if(ret)
+    {
+        cmd->err = ret;
+        rt_kprintf("%s,get response returns %d, cmd: %d\n", __func__, ret, cmd->cmd_code);
+        goto out;
+    }
+    fh_mmc_start_transfer(mmc_drv);
+
+    if(req->stop)
+    {
+        /* send stop command */
+        PRINT_MMC_DBG("%s send stop\n", __func__);
+        fh_mmc_send_command(mmc_drv, req->stop);
+    }
+
+out:
+    fh_mmc_complete_request(mmc_drv);
+    PRINT_MMC_DBG("%s end\n", __func__);
+}
+
+static const struct rt_mmcsd_host_ops fh_mmc_ops =
+{
+    .request            = fh_mmc_request,
+    .set_iocfg          = fh_mmc_set_iocfg,
+    .enable_sdio_irq    = fh_mmc_enable_sdio_irq,
+    .get_card_status    = fh_mmc_get_card_status,
+};
+
+static void fh_mmc_interrupt(int irq, void *param)
+{
+    struct mmc_driver *mmc_drv = (struct mmc_driver *)param;
+    struct fh_mmc_obj *mmc_obj = (struct fh_mmc_obj *)mmc_drv->priv;
+    struct rt_mmcsd_req *req = mmc_drv->req;
+    struct rt_mmcsd_cmd *cmd = mmc_drv->cmd;
+    struct rt_mmcsd_data *data;
+    rt_uint32_t status;
+
+    if (cmd && cmd->data)
+    {
+        data = cmd->data;
+    }
+
+    status = MMC_GetUnmaskedInterrupt(mmc_obj);
+    PRINT_MMC_DBG("unmasked interrupts: 0x%x\n", status);
+
+    if(status & MMC_INT_STATUS_CARD_DETECT)
+    {
+        rt_uint32_t card_status = MMC_GetCardStatus(mmc_obj);
+
+        if (card_status == CARD_UNPLUGED)
+        {
+            rt_kprintf("card disconnected\n");
+        }
+        else
+        {
+            rt_kprintf("card connected\n");
+        }
+        mmcsd_change(mmc_drv->host);
+    }
+
+    if (status & MMC_INT_STATUS_SDIO)
+    {
+        //fixme: handle sdio
+        //mmc_signal_sdio_irq ?
+    }
+
+    if(status & MMC_INIT_STATUS_DATA_ERROR)
+    {
+        rt_kprintf("ERROR: %s, data error, status: 0x%x\n", __func__, status);
+    }
+
+    if (status & MMC_INT_STATUS_TRANSFER_OVER)
+    {
+        //MMC_ResetFifo(mmc_obj);
+        //rt_completion_done(&mmc_drv->transfer_completion);
+    }
+
+    if (status & MMC_INT_STATUS_TX_REQUEST)
+    {
+        fh_mmc_write_pio(mmc_drv);
+    }
+
+    if (status & MMC_INT_STATUS_RX_REQUEST)
+    {
+        fh_mmc_read_pio(mmc_drv);
+    }
+
+    MMC_ClearRawInterrupt(mmc_obj, MMC_INT_STATUS_ALL);
+    rt_completion_done(&mmc_drv->transfer_completion);
+}
+
+int fh_mmc_probe(void *priv_data)
+{
+    struct mmc_driver *mmc_drv;
+    struct rt_mmcsd_host *host;
+    struct fh_mmc_obj *mmc_obj = (struct fh_mmc_obj *)priv_data;
+
+    PRINT_MMC_DBG("%s start\n", __func__);
+
+    mmc_drv = (struct mmc_driver*)rt_malloc(sizeof(struct mmc_driver));
+    rt_memset(mmc_drv, 0, sizeof(struct mmc_driver));
+    mmc_drv->priv = mmc_obj;
+
+    host = mmcsd_alloc_host();
+    if (!host)
+    {
+        rt_kprintf("ERROR: %s, failed to malloc host\n", __func__);
+        return -RT_ENOMEM;
+    }
+
+    mmc_obj->descriptors = (MMC_DMA_Descriptors*)rt_malloc(4096+64);
+    mmc_obj->descriptors = (MMC_DMA_Descriptors*)(((UINT32)(mmc_obj->descriptors)+31)&(~31)); //cache-line aligned...
+
+    g_mmc_dma_buf = rt_malloc(MMC_INTERNAL_DMA_BUF_SIZE+64);
+    g_mmc_dma_buf = (rt_uint32_t*)(((rt_uint32_t)g_mmc_dma_buf+31) & (~31));
+
+    if(!mmc_obj->descriptors)
+    {
+        rt_kprintf("ERROR: %s, failed to malloc dma descriptors\n", __func__);
+        return -RT_ENOMEM;
+    }
+
+    rt_memset(mmc_obj->descriptors, 0, 4096);
+    mmc_drv->max_desc = 4096 / (sizeof(MMC_DMA_Descriptors));
+
+    host->ops = &fh_mmc_ops;
+    host->freq_min = MMC_FEQ_MIN;
+    host->freq_max = MMC_FEQ_MAX;
+    host->valid_ocr = VDD_32_33 | VDD_33_34;
+
+    host->flags = MMCSD_MUTBLKWRITE | \
+                MMCSD_SUP_HIGHSPEED | MMCSD_SUP_SDIO_IRQ;
+    host->max_seg_size = MMC_DMA_DESC_BUFF_SIZE;
+    host->max_dma_segs = mmc_drv->max_desc;
+    host->max_blk_size = 512;
+    //fixme: max_blk_count?
+    host->max_blk_count = 2048;
+    host->private_data = mmc_drv;
+
+    mmc_drv->host = host;
+    gpio_request(mmc_obj->power_pin_gpio);
+    gpio_direction_output(mmc_obj->power_pin_gpio, 0);
+
+    MMC_Init(mmc_obj);
+
+    if(mmc_obj->id == 0){
+        rt_hw_interrupt_install(mmc_obj->irq, fh_mmc_interrupt, (void *)mmc_drv, "mmc_isr_0");
+    }
+    else if(mmc_obj->id == 1){
+        rt_hw_interrupt_install(mmc_obj->irq, fh_mmc_interrupt, (void *)mmc_drv, "mmc_isr_1");
+    }
+
+    rt_hw_interrupt_umask(mmc_obj->irq);
+    mmcsd_change(host);
+
+    MMC_SetInterruptMask(mmc_obj, MMC_INT_STATUS_CARD_DETECT);
+
+    PRINT_MMC_DBG("%s end\n", __func__);
+
+    return 0;
+}
+
+int fh_mmc_exit(void *priv_data)
+{
+    return 0;
+}
+
+struct fh_board_ops mmc_driver_ops =
+{
+        .probe = fh_mmc_probe,
+        .exit = fh_mmc_exit,
+};
+
+void rt_hw_mmc_init(void)
+{
+    PRINT_MMC_DBG("%s start\n", __func__);
+    fh_board_driver_register("mmc", &mmc_driver_ops);
+    PRINT_MMC_DBG("%s end\n", __func__);
+}

+ 51 - 0
bsp/fh8620/drivers/mmc.h

@@ -0,0 +1,51 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#ifndef MMC_H_
+#define MMC_H_
+
+#include "Libraries/inc/fh_driverlib.h"
+#define MMC_FEQ_MIN 100000
+#define MMC_FEQ_MAX 50000000
+
+#define CARD_UNPLUGED   1
+#define CARD_PLUGED     0
+
+struct mmc_driver
+{
+    MMC_DMA_Descriptors* dma_descriptors;
+    rt_uint32_t max_desc;
+    struct rt_mmcsd_host *host;
+    struct rt_mmcsd_req *req;
+    struct rt_mmcsd_data *data;
+    struct rt_mmcsd_cmd *cmd;
+    struct rt_completion transfer_completion;
+    void*  priv;
+};
+
+void rt_hw_mmc_init(void);
+
+#endif /* MMC_H_ */

+ 226 - 0
bsp/fh8620/drivers/pwm.c

@@ -0,0 +1,226 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "fh_def.h"
+#include "pwm.h"
+#include "interrupt.h"
+#include "board_info.h"
+#include "inc/fh_driverlib.h"
+#include <rtdevice.h>
+#ifdef FH_PWM_DEBUG
+#define PRINT_PWM_DBG(fmt, args...)     \
+    do                                  \
+    {                                   \
+        rt_kprintf("FH_PWM_DEBUG: ");   \
+        rt_kprintf(fmt, ## args);       \
+    }                                   \
+    while(0)
+#else
+#define PRINT_PWM_DBG(fmt, args...)  do { } while (0)
+#endif
+
+
+static struct pwm_driver pwm_drv =
+{
+
+};
+
+
+
+
+static int pwm_get_duty_cycle_ns(struct pwm_device* pwm)
+{
+    struct fh_pwm_obj *pwm_obj = (struct fh_pwm_obj *)pwm_drv.priv;
+    rt_uint32_t reg, period, duty;
+    rt_uint32_t clk_rate = 1000000/*todo: clk_get_rate(fh_pwm_ctrl.clk)*/;
+
+    reg = PWM_GetPwmCmd(pwm_obj, pwm->id);
+    period = reg & 0x0fff;
+    duty = (reg >> 16) & 0xfff;
+    duty = period - duty;       //reverse duty cycle
+
+    if(period == 0)
+    {
+        period = duty;
+    }
+
+    pwm->counter_ns = duty * 1000000000 / clk_rate;
+    pwm->period_ns = period * 1000000000 / clk_rate;
+
+    PRINT_PWM_DBG("get duty: %d, period: %d, reg: 0x%x\n", duty, period, reg);
+
+    return 0;
+}
+
+static int pwm_set_duty_cycle_ns(struct pwm_device* pwm)
+{
+    struct fh_pwm_obj *pwm_obj = (struct fh_pwm_obj *)pwm_drv.priv;
+    rt_uint32_t period, duty, reg, clk_rate, duty_revert;
+    clk_rate = 1000000/*todo: clk_get_rate(fh_pwm_ctrl.clk)*/;
+    if(!clk_rate)
+    {
+        rt_kprintf("PWM: clock rate is 0\n");
+        return -RT_EIO;
+    }
+    period = pwm->period_ns / (1000000000 / clk_rate);
+
+    if(period < 8)
+    {
+        rt_kprintf("PWM: min period is 8\n");
+        return -RT_EIO;
+    }
+
+    duty = pwm->counter_ns / (1000000000 / clk_rate);
+
+    if(period < duty)
+    {
+        rt_kprintf("PWM: period < duty\n");
+        return -RT_EIO;
+    }
+
+    duty_revert = period - duty;
+
+    if(duty == period)
+    {
+        reg = (duty & 0xfff) << 16 | (0 & 0xfff);
+    }
+    else
+    {
+        reg = (duty_revert & 0xfff) << 16 | (period & 0xfff);
+    }
+
+    PRINT_PWM_DBG("set duty_revert: %d, period: %d, reg: 0x%x\n", duty_revert, period, reg);
+
+    PWM_SetPwmCmd(pwm_obj, pwm->id, reg);
+    return 0;
+}
+
+
+
+
+static rt_err_t fh_pwm_open(rt_device_t dev, rt_uint16_t oflag)
+{
+    struct fh_pwm_obj *pwm_obj = (struct fh_pwm_obj *)pwm_drv.priv;
+    PWM_Enable(pwm_obj, RT_TRUE);
+    return 0;
+}
+
+static rt_err_t fh_pwm_close(rt_device_t dev)
+{
+    struct fh_pwm_obj *pwm_obj = (struct fh_pwm_obj *)pwm_drv.priv;
+    PWM_Enable(pwm_obj, RT_FALSE);
+    return 0;
+}
+
+static rt_err_t fh_pwm_ioctl(rt_device_t dev, rt_uint8_t cmd, void *arg)
+{
+    int ret = 0;
+    struct pwm_device *pwm;
+    struct fh_pwm_obj *pwm_obj = (struct fh_pwm_obj *)pwm_drv.priv;
+
+    switch(cmd)
+    {
+    case ENABLE_PWM:
+        PWM_Enable(pwm_obj, RT_FALSE);
+        break;
+    case DISABLE_PWM:
+        PWM_Enable(pwm_obj, RT_TRUE);
+        break;
+    case SET_PWM_DUTY_CYCLE:
+        pwm = (struct pwm_device *)arg;
+        PRINT_PWM_DBG("ioctl: pwm addr: %p, pwm->period: %d ns\n", pwm, pwm->period_ns);
+        pwm_set_duty_cycle_ns(pwm);
+        break;
+    case GET_PWM_DUTY_CYCLE:
+        pwm = (struct pwm_device *)arg;
+        PRINT_PWM_DBG("ioctl: pwm->id: %d, pwm->counter: %d, pwm->period: %d\n", pwm->id, pwm->counter_ns, pwm->period_ns);
+        pwm_get_duty_cycle_ns(pwm);
+        break;
+    }
+
+    return ret;
+}
+
+int fh_pwm_probe(void *priv_data)
+{
+    rt_device_t pwm_dev ;
+    struct fh_pwm_obj *pwm_obj = (struct fh_pwm_obj *)priv_data;
+
+    rt_memset(&pwm_drv, 0, sizeof(struct pwm_driver));
+
+    pwm_drv.pwm[0].id = 0;
+    pwm_drv.pwm[1].id = 1;
+    pwm_drv.pwm[2].id = 2;
+
+    pwm_drv.pwm[0].working = 0;
+    pwm_drv.pwm[1].working = 0;
+    pwm_drv.pwm[2].working = 0;
+
+    pwm_drv.priv = pwm_obj;
+
+    //todo: clk
+
+    PWM_Enable(pwm_obj, RT_FALSE);
+
+    pwm_dev = rt_malloc(sizeof(struct rt_device));
+    rt_memset(pwm_dev, 0, sizeof(struct rt_device));
+
+    if (pwm_dev == RT_NULL)
+    {
+        rt_kprintf("ERROR: %s rt_device malloc failed\n", __func__);
+    }
+
+    pwm_dev->user_data = &pwm_drv;
+    pwm_dev->open =fh_pwm_open;
+    pwm_dev->close = fh_pwm_close;
+    pwm_dev->control = fh_pwm_ioctl;
+    pwm_dev->type    = RT_Device_Class_Miscellaneous;
+
+    rt_device_register(pwm_dev, "pwm", RT_DEVICE_FLAG_RDWR);
+
+
+
+    return 0;
+}
+
+int fh_pwm_exit(void *priv_data)
+{
+    return 0;
+}
+
+struct fh_board_ops pwm_driver_ops =
+{
+        .probe = fh_pwm_probe,
+        .exit = fh_pwm_exit,
+};
+
+void rt_hw_pwm_init(void)
+{
+    PRINT_PWM_DBG("%s start\n", __func__);
+    fh_board_driver_register("pwm", &pwm_driver_ops);
+    PRINT_PWM_DBG("%s end\n", __func__);
+}
+

+ 57 - 0
bsp/fh8620/drivers/pwm.h

@@ -0,0 +1,57 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef PWM_H_
+#define PWM_H_
+
+
+#include <rtthread.h>
+#define ENABLE_PWM                  (0x10)
+#define DISABLE_PWM                 (0x11)
+
+#define SET_PWM_DUTY_CYCLE          (0x12)
+#define GET_PWM_DUTY_CYCLE          (0x13)
+
+struct pwm_device
+{
+    int id;
+    int working;
+    rt_uint32_t period_ns;
+    rt_uint32_t counter_ns;
+};
+
+struct pwm_driver
+{
+    //struct clk          *clk;
+    struct pwm_device   pwm[3];
+    struct pwm_device   *cur;
+    void*  priv;
+
+};
+
+
+
+#endif /* PWM_H_ */

+ 416 - 0
bsp/fh8620/drivers/sadc.c

@@ -0,0 +1,416 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "sadc.h"
+#ifdef RT_USING_SADC
+#include "inc/fh_driverlib.h"
+#include "board_info.h"
+#include <rtdef.h>
+
+//#define FH_SADC_DEBUG
+//#define FH_TEST_SADC
+
+
+#ifdef FH_SADC_DEBUG
+#define PRINT_SADC_DBG(fmt, args...)     \
+    do                                  \
+    {                                   \
+        rt_kprintf("FH_SADC_DEBUG: ");   \
+        rt_kprintf(fmt, ## args);       \
+    }                                   \
+    while(0)
+#else
+#define PRINT_SADC_DBG(fmt, args...)  do { } while (0)
+#endif
+
+
+
+
+
+#define __raw_writeb(v,a)	( *(volatile unsigned char  *)(a) = (v))
+#define __raw_writew(v,a)	( *(volatile unsigned short *)(a) = (v))
+#define __raw_writel(v,a)	( *(volatile unsigned int   *)(a) = (v))
+
+#define __raw_readb(a)		( *(volatile unsigned char   *)(a))
+#define __raw_readw(a)		( *(volatile unsigned short  *)(a))
+#define __raw_readl(a)		( *(volatile unsigned int    *)(a))
+
+
+#define wrap_readl(wrap, name) \
+	__raw_readl(&(((struct wrap_sadc_reg *)wrap->regs)->name))
+
+#define wrap_writel(wrap, name, val) \
+	__raw_writel((val), &(((struct wrap_sadc_reg *)wrap->regs)->name))
+
+#define wrap_readw(wrap, name) \
+	__raw_readw(&(((struct wrap_sadc_reg *)wrap->regs)->name))
+
+#define wrap_writew(wrap, name, val) \
+	__raw_writew((val), &(((struct wrap_sadc_reg *)wrap->regs)->name))
+
+#define wrap_readb(wrap, name) \
+	__raw_readb(&(((struct wrap_sadc_reg *)wrap->regs)->name))
+
+#define wrap_writeb(wrap, name, val) \
+	__raw_writeb((val), &(((struct wrap_sadc_reg *)wrap->regs)->name))
+
+
+
+#define IOCTL_GET_SADC_DATA 	1
+#define IOCTL_SADC_POWER_DOWN 	0xff
+#define SADC_WRAP_BASE			(0xf1200000)
+#define SADC_IRQn         		(23)
+#define SADC_MAX_CONTROLLER		(1)
+#define SADC_STATUS_COLESD		(0)
+#define SADC_STATUS_OPEN		(1)
+
+
+
+rt_err_t fh_sadc_isr_read_data(struct wrap_sadc_obj *sadc, rt_uint32_t channel,
+		rt_uint16_t *buf) {
+	rt_uint32_t xainsel = 1 << channel;
+	rt_uint32_t xversel = 0;
+	rt_uint32_t xpwdb = 1;
+	//cnt
+	rt_uint32_t sel2sam_pre_cnt = 2;
+	rt_uint32_t sam_cnt = 2;
+	rt_uint32_t sam2sel_pos_cnt = 2;
+	//time out
+	rt_uint32_t eoc_tos = 0xff;
+	rt_uint32_t eoc_toe = 0xff;
+	rt_uint32_t time_out = 0xffff;
+	//set isr en..
+	rt_uint32_t sadc_isr = 0x01;
+	//start
+	rt_uint32_t sadc_cmd = 0x01;
+	//get data
+	rt_uint32_t temp_data = 0;
+	rt_err_t ret;
+
+
+	//control...
+	wrap_writel(sadc, sadc_control, xainsel | (xversel << 8) | (xpwdb << 12));
+
+
+	wrap_writel(sadc, sadc_cnt,
+			sel2sam_pre_cnt | (sam_cnt << 8) | (sam2sel_pos_cnt << 16));
+
+	wrap_writel(sadc, sadc_timeout,
+			eoc_tos | (eoc_toe << 8) | (time_out << 16));
+
+	wrap_writel(sadc, sadc_ier, sadc_isr);
+
+	wrap_writel(sadc, sadc_cmd, sadc_cmd);
+
+
+   // ret = rt_completion_wait(&sadc->completion, RT_TICK_PER_SECOND / 2);
+
+	ret = rt_sem_take(&sadc->completion, 5000);
+	if(ret != RT_EOK)
+		return ret;
+
+	switch (channel) {
+	case 0:
+	case 1:
+		//read channel 0 1
+		temp_data = wrap_readl(sadc, sadc_dout0);
+		break;
+
+	case 2:
+	case 3:
+		//read channel 2 3
+		temp_data = wrap_readl(sadc, sadc_dout1);
+		break;
+
+	case 4:
+	case 5:
+		//read channel 4 5
+		temp_data = wrap_readl(sadc, sadc_dout2);
+		break;
+
+	case 6:
+	case 7:
+		//read channel 6 7
+		temp_data = wrap_readl(sadc, sadc_dout3);
+		break;
+	default:
+		break;
+	}
+	if (channel % 2) {
+		//read low 16bit
+		*buf = (rt_uint16_t) (temp_data & 0xffff);
+	} else {
+		//read high 16bit
+		*buf = (rt_uint16_t) (temp_data >> 16);
+	}
+	return RT_EOK;
+
+}
+
+
+
+
+
+
+static rt_err_t fh_sadc_init(rt_device_t dev)
+{
+
+   // struct fh_pwm_obj *pwm_obj = (struct fh_pwm_obj *)pwm_drv.priv;
+    PRINT_SADC_DBG("%s\n",__func__);
+    struct wrap_sadc_obj *sadc_pri =(struct wrap_sadc_obj *)dev->user_data;
+    return RT_EOK;
+}
+
+
+
+static rt_err_t fh_sadc_open(rt_device_t dev, rt_uint16_t oflag)
+{
+   // struct fh_pwm_obj *pwm_obj = (struct fh_pwm_obj *)pwm_drv.priv;
+    PRINT_SADC_DBG("%s\n",__func__);
+    struct wrap_sadc_obj *sadc_pri =(struct wrap_sadc_obj *)dev->user_data;
+    return RT_EOK;
+}
+
+static rt_err_t fh_sadc_close(rt_device_t dev)
+{
+    PRINT_SADC_DBG("%s\n",__func__);
+    struct wrap_sadc_obj *sadc_pri =(struct wrap_sadc_obj *)dev->user_data;
+    return RT_EOK;
+}
+
+static rt_err_t fh_sadc_ioctl(rt_device_t dev, rt_uint8_t cmd, void *arg)
+{
+
+	rt_uint32_t control_reg;
+	struct wrap_sadc_obj *sadc_pri =(struct wrap_sadc_obj *)dev->user_data;
+	rt_uint32_t ad_data;
+	rt_uint16_t ad_raw_data;
+
+	SADC_INFO *sadc_info = (SADC_INFO *)arg;
+	rt_err_t ret;
+	switch(cmd){
+	case SADC_CMD_READ_RAW_DATA:
+		ret = fh_sadc_isr_read_data(sadc_pri, sadc_info->channel, &ad_raw_data);
+		if(ret != RT_EOK)
+			return ret;
+		sadc_info->sadc_data = ad_raw_data;
+
+		break;
+	case SADC_CMD_READ_VOLT:
+		ret = fh_sadc_isr_read_data(sadc_pri, sadc_info->channel, &ad_raw_data);
+		if(ret != RT_EOK)
+			return ret;
+
+		ad_data = ad_raw_data * SADC_REF;
+		ad_data /= SADC_MAX_AD_VALUE;
+		sadc_info->sadc_data = ad_data;
+
+		break;
+	case SADC_CMD_DISABLE:
+		control_reg = wrap_readl(sadc_pri, sadc_control);
+		control_reg &= ~(1 << 12);
+		wrap_writel(sadc_pri, sadc_control, control_reg);
+
+		break;
+	default :
+		rt_kprintf("wrong para...\n");
+		return RT_EIO;
+	}
+
+    return RT_EOK;
+}
+
+
+
+static void fh_sadc_interrupt(int irq, void *param)
+{
+
+    rt_uint32_t isr_status;
+	struct wrap_sadc_obj *sadc = (struct wrap_sadc_obj *) param;
+
+	isr_status = wrap_readl(sadc, sadc_int_status);
+
+	if (isr_status & 0x01) {
+		//close isr
+		rt_uint32_t sadc_isr = 0x00;
+
+		wrap_writel(sadc, sadc_ier, sadc_isr);
+		//clear status..
+
+		wrap_writel(sadc, sadc_int_status, isr_status);
+
+		rt_sem_release(&sadc->completion);
+	   // rt_completion_done(&sadc->completion);
+	} else {
+		//add error handle process
+		rt_kprintf("sadc maybe error!\n");
+	}
+
+
+}
+
+
+int fh_sadc_probe(void *priv_data)
+{
+    int ret;
+
+    rt_device_t sadc_dev;
+    //check if the hw is init already...
+    //caution this is a read only data...if the driver want to use.malloc and copy it..
+    struct wrap_sadc_obj *sadc_obj = (struct wrap_sadc_obj *)priv_data;
+    if(sadc_obj->init_flag == SADC_INIT_ALREADY)
+     	return RT_EFULL;
+
+
+    //malloc a rt device..
+    sadc_dev = RT_KERNEL_MALLOC(sizeof(struct rt_device));
+    if(!sadc_dev){
+    	return RT_ENOMEM;
+    }
+    rt_memset(sadc_dev, 0, sizeof(struct rt_device));
+    PRINT_SADC_DBG("id:%d,\treg:%x,\tirq:%d\n",sadc_obj->id,(rt_uint32_t)sadc_obj->regs,sadc_obj->irq_no);
+
+    //bind rtdev to obj data...
+    //caution ...this is used to free mem when exit....
+    //free step:1:get sadc obj...2:free sadc_obj->rt_dev->user_data..3:free sadc_obj->rt_dev 4:sadc_obj->rt_dev = NULL
+    sadc_obj->rt_dev = sadc_dev;
+
+
+
+    //malloc a private data sadc use only...copy data from platform...
+    struct wrap_sadc_obj *sadc_pri = RT_KERNEL_MALLOC(sizeof(struct wrap_sadc_obj));
+    if(!sadc_pri){
+
+    	RT_KERNEL_FREE(sadc_dev);
+    	return RT_ENOMEM;
+    }
+
+    //copy platform data to pri data..
+    rt_memcpy(sadc_pri,sadc_obj,sizeof(struct wrap_sadc_obj));
+
+    PRINT_SADC_DBG("pri....id:%d,\treg:%x,\tirq:%d\n",sadc_pri->id,(rt_uint32_t)sadc_pri->regs,sadc_pri->irq_no);
+
+
+
+    //init sem
+    //rt_completion_init(&sadc_obj->completion);
+    rt_sem_init(&sadc_pri->completion, "sadc_sem", 0, RT_IPC_FLAG_FIFO);
+
+    //init lock
+    rt_mutex_init(&sadc_pri->lock,"sadc_lock", RT_IPC_FLAG_FIFO);
+
+
+    //bind pri data to rt_sadc_dev...
+    sadc_dev->user_data = (void *)sadc_pri;
+    sadc_dev->open =fh_sadc_open;
+    sadc_dev->close = fh_sadc_close;
+    sadc_dev->control = fh_sadc_ioctl;
+    sadc_dev->init = fh_sadc_init;
+
+    if(sadc_pri->id ==0){
+        rt_hw_interrupt_install(sadc_pri->irq_no, fh_sadc_interrupt,
+                                (void *)sadc_pri, "sadc_isr_0");
+    }
+
+    rt_hw_interrupt_umask(sadc_pri->irq_no);
+
+    rt_device_register(sadc_dev, "sadc", RT_DEVICE_FLAG_RDWR);
+
+    sadc_obj->init_flag = SADC_INIT_ALREADY;
+
+    return RT_EOK;
+
+}
+
+
+int fh_sadc_exit(void *priv_data)
+{
+
+	PRINT_SADC_DBG("%s\n",__func__);
+	struct wrap_sadc_obj *sadc_obj = (struct wrap_sadc_obj *)priv_data;
+
+	struct wrap_sadc_obj *sadc_pri = sadc_obj->rt_dev->user_data;
+	//release sem;
+	rt_sem_detach(&sadc_pri->completion);
+	//sadc_pri->completion = RT_NULL;
+
+	//release lock;
+	rt_mutex_detach(&sadc_pri->lock);
+
+	RT_KERNEL_FREE(sadc_obj->rt_dev->user_data);
+
+
+	sadc_obj->rt_dev->user_data = RT_NULL;
+	RT_KERNEL_FREE(sadc_obj->rt_dev);
+	sadc_obj->rt_dev = RT_NULL;
+
+    return 0;
+}
+
+struct fh_board_ops sdac_driver_ops =
+{
+        .probe = fh_sadc_probe,
+        .exit = fh_sadc_exit,
+};
+
+void rt_hw_sadc_init(void)
+{
+    int ret;
+    fh_board_driver_register("sadc", &sdac_driver_ops);
+}
+
+
+#ifdef FH_TEST_SADC
+int fh_sadc_test(void){
+
+	rt_device_t sadc_dev;
+	SADC_INFO info;
+	info.channel = 0;
+	info.sadc_data = 0;
+	sadc_dev = rt_device_find("sadc");
+	if(!sadc_dev){
+		rt_kprintf("cann't find the sadc dev\n");
+	}
+	sadc_dev->init(sadc_dev);
+	sadc_dev->open(sadc_dev,0);
+	while(1)
+	{
+		sadc_dev->control(sadc_dev,SADC_CMD_READ_VOLT,&info);
+		rt_kprintf("channel:%d,volt:%dmv\n",info.channel,info.sadc_data);
+	}
+
+	return 0;
+}
+#endif
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+#ifdef FH_TEST_SADC
+FINSH_FUNCTION_EXPORT(fh_sadc_test, fh_sadc_test);
+#endif
+#endif
+
+#endif

+ 109 - 0
bsp/fh8620/drivers/sadc.h

@@ -0,0 +1,109 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef SADC_H_
+#define SADC_H_
+
+#include <rtdef.h>
+#ifdef RT_USING_SADC
+
+
+/****************************************************************************
+ * #define section
+ *	add constant #define here if any
+ ***************************************************************************/
+//#define FH_SADC_PROC_FILE    "driver/sadc"
+#define MAX_CHANNEL_NO		(8)
+#define SADC_REF			(3300)
+#define SADC_MAX_AD_VALUE	(0x3ff)
+#define LOOP_MODE			(0x55)
+#define ISR_MODE			(0xAA)
+
+
+#define SADC_INIT_ALREADY		(0x33)
+#define SADC_INIT_NOT_YET		(0)
+
+
+#define SADC_CMD_READ_RAW_DATA			(0x22)
+#define SADC_CMD_READ_VOLT				(0x33)
+#define SADC_CMD_DISABLE				(0x44)
+
+/****************************************************************************
+ * ADT section
+ *	add Abstract Data Type definition here
+ ***************************************************************************/
+
+struct wrap_sadc_reg {
+	rt_uint32_t sadc_cmd;
+	rt_uint32_t sadc_control;
+	rt_uint32_t sadc_ier;
+	rt_uint32_t sadc_int_status;
+	rt_uint32_t sadc_dout0;
+	rt_uint32_t sadc_dout1;
+	rt_uint32_t sadc_dout2;
+	rt_uint32_t sadc_dout3;
+	rt_uint32_t sadc_debuge0;
+	rt_uint32_t sadc_status;
+	rt_uint32_t sadc_cnt;
+	rt_uint32_t sadc_timeout;
+};
+
+struct wrap_sadc_obj {
+	rt_uint32_t id;
+	void *regs;
+	rt_uint32_t irq_no;
+	rt_uint32_t init_flag;
+	rt_uint32_t active_channel_no;
+	rt_uint32_t active_channel_status;
+	rt_uint16_t channel_data[MAX_CHANNEL_NO];
+	rt_uint32_t error_rec;
+	rt_uint32_t en_isr;
+	rt_uint32_t sample_mode;
+	struct rt_mutex lock;
+	struct rt_semaphore completion;
+
+    //bind to the rtdev..
+    rt_device_t rt_dev;
+
+};
+
+typedef struct{
+	rt_uint32_t channel;
+	rt_uint32_t sadc_data;
+}SADC_INFO;
+
+
+/****************************************************************************
+ *  extern variable declaration section
+ ***************************************************************************/
+
+/****************************************************************************
+ *  section
+ *	add function prototype here if any
+ ***************************************************************************/
+void rt_hw_sadc_init(void);
+#endif
+#endif /* SADC_H_ */

+ 212 - 0
bsp/fh8620/drivers/spi_fh_adapt.c

@@ -0,0 +1,212 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+ /*
+ * spi_fh_adapt.c
+ *
+ *  Created on: Mar 2, 2016
+ *      Author: duobao
+ */
+
+
+#include <stdint.h>
+#include "spi_fh_adapt.h"
+#include "board_info.h"
+
+#ifdef RT_USING_W25QXX
+#include "spi_flash_w25qxx.h"
+#endif
+
+#ifdef RT_USING_AT45DBXX
+#include "spi_flash_at45dbxx.h"
+#endif
+
+#ifdef RT_USING_SST25VFXX
+#include "spi_flash_sst25vfxx.h"
+#endif
+
+#ifdef RT_USING_GD
+#include "spi_flash_gd.h"
+#endif
+
+
+#ifdef RT_USING_FLASH_DEFAULT
+#include "spi_flash_default.h"
+#endif
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+
+#define WX_MANU_ID		0xEF
+#define AT_MANU_ID      0x1F /* atmel */
+#define SST_MANU_ID		0xBF
+#define GD_MANU_ID      0xC8
+
+
+
+#define SPI_ADAPT_DEBUG
+#ifdef SPI_ADAPT_DEBUG
+
+#define CMD_JEDEC_ID 			0x9f
+
+
+#define FH_SPI_ADAPT_DEBUG(fmt, args...)	    		\
+			rt_kprintf(fmt,##args);
+#else
+#define FH_SPI_ADAPT_DEBUG(fmt, args...)
+#endif
+struct fh_flash_id{
+	unsigned char id;
+	rt_err_t (*fh_flash_init)(struct flash_platform_data *plat_flash);
+	char *name;
+};
+const struct fh_flash_id id_map[] = {
+
+#ifdef RT_USING_W25QXX
+		WX_MANU_ID,w25qxx_init,"winbond",
+#endif
+
+#ifdef RT_USING_AT45DBXX
+		AT_MANU_ID,at45dbxx_init,"atmel",
+#endif
+
+#ifdef RT_USING_SST25VFXX
+		SST_MANU_ID,sst25vfxx_init,"SST",
+#endif
+
+#ifdef RT_USING_GD
+		GD_MANU_ID,gd_init,"GD",
+#endif
+
+};
+
+
+struct fh_flash_id * fh_flash_check_id_map(unsigned char id){
+	struct fh_flash_id *p_map = RT_NULL;
+	unsigned int i;
+	for (i = 0; i < ARRAY_SIZE(id_map); i++) {
+		p_map = (struct fh_flash_id *)&id_map[i];
+		if (p_map->id == id){
+			return p_map;
+		}
+	}
+	return RT_NULL;
+}
+
+
+int fh_flash_adapt_probe(void *priv_data)
+{
+    struct flash_platform_data *plat_flash = priv_data;
+    const char * flash_device_name = plat_flash->flash_name;
+    const char * spi_device_name = plat_flash->spi_name;
+    struct rt_spi_device * rt_spi_device;
+    struct fh_flash_id * flash_model;
+
+    rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
+    if(rt_spi_device == RT_NULL)
+    {
+        rt_kprintf("spi device %s not found!\r\n", spi_device_name);
+        return -RT_ENOSYS;
+    }
+
+
+    /* config spi */
+    {
+        struct rt_spi_configuration cfg;
+        cfg.data_width = 8;
+        cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0 and Mode 3 */
+        cfg.max_hz = 50 * 1000 * 1000; /* 50M */
+        rt_spi_configure(rt_spi_device, &cfg);
+    }
+
+    /* init flash */
+
+	rt_uint8_t cmd;
+	rt_uint8_t id_recv[3];
+	uint16_t memory_type_capacity;
+	rt_err_t ret;
+
+	cmd = 0xFF; /* reset SPI FLASH, cancel all cmd in processing. */
+	rt_spi_send(rt_spi_device, &cmd, 1);
+	/* read flash id */
+	cmd = CMD_JEDEC_ID;
+	rt_spi_send_then_recv(rt_spi_device, &cmd, 1, id_recv, 3);
+
+	//if the flash is already connect.
+	if(id_recv[0] != 0xff){
+		flash_model =fh_flash_check_id_map(id_recv[0]);
+		if(flash_model){
+			ret = flash_model->fh_flash_init(plat_flash);
+			if(ret != RT_EOK){
+				rt_kprintf("flash:%s init error\n",flash_model->name);
+				rt_kprintf("use default flash ops..\n");
+				//flash_model->fh_flash_adapt_init =flash_default_init;
+				ret = flash_default_init(plat_flash);
+			}
+		}
+		else{
+			rt_kprintf(
+					"use default flash ops...\nunrecognized flash id is :%02X %02X %02X\n",
+					id_recv[0], id_recv[1], id_recv[2]);
+			ret = flash_default_init(plat_flash);
+
+		}
+
+		int i;
+		for(i=0; i<plat_flash->nr_parts; i++)
+		{
+		    fh_spi_partition_register(plat_flash->flash_name, &plat_flash->parts[i]);
+		}
+
+		return ret;
+
+	}
+	else{
+		rt_kprintf("please check if you connect the flash already...\n");
+		return RT_ENOSYS;
+	}
+
+
+}
+
+int fh_flash_adapt_exit(void *priv_data)
+{
+    return 0;
+}
+
+struct fh_board_ops flash_driver_ops =
+{
+
+        .probe = fh_flash_adapt_probe,
+        .exit = fh_flash_adapt_exit,
+
+};
+
+rt_err_t fh_flash_adapt_init(void)
+{
+    fh_board_driver_register("fh_flash", &flash_driver_ops);
+    return 0;
+}

+ 71 - 0
bsp/fh8620/drivers/spi_fh_adapt.h

@@ -0,0 +1,71 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+ /*
+ * spi_fh_adapt.h
+ *
+ *  Created on: Mar 2, 2016
+ *      Author: duobao
+ */
+
+#ifndef SPI_FH_ADAPT_H_
+#define SPI_FH_ADAPT_H_
+
+#include <rtthread.h>
+#include <drivers/spi.h>
+
+#define MTD_WRITEABLE       0x400   /* Device is writeable */
+#define MTD_BIT_WRITEABLE   0x800   /* Single bits can be flipped */
+#define MTD_NO_ERASE        0x1000  /* No erase necessary */
+#define MTD_POWERUP_LOCK    0x2000  /* Always locked after reset */
+
+struct mtd_partition {
+    char *name;                 /* identifier string */
+    rt_uint32_t size;              /* partition size */
+    rt_uint32_t offset;            /* offset within the master MTD space */
+    rt_uint32_t mask_flags;        /* master MTD flags to mask out for this partition */
+    struct nand_ecclayout *ecclayout;   /* out of band layout for this partition (NAND only) */
+};
+
+struct flash_platform_data {
+    char        *flash_name;
+    char        *spi_name;
+    struct mtd_partition *parts;
+    unsigned int    nr_parts;
+
+    char        *type;
+
+    /* we'll likely add more ... use JEDEC IDs, etc */
+};
+
+
+rt_err_t fh_flash_adapt_init(void);
+#endif /* SPI_FH_ADAPT_H_ */
+
+
+
+
+

+ 878 - 0
bsp/fh8620/drivers/ssi.c

@@ -0,0 +1,878 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#include <rtdevice.h>
+#include <drivers/spi.h>
+#include "fh_arch.h"
+#include "board_info.h"
+#include "ssi.h"
+#include "gpio.h"
+#include "inc/fh_driverlib.h"
+#include "dma.h"
+#include "dma_mem.h"
+#include "mmu.h"
+//#define FH_SPI_DEBUG
+
+#ifdef FH_SPI_DEBUG
+#define PRINT_SPI_DBG(fmt, args...)     \
+    do                                  \
+    {                                   \
+        rt_kprintf("FH_SPI_DEBUG: ");   \
+        rt_kprintf(fmt, ## args);       \
+    }                                   \
+    while(0)
+#else
+#define PRINT_SPI_DBG(fmt, args...)  do { } while (0)
+#endif
+
+
+#define RX_DMA_CHANNEL	AUTO_FIND_CHANNEL
+#define TX_DMA_CHANNEL	AUTO_FIND_CHANNEL
+
+#define DMA_OR_ISR_THRESHOLD		20
+#define MALLOC_DMA_MEM_SIZE			0x1000
+
+
+//static rt_uint32_t allign_func(rt_uint32_t in_addr,rt_uint32_t allign_size){
+//	return (in_addr + allign_size-1) & (~(allign_size - 1));
+//}
+
+
+void * fh_get_spi_dev_pri_data(struct rt_spi_device* device){
+	return device->parent.user_data;
+}
+
+static rt_err_t fh_spi_configure(struct rt_spi_device* device,
+                          struct rt_spi_configuration* configuration)
+{
+
+    struct spi_slave_info *spi_slave;
+    struct spi_controller *spi_control;
+    struct fh_spi_obj *spi_obj;
+    struct spi_config *config;
+    rt_uint32_t status;
+    rt_uint32_t spi_hz;
+
+    spi_slave = ( struct spi_slave_info *)fh_get_spi_dev_pri_data(device);
+    spi_control = spi_slave->control;
+    spi_obj = &spi_control->obj;
+    config = &spi_obj->config;
+
+    PRINT_SPI_DBG("configuration: \n");
+    PRINT_SPI_DBG("\tmode: 0x%x\n", configuration->mode);
+    PRINT_SPI_DBG("\tdata_width: 0x%x\n", configuration->data_width);
+    PRINT_SPI_DBG("\tmax_hz: 0x%x\n", configuration->max_hz);
+
+    do{
+	  status = SPI_ReadStatus(spi_obj);
+	}
+    while(status & SPI_STATUS_BUSY);
+
+
+	/* data_width */
+	if(configuration->data_width <= 8){
+	  config->data_size = SPI_DATA_SIZE_8BIT;
+	}
+	else if(configuration->data_width <= 16){
+	  config->data_size = SPI_DATA_SIZE_16BIT;
+	}
+	else{
+	  return -RT_ERROR;
+	}
+
+	if(configuration->max_hz > spi_control->max_hz)
+		spi_hz = spi_control->max_hz;
+	else
+		spi_hz = configuration->max_hz;
+
+	//fixme: div
+	config->clk_div = spi_control->clk_in/spi_hz;
+	//config->clk_div = 8;
+	PRINT_SPI_DBG("config hz:%d spi div:%d\n",spi_hz,config->clk_div);
+	/* CPOL */
+	if(configuration->mode & RT_SPI_CPOL){
+	  config->clk_polarity = SPI_POLARITY_HIGH;
+	}
+	else{
+	  config->clk_polarity = SPI_POLARITY_LOW;
+	}
+
+	/* CPHA */
+	if(configuration->mode & RT_SPI_CPHA){
+	  config->clk_phase = SPI_PHASE_TX_FIRST;
+	}
+	else{
+	  config->clk_phase = SPI_PHASE_RX_FIRST;
+	}
+
+	config->frame_format = SPI_FORMAT_MOTOROLA;
+	config->transfer_mode = SPI_MODE_TX_RX;
+
+	SPI_Enable(spi_obj, 0);
+	SPI_SetParameter(spi_obj);
+	SPI_DisableInterrupt(spi_obj, SPI_IRQ_ALL);
+	SPI_Enable(spi_obj, 1);
+
+    return RT_EOK;
+}
+
+
+static void xfer_dma_done(void *arg)
+{
+	struct spi_controller *spi_control = (struct spi_controller *)arg;
+	spi_control->dma_complete_times++;
+
+    struct fh_spi_obj *spi_obj;
+    int ret;
+    rt_uint32_t slave_id;
+    spi_obj = &spi_control->obj;
+
+
+	//rt_kprintf("spi dma isr done.....\n");
+	if (spi_control->dma_complete_times == 2) {
+		spi_control->dma_complete_times = 0;
+
+		//add memcpy to user buff
+		if(spi_control->current_message->recv_buf){
+			rt_memcpy((void*)spi_control->current_message->recv_buf,(void*)spi_control->dma.rx_dummy_buff,spi_control->current_message->length);
+		}
+
+		SPI_Enable(spi_obj,0);
+		SPI_DisableDma(spi_obj,SPI_TX_DMA|SPI_RX_DMA);
+		SPI_Enable(spi_obj,1);
+
+		rt_completion_done(&spi_control->transfer_completion);
+	}
+
+}
+
+void dma_set_tx_data(struct spi_controller *spi_control){
+
+	struct dma_transfer *trans;
+	rt_uint32_t hs_no;
+	struct rt_spi_message* current_message = spi_control->current_message;
+	trans = &spi_control->dma.tx_trans;
+	hs_no = spi_control->dma.tx_hs;
+
+	struct fh_spi_obj *spi_obj;
+	spi_obj = &spi_control->obj;
+
+
+
+	if(current_message->length > MALLOC_DMA_MEM_SIZE){
+		rt_kprintf("[spi_dma]message len too large..\n");
+		rt_kprintf("[spi_dma] message len is %d,max len is %d\n",current_message->length,MALLOC_DMA_MEM_SIZE);
+		RT_ASSERT(current_message->length <= MALLOC_DMA_MEM_SIZE);
+	}
+
+
+	rt_memset((void*)spi_control->dma.tx_dummy_buff,0xff,current_message->length);
+	//copy tx data....
+	if(current_message->send_buf){
+		rt_memcpy(spi_control->dma.tx_dummy_buff,current_message->send_buf,current_message->length);
+	}
+
+
+	trans->dma_number = 0;
+	trans->dst_add = (rt_uint32_t)(spi_obj->base + OFFSET_SPI_DR);
+
+	trans->dst_hs = DMA_HW_HANDSHAKING;
+	trans->dst_inc_mode = DW_DMA_SLAVE_FIX;
+	trans->dst_msize = DW_DMA_SLAVE_MSIZE_1;
+	trans->dst_per = hs_no;
+	trans->dst_width = DW_DMA_SLAVE_WIDTH_8BIT;
+	trans->fc_mode = DMA_M2P;
+
+	trans->src_add = (rt_uint32_t)spi_control->dma.tx_dummy_buff;
+
+	trans->src_inc_mode = DW_DMA_SLAVE_INC;
+	trans->src_msize = DW_DMA_SLAVE_MSIZE_1;
+
+	trans->src_width = DW_DMA_SLAVE_WIDTH_8BIT;
+	trans->trans_len = current_message->length;
+
+
+	trans->complete_callback = (void *)xfer_dma_done;
+	trans->complete_para = (void *)spi_control;
+
+
+
+
+}
+
+void dma_set_rx_data(struct spi_controller *spi_control){
+
+	struct dma_transfer *trans;
+	rt_uint32_t hs_no;
+	struct rt_spi_message* current_message = spi_control->current_message;
+	trans = &spi_control->dma.rx_trans;
+	hs_no = spi_control->dma.rx_hs;
+
+	struct fh_spi_obj *spi_obj;
+	spi_obj = &spi_control->obj;
+
+	if(current_message->length > MALLOC_DMA_MEM_SIZE){
+		rt_kprintf("[spi_dma]message len too large..len is %d\n",current_message->length);
+		RT_ASSERT(current_message->length <= MALLOC_DMA_MEM_SIZE);
+	}
+
+
+	//rt_memset((void *)spi_control->dma.rx_dummy_buff,0,MALLOC_DMA_MEM_SIZE);
+
+	trans->dma_number = 0;
+	trans->fc_mode = DMA_P2M;
+
+	trans->dst_add = (rt_uint32_t)spi_control->dma.rx_dummy_buff;
+	trans->dst_inc_mode = DW_DMA_SLAVE_INC;
+	trans->dst_msize = DW_DMA_SLAVE_MSIZE_1;
+	trans->dst_width = DW_DMA_SLAVE_WIDTH_8BIT;
+
+
+
+	trans->src_add = (rt_uint32_t)(spi_obj->base + OFFSET_SPI_DR);
+	trans->src_inc_mode = DW_DMA_SLAVE_FIX;
+	trans->src_msize = DW_DMA_SLAVE_MSIZE_1;
+	trans->src_width = DW_DMA_SLAVE_WIDTH_8BIT;
+	trans->src_hs = DMA_HW_HANDSHAKING;
+	trans->src_per = hs_no;
+	trans->trans_len = current_message->length;
+
+
+
+	trans->complete_callback = (void *)xfer_dma_done;
+	trans->complete_para = (void *)spi_control;
+
+
+}
+
+
+rt_uint32_t xfer_data_dma(struct spi_controller *spi_control){
+	int ret;
+
+	struct fh_spi_obj *spi_obj;
+	spi_obj = &spi_control->obj;
+
+	struct rt_dma_device *dma_dev = spi_control->dma.dma_dev;
+
+
+	//tx data prepare
+	dma_set_tx_data(spi_control);
+	//rx data prepare
+	dma_set_rx_data(spi_control);
+	//dma go...
+
+
+	SPI_Enable(spi_obj,0);
+
+	//SPI_WriteTxDmaLevel(spi_obj,SPI_FIFO_DEPTH / 4);
+	SPI_WriteTxDmaLevel(spi_obj,1);
+	//SPI_WriteTxDmaLevel(spi_obj,0);
+	SPI_WriteRxDmaLevel(spi_obj,0);
+	SPI_EnableDma(spi_obj,SPI_TX_DMA|SPI_RX_DMA);
+	SPI_Enable(spi_obj,1);
+
+	dma_dev->ops->control(dma_dev,RT_DEVICE_CTRL_DMA_SINGLE_TRANSFER,(void *)&spi_control->dma.rx_trans);
+	dma_dev->ops->control(dma_dev,RT_DEVICE_CTRL_DMA_SINGLE_TRANSFER,(void *)&spi_control->dma.tx_trans);
+
+	ret = rt_completion_wait(&spi_control->transfer_completion, RT_TICK_PER_SECOND*50);
+	//release channel..
+
+	//dma_dev->ops->control(dma_dev,RT_DEVICE_CTRL_DMA_RELEASE_CHANNEL,(void *)&spi_control->dma.tx_trans);
+	//dma_dev->ops->control(dma_dev,RT_DEVICE_CTRL_DMA_RELEASE_CHANNEL,(void *)&spi_control->dma.rx_trans);
+
+	if(ret)
+	{
+		rt_kprintf("ERROR: %s, transfer timeout\n", __func__);
+		return -RT_ETIMEOUT;
+	}
+
+	return RT_EOK;
+}
+
+rt_uint32_t xfer_data_isr(struct spi_controller *spi_control){
+
+	int ret;
+	struct fh_spi_obj *spi_obj;
+	spi_obj = &spi_control->obj;
+    SPI_SetTxLevel(spi_obj, SPI_FIFO_DEPTH / 2);
+    SPI_EnableInterrupt(spi_obj, SPI_IRQ_TXEIM);
+	ret = rt_completion_wait(&spi_control->transfer_completion, RT_TICK_PER_SECOND*50);
+	if(ret)
+	{
+		rt_kprintf("ERROR: %s, transfer timeout\n", __func__);
+		return -RT_ETIMEOUT;
+	}
+
+	return RT_EOK;
+}
+
+
+void fix_spi_xfer_mode(struct spi_controller *spi_control){
+	 //switch dma or isr....first check dma ...is error .use isr xfer...
+	struct rt_dma_device * rt_dma_dev;
+	struct dma_transfer *tx_trans;
+	struct dma_transfer *rx_trans;
+	int ret;
+	//retry to check if the dma status...
+	if(spi_control->dma.dma_flag == DMA_BIND_OK){
+		//if transfer data too short...use isr..
+		if(spi_control->current_message->length < DMA_OR_ISR_THRESHOLD){
+			spi_control->xfer_mode = XFER_USE_ISR;
+			return;
+		}
+#if(0)
+		rt_dma_dev = spi_control->dma.dma_dev;
+		//first request channel
+
+		tx_trans = &spi_control->dma.tx_trans;
+		rx_trans = &spi_control->dma.rx_trans;
+		tx_trans->channel_number = TX_DMA_CHANNEL;
+		rx_trans->channel_number = RX_DMA_CHANNEL;
+
+
+		ret = rt_dma_dev->ops->control(rt_dma_dev,RT_DEVICE_CTRL_DMA_REQUEST_CHANNEL,(void *)tx_trans);
+		if(ret != RT_EOK){
+			spi_control->xfer_mode = XFER_USE_ISR;
+			return;
+		}
+
+		ret = rt_dma_dev->ops->control(rt_dma_dev,RT_DEVICE_CTRL_DMA_REQUEST_CHANNEL,(void *)rx_trans);
+		if(ret != RT_EOK){
+			//release tx channel...
+			rt_dma_dev->ops->control(rt_dma_dev,RT_DEVICE_CTRL_DMA_RELEASE_CHANNEL,(void *)&tx_trans);
+			spi_control->xfer_mode = XFER_USE_ISR;
+			return;
+		}
+#endif
+		spi_control->xfer_mode = XFER_USE_DMA;
+		//if error use isr mode
+	}
+	else
+		spi_control->xfer_mode = XFER_USE_ISR;
+
+
+
+
+}
+
+static rt_uint32_t fh_spi_xfer(struct rt_spi_device* device, struct rt_spi_message* message)
+{
+
+    struct spi_slave_info *spi_slave;
+    struct spi_controller *spi_control;
+    struct fh_spi_obj *spi_obj;
+    int ret;
+    rt_uint32_t slave_id;
+    spi_slave = ( struct spi_slave_info *)fh_get_spi_dev_pri_data(device);
+    spi_control = spi_slave->control;
+    spi_obj = &spi_control->obj;
+    spi_control->transfered_len = 0;
+    spi_control->received_len = 0;
+
+	rt_sem_take(&spi_control->xfer_lock, RT_WAITING_FOREVER);
+
+    rt_completion_init(&spi_control->transfer_completion);
+
+    spi_control->current_message = message;
+    /* take CS */
+    if(message->cs_take)
+    {
+    	if(spi_slave->plat_slave.actice_level == ACTIVE_LOW)
+    		gpio_direction_output(spi_slave->plat_slave.cs_pin, 0);
+    	else
+    		gpio_direction_output(spi_slave->plat_slave.cs_pin, 1);
+
+    	//here will always use the slave_0 because that the cs is gpio...
+    	SPI_EnableSlaveen(spi_obj, 0);
+    }
+
+    //fix transfer mode .....
+    fix_spi_xfer_mode(spi_control);
+
+
+	switch(spi_control->xfer_mode){
+	case XFER_USE_DMA:
+		PRINT_SPI_DBG("use dma xfer.....###############\n");
+		ret = xfer_data_dma(spi_control);
+		if(ret == RT_EOK){
+			break;
+		}
+		else{
+			//use the isr mode to transfer
+			spi_control->xfer_mode = XFER_USE_ISR;
+			rt_kprintf("%s dma transfer error no:%x\n",__func__,ret);
+		}
+	case XFER_USE_ISR:
+		PRINT_SPI_DBG("use isr xfer.....&&&&&&&&&&&&&\n");
+		ret = xfer_data_isr(spi_control);
+		if(ret != RT_EOK)
+			rt_kprintf("%s isr transfer error no:%x\n",__func__,ret);
+		break;
+
+	default:
+		rt_kprintf("%s unknow xfer func...\n",__func__);
+		while(1)
+			;
+	}
+
+    /* release CS */
+    if(message->cs_release)
+    {
+    	if(spi_slave->plat_slave.actice_level == ACTIVE_LOW)
+    		gpio_direction_output(spi_slave->plat_slave.cs_pin, 1);
+    	else
+    		gpio_direction_output(spi_slave->plat_slave.cs_pin, 0);
+    	SPI_DisableSlaveen(spi_obj, 0);
+    }
+
+    rt_sem_release(&spi_control->xfer_lock);
+    PRINT_SPI_DBG("%s end\n", __func__);
+
+    return message->length;
+}
+
+static struct rt_spi_ops fh_spi_ops =
+{
+
+    .configure  = fh_spi_configure,
+    .xfer       = fh_spi_xfer,
+
+};
+
+
+static void fh_spi_interrupt(int irq, void *param)
+{
+
+
+    struct spi_controller *spi_control;
+    struct fh_spi_obj *spi_obj;
+
+    spi_control = (struct spi_controller *)param;
+    spi_obj = &spi_control->obj;
+    rt_uint32_t rx_fifo_capability,tx_fifo_capability;
+    rt_uint8_t data = 0;
+    rt_uint8_t *p;
+    rt_uint32_t status;
+
+//
+
+	if(spi_control->current_message == RT_NULL){
+		rt_kprintf("ERROR: %s, current_message is incorrect\n", __func__);
+	}
+
+	status =  SPI_InterruptStatus(spi_obj);
+	PRINT_SPI_DBG("status: 0x%x\n", status);
+	//fixme: ??recv overflow, underflow; tran overflow??
+	if(status & SPI_ISR_ERROR){
+		rt_kprintf("ERROR: %s, status=%d\n", __func__, status);
+		SPI_ClearInterrupt(spi_obj);
+		//fixme: handle error
+		return;
+	}
+
+	rx_fifo_capability = SPI_ReadRxFifoLevel(spi_obj);
+	tx_fifo_capability = MIN(
+			(SPI_FIFO_DEPTH - SPI_ReadTxFifoLevel(spi_obj)) / 2,
+			(spi_control->current_message->length - spi_control->transfered_len));
+
+
+	PRINT_SPI_DBG("rx_fifo_capability=%d\n", rx_fifo_capability);
+
+	//rx
+	spi_control->received_len += rx_fifo_capability;
+	while(rx_fifo_capability)
+	{
+		data = SPI_ReadData(spi_obj);
+		if(spi_control->current_message->recv_buf){
+			*(rt_uint8_t *)spi_control->current_message->recv_buf++ = data;
+		}
+		PRINT_SPI_DBG("rx, data: 0x%x\n", data);
+		//rt_kprintf("rx, data: 0x%x\n", data);
+		rx_fifo_capability--;
+	}
+
+	if(spi_control->received_len == spi_control->current_message->length)
+	{
+
+		//rt_kprintf("asdasdq4902834908dklfkldjsdhgkljshfgljkhsgfkljhsdfkljghklj");
+		SPI_DisableInterrupt(spi_obj, SPI_ISR_FLAG);
+		PRINT_SPI_DBG("finished, length=%d, received_len=%d\n", spi_control->current_message->length, spi_control->received_len);
+		rt_completion_done(&spi_control->transfer_completion);
+
+
+		return;
+	}
+
+	//tx
+
+	spi_control->transfered_len +=tx_fifo_capability;
+	if(spi_control->current_message->send_buf){
+		p = (rt_uint8_t *)spi_control->current_message->send_buf;
+		while(tx_fifo_capability){
+			PRINT_SPI_DBG("tx, data: 0x%x\n", *p);
+			//rt_kprintf("tx, data: 0x%x\n", *p);
+			SPI_WriteData(spi_obj, *p++);
+			tx_fifo_capability--;
+		}
+		spi_control->current_message->send_buf = p;
+	}
+	else{
+		while(tx_fifo_capability){
+
+			SPI_WriteData(spi_obj, 0xff);
+			tx_fifo_capability--;
+		}
+	}
+
+
+
+}
+
+
+int fh_spi_probe(void *priv_data)
+{
+    char spi_dev_name[20] = {0};
+    char spi_bus_name[20] = {0};
+    char spi_isr_name[20] = {0};
+    char spi_lock_name[20] = {0};
+
+    struct spi_slave_info *spi_slave;
+    struct spi_slave_info *next_slave;
+
+    struct spi_slave_info **control_slave;
+
+    struct spi_controller *spi_control;
+    struct spi_control_platform_data *plat_data;
+    int i,ret;
+
+	struct rt_dma_device * rt_dma_dev;
+	struct dma_transfer *tx_trans;
+	struct dma_transfer *rx_trans;
+
+    //check data...
+    plat_data = (struct spi_control_platform_data *)priv_data;
+
+    if(!plat_data){
+		rt_kprintf("ERROR:platform data null...\n");
+		return -RT_ENOMEM;
+    }
+    if(plat_data->slave_no > FH_SPI_SLAVE_MAX_NO){
+    	rt_kprintf("ERROR:spi controller not support %d slave..\n",plat_data->slave_no);
+    	return -RT_ENOMEM;
+    }
+
+
+    //malloc data
+    spi_control = (struct spi_controller*)rt_malloc(sizeof(struct spi_controller));
+    if(!spi_control){
+    	rt_kprintf("ERROR:no mem for malloc the spi controller..\n");
+    	goto error_malloc_bus;
+    }
+
+    rt_memset(spi_control, 0, sizeof(struct spi_controller));
+    //parse platform control data
+    spi_control->base = plat_data->base;
+    spi_control->id = plat_data->id;
+    spi_control->irq = plat_data->irq;
+    spi_control->max_hz = plat_data->max_hz;
+    spi_control->slave_no = plat_data->slave_no;
+    spi_control->obj.base = plat_data->base;
+    spi_control->clk_in = plat_data->clk_in;
+    spi_control->plat_data = plat_data;
+
+    rt_sprintf(spi_lock_name, "%s%d", "spi_lock", spi_control->id);
+    rt_sem_init(&spi_control->xfer_lock, spi_lock_name, 1, RT_IPC_FLAG_FIFO);
+
+    rt_sprintf(spi_bus_name, "%s%d", "spi_bus", spi_control->id);
+
+    ret = rt_spi_bus_register(&spi_control->spi_bus, spi_bus_name, &fh_spi_ops);
+
+    PRINT_SPI_DBG("bus name is :%s\n",spi_bus_name);
+
+    //isr...
+    rt_sprintf(spi_isr_name, "%s%d", "ssi_isr", spi_control->id);
+    rt_hw_interrupt_install(spi_control->irq, fh_spi_interrupt,
+                                   (void *)spi_control, spi_isr_name);
+
+    rt_hw_interrupt_umask(spi_control->irq);
+    PRINT_SPI_DBG("isr name is :%s\n",spi_isr_name);
+
+    //check dma ....
+    if(plat_data->transfer_mode == USE_DMA_TRANSFER){
+
+        spi_control->dma.dma_dev = (struct rt_dma_device *)rt_device_find(plat_data->dma_name);
+    	if(spi_control->dma.dma_dev == RT_NULL){
+    		rt_kprintf("can't find dma dev\n");
+    		//goto error_malloc_slave;
+    		//spi_control->dma_xfer_flag = USE_ISR_TRANSFER;
+//    		spi_control->dma.dma_flag = DMA_BIND_ERROR;
+//    		spi_control->xfer_mode = XFER_USE_ISR;
+    		goto BIND_DMA_ERROR;
+    	}
+    	else{
+
+			spi_control->dma.control = spi_control;
+			spi_control->dma.rx_hs = plat_data->rx_hs_no;
+			spi_control->dma.tx_hs = plat_data->tx_hs_no;
+			spi_control->dma.dma_name = plat_data->dma_name;
+
+			spi_control->dma.rx_dummy_buff = fh_dma_mem_malloc(MALLOC_DMA_MEM_SIZE);
+			if(!spi_control->dma.rx_dummy_buff){
+				rt_kprintf("malloc rx dma buff failed...\n");
+				//spi_control->xfer_mode = XFER_USE_ISR;
+				goto BIND_DMA_ERROR;
+			}
+
+
+
+			spi_control->dma.tx_dummy_buff = fh_dma_mem_malloc(MALLOC_DMA_MEM_SIZE);
+			if(!spi_control->dma.tx_dummy_buff){
+				rt_kprintf("malloc tx dma buff failed...\n");
+				fh_dma_mem_free(spi_control->dma.rx_dummy_buff);
+				//spi_control->xfer_mode = XFER_USE_ISR;
+				goto BIND_DMA_ERROR;
+			}
+
+			if(((rt_uint32_t)spi_control->dma.tx_dummy_buff % 4)||((rt_uint32_t)spi_control->dma.rx_dummy_buff % 4)){
+				rt_kprintf("dma malloc buff not allign..\n");
+				fh_dma_mem_free(spi_control->dma.rx_dummy_buff);
+				fh_dma_mem_free(spi_control->dma.tx_dummy_buff);
+				goto BIND_DMA_ERROR;
+			}
+
+	    	//open dma dev.
+	    	spi_control->dma.dma_dev->ops->control(spi_control->dma.dma_dev,RT_DEVICE_CTRL_DMA_OPEN,RT_NULL);
+
+	    	//request channel
+	    	rt_dma_dev = spi_control->dma.dma_dev;
+			//first request channel
+			tx_trans = &spi_control->dma.tx_trans;
+			rx_trans = &spi_control->dma.rx_trans;
+			tx_trans->channel_number = TX_DMA_CHANNEL;
+			rx_trans->channel_number = RX_DMA_CHANNEL;
+
+			ret = rt_dma_dev->ops->control(rt_dma_dev,RT_DEVICE_CTRL_DMA_REQUEST_CHANNEL,(void *)tx_trans);
+			if(ret != RT_EOK){
+				goto BIND_DMA_ERROR;
+			}
+
+			ret = rt_dma_dev->ops->control(rt_dma_dev,RT_DEVICE_CTRL_DMA_REQUEST_CHANNEL,(void *)rx_trans);
+			if(ret != RT_EOK){
+				//release tx channel...
+				rt_dma_dev->ops->control(rt_dma_dev,RT_DEVICE_CTRL_DMA_RELEASE_CHANNEL,(void *)&tx_trans);
+				goto BIND_DMA_ERROR;
+			}
+
+	    	//spi_control->xfer_mode = XFER_USE_DMA;
+	    	spi_control->dma.dma_flag = DMA_BIND_OK;
+    	}
+    }
+    else{
+
+BIND_DMA_ERROR:
+			spi_control->dma.dma_flag = DMA_BIND_ERROR;
+			//spi_control->xfer_mode = XFER_USE_ISR;
+    }
+
+
+
+
+    control_slave = &spi_control->spi_slave;
+    for(i=0;i<plat_data->slave_no;i++){
+    	spi_slave = (struct spi_slave_info*)rt_malloc(sizeof(struct spi_slave_info));
+    	if(!spi_slave){
+    		rt_kprintf("ERROR:no mem for malloc the spi_slave%d..\n",i);
+    		goto error_malloc_slave;
+    	}
+    	rt_memset(spi_slave, 0, sizeof(struct spi_slave_info));
+
+    	//parse platform data...
+    	spi_slave->id = i;
+    	//bind to the spi control....will easy to find all the data...
+    	spi_slave->control = spi_control;
+    	spi_slave->plat_slave.cs_pin = plat_data->plat_slave[i].cs_pin;
+    	spi_slave->plat_slave.actice_level = plat_data->plat_slave[i].actice_level;
+    	rt_sprintf(spi_dev_name, "%s%d%s%d", "ssi", spi_control->id,"_",spi_slave->id);
+
+    	*control_slave = spi_slave;
+    	control_slave = &spi_slave->next;
+
+    	//register slave dev...
+    	ret = rt_spi_bus_attach_device(&spi_slave->spi_device,spi_dev_name,spi_bus_name,spi_slave);
+    	if(ret != RT_EOK){
+    		rt_kprintf("register dev to bus failed...\n");
+    		goto error_malloc_slave;
+    	}
+
+    }
+
+
+
+    //request gpio...
+	spi_slave = spi_control->spi_slave;
+	while(spi_slave != RT_NULL)
+	{
+		next_slave = spi_slave->next;
+
+		ret = gpio_request(spi_slave->plat_slave.cs_pin);
+		if(ret!=0){
+			rt_kprintf("request gpio_%d failed...\n",spi_slave->plat_slave.cs_pin);
+			goto error_malloc_slave;
+		}
+
+
+		PRINT_SPI_DBG("spi_slave info addr:%x,id:%d,cs:%d,active:%d\n",(rt_uint32_t)spi_slave, spi_slave->id,
+				spi_slave->plat_slave.cs_pin,
+				spi_slave->plat_slave.actice_level);
+		spi_slave = next_slave;
+	}
+
+	//this will be used in platform exit..
+	plat_data->control = spi_control;
+    return RT_EOK;
+
+error_malloc_slave:
+	//free the slaveinfo already malloc
+	spi_slave = spi_control->spi_slave;
+	while(spi_slave != RT_NULL)
+	{
+		next_slave = spi_slave->next;
+		gpio_release(spi_slave->plat_slave.cs_pin);
+		rt_free(spi_slave);
+		spi_slave = next_slave;
+	}
+	//mask isr
+	rt_hw_interrupt_mask(spi_control->irq);
+	//release sem ..
+	rt_sem_detach(&spi_control->xfer_lock);
+
+	//free the control malloc .
+	rt_free(spi_control);
+
+	//fixme:unregister spi_bus...
+
+error_malloc_bus:
+	return -RT_ENOMEM;
+
+
+
+
+
+}
+
+int fh_spi_exit(void *priv_data)
+{
+
+    struct spi_controller *spi_control;
+    struct spi_control_platform_data *plat_data;
+    struct spi_slave_info *spi_slave;
+    struct spi_slave_info *next_slave;
+
+    plat_data = (struct spi_control_platform_data *)priv_data;
+    spi_control = plat_data->control;
+	spi_slave = spi_control->spi_slave;
+
+	while(spi_slave != RT_NULL)
+	{
+		next_slave = spi_slave->next;
+		gpio_release(spi_slave->plat_slave.cs_pin);
+		rt_free(spi_slave);
+		spi_slave = next_slave;
+	}
+	//mask isr
+	rt_hw_interrupt_mask(spi_control->irq);
+	//release sem ..
+	rt_sem_detach(&spi_control->xfer_lock);
+
+	//free the control malloc .
+	rt_free(spi_control);
+    //fixme free all the malloc data ...
+
+    return 0;
+}
+
+struct fh_board_ops spi_driver_ops =
+{
+
+        .probe = fh_spi_probe,
+        .exit = fh_spi_exit,
+
+};
+
+void rt_hw_spi_init(void)
+{
+
+    int ret;
+
+  //  rt_kprintf("%s start\n", __func__);
+    PRINT_SPI_DBG("%s start\n", __func__);
+    fh_board_driver_register("spi", &spi_driver_ops);
+    PRINT_SPI_DBG("%s end\n", __func__);
+    //fixme: never release?
+
+}
+#if(0)
+#define TEST_SPI_BUFF_SIZE			0x100
+static rt_uint8_t tx_buf[TEST_SPI_BUFF_SIZE] = {0};
+static rt_uint8_t rx_buf[TEST_SPI_BUFF_SIZE] = {0};
+int ssi_test(void){
+	struct rt_spi_device * rt_spi_device;
+
+	int ret;
+	rt_spi_device = (struct rt_spi_device *)rt_device_find("ssi1_0");
+
+	if(rt_spi_device == RT_NULL)
+	{
+		rt_kprintf("%s spi device %s not found!\r\n",__func__ ,"ssi1_0");
+		return -RT_ENOSYS;
+	}
+
+    /* config spi */
+    {
+        struct rt_spi_configuration cfg;
+        cfg.data_width = 8;
+        cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0 and Mode 3 */
+        cfg.max_hz = 50 * 1000 * 1000; /* 50M */
+        rt_spi_configure(rt_spi_device, &cfg);
+    }
+    rt_memset(tx_buf,0x55,TEST_SPI_BUFF_SIZE);
+
+    rt_spi_transfer(rt_spi_device,tx_buf,rx_buf,TEST_SPI_BUFF_SIZE);
+
+
+    ret = rt_memcmp(tx_buf,rx_buf,TEST_SPI_BUFF_SIZE);
+    if(ret != 0){
+    	rt_kprintf("compare error ..error data %x\n",ret);
+    }
+    rt_kprintf("test done \n");
+    return 0;
+}
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+FINSH_FUNCTION_EXPORT(ssi_test, fh_ssi_test);
+#endif
+#endif

+ 134 - 0
bsp/fh8620/drivers/ssi.h

@@ -0,0 +1,134 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef SSI_H_
+#define SSI_H_
+#include "Libraries/inc/fh_driverlib.h"
+#include <drivers/spi.h>
+#include <rtdevice.h>
+#include "fh_dma.h"
+#define SPI_PRIV(drv)   ( (struct fh_spi_obj)(drv->priv) )
+
+#define FH_SPI_SLAVE_MAX_NO			2
+
+struct spi_controller;
+//platform use below
+struct spi_slave_platform_data{
+
+	rt_uint32_t cs_pin;
+#define ACTIVE_LOW			1
+#define ACTIVE_HIGH			2
+	rt_uint32_t actice_level;
+};
+
+
+struct spi_control_platform_data{
+	rt_uint32_t id;
+	rt_uint32_t irq;
+	rt_uint32_t base;
+	rt_uint32_t max_hz;
+	rt_uint32_t slave_no;
+	rt_uint32_t clk_in;
+	//handshake no...
+	rt_uint32_t rx_hs_no;
+	rt_uint32_t tx_hs_no;
+
+	char *dma_name;
+	//isr will be the default...
+#define USE_ISR_TRANSFER			0
+#define USE_DMA_TRANSFER			1
+	rt_uint32_t transfer_mode;
+	struct spi_controller *control;
+	struct spi_slave_platform_data plat_slave[FH_SPI_SLAVE_MAX_NO];
+
+};
+
+
+struct spi_controller;
+//driver use below.......
+struct spi_slave_info
+{
+    struct rt_spi_device spi_device;
+    struct spi_controller *control;
+    struct spi_slave_platform_data plat_slave;
+    rt_uint32_t id;
+    //spi control will use to find all the slave info..
+    struct spi_slave_info *next;
+};
+
+struct spi_dma
+{
+	char *dma_name;
+#define DMA_BIND_OK			0
+#define DMA_BIND_ERROR		1
+	rt_uint32_t dma_flag;
+    //bind to the dma dev..
+	rt_uint32_t rx_hs;
+	rt_uint32_t tx_hs;
+	rt_uint8_t *rx_dummy_buff;
+	rt_uint8_t *tx_dummy_buff;
+    struct rt_dma_device *dma_dev;
+    struct dma_transfer tx_trans;
+    struct dma_transfer rx_trans;
+    struct spi_controller *control;
+};
+
+struct spi_controller
+{
+	rt_uint32_t id;
+	rt_uint32_t irq;
+	rt_uint32_t base;
+	rt_uint32_t max_hz;
+	rt_uint32_t slave_no;
+	rt_uint32_t clk_in;
+	//bind to the platform data....
+	struct spi_control_platform_data *plat_data;
+
+	//rt_uint32_t dma_xfer_flag;
+
+#define XFER_USE_ISR		0
+#define XFER_USE_DMA		1
+	rt_uint32_t xfer_mode;
+
+	struct spi_dma dma;
+	rt_uint32_t dma_complete_times;
+    struct rt_spi_bus spi_bus;
+    struct spi_slave_info *spi_slave;
+    struct rt_spi_message* current_message;
+    struct rt_completion transfer_completion;
+	struct rt_semaphore xfer_lock;
+    struct fh_spi_obj obj;
+    rt_uint32_t received_len;
+    rt_uint32_t transfered_len;
+    void*  priv;
+};
+
+
+
+
+void rt_hw_spi_init(void);
+
+#endif /* SPI_H_ */

+ 197 - 0
bsp/fh8620/drivers/trap.c

@@ -0,0 +1,197 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#include <rthw.h>
+#include <armv6.h>
+#include "fh_arch.h"
+#include "interrupt.h"
+#include "Libraries/inc/fh_ictl.h"
+/**
+ * @addtogroup FH81
+ */
+/*@{*/
+
+extern struct rt_thread *rt_current_thread;
+#ifdef RT_USING_FINSH
+extern long list_thread(void);
+#endif
+
+/**
+ * this function will show registers of CPU
+ *
+ * @param regs the registers point
+ */
+
+void rt_hw_show_register (struct rt_hw_register *regs)
+{
+	rt_kprintf("Execption:\n");
+	rt_kprintf("r00:0x%08x r01:0x%08x r02:0x%08x r03:0x%08x\n", regs->r0, regs->r1, regs->r2, regs->r3);
+	rt_kprintf("r04:0x%08x r05:0x%08x r06:0x%08x r07:0x%08x\n", regs->r4, regs->r5, regs->r6, regs->r7);
+	rt_kprintf("r08:0x%08x r09:0x%08x r10:0x%08x\n", regs->r8, regs->r9, regs->r10);
+	rt_kprintf("fp :0x%08x ip :0x%08x\n", regs->fp, regs->ip);
+	rt_kprintf("sp :0x%08x lr :0x%08x pc :0x%08x\n", regs->sp, regs->lr, regs->pc);
+	rt_kprintf("cpsr:0x%08x\n", regs->cpsr);
+}
+
+/**
+ * When ARM7TDMI comes across an instruction which it cannot handle,
+ * it takes the undefined instruction trap.
+ *
+ * @param regs system registers
+ *
+ * @note never invoke this function in application
+ */
+void rt_hw_trap_udef(struct rt_hw_register *regs)
+{
+	rt_hw_show_register(regs);
+
+	rt_kprintf("undefined instruction\n");
+	rt_kprintf("thread - %s stack:\n", rt_current_thread->name);
+
+#ifdef RT_USING_FINSH
+	list_thread();
+#endif
+	rt_hw_cpu_shutdown();
+}
+
+/**
+ * The software interrupt instruction (SWI) is used for entering
+ * Supervisor mode, usually to request a particular supervisor
+ * function.
+ *
+ * @param regs system registers
+ *
+ * @note never invoke this function in application
+ */
+void rt_hw_trap_swi(struct rt_hw_register *regs)
+{
+	rt_hw_show_register(regs);
+
+	rt_kprintf("software interrupt\n");
+	rt_hw_cpu_shutdown();
+}
+
+/**
+ * An abort indicates that the current memory access cannot be completed,
+ * which occurs during an instruction prefetch.
+ *
+ * @param regs system registers
+ *
+ * @note never invoke this function in application
+ */
+void rt_hw_trap_pabt(struct rt_hw_register *regs)
+{
+	rt_hw_show_register(regs);
+
+	rt_kprintf("prefetch abort\n");
+	rt_kprintf("thread - %s stack:\n", rt_current_thread->name);
+
+#ifdef RT_USING_FINSH
+	list_thread();
+#endif
+	rt_hw_cpu_shutdown();
+}
+
+/**
+ * An abort indicates that the current memory access cannot be completed,
+ * which occurs during a data access.
+ *
+ * @param regs system registers
+ *
+ * @note never invoke this function in application
+ */
+void rt_hw_trap_dabt(struct rt_hw_register *regs)
+{
+	rt_hw_show_register(regs);
+
+	rt_kprintf("data abort\n");
+	rt_kprintf("thread - %s stack:\n", rt_current_thread->name);
+
+#ifdef RT_USING_FINSH
+	list_thread();
+#endif
+	rt_hw_cpu_shutdown();
+}
+
+/**
+ * Normally, system will never reach here
+ *
+ * @param regs system registers
+ *
+ * @note never invoke this function in application
+ */
+void rt_hw_trap_resv(struct rt_hw_register *regs)
+{
+	rt_kprintf("not used\n");
+	rt_hw_show_register(regs);
+	rt_hw_cpu_shutdown();
+}
+
+extern struct rt_irq_desc irq_desc[];
+
+void rt_hw_trap_irq()
+{
+	rt_isr_handler_t isr_func;
+	rt_uint32_t irqstat_l, irqstat_h, irq;
+	void *param;
+
+	fh_intc *p = (fh_intc *)INTC_REG_BASE;
+
+	irqstat_l = p->IRQ_FINALSTATUS_L;
+	irqstat_h = p->IRQ_FINALSTATUS_H;
+	if (irqstat_l)
+	{
+		irq = __rt_ffs(irqstat_l) - 1;
+	}
+	else if(irqstat_h)
+	{
+		irq = __rt_ffs(irqstat_h) - 1 + 32;
+	}
+	else
+	{
+		rt_kprintf("No interrupt occur\n");
+		return;
+	}
+
+	/* get interrupt service routine */
+	isr_func = irq_desc[irq].handler;
+	param = irq_desc[irq].param;
+
+	/* turn to interrupt service routine */
+	if(isr_func){
+		isr_func(irq, param);
+	}
+#ifdef RT_USING_INTERRUPT_INFO
+    irq_desc[irq].counter ++;
+#endif
+}
+
+void rt_hw_trap_fiq()
+{
+	rt_kprintf("fast interrupt request\n");
+}
+
+/*@}*/

+ 292 - 0
bsp/fh8620/drivers/uart.c

@@ -0,0 +1,292 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#include <board.h>
+#include <rtdevice.h>
+#include "fh_arch.h"
+#include "Libraries/inc/fh_uart.h"
+
+
+void rt_fh_uart_handler(int vector, void *param)
+{
+	int status;
+	unsigned int ret;
+	struct fh_uart *uart;
+	unsigned int reg_status;
+	rt_device_t dev = (rt_device_t)param;
+	uart = (struct fh_uart *)dev->user_data;
+	status = uart_get_iir_status(uart->uart_port);
+	if (status & UART_IIR_NOINT)
+	{
+		return;
+	}
+	if(status & UART_IIR_THREMPTY){
+		//first close tx isr
+		uart_disable_irq(uart->uart_port,UART_IER_ETBEI);
+
+		rt_hw_serial_isr((struct rt_serial_device *)dev, RT_SERIAL_EVENT_TX_DONE);
+	}
+	else if((status & UART_IIR_CHRTOUT)==UART_IIR_CHRTOUT){
+		//bug....
+		//if no data in rx fifo
+		reg_status = uart_get_status(uart->uart_port);
+		if((reg_status & 1<<3) == 0)
+			ret = uart_getc(uart->uart_port);
+	}
+	else{
+		rt_interrupt_enter();
+		rt_hw_serial_isr((struct rt_serial_device *)dev, RT_SERIAL_EVENT_RX_IND);
+		rt_interrupt_leave();
+	}
+}
+
+/**
+* UART device in RT-Thread
+*/
+static rt_err_t fh_uart_configure(struct rt_serial_device *serial,
+                                struct serial_configure *cfg)
+{
+	int div;
+	enum data_bits data_mode;
+	enum stop_bits stop_mode;
+	enum parity parity_mode;
+	struct fh_uart *uart;
+
+	RT_ASSERT(serial != RT_NULL);
+    RT_ASSERT(cfg != RT_NULL);
+	uart = (struct fh_uart *)serial->parent.user_data;
+
+	switch (cfg->data_bits)
+	{
+	case DATA_BITS_8:
+		data_mode = UART_DATA_BIT8;
+		break;
+	case DATA_BITS_7:
+		data_mode = UART_DATA_BIT7;
+		break;
+	case DATA_BITS_6:
+		data_mode = UART_DATA_BIT6;
+		break;
+	case DATA_BITS_5:
+		data_mode = UART_DATA_BIT5;
+		break;
+	default:
+		data_mode = UART_DATA_BIT8;
+		break;
+	}
+
+	switch (cfg->stop_bits)
+	{
+	case STOP_BITS_2:
+		stop_mode = UART_STOP_BIT2;
+		break;
+	case STOP_BITS_1:
+	default:
+		stop_mode = UART_STOP_BIT1;
+		break;
+	}
+
+	switch (cfg->parity)
+	{
+	case PARITY_ODD:
+		parity_mode = UART_PARITY_ODD;
+		break;
+	case PARITY_EVEN:
+		parity_mode = UART_PARITY_EVEN;
+		break;
+	case PARITY_NONE:
+	default:
+		parity_mode = UART_PARITY_NONE;
+		break;
+	}
+
+    uart_disable_irq(uart->uart_port, UART_IER_ERBFI);
+
+	uart_configure(uart->uart_port, data_mode,
+					stop_mode, parity_mode,
+					cfg->baud_rate, UART_CLOCK_FREQ);
+
+	uart_enable_irq(uart->uart_port, UART_IER_ERBFI);
+
+    return RT_EOK;
+}
+
+static rt_err_t fh_uart_control(struct rt_serial_device *serial,
+                              int cmd, void *arg)
+{
+    struct fh_uart* uart;
+
+    RT_ASSERT(serial != RT_NULL);
+    uart = (struct fh_uart *)serial->parent.user_data;
+
+    switch (cmd)
+    {
+    case RT_DEVICE_CTRL_CLR_INT:
+        /* disable rx irq */
+		rt_hw_interrupt_mask(uart->irq);
+		uart_disable_irq(uart->uart_port,UART_IER_ERBFI);
+        break;
+    case RT_DEVICE_CTRL_SET_INT:
+        /* enable rx irq */
+		rt_hw_interrupt_umask(uart->irq);
+		uart_enable_irq(uart->uart_port,UART_IER_ERBFI);
+        break;
+    }
+
+    return RT_EOK;
+}
+
+static int fh_uart_putc(struct rt_serial_device *serial, char c)
+{
+	struct fh_uart *uart = serial->parent.user_data;
+	unsigned int ret;
+	ret = uart_get_status(uart->uart_port);
+	if(serial->parent.open_flag & RT_DEVICE_FLAG_INT_TX){
+		//RT_DEVICE_FLAG_INT_TX
+
+		if(c == '\n'){
+			fh_uart_putc(serial,'\r');
+		}
+		if(ret & UART_USR_TFNF){
+			uart_putc(uart->uart_port, c);
+			return 1;
+		}
+		//open tx isr here..
+		uart_enable_irq(uart->uart_port,UART_IER_ETBEI);
+	    return -1;
+	}
+	//poll mode
+	else{
+
+		while(!(uart_get_status(uart->uart_port) & UART_USR_TFNF))
+			;
+		uart_putc(uart->uart_port, c);
+		return 1;
+
+
+	}
+
+
+
+}
+
+static int fh_uart_getc(struct rt_serial_device *serial)
+{
+    int result;
+	struct fh_uart *uart = serial->parent.user_data;
+
+	if (uart_is_rx_ready(uart->uart_port))
+	{
+		result = uart_getc(uart->uart_port);
+	}
+	else
+	{
+		result = -1;
+	}
+
+    return result;
+}
+
+static const struct rt_uart_ops fh_uart_ops =
+{
+    fh_uart_configure,
+    fh_uart_control,
+    fh_uart_putc,
+    fh_uart_getc,
+};
+
+
+#if defined(RT_USING_UART0)
+static struct rt_serial_device serial0;
+struct fh_uart uart0 = {
+	(uart *)UART0_REG_BASE,
+	UART0_IRQn
+};
+
+#endif
+
+#if defined(RT_USING_UART1)
+static struct rt_serial_device serial1;
+struct fh_uart uart1 = {
+	(uart *)UART1_REG_BASE,
+	UART1_IRQn
+};
+
+#endif
+
+
+
+
+/**
+ * This function will handle init uart
+ */
+void rt_hw_uart_init(void)
+{
+	struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
+
+#if defined(RT_USING_UART0)
+#if(0)
+	serial0.ops = &fh_uart_ops;
+	serial0.config = config;
+
+	/* register vcom device */
+	rt_hw_serial_register(&serial0, "uart0",
+			RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM | RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_STANDALONE,
+			&uart0);
+	rt_hw_interrupt_install(uart0.irq, rt_fh_uart_handler,
+			(void *)&(serial0.parent), "UART0");
+	rt_hw_interrupt_umask(uart0.irq);
+#endif
+	serial0.ops = &fh_uart_ops;
+	serial0.config = config;
+
+	/* register vcom device */
+	rt_hw_serial_register(&serial0, "uart0",
+			RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM ,
+			&uart0);
+	rt_hw_interrupt_install(uart0.irq, rt_fh_uart_handler,
+			(void *)&(serial0.parent), "UART0");
+	rt_hw_interrupt_umask(uart0.irq);
+
+#endif
+
+#if defined(RT_USING_UART1)
+	serial1.ops = &fh_uart_ops;
+	serial1.config = config;
+
+	/* register vcom device */
+	rt_hw_serial_register(&serial1, "uart1",
+			RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM ,
+			&uart1);
+	rt_hw_interrupt_install(uart1.irq, rt_fh_uart_handler,
+			(void *)&(serial1.parent), "UART1");
+	rt_hw_interrupt_umask(uart1.irq);
+
+#endif
+
+}
+
+

+ 33 - 0
bsp/fh8620/drivers/uart.h

@@ -0,0 +1,33 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef UART_H_
+#define UART_H_
+
+void rt_hw_uart_init(void);
+
+
+#endif

+ 269 - 0
bsp/fh8620/drivers/wdt.c

@@ -0,0 +1,269 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#include "fh_def.h"
+#include "wdt.h"
+#include "interrupt.h"
+#include "board_info.h"
+#include "inc/fh_driverlib.h"
+#include <rtdevice.h>
+#include <drivers/watchdog.h>
+
+#define FH_WDT_DEBUG
+
+#ifdef FH_WDT_DEBUG
+#define PRINT_WDT_DBG(fmt, args...)     \
+    do                                  \
+    {                                   \
+        rt_kprintf("FH_WDT_DEBUG: ");   \
+        rt_kprintf(fmt, ## args);       \
+    }                                   \
+    while(0)
+#else
+#define PRINT_WDT_DBG(fmt, args...)  do { } while (0)
+#endif
+
+static int heartbeat = WDT_HEARTBEAT;
+
+static rt_uint32_t fh_wdt_time_left(struct wdt_driver *wdt_drv)
+{
+    struct fh_wdt_obj *wdt_obj = wdt_drv->priv;
+    //todo: get clk
+    //return  WDT_GetCurrCount(wdt_obj) / WDT_CLOCK;
+    return  WDT_GetCurrCount(wdt_obj) / 1800000;
+}
+
+
+static void fh_wdt_keepalive(struct wdt_driver *wdt_drv)
+{
+    struct fh_wdt_obj *wdt_obj = wdt_drv->priv;
+    WDT_Kick(wdt_obj);
+}
+
+static inline void fh_wdt_set_next_heartbeat(struct wdt_driver *wdt_drv)
+{
+    wdt_drv->next_heartbeat = rt_tick_get() + heartbeat * RT_TICK_PER_SECOND;
+}
+
+static inline int fh_wdt_top_in_seconds(struct wdt_driver *wdt_drv, unsigned top)
+{
+    /*
+     * There are 16 possible timeout values in 0..15 where the number of
+     * cycles is 2 ^ (16 + i) and the watchdog counts down.
+     */
+    //todo: get_clk
+    return (1 << (17 + top)) / 1800000;
+}
+
+static int fh_wdt_set_top(struct wdt_driver *wdt_drv, unsigned top_s)
+{
+    int i, top_val = FH_WDT_MAX_TOP;
+    struct fh_wdt_obj *wdt_obj = wdt_drv->priv;
+
+    /*
+     * Iterate over the timeout values until we find the closest match. We
+     * always look for >=.
+     */
+
+    for (i = 0; i <= FH_WDT_MAX_TOP; ++i)
+        if (fh_wdt_top_in_seconds(wdt_drv, i) >= top_s) {
+            top_val = i;
+            break;
+        }
+
+    /* Set the new value in the watchdog. */
+    PRINT_WDT_DBG("[wdt] set topval: %d\n", top_val);
+    WDT_SetTopValue(wdt_obj, top_val);
+
+    fh_wdt_set_next_heartbeat(wdt_drv);
+
+    return fh_wdt_top_in_seconds(wdt_drv, top_val);
+}
+
+
+rt_err_t fh_watchdog_init(rt_watchdog_t *wdt)
+{
+    struct wdt_driver *wdt_drv = wdt->parent.user_data;
+    struct fh_wdt_obj *wdt_obj = wdt_drv->priv;
+    if (wdt_drv->in_use)
+        return -RT_EBUSY;
+
+    //todo: spinlock
+    fh_wdt_set_top(wdt_drv, WDT_HW_TIMEOUT);///3000);
+    if (!WDT_IsEnable(wdt_obj))
+    {
+        /*
+         * The watchdog is not currently enabled. Set the timeout to
+         * the maximum and then start it.
+         */
+        rt_uint32_t value;
+        value = WDOG_CONTROL_REG_WDT_EN_MASK;
+        value |= WDOG_CONTROL_REG_RMOD_MASK;
+        WDT_SetCtrl(wdt_obj, value);
+        fh_wdt_keepalive(wdt_drv);
+    }
+
+    fh_wdt_set_next_heartbeat(wdt_drv);
+
+    //todo: unlock
+
+    return RT_EOK;
+}
+
+rt_err_t fh_watchdog_ctrl(rt_watchdog_t *wdt, int cmd, void *arg)
+{
+    struct wdt_driver *wdt_drv = wdt->parent.user_data;
+    struct fh_wdt_obj *wdt_obj = wdt_drv->priv;
+    rt_uint32_t val;
+
+    switch (cmd)
+    {
+    case RT_DEVICE_CTRL_WDT_START:
+        WDT_Enable(wdt_obj, RT_TRUE);
+        break;
+
+    case RT_DEVICE_CTRL_WDT_STOP:
+        WDT_Enable(wdt_obj, RT_FALSE);
+        break;
+
+    case RT_DEVICE_CTRL_WDT_KEEPALIVE:
+        //fh_wdt_set_next_heartbeat(wdt_drv);
+        fh_wdt_keepalive(wdt_drv);
+        break;
+
+    case RT_DEVICE_CTRL_WDT_SET_TIMEOUT:
+        heartbeat = *((int*)(arg));
+        PRINT_WDT_DBG("[wdt] settime value %lu\n", heartbeat);
+        fh_wdt_set_top(wdt_drv, heartbeat);///3000);
+        fh_wdt_keepalive(wdt_drv);
+        fh_wdt_set_next_heartbeat(wdt_drv);
+        break;
+
+    case RT_DEVICE_CTRL_WDT_GET_TIMEOUT:
+        arg = &heartbeat;
+        break;
+
+    case RT_DEVICE_CTRL_WDT_GET_TIMELEFT:
+        val = fh_wdt_time_left(wdt_drv);
+        arg = &val;
+        break;
+
+    default:
+        return -RT_EIO;
+    }
+    return RT_EOK;
+}
+
+static void fh_wdt_interrupt(int irq, void *param)
+{
+    //todo: stop
+    //fh81_pmu_stop();
+}
+
+struct rt_watchdog_ops fh_watchdog_ops =
+{
+    .init = &fh_watchdog_init,
+    .control = &fh_watchdog_ctrl,
+};
+
+
+int fh_wdt_probe(void *priv_data)
+{
+    rt_watchdog_t *wdt_dev;
+    struct wdt_driver *wdt_drv;
+    struct fh_wdt_obj *wdt_obj = (struct fh_wdt_obj *)priv_data;
+
+    wdt_drv = (struct wdt_driver *)rt_malloc(sizeof(struct wdt_driver));
+    rt_memset(wdt_drv, 0, sizeof(struct wdt_driver));
+
+    wdt_drv->priv = wdt_obj;
+
+    rt_hw_interrupt_install(wdt_obj->irq, fh_wdt_interrupt, (void *)wdt_drv, "wdt_irq");
+    rt_hw_interrupt_umask(wdt_obj->irq);
+
+    //todo: clk
+
+    wdt_dev = (rt_watchdog_t *)rt_malloc(sizeof(rt_watchdog_t));
+
+    if (wdt_dev == RT_NULL)
+    {
+        rt_kprintf("ERROR: %s rt_watchdog_t malloc failed\n", __func__);
+    }
+
+    wdt_dev->ops = &fh_watchdog_ops;
+
+    rt_hw_watchdog_register(wdt_dev, "fh_wdt", RT_DEVICE_OFLAG_RDWR, wdt_drv);
+
+    return 0;
+}
+
+int fh_wdt_exit(void *priv_data)
+{
+    return 0;
+}
+
+struct fh_board_ops wdt_driver_ops =
+{
+        .probe = fh_wdt_probe,
+        .exit = fh_wdt_exit,
+};
+
+void rt_hw_wdt_init(void)
+{
+    PRINT_WDT_DBG("%s start\n", __func__);
+    fh_board_driver_register("wdt", &wdt_driver_ops);
+    PRINT_WDT_DBG("%s end\n", __func__);
+}
+
+void wdt_start(int timeout, int kick_times)
+{
+    rt_device_t wdt_dev;
+    int ret;
+
+    wdt_dev = rt_device_find("fh_wdt");
+
+    rt_device_open(wdt_dev, 0);
+
+    ret = rt_device_control(wdt_dev, RT_DEVICE_CTRL_WDT_SET_TIMEOUT, &timeout);
+
+    int i = 0;
+    for( ; i < kick_times; i ++ )
+    {
+        rt_thread_sleep(timeout * RT_TICK_PER_SECOND / 2);
+        ret = rt_device_control(wdt_dev, RT_DEVICE_CTRL_WDT_KEEPALIVE, &timeout);
+        rt_kprintf( "kicked\n" );
+    }
+
+    rt_kprintf( "stop kick the watchdog, it shall reboot for %d seconds.\n", timeout * 2);
+
+}
+
+#ifdef RT_USING_WDT
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+FINSH_FUNCTION_EXPORT(wdt_start, enable wdt);
+#endif
+#endif

+ 46 - 0
bsp/fh8620/drivers/wdt.h

@@ -0,0 +1,46 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef WDT_H_
+#define WDT_H_
+
+
+
+struct wdt_driver
+{
+    //struct clk          *clk;
+    unsigned long       in_use;
+    unsigned long       next_heartbeat;
+    //struct timer_list   timer;
+    int                 expect_close;
+
+    void* priv;
+};
+
+
+
+
+#endif /* WDT_H_ */

+ 14 - 0
bsp/fh8620/libraries/SConscript

@@ -0,0 +1,14 @@
+# for module compiling
+import os
+from building import *
+
+objs = []
+cwd  = GetCurrentDir()
+list = os.listdir(cwd)
+
+for item in list:
+
+    if os.path.isfile(os.path.join(cwd, item, 'SConscript')):
+        objs = objs + SConscript(os.path.join(item, 'SConscript'))
+
+Return('objs')

+ 9 - 0
bsp/fh8620/libraries/driverlib/SConscript

@@ -0,0 +1,9 @@
+from building import *
+
+cwd = GetCurrentDir()
+src	= Glob('*.c')
+path = [cwd + '/..']
+
+group = DefineGroup('Libraries', src, depend = [''], CPPPATH = path)
+
+Return('group')

+ 27 - 0
bsp/fh8620/libraries/driverlib/fh_gpio.c

@@ -0,0 +1,27 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+ 

+ 311 - 0
bsp/fh8620/libraries/driverlib/fh_i2c.c

@@ -0,0 +1,311 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#include "inc/fh_driverlib.h"
+
+int I2C_WaitMasterIdle(struct fh_i2c_obj *i2c_obj)
+{
+    UINT32 reg;
+    int timeout = 200;  //20 ms
+
+    while (GET_REG(i2c_obj->base + OFFSET_I2C_STATUS) & DW_IC_STATUS_MASTER_ACTIVITY)
+    {
+        if(timeout < 0)
+        {
+            rt_kprintf( "ERROR: %s, timeout waiting for master not active, txflr: 0x%x, rxflr: 0x%x, stat: 0x%x\n",
+                    __func__, I2C_GetReceiveFifoLevel(i2c_obj), I2C_GetTransmitFifoLevel(i2c_obj), GET_REG(i2c_obj->base + OFFSET_I2C_INTR_STAT));
+            return -RT_ETIMEOUT;
+        }
+        timeout--;
+        udelay(100);
+    }
+
+    return 0;
+}
+
+int I2C_WaitDeviceIdle(struct fh_i2c_obj *i2c_obj)
+{
+    UINT32 reg;
+
+    int timeout = 2000;  //200 ms
+
+    while (GET_REG(i2c_obj->base + OFFSET_I2C_STATUS) & DW_IC_STATUS_ACTIVITY)
+    {
+        if(timeout < 0)
+        {
+            rt_kprintf( "ERROR: %s, timeout waiting for device not active\n", __func__);
+            return -RT_ETIMEOUT;
+        }
+        timeout--;
+        udelay(100);
+    }
+
+    return 0;
+}
+
+
+static inline UINT32 I2C_CalcSclHcnt(UINT32 ic_clk, UINT32 tSYMBOL, UINT32 tf, int cond, int offset)
+{
+    /*
+     * DesignWare I2C core doesn't seem to have solid strategy to meet
+     * the tHD;STA timing spec.  Configuring _HCNT based on tHIGH spec
+     * will result in violation of the tHD;STA spec.
+     */
+    if (cond)
+    /*
+     * Conditional expression:
+     *
+     *   IC_[FS]S_SCL_HCNT + (1+4+3) >= IC_CLK * tHIGH
+     *
+     * This is based on the DW manuals, and represents an ideal
+     * configuration.  The resulting I2C bus speed will be
+     * faster than any of the others.
+     *
+     * If your hardware is free from tHD;STA issue, try this one.
+     */
+        return (ic_clk * tSYMBOL + 5000) / 10000 - 8 + offset;
+    else
+    /*
+     * Conditional expression:
+     *
+     *   IC_[FS]S_SCL_HCNT + 3 >= IC_CLK * (tHD;STA + tf)
+     *
+     * This is just experimental rule; the tHD;STA period turned
+     * out to be proportinal to (_HCNT + 3).  With this setting,
+     * we could meet both tHIGH and tHD;STA timing specs.
+     *
+     * If unsure, you'd better to take this alternative.
+     *
+     * The reason why we need to take into account "tf" here,
+     * is the same as described in i2c_fh_scl_lcnt().
+     */
+        return (ic_clk * (tSYMBOL + tf) + 5000) / 10000 - 3 + offset;
+}
+
+static inline UINT32 I2C_CalcSclLcnt(UINT32 ic_clk, UINT32 tLOW, UINT32 tf, int offset)
+{
+    /*
+     * Conditional expression:
+     *
+     *   IC_[FS]S_SCL_LCNT + 1 >= IC_CLK * (tLOW + tf)
+     *
+     * DW I2C core starts counting the SCL CNTs for the LOW period
+     * of the SCL clock (tLOW) as soon as it pulls the SCL line.
+     * In order to meet the tLOW timing spec, we need to take into
+     * account the fall time of SCL signal (tf).  Default tf value
+     * should be 0.3 us, for safety.
+     */
+    return ((ic_clk * (tLOW + tf) + 5000) / 10000) - 1 + offset;
+}
+
+static int I2C_SetSpeedCount(struct fh_i2c_obj *i2c_obj)
+{
+    UINT32 hcnt, lcnt;
+
+    /* set standard and fast speed count for high/low periods */
+
+    /* Standard-mode */
+    hcnt = I2C_CalcSclHcnt(i2c_obj->input_clock,
+            40, /* tHD;STA = tHIGH = 4.0 us */
+            3, /* tf = 0.3 us */
+            0, /* 0: DW default, 1: Ideal */
+            0); /* No offset */
+    lcnt = I2C_CalcSclLcnt(i2c_obj->input_clock,
+            47, /* tLOW = 4.7 us */
+            3, /* tf = 0.3 us */
+            0); /* No offset */
+
+    SET_REG(i2c_obj->base + OFFSET_I2C_SS_SCL_HCNT, hcnt);
+    SET_REG(i2c_obj->base + OFFSET_I2C_SS_SCL_LCNT, lcnt);
+
+    /* Fast-mode */
+    hcnt = I2C_CalcSclHcnt(i2c_obj->input_clock,
+            6, /* tHD;STA = tHIGH = 0.6 us */
+            3, /* tf = 0.3 us */
+            0, /* 0: DW default, 1: Ideal */
+            0); /* No offset */
+    lcnt = I2C_CalcSclLcnt(i2c_obj->input_clock,
+            13, /* tLOW = 1.3 us */
+            3, /* tf = 0.3 us */
+            0); /* No offset */
+    SET_REG(i2c_obj->base + OFFSET_I2C_FS_SCL_HCNT, hcnt);
+    SET_REG(i2c_obj->base + OFFSET_I2C_FS_SCL_LCNT, lcnt);
+
+    return 0;
+}
+
+inline UINT8 I2C_GetData(struct fh_i2c_obj *i2c_obj)
+{
+    return GET_REG(i2c_obj->base + OFFSET_I2C_DATA_CMD) & 0xff;
+}
+
+inline void I2C_SetDataCmd(struct fh_i2c_obj *i2c_obj, UINT32 reg)
+{
+    SET_REG(i2c_obj->base + OFFSET_I2C_DATA_CMD, reg);
+}
+
+inline void I2C_SetInterruptMask(struct fh_i2c_obj *i2c_obj, UINT32 mask)
+{
+    SET_REG(i2c_obj->base + OFFSET_I2C_INTR_MASK, mask);
+}
+
+inline UINT32 I2C_GetInterruptMask(struct fh_i2c_obj *i2c_obj)
+{
+    return GET_REG(i2c_obj->base + OFFSET_I2C_INTR_MASK);
+}
+
+UINT32 I2C_ClearAndGetInterrupts(struct fh_i2c_obj *i2c_obj)
+{
+    UINT32 stat;
+    /*
+     * The IC_INTR_STAT register just indicates "enabled" interrupts.
+     * Ths unmasked raw version of interrupt status bits are available
+     * in the IC_RAW_INTR_STAT register.
+     *
+     * That is,
+     *   stat = readl(IC_INTR_STAT);
+     * equals to,
+     *   stat = readl(IC_RAW_INTR_STAT) & readl(IC_INTR_MASK);
+     *
+     * The raw version might be useful for debugging purposes.
+     */
+    stat = GET_REG(i2c_obj->base + OFFSET_I2C_INTR_STAT);
+
+    /*
+     * Do not use the IC_CLR_INTR register to clear interrupts, or
+     * you'll miss some interrupts, triggered during the period from
+     * readl(IC_INTR_STAT) to readl(IC_CLR_INTR).
+     *
+     * Instead, use the separately-prepared IC_CLR_* registers.
+     */
+    if (stat & DW_IC_INTR_RX_UNDER)
+        GET_REG(i2c_obj->base + OFFSET_I2C_CLR_RX_UNDER);
+    if (stat & DW_IC_INTR_RX_OVER)
+        GET_REG(i2c_obj->base + OFFSET_I2C_CLR_RX_OVER);
+    if (stat & DW_IC_INTR_TX_OVER)
+        GET_REG(i2c_obj->base + OFFSET_I2C_CLR_TX_OVER);
+    if (stat & DW_IC_INTR_RD_REQ)
+        GET_REG(i2c_obj->base + OFFSET_I2C_CLR_RD_REQ);
+    if (stat & DW_IC_INTR_TX_ABRT)
+    {
+        /*
+         * The IC_TX_ABRT_SOURCE register is cleared whenever
+         * the IC_CLR_TX_ABRT is read.  Preserve it beforehand.
+         */
+        i2c_obj->abort_source = GET_REG(i2c_obj->base + OFFSET_I2C_TX_ABRT_SOURCE);
+        GET_REG(i2c_obj->base + OFFSET_I2C_CLR_TX_ABRT);
+    }
+    if (stat & DW_IC_INTR_RX_DONE)
+        GET_REG(i2c_obj->base + OFFSET_I2C_CLR_RX_DONE);
+    if (stat & DW_IC_INTR_ACTIVITY)
+        GET_REG(i2c_obj->base + OFFSET_I2C_CLR_ACTIVITY);
+    if (stat & DW_IC_INTR_STOP_DET)
+        GET_REG(i2c_obj->base + OFFSET_I2C_CLR_STOP_DET);
+    if (stat & DW_IC_INTR_START_DET)
+        GET_REG(i2c_obj->base + OFFSET_I2C_CLR_START_DET);
+    if (stat & DW_IC_INTR_GEN_CALL)
+        GET_REG(i2c_obj->base + OFFSET_I2C_CLR_GEN_CALL);
+
+    return stat;
+}
+
+int I2C_HandleTxAbort(struct fh_i2c_obj *i2c_obj)
+{
+    unsigned long abort_source = i2c_obj->abort_source;
+    int i;
+
+    if (abort_source & DW_IC_TX_ABRT_NOACK)
+    {
+        //for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
+        //    rt_kprintf(   "%s: %s\n", __func__, abort_sources[i]);
+        return 0;
+    }
+
+    //for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
+    //    rt_kprintf( "%s: %s\n", __func__, abort_sources[i]);
+    rt_kprintf("%s: abort_sources 0x%x\n", __func__, abort_sources);
+
+    if (abort_source & DW_IC_TX_ARB_LOST)
+        return 0;
+    else if (abort_source & DW_IC_TX_ABRT_GCALL_READ)
+        return 0; /* wrong msgs[] data */
+    else
+        return 0;
+}
+
+inline UINT32 I2C_SetTransmitThreshold(struct fh_i2c_obj *i2c_obj, int txtl)
+{
+    return SET_REG(i2c_obj->base + OFFSET_I2C_TX_TL, txtl);
+}
+
+
+inline UINT32 I2C_GetReceiveFifoLevel(struct fh_i2c_obj *i2c_obj)
+{
+    return GET_REG(i2c_obj->base + OFFSET_I2C_RXFLR);
+}
+
+inline UINT32 I2C_GetTransmitFifoLevel(struct fh_i2c_obj *i2c_obj)
+{
+    return GET_REG(i2c_obj->base + OFFSET_I2C_TXFLR);
+}
+
+inline void I2C_SetSlaveAddress(struct fh_i2c_obj *i2c_obj, rt_uint16_t addr)
+{
+    UINT32 reg;
+    reg = GET_REG(i2c_obj->base + OFFSET_I2C_TAR);
+    reg &= ~(0x3ff);
+    reg |= addr & 0x3ff;
+    SET_REG(i2c_obj->base + OFFSET_I2C_TAR, reg);
+}
+
+inline void I2C_Enable(struct fh_i2c_obj *i2c_obj, int enable)
+{
+    SET_REG(i2c_obj->base + OFFSET_I2C_ENABLE, enable);
+}
+
+
+void I2C_Init(struct fh_i2c_obj *i2c_obj)
+{
+    UINT32 ic_con;
+    UINT32 param0 = GET_REG(i2c_obj->base + OFFSET_I2C_COMP_PARAM1);
+
+    I2C_WaitMasterIdle(i2c_obj);
+    I2C_Enable(i2c_obj, RT_FALSE);
+    I2C_SetSpeedCount(i2c_obj);
+
+    i2c_obj->config.tx_fifo_depth = ((param0 >> 16) & 0xff) + 1;
+    i2c_obj->config.rx_fifo_depth = ((param0 >> 8) & 0xff) + 1;
+
+    /* Configure Tx/Rx FIFO threshold levels */
+    SET_REG(i2c_obj->base + OFFSET_I2C_TX_TL, i2c_obj->config.tx_fifo_depth - 1);
+    SET_REG(i2c_obj->base + OFFSET_I2C_RX_TL, 0);
+
+    /* configure the i2c master */
+    ic_con = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
+    /*OFFSET_I2C_CON_RESTART_EN |*/ DW_IC_CON_SPEED_FAST; //DW_IC_CON_SPEED_STD;
+
+    SET_REG( i2c_obj->base + OFFSET_I2C_CON, ic_con);
+}

+ 69 - 0
bsp/fh8620/libraries/driverlib/fh_ictl.c

@@ -0,0 +1,69 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#include "inc/fh_driverlib.h"
+
+
+
+void ictl_close_all_isr(fh_intc *p){
+	if(p){
+		//enable all interrupts
+		p->IRQ_EN_L = 0xffffffff;
+		p->IRQ_EN_H = 0xffffffff;
+		//mask all  interrupts
+		p->IRQ_MASK_L = 0xffffffff;
+		p->IRQ_MASK_H = 0xffffffff;
+	}
+
+}
+
+
+
+
+void ictl_mask_isr(fh_intc *p,int irq){
+	if(p){
+
+		if (irq < 32)
+	    	p->IRQ_MASK_L |= (1 << irq);
+		else
+			p->IRQ_MASK_H |= (1 << (irq - 32));
+	}
+}
+
+
+
+
+
+void ictl_unmask_isr(fh_intc *p,int irq){
+	if(p){
+	    if (irq < 32)
+	    	p->IRQ_MASK_L &= ~(1 << irq);
+		else
+			p->IRQ_MASK_H &= ~(1 << (irq - 32));
+
+	}
+
+}

+ 413 - 0
bsp/fh8620/libraries/driverlib/fh_mmc.c

@@ -0,0 +1,413 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "inc/fh_driverlib.h"
+
+// *1: card off
+// *0: card on
+inline rt_uint32_t MMC_GetCardStatus(struct fh_mmc_obj *mmc_obj)
+{
+    rt_uint32_t card_status = GET_REG(mmc_obj->base + OFFSET_SDC_CDETECT);
+
+    return card_status & 0x1;
+}
+
+inline void MMC_StartDma(struct fh_mmc_obj *mmc_obj)
+{
+    rt_uint32_t reg;
+
+    SET_REG(mmc_obj->base + OFFSET_SDC_DBADDR, (rt_uint32_t)mmc_obj->descriptors);
+    reg = GET_REG(mmc_obj->base + OFFSET_SDC_BMOD);
+    reg |= 1 << 7;
+    SET_REG(mmc_obj->base + OFFSET_SDC_BMOD, reg);
+}
+
+inline void MMC_StopDma(struct fh_mmc_obj *mmc_obj)
+{
+    rt_uint32_t reg;
+
+    reg = GET_REG(mmc_obj->base + OFFSET_SDC_BMOD);
+    reg &= ~(1 << 7);
+    SET_REG(mmc_obj->base + OFFSET_SDC_BMOD, reg);
+}
+
+void MMC_InitDescriptors(struct fh_mmc_obj *mmc_obj, rt_uint32_t *buf, rt_uint32_t size)
+{
+    MMC_DMA_Descriptors *desc;
+    rt_uint32_t len = 0;
+    int i, desc_cnt = 0;
+
+    desc = mmc_obj->descriptors;
+
+    while(size > 0)
+    {
+        desc[desc_cnt].desc0.bit.own = 1;
+        desc[desc_cnt].desc0.bit.sencond_address_chained = 1;
+        desc[desc_cnt].desc1.bit.buffer1_size = MIN(MMC_DMA_DESC_BUFF_SIZE, size);
+        desc[desc_cnt].desc2.bit.buffer_addr0 = (rt_uint32_t)buf + len;
+        desc[desc_cnt].desc3.bit.buffer_addr1 = (rt_uint32_t)mmc_obj->descriptors + (desc_cnt + 1) * sizeof(MMC_DMA_Descriptors);
+
+        size -= desc[desc_cnt].desc1.bit.buffer1_size;
+        len += desc[desc_cnt].desc1.bit.buffer1_size;
+        desc_cnt++;
+    }
+
+    desc[0].desc0.bit.first_descriptor = 1;
+    desc[desc_cnt-1].desc0.bit.last_descriptor = 1;
+    desc[desc_cnt-1].desc3.bit.buffer_addr1 = 0;
+}
+
+
+inline rt_uint32_t MMC_GetWaterlevel(struct fh_mmc_obj *mmc_obj)
+{
+    return (GET_REG(mmc_obj->base + OFFSET_SDC_STATUS) >> 17) & 0x1fff;
+}
+
+inline rt_uint32_t MMC_GetStatus(struct fh_mmc_obj *mmc_obj)
+{
+    return GET_REG(mmc_obj->base + OFFSET_SDC_STATUS);
+}
+
+inline rt_uint32_t MMC_GetRawInterrupt(struct fh_mmc_obj *mmc_obj)
+{
+    return GET_REG(mmc_obj->base + OFFSET_SDC_RINTSTS);
+}
+
+inline rt_uint32_t MMC_GetUnmaskedInterrupt(struct fh_mmc_obj *mmc_obj)
+{
+    return GET_REG(mmc_obj->base + OFFSET_SDC_MINTSTS);
+}
+
+inline rt_uint32_t MMC_ClearRawInterrupt(struct fh_mmc_obj *mmc_obj, rt_uint32_t interrupts)
+{
+    return SET_REG(mmc_obj->base + OFFSET_SDC_RINTSTS, interrupts);
+}
+
+inline rt_uint32_t MMC_GetInterruptMask(struct fh_mmc_obj *mmc_obj)
+{
+    return GET_REG(mmc_obj->base + OFFSET_SDC_INTMASK);
+}
+
+inline rt_uint32_t MMC_SetInterruptMask(struct fh_mmc_obj *mmc_obj, rt_uint32_t mask)
+{
+    return SET_REG(mmc_obj->base + OFFSET_SDC_INTMASK, mask);
+}
+
+inline void MMC_SetByteCount(struct fh_mmc_obj *mmc_obj, rt_uint32_t bytes)
+{
+    SET_REG(mmc_obj->base + OFFSET_SDC_BYTCNT, bytes);
+}
+
+inline void MMC_SetBlockSize(struct fh_mmc_obj *mmc_obj, rt_uint32_t size)
+{
+    SET_REG(mmc_obj->base + OFFSET_SDC_BLKSIZ, size);
+}
+
+inline rt_uint32_t MMC_GetResponse(struct fh_mmc_obj *mmc_obj, int resp_num)
+{
+    return GET_REG(mmc_obj->base + OFFSET_SDC_RESP0 + resp_num * 4);
+}
+
+inline rt_uint32_t MMC_IsFifoEmpty(struct fh_mmc_obj *mmc_obj)
+{
+    return (GET_REG(mmc_obj->base + OFFSET_SDC_STATUS) >> 2) & 0x1;
+}
+
+inline rt_uint32_t MMC_IsDataStateBusy(struct fh_mmc_obj *mmc_obj)
+{
+    return (GET_REG(mmc_obj->base + OFFSET_SDC_STATUS) >> 10) & 0x1;
+}
+
+int MMC_WriteData(struct fh_mmc_obj *mmc_obj, rt_uint32_t *buf, rt_uint32_t size)
+{
+    int filled = 0, fifo_available, i, retries;
+
+    for (i=0; i<size/4; i++)
+    {
+        retries = 0;
+        do
+        {
+            fifo_available = MMC_FIFO_DEPTH - MMC_GetWaterlevel(mmc_obj);
+            if(retries++ > 10000)
+            {
+                rt_kprintf("ERROR: %s, get water level timeout\n", __func__);
+                return -RT_ETIMEOUT;
+            }
+        }
+        while(!fifo_available);
+        SET_REG(mmc_obj->base + OFFSET_SDC_FIFO, *buf++);
+    }
+
+    retries = 0;
+    while(MMC_IsDataStateBusy(mmc_obj))
+    {
+        if(retries++ > 10000)
+        {
+            rt_kprintf("ERROR: %s, timeout, data line keep being busy\n", __func__);
+            return -RT_ETIMEOUT;
+        }
+    }
+
+    return 0;
+}
+int MMC_ReadData(struct fh_mmc_obj *mmc_obj, rt_uint32_t *buf, rt_uint32_t size)
+{
+    int fifo_available, i, retries;
+
+    for (i=0; i<size/4; i++)
+    {
+        retries = 0;
+        do
+        {
+            fifo_available = MMC_GetWaterlevel(mmc_obj);
+            if(retries++ > 10000)
+            {
+                rt_kprintf("ERROR: %s, get water level timeout\n", __func__);
+                return -RT_ETIMEOUT;
+            }
+        }
+        while(!fifo_available);
+
+        *buf++ = GET_REG(mmc_obj->base + OFFSET_SDC_FIFO);
+    }
+
+    retries = 0;
+    while(MMC_IsDataStateBusy(mmc_obj))
+    {
+        if(retries++ > 10000)
+        {
+            rt_kprintf("ERROR: %s, timeout, data line keep being busy\n", __func__);
+            return -RT_ETIMEOUT;
+        }
+    }
+
+    return 0;
+}
+
+
+int MMC_UpdateClockRegister(struct fh_mmc_obj *mmc_obj, int div)
+{
+    rt_uint32_t tick, timeout;
+
+    tick = rt_tick_get();
+    timeout = tick + RT_TICK_PER_SECOND / 10; //100ms in total
+
+    /* disable clock */
+    SET_REG(mmc_obj->base + OFFSET_SDC_CLKENA, 0);
+    SET_REG(mmc_obj->base + OFFSET_SDC_CLKSRC, 0);
+
+    /* inform CIU */
+    SET_REG(mmc_obj->base + OFFSET_SDC_CMD, 1<<31 | 1<<21);
+    while(GET_REG(mmc_obj->base + OFFSET_SDC_CMD) & 0x80000000)
+    {
+        tick = rt_tick_get();
+        if(tick > timeout)
+        {
+            rt_kprintf("ERROR: %s, update clock timeout\n", __func__);
+            return -RT_ETIMEOUT;
+        }
+    }
+
+    /* set clock to desired speed */
+    SET_REG(mmc_obj->base + OFFSET_SDC_CLKDIV, div);
+
+    /* inform CIU */
+    SET_REG(mmc_obj->base + OFFSET_SDC_CMD, 1<<31 | 1<<21);
+
+    while(GET_REG(mmc_obj->base + OFFSET_SDC_CMD) & 0x80000000)
+    {
+        tick = rt_tick_get();
+        if(tick > timeout)
+        {
+            rt_kprintf("ERROR: %s, update clock timeout\n", __func__);
+            return -RT_ETIMEOUT;
+        }
+    }
+
+    /* enable clock */
+    SET_REG(mmc_obj->base + OFFSET_SDC_CLKENA, 1);
+
+    /* inform CIU */
+    SET_REG(mmc_obj->base + OFFSET_SDC_CMD, 1<<31 | 1<<21);
+
+    while(GET_REG(mmc_obj->base + OFFSET_SDC_CMD) & 0x80000000)
+    {
+        tick = rt_tick_get();
+        if(tick > timeout)
+        {
+            rt_kprintf("ERROR: %s, update clock timeout\n", __func__);
+            return -RT_ETIMEOUT;
+        }
+    }
+
+    return 0;
+}
+
+int MMC_SetCardWidth(struct fh_mmc_obj *mmc_obj, int width)
+{
+    switch(width)
+    {
+    case MMC_CARD_WIDTH_1BIT:
+        SET_REG(mmc_obj->base + OFFSET_SDC_CTYPE, 0);
+        break;
+    case MMC_CARD_WIDTH_4BIT:
+        SET_REG(mmc_obj->base + OFFSET_SDC_CTYPE, 1);
+        break;
+    default:
+        rt_kprintf("ERROR: %s, card width %d is not supported\n", __func__, width);
+        return -RT_ERROR;
+        break;
+    }
+    return 0;
+}
+
+int MMC_SendCommand(struct fh_mmc_obj *mmc_obj, rt_uint32_t cmd, rt_uint32_t arg, rt_uint32_t flags)
+{
+    rt_uint32_t reg, tick, timeout;
+
+    tick = rt_tick_get();
+    timeout = tick + RT_TICK_PER_SECOND; //1s
+
+    SET_REG(mmc_obj->base + OFFSET_SDC_CMDARG, arg);
+    flags |= 1<<31 | 1<<29 | cmd;
+
+    SET_REG(mmc_obj->base + OFFSET_SDC_CMD, flags);
+
+    while(GET_REG(mmc_obj->base + OFFSET_SDC_CMD) & MMC_CMD_START_CMD)
+    {
+        tick = rt_tick_get();
+        if(tick > timeout)
+        {
+            rt_kprintf("ERROR: %s, send cmd timeout\n", __func__);
+            return -RT_ETIMEOUT;
+        }
+    }
+
+    //fixme: check HLE_INT_STATUS
+    return 0;
+}
+
+int MMC_ResetFifo(struct fh_mmc_obj *mmc_obj)
+{
+    rt_uint32_t reg, tick, timeout;
+
+    tick = rt_tick_get();
+    timeout = tick + RT_TICK_PER_SECOND / 10; //100ms
+
+    reg = GET_REG(mmc_obj->base + OFFSET_SDC_CTRL);
+    reg |= 1 << 1;
+    SET_REG(mmc_obj->base + OFFSET_SDC_CTRL, reg);
+
+    //wait until fifo reset finish
+    while(GET_REG(mmc_obj->base + OFFSET_SDC_CTRL) & MMC_CTRL_FIFO_RESET)
+    {
+        tick = rt_tick_get();
+        if(tick > timeout)
+        {
+            rt_kprintf("ERROR: %s, FIFO reset timeout\n", __func__);
+            return -RT_ETIMEOUT;
+        }
+    }
+
+    return 0;
+}
+
+int MMC_Reset(struct fh_mmc_obj *mmc_obj)
+{
+    rt_uint32_t reg, tick, timeout;
+
+    tick = rt_tick_get();
+    timeout = tick + RT_TICK_PER_SECOND / 10; //100ms
+
+    reg = GET_REG(mmc_obj->base + OFFSET_SDC_BMOD);
+    reg |= MMC_BMOD_RESET;
+    SET_REG(mmc_obj->base + OFFSET_SDC_BMOD, reg);
+
+    while(GET_REG(mmc_obj->base + OFFSET_SDC_BMOD) & MMC_BMOD_RESET)
+    {
+        tick = rt_tick_get();
+        if(tick > timeout)
+        {
+            rt_kprintf("ERROR: %s, BMOD Software reset timeout\n", __func__);
+            return -RT_ETIMEOUT;
+        }
+    }
+
+    reg = GET_REG(mmc_obj->base + OFFSET_SDC_CTRL);
+    reg |= MMC_CTRL_CONTROLLER_RESET | MMC_CTRL_FIFO_RESET | MMC_CTRL_DMA_RESET;
+    SET_REG(mmc_obj->base + OFFSET_SDC_CTRL, reg);
+
+    tick = rt_tick_get();
+    timeout = tick + RT_TICK_PER_SECOND / 10; //100ms
+    while(GET_REG(mmc_obj->base + OFFSET_SDC_CTRL) & (MMC_CTRL_CONTROLLER_RESET | MMC_CTRL_FIFO_RESET | MMC_CTRL_DMA_RESET))
+    {
+        tick = rt_tick_get();
+        if(tick > timeout)
+        {
+            rt_kprintf("ERROR: %s, CTRL dma|fifo|ctrl reset timeout\n", __func__);
+            return -RT_ETIMEOUT;
+        }
+    }
+    return 0;
+}
+
+
+void MMC_Init(struct fh_mmc_obj *mmc_obj)
+{
+    rt_uint32_t reg;
+
+    if(mmc_obj->mmc_reset)
+        mmc_obj->mmc_reset(mmc_obj);
+
+    MMC_Reset(mmc_obj);
+
+    //fixed burst
+    reg = GET_REG(mmc_obj->base + OFFSET_SDC_BMOD);
+    reg |= 1 << 1;
+    SET_REG(mmc_obj->base + OFFSET_SDC_BMOD, reg);
+
+    //fixme: power on ? ctrl by gpio ?
+
+    MMC_ClearRawInterrupt(mmc_obj, MMC_INT_STATUS_ALL);
+    MMC_SetInterruptMask(mmc_obj, 0x0);
+
+    //fixme: use_internal_dma
+    reg = GET_REG(mmc_obj->base + OFFSET_SDC_CTRL);
+    reg |= MMC_CTRL_INT_ENABLE;
+#ifdef MMC_USE_DMA
+    reg |= MMC_CTRL_USE_DMA;
+#endif
+    SET_REG(mmc_obj->base + OFFSET_SDC_CTRL, reg);
+
+    //set timeout param
+    SET_REG(mmc_obj->base + OFFSET_SDC_TMOUT, 0xffffffff);
+
+    //set fifo
+    reg = GET_REG(mmc_obj->base + OFFSET_SDC_FIFOTH);
+    reg = (reg >> 16) & 0x7ff;
+    reg = ((0x2 << 28) | ((reg/2) << 16) | ((reg/2 + 1) << 0));
+    SET_REG(mmc_obj->base + OFFSET_SDC_FIFOTH, reg);
+}

+ 42 - 0
bsp/fh8620/libraries/driverlib/fh_pwm.c

@@ -0,0 +1,42 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "inc/fh_driverlib.h"
+
+void PWM_Enable(struct fh_pwm_obj *pwm_obj, int enable)
+{
+    SET_REG(pwm_obj->base + OFFSET_PWM_CTRL, enable);
+}
+
+unsigned int PWM_GetPwmCmd(struct fh_pwm_obj *pwm_obj, int device_id)
+{
+    return GET_REG(pwm_obj->base + OFFSET_PWM_CMD(device_id));
+}
+
+void PWM_SetPwmCmd(struct fh_pwm_obj *pwm_obj, int device_id, unsigned int reg)
+{
+    SET_REG(pwm_obj->base + OFFSET_PWM_CMD(device_id), reg);
+}

+ 2085 - 0
bsp/fh8620/libraries/driverlib/fh_sdio.c

@@ -0,0 +1,2085 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "string.h"
+#include "inc/fh_sdio.h"
+#include "fh_arch.h"
+//#include "interrupt.h"
+
+#define SDIO_PRINTF rt_kprintf
+
+#define SDC_USE_IDMA
+
+#define INSTRUCTIONS_PER_USEC          1000
+#define CMD_TIMEOUT_USEC 	               100000 
+#define DATA_READY_TIMEOUT_USEC 	200000
+#define DMA_TRANSFER_TIMEOUT_TICKS 300
+#define DATA_TRANSFER_OVER_TIMEOUT_USEC 1000
+#define ACMD41_RETRY_COUNT                             1000//100000
+
+#define CIU_CLK		       50000//25000//25000 //27MHz
+#define MMC_FOD_VALUE  125	/* 125 KHz */
+#define NORM_FOD_VALUE  25000//5000//25000	/* 25 MHz */
+#define MMC_FOD_DIVIDER_VALUE   (((CIU_CLK+MMC_FOD_VALUE*2-1)/(MMC_FOD_VALUE*2)))
+#ifdef SDCARD_CLK_DIVIDER
+#define ONE_BIT_BUS_FREQ   SDCARD_CLK_DIVIDER
+#else
+#define ONE_BIT_BUS_FREQ   (((CIU_CLK)/(NORM_FOD_VALUE*2)))
+#endif
+
+static unsigned int sdc_clk_divider = ONE_BIT_BUS_FREQ;
+
+static sdc_t sdc_array[2];
+
+static void plat_loop(unsigned int macrosecond)
+{
+	unsigned int clk;
+	
+	while (macrosecond-- > 0) {
+		for(clk=INSTRUCTIONS_PER_USEC; clk>0; clk--);
+	}
+}
+
+static int synopmob_execute_command(unsigned int base, unsigned int cmd_register, unsigned int arg_register)
+{
+	unsigned int retries = CMD_TIMEOUT_USEC;
+
+	synopmob_set_register(base + RINTSTS, 0xfffe); //clear interrupts, FIXME
+	synopmob_set_register(base+CMDARG, arg_register);
+	synopmob_set_register(base+CMD, cmd_register | (0x80000000|0x20000000/*fixed to use hold*/));
+
+	while (retries-- > 0) {
+		if (!(synopmob_read_register(base+CMD) & 0x80000000/*CMD done bit*/))
+			return 0;
+		plat_loop(1);
+	}
+	
+	return ERRCMDRETRIESOVER;
+}
+
+static int synopmob_wait_command_done(unsigned int base, unsigned int* inst, unsigned int flag)
+{
+	unsigned int retries = CMD_TIMEOUT_USEC;
+	unsigned int sts;
+
+	while (retries-- > 0) {
+		sts = synopmob_read_register(base+RINTSTS);
+		if (sts && ((sts & flag) == flag) ) {
+			*inst = sts;
+			return 0;
+		}
+		plat_loop(1);
+	}
+	return ERRCMDRETRIESOVER;
+}
+
+static int synopmob_wait_data_ready(unsigned int base)
+{
+	unsigned int retries = DATA_READY_TIMEOUT_USEC;
+
+	while (retries-- > 0) {
+		if  (!((synopmob_read_register(base+STATUS)) & 0x00000200)) {
+			return 0;
+		}
+		
+		plat_loop(1);
+	}
+	return ERRDATANOTREADY;
+}
+
+static int synopmob_handle_standard_rinsts(unsigned int raw_int_stat)
+{
+	int error_status = 0;
+	
+	if ( raw_int_stat &  INTMASK_ERROR) {
+		if (raw_int_stat & INTMSK_RESP_ERR) {
+			error_status = ERRRESPRECEP;
+		}
+		if (raw_int_stat & INTMSK_RCRC) {
+			error_status = ERRRESPCRC;
+		}
+		if (raw_int_stat & INTMSK_DCRC) {
+			error_status = ERRDCRC;
+		}		
+		if (raw_int_stat & INTMSK_RTO) {
+			error_status = ERRRESPTIMEOUT;
+		}		
+		if (raw_int_stat & INTMSK_DTO) {
+			error_status = ERRDRTIMEOUT;
+		}
+		if (raw_int_stat & INTMSK_HTO) {
+			error_status = ERRUNDERWRITE;
+		}
+		if (raw_int_stat & INTMSK_FRUN) {
+			error_status = ERROVERREAD;
+		}
+		if (raw_int_stat & INTMSK_HLE) {
+			error_status = ERRHLE;
+		}
+		if (raw_int_stat & INTMSK_SBE) {
+			error_status = ERRSTARTBIT;
+		}		
+		if (raw_int_stat & INTMSK_EBE) {
+			error_status = ERRENDBITERR;
+		}
+	}
+
+//SDIO_PRINTF("------- %s, line %d raw_int_stat = %08x-------\n", __FUNCTION__, __LINE__, raw_int_stat);
+	return error_status;
+}
+
+static int synopmob_check_r1_resp(unsigned int the_response)
+{
+	int retval = 0;
+	
+	if (the_response & R1CS_ERROR_OCCURED_MAP) {
+		if (the_response & R1CS_ADDRESS_OUT_OF_RANGE) {
+			retval = ERRADDRESSRANGE;
+		} else if (the_response & R1CS_ADDRESS_MISALIGN) {
+			retval = ERRADDRESSMISALIGN;
+		} else if (the_response & R1CS_BLOCK_LEN_ERR) {
+			retval = ERRBLOCKLEN;
+		} else if (the_response & R1CS_ERASE_SEQ_ERR) {
+			retval = ERRERASESEQERR;
+		} else if (the_response & R1CS_ERASE_PARAM) {
+			retval = ERRERASEPARAM;
+		} else if (the_response & R1CS_WP_VIOLATION) {
+			retval = ERRPROT;
+		} else if (the_response & R1CS_CARD_IS_LOCKED) {
+			retval = ERRCARDLOCKED;
+		} else if (the_response & R1CS_LCK_UNLCK_FAILED) {
+			retval = ERRCARDLOCKED;
+		} else if (the_response & R1CS_COM_CRC_ERROR) {
+			retval = ERRCRC;
+		} else if (the_response & R1CS_ILLEGAL_COMMAND) {
+			retval = ERRILLEGALCOMMAND;
+		} else if (the_response & R1CS_CARD_ECC_FAILED) {
+			retval = ERRECCFAILED;
+		} else if (the_response & R1CS_CC_ERROR) {
+			retval = ERRCCERR;
+		} else if (the_response & R1CS_ERROR) {
+			retval = ERRUNKNOWN;
+		} else if (the_response & R1CS_UNDERRUN) {
+			retval = ERRUNDERRUN;
+		} else if (the_response & R1CS_OVERRUN) {
+			retval = ERROVERRUN;
+		} else if (the_response & R1CS_CSD_OVERWRITE) {
+			retval = ERRCSDOVERWRITE;
+		} else if (the_response & R1CS_WP_ERASE_SKIP) {
+			retval = ERRPROT;
+		} else if (the_response & R1CS_ERASE_RESET) {
+			retval = ERRERASERESET;
+		} else if (the_response & R1CS_SWITCH_ERROR) {
+			retval = ERRFSMSTATE;
+		}
+	}
+	
+	return retval;
+}
+
+
+static int synopmob_check_r5_resp(unsigned int the_resp)
+{
+	int ret = 0;
+	
+	if (the_resp & R5_IO_ERR_BITS) {
+		if (the_resp & R5_IO_CRC_ERR) {
+			ret = ERRDCRC;
+		} else if (the_resp & R5_IO_BAD_CMD) {
+			ret = ERRILLEGALCOMMAND;
+		} else if (the_resp & R5_IO_GEN_ERR) {
+			ret = ERRUNKNOWN;
+		} else if (the_resp & R5_IO_FUNC_ERR) {
+			ret = ERRBADFUNC;
+		} else if (the_resp & R5_IO_OUT_RANGE) {
+			ret = ERRADDRESSRANGE;
+		}
+	}
+	
+	return ret;
+}
+
+static int sd_send_cmd0(sdc_t* sdc)
+{
+	int   ret;
+	unsigned int intst;
+	unsigned int base = sdc->ip_base;
+
+	ret = synopmob_execute_command(base, 0x4000, 0);
+	if (!ret) {
+		ret = synopmob_wait_command_done(base, &intst, INTMSK_CMD_DONE);
+		if (!ret) {
+			synopmob_set_register(base+RINTSTS, intst);
+			return synopmob_handle_standard_rinsts(intst);
+		}
+	}
+
+	return ret;
+}
+
+static int sd_send_cmd2(sdc_t* sdc)
+{
+	int   ret;
+	unsigned int intst;
+	unsigned int base = sdc->ip_base;
+
+	ret = synopmob_execute_command(base, 0xC2, 0);
+	if (!ret) {
+		ret = synopmob_wait_command_done(base, &intst, INTMSK_CMD_DONE);
+		if (!ret) {
+			synopmob_set_register(base+RINTSTS, intst);
+			return synopmob_handle_standard_rinsts(intst);
+		}
+	}
+
+	return ret;
+}
+
+static int sd_send_cmd3(sdc_t* sdc)
+{
+	int   ret;
+	unsigned int intst;
+	unsigned int resp;
+	unsigned int base = sdc->ip_base;
+
+	ret = synopmob_execute_command(base, 0x43, 0);
+	if (!ret) {
+		ret = synopmob_wait_command_done(base, &intst, INTMSK_CMD_DONE);
+		if (!ret) {
+			synopmob_set_register(base+RINTSTS, intst);
+			ret = synopmob_handle_standard_rinsts(intst);
+			if (!ret) {
+				resp = synopmob_read_register(base+RESP0);
+				sdc->rca = resp >> 16;
+				resp = (resp & 0x1fff) | (((resp>>13)&1)<<19) | (((resp>>14)&3)<<22);
+				return synopmob_check_r1_resp(resp);
+			}
+		}		
+	}
+
+	return ret;
+}
+
+static int sd_send_cmd_r1(sdc_t* sdc, unsigned int cmd, unsigned int arg, unsigned int buzy)
+{
+	int   ret;
+	unsigned int intst;
+	unsigned int resp;
+	unsigned int base = sdc->ip_base;
+	
+	ret = synopmob_execute_command(base, cmd,  arg);
+	if (!ret) {
+		ret = synopmob_wait_command_done(base, &intst, INTMSK_CMD_DONE);
+		if (!ret) {
+			synopmob_set_register(base+RINTSTS, intst);
+			ret = synopmob_handle_standard_rinsts(intst);
+			if (!ret) {
+				resp = synopmob_read_register(base+RESP0);
+				ret = synopmob_check_r1_resp(resp);
+				if (buzy && !ret) {
+					ret = synopmob_wait_data_ready(base);
+				}
+			}
+		}
+	}
+
+	return ret;
+}
+
+static int sd_send_cmd7(sdc_t* sdc)
+{
+	return sd_send_cmd_r1(sdc, 0x47, sdc->rca<<16, 1);
+}
+
+static int sd_send_uncmd7(sdc_t* sdc)
+{
+	int   ret;
+	unsigned int intst;
+	unsigned int base = sdc->ip_base;
+
+	ret = synopmob_execute_command(base, 0x7, 0);
+	if (!ret) {
+		ret = synopmob_wait_command_done(base, &intst, INTMSK_CMD_DONE);
+		if (!ret) {
+			synopmob_set_register(base+RINTSTS, intst);
+			ret = synopmob_handle_standard_rinsts(intst);
+		}
+	}
+
+	return ret;
+}
+
+static int sd_send_cmd16(sdc_t* sdc)
+{
+	return sd_send_cmd_r1(sdc, 0x50, 512, 0);
+}
+
+static int sd_send_cmd55(sdc_t* sdc)
+{
+	return sd_send_cmd_r1(sdc, 0x77, sdc->rca<<16, 0);
+}
+
+static int sd_send_acmd6(sdc_t* sdc, unsigned int bitwidth)
+{
+	unsigned int cmd_arg;
+	int   ret;
+	unsigned int base = sdc->ip_base;
+
+	ret = sd_send_cmd55(sdc);
+	if (!ret) {	
+		cmd_arg = 0; //default to 1bit mode
+		if (bitwidth == 4) {
+			cmd_arg = 2; // 4bit mode
+		}
+		ret = sd_send_cmd_r1(sdc, 0x2046, cmd_arg, 0);
+		if (!ret) {
+			if (bitwidth == 4) {
+				synopmob_set_register(base+CTYPE, FOUR_BIT_MODE);
+			}
+			else {
+				synopmob_set_register(base+CTYPE, ONE_BIT_MODE);
+			}
+		}
+	}
+
+	return ret;
+}
+
+#ifdef SDC_USE_IDMA
+static int sdc_read_write_block(HSDC handle, unsigned int rw, unsigned int blk, unsigned int num, unsigned char* buffer)
+{
+	sdc_t* sdc = (sdc_t*)handle;
+	volatile DmaDesc *pDmaDesc = sdc->pDmaDesc;
+	int   ret;
+	unsigned int intsts = 0;
+	unsigned int cmd;
+	unsigned int multi = 0;
+	unsigned int base = sdc->ip_base;
+	int   loop_for_command_done_check = DATA_TRANSFER_OVER_TIMEOUT_USEC;
+	rt_err_t err;	
+
+	// valid check
+	if (synopmob_read_register(base+CDETECT) & 1) {
+		return ERRCARDNOTCONN;
+	}
+	if (!num || num > 16) {
+		return ERRNOTSUPPORTED;
+	}
+	if (blk + num > sdc->sectors) {
+		return ERRADDRESSRANGE;
+	}
+
+	if ( rw ) {
+		flush_dcache_range((unsigned long)buffer, num << 9);
+	}
+	else {
+	    // to avoid memset bug?
+		inv_dcache_range((unsigned long)buffer, num << 9);
+    }
+
+	err = rt_sem_take(sdc->mutex, RT_WAITING_FOREVER);
+	if (err != RT_EOK) {
+		return ERRNORES;
+	}
+
+	// reset
+	synopmob_set_bits(base+CTRL, FIFO_RESET); //reset FIFO
+	while (synopmob_read_register(base+CTRL) & FIFO_RESET);
+	synopmob_set_register(base + RINTSTS, 0xfffe); //clear interrupts
+
+	cmd = 0x2658; // write
+	if ( !rw ) {
+		cmd = 0x2251; //read
+	}
+	//if (num > 1) {
+	if (num >= 1) { // some card fail on sigle-block mode, so use multi-block instead of sigle-block mode.
+		cmd++;
+		multi++;
+	}
+	if (sdc->card_type == SD_TYPE) {
+		blk <<= 9; //SD stadand capability card use 512 unit.
+	}
+	num <<= 9;
+	
+	pDmaDesc->desc0 |= DescOwnByDma | DescFirstDesc | DescLastDesc;
+	pDmaDesc->desc1 = ((num << DescBuf1SizeShift) & DescBuf1SizMsk);
+	pDmaDesc->desc2 = (unsigned int)buffer;
+	flush_dcache_range((unsigned long)pDmaDesc, sizeof(DmaDesc)); // add SZ_ADJUST
+	synopmob_set_register(base + DBADDR, (unsigned int)(pDmaDesc)); // add SZ_ADJUST
+	synopmob_set_register(base+BLKSIZ, 512);
+	synopmob_set_register(base+BYTCNT, num);
+	synopmob_set_bits(base + CTRL, CTRL_USE_IDMAC);
+	synopmob_set_bits(base + BMOD,BMOD_DE);
+	
+	ret = synopmob_execute_command(base, cmd,  blk);
+	if ( !ret ) {
+		ret = ERRIDMA;
+		synopmob_set_bits(base+CTRL, INT_ENABLE);
+		err = rt_sem_take(sdc->sem, DMA_TRANSFER_TIMEOUT_TICKS);
+		if ( !err ) {
+			while (--loop_for_command_done_check > 0) {
+				intsts = synopmob_read_register(base+RINTSTS);
+				if ((intsts & (INTMSK_CMD_DONE|INTMSK_DAT_OVER)) == (INTMSK_CMD_DONE|INTMSK_DAT_OVER)) {
+					break;
+				}
+				plat_loop(1);
+			}
+			ret = synopmob_handle_standard_rinsts(intsts);
+			if (!ret ) {
+				if( !loop_for_command_done_check || !(sdc->idsts & 0x100)) { //normal interrupt
+					ret = ERRIDMA;
+				}
+			}
+		}
+	}
+
+	if (ret) {
+	   	char* op = "read";
+	   	if (rw) 
+	   		op = "write";
+	   		
+	        SDIO_PRINTF("sdc_read_write_block(%s) fail:, ret = %d\n", op, ret);
+	}
+
+	synopmob_clear_bits(base+CTRL, INT_ENABLE);
+	synopmob_clear_bits(base + CTRL, CTRL_USE_IDMAC);
+	synopmob_clear_bits(base + BMOD,BMOD_DE);
+
+	synopmob_set_register(base+BLKSIZ, 512);
+	synopmob_set_register(base+BYTCNT, 512);
+
+	synopmob_set_register(base + RINTSTS, 0xfffe);
+
+	if ( !ret && rw) {
+		ret = synopmob_wait_data_ready(base);
+	}
+
+	if (!ret && multi ) { //send STOP_TRANSACTION command
+		ret = sd_send_cmd_r1(sdc, 0x404c, 0, 1);
+	}
+
+	rt_sem_release(sdc->mutex);
+	
+	if ( !rw && !ret ) { //read
+		inv_dcache_range((unsigned long)buffer, num);
+	}
+	
+	return ret;
+}
+#else  //no IDMA
+static int sdc_read_write_block(HSDC handle, unsigned int rw, unsigned int blk, unsigned int num, unsigned char* buffer)
+{
+	sdc_t* sdc = (sdc_t*)handle;
+	volatile DmaDesc *pDmaDesc = sdc->pDmaDesc;
+	int   ret;
+	unsigned int intsts = 0;
+	unsigned int entries;
+	unsigned int cmd;
+	unsigned int multi = 0;
+	unsigned int base = sdc->ip_base;
+	int   loop_for_command_done_check = DATA_TRANSFER_OVER_TIMEOUT_USEC;
+	rt_err_t err;	
+
+	// valid check
+	if (synopmob_read_register(base+CDETECT) & 1) {
+		return ERRCARDNOTCONN;
+	}
+	if (!num || num > 16) {
+		return ERRNOTSUPPORTED;
+	}
+	if (blk + num > sdc->sectors) {
+		return ERRADDRESSRANGE;
+	}
+
+	if ( rw ) {
+		flush_dcache_range((unsigned long)buffer, num << 9);
+	}
+	else {
+	    // to avoid memset bug?
+		inv_dcache_range((unsigned long)buffer, num << 9);
+    }
+
+	err = rt_sem_take(sdc->mutex, RT_WAITING_FOREVER);
+	if (err != RT_EOK) {
+		return ERRNORES;
+	}
+
+	// reset
+	synopmob_set_bits(base+CTRL, FIFO_RESET); //reset FIFO
+	while (synopmob_read_register(base+CTRL) & FIFO_RESET);
+	synopmob_set_register(base + RINTSTS, 0xfffe); //clear interrupts
+
+	cmd = 0x2658; // write
+	if ( !rw ) {
+		cmd = 0x2251; //read
+	}
+	if (num > 1) {
+		cmd++;
+		multi++;
+	}
+	if (sdc->card_type == SD_TYPE) {
+		blk <<= 9; //SD stadand capability card use 512 unit.
+	}
+	num <<= 9;
+	
+	synopmob_set_register(base+BLKSIZ, 512);
+	synopmob_set_register(base+BYTCNT, num);
+	
+	ret = synopmob_execute_command(base, cmd,  blk);
+	if ( !ret ) {
+		while (1) {
+			ret = synopmob_wait_command_done(base, &intsts, 0);
+			if (ret)
+				break;
+
+			ret = synopmob_handle_standard_rinsts(intsts);
+			if (ret)
+				break;
+
+			if (!rw && (intsts & (INTMSK_RXDR|INTMSK_DAT_OVER)) ){
+				while (num > 0 ) {
+					entries = synopmob_read_register(base + STATUS);
+					if (!GET_FIFO_COUNT(entries))
+						break;
+					*((volatile unsigned int*)buffer) = synopmob_read_register(base + FIFODAT);
+					buffer += 4;
+					num -= 4;
+				}
+			}
+			
+			if (rw && ( intsts & INTMSK_TXDR ) ) {
+				while (num > 0) {
+					entries = synopmob_read_register(base+STATUS);
+					if ( entries & 8 ) { //FIFO is full
+						break;
+					}
+					synopmob_set_register(base+FIFODAT, *((volatile unsigned int*)buffer));
+					buffer += 4;
+					num -= 4;
+				}
+			}
+			
+			if ( intsts & INTMSK_DAT_OVER ) {
+				break;
+			}
+
+			if (intsts & INTMSK_CMD_DONE) {
+				entries = synopmob_read_register(base+RESP0);
+				ret = synopmob_check_r1_resp(entries);
+				if (ret) {
+					break;
+				}
+			}
+
+			synopmob_set_register(base+RINTSTS, intsts); //write to clear
+			intsts = 0;
+		}		
+		
+		if (intsts) {
+			synopmob_set_register(base+RINTSTS, intsts); //write to clear
+		}
+	}
+
+	synopmob_set_register(base+BLKSIZ, 512);
+	synopmob_set_register(base+BYTCNT, 512);
+	synopmob_set_register(base + RINTSTS, 0xfffe);
+
+	if ( !ret && rw) {
+		ret = synopmob_wait_data_ready(base);
+	}
+
+	if (!ret && multi ) { //send STOP_TRANSACTION command
+		ret = sd_send_cmd_r1(sdc, 0x404c, 0, 1);
+	}
+
+	rt_sem_release(sdc->mutex);
+	
+	if ( !rw && !ret ) { //read
+		inv_dcache_range((unsigned long)buffer, num);
+	}
+	
+	return ret;
+}
+#endif //SDC_USE_IDMA
+
+int sdc_write_block(HSDC handle, unsigned int blk, unsigned int num, unsigned char* buffer)
+{
+	return sdc_read_write_block(handle, 1, blk, num, buffer);
+}
+
+int sdc_read_block(HSDC handle, unsigned int blk, unsigned int num, unsigned char* buffer)
+{
+	return sdc_read_write_block(handle, 0, blk, num, buffer);
+}
+
+int sdc_erase_block(HSDC handle, unsigned int blk, unsigned int num)
+{
+	int   ret;
+	sdc_t* sdc = (sdc_t*)handle;
+	
+	if (sdc->card_type == SD_TYPE) {
+		blk <<= 9; //SD stadand capability card use 512 unit.
+		num = ((num-1)<<9) + blk;
+	}
+	else {
+		num = blk + num - 1;
+	}
+	
+	ret = sd_send_cmd_r1(sdc, 0x40|32, blk, 0); // cmd32
+	if (!ret) {
+		ret = sd_send_cmd_r1(sdc, 0x40|33, num, 0); // cmd33
+		if (!ret) {
+			ret = sd_send_cmd_r1(sdc, 0x40|38, 0, 1); // cmd38
+		}
+	}
+
+	return ret;
+}
+
+int sdc_get_sector_num(HSDC handle)
+{
+	return ((sdc_t*)handle)->sectors;
+}
+
+static int sd_send_cmd9(sdc_t* sdc)
+{
+	int   ret;
+	unsigned int intst;
+	unsigned int resp0;
+	unsigned int resp1;
+	unsigned int resp2;
+	unsigned int resp3;
+	unsigned int base = sdc->ip_base;
+	unsigned int C_SIZE;
+	unsigned int C_SIZE_MULT;
+	unsigned int READ_BL_LEN;
+
+	ret = synopmob_execute_command(base, 0xC9, sdc->rca<<16);
+	if (!ret) {
+		ret = synopmob_wait_command_done(base, &intst, INTMSK_CMD_DONE);
+		if (!ret) {
+			synopmob_set_register(base+RINTSTS, intst);
+			ret = synopmob_handle_standard_rinsts(intst);
+			if (!ret) {
+				sdc->csd[0] = resp0 = synopmob_read_register(base+RESP0);
+				sdc->csd[1] = resp1 = synopmob_read_register(base+RESP1);
+				sdc->csd[2] = resp2 = synopmob_read_register(base+RESP2);
+				sdc->csd[3] = resp3 = synopmob_read_register(base+RESP3);
+				
+				if ((resp3>>30) == 0) { //CSD version 1.0
+					C_SIZE = (resp1 >> 30) | ((resp2 & 0x3ff)<<2);
+					C_SIZE_MULT = ((resp1 >> 15) & 0x07);				
+					READ_BL_LEN = ((resp2 >> 16) & 0xf);
+					sdc->sectors = ((((C_SIZE+1)<<(C_SIZE_MULT+2))<<(READ_BL_LEN))>>9);
+				}
+				else { //CSD version 2.0
+					sdc->sectors = (((resp1 >> 16)+1)<<10);
+				}
+			}
+		}		
+	}
+
+	return ret;
+}
+
+static int sd_send_cmd5(sdc_t* sdc, unsigned int arg, unsigned int* resp)
+{
+	unsigned int cmd_reg = 0x45;
+	unsigned int intst;
+	int   ret;
+	unsigned int base = sdc->ip_base;
+
+	ret = synopmob_execute_command(base, cmd_reg, arg);
+	if (!ret) {
+		ret = synopmob_wait_command_done(base, &intst, INTMSK_CMD_DONE);
+		if (!ret) {
+			synopmob_set_register(base+RINTSTS, intst);
+			ret = synopmob_handle_standard_rinsts(intst);
+			if (!ret) {
+				*resp = synopmob_read_register(base+RESP0);
+			}
+		}
+	}
+	
+	return ret;	
+}
+
+static int sd_send_cmd8(sdc_t* sdc)
+{
+	int   ret;
+	unsigned int cmd_reg = 0x48;
+	unsigned int intst;
+	unsigned int err = 0;
+	unsigned int base = sdc->ip_base;
+	
+	ret = synopmob_execute_command(base, cmd_reg, 0x000001A5);
+	if (!ret) {
+		while (1) {
+			ret = synopmob_wait_command_done(base, &intst, 0);
+			if (!ret) {
+				synopmob_set_register(base+RINTSTS, intst);
+				err |= synopmob_handle_standard_rinsts(intst);
+				if (intst & INTMSK_CMD_DONE) {
+					break;
+				}
+			}
+		}
+	}
+
+	return err;
+}
+
+static int sd_send_acmd41(sdc_t* sdc, int* hcs)
+{
+	unsigned int cmd_reg = 0x69;
+	unsigned int resp;
+	int   ret = 0;
+	unsigned int count = ACMD41_RETRY_COUNT;
+	unsigned int cmd_arg = 0xff8000;
+	unsigned int base = sdc->ip_base;
+
+	if (*hcs) {
+		cmd_arg |= (1<<30);
+	}
+	while ( count > 0) {
+		SDC_WHERE();
+		ret = sd_send_cmd55(sdc);
+		if (ret)
+			break;
+
+		SDC_WHERE();
+		ret = synopmob_execute_command(base, cmd_reg, cmd_arg);
+		if (ret)
+			break;
+
+		SDC_WHERE();
+		ret = synopmob_wait_command_done(base, &resp, INTMSK_CMD_DONE);
+		if ( ret ) 
+			break;
+
+		SDC_WHERE();
+		synopmob_set_register(base+RINTSTS, resp);
+		ret = synopmob_handle_standard_rinsts(resp);
+		if (!ret) {
+			SDC_WHERE();
+			resp = synopmob_read_register(base+RESP0);
+			if (resp & 0x80000000) { //card is ready.
+				SDC_WHERE();
+				if ( !(resp & (1<<30)) ) {
+					SDC_WHERE();
+					*hcs = 0;
+				}
+				if ( (resp & 0x00ff8000) != 0x00ff8000 ) { //not supported voltage
+					ret = ERRHARDWARE;
+				}
+				break;
+			}
+		}
+
+		--count;
+		plat_loop(1);
+	}
+
+	if (!count)
+		ret = ERRACMD41TIMEOUT;
+	
+	return ret;
+}
+
+static int sd_send_acmd51(sdc_t* sdc) //Send SCR
+{
+	unsigned int cmd_reg = 0x2273;
+	unsigned int resp;
+	int   ret;
+	unsigned int intst = 0;
+	unsigned int entries;
+	int   count = 1;
+	unsigned int base = sdc->ip_base;
+
+	ret = sd_send_cmd55(sdc);
+	if (!ret) {	
+		synopmob_set_register(base+BLKSIZ, 8);
+		synopmob_set_register(base+BYTCNT, 8);
+		ret = synopmob_execute_command(base, cmd_reg, 0);
+		if (!ret) {
+			while (1) {
+				ret = synopmob_wait_command_done(base, &intst, 0);
+				if (ret) {
+					break;
+				}
+
+				ret = synopmob_handle_standard_rinsts(intst);
+				if (ret) {
+					break;
+				}
+				
+				if (intst & INTMSK_CMD_DONE) {
+					resp = synopmob_read_register(base+RESP0);
+					ret = synopmob_check_r1_resp(resp);
+					if (ret) 
+						break;
+				}
+
+				if (intst & INTMSK_DAT_OVER) {
+					entries = synopmob_read_register(base + STATUS);
+					if (GET_FIFO_COUNT(entries) == 2) {
+						while (count >= 0) {
+							entries = synopmob_read_register(base + FIFODAT);
+							sdc->scr[count--] = BE32_TO_CPU(entries);
+						}
+					}
+					break;
+				}
+
+				synopmob_set_register(base+RINTSTS, intst);
+				intst = 0;
+			}
+
+			if (intst) {
+				synopmob_set_register(base+RINTSTS, intst);
+			}
+		}
+
+		synopmob_set_register(base+BLKSIZ, 512);
+		synopmob_set_register(base+BYTCNT, 512);
+	}
+
+	return ret;
+}
+
+
+static int sd_send_cmd6(sdc_t* sdc, unsigned int cmd_arg, unsigned int* data_buff) 
+{
+	unsigned int cmd_reg = 0x2246;
+	unsigned int resp;
+	int   ret;
+	unsigned int intst = 0;
+	unsigned int entries;
+	int   count = 64;
+	unsigned int base = sdc->ip_base;
+
+	synopmob_set_register(base+BLKSIZ, 64);
+	synopmob_set_register(base+BYTCNT, 64);
+	ret = synopmob_execute_command(base, cmd_reg, cmd_arg);
+	if (!ret) {
+		while (1) {
+			ret = synopmob_wait_command_done(base, &intst, 0);
+			if (ret) {
+				break;
+			}
+
+			ret = synopmob_handle_standard_rinsts(intst);
+			if (ret) {
+				break;
+			}
+				
+			if (intst & INTMSK_CMD_DONE) {
+				resp = synopmob_read_register(base+RESP0);
+				ret = synopmob_check_r1_resp(resp);
+				if (ret) 
+					break;
+			}
+
+			while (count > 0) {
+				entries = synopmob_read_register(base + STATUS);
+				if ( !GET_FIFO_COUNT(entries) ) {
+					break;
+				}
+				*(data_buff++) = synopmob_read_register(base + FIFODAT);
+				count -= 4;
+			}
+
+			if (intst & INTMSK_DAT_OVER) {
+				break;
+			}
+
+			synopmob_set_register(base+RINTSTS, intst); //write to clear
+			intst = 0;
+		}
+
+		if (intst) {
+			synopmob_set_register(base+RINTSTS, intst); //write to clear
+		}
+	}
+
+	synopmob_set_register(base+BLKSIZ, 512);
+	synopmob_set_register(base+BYTCNT, 512);
+
+	return ret;
+}
+
+static int synopmob_send_clock_only_cmd(unsigned int base)
+{
+	return synopmob_execute_command(base, 0x202000, 0);
+}
+
+
+static int synopmob_disable_all_clocks(unsigned int base)
+{
+	synopmob_set_register(base+CLKENA, 0);
+	return synopmob_send_clock_only_cmd(base);
+}
+
+static int synopmob_enable_clocks_with_val(unsigned int base, unsigned int val)
+{
+	synopmob_set_register(base+CLKENA, val);
+	return synopmob_send_clock_only_cmd(base);
+}
+
+
+static int synopmob_set_clk_freq(sdc_t* sdc, unsigned int divider)
+{
+	#define MAX_DIVIDER_VALUE      0xff
+	
+	unsigned int orig_clkena;
+	int  retval;
+	unsigned int base = sdc->ip_base;
+
+	if (divider > MAX_DIVIDER_VALUE) {
+		return 0xffffffff;
+	}
+
+	/* To make sure we dont disturb enable/disable settings of the cards*/
+	orig_clkena = synopmob_read_register(base+CLKENA);
+
+	/* Disable all clocks before changing frequency the of card clocks */
+	if ((retval = synopmob_disable_all_clocks(base)) != 0) {
+		return retval;
+	}
+	/* Program the clock divider in our case it is divider 0 */
+	synopmob_clear_bits(base+CLKDIV, MAX_DIVIDER_VALUE);
+	synopmob_set_bits(base+CLKDIV, divider);
+	
+	/*Send the command to CIU using synopmob_send_clock_only_cmd and enable the clocks in CLKENA register */
+	if ((retval = synopmob_send_clock_only_cmd(base)) != 0) {
+		synopmob_enable_clocks_with_val(base, orig_clkena);
+		return retval;
+	}
+
+	return synopmob_enable_clocks_with_val(base, orig_clkena);
+}
+
+static int enum_sd_card(sdc_t* sdc)
+{
+	int ret;
+	int count = 1000;
+	int hcs = 0;
+	unsigned int buffer[16];
+	unsigned int base = sdc->ip_base;
+
+	if (synopmob_read_register(base+CDETECT) & 1) {
+		return ERRCARDNOTCONN;
+	}
+	
+	#if 0
+	synopmob_set_bits(0x98500004, (1<<24)); //set to output mode
+	synopmob_set_bits(0x98500000, (1<<24)); //power off
+	plat_loop(1000000/5); //Lets give some ramp down period
+	synopmob_clear_bits(0x98500000, (1<<24)); //power on
+	plat_loop(1000000/5);//Lets give some ramp down period
+	#endif
+	
+	synopmob_set_register(base+CTYPE, ONE_BIT_MODE);
+
+	synopmob_set_register(base+CLKENA, 0x00000001); /*enable clock, non-low-power mode*/
+	ret = synopmob_set_clk_freq(sdc, MMC_FOD_DIVIDER_VALUE);
+	
+	if ( !ret ) {
+		plat_loop(1000); //enough for 74 clock.	
+		SDC_WHERE();
+		ret = sd_send_cmd0(sdc); //CMD0 has no response
+	}
+	
+	if ( !ret ) {
+		SDC_WHERE();
+		ret = sd_send_cmd8(sdc); //even if CMD8 get response, it may be V1.0 card.
+		if (!ret) {
+			hcs = 1;
+		}
+		SDC_WHERE();
+		ret = sd_send_acmd41(sdc, &hcs);
+	}
+
+	if (!ret) {
+		SDC_WHERE();
+		ret = sd_send_cmd2(sdc); //CID
+	}
+
+	if (!ret) {
+		SDC_WHERE();
+		ret = sd_send_cmd3(sdc); //get RCA
+	}
+
+	if (!ret) {
+		SDC_WHERE();
+		ret = sd_send_cmd9(sdc); //CSD
+	}
+
+	if (!ret) {
+		SDC_WHERE();
+		ret = sd_send_cmd7(sdc); //select the card
+	}
+
+	if (!ret && (sdc->wkmod & SDC_WKMOD_4WIRE) ) {
+		SDC_WHERE();
+		ret = sd_send_acmd51(sdc); //SCR
+		if (!ret && (sdc->scr[1] & 0x00040000)) { // 4bit mode supported?
+			ret = sd_send_acmd6(sdc, 4); //switch to 4bit mode
+		}
+	}
+	
+	if (!ret && (sdc->wkmod & SDC_WKMOD_50M_HI_SPEED) && (sdc->csd[2] & 0x40000000) ) { //judge whether class10 is supported? CMD6 is belonging to class10.
+		SDC_WHERE();
+		ret = sd_send_cmd6(sdc, 0x00fffff1, buffer); //switch to high speed mode.
+		if ( !ret &&  (*(((unsigned char*)buffer)+13)&0x02) ) { //the card support high speed mode?
+			SDC_WHERE();
+			ret = sd_send_cmd6(sdc, 0x80fffff1, buffer); //switch to high speed mode.
+			if (!ret && ((*(((unsigned char*)buffer)+16) & 0xf) == 1) ) {
+				//switch to high speed mode sucess.
+				sd_send_uncmd7(sdc); //deselect the card
+				sd_send_cmd9(sdc); //CSD
+				ret = sd_send_cmd7(sdc); //select the card
+			}
+		}
+	}
+	
+	if (!ret && (sdc->wkmod & (SDC_WKMOD_50M_HI_SPEED|SDC_WKMOD_25M_STAND_SPEED))) {
+		if ( (sdc->csd[3] & 0xff) == 0x5A ) { //50MHz high speed mode.			
+			SDC_WHERE();
+			ret = synopmob_set_clk_freq(sdc, (((CIU_CLK)/(50000*2))));
+		}
+		else if ( (sdc->csd[3] & 0xff) == 0x32 ) {
+			SDC_WHERE(); //25MHz standard speed mode.
+			ret = synopmob_set_clk_freq(sdc, sdc_clk_divider/*ONE_BIT_BUS_FREQ*/);
+		}
+	}
+
+	if (!ret) {
+		sdc->card_type = SD_TYPE;
+		if (hcs) {
+			sdc->card_type = SD_2_0_TYPE;
+		}
+	}
+
+	return ret;
+}
+
+int sdio_drv_creg_read(HSDC handle, int addr, int fn, unsigned int *resp)
+{
+	sdc_t* sdc = (sdc_t*)handle;
+	unsigned int arg;
+	unsigned int cmd_reg = 0x74;
+	unsigned int intst;
+	int   ret;
+	unsigned int base = sdc->ip_base;
+	rt_err_t err;
+
+    if(resp) {
+        *resp = 0;
+    }
+    
+	err = rt_sem_take(sdc->mutex, RT_WAITING_FOREVER);
+	if (err != RT_EOK) {
+		return ERRNORES;
+	}
+
+	arg = (fn << 28) | (addr << 9);
+	ret = synopmob_execute_command(base, cmd_reg, arg);
+	if (!ret) {
+		ret = synopmob_wait_command_done(base, &intst, INTMSK_CMD_DONE);
+		if (!ret) {
+			synopmob_set_register(base+RINTSTS, intst); //write to clear
+			ret = synopmob_handle_standard_rinsts(intst);
+			if (!ret) {
+				*resp = synopmob_read_register(base+RESP0);
+				ret = synopmob_check_r5_resp(*resp);
+			}
+		}
+	}
+
+	rt_sem_release(sdc->mutex);
+	
+	if (ret) {
+		ret++;
+		ret--;
+		SDIO_PRINTF("sdio_drv_creg_read fail:, ret = %d\n", ret);
+	}
+	
+	return ret;
+}
+
+int sdio_drv_creg_write(HSDC handle, int addr, int fn, unsigned char data, unsigned int *resp)
+{
+	sdc_t* sdc = (sdc_t*)handle;
+	unsigned int arg;
+	unsigned int cmd_reg = 0x74;
+	unsigned int intst;
+	int   ret;
+	unsigned int base = sdc->ip_base;
+	rt_err_t err;
+
+	err = rt_sem_take(sdc->mutex, RT_WAITING_FOREVER);
+	if (err != RT_EOK) {
+		return ERRNORES;
+	}
+	
+	arg = (1 << 31) | (fn << 28) | (1 << 27) | (addr << 9) | data;
+	ret = synopmob_execute_command(base, cmd_reg, arg);
+	if (!ret) {
+		ret = synopmob_wait_command_done(base, &intst, INTMSK_CMD_DONE);
+		if (!ret) {
+			synopmob_set_register(base+RINTSTS, intst); //write to clear
+			ret = synopmob_handle_standard_rinsts(intst);
+			if (!ret) {
+				*resp = synopmob_read_register(base+RESP0);
+				ret = synopmob_check_r5_resp(*resp);
+			}
+		}
+	}
+
+	rt_sem_release(sdc->mutex);
+	if (ret) {
+		ret++;
+		ret--;
+		SDIO_PRINTF("sdio_drv_creg_write fail:, ret = %d\n", ret);
+	}
+	
+	return ret;
+}
+
+#define ARC_REG_DC_IVDL 0x4A
+#define ARC_REG_DC_FLDL 0x4C
+#define ARC_REG_DC_CTRL 0x48
+#define FS_FLAG 0x100
+#define _psp_get_aux(aux_reg) \
+   (unsigned long)_lr((unsigned)(aux_reg))
+
+#define _psp_set_aux(aux_reg,value) \
+   _sr((unsigned)(value),(unsigned)(aux_reg))
+
+extern void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size);
+extern void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size);
+void inv_dcache_range(unsigned long start, unsigned long len)
+{
+	mmu_invalidate_dcache(start, len);
+}
+
+void flush_dcache_range(unsigned long start, unsigned long len)
+{
+	mmu_clean_dcache(start, len);
+}
+
+int g_use_bcm43362 = 0;
+static int sdio_drv_read_write(sdc_t* sdc, unsigned int rw, unsigned int addr, unsigned int fn, unsigned int bcnt,
+								   unsigned int bsize, unsigned char *buf)
+{
+	volatile DmaDesc *pDmaDesc = sdc->pDmaDesc;
+	int   ret;	
+	unsigned int intsts = 0;
+	unsigned int cmd = 0x2275;
+	unsigned int base = sdc->ip_base;
+	unsigned int arg;
+	unsigned int num;
+	int   loop_for_command_done_check = 10000;//DATA_TRANSFER_OVER_TIMEOUT_USEC;	
+	rt_err_t err;	
+
+//SDIO_PRINTF("------- %s, line %d buf = %08x size = %d -------\n", __FUNCTION__, __LINE__, buf, bsize);
+	arg = (fn << 28) | (addr << 9);
+
+	if (g_use_bcm43362) {
+		arg |= (1 << 26); //OPcode = 1............, for AP6181.
+	}
+
+	if (bcnt == 1 && bsize <= 512)
+		arg |= (bsize & 0x1ff);
+	else
+		arg |= ((1 << 27) | bcnt);	
+	if ( rw ) {
+		cmd |= 0x400;
+		arg |= (1 << 31);
+	}
+	num = bsize*bcnt;
+
+	if ( rw ) {
+		flush_dcache_range((unsigned long)buf, num);
+	}
+	else {
+		inv_dcache_range((unsigned long)buf, num);
+    }
+
+	err = rt_sem_take(sdc->mutex, RT_WAITING_FOREVER);
+	if (err != RT_EOK) {
+	return ERRNORES;
+	}
+
+//synopmob_set_bits(base+FIFOTH, 0x2 << 28);
+	// reset
+	synopmob_set_bits(base+CTRL, FIFO_RESET); //reset FIFO
+	while (synopmob_read_register(base+CTRL) & FIFO_RESET);
+	synopmob_set_register(base + RINTSTS, 0xfffe); //clear interrupts
+
+	//pDmaDesc->desc0 = 0;
+	pDmaDesc->desc0 |= DescOwnByDma | DescFirstDesc | DescLastDesc;
+	pDmaDesc->desc1 = ((num << DescBuf1SizeShift) & DescBuf1SizMsk);
+	pDmaDesc->desc2 = (unsigned int)buf;
+	//pDmaDesc->desc3 = 0;
+	flush_dcache_range((unsigned int)pDmaDesc, sizeof(DmaDesc));
+	synopmob_set_register(base+DBADDR, (unsigned int)pDmaDesc);
+	synopmob_set_register(base+BLKSIZ, bsize);
+	synopmob_set_register(base+BYTCNT, num);
+	synopmob_set_bits(base + CTRL, CTRL_USE_IDMAC);
+	synopmob_set_bits(base + BMOD,BMOD_DE);
+
+//SDIO_PRINTF("pDmaDesc = %08x, %08x / %08x / %08x / %08x\n", pDmaDesc, pDmaDesc->desc0, pDmaDesc->desc1, pDmaDesc->desc2, pDmaDesc->desc3);
+	ret = synopmob_execute_command(base, cmd,  arg);
+	if ( !ret ) {
+		ret = ERRIDMA;
+		err = rt_sem_take(sdc->sem, DMA_TRANSFER_TIMEOUT_TICKS);
+		if ( !err ) {
+			while (--loop_for_command_done_check > 0) {
+				intsts = synopmob_read_register(base+RINTSTS);
+				if ((intsts & (INTMSK_CMD_DONE|INTMSK_DAT_OVER)) == (INTMSK_CMD_DONE|INTMSK_DAT_OVER)) {
+					break;
+				}
+				plat_loop(1);
+			}
+			ret = synopmob_handle_standard_rinsts(intsts);
+			if (!ret ) {
+				if( !loop_for_command_done_check || !(sdc->idsts & 0x100)) { //normal interrupt
+SDIO_PRINTF("------- %s, line %d idsts = %08x check = %d -------\n", __FUNCTION__, __LINE__, sdc->idsts, loop_for_command_done_check);
+					ret = ERRIDMA;
+				}
+			}
+			else
+                SDIO_PRINTF("------- %s, line %d intsts = %08x buf = %08x -------\n", __FUNCTION__, __LINE__, intsts, buf);
+		}
+	}
+
+	if (!ret) {
+		synopmob_set_register(base + RINTSTS, 0xfffe); //clear interrupts
+		synopmob_clear_bits(base + CTRL, CTRL_USE_IDMAC);
+		synopmob_clear_bits(base + BMOD,BMOD_DE);
+		synopmob_set_register(base+BLKSIZ, 512);
+		synopmob_set_register(base+BYTCNT, 512);
+	}
+	else {
+   		char* op = "read";
+   		if (rw) 
+   			op = "write";
+   		
+        SDIO_PRINTF("sdio_drv_read_write1(%s) fail:, ret = %d\n", op, ret);
+	}
+		
+	if ( rw && !ret ) { //write
+		ret = synopmob_wait_data_ready(base);
+	}
+
+	rt_sem_release(sdc->mutex);
+
+	if ( !rw && !ret ) { //read
+		inv_dcache_range((unsigned long)buf, num);
+	}
+	
+       if (ret) {
+       		char* op = "read";
+       		if (rw) 
+       			op = "write";
+       		
+	        SDIO_PRINTF("sdio_drv_read_write2(%s) fail:, ret = %d\n", op, ret);
+       }
+	return ret;
+	//return ret ? 0/*false*/ : 1/*true*/;
+}
+
+int sdio_drv_read(HSDC handle, unsigned int addr, unsigned int fn, unsigned int bcnt,
+		   unsigned int bsize, unsigned char *buf)
+{
+	return sdio_drv_read_write((sdc_t*)handle, 0, addr, fn, bcnt, bsize, buf);
+}
+
+int sdio_drv_write(HSDC handle, unsigned int addr, unsigned int fn, unsigned int bcnt,
+		   unsigned int bsize, unsigned char *buf)
+{
+	return sdio_drv_read_write((sdc_t*)handle, 1, addr, fn, bcnt, bsize, buf);
+}
+
+static void dumpchain(DmaDesc *pChain)
+{
+    int i = 0;
+    DmaDesc *tmp_pChain = pChain;
+    
+    while(tmp_pChain && i < 10)
+    {
+        SDIO_PRINTF("[%d]: chain =%p, buf = %p, size = %d, csi = %08x, next = %p\n", i, tmp_pChain, (DmaDesc *)tmp_pChain->desc2, tmp_pChain->desc1, tmp_pChain->desc0, (DmaDesc *)tmp_pChain->desc3);
+        tmp_pChain = (DmaDesc *)tmp_pChain->desc3;
+        i++;
+
+        if(tmp_pChain == pChain)
+            break;
+    }
+}
+
+#ifdef DONT_COPY_NET_PAYLOAD_TO_SEND
+#if 1
+int sdio_drv_chain_write(sdc_t* sdc, unsigned int addr, unsigned int fn, unsigned int bcnt, unsigned int bsize, buf_chain_t *chain)
+{
+	int   ret;	
+	unsigned int intsts = 0;
+	unsigned int cmd = 0x2275;
+	unsigned int base = sdc->ip_base;
+	unsigned int arg;
+	unsigned int num;
+	unsigned int chain_len = 0;
+	int   loop_for_command_done_check = DATA_TRANSFER_OVER_TIMEOUT_USEC;	
+	rt_err_t err;	
+	unsigned int rw = 1;
+	DmaDesc *tmpDesc = (DmaDesc *)chain;
+	DmaDesc *lastDesc = (void*)0;
+
+	arg = (fn << 28) | (addr << 9);
+	if (bcnt == 1 && bsize <= 512)
+		arg |= (bsize & 0x1ff);
+	else
+		arg |= ((1 << 27) | bcnt);	
+	if ( rw ) {
+		cmd |= 0x400;
+		arg |= (1 << 31);
+	}
+	num = bsize*bcnt;
+
+	err = rt_sem_take(sdc->mutex, RT_WAITING_FOREVER);
+	if (err != RT_EOK) {
+		return ERRNORES;
+	}
+	
+	// reset
+	synopmob_set_bits(base+CTRL, FIFO_RESET); //reset FIFO
+	while (synopmob_read_register(base+CTRL) & FIFO_RESET);
+    	synopmob_set_register(base + RINTSTS, 0xfffe); //clear interrupts
+	
+    while(tmpDesc != 0) {
+        // make sure size is little than DescBuf1SizMsk
+        if(tmpDesc->desc1 > (DescBuf1SizMsk >> DescBuf1SizeShift)) {
+            // TBD... fix me 
+            rt_sem_release(sdc->mutex);
+            return 0;
+        }
+        // TBD... fix me, we must align tmpDesc->desc2 to 4 ?
+        
+        tmpDesc->desc0 = DescOwnByDma | DescSecAddrChained;
+        
+        // is it last node?
+        if(tmpDesc->desc3 == 0 || tmpDesc->desc3 == (unsigned int)chain) {
+    		tmpDesc->desc0 |= DescLastDesc;
+    		lastDesc = tmpDesc;
+        }
+        else {
+        	tmpDesc->desc0 |= DescDisInt; //disable interrupt...        	
+        }
+        
+        // is it first node?
+        if((char *)tmpDesc == (char *)chain) {
+    		tmpDesc->desc0 |= DescFirstDesc;
+        } 
+
+        flush_dcache_range(tmpDesc->desc2, tmpDesc->desc1);
+        
+        tmpDesc = (DmaDesc *)tmpDesc->desc3;
+        chain_len += sizeof(buf_chain_t);
+
+        if((char *)tmpDesc == (char *)chain) {
+        	break;
+        }
+    }
+
+    lastDesc->desc3 = (unsigned int)chain;
+
+	//FIXME, chain must be continuous arrry.
+	flush_dcache_range((unsigned long)chain, chain_len);
+
+	synopmob_set_register(base+DBADDR, (unsigned int)(chain));
+    
+	synopmob_set_register(base+BLKSIZ, bsize);
+	synopmob_set_register(base+BYTCNT, num);
+	synopmob_set_bits(base + CTRL, CTRL_USE_IDMAC);
+	synopmob_set_bits(base + BMOD,BMOD_DE);
+	
+	ret = synopmob_execute_command(base, cmd,  arg);
+	if ( !ret ) {
+		ret = ERRIDMA;
+		err = rt_sem_take(sdc->sem, DMA_TRANSFER_TIMEOUT_TICKS);
+		if ( !err ) {
+			while (--loop_for_command_done_check > 0) {
+				intsts = synopmob_read_register(base+RINTSTS);
+				if ((intsts & (INTMSK_CMD_DONE|INTMSK_DAT_OVER)) == (INTMSK_CMD_DONE|INTMSK_DAT_OVER)) {
+					break;
+				}
+				plat_loop(1);
+			}
+			ret = synopmob_handle_standard_rinsts(intsts);
+			if (!ret ) {
+				if( !loop_for_command_done_check || !(sdc->idsts & 0x100)) { //normal interrupt
+					ret = ERRIDMA;
+				}
+			}
+		}
+	}
+
+	if (!ret) {
+		synopmob_set_register(base + RINTSTS, 0xfffe); //clear interrupts
+		synopmob_clear_bits(base + CTRL, CTRL_USE_IDMAC);
+		synopmob_clear_bits(base + BMOD,BMOD_DE);
+		synopmob_set_register(base+BLKSIZ, 512);
+		synopmob_set_register(base+BYTCNT, 512);
+	}
+	else {
+	   		char* op = "read";
+	   		if (rw) 
+	   			op = "write";
+	   		
+	        SDIO_PRINTF("sdio_drv_chain_write1(%s) fail:, ret = %d, bsize = %d * %d\n", op, ret, bsize, bcnt);
+	        dumpchain((DmaDesc *)chain);
+	}
+
+	if ( rw && !ret ) {
+		ret = synopmob_wait_data_ready(base);
+	}
+
+	rt_sem_release(sdc->mutex);
+
+	if (ret) {
+		ret++;
+		ret--;
+	        SDIO_PRINTF("sdio_drv_chain_write2, fail:, ret = %d\n", ret);
+	}
+
+	return ret;
+	//return ret ? 0/*false*/ : 1/*true*/;
+}
+#elif 0
+int sdio_drv_chain_write(sdc_t* sdc, unsigned int addr, unsigned int fn, unsigned int bcnt, unsigned int bsize, buf_chain_t *chain)
+{
+	//static volatile DmaDesc __attribute__ ((aligned(32))) st_pchain[4];
+	volatile DmaDesc *st_pchain = (DmaDesc *)0x9a700000;
+		
+	int   ret;	
+	unsigned int intsts = 0;
+	unsigned int cmd = 0x2275;
+	unsigned int base = sdc->ip_base;
+	unsigned int arg;
+	unsigned int num;
+	unsigned int chain_len = 0;
+	int   loop_for_command_done_check = DATA_TRANSFER_OVER_TIMEOUT_USEC;	
+	char err;	
+	unsigned int rw = 1;
+
+	buf_chain_t *usrchain;
+	unsigned int desc0;
+	unsigned int length = 0;
+
+	if (!chain) {
+		return 0;
+	}
+
+	arg = (fn << 28) | (addr << 9);
+	if (bcnt == 1 && bsize <= 512)
+		arg |= (bsize & 0x1ff);
+	else
+		arg |= ((1 << 27) | bcnt);	
+	if ( rw ) {
+		cmd |= 0x400;
+		arg |= (1 << 31);
+	}
+	num = bsize*bcnt;
+
+	OSSemPend(sdc->mutex, 0, &err);
+	if (err != OS_NO_ERR) {
+		return ERRNORES;
+	}
+	
+	// reset
+	synopmob_set_bits(base+CTRL, FIFO_RESET); //reset FIFO
+	while (synopmob_read_register(base+CTRL) & FIFO_RESET);
+    	synopmob_set_register(base + RINTSTS, 0xfffe); //clear interrupts
+
+	usrchain = chain;
+    	while (1) {
+		if(usrchain->size > (DescBuf1SizMsk >> DescBuf1SizeShift)) {
+            		// TBD... fix me 
+	            OSSemPost (sdc->mutex);
+        	    return 0;
+		}
+		length += usrchain->size;
+    		desc0 = DescOwnByDma | DescSecAddrChained;
+    		if (!usrchain->next || usrchain->next == chain) {
+    			desc0 |= DescLastDesc;
+    		}
+		else {
+        		desc0 |= DescDisInt; //disable interrupt...        	
+		}        
+
+		if(usrchain == chain) {
+			desc0 |= DescFirstDesc;
+		}
+
+    		st_pchain[chain_len].desc0 = desc0;
+		st_pchain[chain_len].desc1 = (unsigned int)usrchain->size;
+		st_pchain[chain_len].desc2 = (unsigned int)usrchain->buf;
+		st_pchain[chain_len].desc3 = (unsigned int)(&st_pchain[chain_len+1]);
+		flush_dcache_range((unsigned int)usrchain->buf, usrchain->size);
+		
+		usrchain = usrchain->next;
+		if( !usrchain || usrchain == chain) {
+	        	break;
+		}
+		if (++chain_len >= 4) {
+			while(1) SDIO_PRINTF("sdio_drv_chain_write:long chain!\n");
+		}
+    	}
+	st_pchain[chain_len].desc3 = (unsigned int)(&st_pchain[0]);
+
+	if (length != num) {
+		while (1) SDIO_PRINTF("sdio_drv_chain_write:too long packet!\n");
+	}
+
+	synopmob_set_register(base+DBADDR, (unsigned int)(st_pchain));
+    
+	synopmob_set_register(base+BLKSIZ, bsize);
+	synopmob_set_register(base+BYTCNT, num);
+	synopmob_set_bits(base + CTRL, CTRL_USE_IDMAC);
+	synopmob_set_bits(base + BMOD,BMOD_DE);
+	
+	ret = synopmob_execute_command(base, cmd,  arg);
+	if ( !ret ) {
+		ret = ERRIDMA;
+		OSSemPend(sdc->sem, DMA_TRANSFER_TIMEOUT_TICKS, &err);
+		if ( !err ) {
+			while (--loop_for_command_done_check > 0) {
+				intsts = synopmob_read_register(base+RINTSTS);
+				if ((intsts & (INTMSK_CMD_DONE|INTMSK_DAT_OVER)) == (INTMSK_CMD_DONE|INTMSK_DAT_OVER)) {
+					break;
+				}
+				plat_loop(1);
+			}
+			ret = synopmob_handle_standard_rinsts(intsts);
+			if (!ret ) {
+				if( !loop_for_command_done_check || !(sdc->idsts & 0x100)) { //normal interrupt
+					ret = ERRIDMA;
+				}
+			}
+		}
+	}
+
+	if (!ret) {
+		synopmob_set_register(base + RINTSTS, 0xfffe); //clear interrupts
+		synopmob_clear_bits(base + CTRL, CTRL_USE_IDMAC);
+		synopmob_clear_bits(base + BMOD,BMOD_DE);
+		synopmob_set_register(base+BLKSIZ, 512);
+		synopmob_set_register(base+BYTCNT, 512);
+	}
+	else {
+	   	char* op = "read";
+	   	if (rw) 
+	   		op = "write";
+	   		
+	        SDIO_PRINTF("sdio_drv_chain_write1(%s) fail:, ret = %d\n", op, ret);
+	}
+
+	if ( rw && !ret ) {
+		ret = synopmob_wait_data_ready(base);
+	}
+
+	OSSemPost (sdc->mutex);
+
+	return ret;
+	//return ret ? 0/*false*/ : 1/*true*/;
+}
+#else
+static unsigned char __attribute__ ((aligned(32))) st_net_buf[2*1024];
+int sdio_drv_chain_write(sdc_t* sdc, unsigned int addr, unsigned int fn, unsigned int bcnt, unsigned int bsize, buf_chain_t *chain)
+{
+	static volatile DmaDesc __attribute__ ((aligned(32))) st_pchain;
+		
+	int   ret;	
+	unsigned int intsts = 0;
+	unsigned int cmd = 0x2275;
+	unsigned int base = sdc->ip_base;
+	unsigned int arg;
+	unsigned int num;
+	int   loop_for_command_done_check = DATA_TRANSFER_OVER_TIMEOUT_USEC;	
+	rt_err_t err;	
+	unsigned int rw = 1;
+
+	buf_chain_t *usrchain;
+	unsigned int length = 0;
+
+	if (!chain) {
+		return 0;
+	}
+
+	arg = (fn << 28) | (addr << 9);
+	if (bcnt == 1 && bsize <= 512)
+		arg |= (bsize & 0x1ff);
+	else
+		arg |= ((1 << 27) | bcnt);	
+	if ( rw ) {
+		cmd |= 0x400;
+		arg |= (1 << 31);
+	}
+	num = bsize*bcnt;
+
+	err = rt_sem_take(sdc->mutex, RT_WAITING_FOREVER);
+	if (err != RT_EOK) {
+		return ERRNORES;
+	}
+	
+	
+	// reset
+	synopmob_set_bits(base+CTRL, FIFO_RESET); //reset FIFO
+	while (synopmob_read_register(base+CTRL) & FIFO_RESET);
+    	synopmob_set_register(base + RINTSTS, 0xfffe); //clear interrupts
+
+	usrchain = chain;
+    	while (1) {    		
+    		if (length + usrchain->size >= sizeof(st_net_buf)) {
+    			while(1) SDIO_PRINTF("too long net pkt\n");
+    		}
+    		
+    		memcpy(st_net_buf + length, usrchain->buf, usrchain->size);
+    		length += usrchain->size;
+    		usrchain = usrchain->next;
+    		if (!usrchain || usrchain->next == chain) {
+    			break;
+    		}
+    	}
+    	
+    	st_pchain.desc0 = DescOwnByDma | DescSecAddrChained | DescLastDesc | DescFirstDesc;
+    	st_pchain.desc1 = length;
+    	st_pchain.desc2 = (unsigned int)st_net_buf;
+ 	st_pchain.desc3 = (unsigned int)&st_pchain;
+	flush_dcache_range((unsigned long)st_net_buf, length);	
+	
+	if (length != num) {
+		while (1) SDIO_PRINTF("sdio_drv_chain_write:too long packet!\n");
+	}
+
+	synopmob_set_register(base+DBADDR, (unsigned int)(&st_pchain));
+    
+	synopmob_set_register(base+BLKSIZ, bsize);
+	synopmob_set_register(base+BYTCNT, num);
+	synopmob_set_bits(base + CTRL, CTRL_USE_IDMAC);
+	synopmob_set_bits(base + BMOD,BMOD_DE);
+	
+	ret = synopmob_execute_command(base, cmd,  arg);
+	if ( !ret ) {
+		ret = ERRIDMA;
+		err = rt_sem_take(sdc->sem, DMA_TRANSFER_TIMEOUT_TICKS);
+		if ( !err ) {
+			while (--loop_for_command_done_check > 0) {
+				intsts = synopmob_read_register(base+RINTSTS);
+				if ((intsts & (INTMSK_CMD_DONE|INTMSK_DAT_OVER)) == (INTMSK_CMD_DONE|INTMSK_DAT_OVER)) {
+					break;
+				}
+				plat_loop(1);
+			}
+			ret = synopmob_handle_standard_rinsts(intsts);
+			if (!ret ) {
+				if( !loop_for_command_done_check || !(sdc->idsts & 0x100)) { //normal interrupt
+					ret = ERRIDMA;
+				}
+			}
+		}
+	}
+
+	if (!ret) {
+		synopmob_set_register(base + RINTSTS, 0xfffe); //clear interrupts
+		synopmob_clear_bits(base + CTRL, CTRL_USE_IDMAC);
+		synopmob_clear_bits(base + BMOD,BMOD_DE);
+		synopmob_set_register(base+BLKSIZ, 512);
+		synopmob_set_register(base+BYTCNT, 512);
+	}
+	else {
+	   	char* op = "read";
+	   	if (rw) 
+	   		op = "write";
+	   		
+	        SDIO_PRINTF("sdio_drv_chain_write1(%s) fail:, ret = %d\n", op, ret);
+	}
+
+	if ( rw && !ret ) {
+		ret = synopmob_wait_data_ready(base);
+	}
+
+	rt_sem_release(sdc->mutex);
+
+	return ret;
+	//return ret ? 0/*false*/ : 1/*true*/;
+}
+#endif
+#endif
+
+static int sdio_card_reset(sdc_t* sdc)
+{
+	unsigned int resp;
+	int ret;
+
+	/* Soft Reset card */
+    sdio_drv_creg_write(sdc, 0x6, 0, 0x8, &resp);
+
+	return 0;
+}
+
+static int enum_sdio_card(sdc_t* sdc)
+{
+	int ret;
+	unsigned int resp;
+	unsigned int base = sdc->ip_base;
+
+	#if 0
+	synopmob_set_bits(0x98500004, (1<<24)); //set to output mode
+	synopmob_set_bits(0x98500000, (1<<24)); //power off
+	plat_loop(1000000/5); //Lets give some ramp down period
+	synopmob_clear_bits(0x98500000, (1<<24)); //power on
+	plat_loop(1000000/5);//Lets give some ramp down period
+	#endif
+
+	synopmob_set_register(base+CTYPE, ONE_BIT_MODE);
+
+	synopmob_set_register(base+CLKENA, 0x00000001); /*enable clock, non-low-power mode*/
+	ret = synopmob_set_clk_freq(sdc, MMC_FOD_DIVIDER_VALUE);
+	
+	if ( !ret ) {
+		plat_loop(100); //enough for 74 clock.	
+		#if 0
+		sdio_card_reset(sdc);
+		plat_loop(100000);
+		#endif
+		ret = sd_send_cmd5(sdc, 0, &resp);
+		if (!ret) {
+			resp &= 0x00ffffff;
+			ret = sd_send_cmd5(sdc, resp, &resp);
+		}
+	}
+
+	if (!ret) {
+		ret = sd_send_cmd3(sdc); //get RCA
+	}
+	
+	if (!ret) {
+		ret = sd_send_cmd7(sdc); //select the card
+	}
+
+
+	if (!g_use_bcm43362)
+	{
+	sdio_drv_creg_read(sdc, 0x13, 0, &resp);
+	if ((resp & 1) && (sdc->wkmod & (SDC_WKMOD_4WIRE|SDC_WKMOD_25M_STAND_SPEED|SDC_WKMOD_50M_HI_SPEED))){ //high speed support?
+		if (sdc->wkmod & SDC_WKMOD_4WIRE) {
+			sdio_drv_creg_read(sdc, 0x7, 0, &resp);
+			resp &= 0xfc;
+			resp |= (1 << 1);
+			sdio_drv_creg_write(sdc, 0x7, 0, resp, &resp); //switch to 4bit mode
+			sdio_drv_creg_read(sdc, 0x7, 0, &resp);
+			if ((resp & 0x3) != 0x2) {
+				return  ERRCARDINTERNAL; // 4bit mode failed
+			}
+			synopmob_set_register(base+CTYPE, FOUR_BIT_MODE);
+		}
+		if (sdc->wkmod & (SDC_WKMOD_25M_STAND_SPEED|SDC_WKMOD_50M_HI_SPEED)) {
+			ret = synopmob_set_clk_freq(sdc, ONE_BIT_BUS_FREQ);
+			//ret = synopmob_set_clk_freq(sdc, 0);
+		}
+	}
+
+	sdio_drv_creg_read(sdc, 0x3, 0, &resp); 
+	if (!ret) {
+		sdio_drv_creg_read(sdc, 0x0, 0, &resp); //card version
+		sdio_drv_creg_write(sdc, 0x4, 0, 0x3, &resp); //enable interrupts in card
+		sdio_drv_creg_write(sdc, 0x2, 0, 0x2, &resp); //Eable IO in card
+		do {
+			sdio_drv_creg_read(sdc, 0x3, 0, &resp); 
+		} while (!(resp & 2));
+	}
+	} //g_use_bcm43362
+
+	sdc->card_type = SDIO_TYPE;
+
+	synopmob_set_bits(base+CTRL, INT_ENABLE);
+	
+	return ret;
+}
+
+int sdio_high_speed_mode(HSDC handle, int bitwidth, int freq)
+{
+	int ret;
+	sdc_t* sdc = (sdc_t*)handle;
+
+	if (bitwidth == 4)
+	{
+		synopmob_set_register(sdc->ip_base+CTYPE, FOUR_BIT_MODE);
+	}
+
+	ret = synopmob_set_clk_freq(sdc, /*ONE_BIT_BUS_FREQ*/1);
+	if (ret != 0)
+	{
+		SDIO_PRINTF("sdio_high_speed_mode fail:, ret = %d\n", ret);
+	}
+
+	return ret;
+}
+
+static int common_init(unsigned int which, unsigned int sdio, unsigned int wkmod, unsigned int* dma_desc, HSDC* phandle)
+{
+	int    ret = ERRNORES;
+	sdc_t* sdc;
+	unsigned int  base;
+	unsigned int  temp;
+	unsigned int  fifo_thresh;
+	volatile DmaDesc *pDmaDesc;
+	rt_sem_t sem;
+	rt_sem_t mutex;
+	
+	base = SDC0_REG_BASE;
+	temp = PMU_SDC0_RST_BIT;
+	if (which > 0) {
+		base = SDC1_REG_BASE;
+		temp = PMU_SDC1_RST_BIT;
+	}
+	
+#if 0
+	//PMU_RST_MODULE(temp); plat_loop(1);
+	temp = synopmob_read_register(PMU_REG_CLK_DIV3);
+	temp &= (~(0x0f<<8));
+	temp |= (0xf<<8);
+	synopmob_set_register(PMU_REG_CLK_DIV3, temp);
+#endif
+	*phandle = (HSDC)0;
+	
+	sdc = &sdc_array[which];
+	sem = sdc->sem;
+	mutex = sdc->mutex;
+	memset((void *)sdc, 0, sizeof(*sdc));
+	sdc->wkmod = wkmod;
+	sdc->idma_support = 0;
+	sdc->ip_base = base;
+	sdc->rca = 0;
+	sdc->card_type = NONE_TYPE;
+	if (!sem) {
+		sem = rt_sem_create("fh_sdio_sem", 0, RT_IPC_FLAG_PRIO);//OSSemCreate (0);
+		if ( !sem ) {
+			return ret;
+		}
+	}
+	sdc->sem = sem;
+
+	if (!mutex) {
+		mutex = rt_sem_create("fh_sdio_mutex", 1, RT_IPC_FLAG_PRIO);//OSSemCreate (1);
+		if ( !mutex ) {
+			return ret;
+		}
+	}
+	sdc->mutex = mutex;
+	
+	synopmob_set_bits(base + CTRL, CTRL_RESET); //reset host controller
+	plat_loop(100);
+
+	synopmob_clear_bits(base + CTRL,CTRL_USE_IDMAC);
+	sdc->idma_support = 1; //fixed to support IDMA
+
+	pDmaDesc = (volatile DmaDesc *)dma_desc;
+	sdc->pDmaDesc = pDmaDesc;
+	if (sdc->idma_support) {
+		synopmob_set_bits(base + CTRL, DMA_RESET);
+		plat_loop(100);
+		synopmob_set_bits(base + CTRL, FIFO_RESET);
+		plat_loop(100);
+		synopmob_set_bits(base + BMOD, BMOD_SWR);
+		plat_loop(100);
+		
+		//synopmob_set_bits(base + BMOD,BMOD_DE);		
+		pDmaDesc->desc0 = DescSecAddrChained;
+		pDmaDesc->desc1 = 0;
+		pDmaDesc->desc2 = 0;
+		pDmaDesc->desc3 = (unsigned int)(pDmaDesc);
+		synopmob_set_register(base + DBADDR, (unsigned int)(pDmaDesc));
+	}
+
+	synopmob_set_register(base+CTYPE, ONE_BIT_MODE);
+
+	synopmob_set_register(base+RINTSTS, 0xffffffff);//clear interrupt.
+	synopmob_clear_bits(base+CTRL, INT_ENABLE);
+	synopmob_set_register(base+INTMSK, 0); // mask all INTR
+	synopmob_set_register(base+IDINTEN, IDMAINTBITS); //Enable DMA INTR
+
+
+	synopmob_set_register(base+TMOUT, 0xffffffff); /* Set Data and Response timeout to Maximum Value*/
+
+	/* Set the card Debounce to allow the CDETECT fluctuations to settle down*/	
+	synopmob_set_register(base+DEBNCE, 0x0FFFFF);
+
+	fifo_thresh = synopmob_read_register(base+FIFOTH);
+	//fifo_thresh = GET_FIFO_DEPTH(fifo_thresh) / 2;
+	fifo_thresh = (GET_FIFO_DEPTH(fifo_thresh) + 1) / 2;
+	sdc->fifo_depth = fifo_thresh * 2;	
+	sdc->fifo_threth = fifo_thresh;
+	/* Tx Watermark */
+	synopmob_clear_bits(base+FIFOTH, 0xfff);
+	synopmob_set_bits(base+FIFOTH, fifo_thresh);
+	/* Rx Watermark */
+	synopmob_clear_bits(base+FIFOTH, 0x0fff0000);
+	synopmob_set_bits(base+FIFOTH, (fifo_thresh-1) << 16);
+	//synopmob_set_bits(base+FIFOTH, 2<< 28);
+
+	if (!sdio) {
+		ret = enum_sd_card(sdc);
+	}
+	else {
+		ret = enum_sdio_card(sdc);
+	}
+
+	if (!ret) {
+		*phandle = (HSDC)sdc;
+	}
+
+	return ret;
+}
+
+int sdc_is_connected(unsigned int which)
+{
+	unsigned int base = SDC0_REG_BASE;
+	
+	if (which > 0)
+		base = SDC1_REG_BASE;
+
+	return !(synopmob_read_register(base+CDETECT) & 1);
+}
+
+int sdc_init(unsigned int which, unsigned int wkmod, unsigned int* dma_desc, HSDC* phandle)
+{
+	return common_init(which, 0, wkmod, dma_desc, phandle);
+}
+
+int sdio_init(unsigned int which, unsigned int wkmod, unsigned int* dma_desc, HSDC* phandle)
+{
+	return common_init(which, 1, wkmod, dma_desc, phandle);
+}
+
+int sdio_enable_card_int(HSDC handle, int enable)
+{
+	unsigned int base = ((sdc_t*)handle)->ip_base;
+
+	if (enable) {
+		//synopmob_set_register(base+INTMSK, INTMSK_SDIO);
+		synopmob_set_register(base+INTMSK, (synopmob_read_register(base+INTMSK) | INTMSK_SDIO ));
+	}
+	else {
+		//synopmob_set_register(base+INTMSK, 0);
+		synopmob_set_register(base+INTMSK, (synopmob_read_register(base+INTMSK) & ~INTMSK_SDIO ));
+	}
+
+	return 0;
+}
+
+int sdio_set_card_int_cb(HSDC handle, void (*cb)(void))
+{
+	((sdc_t*)handle)->cb = cb;
+
+	return 0;
+}
+
+static void OSSDCISR(sdc_t* sdc)
+{
+	unsigned int sts;
+	unsigned int base;
+
+	base = sdc->ip_base;
+	sts = synopmob_read_register(base+IDSTS);
+	if ( sts ) {
+		synopmob_set_register(base+IDSTS, sts);
+		sdc->idsts = sts;
+		rt_sem_release(sdc->sem);
+	}
+
+	//sts = synopmob_read_register(base+RINTSTS);
+	sts = synopmob_read_register(base+MINTSTS);
+	sts &= INTMSK_SDIO;
+	if ( sts ) { //interrupt from WIFI card.
+		//synopmob_set_register(base+INTMSK, 0); //mask all the interrupt	
+		synopmob_set_register(base+INTMSK, synopmob_read_register(base+INTMSK) & ~INTMSK_SDIO ); //mask sdio interrupt	
+		synopmob_set_register(base+RINTSTS, sts);
+		synopmob_set_register(base+MINTSTS, sts);
+		if (sdc->cb) {
+			sdc->cb();
+		}
+	}
+}
+
+void OSSDCINTR_0(int vector, void *param)
+{
+	OSSDCISR(&sdc_array[0]);
+}
+
+void OSSDCINTR_1(int vector, void *param)
+{
+	OSSDCISR(&sdc_array[1]);
+}
+
+void fh_sdio0_init(void)
+{
+    int sd0_irq = SDC0_IRQn;
+    
+    rt_hw_interrupt_install(sd0_irq, OSSDCINTR_0, NULL, NULL);
+    rt_hw_interrupt_umask(sd0_irq);
+}
+
+void fh_sdio1_init(void)
+{
+    int sd1_irq = SDC1_IRQn;
+    
+    rt_hw_interrupt_install(sd1_irq, OSSDCINTR_1, NULL, NULL);
+    rt_hw_interrupt_umask(sd1_irq);
+}
+
+void fh_sdio_init(void)
+{
+    fh_sdio0_init();
+    fh_sdio1_init();
+}
+
+int sdc_deinit(HSDC handle)
+{
+	return -1;  // TBD... fix me
+}
+
+int sdc_set_clk_divider(unsigned int divider)
+{
+    if(divider > 255)
+        return -1;
+    
+    sdc_clk_divider = divider;
+    return 0;
+}
+

+ 164 - 0
bsp/fh8620/libraries/driverlib/fh_spi.c

@@ -0,0 +1,164 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "fh_def.h"
+#include "fh_arch.h"
+#include "inc/fh_driverlib.h"
+
+void SPI_EnableSlaveen(struct fh_spi_obj *spi_obj, rt_uint32_t port)
+{
+    rt_uint32_t reg;
+
+    reg = GET_REG(spi_obj->base + OFFSET_SPI_SER);
+    reg |= (1 << port);
+    SET_REG(spi_obj->base + OFFSET_SPI_SER, reg);
+}
+
+void SPI_DisableSlaveen(struct fh_spi_obj *spi_obj, rt_uint32_t port)
+{
+    rt_uint32_t reg;
+
+    reg = GET_REG(spi_obj->base + OFFSET_SPI_SER);
+    reg &= ~(1 << port);
+    SET_REG(spi_obj->base + OFFSET_SPI_SER, reg);
+}
+
+void SPI_SetTxLevel(struct fh_spi_obj *spi_obj, rt_uint32_t level)
+{
+    SET_REG(spi_obj->base + OFFSET_SPI_TXFTLR, level);
+}
+
+void SPI_EnableInterrupt(struct fh_spi_obj *spi_obj, rt_uint32_t flag)
+{
+    rt_uint32_t reg;
+
+    reg = GET_REG(spi_obj->base + OFFSET_SPI_IMR);
+    reg |= flag;
+    SET_REG(spi_obj->base + OFFSET_SPI_IMR, reg);
+}
+
+
+void SPI_EnableDma(struct fh_spi_obj *spi_obj, rt_uint32_t channel)
+{
+    rt_uint32_t reg;
+
+    reg = GET_REG(spi_obj->base + OFFSET_SPI_DMACTRL);
+    reg |= channel;
+    SET_REG(spi_obj->base + OFFSET_SPI_DMACTRL, reg);
+}
+
+
+void SPI_DisableDma(struct fh_spi_obj *spi_obj, rt_uint32_t channel)
+{
+    rt_uint32_t reg;
+
+    reg = GET_REG(spi_obj->base + OFFSET_SPI_DMACTRL);
+    reg &= ~channel;
+    SET_REG(spi_obj->base + OFFSET_SPI_DMACTRL, reg);
+
+}
+
+
+void SPI_DisableInterrupt(struct fh_spi_obj *spi_obj, rt_uint32_t flag)
+{
+    rt_uint32_t reg;
+
+    reg = GET_REG(spi_obj->base + OFFSET_SPI_IMR);
+    reg &= ~flag;
+    SET_REG(spi_obj->base + OFFSET_SPI_IMR, reg);
+
+}
+
+rt_uint32_t SPI_InterruptStatus(struct fh_spi_obj *spi_obj)
+{
+    return GET_REG(spi_obj->base + OFFSET_SPI_ISR);
+}
+
+void SPI_ClearInterrupt(struct fh_spi_obj *spi_obj)
+{
+    GET_REG(spi_obj->base + OFFSET_SPI_ICR);
+}
+
+rt_uint32_t SPI_ReadTxFifoLevel(struct fh_spi_obj *spi_obj)
+{
+    return GET_REG(spi_obj->base + OFFSET_SPI_TXFLR);
+}
+
+rt_uint32_t SPI_ReadRxFifoLevel(struct fh_spi_obj *spi_obj)
+{
+    return GET_REG(spi_obj->base + OFFSET_SPI_RXFLR);
+}
+
+UINT8 SPI_ReadData(struct fh_spi_obj *spi_obj)
+{
+    return GET_REG(spi_obj->base + OFFSET_SPI_DR) & 0xff;
+}
+
+void SPI_WriteData(struct fh_spi_obj *spi_obj, UINT8 data)
+{
+    SET_REG(spi_obj->base + OFFSET_SPI_DR, data);
+}
+
+rt_uint32_t SPI_ReadStatus(struct fh_spi_obj *spi_obj)
+{
+    return GET_REG(spi_obj->base + OFFSET_SPI_SR);
+}
+
+void SPI_Enable(struct fh_spi_obj *spi_obj, int enable)
+{
+    SET_REG(spi_obj->base + OFFSET_SPI_SSIENR, enable);
+}
+
+void SPI_WriteTxDmaLevel(struct fh_spi_obj *spi_obj, rt_uint32_t data)
+{
+    SET_REG(spi_obj->base + OFFSET_SPI_DMATDL, data);
+}
+
+void SPI_WriteRxDmaLevel(struct fh_spi_obj *spi_obj, rt_uint32_t data)
+{
+    SET_REG(spi_obj->base + OFFSET_SPI_DMARDL, data);
+}
+
+void SPI_SetParameter(struct fh_spi_obj *spi_obj)
+{
+    rt_uint32_t reg;
+    struct spi_config *config;
+
+    config = &spi_obj->config;
+
+    SET_REG(spi_obj->base + OFFSET_SPI_BAUD, config->clk_div);
+
+    reg = GET_REG(spi_obj->base + OFFSET_SPI_CTRL0);
+
+    reg &= ~(0x3ff);
+    reg |= config->data_size        \
+         | config->frame_format     \
+         | config->clk_phase        \
+         | config->clk_polarity     \
+         | config->transfer_mode;
+
+    SET_REG(spi_obj->base + OFFSET_SPI_CTRL0, reg);
+}

+ 144 - 0
bsp/fh8620/libraries/driverlib/fh_timer.c

@@ -0,0 +1,144 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+/*****************************************************************************
+ *  Include Section
+ *  add all #include here
+ *****************************************************************************/
+#include "inc/fh_driverlib.h"
+/*****************************************************************************
+ * Define section
+ * add all #define here
+ *****************************************************************************/
+
+/****************************************************************************
+ * ADT section
+ *  add definition of user defined Data Type that only be used in this file  here
+ ***************************************************************************/
+
+
+
+/******************************************************************************
+ * Function prototype section
+ * add prototypes for all functions called by this file,execepting those
+ * declared in header file
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Global variables section - Exported
+ * add declaration of global variables that will be exported here
+ * e.g.
+ *  int8_t foo;
+ ****************************************************************************/
+
+
+/*****************************************************************************
+ * Global variables section - Local
+ * define global variables(will be refered only in this file) here,
+ * static keyword should be used to limit scope of local variable to this file
+ * e.g.
+ *  static uint8_t ufoo;
+ *****************************************************************************/
+
+
+
+
+ /* function body */
+
+
+/*****************************************************************************
+ * Description:
+ *      add funtion description here
+ * Parameters:
+ *      description for each argument, new argument starts at new line
+ * Return:
+ *      what does this function returned?
+ *****************************************************************************/
+int timer_init(timer *tim)
+{
+	tim->TIMER_CTRL_REG = 0;
+}
+
+int timer_set_mode(timer *tim, enum timer_mode mode)
+{
+	switch (mode)
+	{
+		case TIMER_MODE_PERIODIC:
+			tim->TIMER_CTRL_REG |= TIMER_CTRL_MODE;
+			break;
+		case TIMER_MODE_ONESHOT:
+			tim->TIMER_CTRL_REG |= TIMER_CTRL_MODE;
+			break;
+		default:
+			rt_kprintf("Not support TIMER mode\n");
+			return -1;
+			break;
+	}
+
+	return 0;
+}
+
+void timer_set_period(timer *tim, UINT32 period, UINT32 clock)
+{
+	tim->TIMER_LOAD_COUNT = clock/period;
+}
+
+
+
+void timer_enable(timer *tim)
+{
+	tim->TIMER_CTRL_REG |= TIMER_CTRL_ENABLE;
+}
+
+void timer_disable(timer *tim)
+{
+	tim->TIMER_CTRL_REG &= ~TIMER_CTRL_ENABLE;
+}
+
+void timer_enable_irq(timer *tim)
+{
+	tim->TIMER_CTRL_REG &= ~TIMER_CTRL_INTMASK;
+}
+
+void timer_disable_irq(timer *tim)
+{
+	tim->TIMER_CTRL_REG |= TIMER_CTRL_INTMASK;
+}
+
+UINT32 timer_get_status(timer *tim)
+{
+	return tim->TIMER_INT_STATUS;
+}
+
+UINT32 timer_get_eoi(timer *tim)
+{
+	return tim->TIMER_EOI;
+}
+
+UINT32 timer_get_value(timer *tim)
+{
+	return tim->TIMER_LOAD_COUNT - tim->TIMER_CURRENT_VALUE;
+}

+ 278 - 0
bsp/fh8620/libraries/driverlib/fh_uart.c

@@ -0,0 +1,278 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+/*****************************************************************************
+ *  Include Section
+ *  add all #include here
+ *****************************************************************************/
+#include "inc/fh_driverlib.h"
+/*****************************************************************************
+ * Define section
+ * add all #define here
+ *****************************************************************************/
+
+/****************************************************************************
+ * ADT section
+ *  add definition of user defined Data Type that only be used in this file  here
+ ***************************************************************************/
+
+/******************************************************************************
+ * Function prototype section
+ * add prototypes for all functions called by this file,execepting those
+ * declared in header file
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Global variables section - Exported
+ * add declaration of global variables that will be exported here
+ * e.g.
+ *  int8_t foo;
+ ****************************************************************************/
+
+
+/*****************************************************************************
+ * Global variables section - Local
+ * define global variables(will be refered only in this file) here,
+ * static keyword should be used to limit scope of local variable to this file
+ * e.g.
+ *  static uint8_t ufoo;
+ *****************************************************************************/
+
+
+
+
+ /* function body */
+
+
+/*****************************************************************************
+ * Description:
+ *      add funtion description here
+ * Parameters:
+ *      description for each argument, new argument starts at new line
+ * Return:
+ *      what does this function returned?
+ *****************************************************************************/
+
+
+int uart_init(uart *port)
+{
+	port->UART_IER = 0;
+	port->UART_LCR = 0;
+	//port->UART_DLL = 0;
+	//port->UART_DLH = 0;
+}
+
+UINT32 uart_get_status(uart *port)
+{
+	return port->UART_USR;
+}
+
+
+void uart_configure(uart *port, enum data_bits data_bit,
+					enum stop_bits stop_bit, enum parity parity,
+					UINT32 buard_rate, UINT32 uart_clk)
+{
+	UINT32 divisor;
+	UINT32 freq;
+	UINT32 baud_div;
+	UINT32 lcr_reg = 0;
+	UINT32 ret;
+
+	/*divisor = DIV(buard_rate);
+	port->UART_LCR |= UART_LCR_DLAB;
+	port->UART_DLL = divisor & 0xFF;
+	port->UART_DLH = (divisor >> 8) & 0xFF;
+	port->UART_LCR &= ~UART_LCR_DLAB;*/
+
+    do{
+        //clear fifo...
+        port->UART_FCR = UART_FCR_RFIFOR | UART_FCR_XFIFOR;
+        //read status..
+        ret = uart_get_status(port);
+    }while(ret & UART_USR_BUSY);
+	switch (data_bit) {
+		case UART_DATA_BIT5:
+			lcr_reg |= UART_LCR_DLS5;
+			break;
+		case UART_DATA_BIT6:
+			lcr_reg |= UART_LCR_DLS6;
+			break;
+		case UART_DATA_BIT7:
+			lcr_reg |= UART_LCR_DLS7;
+			break;
+		case UART_DATA_BIT8:
+			lcr_reg |= UART_LCR_DLS8;
+			break;
+		default:
+			lcr_reg |= UART_LCR_DLS8;
+			break;
+	}
+
+	switch (stop_bit) {
+		case UART_STOP_BIT1:
+			lcr_reg |= UART_LCR_STOP1;
+			break;
+		case UART_STOP_BIT2:
+			lcr_reg |= UART_LCR_STOP2;
+			break;
+		default:
+			lcr_reg |= UART_LCR_STOP1;
+			break;
+	}
+
+	switch (parity) {
+		case UART_PARITY_EVEN:
+			lcr_reg |= UART_LCR_EVEN | UART_LCR_PEN;
+			break;
+		case UART_PARITY_ODD:
+			lcr_reg |= UART_LCR_PEN;
+			break;
+		case UART_PARITY_ST:
+			lcr_reg |= UART_LCR_SP;
+			break;
+		case UART_PARITY_NONE:
+		default:
+			break;
+	}
+
+
+
+	switch (buard_rate) {
+		case 115200:
+			baud_div =  BAUDRATE_115200;
+			break;
+		case 57600:
+			baud_div =  BAUDRATE_57600;
+			break;
+		case 38400:
+			baud_div =  BAUDRATE_38400;
+			break;
+		case 19200:
+			baud_div =  BAUDRATE_19200;
+			break;
+		case 9600:
+			baud_div =  BAUDRATE_9600;
+			break;
+		default:
+			baud_div = BAUDRATE_115200;
+			break;
+	}
+
+	//clear fifo
+	port->UART_FCR = UART_FCR_RFIFOR | UART_FCR_XFIFOR;
+
+	//div
+	ret = port->UART_LCR;
+	ret |= UART_LCR_DLAB;
+	port->UART_LCR = ret;
+	port->RBRTHRDLL = baud_div & 0x00ff;
+	port->DLHIER = (baud_div & 0x00ff)>>8;
+	/* clear DLAB */
+	ret = ret & 0x7f;
+	port->UART_LCR = ret;
+
+	//line control
+	port->UART_LCR = lcr_reg;
+	//fifo control
+	port->UART_FCR = UART_FCR_FIFOE | UART_FCR_RFIFOR | UART_FCR_XFIFOR | UART_FCR_TET_1_4 | UART_FCR_RT_ONE;
+
+}
+
+
+int uart_enable_irq(uart *port, UINT32 mode)
+{
+	unsigned int ret;
+	ret = port->UART_IER;
+	ret |= mode;
+	port->UART_IER = ret;
+}
+
+int uart_disable_irq(uart *port, UINT32 mode)
+{
+	unsigned int ret;
+	ret = port->UART_IER;
+	ret &= ~mode;
+
+	port->UART_IER = ret;
+}
+
+UINT32 uart_get_iir_status(uart *port)
+{
+	return port->UART_IIR;
+}
+
+UINT32 uart_get_line_status(uart *port)
+{
+	return port->UART_LSR;
+}
+
+UINT32 uart_is_rx_ready(uart *port)
+{
+	return port->UART_LSR & UART_LSR_DR;
+}
+
+UINT8 uart_getc(uart *port)
+{
+	return port->UART_RBR & 0xFF;
+}
+
+void uart_putc(uart *port, UINT8 c)
+{
+	//while(!(port->UART_USR & UART_USR_TFNF));
+	port->UART_THR = c;
+}
+
+void uart_set_fifo_mode(uart *port, UINT32 fifo_mode)
+{
+	port->UART_FCR = fifo_mode;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 58 - 0
bsp/fh8620/libraries/driverlib/fh_wdt.c

@@ -0,0 +1,58 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "inc/fh_driverlib.h"
+
+void WDT_Enable(struct fh_wdt_obj *wdt_obj, int enable)
+{
+    SET_REG(wdt_obj->base + WDOG_CONTROL_REG_OFFSET, enable);
+}
+
+inline int WDT_IsEnable(struct fh_wdt_obj *wdt_obj)
+{
+    return GET_REG(wdt_obj->base + WDOG_CONTROL_REG_OFFSET) &
+        WDOG_CONTROL_REG_WDT_EN_MASK;
+}
+
+void WDT_SetTopValue(struct fh_wdt_obj *wdt_obj, int top)
+{
+    SET_REG(wdt_obj->base + WDOG_TIMEOUT_RANGE_REG_OFFSET, top);
+}
+
+void WDT_SetCtrl(struct fh_wdt_obj *wdt_obj, UINT32 reg)
+{
+    SET_REG(wdt_obj->base + WDOG_CONTROL_REG_OFFSET, reg);
+}
+
+void WDT_Kick(struct fh_wdt_obj *wdt_obj)
+{
+    SET_REG(wdt_obj->base + WDOG_COUNTER_RESTART_REG_OFFSET, WDOG_COUNTER_RESTART_KICK_VALUE);
+}
+
+UINT32 WDT_GetCurrCount(struct fh_wdt_obj *wdt_obj)
+{
+    return GET_REG(wdt_obj->base + WDOG_CURRENT_COUNT_REG_OFFSET);
+}

+ 39 - 0
bsp/fh8620/libraries/inc/fh_driverlib.h

@@ -0,0 +1,39 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#include <rtthread.h>
+#include <rthw.h>
+#include "fh_def.h"
+#include "fh_arch.h"
+#include "fh_ictl.h"
+#include "fh_timer.h"
+#include "fh_uart.h"
+#include "fh_spi.h"
+#include "fh_gpio.h"
+#include "fh_mmc.h"
+#include "fh_i2c.h"
+#include "fh_pwm.h"
+#include "fh_wdt.h"

+ 54 - 0
bsp/fh8620/libraries/inc/fh_gpio.h

@@ -0,0 +1,54 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef FH_GPIO_H_
+#define FH_GPIO_H_
+
+
+#define     REG_GPIO_SWPORTA_DR         (0x0000)
+#define     REG_GPIO_SWPORTA_DDR        (0x0004)
+#define     REG_GPIO_PORTA_CTL          (0x0008)
+#define     REG_GPIO_INTEN              (0x0030)
+#define     REG_GPIO_INTMASK            (0x0034)
+#define     REG_GPIO_INTTYPE_LEVEL      (0x0038)
+#define     REG_GPIO_INT_POLARITY       (0x003C)
+#define     REG_GPIO_INTSTATUS          (0x0040)
+#define     REG_GPIO_RAWINTSTATUS       (0x0044)
+#define     REG_GPIO_DEBOUNCE           (0x0048)
+#define     REG_GPIO_PORTA_EOI          (0x004C)
+#define     REG_GPIO_EXT_PORTA          (0x0050)
+
+#define NUM_OF_GPIO         (64)
+
+struct fh_gpio_obj
+{
+    unsigned int              id;
+    unsigned int              irq;
+};
+
+
+
+#endif /* FH_GPIO_H_ */

+ 226 - 0
bsp/fh8620/libraries/inc/fh_i2c.h

@@ -0,0 +1,226 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef FH_I2C_H_
+#define FH_I2C_H_
+
+#include "fh_def.h"
+
+#define     OFFSET_I2C_CON             (0x0000)
+#define     OFFSET_I2C_TAR             (0x0004)
+#define     OFFSET_I2C_SAR             (0x0008)
+#define     OFFSET_I2C_HS_MADDR        (0x000C)
+#define     OFFSET_I2C_DATA_CMD        (0x0010)
+#define     OFFSET_I2C_SS_SCL_HCNT     (0x0014)
+#define     OFFSET_I2C_SS_SCL_LCNT     (0x0018)
+#define     OFFSET_I2C_FS_SCL_HCNT     (0x001C)
+#define     OFFSET_I2C_FS_SCL_LCNT     (0x0020)
+#define     OFFSET_I2C_HS_SCL_HCNT     (0x0024)
+#define     OFFSET_I2C_HS_SCL_LCNT     (0x0028)
+#define     OFFSET_I2C_INTR_STAT       (0x002c)
+#define     OFFSET_I2C_INTR_MASK       (0x0030)
+#define     OFFSET_I2C_RAW_INTR_STAT   (0x0034)
+#define     OFFSET_I2C_RX_TL           (0x0038)
+#define     OFFSET_I2C_TX_TL           (0x003c)
+#define     OFFSET_I2C_CLR_INTR        (0x0040)
+#define     OFFSET_I2C_CLR_RX_UNDER    (0x0044)
+#define     OFFSET_I2C_CLR_RX_OVER     (0x0048)
+#define     OFFSET_I2C_CLR_TX_OVER     (0x004c)
+#define     OFFSET_I2C_CLR_RD_REQ      (0x0050)
+#define     OFFSET_I2C_CLR_TX_ABRT     (0x0054)
+#define     OFFSET_I2C_CLR_RX_DONE     (0x0058)
+#define     OFFSET_I2C_CLR_ACTIVITY    (0x005c)
+#define     OFFSET_I2C_CLR_STOP_DET    (0x0060)
+#define     OFFSET_I2C_CLR_START_DET   (0x0064)
+#define     OFFSET_I2C_CLR_GEN_CALL    (0x0068)
+#define     OFFSET_I2C_ENABLE          (0x006c)
+#define     OFFSET_I2C_STATUS          (0x0070)
+#define     OFFSET_I2C_TXFLR           (0x0074)
+#define     OFFSET_I2C_RXFLR           (0x0078)
+#define     OFFSET_I2C_DMA_CR          (0x0088)
+#define     OFFSET_I2C_DMA_TDLR        (0x008c)
+#define     OFFSET_I2C_DMA_RDLR        (0x0090)
+#define     OFFSET_I2C_COMP_PARAM1     (0x00f4)
+#define     OFFSET_I2C_TX_ABRT_SOURCE  (0x0080)
+
+#define I2C_M_TEN       0x0100  /* this is a ten bit chip address */
+#define I2C_M_RD        0x0001  /* read data, from slave to master */
+#define I2C_M_NOSTART       0x4000  /* if I2C_FUNC_PROTOCOL_MANGLING */
+#define I2C_M_REV_DIR_ADDR  0x2000  /* if I2C_FUNC_PROTOCOL_MANGLING */
+#define I2C_M_IGNORE_NAK    0x1000  /* if I2C_FUNC_PROTOCOL_MANGLING */
+#define I2C_M_NO_RD_ACK     0x0800  /* if I2C_FUNC_PROTOCOL_MANGLING */
+#define I2C_M_RECV_LEN      0x0400  /* length will be first received byte */
+
+#define DW_IC_CON_MASTER        0x1
+#define DW_IC_CON_SPEED_STD     0x2
+#define DW_IC_CON_SPEED_FAST        0x4
+#define DW_IC_CON_10BITADDR_MASTER  0x10
+#define DW_IC_CON_RESTART_EN        0x20
+#define DW_IC_CON_SLAVE_DISABLE     0x40
+
+#define DW_IC_INTR_RX_UNDER 0x001
+#define DW_IC_INTR_RX_OVER  0x002
+#define DW_IC_INTR_RX_FULL  0x004
+#define DW_IC_INTR_TX_OVER  0x008
+#define DW_IC_INTR_TX_EMPTY 0x010
+#define DW_IC_INTR_RD_REQ   0x020
+#define DW_IC_INTR_TX_ABRT  0x040
+#define DW_IC_INTR_RX_DONE  0x080
+#define DW_IC_INTR_ACTIVITY 0x100
+#define DW_IC_INTR_STOP_DET 0x200
+#define DW_IC_INTR_START_DET    0x400
+#define DW_IC_INTR_GEN_CALL 0x800
+
+#define DW_IC_INTR_DEFAULT_MASK     (DW_IC_INTR_RX_FULL | \
+                     DW_IC_INTR_TX_EMPTY | \
+                     DW_IC_INTR_TX_ABRT | \
+                     DW_IC_INTR_STOP_DET)
+
+#define DW_IC_STATUS_ACTIVITY   0x1
+#define DW_IC_STATUS_MASTER_ACTIVITY   0x20
+
+#define DW_IC_ERR_TX_ABRT   0x1
+
+/*
+ * status codes
+ */
+#define STATUS_IDLE         0x0
+#define STATUS_WRITE_IN_PROGRESS    0x1
+#define STATUS_READ_IN_PROGRESS     0x2
+
+#define TIMEOUT         20 /* ms */
+
+/*
+ * hardware abort codes from the DW_IC_TX_ABRT_SOURCE register
+ *
+ * only expected abort codes are listed here
+ * refer to the datasheet for the full list
+ */
+#define ABRT_7B_ADDR_NOACK  0
+#define ABRT_10ADDR1_NOACK  1
+#define ABRT_10ADDR2_NOACK  2
+#define ABRT_TXDATA_NOACK   3
+#define ABRT_GCALL_NOACK    4
+#define ABRT_GCALL_READ     5
+#define ABRT_SBYTE_ACKDET   7
+#define ABRT_SBYTE_NORSTRT  9
+#define ABRT_10B_RD_NORSTRT 10
+#define ABRT_MASTER_DIS     11
+#define ARB_LOST        12
+
+#define DW_IC_TX_ABRT_7B_ADDR_NOACK (1UL << ABRT_7B_ADDR_NOACK)
+#define DW_IC_TX_ABRT_10ADDR1_NOACK (1UL << ABRT_10ADDR1_NOACK)
+#define DW_IC_TX_ABRT_10ADDR2_NOACK (1UL << ABRT_10ADDR2_NOACK)
+#define DW_IC_TX_ABRT_TXDATA_NOACK  (1UL << ABRT_TXDATA_NOACK)
+#define DW_IC_TX_ABRT_GCALL_NOACK   (1UL << ABRT_GCALL_NOACK)
+#define DW_IC_TX_ABRT_GCALL_READ    (1UL << ABRT_GCALL_READ)
+#define DW_IC_TX_ABRT_SBYTE_ACKDET  (1UL << ABRT_SBYTE_ACKDET)
+#define DW_IC_TX_ABRT_SBYTE_NORSTRT (1UL << ABRT_SBYTE_NORSTRT)
+#define DW_IC_TX_ABRT_10B_RD_NORSTRT    (1UL << ABRT_10B_RD_NORSTRT)
+#define DW_IC_TX_ABRT_MASTER_DIS    (1UL << ABRT_MASTER_DIS)
+#define DW_IC_TX_ARB_LOST       (1UL << ARB_LOST)
+
+#define DW_IC_TX_ABRT_NOACK     (DW_IC_TX_ABRT_7B_ADDR_NOACK | \
+                     DW_IC_TX_ABRT_10ADDR1_NOACK | \
+                     DW_IC_TX_ABRT_10ADDR2_NOACK | \
+                     DW_IC_TX_ABRT_TXDATA_NOACK | \
+                     DW_IC_TX_ABRT_GCALL_NOACK)
+
+static char *abort_sources[] = {
+    [ABRT_7B_ADDR_NOACK] =
+    "slave address not acknowledged (7bit mode)",
+    [ABRT_10ADDR1_NOACK] =
+    "first address byte not acknowledged (10bit mode)",
+    [ABRT_10ADDR2_NOACK] =
+    "second address byte not acknowledged (10bit mode)",
+    [ABRT_TXDATA_NOACK] =
+    "data not acknowledged",
+    [ABRT_GCALL_NOACK] =
+    "no acknowledgement for a general call",
+    [ABRT_GCALL_READ] =
+    "read after general call",
+    [ABRT_SBYTE_ACKDET] =
+    "start byte acknowledged",
+    [ABRT_SBYTE_NORSTRT] =
+    "trying to send start byte when restart is disabled",
+    [ABRT_10B_RD_NORSTRT] =
+    "trying to read when restart is disabled (10bit mode)",
+    [ABRT_MASTER_DIS] =
+    "trying to use disabled adapter",
+    [ARB_LOST] =
+    "lost arbitration",
+};
+/* i2c interrput definition */
+#define M_GEN_CALL      (1<<11)
+#define M_START_DET     (1<<10)
+#define M_STOP_DET      (1<<9)
+#define M_ACTIVITY      (1<<8)
+#define M_RX_DONE       (1<<7)
+#define M_TX_ABRT       (1<<6)
+#define M_RD_REQ        (1<<5)
+#define M_TX_EMPTY      (1<<4)
+#define M_TX_OVER       (1<<3)
+#define M_RX_FULL       (1<<2)
+#define M_RX_OVER       (1<<1)
+#define M_RX_UNDER      (1<<0)
+#define M_NONE          (0)
+
+
+struct i2c_config
+{
+    int speed_mode;
+    UINT32 tx_fifo_depth;
+    UINT32 rx_fifo_depth;
+};
+
+struct fh_i2c_obj
+{
+    UINT32        id;
+    UINT32        irq;
+    UINT32        base;
+    UINT32        input_clock;
+    UINT32        abort_source;
+    struct i2c_config config;
+
+
+};
+
+void I2C_Init(struct fh_i2c_obj *i2c_obj);
+inline void I2C_Enable(struct fh_i2c_obj *i2c_obj, int enable);
+inline void I2C_SetSlaveAddress(struct fh_i2c_obj *i2c_obj, rt_uint16_t addr);
+inline UINT32 I2C_GetTransmitFifoLevel(struct fh_i2c_obj *i2c_obj);
+inline UINT32 I2C_GetReceiveFifoLevel(struct fh_i2c_obj *i2c_obj);
+inline UINT32 I2C_SetTransmitThreshold(struct fh_i2c_obj *i2c_obj, int txtl);
+int I2C_HandleTxAbort(struct fh_i2c_obj *i2c_obj);
+UINT32 I2C_ClearAndGetInterrupts(struct fh_i2c_obj *i2c_obj);
+inline void I2C_SetInterruptMask(struct fh_i2c_obj *i2c_obj, UINT32 mask);
+inline UINT32 I2C_GetInterruptMask(struct fh_i2c_obj *i2c_obj);
+inline void I2C_SetDataCmd(struct fh_i2c_obj *i2c_obj, UINT32 reg);
+inline UINT8 I2C_GetData(struct fh_i2c_obj *i2c_obj);
+int I2C_WaitMasterIdle(struct fh_i2c_obj *i2c_obj);
+int I2C_WaitDeviceIdle(struct fh_i2c_obj *i2c_obj);
+
+#endif /* FH_I2C_H_ */

+ 58 - 0
bsp/fh8620/libraries/inc/fh_ictl.h

@@ -0,0 +1,58 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#ifndef FH_ICTL_H_
+#define FH_ICTL_H_
+
+#include "fh_def.h"
+
+typedef struct {
+	RwReg IRQ_EN_L;
+	RwReg IRQ_EN_H;
+	RwReg IRQ_MASK_L;
+	RwReg IRQ_MASK_H;
+	RwReg IRQ_FORCE_L;
+	RwReg IRQ_FORCE_H;
+	RwReg IRQ_RAWSTARUS_L;
+	RwReg IRQ_RAWSTARUS_H;
+	RwReg IRQ_STATUS_L;
+	RwReg IRQ_STATUS_H;
+	RwReg IRQ_MASKSTATUS_L;
+	RwReg IRQ_MASKSTATUS_H;
+	RwReg IRQ_FINALSTATUS_L;
+	RwReg IRQ_FINALSTATUS_H;
+	RwReg IRQ_VECTOR;
+}fh_intc;
+
+
+
+void ictl_close_all_isr(fh_intc *p);
+
+void ictl_mask_isr(fh_intc *p,int irq);
+
+void ictl_unmask_isr(fh_intc *p,int irq);
+
+#endif

+ 225 - 0
bsp/fh8620/libraries/inc/fh_mmc.h

@@ -0,0 +1,225 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#ifndef FH_MMC_H_
+#define FH_MMC_H_
+
+#include "fh_def.h"
+
+
+#define     OFFSET_SDC_CTRL                         (0x0000)
+#define     OFFSET_SDC_PWREN                        (0x0004)
+#define     OFFSET_SDC_CLKDIV                       (0x0008)
+#define     OFFSET_SDC_CLKSRC                       (0x000C)
+#define     OFFSET_SDC_CLKENA                       (0x0010)
+#define     OFFSET_SDC_TMOUT                        (0x0014)
+#define     OFFSET_SDC_CTYPE                        (0x0018)
+#define     OFFSET_SDC_BLKSIZ                       (0x001C)
+#define     OFFSET_SDC_BYTCNT                       (0x0020)
+#define     OFFSET_SDC_INTMASK                      (0x0024)
+#define     OFFSET_SDC_CMDARG                       (0x0028)
+#define     OFFSET_SDC_CMD                          (0x002C)
+#define     OFFSET_SDC_RESP0                        (0x0030)
+#define     OFFSET_SDC_RESP1                        (0x0034)
+#define     OFFSET_SDC_RESP2                        (0x0038)
+#define     OFFSET_SDC_RESP3                        (0x003C)
+#define     OFFSET_SDC_MINTSTS                      (0x0040)
+#define     OFFSET_SDC_RINTSTS                      (0x0044)
+#define     OFFSET_SDC_STATUS                       (0x0048)
+#define     OFFSET_SDC_FIFOTH                       (0x004C)
+#define     OFFSET_SDC_CDETECT                      (0x0050)
+#define     OFFSET_SDC_WRTPRT                       (0x0054)
+#define     OFFSET_SDC_GPIO                         (0x0058)
+#define     OFFSET_SDC_TCBCNT                       (0x005C)
+#define     OFFSET_SDC_TBBCNT                       (0x0060)
+#define     OFFSET_SDC_DEBNCE                       (0x0064)
+#define     OFFSET_SDC_USRID                        (0x0068)
+#define     OFFSET_SDC_VERID                        (0x006C)
+#define     OFFSET_SDC_HCON                         (0x0070)
+#define     OFFSET_SDC_UHS_REG                      (0x0074)
+#define     OFFSET_SDC_RST_N                        (0x0078)
+#define     OFFSET_SDC_BMOD                         (0x0080)
+#define     OFFSET_SDC_PLDMND                       (0x0084)
+#define     OFFSET_SDC_DBADDR                       (0x0088)
+#define     OFFSET_SDC_IDSTS                        (0x008C)
+#define     OFFSET_SDC_IDINTEN                      (0x0090)
+#define     OFFSET_SDC_DSCADDR                      (0x0094)
+#define     OFFSET_SDC_BUFADDR                      (0x0098)
+#define     OFFSET_SDC_CARDTHRCTL                   (0x0100)
+#define     OFFSET_SDC_BACK_END_POWER               (0x0104)
+#define     OFFSET_SDC_FIFO                         (0x0200)
+
+#define     MMC_FIFO_DEPTH                      (16)
+
+#define     MMC_CMD_FLAG_RESPONSE_EXPECTED      BIT(6)
+#define     MMC_CMD_FLAG_LONG_RESPONSE          BIT(7)
+#define     MMC_CMD_FLAG_CHECK_RESP_CRC         BIT(8)
+#define     MMC_CMD_FLAG_DATA_EXPECTED          BIT(9)
+#define     MMC_CMD_FLAG_WRITE_TO_CARD          BIT(10)
+#define     MMC_CMD_FLAG_DATA_STREAM            BIT(11)
+#define     MMC_CMD_FLAG_AUTO_STOP              BIT(12)
+#define     MMC_CMD_FLAG_WAIT_PREV_DATA         BIT(13)
+#define     MMC_CMD_FLAG_STOP_TRANSFER          BIT(14)
+#define     MMC_CMD_FLAG_SEND_INIT              BIT(15)
+#define     MMC_CMD_FLAG_SWITCH_VOLTAGE         BIT(28)
+
+#define     MMC_STATUS_DATA_BUSY                BIT(9)
+#define     MMC_CTRL_CONTROLLER_RESET           BIT(0)
+#define     MMC_CTRL_FIFO_RESET                 BIT(1)
+#define     MMC_CTRL_DMA_RESET                  BIT(2)
+#define     MMC_CTRL_INT_ENABLE                 BIT(4)
+#define     MMC_CTRL_USE_DMA                    BIT(25)
+#define     MMC_CMD_START_CMD                   BIT(31)
+#define     MMC_BMOD_RESET                      BIT(0)
+
+#define     MMC_CLOCK_IN                        (50000000)
+
+#define     MMC_CARD_WIDTH_1BIT                 (0)
+#define     MMC_CARD_WIDTH_4BIT                 (1)
+
+#define     MMC_INT_STATUS_CARD_DETECT          BIT(0)
+#define     MMC_INT_STATUS_RESPONSE_ERROR       BIT(1)
+#define     MMC_INT_STATUS_CMD_DONE             BIT(2)
+#define     MMC_INT_STATUS_TRANSFER_OVER        BIT(3)
+#define     MMC_INT_STATUS_TX_REQUEST           BIT(4)
+#define     MMC_INT_STATUS_RX_REQUEST           BIT(5)
+#define     MMC_INT_STATUS_RESP_CRC_ERROR       BIT(6)
+#define     MMC_INT_STATUS_DATA_CRC_ERROR       BIT(7)
+#define     MMC_INT_STATUS_RESPONSE_TIMEOUT     BIT(8)
+#define     MMC_INT_STATUS_READ_TIMEOUT         BIT(9)
+#define     MMC_INT_STATUS_STARVATION_TIMEOUT   BIT(10)
+#define     MMC_INT_STATUS_OVERRUN_UNDERRUN     BIT(11)
+#define     MMC_INT_STATUS_HARDWARE_LOCKED      BIT(12)
+#define     MMC_INT_STATUS_START_BIT_ERROR      BIT(13)
+#define     MMC_INT_STATUS_AUTO_CMD_DONE        BIT(14)
+#define     MMC_INT_STATUS_END_BIT_ERROR        BIT(15)
+#define     MMC_INT_STATUS_SDIO                 BIT(16)
+#define     MMC_INT_STATUS_ALL                  (~0)
+
+#define     MMC_INIT_STATUS_DATA_ERROR          (MMC_INT_STATUS_DATA_CRC_ERROR \
+                                                | MMC_INT_STATUS_START_BIT_ERROR | MMC_INT_STATUS_END_BIT_ERROR)
+
+#define     MMC_USE_DMA
+
+#ifdef      MMC_USE_DMA
+#define     MMC_INT_STATUS_DATA                 (MMC_INT_STATUS_TRANSFER_OVER | MMC_INIT_STATUS_DATA_ERROR)
+#else
+#define     MMC_INT_STATUS_DATA                 (MMC_INT_STATUS_TRANSFER_OVER | MMC_INIT_STATUS_DATA_ERROR \
+                                                | MMC_INT_STATUS_TX_REQUEST | MMC_INT_STATUS_RX_REQUEST)
+#endif
+
+#define     MMC_DMA_DESC_BUFF_SIZE              (0x1f00)
+
+
+typedef union
+{
+    struct
+    {
+        UINT32  reserved                            :1; //0~15
+        UINT32  disable_interrupt_on_completion     :1; //16~31
+        UINT32  last_descriptor                     :1; //0~15
+        UINT32  first_descriptor                    :1; //16~31
+        UINT32  sencond_address_chained             :1; //0~15
+        UINT32  end_of_ring                         :1; //16~31
+        UINT32  reserved_29_6                       :24; //0~15
+        UINT32  card_error_summary                  :1; //16~31
+        UINT32  own                                 :1; //16~31
+    }bit;
+    UINT32 dw;
+}MMC_DMA_Descriptor0;
+
+typedef union
+{
+    struct
+    {
+        UINT32  buffer1_size                        :13; //0~15
+        UINT32  buffer2_size                        :13; //16~31
+        UINT32  reserved_26_31                      :6; //0~15
+    }bit;
+    UINT32 dw;
+}MMC_DMA_Descriptor1;
+
+typedef union
+{
+    struct
+    {
+        UINT32  buffer_addr0                     :32; //0~15
+    }bit;
+    UINT32 dw;
+}MMC_DMA_Descriptor2;
+
+typedef union
+{
+    struct
+    {
+        UINT32  buffer_addr1                     :32; //0~15
+    }bit;
+    UINT32 dw;
+}MMC_DMA_Descriptor3;
+
+typedef struct
+{
+    MMC_DMA_Descriptor0 desc0;       /* control and status information of descriptor */
+    MMC_DMA_Descriptor1 desc1;       /* buffer sizes                                 */
+    MMC_DMA_Descriptor2 desc2;       /* physical address of the buffer 1             */
+    MMC_DMA_Descriptor3 desc3;       /* physical address of the buffer 2             */
+}MMC_DMA_Descriptors;
+
+struct fh_mmc_obj
+{
+    rt_uint32_t             id;
+    rt_uint32_t             irq;
+    rt_uint32_t             base;
+    rt_uint32_t             power_pin_gpio;
+    MMC_DMA_Descriptors     *descriptors;
+    void                    (*mmc_reset)(struct fh_mmc_obj *);
+};
+inline void MMC_SetBlockSize(struct fh_mmc_obj *mmc_obj, rt_uint32_t size);
+inline void MMC_SetByteCount(struct fh_mmc_obj *mmc_obj, rt_uint32_t bytes);
+inline rt_uint32_t MMC_GetWaterlevel(struct fh_mmc_obj *mmc_obj);
+inline rt_uint32_t MMC_GetResponse(struct fh_mmc_obj *mmc_obj, int resp_num);
+inline rt_uint32_t MMC_GetRegCmd(struct fh_mmc_obj *mmc_obj);
+inline rt_uint32_t MMC_GetRegCtrl(struct fh_mmc_obj *mmc_obj);
+inline rt_uint32_t MMC_SetInterruptMask(struct fh_mmc_obj *mmc_obj, rt_uint32_t mask);
+inline rt_uint32_t MMC_GetInterruptMask(struct fh_mmc_obj *mmc_obj);
+inline rt_uint32_t MMC_ClearRawInterrupt(struct fh_mmc_obj *mmc_obj, rt_uint32_t interrupts);
+inline rt_uint32_t MMC_GetRawInterrupt(struct fh_mmc_obj *mmc_obj);
+inline rt_uint32_t MMC_GetStatus(struct fh_mmc_obj *mmc_obj);
+inline rt_uint32_t MMC_GetCardStatus(struct fh_mmc_obj *mmc_obj);
+
+void MMC_Init(struct fh_mmc_obj *mmc_obj);
+int MMC_ResetFifo(struct fh_mmc_obj *mmc_obj);
+int MMC_SetCardWidth(struct fh_mmc_obj *mmc_obj, int width);
+int MMC_UpdateClockRegister(struct fh_mmc_obj *mmc_obj, int div);
+int MMC_SendCommand(struct fh_mmc_obj *mmc_obj, rt_uint32_t cmd, rt_uint32_t arg, rt_uint32_t flags);
+int MMC_WriteData(struct fh_mmc_obj *mmc_obj, rt_uint32_t *buf, rt_uint32_t size);
+int MMC_ReadData(struct fh_mmc_obj *mmc_obj, rt_uint32_t *buf, rt_uint32_t size);
+
+inline void MMC_StartDma(struct fh_mmc_obj *mmc_obj);
+inline void MMC_StopDma(struct fh_mmc_obj *mmc_obj);
+void MMC_InitDescriptors(struct fh_mmc_obj *mmc_obj, rt_uint32_t *buf, rt_uint32_t size);
+
+#endif /* FH_MMC_H_ */

+ 44 - 0
bsp/fh8620/libraries/inc/fh_pwm.h

@@ -0,0 +1,44 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#ifndef FH_PWM_H_
+#define FH_PWM_H_
+
+#define OFFSET_PWM_CTRL                (0x00)
+#define OFFSET_PWM_CMD(n)              (((n) * 4) + OFFSET_PWM_CTRL + 4)
+
+struct fh_pwm_obj
+{
+    int                 id;
+    int                 irq;
+    unsigned int         base;
+};
+
+void PWM_Enable(struct fh_pwm_obj *pwm_obj, int enable);
+void PWM_SetPwmCmd(struct fh_pwm_obj *pwm_obj, int device_id, unsigned int reg);
+unsigned int PWM_GetPwmCmd(struct fh_pwm_obj *pwm_obj, int device_id);
+
+#endif /* FH_PWM_H_ */

+ 356 - 0
bsp/fh8620/libraries/inc/fh_sdio.h

@@ -0,0 +1,356 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#ifndef FH_SDIO_H_
+#define FH_SDIO_H_
+
+#include <rtthread.h>
+
+//#define __ASIC_BRANCH__
+
+enum {
+	CTRL        = 0x0, 	/** Control */
+	PWREN    = 0x4, 	/** Power-enable */
+	CLKDIV   = 0x8, 	/** Clock divider */
+	CLKSRC   = 0xC, 	/** Clock source */
+	CLKENA   = 0x10,    /** Clock enable */
+	TMOUT    = 0x14,    /** Timeout */
+	CTYPE    = 0x18,    /** Card type */
+	BLKSIZ   = 0x1C,    /** Block Size */
+	BYTCNT   = 0x20,    /** Byte count */
+	INTMSK   = 0x24,    /** Interrupt Mask */
+	CMDARG   = 0x28,    /** Command Argument */
+	CMD      = 0x2C,    /** Command */
+	RESP0    = 0x30,    /** Response 0 */
+	RESP1    = 0x34,    /** Response 1 */
+	RESP2    = 0x38,    /** Response 2 */
+	RESP3    = 0x3C,    /** Response 3 */
+	MINTSTS  = 0x40,    /** Masked interrupt status */
+	RINTSTS  = 0x44,    /** Raw interrupt status */
+	STATUS   = 0x48,    /** Status */
+	FIFOTH   = 0x4C,    /** FIFO threshold */
+	CDETECT  = 0x50,    /** Card detect */
+	WRTPRT   = 0x54,    /** Write protect */
+	GPIO     = 0x58,    /** General Purpose IO */
+	TCBCNT   = 0x5C,    /** Transferred CIU byte count */
+	TBBCNT   = 0x60,    /** Transferred host/DMA to/from byte count */
+	DEBNCE   = 0x64,    /** Card detect debounce */
+	USRID    = 0x68,    /** User ID */
+	VERID    = 0x6C,    /** Version ID */
+	HCON     = 0x70,    /** Hardware Configuration */
+	UHSREG   = 0x74,    /** Reserved */
+ 	BMOD	 = 0x80,    /** Bus mode Register */
+	PLDMND	 = 0x84,    /** Poll Demand */
+	DBADDR	 = 0x88,    /** Descriptor Base Address */
+	IDSTS	 = 0x8C,    /** Internal DMAC Status */
+	IDINTEN  = 0x90,    /** Internal DMAC Interrupt Enable */
+	DSCADDR  = 0x94,    /** Current Host Descriptor Address */
+	BUFADDR	 = 0x98,    /** Current Host Buffer Address */
+	FIFODAT  = 0x200,   /** FIFO data read write */
+};
+
+/* Control register definitions */
+#define CTRL_RESET	          0x00000001
+#define FIFO_RESET              0x00000002
+#define DMA_RESET	          0x00000004
+#define INT_ENABLE	          0x00000010
+#define READ_WAIT	          0x00000040
+#define CTRL_USE_IDMAC	   0x02000000
+
+/* Interrupt mask defines */
+#define INTMSK_CDETECT        0x00000001
+#define INTMSK_RESP_ERR     0x00000002
+#define INTMSK_CMD_DONE   0x00000004
+#define INTMSK_DAT_OVER    0x00000008
+#define INTMSK_TXDR             0x00000010
+#define INTMSK_RXDR             0x00000020
+#define INTMSK_RCRC             0x00000040
+#define INTMSK_DCRC             0x00000080
+#define INTMSK_RTO               0x00000100
+#define INTMSK_DTO               0x00000200
+#define INTMSK_HTO               0x00000400
+#define INTMSK_VSI                INTMSK_HTO  // VSI => Voltage Switch Interrupt
+#define INTMSK_FRUN             0x00000800
+#define INTMSK_HLE                0x00001000
+#define INTMSK_SBE                0x00002000
+#define INTMSK_ACD               0x00004000
+#define INTMSK_EBE                0x00008000
+#define INTMSK_SDIO              0x00010000
+#define INTMASK_ERROR        (INTMSK_RESP_ERR|INTMSK_RCRC|INTMSK_DCRC|INTMSK_RTO|INTMSK_DTO|INTMSK_HTO|INTMSK_FRUN|INTMSK_HLE|INTMSK_SBE|INTMSK_EBE)
+
+/*BMOD register define */
+#define  BMOD_SWR 	  	   0x00000001
+#define  BMOD_DE 		   0x00000080
+
+/* for STATUS register */
+#define GET_FIFO_COUNT(x)           	(((x)&0x3ffe0000)>>17)
+#define GET_FIFO_DEPTH(x)       ((((x)&0x0FFF0000)>>16)+1)
+
+/* for IDMA intr register */
+#define IDMAINTBITS   0x337
+
+/* PMU related registers */
+//#define PMU_REG_BASE           0xF0000000
+#define PMU_REG_RST             0xF0000100
+#define PMU_REG_CLK_DIV3   0xF0000030
+#define PMU_SDC0_RST_BIT  9
+#define PMU_SDC1_RST_BIT  10
+#define PMU_RST_MODULE(x) *((volatile unsigned int*)(PMU_REG_RST)) = (~((1<<(x))))
+
+/* Define Card status bits (R1 response) */
+#define R1CS_ADDRESS_OUT_OF_RANGE       0x80000000
+#define R1CS_ADDRESS_MISALIGN		    0x40000000
+#define R1CS_BLOCK_LEN_ERR       		0x20000000
+#define R1CS_ERASE_SEQ_ERR	           	0x10000000
+#define R1CS_ERASE_PARAM	            0x08000000
+#define R1CS_WP_VIOLATION		        0x04000000
+#define R1CS_CARD_IS_LOCKED	            0x02000000
+#define R1CS_LCK_UNLCK_FAILED		    0x01000000
+#define R1CS_COM_CRC_ERROR		        0x00800000
+#define R1CS_ILLEGAL_COMMAND		    0x00400000
+#define R1CS_CARD_ECC_FAILED		    0x00200000
+#define R1CS_CC_ERROR		        	0x00100000
+#define R1CS_ERROR		            	0x00080000
+#define R1CS_UNDERRUN		        	0x00040000
+#define R1CS_OVERRUN		        	0x00020000
+#define R1CS_CSD_OVERWRITE	        	0x00010000
+#define R1CS_WP_ERASE_SKIP	        	0x00008000
+#define R1CS_RESERVED_0	        		0x00004000
+#define R1CS_ERASE_RESET        		0x00002000
+#define R1CS_CURRENT_STATE_MASK    		0x00001e00
+#define R1CS_READY_FOR_DATA	        	0x00000100
+#define R1CS_SWITCH_ERROR        		0x00000080
+#define R1CS_RESERVED_1		        	0x00000040
+#define R1CS_APP_CMD		        	0x00000020
+#define R1CS_RESERVED_2		        	0x00000010
+#define R1CS_APP_SPECIFIC_MASK	    	0x0000000c
+#define R1CS_MANUFAC_TEST_MASK    		0x00000003
+#define R1CS_ERROR_OCCURED_MAP	    	0xfdffa080
+#define R1CS_CURRENT_STATE(x)	    	(((x)&R1CS_CURRENT_STATE_MASK)>>9)
+
+/* R5 response */
+#define R5_IO_CRC_ERR	  0x00008000
+#define R5_IO_BAD_CMD	  0x00004000
+#define R5_IO_GEN_ERR	  0x00000800
+#define R5_IO_FUNC_ERR	  0x00000200
+#define R5_IO_OUT_RANGE 0x00000100
+#define R5_IO_ERR_BITS	  0x0000cb00
+
+enum {
+	NONE_TYPE = 0,
+	SD_TYPE,
+	SD_2_0_TYPE,
+	SDIO_TYPE,
+};
+
+enum {
+	CARD_STATE_EMPTY = -1,
+	CARD_STATE_IDLE = 0,
+	CARD_STATE_READY = 1,
+	CARD_STATE_IDENT = 2,
+	CARD_STATE_STBY = 3,
+	CARD_STATE_TRAN = 4,
+	CARD_STATE_DATA = 5,
+	CARD_STATE_RCV = 6,
+	CARD_STATE_PRG = 7,
+	CARD_STATE_DIS = 8,
+	CARD_STATE_INA = 9
+};
+
+enum DmaDescriptorDES1    // Buffer's size field of Descriptor
+{
+     DescBuf2SizMsk       = 0x03FFE000,    /* Mask for Buffer2 Size                            25:13   */
+     DescBuf2SizeShift    = 13,            /* Shift value for Buffer2 Size                             */
+     DescBuf1SizMsk       = 0x00001FFF,    /* Mask for Buffer1 Size                            12:0    */
+     DescBuf1SizeShift    = 0,             /* Shift value for Buffer2 Size                             */
+};
+
+enum DmaDescriptorDES0    // Control and status word of DMA descriptor DES0
+{
+     DescOwnByDma          = 0x80000000,   /* (OWN)Descriptor is owned by DMA engine              31   */
+     DescCardErrSummary    = 0x40000000,   /* Indicates EBE/RTO/RCRC/SBE/DRTO/DCRC/RE             30   */
+     DescEndOfRing         = 0x00000020,   /* A "1" indicates End of Ring for Ring Mode           05   */
+     DescSecAddrChained    = 0x00000010,   /* A "1" indicates DES3 contains Next Desc Address     04   */
+     DescFirstDesc         = 0x00000008,   /* A "1" indicates this Desc contains first            03
+                                              buffer of the data                                       */
+     DescLastDesc          = 0x00000004,   /* A "1" indicates buffer pointed to by this this      02
+                                              Desc contains last buffer of Data                        */
+     DescDisInt            = 0x00000002,   /* A "1" in this field disables the RI/TI of IDSTS     01
+                                              for data that ends in the buffer pointed to by
+                                              this descriptor                                          */
+};
+
+typedef struct DmaDescStruct {
+		unsigned int desc0;   	 /* control and status information of descriptor */
+		unsigned int desc1;   	 /* buffer sizes                                 */
+		unsigned int desc2;   	 /* physical address of the buffer 1             */
+		unsigned int desc3;    	 /* physical address of the buffer 2             */
+}DmaDesc;
+
+typedef struct {
+	unsigned int wkmod;
+	volatile DmaDesc *pDmaDesc;
+	unsigned int idma_support;
+	unsigned int rca;
+	unsigned int ip_base;
+	unsigned int card_type;
+	unsigned int fifo_depth;
+	unsigned int fifo_threth;
+	unsigned int sectors;
+	unsigned int scr[2];
+	unsigned int csd[4];
+	unsigned int idsts;
+	rt_sem_t sem;
+	rt_sem_t mutex;
+	void (*cb)(void);
+} sdc_t;
+
+#define ONE_BIT_MODE     (0)
+#define FOUR_BIT_MODE   (1)
+
+#define BE32_TO_CPU(x) ((unsigned int)(             \
+       (((unsigned int)(x) & (unsigned int)0x000000ffUL) << 24) |        \
+        (((unsigned int)(x) & (unsigned int)0x0000ff00UL) <<  8) |        \
+       (((unsigned int)(x) & (unsigned int)0x00ff0000UL) >>  8) |        \
+     (((unsigned int)(x) & (unsigned int)0xff000000UL) >> 24)))
+
+#define synopmob_set_bits(reg, bit_id) *((volatile unsigned int *)(reg)) |= ((unsigned int)(bit_id))
+#define synopmob_clear_bits(reg, bit_id) *((volatile unsigned int *)(reg)) &= (~((unsigned int)(bit_id)))
+#define synopmob_set_register(reg, val) *((volatile unsigned int*)(reg)) = (val)
+#define synopmob_read_register(reg) (*((volatile unsigned int*)(reg)))
+
+
+enum {
+	ERRNOERROR = 0,
+		
+	// for raw interrupt status error
+	ERRRESPRECEP,    // 1
+	ERRRESPCRC,
+	ERRDCRC,
+	ERRRESPTIMEOUT,
+	ERRDRTIMEOUT,
+	ERRUNDERWRITE,
+	ERROVERREAD,
+	ERRHLE,
+	ERRSTARTBIT,
+	ERRENDBITERR,  // 10
+
+	// for R1 response
+	ERRADDRESSRANGE,  // 11
+	ERRADDRESSMISALIGN,
+	ERRBLOCKLEN,
+	ERRERASESEQERR,
+	ERRERASEPARAM,
+	ERRPROT,
+	ERRCARDLOCKED,
+	ERRCRC,
+	ERRILLEGALCOMMAND,
+	ERRECCFAILED,
+	ERRCCERR,
+	ERRUNKNOWN,
+	ERRUNDERRUN,
+	ERROVERRUN,
+	ERRCSDOVERWRITE,
+	ERRERASERESET,
+	ERRFSMSTATE,  // 27
+
+	// for R5 response
+	ERRBADFUNC,   // 28
+
+	// others
+	ERRCARDNOTCONN,  // 29
+	ERRCARDWPROTECT,
+	ERRCMDRETRIESOVER,
+	ERRNOTSUPPORTED,
+	ERRHARDWARE,
+	ERRDATANOTREADY,
+	ERRCARDINTERNAL,
+	ERRACMD41TIMEOUT,
+	ERRIDMA,
+	ERRNORES,
+
+	ERRNOTEQUAL,
+};
+
+#ifdef __ASIC_BRANCH__
+#define SDC_WHERE() *((volatile unsigned int*)0x9b800000) = ((unsigned int)(__LINE__))
+#define SDC_ERROR()  do { *((volatile unsigned int*)0x9b800008)=ret; *((volatile unsigned int*)0x9a7ff000) = 0;}while(0)
+#define SDC_FINISH() *((volatile unsigned int*)0x9a7ff004) = 0;
+#else
+#define SDC_WHERE()
+#define SDC_ERROR()
+#define SDC_FINISH()
+#endif //__ASIC_BRANCH__
+
+#define SDC_WKMOD_25M_STAND_SPEED  0x0002   // 25M standard speed
+#define SDC_WKMOD_50M_HI_SPEED         0x0004   // 50M high speed
+#define SDC_WKMOD_1WIRE                        0x0008   // 1 wire transfer mode
+#define SDC_WKMOD_4WIRE                        0x0010   // 4 wire transfer mode
+
+#define SDC_RW_USE_DMA                           0x80000000   // Use DMA transfer?
+
+
+typedef void* HSDC;
+
+// map to DmaDesc
+typedef struct _buf_chain {
+    unsigned int csi;             // desc0
+    unsigned int size;            // desc1
+    void * buf;             // desc2
+    struct _buf_chain *next; // desc3
+}buf_chain_t;
+
+
+/*
+  * for SD card
+   */
+extern int sdc_is_connected(unsigned int which);
+extern int sdc_init(unsigned int which, unsigned int wkmod, unsigned int* dma_desc/*4Byte aligned,16 bytes space*/, HSDC* phandle);
+extern int sdc_read_block(HSDC handle, unsigned int blk, unsigned int num, unsigned char* buffer);
+extern int sdc_write_block(HSDC handle, unsigned int blk, unsigned int num, unsigned char* buffer);
+extern int sdc_erase_block(HSDC handle, unsigned int blk, unsigned int num);
+extern int sdc_get_sector_num(HSDC handle);
+extern int sdc_set_clk_divider(unsigned int divider);
+
+/*
+  * for SDIO WIFI card
+   */
+extern void fh_sdio0_init(void);
+extern void fh_sdio1_init(void);
+extern void fh_sdio_init(void);
+extern int sdio_init(unsigned int which, unsigned int wkmod, unsigned int* dma_desc/*4Byte aligned,16 bytes space*/, HSDC* phandle);
+extern int sdio_high_speed_mode(HSDC handle, int bitwidth, int freq);
+extern int sdio_enable_card_int(HSDC handle, int enable);
+extern int sdio_set_card_int_cb(HSDC handle, void (*cb)(void));
+extern int sdio_drv_read(HSDC handle, unsigned int addr, unsigned int fn, unsigned int bcnt, unsigned int bsize, unsigned char *buf);
+extern int sdio_drv_write(HSDC handle, unsigned int addr, unsigned int fn, unsigned int bcnt, unsigned int bsize, unsigned char *buf);
+extern int sdio_drv_creg_read(HSDC handle, int addr, int fn, unsigned int *resp);
+extern int sdio_drv_creg_write(HSDC handle, int addr, int fn, unsigned char data, unsigned int *resp);
+
+extern void inv_dcache_range(unsigned long start, unsigned long len);
+extern void flush_dcache_range(unsigned long start, unsigned long len);
+ 
+#endif //__sdcard_h__

+ 148 - 0
bsp/fh8620/libraries/inc/fh_spi.h

@@ -0,0 +1,148 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef FH_SPI_H_
+#define FH_SPI_H_
+
+#include "fh_def.h"
+#include "fh_arch.h"
+
+#define OFFSET_SPI_CTRL0                        (0x00)
+#define OFFSET_SPI_CTRL1                        (0x04)
+#define OFFSET_SPI_SSIENR                       (0x08)
+#define OFFSET_SPI_MWCR                         (0x0c)
+#define OFFSET_SPI_SER                          (0x10)
+#define OFFSET_SPI_BAUD                         (0x14)
+#define OFFSET_SPI_TXFTLR                       (0x18)
+#define OFFSET_SPI_RXFTLR                       (0x1c)
+#define OFFSET_SPI_TXFLR                        (0x20)
+#define OFFSET_SPI_RXFLR                        (0x24)
+#define OFFSET_SPI_SR                           (0x28)
+#define OFFSET_SPI_IMR                          (0x2c)
+#define OFFSET_SPI_ISR                          (0x30)
+#define OFFSET_SPI_RISR                         (0x34)
+#define OFFSET_SPI_TXOIC                        (0x38)
+#define OFFSET_SPI_RXOIC                        (0x3c)
+#define OFFSET_SPI_RXUIC                        (0x40)
+#define OFFSET_SPI_MSTIC                        (0x44)
+#define OFFSET_SPI_ICR                          (0x48)
+#define OFFSET_SPI_DMACTRL                      (0x4c)
+#define OFFSET_SPI_DMATDL                       (0x50)
+#define OFFSET_SPI_DMARDL                       (0x54)
+#define OFFSET_SPI_IDR                          (0x58)
+#define OFFSET_SPI_SSI_COMPVER                  (0x5c)
+#define OFFSET_SPI_DR                           (0x60)
+
+
+#define SPI_FORMAT_MOTOROLA         (0x00)
+#define SPI_FORMAT_TI               (0x10)
+#define SPI_FORMAT_MICROWIRE        (0x20)
+
+#define SPI_MODE_TX_RX              (0x000)
+#define SPI_MODE_TX_ONLY            (0x100)
+#define SPI_MODE_RX_ONLY            (0x200)
+#define SPI_MODE_EEPROM             (0x300)
+
+#define SPI_DATA_SIZE_4BIT          (0x03)
+#define SPI_DATA_SIZE_5BIT          (0x04)
+#define SPI_DATA_SIZE_6BIT          (0x05)
+#define SPI_DATA_SIZE_7BIT          (0x06)
+#define SPI_DATA_SIZE_8BIT          (0x07)
+#define SPI_DATA_SIZE_9BIT          (0x08)
+#define SPI_DATA_SIZE_10BIT         (0x09)
+#define SPI_DATA_SIZE_16BIT         (0x0f)
+
+#define SPI_POLARITY_HIGH           (1<<7)
+#define SPI_POLARITY_LOW            (0<<7)
+
+#define SPI_PHASE_RX_FIRST          (0<<6)
+#define SPI_PHASE_TX_FIRST          (1<<6)
+
+#define SPI_FIFO_DEPTH              (32)
+
+#define SPI_IRQ_TXEIM               (1<<0)
+#define SPI_IRQ_TXOIM               (1<<1)
+#define SPI_IRQ_RXUIM               (1<<2)
+#define SPI_IRQ_RXOIM               (1<<3)
+#define SPI_IRQ_RXFIM               (1<<4)
+#define SPI_IRQ_MSTIM               (1<<5)
+#define SPI_IRQ_ALL                 (0x3f)
+
+#define SPI_ISR_FLAG        (SPI_IRQ_TXEIM|SPI_IRQ_TXOIM|SPI_IRQ_RXUIM|SPI_IRQ_RXOIM)
+#define SPI_ISR_ERROR       (SPI_IRQ_TXOIM | SPI_IRQ_RXUIM | SPI_IRQ_RXOIM)
+
+#define SPI_STATUS_BUSY             (1)
+
+
+#define SPI_TX_DMA			(1<<1)
+#define SPI_RX_DMA			(1<<0)
+
+
+struct spi_config
+{
+    rt_uint32_t        frame_format;
+    rt_uint32_t        transfer_mode;
+    rt_uint32_t        clk_polarity;
+    rt_uint32_t        clk_phase;
+    rt_uint32_t        data_size;
+    rt_uint32_t        clk_div;
+};
+
+
+
+
+struct fh_spi_obj
+{
+    rt_uint32_t        id;
+    rt_uint32_t        irq;
+    rt_uint32_t        base;
+    rt_uint32_t        fifo_len;
+    rt_uint32_t        transfered_len;
+    rt_uint32_t        received_len;
+    rt_uint32_t        cs_gpio_pin;
+
+    struct spi_config config;
+};
+
+void SPI_EnableSlaveen(struct fh_spi_obj *spi_obj, rt_uint32_t port);
+void SPI_DisableSlaveen(struct fh_spi_obj *spi_obj, rt_uint32_t port);
+void SPI_SetTxLevel(struct fh_spi_obj *spi_obj, rt_uint32_t level);
+void SPI_EnableIrq(struct fh_spi_obj *spi_obj, rt_uint32_t flag);
+void SPI_DisableIrq(struct fh_spi_obj *spi_obj, rt_uint32_t flag);
+rt_uint32_t SPI_InterruptStatus(struct fh_spi_obj *spi_obj);
+void SPI_ClearInterrupt(struct fh_spi_obj *spi_obj);
+rt_uint32_t SPI_ReadTxFifoLevel(struct fh_spi_obj *spi_obj);
+rt_uint32_t SPI_ReadRxFifoLevel(struct fh_spi_obj *spi_obj);
+UINT8 SPI_ReadData(struct fh_spi_obj *spi_obj);
+void SPI_WriteData(struct fh_spi_obj *spi_obj, UINT8 data);
+rt_uint32_t SPI_ReadStatus(struct fh_spi_obj *spi_obj);
+void SPI_Enable(struct fh_spi_obj *spi_obj, int enable);
+void SPI_SetParameter(struct fh_spi_obj *spi_obj);
+void SPI_EnableDma(struct fh_spi_obj *spi_obj, rt_uint32_t channel);
+void SPI_DisableDma(struct fh_spi_obj *spi_obj, rt_uint32_t channel);
+void SPI_WriteTxDmaLevel(struct fh_spi_obj *spi_obj, rt_uint32_t data);
+void SPI_WriteRxDmaLevel(struct fh_spi_obj *spi_obj, rt_uint32_t data);
+#endif /* FH_SPI_H_ */

+ 100 - 0
bsp/fh8620/libraries/inc/fh_timer.h

@@ -0,0 +1,100 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#ifndef FH_TIMER_H_
+#define FH_TIMER_H_
+
+ /****************************************************************************
+ * #include section
+ *	add #include here if any
+ ***************************************************************************/
+#include "fh_def.h"
+
+
+
+
+ /****************************************************************************
+ * #define section
+ *	add constant #define here if any
+ ***************************************************************************/
+#define TIMER_CTRL_ENABLE   (1u << 0)
+#define TIMER_CTRL_MODE     (1u << 1)
+#define TIMER_CTRL_INTMASK  (1u << 2)
+#define TIMER_CTRL_PWMEN    (1u << 3)
+
+
+
+ /****************************************************************************
+ * ADT section
+ *	add Abstract Data Type definition here
+ ***************************************************************************/
+typedef struct {
+	RwReg TIMER_LOAD_COUNT;
+	RwReg TIMER_CURRENT_VALUE;
+	RwReg TIMER_CTRL_REG;
+	RwReg TIMER_EOI;
+	RwReg TIMER_INT_STATUS;
+}timer;
+
+ enum timer_mode {
+ 	TIMER_MODE_PERIODIC = 0,
+ 	TIMER_MODE_ONESHOT = 1,
+ };
+
+
+
+
+/****************************************************************************
+*  extern variable declaration section
+***************************************************************************/
+
+/****************************************************************************
+*  section
+*	add function prototype here if any
+***************************************************************************/
+
+
+int timer_init(timer *tim);
+
+int timer_set_mode(timer *tim, enum timer_mode);
+
+void timer_set_period(timer *tim, UINT32 period, UINT32 clock);
+
+void timer_enable(timer *tim);
+
+void timer_disable(timer *tim);
+
+void timer_enable_irq(timer *tim);
+
+void timer_disable_irq(timer *tim);
+
+UINT32 timer_get_status(timer *tim);
+
+void udelay(unsigned long usec);
+
+
+#endif /* #ifndef _TIMER_ */
+

+ 245 - 0
bsp/fh8620/libraries/inc/fh_uart.h

@@ -0,0 +1,245 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#ifndef FH_UART_H_
+#define FH_UART_H_
+
+ /****************************************************************************
+ * #include section
+ *	add #include here if any
+ ***************************************************************************/
+#include "fh_def.h"
+
+ /****************************************************************************
+ * #define section
+ *	add constant #define here if any
+ ***************************************************************************/
+
+#define UART_RBR RBRTHRDLL
+#define UART_THR RBRTHRDLL
+#define UART_DLL RBRTHRDLL
+
+#define UART_DLH DLHIER
+#define UART_IER DLHIER
+
+#define UART_IIR IIRFCR
+#define UART_FCR IIRFCR
+
+/* LSR register bits */
+#define UART_LSR_DR    (1 << 0)
+#define UART_LSR_OE    (1 << 1)
+#define UART_LSR_PE    (1 << 2)
+#define UART_LSR_FE    (1 << 3)
+#define UART_LSR_BI    (1 << 4)
+#define UART_LSR_THER  (1 << 5)
+#define UART_LST_TEMT  (1 << 6)
+#define UART_LSR_RFE   (1 << 7)
+
+/* LCR register bits */
+#define UART_LCR_DLS5   0x00
+#define UART_LCR_DLS6   0x01
+#define UART_LCR_DLS7   0x02
+#define UART_LCR_DLS8   0x03
+#define UART_LCR_STOP1  0
+#define UART_LCR_STOP2  (1 << 2)
+#define UART_LCR_PEN    (1 << 3)
+#define UART_LCR_EVEN   (1 << 4)
+#define UART_LCR_SP     (1 << 5)
+#define UART_LCR_BC     (1 << 6)
+#define UART_LCR_DLAB   (1 << 7)
+
+/* MCR register bits */
+#define UART_MCR_DTR    (1 << 0)
+#define UART_MCR_RTS    (1 << 1)
+#define UART_MCR_OUT1   (1 << 2)
+#define UART_MCR_OUT2   (1 << 3)
+#define UART_MCR_LB     (1 << 4)
+#define UART_MCR_AFCE   (1 << 5)
+#define UART_MCR_SIRE   (1 << 6)
+
+/* FCR register bits */
+#define UART_FCR_FIFOE  (1 << 0)
+#define UART_FCR_RFIFOR (1 << 1)
+#define UART_FCR_XFIFOR (1 << 2)
+#define UART_FCR_DMAM   (1 << 3)
+#define UART_FCR_TET_EMPTY (0x00 << 4)
+#define UART_FCR_TET_TWO   (0x01 << 4)
+#define UART_FCR_TET_1_4   (0x02 << 4)
+#define UART_FCR_TET_1_2   (0x03 << 4)
+#define UART_FCR_RT_ONE    (0x00 << 6)
+#define UART_FCR_RT_1_4    (0x01 << 6)
+#define UART_FCR_RT_1_2    (0x02 << 6)
+#define UART_FCR_RT_L2     (0x03 << 6)
+
+/* IER register bits */
+#define UART_IER_ERBFI   (1 << 0)
+#define UART_IER_ETBEI   (1 << 1)
+#define UART_IER_ELSI    (1 << 2)
+#define UART_IER_EDSSI   (1 << 3)
+#define UART_IER_PTIME   (1 << 7)
+
+/* USR register bits */
+#define UART_USR_BUSY    (1 << 0)
+#define UART_USR_TFNF    (1 << 1)
+#define UART_USR_TFE     (1 << 2)
+#define UART_USR_RNFE    (1 << 3)
+#define UART_USR_RFE     (1 << 4)
+
+/* IIR register bits */
+#define UART_IIR_RIID_MASK 0x0f
+#define UART_IIR_MODEM    0x00
+#define UART_IIR_NOINT    0x01
+#define UART_IIR_THREMPTY 0x02
+#define UART_IIR_RDATD    0x04
+#define UART_IIR_RLINEST  0x06
+#define UART_IIR_BUSY     0x07
+#define UART_IIR_CHRTOUT  0x0c
+#define UART_IIR_FIFOSE  (0x03 << 6)
+
+//uart baudrate cofig
+//#define 	UART_CLOCK_FREQ   	(27000000)   //27MHZ
+//
+//#define DIV(n)	(((UART_CLOCK_FREQ/(n))+8)/16)
+
+
+ /****************************************************************************
+ * ADT section
+ *	add Abstract Data Type definition here
+ ***************************************************************************/
+
+
+
+
+typedef struct {
+	RwReg RBRTHRDLL; /* UART_RBR, UART_THR, UART_DLL */
+	RwReg DLHIER;    /* UART_DLH, UART_IER */
+	RwReg IIRFCR;    /* UART_IIR, UART_FCR */
+	RwReg UART_LCR; /*(0x000c) */
+	RwReg UART_MCR; /*(0x0010) */
+	RwReg UART_LSR; /*(0x0014) */
+	RwReg UART_MSR; /*(0x0018) */
+	RwReg UART_SCR; /*(0x001c) */
+	RwReg reserved[20];
+	RwReg UART_FAR; /* (0x0070) */
+	RwReg UART_TFR; /* (0x0074) */
+	RwReg UART_RFW; /* (0x0078) */
+	RwReg UART_USR; /* (0x007c) */
+	RwReg UART_TFL; /* (0x0080) */
+	RwReg UART_RFL; /* (0x0084) */
+	RwReg UART_SRR; /* (0x0088) */
+	RwReg reserved1[3];
+	RwReg UART_SFE;  /* (0x0098) */
+	RwReg UART_SRT;  /* (0x009c) */
+	RwReg UART_STET; /* (0x00a0) */
+	RwReg UART_HTX;  /* (0x00a4) */
+	RwReg UART_DMASA; /* (0x00a8) */
+	RwReg reserved2[18];
+	RwReg UART_CPR;  /* (0x00f4) */
+	RwReg UART_UCV;  /* (0x00f8) */
+	RwReg UART_CTR;  /* (0x00fc) */
+}uart;
+
+
+
+struct fh_uart {
+	uart *uart_port;
+	int irq;
+};
+
+
+
+
+
+enum data_bits {
+	UART_DATA_BIT5 = 0,
+	UART_DATA_BIT6 = 1,
+	UART_DATA_BIT7 = 2,
+	UART_DATA_BIT8 = 3
+};
+
+enum stop_bits {
+	UART_STOP_BIT1   = 0,
+	UART_STOP_BIT1_5 = 1,
+	UART_STOP_BIT2   = 2
+};
+
+enum parity {
+	UART_PARITY_NONE = 0,
+	UART_PARITY_EVEN = 1,
+	UART_PARITY_ODD  = 2,
+	UART_PARITY_ST   = 3 /* Stick Parity */
+};
+
+
+#define 	UART_CLOCK_FREQ   	(30000000)   //30MHZ
+typedef enum enum_uart_baudrate{
+	BAUDRATE_9600 	= (((UART_CLOCK_FREQ/9600)+8)/16),
+	BAUDRATE_19200 	= (((UART_CLOCK_FREQ/19200)+8)/16),
+	BAUDRATE_38400  = (((UART_CLOCK_FREQ/38400)+8)/16),
+	BAUDRATE_57600  = (((UART_CLOCK_FREQ/57600)+8)/16),
+	BAUDRATE_115200 = (((UART_CLOCK_FREQ/115200)+8)/16),
+	BAUDRATE_194000 = (((UART_CLOCK_FREQ/194000)+8)/16),
+}uart_baudrate_e;
+
+/****************************************************************************
+*  extern variable declaration section
+***************************************************************************/
+
+extern int uart_init(uart *port);
+
+extern UINT32 uart_get_status(uart *port);
+
+extern void uart_configure(uart *port, enum data_bits data_bit,
+					enum stop_bits stop_bit, enum parity parity,
+					UINT32 buard_rate, UINT32 uart_clk);
+
+
+extern int uart_enable_irq(uart *port, UINT32 mode);
+
+extern int uart_disable_irq(uart *port, UINT32 mode);
+
+extern UINT32 uart_get_iir_status(uart *port);
+
+extern UINT32 uart_get_line_status(uart *port);
+
+extern UINT32 uart_is_rx_ready(uart *port);
+
+extern UINT8 uart_getc(uart *port);
+
+extern void uart_putc(uart *port, UINT8 c);
+
+extern void uart_set_fifo_mode(uart *port, UINT32 fifo_mode);
+
+/****************************************************************************
+*  section
+*	add function prototype here if any
+***************************************************************************/
+
+
+
+
+#endif /* #ifndef _TIMER_ */
+

+ 65 - 0
bsp/fh8620/libraries/inc/fh_wdt.h

@@ -0,0 +1,65 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef FH_WDT_H_
+#define FH_WDT_H_
+
+#include "fh_def.h"
+
+#define WDOG_CONTROL_REG_OFFSET                  0x00
+#define WDOG_CONTROL_REG_WDT_EN_MASK             0x01
+#define WDOG_CONTROL_REG_RMOD_MASK               0x02
+#define WDOG_TIMEOUT_RANGE_REG_OFFSET            0x04
+#define WDOG_CURRENT_COUNT_REG_OFFSET            0x08
+#define WDOG_COUNTER_RESTART_REG_OFFSET          0x0c
+
+#define WDOG_COUNTER_RESTART_KICK_VALUE      0x76
+
+/* Hardware timeout in seconds */
+#define WDT_HW_TIMEOUT 2
+/* User land timeout */
+#define WDT_HEARTBEAT 15
+
+/* The maximum TOP (timeout period) value that can be set in the watchdog. */
+#define FH_WDT_MAX_TOP      15
+
+#define WDT_TIMEOUT     (HZ / 2)
+
+struct fh_wdt_obj
+{
+    int                 id;
+    int                 irq;
+    unsigned int         base;
+};
+
+void WDT_Enable(struct fh_wdt_obj *wdt_obj, int enable);
+inline int WDT_IsEnable(struct fh_wdt_obj *wdt_obj);
+void WDT_SetTopValue(struct fh_wdt_obj *wdt_obj, int top);
+void WDT_SetCtrl(struct fh_wdt_obj *wdt_obj, UINT32 reg);
+void WDT_Kick(struct fh_wdt_obj *wdt_obj);
+unsigned int  WDT_GetCurrCount(struct fh_wdt_obj *wdt_obj);
+
+#endif /* FH_WDT_H_ */

+ 10 - 0
bsp/fh8620/libraries/startup/SConscript

@@ -0,0 +1,10 @@
+from building import *
+
+Import('rtconfig')
+
+cwd = GetCurrentDir()
+src = ['gcc/start_gcc.S']
+
+group = DefineGroup('Libraries', src, depend = [''])
+
+Return('group')

+ 416 - 0
bsp/fh8620/libraries/startup/gcc/start_gcc.S

@@ -0,0 +1,416 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#include <rtconfig.h>
+#include <armv6.h>
+
+#define CONFIG_STACKSIZE 	512
+
+#define FPEXC_EN            (1 << 30) /* VFP enable bit */
+.equ    I_BIT,              0x80    @ when I bit is set, IRQ is disabled
+.equ    F_BIT,              0x40    @ when F bit is set, FIQ is disabled
+
+#.equ 	USERMODE, 			0x10
+#.equ 	FIQMODE,			0x11
+#.equ 	IRQMODE,			0x12
+#.equ 	SVCMODE,			0x13
+#.equ 	ABORTMODE,			0x17
+#.equ 	UNDEFMODE,			0x1b
+#.equ 	MODEMASK,			0x1f
+#.equ 	NOINT,				0xc0
+
+
+.equ    RAM_BASE,           0x00000000  /*Start address of RAM*/
+.equ    ROM_BASE,           0xA0000000  /*Start address of Flash*/
+
+#define    FH81_INTC_BASE   0xE0200000
+
+/*
+ *************************************************************************
+ *
+ * Jump vector table
+ *
+ *************************************************************************
+ */
+
+.section .init, "ax"
+.code 32
+
+.globl _start
+_start:
+	b		reset
+	ldr		pc, _vector_undef
+	ldr		pc, _vector_swi
+	ldr		pc, _vector_pabt
+	ldr		pc, _vector_dabt
+	ldr		pc, _vector_resv
+	ldr		pc, _vector_irq
+	ldr		pc, _vector_fiq
+
+_vector_undef:	.word vector_undef
+_vector_swi:	.word vector_swi
+_vector_pabt:	.word vector_pabt
+_vector_dabt:	.word vector_dabt
+_vector_resv:	.word vector_resv
+_vector_irq:	.word vector_irq
+_vector_fiq:	.word vector_fiq
+
+.balignl 	16,0xdeadbeef
+
+/*
+ *************************************************************************
+ *
+ * Startup Code (reset vector)
+ * relocate armboot to ram
+ * setup stack
+ * jump to second stage
+ *
+ *************************************************************************
+ */
+
+/*
+ * rtthread kernel start and end
+ * which are defined in linker script
+ */
+.globl _rtthread_start
+_rtthread_start:
+	.word _start
+	
+.globl _rtthread_end
+_rtthread_end:
+	.word  _end
+
+/*
+ * rtthread bss start and end which are defined in linker script
+ */
+.globl _bss_start
+_bss_start:	
+	.word __bss_start
+	
+.globl _bss_end
+_bss_end:
+	.word __bss_end
+
+/* IRQ stack memory (calculated at run-time) 						*/
+.globl IRQ_STACK_START
+IRQ_STACK_START:
+	.word _irq_stack_start + 1024
+	
+.globl FIQ_STACK_START
+FIQ_STACK_START:
+	.word _fiq_stack_start + 1024
+	
+.globl UNDEFINED_STACK_START
+UNDEFINED_STACK_START:
+	.word _undefined_stack_start + CONFIG_STACKSIZE
+	
+.globl ABORT_STACK_START
+ABORT_STACK_START:
+	.word _abort_stack_start + CONFIG_STACKSIZE
+	
+.globl _STACK_START
+_STACK_START:
+	.word _svc_stack_start + 4096
+
+/* ----------------------------------entry------------------------------*/
+reset:
+	
+	/* set the cpu to SVC32 mode 	*/
+	mrs		r0,cpsr
+	bic		r0,r0,#MODEMASK
+	orr		r0,r0,#SVCMODE
+	msr		cpsr,r0
+
+    @vector 0x0
+	@enable icaches
+	@little endian
+	@disable dcaches, mmu
+	//ldr r0, =0x00400078
+	@ldr r0, =0x0000107a
+   // mcr p15, 0, r0, c1, c0, 0
+
+   //read
+	ldr r0, =0x0
+	mrc p15, 0, r0, c1, c0, 0
+
+	//change
+	ldr r0, =0x00400078
+	mcr p15, 0, r0, c1, c0, 0
+	//check
+	ldr r0, =0x0
+	mrc p15, 0, r0, c1, c0, 0
+
+    ldr r0, =0x00000000
+    mcr p15, 0, r0, c8, c7, 0 	@ Flush TLB
+  	mcr p15, 0, r0, c7, c7, 0 	@ Flush Caches
+    mcr p15, 0, r0, c7, c10, 4 	@ Flush Write Buffer
+
+    /* mask all IRQs by clearing all bits in the INTMRs     set low and high to 0 */
+    ldr	r1, =FH81_INTC_BASE
+    ldr	r0, =0x0
+    str	r0, [r1]
+    str	r0, [r1, #4]
+
+
+	/* setup stack */
+	bl		stack_setup
+
+	/* clear .bss */
+	mov   	r0,#0                   /* get a zero 						*/
+	ldr   	r1,=__bss_start         /* bss start 						*/
+	ldr   	r2,=__bss_end           /* bss end 							*/
+	
+bss_loop:
+	cmp   	r1,r2                   /* check if data to clear 			*/
+	strlo 	r0,[r1],#4              /* clear 4 bytes 					*/
+	blo   	bss_loop                /* loop until done 					*/
+
+	/* call C++ constructors of global objects 							*/
+	ldr 	r0, =__ctors_start__
+	ldr 	r1, =__ctors_end__
+	
+ctor_loop:
+	cmp 	r0, r1
+	beq 	ctor_end
+	ldr 	r2, [r0], #4
+	stmfd 	sp!, {r0-r1}
+	mov 	lr, pc
+	bx 		r2
+	ldmfd 	sp!, {r0-r1}
+	b		ctor_loop
+	
+ctor_end:
+
+    /* enable_unaligned_access */
+    mrc p15, 0, r0, c1, c0, 0
+    bic r0, r0, #0x02        /*Clear the A bit, bit 1*/
+    and r0, r0, #(1 << 22)   /*Set the U bit, bit 22*/
+    mcr p15, 0, r0, c1, c0, 0
+
+#ifdef RT_USING_VFP
+    bl      vfp_init
+#endif
+
+	/* start RT-Thread Kernel 		*/
+	ldr		pc, _rtthread_startup
+
+_rtthread_startup: 
+	.word rtthread_startup
+
+.global cpu_reset
+cpu_reset:
+
+	#ldr	r0, =0xfffffd00
+	#ldr	r1, =(AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST)
+	#str	r1, [r0]
+	#mov	pc, lr
+	B cpu_reset
+
+/*
+ *************************************************************************
+ *
+ * Interrupt handling
+ *
+ *************************************************************************
+ */
+
+.macro push_exp_reg
+    sub     sp, sp, #S_FRAME_SIZE   @/* Sizeof(struct rt_hw_stack)  */
+    stmib   sp, {r0 - r12}          @/* Calling r0-r12                  */
+    mov     r0, sp
+    mrs     r6, spsr                @/* Save CPSR                       */
+    str     lr, [r0, #S_PC]         @/* Push PC                         */
+    str     r6, [r0, #S_CPSR]       @/* Push CPSR                       */
+    @ switch to SVC mode with no interrupt
+    msr     cpsr_c, #I_BIT|F_BIT|SVCMODE
+    str     sp, [r0, #S_SP]         @/* Save calling SP                 */
+    str     lr, [r0, #S_LR]         @/* Save calling PC                 */
+.endm
+
+#ifdef RT_USING_VFP
+__ret_to_undef:
+    ldmfd   sp!, {r4}       @ pop task's cpsr to spsr
+    msr     spsr_cxsf, r4
+    ldmfd   sp!, {r0-r12}
+    add     sp, sp, #4
+    ldmfd   sp!, {lr,pc}^
+#endif
+
+/* exception handlers    */
+    .align  5
+vector_undef:
+    push_exp_reg
+#ifdef RT_USING_VFP
+    cps     #UNDEFMODE
+    ldr     r2, [r0, #S_PC]     @ r2=faulted PC+4
+    adr     r9, __ret_to_undef  @ r9=exception success return
+    sub     r1, r2, #4
+    ldr     r0, [r1]            @ r0=faulted instruction
+    bl      undef_entry
+    mov     r0, sp
+#endif
+    bl     rt_hw_trap_udef
+
+    .align  5
+vector_swi:
+    push_exp_reg
+    bl     rt_hw_trap_swi
+
+    .align  5
+vector_pabt:
+    push_exp_reg
+    bl     rt_hw_trap_pabt
+
+    .align  5
+vector_dabt:
+    push_exp_reg
+    bl     rt_hw_trap_dabt
+
+    .align  5
+vector_resv:
+    push_exp_reg
+    bl     rt_hw_trap_resv
+
+.globl     rt_interrupt_enter
+.globl     rt_interrupt_leave
+.globl     rt_thread_switch_interrupt_flag
+.globl     rt_interrupt_from_thread
+.globl     rt_interrupt_to_thread
+vector_irq:
+    stmfd   sp!, {r0-r12,lr}
+@
+#ifdef RT_USING_VFP
+    vmrs    r0, fpexc
+    stmfd   sp!, {r0}            @ save VFP status -- irq_fpexc = fpexc
+    bic     r0, r0, #FPEXC_EN    @ always disable VFP so we can
+                                 @ lazily save/restore the old state.
+    vmsr    fpexc, r0
+#endif
+
+    bl      rt_interrupt_enter
+    bl      rt_hw_trap_irq
+    bl      rt_interrupt_leave
+
+#ifdef RT_USING_VFP
+    ldmfd   sp!, {r1}
+    vmrs    r0, fpexc
+    tst     r0, #FPEXC_EN        @ irq used VFP?
+    bicne   r1, r0, #FPEXC_EN    @ if irq used VFP, then clear fpexc.en bit
+    vmsr    fpexc, r1            @ restore VFP status
+                                 @ if irq not used VFP, then fpexc = irq_fpexc
+                                 @ if irq used VFP, then disable VFP
+#endif
+
+    @ if rt_thread_switch_interrupt_flag set, jump to
+    @ rt_hw_context_switch_interrupt_do and don't return
+    ldr     r0, =rt_thread_switch_interrupt_flag
+    ldr     r1, [r0]
+    cmp     r1, #1
+    beq     rt_hw_context_switch_interrupt_do
+
+    ldmfd   sp!, {r0-r12,lr}
+    @mrs r8,spsr
+    @msr cpsr, r8
+    subs    pc, lr, #4
+
+    .align  5
+vector_fiq:
+    stmfd   sp!,{r0-r7,lr}
+    bl      rt_hw_trap_fiq
+    ldmfd   sp!,{r0-r7,lr}
+    subs    pc,lr,#4
+
+rt_hw_context_switch_interrupt_do:
+    mov     r1,  #0         @ clear flag
+    str     r1,  [r0]
+
+    ldmfd   sp!, {r0-r12,lr}@ reload saved registers
+    stmfd   sp,  {r0-r2}    @ save r0-r2
+
+    mrs     r0,  spsr       @ get cpsr of interrupt thread
+
+    sub     r1,  sp, #4*3
+    sub     r2,  lr, #4     @ save old task's pc to r2
+
+    @ switch to SVC mode with no interrupt
+    msr     cpsr_c, #I_BIT|F_BIT|SVCMODE
+
+    stmfd   sp!, {r2}       @ push old task's pc
+    stmfd   sp!, {r3-r12,lr}@ push old task's lr,r12-r4
+    ldmfd   r1,  {r1-r3}    @ restore r0-r2 of the interrupt thread
+    stmfd   sp!, {r1-r3}    @ push old task's r0-r2
+    stmfd   sp!, {r0}       @ push old task's cpsr
+
+    ldr     r4,  =rt_interrupt_from_thread
+    ldr     r5,  [r4]
+    str     sp,  [r5]       @ store sp in preempted tasks's TCB
+
+    ldr     r6,  =rt_interrupt_to_thread
+    ldr     r6,  [r6]
+    ldr     sp,  [r6]       @ get new task's stack pointer
+
+    ldmfd   sp!, {r4}       @ pop new task's cpsr to spsr
+    msr     spsr_cxsf, r4
+
+#ifdef RT_USING_VFP
+    vmrs    r0, fpexc
+    bic     r0, r0, #FPEXC_EN    @ always disable VFP so we can
+                                 @ lazily save/restore the old state.
+    vmsr    fpexc, r0
+#endif
+
+    ldmfd   sp!, {r0-r12,lr,pc}^ @ pop new task's r0-r12,lr & pc, copy spsr to cpsr
+
+
+stack_setup:
+    mrs     r0, cpsr
+    bic     r0, r0, #MODEMASK
+    orr     r1, r0, #UNDEFMODE|NOINT
+    msr     cpsr_cxsf, r1           /* undef mode          */
+    ldr     sp, UNDEFINED_STACK_START
+
+    orr     r1,r0,#ABORTMODE|NOINT
+    msr     cpsr_cxsf,r1            /* abort mode          */
+    ldr     sp, ABORT_STACK_START
+
+    orr     r1,r0,#IRQMODE|NOINT
+    msr     cpsr_cxsf,r1            /* IRQ mode            */
+    ldr     sp, IRQ_STACK_START
+
+    orr     r1,r0,#FIQMODE|NOINT
+    msr     cpsr_cxsf,r1            /* FIQ mode            */
+    ldr     sp, FIQ_STACK_START
+
+    bic     r0,r0,#MODEMASK
+    orr     r1,r0,#SVCMODE|NOINT
+    msr     cpsr_cxsf,r1            /* SVC mode            */
+
+    ldr     sp, _STACK_START
+
+    /* USER mode is not initialized. */
+    bx      lr    /* The LR register may be not valid for the mode changes.*/
+
+/*/*}*/

+ 96 - 0
bsp/fh8620/link.ld

@@ -0,0 +1,96 @@
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+	. =0xA0000000;
+
+    . = ALIGN(4);
+    __text_start = .;
+    .text : 
+    {
+        *(.init)
+        *(.text)
+        *(.gnu.linkonce.t*)
+        
+        /* section information for finsh shell */
+        . = ALIGN(4);
+        __fsymtab_start = .;
+        KEEP(*(FSymTab))
+        __fsymtab_end = .;
+        . = ALIGN(4);
+        __vsymtab_start = .;
+        KEEP(*(VSymTab))
+        __vsymtab_end = .;
+        . = ALIGN(4);   
+
+        . = ALIGN(4);
+        __rt_init_start = .;
+        KEEP(*(SORT(.rti_fn*)))
+        __rt_init_end = .;
+        . = ALIGN(4);
+
+        /* section information for modules */
+        . = ALIGN(4);
+        __rtmsymtab_start = .;
+        KEEP(*(RTMSymTab))
+        __rtmsymtab_end = .;
+    }
+    __text_end = .;
+
+    . = ALIGN(4);
+    __rodata_start = .;
+    .rodata : { *(.rodata) *(.rodata.*) *(.gnu.linkonce.r*) *(.eh_frame) }
+    __rodata_end = .;
+
+    . = ALIGN(4);
+    .ctors :
+    {
+        PROVIDE(__ctors_start__ = .);
+        KEEP(*(SORT(.ctors.*)))
+        KEEP(*(.ctors))
+        PROVIDE(__ctors_end__ = .);
+    }
+
+    .dtors :
+    {
+        PROVIDE(__dtors_start__ = .);
+        KEEP(*(SORT(.dtors.*)))
+        KEEP(*(.dtors))
+        PROVIDE(__dtors_end__ = .);
+    }
+
+    . = ALIGN(4);
+    __data_start = .;
+    .data :
+    {
+        *(.data)
+        *(.data.*)
+        *(.gnu.linkonce.d*)
+    }
+    __data_end = .;
+
+    . = ALIGN(4);
+    .nobss : { *(.nobss) }
+
+    . = ALIGN(4);
+    __bss_start = .;
+    .bss : { *(.bss) }
+    __bss_end = .;
+
+    /* stabs debugging sections. */
+    .stab 0 : { *(.stab) }
+    .stabstr 0 : { *(.stabstr) }
+    .stab.excl 0 : { *(.stab.excl) }
+    .stab.exclstr 0 : { *(.stab.exclstr) }
+    .stab.index 0 : { *(.stab.index) }
+    .stab.indexstr 0 : { *(.stab.indexstr) }
+    .comment 0 : { *(.comment) }
+    .debug_abbrev 0 : { *(.debug_abbrev) }
+    .debug_info 0 : { *(.debug_info) }
+    .debug_line 0 : { *(.debug_line) }
+    .debug_pubnames 0 : { *(.debug_pubnames) }
+    .debug_aranges 0 : { *(.debug_aranges) }
+
+    _end = .;
+}

+ 15 - 0
bsp/fh8620/platform/SConscript

@@ -0,0 +1,15 @@
+# RT-Thread building script for bridge
+
+import os
+from building import *
+
+cwd = GetCurrentDir()
+objs = []
+list = os.listdir(cwd)
+
+for d in list:
+    path = os.path.join(cwd, d)
+    if os.path.isfile(os.path.join(path, 'SConscript')):
+        objs = objs + SConscript(os.path.join(d, 'SConscript'))
+
+Return('objs')

+ 33 - 0
bsp/fh8620/platform/board.h

@@ -0,0 +1,33 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef __BOARD_H__
+#define __BOARD_H__
+#include "platform_def.h"
+
+void rt_hw_board_init(void);
+
+#endif

+ 83 - 0
bsp/fh8620/platform/board_info.h

@@ -0,0 +1,83 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef __BOARD_INFO_H__
+#define __BOARD_INFO_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/****************************************************************************
+ * #include section
+ *	add #include here if any
+ ***************************************************************************/
+
+/****************************************************************************
+ * #define section
+ *	add constant #define here if any
+ ***************************************************************************/
+
+/****************************************************************************
+ * ADT section
+ *	add Abstract Data Type definition here
+ ***************************************************************************/
+
+typedef int (*probe_p)(void *);
+typedef int (*exit_p)(void *);
+
+struct fh_board_ops {
+	//void *ops_data;
+	probe_p probe;
+	probe_p exit;
+};
+
+struct fh_board_info {
+	char *name;
+	void *data;
+	struct fh_board_ops *ops;
+
+};
+
+/****************************************************************************
+ *  extern variable declaration section
+ ***************************************************************************/
+
+int fh_board_info_init(void);
+struct fh_board_info *fh_board_info_register(char *info_name, void *data);
+int fh_board_driver_register(char *info_name, struct fh_board_ops *ops);
+void fh_print_all_board_info(void);
+void fh_free_all_info(void);
+/****************************************************************************
+ *  section
+ *	add function prototype here if any
+ ***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 8 - 0
bsp/fh8620/platform/common/SConscript

@@ -0,0 +1,8 @@
+from building import *
+
+cwd = GetCurrentDir()
+src = Glob('*.c')
+
+group = DefineGroup('Platform', src, depend = [''])
+
+Return('group')

+ 250 - 0
bsp/fh8620/platform/common/board_info.c

@@ -0,0 +1,250 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+/*****************************************************************************
+ *  Include Section
+ *  add all #include here
+ *****************************************************************************/
+#include "board_info.h"
+#include <rtdevice.h>
+#include <string.h>
+/*****************************************************************************
+ * Define section
+ * add all #define here
+ *****************************************************************************/
+struct fh_board_info_list_node {
+	struct fh_board_info obj;
+	rt_list_t list;
+};
+
+#define CHECK_TEST_LIST_EMPTY		\
+		if(rt_list_isempty(&board_info_head.list)) \
+		rt_kprintf("board info is null...please register first..\n")
+
+/****************************************************************************
+ * ADT section
+ *  add definition of user defined Data Type that only be used in this file  here
+ ***************************************************************************/
+
+#define list_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = rt_list_entry((head)->next, typeof(*pos), member),	\
+		n = rt_list_entry(pos->member.next, typeof(*pos), member);	\
+	     &pos->member != (head); 					\
+	     pos = n, n = rt_list_entry(n->member.next, typeof(*n), member))
+
+#define PARA_ERROR			(-1)
+#define PROBE_FUNC_MISS		(-2)
+
+/******************************************************************************
+ * Function prototype section
+ * add prototypes for all functions called by this file,execepting those
+ * declared in header file
+ *****************************************************************************/
+
+//static void fh81_soc_free_all_test(void);
+//static void fh81_soc_print_all_test(void);
+//static void fh81_soc_auto_test_all(void);
+//static void fh81_soc_test_help(void);
+/*****************************************************************************
+ * Global variables section - Exported
+ * add declaration of global variables that will be exported here
+ * e.g.
+ *  int8_t foo;
+ ****************************************************************************/
+
+/*****************************************************************************
+
+ *  static fun;
+ *****************************************************************************/
+static struct fh_board_info_list_node board_info_head;
+
+
+
+/*****************************************************************************
+ * Global variables section - Local
+ * define global variables(will be refered only in this file) here,
+ * static keyword should be used to limit scope of local variable to this file
+ * e.g.
+ *  static uint8_t ufoo;
+ *****************************************************************************/
+
+
+ /* function body */
+/*****************************************************************************
+ * Description:
+ *      add funtion description here
+ * Parameters:
+ *      description for each argument, new argument starts at new line
+ * Return:
+ *      what does this function returned?
+ *****************************************************************************/
+
+int fh_board_info_init(void) {
+
+	memset(&board_info_head, 0x0, sizeof(struct fh_board_info_list_node));
+	rt_list_init(&board_info_head.list);
+	board_info_head.obj.name = "NO INFO";
+	return 0;
+}
+
+void fh_free_all_info(void) {
+	rt_list_t *p_list;
+	struct fh_board_info_list_node *info_node;
+	struct fh_board_info_list_node *_info_node;
+	p_list = &board_info_head.list;
+
+	CHECK_TEST_LIST_EMPTY;
+
+	list_for_each_entry_safe(info_node, _info_node, p_list, list)
+	{
+
+		if (info_node->obj.ops->exit) {
+			info_node->obj.ops->exit(info_node->obj.data);
+		}
+		rt_kprintf("soc free list name:(%s)\n", info_node->obj.name);
+		rt_free(info_node);
+	}
+	fh_board_info_init();
+}
+
+void fh_print_all_board_info(void) {
+	rt_list_t *p_list;
+
+	struct fh_board_info_list_node *info_node;
+	struct fh_board_info_list_node *_info_node;
+	p_list = &board_info_head.list;
+
+	CHECK_TEST_LIST_EMPTY;
+
+	list_for_each_entry_safe(info_node, _info_node, p_list, list)
+	{
+		rt_kprintf("%s\n", info_node->obj.name);
+	}
+}
+
+/*****************************************************************************
+ * Description:
+ *      add funtion description here
+ * Parameters:
+ *      description for each argument, new argument starts at new line
+ * Return:
+ *      what does this function returned?
+ *****************************************************************************/
+
+//register the platform info such as base add,isr no..
+//caution:do not free the name and data because of here not copy
+struct fh_board_info *fh_board_info_register(char *info_name, void *data) {
+	rt_list_t *p_list;
+	struct fh_board_info_list_node *new_node;
+	struct fh_board_info_list_node *info_node;
+	struct fh_board_info_list_node *_info_node;
+	p_list = &board_info_head.list;
+
+	if (RT_NULL == info_name || RT_NULL == data) {
+		rt_kprintf("info name or info data is NULL!\n");
+		return RT_NULL;
+	}
+
+	//check if the func is already in the test list....
+#if(0)
+	list_for_each_entry_safe(info_node, _info_node, p_list, list) {
+		if (!memcmp(info_node->obj.name, info_name, strlen(info_name))) {
+			rt_kprintf("info_name(%s) is already registered\n", info_name);
+			return RT_NULL;
+		}
+	}
+#endif
+
+	new_node = (struct fh_board_info_list_node *) rt_malloc(
+			sizeof(struct fh_board_info_list_node));
+	if (!new_node) {
+		rt_kprintf("malloc new_list_node failed~\n");
+		return RT_NULL;
+	}
+
+	new_node->obj.name = info_name;
+	new_node->obj.data = data;
+	//here insert "before" and test is "after" will make the list like a fifo...
+	rt_list_insert_before(&board_info_head.list, &new_node->list);
+	return &new_node->obj;
+}
+
+//back the platform info
+static void *fh_get_board_info_data(char *info_name) {
+
+	rt_list_t *p_list;
+	struct fh_board_info_list_node *info_node;
+	struct fh_board_info_list_node *_info_node;
+	p_list = &board_info_head.list;
+
+	//check info name
+	if (RT_NULL == info_name) {
+		rt_kprintf("info name is NULL!\n");
+		return RT_NULL;
+	}
+
+	CHECK_TEST_LIST_EMPTY;
+
+	list_for_each_entry_safe(info_node, _info_node, p_list, list)
+	{
+		if (!strcmp(info_node->obj.name, info_name)) {
+			return info_node->obj.data;
+		}
+	}
+
+	rt_kprintf("Can't find the board info name:%s\n", info_name);
+}
+
+int fh_board_driver_register(char *info_name, struct fh_board_ops *ops) {
+
+	rt_list_t *p_list;
+	struct fh_board_info_list_node *new_node;
+	struct fh_board_info_list_node *info_node;
+	struct fh_board_info_list_node *_info_node;
+	p_list = &board_info_head.list;
+
+	if (RT_NULL == info_name || RT_NULL == ops) {
+		rt_kprintf("info name or ops func is NULL!\n");
+		return PARA_ERROR;
+	}
+
+	list_for_each_entry_safe(info_node, _info_node, p_list, list)
+	{
+		if (!strcmp(info_node->obj.name, info_name)) {
+
+			info_node->obj.ops = ops;
+			if (info_node->obj.ops->probe) {
+				info_node->obj.ops->probe(info_node->obj.data);
+			}
+
+			//return info_node->obj.data;
+		}
+	}
+
+	//rt_kprintf("Can't find the board info name:%s\n",info_name);
+
+	return 0;
+}

+ 120 - 0
bsp/fh8620/platform/common/chkenv.c

@@ -0,0 +1,120 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+/*****************************************************************************
+ *  Include Section
+ *  add all #include here
+ *  those macro below should define....
+ *  or the dsp or isp lib will not be supported
+ *****************************************************************************/
+#include <rtconfig.h>
+
+//#pragma comment ( linker, "/EXPORT: MyExportFunction = _MyExportFunctio" )
+//#pragma message
+//#warning RT_NAME_MAX=32
+//#error ....
+
+//#define yu_error(macro) #error  ##macro
+
+
+/**************************
+ *
+ *
+ * define value below.
+ *
+ *
+ **************************/
+#if RT_NAME_MAX	!= 16
+#error "define RT_NAME_MAX 16"
+#endif
+
+#if RT_TICK_PER_SECOND	!= 100
+#warning "RT_TICK_PER_SECOND = 100"
+#endif
+
+
+#if RT_ALIGN_SIZE  != 4
+#error "define RT_ALIGN_SIZE 4"
+#endif
+
+/**************************
+ *
+ *
+ * should define below..
+ *
+ *
+ **************************/
+#ifndef RT_USING_SEMAPHORE
+#error need define "RT_USING_SEMAPHORE"
+#endif
+
+#ifndef RT_USING_MUTEX
+#error need define "RT_USING_MUTEX"
+#endif
+
+#ifndef RT_USING_EVENT
+#error need define "RT_USING_EVENT"
+#endif
+
+#ifndef RT_USING_MAILBOX
+#error need define "RT_USING_MAILBOX"
+#endif
+
+#ifndef RT_USING_MESSAGEQUEUE
+#warning need define "RT_USING_MESSAGEQUEUE"
+#endif
+
+#ifndef RT_USING_MEMPOOL
+#warning need define "RT_USING_MEMPOOL"
+#endif
+
+#ifndef RT_USING_HEAP
+#error need define "RT_USING_HEAP"
+#endif
+
+#ifndef RT_USING_MEMHEAP
+#warning need define "RT_USING_MEMHEAP"
+#endif
+
+#ifndef RT_USING_DEVICE
+#error need define "RT_USING_DEVICE"
+#endif
+
+#ifndef RT_USING_CONSOLE
+#error need define "RT_USING_CONSOLE"
+#endif
+
+#ifndef RT_USING_FINSH
+#error need define "RT_USING_FINSH"
+#endif
+
+#ifndef RT_USING_I2C
+#error need define "RT_USING_I2C"
+#endif
+
+
+
+

+ 15 - 0
bsp/fh8620/platform/fh8620/SConscript

@@ -0,0 +1,15 @@
+# RT-Thread building script for bridge
+
+import os
+from building import *
+
+cwd = GetCurrentDir()
+objs = []
+list = os.listdir(cwd)
+
+for d in list:
+    path = os.path.join(cwd, d)
+    if os.path.isfile(os.path.join(path, 'SConscript')):
+        objs = objs + SConscript(os.path.join(d, 'SConscript'))
+
+Return('objs')

+ 117 - 0
bsp/fh8620/platform/fh8620/arch.h

@@ -0,0 +1,117 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef ARCH_H_
+#define ARCH_H_
+
+
+/*****************************/
+/* BSP CONTROLLER BASE       */
+/*****************************/
+#define		INTC_REG_BASE		(0xE0200000)
+#define		SDC0_REG_BASE		(0xE2000000)
+#define		SDC1_REG_BASE		(0xE2100000)
+#define		TVE_REG_BASE		(0xE8000000)
+#define		VOU_REG_BASE		(0xE8100000)
+#define		AES_REG_BASE		(0xE8200000)
+#define		JPEG_REG_BASE		(0xE8300000)
+#define		ISPB_REG_BASE		(0xEA000000)
+#define		ISPF_REG_BASE		(0xEA100000)
+#define		VPU_REG_BASE		(0xEC000000)
+#define		VCU_REG_BASE		(0xEC100000)
+#define		DDRC_REG_BASE		(0xED000000)
+#define 	DMAC_REG_BASE		(0xEE000000)
+#define 	GMAC_REG_BASE		(0xEF000000)
+#define 	PMU_REG_BASE		(0xF0000000)
+#define 	I2C0_REG_BASE		(0xF0200000)
+#define 	GPIO0_REG_BASE		(0xF0300000)
+#define     GPIO1_REG_BASE      (0xf4000000)
+#define 	PWM_REG_BASE		(0xF0400000)
+#define 	SPI0_REG_BASE		(0xF0500000)
+#define 	SPI1_REG_BASE		(0xF0600000)
+#define		UART0_REG_BASE		(0xF0700000)
+#define		UART1_REG_BASE		(0xF0800000)
+#define		I2S_REG_BASE		(0xF0900000)
+#define		ACODEC_REG_BASE		(0xF0A00000)
+#define		I2C1_REG_BASE		(0xF0B00000)
+#define		TMR_REG_BASE		(0xF0C00000)
+#define		WDT_REG_BASE		(0xF0D00000)
+#define		DPHY_REG_BASE		(0xF1000000)
+#define		MIPIC_REG_BASE		(0xF1100000)
+#define		SADC_REG_BASE		(0xF1200000)
+
+
+
+
+
+typedef enum IRQn
+{
+  PAE_IRQn             =  0,
+  VPU_IRQn             =  1,
+  ISP_F_IRQn           =  2,
+  ISP_B_IRQn           =  3,
+  VOU_IRQn             =  4,
+  JPEG_IRQn            =  5,
+  TVE_IRQn             =  6,
+  TOE_IRQn             =  7,
+  DDRC_IRQn            =  8,
+  DMAC_IRQn            =  9,
+  AES_IRQn             = 10,
+  MIPIC_IRQn           = 11,
+  MIPI_WRAP_IRQn       = 12,
+  PMU_IRQn             = 13,
+  EMAC_IRQn            = 14,
+  AXIC0_IRQn           = 16,
+  AXIC1_IRQn           = 17,
+  X2H0_IRQn            = 18,
+  X2H1_IRQn            = 19,
+  AHBC0_IRQn           = 20,
+  AHBC1_IRQn           = 21,
+  SADC_IRQn            = 23,
+  SDC0_IRQn            = 24,
+  SDC1_IRQn            = 25,
+  ACW_IRQn             = 26,
+  WDT_IRQn             = 27,
+  SPI0_IRQn            = 28,
+  SPI1_IRQn            = 29,
+  UART0_IRQn           = 30,
+  UART1_IRQn           = 31,
+  I2S0_IRQn            = 32,
+  I2S1_IRQn            = 33,
+  RTC_IRQn             = 34,
+  PWM_IRQn             = 35,
+  TMR0_IRQn            = 36,
+  TMR1_IRQn            = 37,
+  USB0_IRQn            = 38,
+  USB1_IRQn            = 39,
+  GPIO0_IRQn           = 40,
+  GPIO1_IRQn           = 41,
+  I2C0_IRQn            = 42,
+  I2C1_IRQn            = 43,
+
+} IRQn_Type;
+
+#endif /* ARCH_H_ */

+ 9 - 0
bsp/fh8620/platform/fh8620/iot_cam/SConscript

@@ -0,0 +1,9 @@
+from building import *
+
+cwd = GetCurrentDir()
+src = Glob('*.c')
+path = [cwd, cwd + '/..']
+
+group = DefineGroup('Platform', src, depend = ['CONFIG_BOARD_IOTCAM', 'CONFIG_CHIP_FH8620'], CPPPATH = path)
+
+Return('group')

+ 692 - 0
bsp/fh8620/platform/fh8620/iot_cam/board.c

@@ -0,0 +1,692 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+/*****************************************************************************
+ *  Include Section
+ *  add all #include here
+ *****************************************************************************/
+#include <mmu.h>
+#include "fh_def.h"
+#include "arch.h"
+#include "board_info.h"
+#include "inc/fh_driverlib.h"
+#include "iomux.h"
+#include "fh_pmu.h"
+#include "spi_fh_adapt.h"
+
+#ifdef RT_USING_SADC
+#include "sadc.h"
+#endif
+
+#ifdef RT_USING_SPI
+#include "ssi.h"
+#include "fh_dma.h"
+#endif
+
+#ifdef RT_USING_ENC28J60
+#include "enc28j60.h"
+#include "gpio.h"
+#endif
+
+#ifndef HW_WIFI_POWER_GPIO
+    #define HW_WIFI_POWER_GPIO    47  // wifi power on
+#endif
+#ifndef HW_WIFI_POWER_GPIO_ON_LEVEL
+    #define HW_WIFI_POWER_GPIO_ON_LEVEL 0
+#endif
+
+#ifndef HW_CIS_RST_GPIO
+    #define HW_CIS_RST_GPIO       45  // cis(sensor) reset
+#endif
+#ifndef HW_CIS_RST_GPIO_LEVEL
+    #define HW_CIS_RST_GPIO_LEVEL 1
+#endif
+
+
+#ifndef HW_SDCARD_POWER_GPIO
+	#define HW_SDCARD_POWER_GPIO  63   //not used
+#endif
+/****************************************************************************
+ * ADT section
+ *  add definition of user defined Data Type that only be used in this file  here
+ ***************************************************************************/
+struct st_platform_info {
+	char *name;
+	void *private_data;
+};
+
+/******************************************************************************
+ * Function prototype section
+ * add prototypes for all functions called by this file,execepting those
+ * declared in header file
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Global variables section - Exported
+ * add declaration of global variables that will be exported here
+ * e.g.
+ *  int8_t foo;
+ ****************************************************************************/
+
+/*****************************************************************************
+ * Global variables section - Local
+ * define global variables(will be refered only in this file) here,
+ * static keyword should be used to limit scope of local variable to this file
+ * e.g.
+ *  static uint8_t ufoo;
+ *****************************************************************************/
+
+void fh_mmc_reset(struct fh_mmc_obj *mmc_obj)
+{
+	rt_uint32_t value;
+	if (mmc_obj->id)
+		fh_pmu_write(REG_PMU_SWRST_AHB_CTRL, 0xfffffffd);
+	else
+		fh_pmu_write(REG_PMU_SWRST_AHB_CTRL, 0xfffffffb);
+	do {
+		fh_pmu_read(REG_PMU_SWRST_AHB_CTRL, &value);
+	} while (value != 0xffffffff);
+}
+
+static struct fh_mmc_obj mmc0_obj =
+{
+    .id = 0,
+    .irq = SDC0_IRQn,
+    .base = SDC0_REG_BASE,
+    .power_pin_gpio = HW_SDCARD_POWER_GPIO,
+    .mmc_reset = fh_mmc_reset,
+};
+
+static struct fh_mmc_obj mmc1_obj =
+{
+    .id = 1,
+    .irq = SDC1_IRQn,
+    .base = SDC1_REG_BASE,
+    .power_pin_gpio = HW_WIFI_POWER_GPIO,
+    .mmc_reset = fh_mmc_reset,
+};
+
+#ifdef RT_USING_SPI
+#define SPI0_CLK_IN					(50000000)
+#define SPI0_MAX_BAUD				(SPI0_CLK_IN/2)
+
+static struct spi_control_platform_data spi0_platform_data =
+{
+    .id = 0,
+    .irq = SPI0_IRQn,
+    .base = SPI0_REG_BASE,
+    .max_hz = SPI0_MAX_BAUD,
+    .slave_no = FH_SPI_SLAVE_MAX_NO,
+    .clk_in = SPI0_CLK_IN,
+    .rx_hs_no = SPI0_RX,
+    .tx_hs_no = SPI0_TX,
+    .dma_name = "fh81_dma",
+    .transfer_mode = SPI0_TRANSFER_MODE,
+    .plat_slave[0].cs_pin = SPI_CRTOLLER0_SLAVE0_CS,
+    .plat_slave[0].actice_level = ACTIVE_LOW,
+    .plat_slave[1].cs_pin = SPI_CRTOLLER0_SLAVE1_CS,
+    .plat_slave[1].actice_level = ACTIVE_LOW,
+};
+
+
+#define SPI1_CLK_IN					(50000000)
+#define SPI1_MAX_BAUD				(SPI1_CLK_IN/2)
+
+static struct spi_control_platform_data spi1_platform_data =
+{
+    .id = 1,
+    .irq = SPI1_IRQn,
+    .base = SPI1_REG_BASE,
+    .max_hz = SPI1_MAX_BAUD,
+    .slave_no = FH_SPI_SLAVE_MAX_NO,
+    .clk_in = SPI1_CLK_IN,
+    .rx_hs_no = SPI1_RX,
+    .tx_hs_no = SPI1_TX,
+    .dma_name = "fh81_dma",
+    .transfer_mode = SPI1_TRANSFER_MODE,
+    .plat_slave[0].cs_pin = SPI_CRTOLLER1_SLAVE0_CS,
+    .plat_slave[0].actice_level = ACTIVE_LOW,
+    .plat_slave[1].cs_pin = SPI_CRTOLLER1_SLAVE1_CS,
+    .plat_slave[1].actice_level = ACTIVE_LOW,
+};
+#endif
+
+static struct fh_i2c_obj i2c0_obj =
+{
+    .id = 0,
+    .irq = I2C0_IRQn,
+    .base = I2C0_REG_BASE,
+};
+
+static struct fh_i2c_obj i2c1_obj =
+{
+    .id = 1,
+    .irq = I2C1_IRQn,
+    .base = I2C1_REG_BASE,
+};
+
+static struct fh_gpio_obj gpio0_obj =
+{
+    .id = 0,
+    .irq = GPIO0_IRQn,
+};
+
+static struct fh_gpio_obj gpio1_obj =
+{
+    .id = 1,
+    .irq = GPIO1_IRQn,
+};
+
+static struct fh_pwm_obj pwm_obj =
+{
+    .id = 0,
+    .base = PWM_REG_BASE,
+};
+
+static struct fh_wdt_obj wdt_obj =
+{
+    .id = 0,
+    .base = WDT_REG_BASE,
+    .irq = WDT_IRQn,
+};
+
+
+#ifdef RT_USING_SADC
+static struct wrap_sadc_obj sadc_obj =
+{
+		.id = 0,
+		.regs = (void *)SADC_REG_BASE,
+		.irq_no = SADC_IRQn,
+		.sample_mode = ISR_MODE,
+};
+#endif
+
+
+static struct mtd_partition fh_sf_parts[] = {
+    {
+        /* head & Ramboot */
+        .name       = "bootstrap",
+        .offset     = 0,
+        .size       = 0x4000,
+        .mask_flags = MTD_WRITEABLE, /* force read-only */
+    }, {
+        /* isp param */
+        .name       = "isp-param",
+        .offset     = 0x4000,
+        .size       = 0x4000,
+        .mask_flags = MTD_WRITEABLE, /* force read-only */
+    }, {
+        /* pae param */
+        .name       = "pae-param",
+        .offset     = 0x8000,
+        .size       = 0x8000,
+        .mask_flags = MTD_WRITEABLE, /* force read-only */
+    }, {
+        /* Uboot SPL */
+        .name       = "uboot-spl",
+        .offset     = 0x10000,
+        .size       = 0x10000,
+        .mask_flags = MTD_WRITEABLE, /* force read-only */
+    }, {
+        /* U-Boot environment */
+        .name       = "uboot-env",
+        .offset     = 0x20000,
+        .size       = 0x10000,
+        .mask_flags = MTD_WRITEABLE, /* force read-only */
+    }, {
+        /* U-Boot */
+        .name       = "uboot",
+        .offset     = 0x30000,
+        .size       = 0x30000,
+        .mask_flags = MTD_WRITEABLE, /* force read-only */
+    }, {
+        .name       = "kernel",
+        .offset     = 0x60000,
+        .size       = 0x400000,
+        .mask_flags = 0,
+    }, {
+        .name       = "rootfs",
+        .offset     = 0x460000,
+        .size       = 0x300000,
+        .mask_flags = 0,
+    }, {
+        .name       = "app",
+        .offset     = 0x760000,
+        .size       = 0x8a0000,
+        .mask_flags = 0,
+    }//mtdparts=spi0.0:64k(bootstrap),64k(u-boot-env),192k(u-boot),4M(kernel),8M(rootfs),-(app)
+    /* two blocks with bad block table (and mirror) at the end */
+};
+
+
+static struct flash_platform_data fh_flash_platform_data  =
+{
+    .flash_name = "fh_flash",
+    .spi_name   = "ssi0_0",
+    .parts      = fh_sf_parts,
+    .nr_parts   = ARRAY_SIZE(fh_sf_parts),
+};
+
+struct st_platform_info plat_mmc0 =
+{
+    .name = "mmc",
+    .private_data = &mmc0_obj,
+};
+
+
+struct st_platform_info plat_mmc1 =
+{
+    .name = "mmc",
+    .private_data = &mmc1_obj,
+};
+#ifdef RT_USING_SPI
+struct st_platform_info plat_spi0 =
+{
+    .name = "spi",
+    .private_data = &spi0_platform_data,
+};
+
+struct st_platform_info plat_spi1 =
+{
+    .name = "spi",
+    .private_data = &spi1_platform_data,
+};
+#endif
+
+struct st_platform_info plat_flash =
+{
+    .name = "fh_flash",
+    .private_data = &fh_flash_platform_data,
+};
+
+struct st_platform_info plat_i2c0 =
+{
+    .name = "i2c",
+    .private_data = &i2c0_obj,
+};
+
+struct st_platform_info plat_i2c1 =
+{
+    .name = "i2c",
+    .private_data = &i2c1_obj,
+};
+
+struct st_platform_info plat_gpio0 =
+{
+    .name = "gpio",
+    .private_data = &gpio0_obj,
+};
+
+struct st_platform_info plat_gpio1 =
+{
+    .name = "gpio",
+    .private_data = &gpio1_obj,
+};
+
+struct st_platform_info plat_pwm =
+{
+    .name = "pwm",
+    .private_data = &pwm_obj,
+};
+
+struct st_platform_info plat_wdt =
+{
+    .name = "wdt",
+    .private_data = &wdt_obj,
+};
+#ifdef RT_USING_SADC
+struct st_platform_info plat_sadc =
+{
+    .name = "sadc",
+    .private_data = &sadc_obj,
+};
+#endif
+
+const static struct st_platform_info *platform_info[] = {
+		&plat_mmc0,
+		//&plat_mmc1,//by PeterJiang, wifi don't use SDIO framework...
+#ifdef RT_USING_SPI
+        &plat_spi0,
+#endif
+#ifdef RT_USING_SPI1
+        &plat_spi1,
+#endif
+        &plat_flash,
+        &plat_i2c0,
+        &plat_i2c1,
+        &plat_gpio0,
+        &plat_gpio1,
+        &plat_pwm,
+        &plat_wdt,
+#ifdef RT_USING_SADC
+        &plat_sadc,
+#endif
+};
+
+
+ /* function body */
+
+/*****************************************************************************
+ * Description:
+ *      add funtion description here
+ * Parameters:
+ *      description for each argument, new argument starts at new line
+ * Return:
+ *      what does this function returned?
+ *****************************************************************************/
+
+ void clock_init(void)
+ {
+ 	//UINT32 reg;
+ 	//gate enable, spi0, gmac, uart0, timer0, wdt, pts
+#ifdef YG_TEK
+	fh_pmu_write_mask(REG_PMU_PAD_MAC_TXER_CFG, 0x100000, 0x100000);
+#endif
+ 	//SPI0
+	fh_pmu_write_mask(REG_PMU_CLK_DIV3, 0xb, 0xff);
+
+ 	//GMAC
+	fh_pmu_write_mask(REG_PMU_CLK_DIV6, 0x5000000, 0xf000000);
+
+ 	//UART0
+	fh_pmu_write_mask(REG_PMU_CLK_DIV4, 0x1, 0xf);
+
+ 	//TIMER0
+	fh_pmu_write_mask(REG_PMU_CLK_DIV5, 0x1d0000, 0x3f0000);
+
+ 	//PTS
+	fh_pmu_write_mask(REG_PMU_CLK_DIV2, 0x23, 0x3f);
+
+ 	//WDT
+	//fh_pmu_write_mask(REG_PMU_CLK_DIV5, 0x1d00, 0x3f00);
+	fh_pmu_write_mask(REG_PMU_CLK_DIV5, 0x3500, 0x3f00);
+
+ 	//clock enable
+	fh_pmu_write_mask(REG_PMU_CLK_GATE, 0, 0x720ba080);
+
+    //sd0_drv_sel
+	fh_pmu_write_mask(REG_PMU_CLK_SEL, 0x200000, 0x300000);
+    //sd0_sample_sel
+	fh_pmu_write_mask(REG_PMU_CLK_SEL, 0x00000, 0x30000);
+
+ 	//sd1_drv_sel
+	fh_pmu_write_mask(REG_PMU_CLK_SEL, 0x2000, 0x3000);
+ 	//sd1_sample_sel
+	fh_pmu_write_mask(REG_PMU_CLK_SEL, 0x000, 0x300);
+
+ }
+
+
+void fh_platform_info_register(void){
+	struct fh_board_info *test_info;
+	int i;
+
+	for(i=0;i<sizeof(platform_info)/sizeof(struct st_platform_info *);i++){
+		test_info = fh_board_info_register(platform_info[i]->name,platform_info[i]->private_data);
+		if(!test_info){
+			rt_kprintf("info_name(%s) failed registered\n", platform_info[i]->name);
+		}
+	}
+}
+
+void rt_hw_board_init()
+{
+	/* initialize the system clock */
+	rt_hw_clock_init();
+	//add iomux init 2015-3-11 by yu.zhang for fh81(fullhan)
+	//iomux_init();
+    fh_iomux_init(PMU_REG_BASE + 0x5c);
+	//add clk init  2015-3-11 by yu.zhang for fh81(fullhan)
+	clock_init();
+	/* initialize uart */
+	rt_hw_uart_init();
+	rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
+	/* initialize timer1 */
+	rt_hw_timer_init();
+	//board data info init...
+	fh_board_info_init();
+	fh_platform_info_register();
+
+}
+
+void rt_board_driver_init(){
+
+	//add board init lock here...
+	/*rt_show_version();*/
+	int ret;
+
+/* Filesystem Initialization */
+#ifdef RT_USING_DFS
+	{
+		/* init the device filesystem */
+		dfs_init();
+		rt_kprintf("DFS initialized!\n");
+#if defined(RT_USING_DFS_ELMFAT)
+		/* init the elm chan FatFs filesystam*/
+		elm_init();
+		rt_kprintf("ELM initialized!\n");
+#endif
+
+#if defined(RT_USING_DFS_ROMFS)
+		dfs_romfs_init();
+		if (dfs_mount(RT_NULL, "/rom", "rom", 0, &romfs_root) == 0)
+		{
+			rt_kprintf("ROM File System initialized!\n");
+		}
+		else
+			rt_kprintf("ROM File System initialzation failed!\n");
+#endif
+
+#if defined(RT_USING_DFS_DEVFS)
+		devfs_init();
+		if (dfs_mount(RT_NULL, "/dev", "devfs", 0, 0) == 0)
+			rt_kprintf("Device File System initialized!\n");
+		else
+			rt_kprintf("Device File System initialzation failed!\n");
+
+		#ifdef RT_USING_NEWLIB
+		/* init libc */
+		libc_system_init(RT_CONSOLE_DEVICE_NAME);
+		#endif
+#endif
+
+#if defined(RT_USING_DFS_UFFS)
+	{
+		/* init the uffs filesystem */
+		dfs_uffs_init();
+
+		/* mount flash device as flash directory */
+		if(dfs_mount("nand0", "/nand0", "uffs", 0, 0) == 0)
+			rt_kprintf("UFFS File System initialized!\n");
+		else
+			rt_kprintf("UFFS File System initialzation failed!\n");
+	}
+#endif
+
+
+#ifdef RT_USING_DFS_RAMFS
+	dfs_ramfs_init();
+	{
+		rt_uint8_t *ramfs_pool = RT_NULL;
+		struct dfs_ramfs* ramfs;
+		ramfs_pool = rt_malloc(0x800000);
+		if(ramfs_pool)
+		{
+			ramfs =(struct dfs_ramfs*) dfs_ramfs_create((rt_uint8_t*)ramfs_pool, 0x800000);
+			if (ramfs != RT_NULL)
+			{
+				if (dfs_mount(RT_NULL, "/", "ram", 0, ramfs) == 0)
+				{
+					rt_kprintf("Mount RAMDisk done!\n");
+				}
+				else
+				{
+					rt_kprintf("Mount RAMDisk failed.\n");
+				}
+			}
+		}
+		else
+		{
+			rt_kprintf("alloc ramfs poll failed\n");
+		}
+	}
+#endif
+	}
+#endif
+/* Filesystem Initialization end*/
+
+#ifdef RT_USING_GPIO
+    {
+        rt_hw_gpio_init();
+	rt_kprintf("GPIO initialized!\n");
+
+#ifdef RT_USING_SDIO
+        //wifi
+        gpio_request(HW_WIFI_POWER_GPIO);
+        gpio_direction_output(HW_WIFI_POWER_GPIO, !HW_WIFI_POWER_GPIO_ON_LEVEL);
+        udelay(1000);
+        gpio_direction_output(HW_WIFI_POWER_GPIO, HW_WIFI_POWER_GPIO_ON_LEVEL);
+        //micro sd
+        gpio_request(HW_SDCARD_POWER_GPIO);
+        gpio_direction_output(HW_SDCARD_POWER_GPIO, 0);
+	rt_kprintf("SDIO initialized!\n");
+#endif
+        //sensor
+        gpio_request(HW_CIS_RST_GPIO);
+        gpio_direction_output(HW_CIS_RST_GPIO, HW_CIS_RST_GPIO_LEVEL);
+
+
+    }
+#endif
+
+#ifdef RT_USING_SDIO
+#ifndef RT_USING_WIFI_MARVEL
+    rt_mmcsd_core_init();
+	rt_kprintf("MMC CORE initialized!\n");
+    rt_mmcsd_blk_init();
+	rt_kprintf("MMC BLK initialized!\n");
+    rt_hw_mmc_init();
+	rt_kprintf("MMC initialized!\n");
+    rt_thread_delay(RT_TICK_PER_SECOND*2);
+    /* mount sd card fat partition 1 as root directory */
+    #ifdef RT_USING_DFS_ELMFAT
+        if (dfs_mount("sd0", "/", "elm", 0, 0) == 0)
+        {
+            rt_kprintf("File System initialized!\n");
+        }
+        else
+            rt_kprintf("File System initialization failed!\n");
+    #endif
+#endif
+#endif
+
+
+#ifdef RT_USING_FH_DMA
+	{
+        rt_fh_dma_init();
+	rt_kprintf("DMA initialized!\n");
+	}
+#endif
+
+
+
+#ifdef RT_USING_FH_ACW
+	{
+		 fh_audio_init();
+			rt_kprintf("AUDIO initialized!\n");
+	}
+#endif
+
+#ifdef RT_USING_LWIP
+	{
+		/* init lwip system */
+		lwip_sys_init();
+		rt_kprintf("LWIP SYS initialized!\n");
+		eth_system_device_init();
+		rt_kprintf("ETH initialized!\n");
+	}
+#endif
+
+#ifdef RT_USING_GMAC
+        /* register ethernetif device */
+        rt_app_fh_gmac_init();
+	rt_kprintf("GMAC initialized!\n");
+#endif
+
+
+#ifdef RT_USING_I2C
+	{
+	    rt_hw_i2c_init();
+		rt_kprintf("I2C initialized!\n");
+	}
+#endif
+
+#ifdef RT_USING_PWM
+    {
+        rt_hw_pwm_init();
+	rt_kprintf("PWM initialized!\n");
+}
+#endif
+
+#ifdef RT_USING_WDT
+    {
+        rt_hw_wdt_init();
+	rt_kprintf("WDT initialized!\n");
+}
+#endif
+
+
+#ifdef RT_USING_SPI
+    {
+        rt_hw_spi_init();
+	rt_kprintf("SPI initialized!\n");
+    }
+#endif
+
+
+#ifdef RT_USING_FH_FLASH_ADAPT
+    fh_flash_adapt_init();
+    rt_kprintf("FLASH initialized!\n");
+#endif
+
+	rt_kprintf("init done\n");
+#ifdef RT_USING_SADC
+    rt_hw_sadc_init();
+	rt_kprintf("SADC initialized!\n");
+#endif
+
+#ifdef RT_USING_ENC28J60
+	gpio_request(ENC28J60_INT);
+	gpio_direction_input(ENC28J60_INT);
+	gpio_set_irq_type(ENC28J60_INT, IRQ_TYPE_EDGE_FALLING);
+	rt_hw_interrupt_install(gpio_to_irq(ENC28J60_INT), (void *)enc28j60_isr, RT_NULL, RT_NULL);
+	gpio_irq_enable(gpio_to_irq(ENC28J60_INT));
+	gpio_release(ENC28J60_INT);
+
+	enc28j60_attach(ENC28J60_SPI_DEV);
+#endif
+}
+

+ 106 - 0
bsp/fh8620/platform/fh8620/iot_cam/board_def.h

@@ -0,0 +1,106 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef BOARD_DEF_H_
+#define BOARD_DEF_H_
+
+
+/* ***********************
+ * SECTION:	DRIVE
+ * ***********************/
+// Basic drive..
+#define RT_USING_UART1
+#define RT_USING_GPIO
+#define RT_USING_SDIO
+#define RT_USING_FH_DMA
+#define RT_USING_FH_ACW
+#define RT_USING_I2C
+#define RT_USING_PWM
+#define RT_USING_WDT
+#define RT_USING_SPI
+#define RT_USING_SADC
+
+#define RT_USING_DSP
+#define RT_USING_ISP
+
+#define CONFIG_PLAT_V2
+
+#ifndef FH_DDR_START
+#define	FH_DDR_START		0xA0000000
+#define FH_DDR_END		0xA1000000
+
+#define FH_RTT_OS_MEM_SIZE	0x00600000
+#define FH_DMA_MEM_SIZE		0x20000 /* 128k */
+
+#define FH_RTT_OS_MEM_END	(FH_DDR_START + FH_RTT_OS_MEM_SIZE)
+#define FH_SDK_MEM_START	(FH_RTT_OS_MEM_END + FH_DMA_MEM_SIZE)
+#define FH_RTT_OS_HEAP_END	FH_SDK_MEM_START
+#define FH_SDK_MEM_SIZE		(FH_DDR_END - FH_SDK_MEM_START)
+#endif /* end of FH_DDR_START*/
+ 
+/* ***********************
+ * SECTION:	DRIVE COMPONENT
+ * ***********************/
+#define UART_NAME 						"uart1"
+#define RT_USING_DMA_MEM
+
+#define RT_USING_MCI0
+#define RT_USING_GD
+#define RT_USING_FLASH_DEFAULT
+#define RT_USING_FH_FLASH_ADAPT
+
+
+#ifndef _FH_AUTO_CONFIG_
+#define CHANNUM 2
+#define CHN0_Height 720
+#define CHN0_WIDTH 1280
+#define CHN0_Framerate 0x00010019
+#define CHN0_Bitrate (2048 *4)
+
+
+#define CHN1_Framerate 0x00010019
+#define CHN1_WIDTH 352
+#define CHN1_Height 288
+#define CHN1_Bitrate 512
+
+
+#define VPU_FRAME_CTRL 1
+#define CONFIG_IRCUT_OFF 1
+#define CONFIG_ISP_25FPS 1
+#define NOT_RECORD 1
+#define ENABLE_JPEG 1
+#define CONFIG_ISP_720P 1
+#define ENABLE_COOLVIEW 1
+#define ENABLE_OSD 1
+#define USE_RC 1
+#define OSD_CHN_FONT_USING 1
+#endif
+
+
+
+
+
+#endif /* BOARD_H_ */

+ 668 - 0
bsp/fh8620/platform/fh8620/iot_cam/iomux.c

@@ -0,0 +1,668 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#include "rtdef.h"
+#include "iomux.h"
+#include "rtconfig.h"
+
+
+Iomux_Pad fh_iomux_cfg[] = {
+		{
+			.func_name = { "RESETN", "", "", "", },
+			.reg_type  = 9,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_UP,
+			.drv_cur   = -1,
+		},
+		{
+			.func_name = { "TEST", "", "", "", },
+			.reg_type  = 9,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = -1,
+		},
+		{
+			.func_name = { "CIS_CLK", "", "", "", },
+			.reg_type  = 5,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_NONE,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "CIS_HSYNC", "GPIO20", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "CIS_VSYNC", "GPIO21", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "CIS_PCLK", "", "", "", },
+			.reg_type  = 9,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 0,
+		},
+		{
+			.func_name = { "CIS_D0", "GPIO22", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "CIS_D1", "GPIO23", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "CIS_D2", "GPIO24", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "CIS_D3", "GPIO25", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "CIS_D4", "GPIO26", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "CIS_D5", "GPIO27", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "CIS_D6", "GPIO28", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "CIS_D7", "GPIO29", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "CIS_D8", "GPIO30", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "CIS_D9", "GPIO31", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "CIS_D10", "GPIO32", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "CIS_D11", "GPIO33", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "MAC_REF_CLK", "", "", "", },
+			.reg_type  = 17,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_NONE,
+			.drv_cur   = 3,
+		},
+		{
+			.func_name = { "MAC_MDC", "GPIO34", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_NONE,
+			.drv_cur   = 0,
+		},
+		{
+			.func_name = { "MAC_MDIO", "", "", "", },
+			.reg_type  = 17,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "MAC_COL", "GPIO35", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "MAC_CRS", "GPIO36", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "MAC_RXCK", "", "", "", },
+			.reg_type  = 9,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = -1,
+		},
+		{
+			.func_name = { "MAC_RXD0", "", "", "", },
+			.reg_type  = 17,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = -1,
+		},
+
+		{
+			.func_name = { "MAC_RXD1", "GPIO38", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "MAC_RXD2", "GPIO39", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "MAC_RXD3", "GPIO40", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "MAC_RXDV", "GPIO41", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "MAC_TXCK", "", "", "", },
+			.reg_type  = 9,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = -1,
+		},
+		{
+			.func_name = { "MAC_TXD0", "GPIO42", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "MAC_TXD1", "GPIO43", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "MAC_TXD2", "GPIO44", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "MAC_TXD3", "GPIO45", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "MAC_TXEN", "GPIO46", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "MAC_RXER", "GPIO47", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "GPIO0", "ARC_JTAG_TCK", "GPIO0", "CIS_SSI0_CSN1", },
+			.reg_type  = 21,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_NONE,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "GPIO1", "ARC_JTAG_TRSTN", "GPIO1", "CIS_SSI0_RXD", },
+			.reg_type  = 21,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_NONE,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "GPIO2", "ARC_JTAG_TMS", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_NONE,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "GPIO3", "ARC_JTAG_TDI", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_NONE,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "GPIO4", "ARC_JTAG_TDO", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_NONE,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "JTAG_TCK", "GPIO5", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_NONE,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "JTAG_TRSTN", "GPIO6", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_NONE,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "JTAG_TMS", "GPIO7", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "JTAG_TDI", "GPIO8", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_NONE,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "JTAG_TDO", "GPIO9", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_NONE,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "GPIO10", "UART1_OUT", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_UP,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "GPIO11", "UART1_IN", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_UP,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "GPIO12", "PWM_OUT0", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_NONE,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "GPIO13", "PWM_OUT1", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_NONE,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "GPIO14", "PWM_OUT2", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_NONE,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "RESERVED", "", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+		},
+		{
+			.func_name = { "RESERVED", "", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+		},
+		{
+			.func_name = { "RESERVED", "", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+		},
+		{
+			.func_name = { "RESERVED", "", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+		},
+		{
+			.func_name = { "RESERVED", "", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+		},
+		{
+			.func_name = { "UART0_IN", "GPIO48", "UART0_IN", " I2S_WS", },
+			.reg_type  = 21,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_UP,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "UART0_OUT", "GPIO49", "UART0_OUT", "I2S_CLK", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "CIS_SCL", "GPIO56", "CIS_SCL", "CIS_SSI0_CLK", },
+			.reg_type  = 13,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_NONE,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "CIS_SDA", "GPIO57", "CIS_SDA", "CIS_SSI0_TXD", },
+			.reg_type  = 13,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_NONE,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "SCL1", "GPIO50", "SCL1", "I2S_DI", },
+			.reg_type  = 21,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_NONE,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "SDA1", "GPIO51", "I2S_DO", "", },
+			.reg_type  = 21,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_NONE,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "SSI0_CLK", "", "", "", },
+			.reg_type  = 5,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_NONE,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "SSI0_TXD", "", "", "", },
+			.reg_type  = 5,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_NONE,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "SSI0_CSN0", "GPIO54", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "SSI0_CSN1", "GPIO55", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "SSI0_RXD", "", "", "", },
+			.reg_type  = 17,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = -1,
+		},
+		{
+			.func_name = { "SD0_CD", "GPIO52", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "SD0_WP", "GPIO53", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "SD0_CLK", "", "", "", },
+			.reg_type  = 5,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_NONE,
+			.drv_cur   = 3,
+		},
+		{
+			.func_name = { "SD0_CMD_RSP", "", "", "", },
+			.reg_type  = 17,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_UP,
+			.drv_cur   = 3,
+		},
+		{
+			.func_name = { "SD0_DATA0", "", "", "", },
+			.reg_type  = 17,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_UP,
+			.drv_cur   = 3,
+		},
+		{
+			.func_name = { "SD0_DATA1", "", "", "", },
+			.reg_type  = 17,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_UP,
+			.drv_cur   = 2,
+		},
+		{
+			.func_name = { "SD0_DATA2", "", "", "", },
+			.reg_type  = 17,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_UP,
+			.drv_cur   = 3,
+		},
+		{
+			.func_name = { "SD0_DATA3", "", "", "", },
+			.reg_type  = 17,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_UP,
+			.drv_cur   = 3,
+		},
+		{
+			.func_name = { "SD1_CLK", "SSI1_CLK", "", "", },
+			.reg_type  = 8,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_NONE,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "SD1_CD", "GPIO_58", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "SD1_WP", "GPIO_59", "", "", },
+			.reg_type  = 20,
+	        .func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+		{
+			.func_name = { "SD1_DATA0", "SSI1_TXD", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_UP,
+			.drv_cur   = 3,
+		},
+		{
+			.func_name = { "SD1_DATA1", "SSI1_CSN0", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_UP,
+			.drv_cur   = 3,
+		},
+		{
+			.func_name = { "SD1_DATA2", "SSI1_CSN1", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_UP,
+			.drv_cur   = 3,
+		},
+		{
+			.func_name = { "SD1_DATA3", "", "", "", },
+			.reg_type  = 17,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_UP,
+			.drv_cur   = 3,
+		},
+		{
+			.func_name = { "SD1_CMD_RSP", "SSI1_RXD", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_UP,
+			.drv_cur   = 3,
+		},
+		{
+			.func_name = { "RESERVED", "", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+		},
+		{
+			.func_name = { "RESERVED", "", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+		},
+		{
+			.func_name = { "RESERVED", "", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+		},
+		{
+			.func_name = { "RESERVED", "", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+		},
+		{
+			.func_name = { "CLK_SW0", "", "", "", },
+			.reg_type  = 9,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_UP,
+			.drv_cur   = -1,
+		},
+		{
+			.func_name = { "CLK_SW1", "", "", "", },
+			.reg_type  = 9,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_UP,
+			.drv_cur   = -1,
+		},
+		{
+			.func_name = { "CLK_SW2", "", "", "", },
+			.reg_type  = 9,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_UP,
+			.drv_cur   = -1,
+		},
+		{
+			.func_name = { "CLK_SW3", "", "", "", },
+			.reg_type  = 9,
+			.func_sel  = 0,
+			.pupd 	   = IOMUX_PUPD_UP,
+			.drv_cur   = -1,
+		},
+		{
+			.func_name = { "RESERVED", "", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 0,
+		},
+		{
+			.func_name = { "MAC_TXER", "GPIO37", "", "", },
+			.reg_type  = 20,
+			.func_sel  = 1,
+			.pupd 	   = IOMUX_PUPD_DOWN,
+			.drv_cur   = 1,
+		},
+};
+
+
+const int fh_iomux_cfg_count = ARRAY_SIZE(fh_iomux_cfg);

+ 4 - 0
bsp/fh8620/platform/fh8620/iot_cam/readme

@@ -0,0 +1,4 @@
+IoT Camera
+powered by RT-Thread
+V1.0
+2016-3-14

+ 123 - 0
bsp/fh8620/platform/fh8620/iot_cam/startup.c

@@ -0,0 +1,123 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#include <rthw.h>
+#include <rtthread.h>
+#include <mmu.h>
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+#endif
+
+#ifdef RT_USING_DMA_MEM
+#include "dma_mem.h"
+#endif
+
+#include "board_def.h"
+
+extern void rt_hw_interrupt_init(void);
+extern void rt_hw_board_init(void);
+extern void rt_system_timer_init(void);
+extern void rt_system_scheduler_init(void);
+extern void rt_thread_idle_init(void);
+extern void mmu_invalidate_icache();
+extern void rt_hw_cpu_icache_enable(void);
+extern void rt_show_version(void);
+extern void rt_system_heap_init(void*, void*);
+extern void rt_hw_finsh_init(void);
+extern void rt_application_init(void);
+
+static struct mem_desc fh_mem_desc[] = 
+{
+		{ 0xA0000000, FH_RTT_OS_MEM_END-1, 0xA0000000, SECT_RWX_CB, 0, SECT_MAPPED },
+		{ FH_RTT_OS_MEM_END, FH_DDR_END-1, FH_RTT_OS_MEM_END, SECT_RWNX_NCNB, 0, SECT_MAPPED },
+		{ 0xFFFF0000, 0xFFFF1000-1, 0xA0000000, SECT_TO_PAGE, PAGE_ROX_CB, PAGE_MAPPED }, /* isr vector table */
+		{ 0xE0000000, 0xF1300000-1, 0xE0000000, SECT_RWNX_NCNB, 0, SECT_MAPPED },       /* io table */
+		{ 0xF4000000, 0xF4100000-1, 0xF4000000, SECT_RWNX_NCNB, 0, SECT_MAPPED },       /* GPIO#1 io table */
+};
+
+rt_uint8_t _irq_stack_start[1024];
+rt_uint8_t _fiq_stack_start[1024];
+rt_uint8_t _undefined_stack_start[512];
+rt_uint8_t _abort_stack_start[512];
+rt_uint8_t _svc_stack_start[4096] SECTION(".nobss");
+extern unsigned char __bss_start;
+extern unsigned char __bss_end;
+
+/**
+ * This function will startup RT-Thread RTOS.
+ */
+void rtthread_startup(void)
+{
+	/* disable interrupt first */
+	rt_hw_interrupt_disable();
+	/* initialize hardware interrupt */
+	rt_hw_interrupt_init();
+
+	/* initialize mmu */
+	rt_hw_mmu_init(fh_mem_desc, sizeof(fh_mem_desc)/sizeof(fh_mem_desc[0]));
+
+	rt_system_heap_init((void*)&__bss_end, (void*)FH_RTT_OS_MEM_END);
+
+#ifdef RT_USING_DMA_MEM
+	//just use the last 100KB
+	fh_dma_mem_init((rt_uint32_t *)FH_RTT_OS_MEM_END, FH_DMA_MEM_SIZE);
+#endif
+
+	/* initialize board */
+	rt_hw_board_init();
+
+	/* show version */
+	rt_show_version();
+
+	/* initialize tick */
+	rt_system_tick_init();
+
+	/* initialize kernel object */
+	rt_system_object_init();
+
+	/* initialize timer system */
+	rt_system_timer_init();
+
+	/* initialize scheduler system */
+	rt_system_scheduler_init();
+
+	/* initialize application */
+	rt_application_init();
+
+	/* initialize system timer thread */
+	rt_system_timer_thread_init();
+
+	/* initialize idle thread */
+	rt_thread_idle_init();
+
+	/* start scheduler */
+	rt_system_scheduler_start();
+
+	/* never reach here */
+
+	return ;
+}

+ 44 - 0
bsp/fh8620/platform/fh_arch.h

@@ -0,0 +1,44 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef FH_ARCH_H_
+#define FH_ARCH_H_
+
+
+#ifdef CONFIG_CHIP_FH8620
+#include "plat-v2/arch.h"
+#endif
+
+#ifdef CONFIG_CHIP_FH8620G
+#include "plat-v2/arch.h"
+#endif
+
+#ifdef CONFIG_CHIP_FH8810
+#include "plat-v2/arch.h"
+#endif
+
+
+#endif /* FH_ARCH_H_ */

+ 90 - 0
bsp/fh8620/platform/fh_def.h

@@ -0,0 +1,90 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef FH_DEF_H_
+#define FH_DEF_H_
+
+
+
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+
+typedef char				SINT8;
+typedef short				SINT16;
+typedef int					SINT32;
+typedef long long			SINT64;
+typedef unsigned char		UINT8;
+typedef unsigned short		UINT16;
+typedef unsigned int		UINT32;
+typedef unsigned long long	UINT64;
+
+#ifndef TYPE_DEFINED
+typedef	unsigned char		uchar;
+typedef signed   char		int8;
+typedef unsigned char		uint8;
+typedef signed   short		int16;
+typedef unsigned short		uint16;
+typedef signed   int		int32;
+typedef unsigned int		uint32;
+typedef signed   long  long	int64;
+typedef unsigned long long	uint64;
+typedef float        		ieee_single;
+typedef double       		ieee_double;
+
+typedef unsigned long  		boolean;
+
+#define TYPE_DEFINED
+
+#endif
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+#define reg_read(addr) (*((volatile UINT32 *)(addr)))
+#define reg_write(addr,value) (*(volatile UINT32 *)(addr)=(value))
+
+#define GET_REG(addr) reg_read(addr)
+#define SET_REG(addr,value) reg_write(addr,value)
+#define SET_REG_M(addr,value,mask) reg_write(addr,(reg_read(addr)&(~(mask)))|((value)&(mask)))
+#define SET_REG_B(addr,element,highbit,lowbit) SET_REG_M((addr),((element)<<(lowbit)),(((1<<((highbit)-(lowbit)+1))-1)<<(lowbit)))
+
+#define GET_REG8(addr) (*((volatile UINT8 *)(addr)))
+#define SET_REG8(addr,value) (*(volatile UINT8 *)(addr)=(value))
+
+#define read_reg(addr)  (*((volatile uint32 *)(addr)))
+#define write_reg(addr, reg)  (*((volatile uint32 *)(addr))) = (uint32)(reg)
+#define inw(addr)  (*((volatile uint32 *)(addr)))
+#define outw(addr, reg)  (*((volatile uint32 *)(addr))) = (uint32)(reg)
+#ifndef BIT
+#define BIT(nr)         (1UL << (nr))
+#endif
+
+typedef volatile const unsigned int RoReg; /**< Read only 32-bit register (volatile const unsigned int) */
+typedef volatile       unsigned int WoReg; /**< Write only 32-bit register (volatile unsigned int) */
+typedef volatile       unsigned int RwReg; /**< Read-Write 32-bit register (volatile unsigned int) */
+
+
+
+#endif /* FH_DEF_H_ */

+ 13 - 0
bsp/fh8620/platform/plat-v2/SConscript

@@ -0,0 +1,13 @@
+Import('RTT_ROOT')
+Import('rtconfig')
+from building import *
+
+cwd  = GetCurrentDir()
+
+src = Glob('*.c')
+
+path = [cwd, cwd + '/..']
+
+group = DefineGroup('Platform', src, depend = ['CONFIG_PLAT_V2'], CPPPATH = path)
+
+Return('group')

+ 116 - 0
bsp/fh8620/platform/plat-v2/arch.h

@@ -0,0 +1,116 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef ARCH_H_
+#define ARCH_H_
+
+/*****************************/
+/* BSP CONTROLLER BASE       */
+/*****************************/
+#define		INTC_REG_BASE		(0xE0200000)
+#define		SDC0_REG_BASE		(0xE2000000)
+#define		SDC1_REG_BASE		(0xE2100000)
+#define		TVE_REG_BASE		(0xE8000000)
+#define		VOU_REG_BASE		(0xE8100000)
+#define		AES_REG_BASE		(0xE8200000)
+/*
+#define		JPEG_REG_BASE		(0xE8300000)
+#define		ISPB_REG_BASE		(0xEA000000)
+#define		ISPF_REG_BASE		(0xEA100000)
+#define		VPU_REG_BASE		(0xEC000000)
+#define		VCU_REG_BASE		(0xEC100000)
+#define		DDRC_REG_BASE		(0xED000000)
+*/
+#define 	DMAC_REG_BASE		(0xEE000000)
+#define 	GMAC_REG_BASE		(0xEF000000)
+#define 	PMU_REG_BASE		(0xF0000000)
+#define 	I2C0_REG_BASE		(0xF0200000)
+#define 	GPIO0_REG_BASE		(0xF0300000)
+#define     GPIO1_REG_BASE      (0xf4000000)
+#define 	PWM_REG_BASE		(0xF0400000)
+#define 	SPI0_REG_BASE		(0xF0500000)
+#define 	SPI1_REG_BASE		(0xF0600000)
+#define		UART0_REG_BASE		(0xF0700000)
+#define		UART1_REG_BASE		(0xF0800000)
+/*#define		I2S_REG_BASE		(0xF0900000)*/
+#define		ACODEC_REG_BASE		(0xF0A00000)
+#define		I2C1_REG_BASE		(0xF0B00000)
+#define		TMR_REG_BASE		(0xF0C00000)
+#define		WDT_REG_BASE		(0xF0D00000)
+/*
+#define		DPHY_REG_BASE		(0xF1000000)
+#define		MIPIC_REG_BASE		(0xF1100000)
+*/
+#define		SADC_REG_BASE		(0xF1200000)
+
+typedef enum IRQn
+{
+  PAE_IRQn             =  0,
+  VPU_IRQn             =  1,
+  ISP_F_IRQn           =  2,
+  ISP_B_IRQn           =  3,
+  VOU_IRQn             =  4,
+  JPEG_IRQn            =  5,
+  TVE_IRQn             =  6,
+  TOE_IRQn             =  7,
+  DDRC_IRQn            =  8,
+  DMAC_IRQn            =  9,
+  AES_IRQn             = 10,
+  MIPIC_IRQn           = 11,
+  MIPI_WRAP_IRQn       = 12,
+  PMU_IRQn             = 13,
+  EMAC_IRQn            = 14,
+  AXIC0_IRQn           = 16,
+  AXIC1_IRQn           = 17,
+  X2H0_IRQn            = 18,
+  X2H1_IRQn            = 19,
+  AHBC0_IRQn           = 20,
+  AHBC1_IRQn           = 21,
+  SADC_IRQn            = 23,
+  SDC0_IRQn            = 24,
+  SDC1_IRQn            = 25,
+  ACW_IRQn             = 26,
+  WDT_IRQn             = 27,
+  SPI0_IRQn            = 28,
+  SPI1_IRQn            = 29,
+  UART0_IRQn           = 30,
+  UART1_IRQn           = 31,
+  I2S0_IRQn            = 32,
+  I2S1_IRQn            = 33,
+  RTC_IRQn             = 34,
+  PWM_IRQn             = 35,
+  TMR0_IRQn            = 36,
+  TMR1_IRQn            = 37,
+  USB0_IRQn            = 38,
+  USB1_IRQn            = 39,
+  GPIO0_IRQn           = 40,
+  GPIO1_IRQn           = 41,
+  I2C0_IRQn            = 42,
+  I2C1_IRQn            = 43,
+
+} IRQn_Type;
+
+#endif /* ARCH_H_ */

+ 2658 - 0
bsp/fh8620/platform/plat-v2/clock.c

@@ -0,0 +1,2658 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#include "clock.h"
+#include <rtdevice.h>
+#include "fh_arch.h"
+#include "Libraries/inc/fh_timer.h"
+#include "fh_pmu.h"
+//#include "chip_reg.h"
+//NEED_CAUTION.
+
+#define TIMER_CLOCK 1000000
+#define FH_CLK_DEBUG
+
+#define FH_CLK_DIV_DEFAULT
+//#define FH_CLK_GATE_DEFAULT
+
+//#define FH_DBG_CLK
+
+#define FH_CLK_DIV_DEFAULT_VALUE			0x55aaaa55
+#define FH_CLK_GATE_DEFAULT_VALUE			0xaa5555aa
+
+#define CONFIG_PAE_PTS_CLOCK   (1000000)
+#define TICKS_PER_USEC         (CONFIG_PAE_PTS_CLOCK / 1000000)
+#define REG_PAE_PTS_REG        (0xec100000 + 0x0040)
+
+
+
+#define fh_clk_err(p,fmt,args...)\
+		rt_kprintf("clk_err: %s->\t"fmt,p->name, ##args)
+
+#ifdef FH_CLK_DEBUG
+#define fh_clk_debug(p,fmt,args...)\
+		rt_kprintf("%s:\t\t"fmt,p->name, ##args)
+
+
+#define fh_clk_debug_no_handle(fmt,args...)\
+		rt_kprintf(fmt, ##args)
+#else
+//#define fh_clk_err(p,fmt,args...)
+#define fh_clk_debug(p,fmt,args...)
+#define fh_clk_debug_no_handle(fmt,args...)
+#endif
+
+struct fh_clk_tree;
+
+static struct fh_clk_tree fh_clk_tree;
+
+
+
+#define __raw_writel(v,a)       (*(volatile unsigned int   *)(a) = (v))
+#define __raw_readl(a)          (*(volatile unsigned int   *)(a))
+
+
+
+
+#define FH_TIMER_WRITEL(offset,value)		__raw_writel(value,(fh_clk_tree.c_base_addr + offset))
+#define FH_TIMER_READL(offset)				__raw_readl((fh_clk_tree.c_base_addr + offset))
+
+
+
+
+
+enum clk_gate_enum{
+#define CLK_GATE			(1)
+#define CLK_UNGATE			(0)
+	ISP_ACLK_GATE = (1<<0),
+	HCLK_GATE = (1<<1),
+	CPU_FCLK0_GATE = (1<<3),
+	VCU_CLK_GATE = (1<<4),
+	VOU_CLK_GATE = (1<<5),
+	MCLK_GATE = (1<<6),
+	SPI0_CLK_GATE = (1<<7),
+	SPI1_CLK_GATE = (1<<8),
+	SDC0_CLK_GATE = (1<<9),
+	SDC1_CLK_GATE = (1<<10),
+	AC_MCLK_GATE = (1<<11),  /////
+	I2C0_CLK_GATE = (1<<12),
+	UART0_CLK_GATE = (1<<13),
+	UART1_CLK_GATE = (1<<14),
+	//can't change
+	WDT_CLK_GATE = (1<<15),
+
+	PWM_CLK_GATE = (1<<16),
+	TMR0_CLK_GATE = (1<<17),
+	TMR1_CLK_GATE = (1<<18),
+	PTS_CLK_GATE = (1<<19),
+	MIPI_DPHY_CLK20M_GATE = (1<<20),
+	MIPI_P32_CLK_GATE = (1<<21),
+	PIX_CLK_GATE = (1<<22),			////
+	CIS_CLK_OUT_GATE = (1<<23),
+	I2S_SCLK_GATE = (1<<24),		//////
+	ETH_REF_CLK_GATE = (1<<25),
+	SADC_CLK_GATE = (1<<26),
+	I2C1_CLK_GATE = (1<<27),
+	ETH_RX_CLK_GATE = (1<<28), /////
+	ETH_TX_CLK_GATE = (1<<29), /////
+	ETH_RMII_CLK_GATE = (1<<30),////
+
+
+};
+
+
+
+//struct fh_clk;
+
+typedef void (*clk_update)(struct fh_clk* p_clk);
+
+//update func...
+void 	clk_in_update(struct fh_clk* p_clk);
+void 	pll1_clk_update(struct fh_clk* p_clk);
+void	pll0_clk_update(struct fh_clk* p_clk);
+void    cis_pclk_update(struct fh_clk* p_clk);
+void	ddr_clk_update(struct fh_clk* p_clk);
+void	ddr_clk_update(struct fh_clk* p_clk);
+void	fclk_update(struct fh_clk* p_clk);
+void	aclk_update(struct fh_clk* p_clk);
+void	hclk_update(struct fh_clk* p_clk);
+void	pclk_update(struct fh_clk* p_clk);
+void	isp_aclk_update(struct fh_clk* p_clk);
+void	vcu_clk_update(struct fh_clk* p_clk);
+void	vou_clk_update(struct fh_clk* p_clk);
+void	mipi_p32_clk_update(struct fh_clk* p_clk);
+void	cis_clk_out_update(struct fh_clk* p_clk);
+void	pts_update(struct fh_clk* p_clk);
+void 	mipi_pix_clk_update(struct fh_clk* p_clk);
+void	spi0_clk_update(struct fh_clk* p_clk);
+void	spi1_clk_update(struct fh_clk* p_clk);
+void	mipi_dphy_clk20m_update(struct fh_clk* p_clk);
+void	i2c0_clk_update(struct fh_clk* p_clk);
+void	i2c1_clk_update(struct fh_clk* p_clk);
+void	uart0_clk_update(struct fh_clk* p_clk);
+void	uart1_clk_update(struct fh_clk* p_clk);
+void	pwm_clk_update(struct fh_clk* p_clk);
+void	time0_clk_update(struct fh_clk* p_clk);
+void	time1_clk_update(struct fh_clk* p_clk);
+void	sadc_clk_update(struct fh_clk* p_clk);
+void	sdc0_clk2x_update(struct fh_clk* p_clk);
+void	sdc0_clk_update(struct fh_clk* p_clk);
+void	sdc0_clk_out_update(struct fh_clk* p_clk);
+void	sdc0_clk_sample_update(struct fh_clk* p_clk);
+void	sdc0_clk_drv_update(struct fh_clk* p_clk);
+void	sdc1_clk2x_update(struct fh_clk* p_clk);
+void	sdc1_clk_update(struct fh_clk* p_clk);
+void	sdc1_clk_out_update(struct fh_clk* p_clkt);
+void	sdc1_clk_sample_update(struct fh_clk* p_clk);
+void	sdc1_clk_drv_update(struct fh_clk* p_clk);
+void 	eth_ref_clk_update(struct fh_clk* p_clk);
+void	wdt_clk_update(struct fh_clk* p_clk);
+
+rt_int32_t check_pix_clk_source(rt_uint32_t offset,rt_uint32_t mask,rt_uint32_t *value);
+void	 pix_update(struct fh_clk* p_clk);
+
+struct fh_clk_div{
+//some has prediv....
+//this two could have or......
+#define PRE_DIV_CAL_ALREADY		(0x80000000)
+#define PRE_DIV_ENABLE		(0x01)
+#define DIV_ENABLE			(0x10)
+	rt_uint32_t div_flag;
+
+	rt_uint32_t pdiv_value;
+
+	//rt_uint32_t hw_div_value;
+	rt_uint32_t sw_div_value;
+	rt_uint32_t sw_div_multi;
+	//rt_uint32_t clk_in_hz;
+	rt_uint32_t reg_offset;
+	rt_uint32_t reg_mask;
+	//rt_uint32_t rate;
+};
+
+struct fh_clk_mux{
+//#define MUX_LEVEL_1		(1)
+//#define MUX_LEVEL_2		(2)
+//#define MAX_MUX_LEVEL	MUX_LEVEL_2
+//	rt_uint32_t lev;
+#define HAS_MUX				(0)
+#define HAS_NO_MUX			(1)
+	rt_uint32_t mux_flag;
+	rt_uint32_t hw_mux_value;
+	rt_uint32_t sw_mux_value;
+	rt_uint32_t reg_offset;
+	rt_uint32_t reg_mask;
+};
+
+struct fh_clk_gate{
+
+#define HAS_GATE			(0)
+#define HAS_NO_GATE			(1)
+	rt_uint32_t gate_flag;
+#define CLK_UNGATE			(0)
+#define CLK_GATE			(1)
+	//rt_uint32_t	hw_status;
+	rt_uint32_t	sw_status;
+	//rt_uint32_t value;
+
+	rt_uint32_t reg_offset;
+	rt_uint32_t reg_mask;
+
+};
+
+
+
+
+
+
+/***************
+ *
+ * level 1
+ *
+ ***************/
+struct fh_clk_level_1{
+	rt_uint32_t clk_in_out;
+};
+
+
+/***************
+ *
+ * level 2
+ *
+ ***************/
+struct fh_clk_level_2{
+	rt_uint32_t clk_in_out;
+};
+
+/***************
+ *
+ * level 3
+ *
+ ***************/
+struct fh_clk_level_3_ddr{
+	//rt_uint32_t mux_level;
+
+	struct fh_clk_mux mux[2];
+	struct fh_clk_gate gate;
+	struct fh_clk_div div;
+};
+
+struct fh_clk_level_3_sdc{
+#define DIFF_REFERENCE				(0x80000000)
+
+	rt_uint32_t phase_diff;
+	rt_uint32_t reg_offset;
+	rt_uint32_t reg_mask;
+
+};
+
+struct fh_clk_level_3_gmac{
+
+};
+
+struct fh_clk_level_3_normal{
+	struct fh_clk_mux mux;
+	struct fh_clk_gate gate;
+	struct fh_clk_div div;
+};
+
+
+struct fh_clk_level_3 {
+
+#define LEVEL_PERI_NORMAL		(0x301)
+#define LEVEL_PERI_DDR			(0x302)
+#define LEVEL_PERI_SDC			(0x303)
+#define LEVEL_PERI_GMAC			(0x304)
+	rt_uint32_t peri_flag;
+	union
+	{
+		struct fh_clk_level_3_ddr ddr;
+		struct fh_clk_level_3_sdc sdc;
+		struct fh_clk_level_3_gmac gmac;
+		struct fh_clk_level_3_normal normal;
+	}obj;
+
+};
+
+
+
+
+struct fh_clk {
+	char *name;
+#define LEVEL_CRYSTAL			(0x100)
+#define LEVEL_PLL				(0x200)
+#define LEVEL_PERIPHERAL		(0x300)
+	rt_uint32_t level;
+
+#define ROOT_NODE			(RT_NULL)
+	struct fh_clk *parent;
+
+	union
+	{
+		struct fh_clk_level_1 crystal;
+		struct fh_clk_level_2 pll;
+		struct fh_clk_level_3 peri;
+	}clk;
+
+	rt_uint32_t clk_out_rate;
+#define CLK_HAS_NO_GATE				(0x80000000)
+	rt_uint32_t gate;
+
+	clk_update update_func;
+
+	//struct fh_clk_tree *p_tree;
+};
+
+struct fh_clk_tree{
+	rt_uint32_t c_base_addr;
+	struct fh_clk **clk_head;
+};
+
+
+
+/*********
+ *
+ *
+ * clk map....
+ *
+ *
+ ********/
+#define CRYSTAL_HZ			(24000000)
+struct fh_clk clk_in = {
+	.name = "clk_in",
+	.level = LEVEL_CRYSTAL,
+	.parent = ROOT_NODE,
+	.clk.crystal.clk_in_out = CRYSTAL_HZ,
+	//.clk_out_rate = clk_in.clk.crystal.clk_in_out,
+	.clk_out_rate = CRYSTAL_HZ,
+	.update_func = clk_in_update,
+};
+
+
+
+#define CIS_PCLK_HZ			(108000000)
+struct fh_clk cis_pclk = {
+	.name = "cis_pclk",
+	.level = LEVEL_CRYSTAL,
+	.parent = ROOT_NODE,
+	.clk.crystal.clk_in_out = CIS_PCLK_HZ,
+	//.clk_out_rate = clk_in.clk.crystal.clk_in_out,
+	.clk_out_rate = CIS_PCLK_HZ,
+	.update_func = cis_pclk_update,
+};
+
+
+#define PLL0_HZ				(864000000)
+struct fh_clk pll0 = {
+	.name = "pll0",
+	.level = LEVEL_PLL,
+	.parent = &clk_in,
+	.clk.crystal.clk_in_out = PLL0_HZ,
+	//.clk_out_rate = pll0.clk.crystal.clk_in_out,
+	.clk_out_rate = PLL0_HZ,
+	.update_func = pll0_clk_update,
+};
+
+
+#define PLL1_HZ				(600000000)
+struct fh_clk pll1 = {
+	.name = "pll1",
+	.level = LEVEL_PLL,
+	.parent = &clk_in,
+	.clk.crystal.clk_in_out = PLL1_HZ,
+	.clk_out_rate  = PLL1_HZ,
+	.update_func = pll1_clk_update,
+
+};
+
+
+//NEED_CAUTION   parent not fix...
+static struct fh_clk ddr_clk_normal = {
+	.name = "ddr_normal",
+	.level = LEVEL_PERIPHERAL,
+	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_DDR,
+	//0:xtal_clk
+	//1:pll0_clk
+#define MUX0_XTAL_CLK				(0)
+#define MUX0_PLL0_CLK				(1)
+
+	.clk.peri.obj.ddr.mux[0].reg_offset = REG_PMU_SYS_CTRL,
+	.clk.peri.obj.ddr.mux[0].reg_mask = 1<<0,
+
+	//0:pll0 clk  default 864/2M
+	//1:pll1 clk  default 600M
+#define MUX1_PLL0_CLK				(0)
+#define MUX1_PLL1_CLK				(1)
+	.clk.peri.obj.ddr.mux[1].reg_offset = REG_PMU_CLK_SEL,
+	.clk.peri.obj.ddr.mux[1].reg_mask = 1<<24,
+
+	//gate
+	//.clk.peri.obj.ddr.gate.enable_status = CLK_ENABLE,
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.ddr.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.ddr.gate.sw_status = CLK_UNGATE,
+#endif
+	.clk.peri.obj.ddr.gate.gate_flag = HAS_GATE,
+	.clk.peri.obj.ddr.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.ddr.gate.reg_mask = MCLK_GATE,
+
+
+
+	//div
+	//clk in maybe cry or pll
+	.clk.peri.obj.ddr.div.div_flag = DIV_ENABLE,
+	//.clk.peri.obj.ddr.div.pdiv_value = 2,
+
+#ifdef FH_CLK_DIV_DEFAULT
+	.clk.peri.obj.ddr.div.sw_div_value = FH_CLK_DIV_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.ddr.div.sw_div_value = 1,
+#endif
+	.clk.peri.obj.ddr.div.sw_div_multi =1,
+	.clk.peri.obj.ddr.div.reg_offset = REG_PMU_CLK_DIV1,
+	.clk.peri.obj.ddr.div.reg_mask = 0xff <<0,
+
+	.update_func = ddr_clk_update,
+};
+
+
+
+
+
+
+
+
+//NEED_CAUTION   parent not fix...
+static struct fh_clk ddr_clk_div2 = {
+	.name = "ddr_div2",
+	.level = LEVEL_PERIPHERAL,
+	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_DDR,
+	//0:xtal_clk
+	//1:pll0_clk
+	.clk.peri.obj.ddr.mux[0].reg_offset = REG_PMU_SYS_CTRL,
+	.clk.peri.obj.ddr.mux[0].reg_mask = 1<<0,
+
+	//0:pll0 clk  default 864/2M
+	//1:pll1 clk  default 600M
+	.clk.peri.obj.ddr.mux[1].reg_offset = REG_PMU_CLK_SEL,
+	.clk.peri.obj.ddr.mux[1].reg_mask = 1<<24,
+
+	//gate
+	//.clk.peri.obj.ddr.gate.enable_status = CLK_ENABLE,
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.ddr.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.ddr.gate.sw_status = CLK_UNGATE,
+#endif
+	.clk.peri.obj.ddr.gate.gate_flag = HAS_GATE,
+	.clk.peri.obj.ddr.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.ddr.gate.reg_mask = MCLK_GATE,
+
+	//div
+	//clk in maybe cry or pll
+	.clk.peri.obj.ddr.div.div_flag = PRE_DIV_ENABLE | DIV_ENABLE,
+	.clk.peri.obj.ddr.div.pdiv_value = 2,
+#ifdef FH_CLK_DIV_DEFAULT
+	.clk.peri.obj.ddr.div.sw_div_value = FH_CLK_DIV_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.ddr.div.sw_div_value = 1,
+#endif
+	.clk.peri.obj.ddr.div.sw_div_multi =1,
+	.clk.peri.obj.ddr.div.reg_offset = REG_PMU_CLK_DIV1,
+	.clk.peri.obj.ddr.div.reg_mask = 0xff <<0,
+
+
+	.update_func = ddr_clk_update,
+};
+
+
+
+static struct fh_clk cpu_fclk = {
+	.name = "cpu_fclk",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+	//0:xtal_clk
+	//1:pll0_clk
+	.clk.peri.obj.normal.mux.reg_offset = REG_PMU_SYS_CTRL,
+	.clk.peri.obj.normal.mux.reg_mask = 1<<0,
+
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_NO_GATE,
+	//.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	//.clk.peri.obj.normal.gate.reg_mask = CPU_FCLK0_GATE,
+
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = DIV_ENABLE,
+
+#ifdef FH_CLK_DIV_DEFAULT
+	.clk.peri.obj.normal.div.sw_div_value = FH_CLK_DIV_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.div.sw_div_value = 0,
+#endif
+
+	.clk.peri.obj.normal.div.sw_div_multi =1,
+	.clk.peri.obj.normal.div.reg_offset =REG_PMU_CLK_DIV0,
+	.clk.peri.obj.normal.div.reg_mask = 0xff << 0,
+
+	.update_func = fclk_update,
+
+};
+
+
+//NEED_CAUTION   parent not fix...
+static struct fh_clk cpu_aclk = {
+	.name = "cpu_aclk",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+	//0:xtal_clk
+	//1:pll0_clk
+	.clk.peri.obj.normal.mux.mux_flag = HAS_NO_MUX,
+//	.clk.peri.obj.normal.mux.reg_offset = REG_PMU_SYS_CTRL,
+//	.clk.peri.obj.normal.mux.reg_mask = 1<<0,
+
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_GATE,
+
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.normal.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.gate.sw_status = CLK_UNGATE,
+#endif
+
+
+	.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.normal.gate.reg_mask = CPU_FCLK0_GATE,
+
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = PRE_DIV_ENABLE,
+	.clk.peri.obj.normal.div.pdiv_value = 2,
+//	.clk.peri.obj.normal.div.reg_offset =REG_PMU_CLK_DIV0,
+//	.clk.peri.obj.normal.div.reg_mask = 0xff << 0,
+
+	.update_func = aclk_update,
+
+};
+
+
+
+
+static struct fh_clk cpu_hclk = {
+	.name = "cpu_hclk",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+	//0:xtal_clk
+	//1:pll0_clk
+	.clk.peri.obj.normal.mux.reg_offset = REG_PMU_SYS_CTRL,
+	.clk.peri.obj.normal.mux.reg_mask = 1<<0,
+
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_NO_GATE,
+	//.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	//.clk.peri.obj.normal.gate.reg_mask = CPU_FCLK0_GATE,
+
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = DIV_ENABLE,
+
+#ifdef FH_CLK_DIV_DEFAULT
+	.clk.peri.obj.normal.div.sw_div_value = FH_CLK_DIV_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.div.sw_div_value = 1,
+#endif
+	.clk.peri.obj.normal.div.sw_div_multi =1,
+	.clk.peri.obj.normal.div.reg_offset =REG_PMU_CLK_DIV0,
+	.clk.peri.obj.normal.div.reg_mask = 0xff << 16,
+
+	.update_func = hclk_update,
+};
+//NEED_CAUTION   parent not fix...
+
+static struct fh_clk cpu_pclk = {
+	.name = "cpu_pclk",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+	//0:xtal_clk
+	//1:pll0_clk
+	.clk.peri.obj.normal.mux.mux_flag = HAS_NO_MUX,
+
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_GATE,
+
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.normal.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.gate.sw_status = CLK_UNGATE,
+#endif
+
+
+	.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.normal.gate.reg_mask = HCLK_GATE,
+
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = PRE_DIV_ENABLE,
+	.clk.peri.obj.normal.div.pdiv_value = 2,
+//	.clk.peri.obj.normal.div.reg_offset =REG_PMU_CLK_DIV0,
+//	.clk.peri.obj.normal.div.reg_mask = 0xff << 0,
+
+	.update_func = pclk_update,
+
+};
+
+
+//NEED_CAUTION   parent not fix...
+static struct fh_clk isp_aclk = {
+	.name = "isp_aclk",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+	//0:xtal_clk
+	//1:pll0_clk
+	.clk.peri.obj.normal.mux.reg_offset = REG_PMU_SYS_CTRL,
+	.clk.peri.obj.normal.mux.reg_mask = 1<<0,
+
+	//gate
+	.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.normal.gate.reg_mask = ISP_ACLK_GATE,
+	.clk.peri.obj.normal.gate.gate_flag = HAS_GATE,
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.normal.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.gate.sw_status = CLK_UNGATE,
+#endif
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = DIV_ENABLE,
+	.clk.peri.obj.normal.div.reg_offset = REG_PMU_CLK_DIV0,
+	.clk.peri.obj.normal.div.reg_mask = 0x03 << 8,
+	.clk.peri.obj.normal.div.sw_div_multi =1,
+
+
+#ifdef FH_CLK_DIV_DEFAULT
+	.clk.peri.obj.normal.div.sw_div_value = FH_CLK_DIV_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.div.sw_div_value = 1,
+#endif
+
+	.update_func = isp_aclk_update,
+
+};
+
+//
+////NEED_CAUTION   parent not fix...
+static struct fh_clk vcu_clk = {
+	.name = "vcu_clk",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+	//0:xtal_clk
+	//1:pll0_clk
+	.clk.peri.obj.normal.mux.reg_offset = REG_PMU_SYS_CTRL,
+	.clk.peri.obj.normal.mux.reg_mask = 1<<0,
+
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_GATE,
+	.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.normal.gate.reg_mask = VCU_CLK_GATE,
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.normal.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.gate.sw_status = CLK_UNGATE,
+#endif
+
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = DIV_ENABLE,
+	.clk.peri.obj.normal.div.reg_offset = REG_PMU_CLK_DIV0,
+	.clk.peri.obj.normal.div.reg_mask = 0x03 << 24,
+	.clk.peri.obj.normal.div.sw_div_multi =1,
+
+
+
+#ifdef FH_CLK_DIV_DEFAULT
+	.clk.peri.obj.normal.div.sw_div_value = FH_CLK_DIV_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.div.sw_div_value = 1,
+#endif
+
+
+	.update_func = vcu_clk_update,
+
+};
+
+static struct fh_clk vou_clk = {
+	.name = "vou_clk",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+	//0:xtal_clk
+	//1:pll0_clk
+	.clk.peri.obj.normal.mux.reg_offset = REG_PMU_SYS_CTRL,
+	.clk.peri.obj.normal.mux.reg_mask = 1<<0,
+
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_GATE,
+	.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.normal.gate.reg_mask = VOU_CLK_GATE,
+
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.normal.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.gate.sw_status = CLK_UNGATE,
+#endif
+
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = DIV_ENABLE,
+	.clk.peri.obj.normal.div.reg_offset = REG_PMU_CLK_DIV1,
+	.clk.peri.obj.normal.div.reg_mask = 0x3f << 8,
+	.clk.peri.obj.normal.div.sw_div_multi =1,
+
+
+#ifdef FH_CLK_DIV_DEFAULT
+	.clk.peri.obj.normal.div.sw_div_value = FH_CLK_DIV_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.div.sw_div_value = 1,
+#endif
+
+	.update_func = vou_clk_update,
+};
+
+
+
+static struct fh_clk mipi_p32_clk = {
+	.name = "mipi_p32_clk",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+	//0:xtal_clk
+	//1:pll0_clk
+	.clk.peri.obj.normal.mux.reg_offset = REG_PMU_SYS_CTRL,
+	.clk.peri.obj.normal.mux.reg_mask = 1<<0,
+
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_GATE,
+	.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.normal.gate.reg_mask = MIPI_P32_CLK_GATE,
+
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.normal.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.gate.sw_status = CLK_UNGATE,
+#endif
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = DIV_ENABLE,
+	.clk.peri.obj.normal.div.reg_offset = REG_PMU_CLK_DIV2,
+	.clk.peri.obj.normal.div.reg_mask = 0x0f << 16,
+	.clk.peri.obj.normal.div.sw_div_multi =1,
+
+
+#ifdef FH_CLK_DIV_DEFAULT
+	.clk.peri.obj.normal.div.sw_div_value = FH_CLK_DIV_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.div.sw_div_value = 1,
+#endif
+
+
+	.update_func = mipi_p32_clk_update,
+
+};
+
+
+
+static struct fh_clk cis_clk_out = {
+	.name = "cis_clk_out",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+	//0:xtal_clk
+	//1:pll0_clk
+	.clk.peri.obj.normal.mux.reg_offset = REG_PMU_SYS_CTRL,
+	.clk.peri.obj.normal.mux.reg_mask = 1<<0,
+
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_GATE,
+	.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.normal.gate.reg_mask = CIS_CLK_OUT_GATE,
+
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.normal.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.gate.sw_status = CLK_UNGATE,
+#endif
+
+
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = DIV_ENABLE,
+	.clk.peri.obj.normal.div.reg_offset = REG_PMU_CLK_DIV1,
+	.clk.peri.obj.normal.div.reg_mask = 0xff << 16,
+	.clk.peri.obj.normal.div.sw_div_multi =1,
+
+
+#ifdef FH_CLK_DIV_DEFAULT
+	.clk.peri.obj.normal.div.sw_div_value = FH_CLK_DIV_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.div.sw_div_value = 3,
+#endif
+
+	.update_func = cis_clk_out_update,
+
+};
+
+
+
+
+static struct fh_clk pts_clk = {
+	.name = "pts_clk",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+	//0:xtal_clk
+	//1:pll0_clk
+	.clk.peri.obj.normal.mux.reg_offset = REG_PMU_SYS_CTRL,
+	.clk.peri.obj.normal.mux.reg_mask = 1<<0,
+
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_GATE,
+	.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.normal.gate.reg_mask = PTS_CLK_GATE,
+
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.normal.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.gate.sw_status = CLK_UNGATE,
+#endif
+
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = DIV_ENABLE | PRE_DIV_ENABLE,
+	.clk.peri.obj.normal.div.reg_offset = REG_PMU_CLK_DIV2,
+	.clk.peri.obj.normal.div.reg_mask = 0xff << 0,
+	.clk.peri.obj.normal.div.sw_div_multi =1,
+#ifdef FH_CLK_DIV_DEFAULT
+	.clk.peri.obj.normal.div.sw_div_value = FH_CLK_DIV_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.div.sw_div_value = 35,
+#endif
+
+	.clk.peri.obj.normal.div.pdiv_value = 12,
+
+	.update_func = pts_update,
+
+};
+
+
+
+
+static struct fh_clk mipi_pix_clk = {
+	.name = "mipi_pix_clk_i",
+	.level = LEVEL_PERIPHERAL,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+	//0:xtal_clk
+	//1:pll0_clk
+	.clk.peri.obj.normal.mux.reg_offset = REG_PMU_SYS_CTRL,
+	.clk.peri.obj.normal.mux.reg_mask = 1<<0,
+
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_NO_GATE,
+
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = DIV_ENABLE,
+	.clk.peri.obj.normal.div.reg_offset = REG_PMU_CLK_DIV2,
+	.clk.peri.obj.normal.div.reg_mask = 0x0f << 24,
+	.clk.peri.obj.normal.div.sw_div_multi =1,
+#ifdef FH_CLK_DIV_DEFAULT
+	.clk.peri.obj.normal.div.sw_div_value = FH_CLK_DIV_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.div.sw_div_value = 3,
+#endif
+
+	.update_func = mipi_pix_clk_update,
+
+
+};
+
+
+
+static struct fh_clk pix_clk = {
+	.name = "pix_clk",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+	//0:xtal_clk
+	//1:pll0_clk
+#define CIS_PIX_CLK				(0)
+#define CIS_PIX_CLK_OPPOSITE	(1)
+#define MIPI_PIX_CLK			(2)
+
+	.clk.peri.obj.normal.mux.reg_offset = REG_PMU_CLK_SEL,
+	.clk.peri.obj.normal.mux.reg_mask = 3<<4,
+
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_GATE,
+	.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.normal.gate.reg_mask = PIX_CLK_GATE,
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.normal.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.gate.sw_status = CLK_UNGATE,
+#endif
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = 0,
+
+
+
+	.update_func = pix_update,
+
+};
+
+
+
+
+
+
+static struct fh_clk spi0_clk = {
+	.name = "spi0_clk",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+
+
+	.clk.peri.obj.normal.mux.mux_flag = HAS_NO_MUX,
+
+
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_GATE,
+	.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.normal.gate.reg_mask = SPI0_CLK_GATE,
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.normal.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.gate.sw_status = CLK_UNGATE,
+#endif
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = DIV_ENABLE,
+	.clk.peri.obj.normal.div.reg_offset = REG_PMU_CLK_DIV3,
+	.clk.peri.obj.normal.div.reg_mask = 0xff << 0,
+	.clk.peri.obj.normal.div.sw_div_multi =1,
+
+
+#ifdef FH_CLK_DIV_DEFAULT
+	.clk.peri.obj.normal.div.sw_div_value = FH_CLK_DIV_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.div.sw_div_value = 11,
+#endif
+
+	.update_func = spi0_clk_update,
+
+};
+
+
+
+
+static struct fh_clk spi1_clk = {
+	.name = "spi1_clk",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+
+	.clk.peri.obj.normal.mux.mux_flag = HAS_NO_MUX,
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_GATE,
+	.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.normal.gate.reg_mask = SPI1_CLK_GATE,
+
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.normal.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.gate.sw_status = CLK_UNGATE,
+#endif
+
+
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = DIV_ENABLE,
+	.clk.peri.obj.normal.div.reg_offset = REG_PMU_CLK_DIV3,
+	.clk.peri.obj.normal.div.reg_mask = 0xff << 16,
+	.clk.peri.obj.normal.div.sw_div_multi =1,
+
+
+
+#ifdef FH_CLK_DIV_DEFAULT
+	.clk.peri.obj.normal.div.sw_div_value = FH_CLK_DIV_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.div.sw_div_value = 11,
+#endif
+
+#ifdef RT_USING_SPI1
+	.clk.peri.obj.normal.div.sw_div_value = 11,
+#endif
+
+	.update_func = spi1_clk_update,
+
+};
+
+
+
+
+static struct fh_clk mipi_dphy_clk20m = {
+	.name = "mipi_dphy_clk20m",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+	.clk.peri.obj.normal.mux.mux_flag = HAS_NO_MUX,
+
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_GATE,
+	.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.normal.gate.reg_mask = MIPI_DPHY_CLK20M_GATE,
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.normal.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.gate.sw_status = CLK_UNGATE,
+#endif
+
+
+
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = PRE_DIV_ENABLE,
+//	.clk.peri.obj.normal.div.reg_offset = REG_PMU_CLK_DIV3,
+//	.clk.peri.obj.normal.div.reg_mask = 0xff << 16,
+	.clk.peri.obj.normal.div.sw_div_multi =1,
+	.clk.peri.obj.normal.div.pdiv_value = 30,
+//	.clk.peri.obj.normal.div.sw_div_value = 11,
+
+	.update_func = mipi_dphy_clk20m_update,
+};
+
+
+
+static struct fh_clk i2c0_clk = {
+	.name = "i2c0_clk",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+	.clk.peri.obj.normal.mux.mux_flag = HAS_NO_MUX,
+
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_GATE,
+	.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.normal.gate.reg_mask = I2C0_CLK_GATE,
+
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.normal.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.gate.sw_status = CLK_UNGATE,
+#endif
+
+
+
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = DIV_ENABLE | PRE_DIV_ENABLE,
+	.clk.peri.obj.normal.div.reg_offset = REG_PMU_CLK_DIV4,
+	.clk.peri.obj.normal.div.reg_mask = 0x3f << 16,
+	.clk.peri.obj.normal.div.sw_div_multi = 1,
+
+#ifdef FH_CLK_DIV_DEFAULT
+	.clk.peri.obj.normal.div.sw_div_value = FH_CLK_DIV_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.div.sw_div_value = 1,
+#endif
+
+	.clk.peri.obj.normal.div.pdiv_value = 20,
+
+	.update_func = i2c0_clk_update,
+
+};
+
+
+static struct fh_clk i2c1_clk = {
+	.name = "i2c1_clk",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+	.clk.peri.obj.normal.mux.mux_flag = HAS_NO_MUX,
+
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_GATE,
+	.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.normal.gate.reg_mask = I2C1_CLK_GATE,
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.normal.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.gate.sw_status = CLK_UNGATE,
+#endif
+
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = DIV_ENABLE | PRE_DIV_ENABLE,
+	.clk.peri.obj.normal.div.reg_offset = REG_PMU_CLK_DIV4,
+	.clk.peri.obj.normal.div.reg_mask = 0x3f << 24,
+	.clk.peri.obj.normal.div.sw_div_multi = 1,
+
+#ifdef FH_CLK_DIV_DEFAULT
+	.clk.peri.obj.normal.div.sw_div_value = FH_CLK_DIV_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.div.sw_div_value = 1,
+#endif
+	.clk.peri.obj.normal.div.pdiv_value = 20,
+
+
+	.update_func = i2c1_clk_update,
+};
+
+
+static struct fh_clk uart0_clk = {
+	.name = "uart0_clk",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+	.clk.peri.obj.normal.mux.mux_flag = HAS_NO_MUX,
+
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_GATE,
+	.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.normal.gate.reg_mask = UART0_CLK_GATE,
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.normal.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.gate.sw_status = CLK_UNGATE,
+#endif
+
+
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = DIV_ENABLE | PRE_DIV_ENABLE,
+	.clk.peri.obj.normal.div.reg_offset = REG_PMU_CLK_DIV4,
+	.clk.peri.obj.normal.div.reg_mask = 0x1f << 0,
+	.clk.peri.obj.normal.div.sw_div_multi = 1,
+
+#ifdef FH_CLK_DIV_DEFAULT
+	.clk.peri.obj.normal.div.sw_div_value = FH_CLK_DIV_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.div.sw_div_value = 1,
+#endif
+
+
+	.clk.peri.obj.normal.div.pdiv_value = 10,
+
+
+	.update_func = uart0_clk_update,
+
+};
+
+static struct fh_clk uart1_clk = {
+	.name = "uart1_clk",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+	.clk.peri.obj.normal.mux.mux_flag = HAS_NO_MUX,
+
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_GATE,
+	.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.normal.gate.reg_mask = UART1_CLK_GATE,
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.normal.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.gate.sw_status = CLK_UNGATE,
+#endif
+
+
+
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = DIV_ENABLE | PRE_DIV_ENABLE,
+	.clk.peri.obj.normal.div.reg_offset = REG_PMU_CLK_DIV4,
+	.clk.peri.obj.normal.div.reg_mask = 0x1f << 8,
+	.clk.peri.obj.normal.div.sw_div_multi = 1,
+
+#ifdef FH_CLK_DIV_DEFAULT
+	.clk.peri.obj.normal.div.sw_div_value = FH_CLK_DIV_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.div.sw_div_value = 1,
+#endif
+
+
+
+	.clk.peri.obj.normal.div.pdiv_value = 10,
+
+	.update_func = uart1_clk_update,
+
+};
+
+
+
+
+static struct fh_clk pwm_clk = {
+	.name = "pwm_clk",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+	.clk.peri.obj.normal.mux.mux_flag = HAS_NO_MUX,
+
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_GATE,
+	.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.normal.gate.reg_mask = PWM_CLK_GATE,
+
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.normal.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.gate.sw_status = CLK_UNGATE,
+#endif
+
+
+
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = DIV_ENABLE | PRE_DIV_ENABLE,
+	.clk.peri.obj.normal.div.reg_offset = REG_PMU_CLK_DIV5,
+	.clk.peri.obj.normal.div.reg_mask = 0x3f << 0,
+	.clk.peri.obj.normal.div.sw_div_multi = 1,
+
+#ifdef FH_CLK_DIV_DEFAULT
+	.clk.peri.obj.normal.div.sw_div_value = FH_CLK_DIV_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.div.sw_div_value = 29,
+#endif
+
+
+
+	.clk.peri.obj.normal.div.pdiv_value = 20,
+
+	.update_func = pwm_clk_update,
+};
+
+
+
+static struct fh_clk time0_clk = {
+	.name = "time0_clk",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+	.clk.peri.obj.normal.mux.mux_flag = HAS_NO_MUX,
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_GATE,
+	.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.normal.gate.reg_mask = TMR0_CLK_GATE,
+
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.normal.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.gate.sw_status = CLK_UNGATE,
+#endif
+
+
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = DIV_ENABLE | PRE_DIV_ENABLE,
+	.clk.peri.obj.normal.div.reg_offset = REG_PMU_CLK_DIV5,
+	.clk.peri.obj.normal.div.reg_mask = 0x3f << 16,
+	.clk.peri.obj.normal.div.sw_div_multi = 1,
+
+#ifdef FH_CLK_DIV_DEFAULT
+	.clk.peri.obj.normal.div.sw_div_value = FH_CLK_DIV_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.div.sw_div_value = 29,
+#endif
+
+
+
+	.clk.peri.obj.normal.div.pdiv_value = 20,
+
+
+	.update_func = time0_clk_update,
+
+};
+
+
+static struct fh_clk time1_clk = {
+	.name = "time1_clk",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+	.clk.peri.obj.normal.mux.mux_flag = HAS_NO_MUX,
+
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_GATE,
+	.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.normal.gate.reg_mask = TMR1_CLK_GATE,
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.normal.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.gate.sw_status = CLK_UNGATE,
+#endif
+
+
+
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = DIV_ENABLE | PRE_DIV_ENABLE,
+	.clk.peri.obj.normal.div.reg_offset = REG_PMU_CLK_DIV5,
+	.clk.peri.obj.normal.div.reg_mask = 0x3f << 24,
+	.clk.peri.obj.normal.div.sw_div_multi = 1,
+
+#ifdef FH_CLK_DIV_DEFAULT
+	.clk.peri.obj.normal.div.sw_div_value = FH_CLK_DIV_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.div.sw_div_value = 29,
+#endif
+
+
+	.clk.peri.obj.normal.div.pdiv_value = 20,
+
+	.update_func = time1_clk_update,
+
+};
+
+
+
+
+static struct fh_clk sadc_clk = {
+	.name = "sadc_clk",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+	.clk.peri.obj.normal.mux.mux_flag = HAS_NO_MUX,
+
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_GATE,
+	.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.normal.gate.reg_mask = SADC_CLK_GATE,
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.normal.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.gate.sw_status = CLK_UNGATE,
+#endif
+
+
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = PRE_DIV_ENABLE,
+	.clk.peri.obj.normal.div.sw_div_multi = 1,
+	.clk.peri.obj.normal.div.pdiv_value = 120,
+
+	.update_func = sadc_clk_update,
+
+};
+
+
+
+static struct fh_clk sdc0_clk2x = {
+	.name = "sdc0_clk2x",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+	.clk.peri.obj.normal.mux.mux_flag = HAS_NO_MUX,
+
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_GATE,
+
+	.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.normal.gate.reg_mask = SDC0_CLK_GATE,
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.normal.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.gate.sw_status = CLK_UNGATE,
+#endif
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = DIV_ENABLE | PRE_DIV_ENABLE,
+	.clk.peri.obj.normal.div.reg_offset = REG_PMU_CLK_DIV3,
+	.clk.peri.obj.normal.div.reg_mask = 0x0f << 8,
+	.clk.peri.obj.normal.div.sw_div_multi = 1,
+
+#ifdef FH_CLK_DIV_DEFAULT
+	.clk.peri.obj.normal.div.sw_div_value = FH_CLK_DIV_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.div.sw_div_value = 5,
+#endif
+
+
+	.clk.peri.obj.normal.div.pdiv_value = 2,
+
+	.update_func = sdc0_clk2x_update,
+
+};
+
+
+
+static struct fh_clk sdc0_clk = {
+	.name = "sdc0_clk",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_SDC,
+	.clk.peri.obj.sdc.phase_diff = DIFF_SDC_REFCLK_0 | DIFF_REFERENCE,
+//	.clk.peri.obj.sdc.reg_offset = REG_PMU_CLK_SEL,
+//	.clk.peri.obj.sdc.reg_mask = 0x0,
+
+	.update_func = sdc0_clk_update,
+
+};
+
+
+
+static struct fh_clk sdc0_clk_out = {
+	.name = "sdc0_clk_out",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_SDC,
+	.clk.peri.obj.sdc.phase_diff = DIFF_SDC_REFCLK_0,
+//	.clk.peri.obj.sdc.reg_offset = REG_PMU_CLK_SEL,
+//	.clk.peri.obj.sdc.reg_mask = 0x0,
+
+	.update_func = sdc0_clk_out_update,
+};
+
+
+
+static struct fh_clk sdc0_clk_sample = {
+	.name = "sdc0_clk_sample",
+	.level = LEVEL_PERIPHERAL,
+
+	.clk.peri.peri_flag = LEVEL_PERI_SDC,
+	.clk.peri.obj.sdc.phase_diff = DIFF_SDC_REFCLK_0,
+	.clk.peri.obj.sdc.reg_offset = REG_PMU_CLK_SEL,
+	.clk.peri.obj.sdc.reg_mask = 3<16,
+
+
+	.update_func = sdc0_clk_sample_update,
+};
+
+static struct fh_clk sdc0_clk_drive = {
+	.name = "sdc0_clk_drive",
+	.level = LEVEL_PERIPHERAL,
+
+	.clk.peri.peri_flag = LEVEL_PERI_SDC,
+	.clk.peri.obj.sdc.phase_diff = DIFF_SDC_REFCLK_0,
+	.clk.peri.obj.sdc.reg_offset = REG_PMU_CLK_SEL,
+	.clk.peri.obj.sdc.reg_mask = 3<20,
+
+
+	.update_func = sdc0_clk_drv_update,
+};
+
+
+
+
+static struct fh_clk sdc1_clk2x = {
+	.name = "sdc1_clk2x",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+	.clk.peri.obj.normal.mux.mux_flag = HAS_NO_MUX,
+
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_GATE,
+	.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.normal.gate.reg_mask = SDC1_CLK_GATE,
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.normal.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.gate.sw_status = CLK_UNGATE,
+#endif
+
+
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = DIV_ENABLE | PRE_DIV_ENABLE,
+	.clk.peri.obj.normal.div.reg_offset = REG_PMU_CLK_DIV3,
+	.clk.peri.obj.normal.div.reg_mask = 0x0f << 24,
+	.clk.peri.obj.normal.div.sw_div_multi = 1,
+#ifdef FH_CLK_DIV_DEFAULT
+	.clk.peri.obj.normal.div.sw_div_value = FH_CLK_DIV_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.div.sw_div_value = 5,
+#endif
+
+
+	.clk.peri.obj.normal.div.pdiv_value = 2,
+
+
+	.update_func = sdc1_clk2x_update,
+};
+
+
+
+static struct fh_clk sdc1_clk = {
+	.name = "sdc1_clk",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_SDC,
+	.clk.peri.obj.sdc.phase_diff = DIFF_SDC_REFCLK_0 | DIFF_REFERENCE,
+//	.clk.peri.obj.sdc.reg_offset = REG_PMU_CLK_SEL,
+//	.clk.peri.obj.sdc.reg_mask = 0x0,
+
+	.update_func = sdc1_clk_update,
+};
+
+
+
+static struct fh_clk sdc1_clk_out = {
+	.name = "sdc1_clk_out",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_SDC,
+	.clk.peri.obj.sdc.phase_diff = DIFF_SDC_REFCLK_0,
+//	.clk.peri.obj.sdc.reg_offset = REG_PMU_CLK_SEL,
+//	.clk.peri.obj.sdc.reg_mask = 0x0,
+
+	.update_func = sdc1_clk_out_update,
+};
+
+
+
+static struct fh_clk sdc1_clk_sample = {
+	.name = "sdc1_clk_sample",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_SDC,
+	.clk.peri.obj.sdc.phase_diff = DIFF_SDC_REFCLK_0,
+	.clk.peri.obj.sdc.reg_offset = REG_PMU_CLK_SEL,
+	.clk.peri.obj.sdc.reg_mask = 3<8,
+
+	.update_func = sdc1_clk_sample_update,
+};
+
+static struct fh_clk sdc1_clk_drive = {
+	.name = "sdc1_clk_drive",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_SDC,
+	.clk.peri.obj.sdc.phase_diff = DIFF_SDC_REFCLK_0,
+	.clk.peri.obj.sdc.reg_offset = REG_PMU_CLK_SEL,
+	.clk.peri.obj.sdc.reg_mask = 3<12,
+
+	.update_func = sdc1_clk_drv_update,
+};
+
+
+
+
+
+static struct fh_clk eth_ref_clk = {
+	.name = "eth_ref_clk",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+
+	.clk.peri.obj.normal.mux.mux_flag = HAS_NO_MUX,
+
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_GATE,
+	.clk.peri.obj.normal.gate.reg_offset = REG_PMU_CLK_GATE,
+	.clk.peri.obj.normal.gate.reg_mask = ETH_REF_CLK_GATE,
+
+
+#ifdef FH_CLK_GATE_DEFAULT
+	.clk.peri.obj.normal.gate.sw_status = FH_CLK_GATE_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.gate.sw_status = CLK_UNGATE,
+#endif
+
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = DIV_ENABLE | PRE_DIV_ENABLE,
+	.clk.peri.obj.normal.div.reg_offset = REG_PMU_CLK_DIV6,
+	.clk.peri.obj.normal.div.reg_mask = 0x0f << 24,
+	.clk.peri.obj.normal.div.sw_div_multi = 1,
+
+
+#ifdef FH_CLK_DIV_DEFAULT
+	.clk.peri.obj.normal.div.sw_div_value = FH_CLK_DIV_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.div.sw_div_value = 5,
+#endif
+
+
+
+
+	.clk.peri.obj.normal.div.pdiv_value = 2,
+
+
+	.update_func = eth_ref_clk_update,
+};
+
+
+
+
+static struct fh_clk wdt_clk = {
+	.name = "wdt_clk",
+	.level = LEVEL_PERIPHERAL,
+//	//.parent = &clk_in,
+	.clk.peri.peri_flag = LEVEL_PERI_NORMAL,
+	.clk.peri.obj.normal.mux.mux_flag = HAS_NO_MUX,
+
+	//gate
+	.clk.peri.obj.normal.gate.gate_flag = HAS_NO_GATE,
+
+
+	//div
+	.clk.peri.obj.normal.div.div_flag = DIV_ENABLE,
+	.clk.peri.obj.normal.div.reg_offset = REG_PMU_CLK_DIV5,
+	.clk.peri.obj.normal.div.reg_mask = 0x3f << 8,
+	.clk.peri.obj.normal.div.sw_div_multi = 1,
+
+
+
+#ifdef FH_CLK_DIV_DEFAULT
+	.clk.peri.obj.normal.div.sw_div_value = FH_CLK_DIV_DEFAULT_VALUE,
+#else
+	.clk.peri.obj.normal.div.sw_div_value = 29,
+#endif
+
+
+	.update_func = wdt_clk_update,
+};
+
+
+
+struct fh_clk *fh_clk_array[] = {
+		&clk_in,
+		&cis_pclk,
+		&pll0,
+		&pll1,
+		&ddr_clk_normal,
+		&ddr_clk_div2,
+		&cpu_fclk,
+		&cpu_aclk,
+		&cpu_hclk,
+		&cpu_pclk,
+		&isp_aclk,
+		&vcu_clk,
+		&vou_clk,
+		&mipi_p32_clk,
+		&cis_clk_out,
+		&pts_clk,
+		&mipi_pix_clk,
+		&pix_clk,
+
+		//pll1
+		&sdc0_clk2x,
+		&sdc0_clk,
+		&sdc0_clk_out,
+		&sdc0_clk_sample,
+		&sdc0_clk_drive,
+
+		&sdc1_clk2x,
+		&sdc1_clk,
+		&sdc1_clk_out,
+		&sdc1_clk_sample,
+		&sdc1_clk_drive,
+
+
+		&spi0_clk,
+		&spi1_clk,
+		&mipi_dphy_clk20m,
+		&i2c0_clk,
+		&i2c1_clk,
+		&uart0_clk,
+		&uart1_clk,
+		&pwm_clk,
+		&time0_clk,
+		&time1_clk,
+		&sadc_clk,
+		&eth_ref_clk,
+
+		&wdt_clk,
+
+
+};
+
+static inline rt_int32_t wrap_read_reg(rt_uint32_t offset, rt_uint32_t mask,
+		rt_uint32_t *value)
+{
+	rt_uint32_t temp_v, temp_shift;
+
+	/*	if(fh_pmu_status() == PMU_STATUS_CLOSE)
+	 return -1;*/
+	temp_v = FH_TIMER_READL(offset);
+	temp_v &= mask;
+	temp_shift = __rt_ffs(mask);
+	temp_v = temp_v >> (temp_shift - 1);
+	*value = temp_v;
+	return 0;
+}
+
+static inline rt_int32_t wrap_write_reg(rt_uint32_t offset, rt_uint32_t mask,
+		rt_uint32_t value)
+{
+	rt_uint32_t temp_v, temp_shift;
+
+	/*
+	 if(fh_pmu_status() == PMU_STATUS_CLOSE)
+	 return -1;
+	 */
+
+	temp_v = FH_TIMER_READL(offset);
+	temp_v &= ~mask;
+	temp_shift = __rt_ffs(mask);
+	temp_v |= value << (temp_shift - 1);
+	FH_TIMER_WRITEL(offset, temp_v);
+	return 0;
+}
+
+rt_int32_t check_pix_clk_source(rt_uint32_t offset, rt_uint32_t mask,
+		rt_uint32_t *value)
+{
+	rt_uint32_t mux0;
+	rt_int32_t ret;
+	ret = wrap_read_reg(offset, mask, &mux0);
+
+	if (ret != 0) {
+		return ret;
+	}
+
+	*value = mux0;
+	return 0;
+}
+
+rt_int32_t check_xtal_pll0(rt_uint32_t offset, rt_uint32_t mask,
+		rt_uint32_t *value)
+{
+	rt_uint32_t mux0;
+	rt_int32_t ret;
+	ret = wrap_read_reg(offset, mask, &mux0);
+
+	if (ret != 0) {
+		return ret;
+	}
+	if (mux0 == MUX0_PLL0_CLK)
+		*value = MUX0_PLL0_CLK;
+	else
+		*value = MUX0_XTAL_CLK;
+
+	return 0;
+}
+
+void cal_pll0_prediv(rt_uint32_t *div_flag, rt_uint32_t *pre_value)
+{
+
+	if (!(*div_flag & PRE_DIV_CAL_ALREADY)) {
+		//before has got the prediv value..
+		if (*div_flag & PRE_DIV_ENABLE) {
+
+			*pre_value *= 2;
+		} else {
+			*pre_value = 2;
+		}
+		*div_flag |= PRE_DIV_ENABLE | PRE_DIV_CAL_ALREADY;
+	}
+
+}
+
+rt_int32_t sw_div_process(rt_uint32_t div_flag, rt_uint32_t offset,
+		rt_uint32_t mask, rt_uint32_t *div_value)
+{
+
+	//rt_kprintf("----------div go----------\n");
+	rt_uint32_t div;
+	rt_int32_t ret;
+	if (div_flag & DIV_ENABLE) {
+		ret = wrap_read_reg(offset, mask, &div);
+		if (ret != 0) {
+			return ret;
+		}
+
+//
+//		rt_kprintf("hw value is %x\n",div);
+//		rt_kprintf("sw value is %x\n",div_value);
+//
+//		rt_kprintf("offset is %x,value :%x\n",offset + 0xf0000000,*(rt_uint32_t*)(offset + 0xf0000000));
+//		rt_kprintf("mask is %x\n",mask);
+
+		//if use the hw default value....
+
+		if (*div_value == FH_CLK_DIV_DEFAULT_VALUE) {
+			*div_value = div;
+			return 0;
+		}
+
+		if (div != *div_value) {
+			ret = wrap_write_reg(offset, mask, *div_value);
+			if (ret != 0) {
+				return ret;
+			}
+		}
+	}
+	//rt_kprintf("----------div done----------\n");
+	return 0;
+	//*div_flag |= PRE_DIV_ENABLE;
+}
+
+void cal_baud_hz(rt_uint32_t clk_in, rt_uint32_t div_flag, rt_uint32_t pre_div,
+		rt_uint32_t div, rt_uint32_t div_multi, rt_uint32_t *baud_out)
+{
+	//div += 1;
+	if (div_flag & PRE_DIV_ENABLE) {
+		*baud_out = (clk_in / pre_div);
+	} else {
+		*baud_out = clk_in;
+	}
+
+	if (div_flag & DIV_ENABLE) {
+		*baud_out /= ((div + 1) * div_multi);
+	}
+
+}
+
+void cal_baud_div(rt_uint32_t clk_in, rt_uint32_t div_flag, rt_uint32_t pre_div,
+		rt_uint32_t *div, rt_uint32_t div_multi, rt_uint32_t baud_out)
+{
+	//div += 1;
+	rt_uint32_t temp_baud_hz, temp_baud_div;
+
+	if (div_flag & DIV_ENABLE) {
+		if (div_flag & PRE_DIV_ENABLE) {
+			temp_baud_hz = (clk_in / pre_div);
+		} else {
+			temp_baud_hz = clk_in;
+		}
+		temp_baud_div = temp_baud_hz / baud_out;
+		*div = temp_baud_div - 1;
+	}
+
+}
+
+rt_int32_t process_gate(rt_uint32_t gate_flag, rt_uint32_t reg_offset,
+		rt_uint32_t reg_mask, rt_uint32_t *sw_status,
+		rt_uint32_t *pclk_status)
+{
+	//rt_kprintf("----------gate go----------\n");
+	rt_uint32_t hw_gate;
+	rt_int32_t ret;
+	if (gate_flag == HAS_GATE) {
+		ret = wrap_read_reg(reg_offset, reg_mask, &hw_gate);
+		if (ret != 0) {
+			return ret;
+		}
+
+		if (*sw_status == FH_CLK_GATE_DEFAULT_VALUE) {
+			*sw_status = hw_gate;
+			*pclk_status = *sw_status;
+			return 0;
+		}
+
+//		rt_kprintf("gate hw is :%x\n",hw_gate);
+//		rt_kprintf("gate sw is :%x\n",sw_status);
+		if (hw_gate != *sw_status) {
+			//update the gate..
+//			rt_kprintf("gate reg offset is :%x\n",reg_offset);
+//			rt_kprintf("gate reg mask is :%x\n",reg_mask);
+//			rt_kprintf("gate reg write is :%x\n",sw_status);
+			ret = wrap_write_reg(reg_offset, reg_mask, *sw_status);
+			if (ret != 0) {
+				return ret;
+			}
+		}
+
+		*pclk_status = *sw_status;
+	}
+
+	else {
+		*pclk_status |= CLK_HAS_NO_GATE;
+	}
+	//rt_kprintf("---------gate done---------\n");
+	return 0;
+
+}
+
+void clk_handle(struct fh_clk* p_clk, struct fh_clk *parent)
+{
+	//rt_uint32_t div;
+	//rt_uint32_t sw_gate;
+	rt_uint32_t phase;
+	rt_int32_t ret;
+	p_clk->parent = parent;
+//	switch
+	//fh_clk_debug(p_clk,"----parent----\t ----clk out rate----\n ");
+	if (p_clk->parent)
+		//rt_kprintf("%-8.*s 0x%02x", RT_NAME_MAX, thread->name, thread->current_priority);
+		fh_clk_debug(p_clk, "parent:'%s'\n", p_clk->parent->name);
+	else
+		fh_clk_debug(p_clk, "'root node'\n");
+
+	switch (p_clk->level) {
+
+	case LEVEL_CRYSTAL:
+		//fh_clk_debug(p_clk,"clk out:%d\n",p_clk->clk_out_rate);
+		break;
+	case LEVEL_PLL:
+		//fh_clk_debug(p_clk,"%d\n",p_clk->clk_out_rate);
+		break;
+	case LEVEL_PERIPHERAL:
+
+		switch (p_clk->clk.peri.peri_flag) {
+
+		case LEVEL_PERI_NORMAL:
+			//div = p_clk->clk.peri.obj.normal.div.sw_div_value;
+			ret =
+					sw_div_process(
+							p_clk->clk.peri.obj.normal.div.div_flag,
+							p_clk->clk.peri.obj.normal.div.reg_offset,
+							p_clk->clk.peri.obj.normal.div.reg_mask,
+							&p_clk->clk.peri.obj.normal.div.sw_div_value);
+
+			if (ret != 0) {
+				fh_clk_err(p_clk,
+						"div process failed.error no:%x\n",
+						ret);
+				break;
+			}
+
+			//fh_clk_debug(p_clk,"hw div is %d\n",p_clk->clk.peri.obj.ddr.div.hw_div_value);
+//			fh_clk_debug(p_clk,"sw div is %d\n",p_clk->clk.peri.obj.normal.div.sw_div_value);
+//			fh_clk_debug(p_clk,"pre div is %d\n",p_clk->clk.peri.obj.normal.div.pdiv_value);
+//			fh_clk_debug(p_clk,"clk in is %d\n",p_clk->parent->clk_out_rate);
+//			fh_clk_debug(p_clk,"peri flag is %x\n",p_clk->clk.peri.obj.normal.div.div_flag);
+			//hw will self add 1..
+
+			cal_baud_hz(p_clk->parent->clk_out_rate,
+					p_clk->clk.peri.obj.normal.div.div_flag,
+					p_clk->clk.peri.obj.normal.div.pdiv_value,
+					p_clk->clk.peri.obj.normal.div.sw_div_value,
+					p_clk->clk.peri.obj.normal.div.sw_div_multi,
+					&p_clk->clk_out_rate);
+
+			//fh_clk_debug_no_handle("%d\n",p_clk->clk_out_rate);
+			//fix the gate..
+			//sw_gate = p_clk->clk.peri.obj.normal.gate.sw_status;
+			ret =
+					process_gate(
+							p_clk->clk.peri.obj.normal.gate.gate_flag,
+							p_clk->clk.peri.obj.normal.gate.reg_offset,
+							p_clk->clk.peri.obj.normal.gate.reg_mask,
+							&p_clk->clk.peri.obj.normal.gate.sw_status,
+							&p_clk->gate);
+
+			if (ret != 0) {
+				fh_clk_err(p_clk,
+						"gate process failed.error no:%x\n",
+						ret);
+				break;
+			}
+
+			break;
+		case LEVEL_PERI_DDR:
+			//rt_uint32_t mux0,mux1;
+			//div = p_clk->clk.peri.obj.ddr.div.sw_div_value;
+
+			ret =
+					sw_div_process(
+							p_clk->clk.peri.obj.ddr.div.div_flag,
+							p_clk->clk.peri.obj.ddr.div.reg_offset,
+							p_clk->clk.peri.obj.ddr.div.reg_mask,
+							&p_clk->clk.peri.obj.ddr.div.sw_div_value);
+
+			if (ret != 0) {
+				fh_clk_err(p_clk,
+						"div process failed.error no:%x\n",
+						ret);
+				break;
+			}
+
+//			fh_clk_debug(p_clk,"sw div is %d\n",p_clk->clk.peri.obj.ddr.div.sw_div_value);
+//			fh_clk_debug(p_clk,"pre div is %d\n",p_clk->clk.peri.obj.ddr.div.pdiv_value);
+//			fh_clk_debug(p_clk,"clk in is %d\n",p_clk->parent->clk_out_rate);
+//			fh_clk_debug(p_clk,"peri flag is %x\n",p_clk->clk.peri.obj.ddr.div.div_flag);
+
+			cal_baud_hz(p_clk->parent->clk_out_rate,
+					p_clk->clk.peri.obj.ddr.div.div_flag,
+					p_clk->clk.peri.obj.ddr.div.pdiv_value,
+					p_clk->clk.peri.obj.ddr.div.sw_div_value,
+					p_clk->clk.peri.obj.ddr.div.sw_div_multi,
+					&p_clk->clk_out_rate);
+
+			//fh_clk_debug_no_handle("%d\n",p_clk->clk_out_rate);
+			//fix the gate..
+			//fh_clk_debug(p_clk,"gate reg add is:%x\t mask is:%x\n",p_clk->clk.peri.obj.ddr.gate.reg_offset,p_clk->clk.peri.obj.ddr.gate.reg_mask);
+			//sw_gate = p_clk->clk.peri.obj.ddr.gate.sw_status;
+
+			ret = process_gate(
+					p_clk->clk.peri.obj.ddr.gate.gate_flag,
+					p_clk->clk.peri.obj.ddr.gate.reg_offset,
+					p_clk->clk.peri.obj.ddr.gate.reg_mask,
+					&p_clk->clk.peri.obj.ddr.gate.sw_status,
+					&p_clk->gate);
+
+			if (ret != 0) {
+				fh_clk_err(p_clk,
+						"gate process failed.error no:%x\n",
+						ret);
+				break;
+			}
+
+			break;
+		case LEVEL_PERI_SDC:
+			//just need to handle the phase....
+			p_clk->clk_out_rate = p_clk->parent->clk_out_rate;
+			if (p_clk->clk.peri.obj.sdc.phase_diff & DIFF_REFERENCE) {
+				//fh_clk_debug(p_clk,"this is the reference..no need to process..\n");
+				break;
+			}
+
+			//baud ...
+
+			//phase..
+			//fh_clk_debug_no_handle("%d\n",p_clk->clk_out_rate);
+			//hw status..
+			ret = wrap_read_reg(p_clk->clk.peri.obj.sdc.reg_offset,
+					p_clk->clk.peri.obj.sdc.reg_mask,
+					&phase);
+
+			if (ret != 0) {
+				fh_clk_err(p_clk,
+						"read pmu failed.error no:%x\n",
+						ret);
+				break;
+			}
+
+//			fh_clk_debug(p_clk,"hw phase is :%x\n",phase);
+//			fh_clk_debug(p_clk,"sw phase is :%x\n",p_clk->clk.peri.obj.sdc.phase_diff);
+			if (phase != p_clk->clk.peri.obj.sdc.phase_diff) {
+				//update the hw para..
+				ret =
+						wrap_write_reg(
+								p_clk->clk.peri.obj.sdc.reg_offset,
+								p_clk->clk.peri.obj.sdc.reg_mask,
+								p_clk->clk.peri.obj.sdc.phase_diff);
+				if (ret != 0) {
+					fh_clk_err(p_clk,
+							"write pmu failed.error no:%x\n",
+							ret);
+					break;
+				}
+			}
+
+			break;
+		case LEVEL_PERI_GMAC:
+			break;
+		default:
+			break;
+
+		}
+	}
+
+	fh_clk_debug(p_clk, "clk out:%d\n", p_clk->clk_out_rate);
+
+}
+
+//
+void clk_in_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, RT_NULL);
+}
+
+void cis_pclk_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, RT_NULL);
+}
+
+void pll1_clk_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &clk_in);
+}
+
+void pll0_clk_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &clk_in);
+}
+
+void ddr_clk_update(struct fh_clk* p_clk)
+{
+
+	//check if pll0 or pll1
+	rt_uint32_t mux0, mux1;
+	rt_int32_t ret;
+	struct fh_clk* parent;
+	//1 step: fix the parent..
+	ret = wrap_read_reg(p_clk->clk.peri.obj.ddr.mux[1].reg_offset,
+			p_clk->clk.peri.obj.ddr.mux[1].reg_mask, &mux1);
+	if (ret != 0) {
+		fh_clk_err(p_clk, "read pmu failed.error no:%x\n", ret);
+		return;
+	}
+
+	if (mux1 == MUX1_PLL0_CLK) {
+		ret = check_xtal_pll0(p_clk->clk.peri.obj.ddr.mux[0].reg_offset,
+				p_clk->clk.peri.obj.ddr.mux[0].reg_mask, &mux0);
+		if (ret != 0) {
+			fh_clk_err(p_clk, "read pmu failed.error no:%x\n", ret);
+			return;
+		}
+		if (mux0 == MUX0_PLL0_CLK) {
+			//ddr normal parent is pll0
+			parent = &pll0;
+		} else {
+			//ddr normal parent is xtal
+			parent = &clk_in;
+		}
+	} else {
+		//ddr normal parent is pll1
+		parent = &pll1;
+	}
+	p_clk->clk.peri.obj.ddr.mux[0].mux_flag = HAS_MUX;
+	p_clk->clk.peri.obj.ddr.mux[1].mux_flag = HAS_MUX;
+	clk_handle(p_clk, parent);
+
+}
+
+void fclk_update(struct fh_clk* p_clk)
+{
+
+	//check if pll0 or xtal
+	rt_uint32_t mux0;
+	rt_int32_t ret;
+	struct fh_clk* parent;	//1 step: fix the parent..
+
+	//mux0 = check_xtal_pll0(p_clk->clk.peri.obj.ddr.mux[0].reg_offset,p_clk->clk.peri.obj.ddr.mux[0].reg_mask);
+	ret = check_xtal_pll0(p_clk->clk.peri.obj.normal.mux.reg_offset,
+			p_clk->clk.peri.obj.normal.mux.reg_mask, &mux0);
+	if (ret != 0) {
+		fh_clk_err(p_clk, "read pmu failed.error no:%x\n", ret);
+		return;
+	}
+
+	//fh_clk_debug(p_clk,"mux0 wrap value is %x\n",mux0);
+	if (mux0 == MUX0_PLL0_CLK) {
+		//ddr normal parent is pll0
+		parent = &pll0;
+	} else {
+		//ddr normal parent is xtal
+		parent = &clk_in;
+	}
+	p_clk->clk.peri.obj.normal.mux.mux_flag = HAS_MUX;
+	//2 step:fix the div...
+	if (mux0 == MUX0_PLL0_CLK) {
+		//cal_pll0_prediv(&p_clk->clk.peri.obj.ddr.div.div_flag,&p_clk->clk.peri.obj.ddr.div.pdiv_value);
+		cal_pll0_prediv(&p_clk->clk.peri.obj.normal.div.div_flag,
+				&p_clk->clk.peri.obj.normal.div.pdiv_value);
+	}
+	clk_handle(p_clk, parent);
+}
+
+void pix_update(struct fh_clk* p_clk)
+{
+
+	//check if pll0 or xtal
+	rt_uint32_t mux0;
+	rt_int32_t ret;
+	struct fh_clk* parent;	//1 step: fix the parent..
+#if(1)
+	//mux0 = check_xtal_pll0(p_clk->clk.peri.obj.ddr.mux[0].reg_offset,p_clk->clk.peri.obj.ddr.mux[0].reg_mask);
+	ret = check_pix_clk_source(p_clk->clk.peri.obj.normal.mux.reg_offset,
+			p_clk->clk.peri.obj.normal.mux.reg_mask, &mux0);
+	if (ret != 0) {
+		fh_clk_err(p_clk, "read pmu failed.error no:%x\n", ret);
+		return;
+	}
+//#define CIS_PIX_CLK				(0)
+//#define CIS_PIX_CLK_OPPOSITE	(1)
+//#define MIPI_PIX_CLK			(2)
+
+	//fh_clk_debug(p_clk,"mux0 wrap value is %x\n",mux0);
+	if (mux0 == CIS_PIX_CLK || mux0 == CIS_PIX_CLK_OPPOSITE) {
+		//ddr normal parent is pll0
+		parent = &cis_pclk;
+	} else {
+		parent = &mipi_pix_clk;
+	}
+	p_clk->clk.peri.obj.normal.mux.mux_flag = HAS_MUX;
+
+#endif
+	clk_handle(p_clk, parent);
+}
+
+void aclk_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &cpu_fclk);
+
+}
+
+void hclk_update(struct fh_clk* p_clk)
+{
+
+	fclk_update(p_clk);
+}
+
+void pclk_update(struct fh_clk* p_clk)
+{
+
+	clk_handle(p_clk, &cpu_hclk);
+}
+
+void isp_aclk_update(struct fh_clk* p_clk)
+{
+
+	fclk_update(p_clk);
+}
+
+void vcu_clk_update(struct fh_clk* p_clk)
+{
+	fclk_update(p_clk);
+}
+
+void vou_clk_update(struct fh_clk* p_clk)
+{
+	fclk_update(p_clk);
+}
+
+void mipi_p32_clk_update(struct fh_clk* p_clk)
+{
+	fclk_update(p_clk);
+}
+
+void cis_clk_out_update(struct fh_clk* p_clk)
+{
+	fclk_update(p_clk);
+}
+
+void pts_update(struct fh_clk* p_clk)
+{
+	fclk_update(p_clk);
+}
+
+void mipi_pix_clk_update(struct fh_clk* p_clk)
+{
+	fclk_update(p_clk);
+}
+
+void spi0_clk_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &pll1);
+}
+
+void spi1_clk_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &pll1);
+}
+
+void mipi_dphy_clk20m_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &pll1);
+}
+
+void i2c0_clk_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &pll1);
+}
+
+void i2c1_clk_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &pll1);
+}
+
+void uart0_clk_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &pll1);
+}
+
+void pwm_clk_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &pll1);
+}
+
+void time0_clk_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &pll1);
+}
+
+void time1_clk_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &pll1);
+}
+
+void uart1_clk_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &pll1);
+}
+
+void sadc_clk_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &pll1);
+}
+
+//sdc0...
+void sdc0_clk2x_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &pll1);
+}
+
+void sdc0_clk_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &sdc0_clk2x);
+}
+
+void sdc0_clk_out_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &sdc0_clk);
+}
+
+void sdc0_clk_sample_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &sdc0_clk2x);
+}
+
+void sdc0_clk_drv_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &sdc0_clk2x);
+}
+
+void sdc1_clk2x_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &pll1);
+}
+
+void sdc1_clk_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &sdc1_clk2x);
+}
+
+void sdc1_clk_out_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &sdc1_clk);
+}
+
+void sdc1_clk_sample_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &sdc1_clk2x);
+}
+
+void sdc1_clk_drv_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &sdc1_clk2x);
+}
+
+void eth_ref_clk_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &pll1);
+}
+
+void wdt_clk_update(struct fh_clk* p_clk)
+{
+	clk_handle(p_clk, &cpu_pclk);
+}
+
+/**
+ * @brief System Clock Configuration
+ */
+#define CLK_CONTROL_BASE			PMU_REG_BASE
+void rt_hw_clock_init(void)
+{
+	struct fh_clk *p;
+	int i;
+	fh_clk_tree.c_base_addr = CLK_CONTROL_BASE;
+	fh_clk_tree.clk_head = fh_clk_array;
+
+	//first open all the clock..
+	FH_TIMER_WRITEL(REG_PMU_CLK_GATE, 0x0);
+	for (i = 0; i < sizeof(fh_clk_array) / sizeof(struct fh_clk *); i++) {
+		p = fh_clk_tree.clk_head[i];
+		if (p->update_func)
+			p->update_func(p);
+	}
+}
+
+/***************
+ *
+ * new add
+ *
+ **************/
+
+/* clocks cannot be de-registered no refcounting necessary */
+struct fh_clk *clk_get(const char *name)
+{
+
+	struct fh_clk *p;
+	int i;
+
+	for (i = 0; i < sizeof(fh_clk_array) / sizeof(struct fh_clk *); i++) {
+		p = fh_clk_tree.clk_head[i];
+		if (!strcmp(p->name, name)) {
+			return p;
+		}
+	}
+
+	return RT_NULL;
+}
+
+//
+//#define HAS_GATE			(0)
+//#define HAS_NO_GATE			(1)
+//	rt_uint32_t gate_flag;
+//#define CLK_UNGATE			(0)
+//#define CLK_GATE			(1)
+
+void clk_gate_control(struct fh_clk *p_clk, rt_uint32_t status)
+{
+
+	if (status > CLK_GATE)
+		return;
+
+	if (p_clk->level == LEVEL_PERIPHERAL) {
+
+		switch (p_clk->clk.peri.peri_flag) {
+		case LEVEL_PERI_NORMAL:
+
+			if (p_clk->clk.peri.obj.normal.gate.gate_flag
+					== HAS_GATE) {
+				p_clk->clk.peri.obj.normal.gate.sw_status =
+						status;
+			} else {
+				rt_kprintf("[%-16.15s]: no gate...\t\n",
+						p_clk->name);
+			}
+
+			break;
+		case LEVEL_PERI_DDR:
+			if (p_clk->clk.peri.obj.ddr.gate.gate_flag == HAS_GATE) {
+				p_clk->clk.peri.obj.ddr.gate.sw_status = status;
+			} else {
+				rt_kprintf("[%-16.15s]: no gate...\t\n",
+						p_clk->name);
+			}
+
+			break;
+
+		default:
+			break;
+		}
+
+		p_clk->update_func(p_clk);
+
+	}
+
+}
+
+void clk_gate(struct fh_clk *p_clk)
+{
+	clk_gate_control(p_clk, CLK_GATE);
+}
+
+void clk_ungate(struct fh_clk *p_clk)
+{
+	clk_gate_control(p_clk, CLK_UNGATE);
+}
+
+rt_uint32_t clk_get_rate(struct fh_clk *p_clk)
+{
+	rt_uint32_t rate;
+	//first update the status
+	p_clk->update_func(p_clk);
+	rate = p_clk->clk_out_rate;
+	return rate;
+}
+
+void clk_set_rate(struct fh_clk *p_clk, rt_uint32_t rate_value)
+{
+
+	rt_uint32_t clk_in, div_flag, pre_div, div_multi, baud_out;
+
+	if (p_clk->level == LEVEL_PERIPHERAL) {
+
+		switch (p_clk->clk.peri.peri_flag) {
+		case LEVEL_PERI_NORMAL:
+
+			clk_in = p_clk->parent->clk_out_rate;
+			div_flag = p_clk->clk.peri.obj.normal.div.div_flag;
+			pre_div = p_clk->clk.peri.obj.normal.div.pdiv_value;
+			div_multi = p_clk->clk.peri.obj.normal.div.sw_div_multi;
+			baud_out = rate_value;
+
+			cal_baud_div(clk_in, div_flag, pre_div,
+					&p_clk->clk.peri.obj.normal.div.sw_div_value,
+					div_multi, baud_out);
+
+			break;
+		case LEVEL_PERI_DDR:
+			//rt_uint32_t mux0,mux1;
+			clk_in = p_clk->parent->clk_out_rate;
+			div_flag = p_clk->clk.peri.obj.ddr.div.div_flag;
+			pre_div = p_clk->clk.peri.obj.ddr.div.pdiv_value;
+			div_multi = p_clk->clk.peri.obj.ddr.div.sw_div_multi;
+			baud_out = rate_value;
+
+			cal_baud_div(clk_in, div_flag, pre_div,
+					&p_clk->clk.peri.obj.ddr.div.sw_div_value,
+					div_multi, baud_out);
+			break;
+		case LEVEL_PERI_SDC:
+			fh_clk_debug(p_clk,
+					"sdc can't set baud,please set the 'sdcx_clk2x'\n");
+			break;
+		case LEVEL_PERI_GMAC:
+			fh_clk_debug(p_clk, "gmac not support set baud\n");
+			break;
+		default:
+			break;
+		}
+		p_clk->update_func(p_clk);
+
+	}
+
+}
+
+rt_uint32_t sdc_get_phase(struct fh_clk *p_clk)
+{
+
+	if (p_clk->level == LEVEL_PERIPHERAL) {
+		if (p_clk->clk.peri.peri_flag == LEVEL_PERI_SDC) {
+
+			p_clk->update_func(p_clk);
+			return p_clk->clk.peri.obj.sdc.phase_diff;
+		}
+	}
+	return SDC_CLK_PARA_ERROR;
+
+}
+
+rt_uint32_t sdc_set_phase(struct fh_clk *p_clk, rt_uint32_t phase)
+{
+
+	if (phase > DIFF_SDC_REFCLK_270)
+		return SDC_CLK_PARA_ERROR;
+
+	if (p_clk->level == LEVEL_PERIPHERAL) {
+		if (p_clk->clk.peri.peri_flag == LEVEL_PERI_SDC) {
+			p_clk->clk.peri.obj.sdc.phase_diff = phase;
+			p_clk->update_func(p_clk);
+			return SDC_CLK_PARA_OK;
+		}
+	}
+	return SDC_CLK_PARA_ERROR;
+
+}
+
+#ifdef FH_DBG_CLK
+int fh_clk_nlist()
+{
+	struct fh_clk *p;
+	int i;
+
+	for(i = 0;i<sizeof(fh_clk_array)/sizeof(struct fh_clk *);i++) {
+		p = fh_clk_tree.clk_head[i];
+		//p->update_func(p);
+		rt_kprintf("[%-16.15s]:\t\t[baud]:%d\t\n",p->name,p->clk_out_rate);
+	}
+
+	return 0;
+}
+
+int fh_clk_glist()
+{
+	struct fh_clk *p;
+	int i;
+	rt_kprintf("first bit set means has no gate..\n");
+	for(i = 0;i<sizeof(fh_clk_array)/sizeof(struct fh_clk *);i++) {
+		p = fh_clk_tree.clk_head[i];
+		//p->update_func(p);
+		if(!(p->gate & CLK_HAS_NO_GATE))
+		rt_kprintf("[%-16.15s]:\t\t[gate]:%d\t\n",p->name,p->gate);
+		else
+		rt_kprintf("[%-16.15s]:\t\t[gate]:no gate..\t\n",p->name);
+	}
+
+	return 0;
+}
+#endif
+
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+#ifdef FH_DBG_CLK
+FINSH_FUNCTION_EXPORT(fh_clk_nlist, fh_clk_name_list..);
+FINSH_FUNCTION_EXPORT(fh_clk_glist, fh_clk_gate_list..);
+#endif
+#endif
+
+

+ 62 - 0
bsp/fh8620/platform/plat-v2/clock.h

@@ -0,0 +1,62 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef TIMER_H_
+#define TIMER_H_
+
+
+#include <rtdef.h>
+
+
+void rt_hw_clock_init(void);
+void rt_hw_get_clock(void);
+void rt_hw_set_dividor(rt_uint8_t hdivn, rt_uint8_t pdivn);
+void rt_hw_set_clock(rt_uint8_t sdiv, rt_uint8_t pdiv, rt_uint8_t mdiv);
+
+
+struct fh_clk;
+/*
+void fh_pmu_open(void);
+void fh_pmu_close(void);
+*/
+
+#define DIFF_SDC_REFCLK_0			(0)
+#define DIFF_SDC_REFCLK_90			(1)
+#define DIFF_SDC_REFCLK_180			(2)
+#define DIFF_SDC_REFCLK_270			(3)
+#define SDC_CLK_PARA_ERROR		(0xffff0000)
+#define SDC_CLK_PARA_OK			(0)
+
+
+void clk_gate(struct fh_clk *p_clk);
+void clk_ungate(struct fh_clk *p_clk);
+struct fh_clk *clk_get(const char *name);
+rt_uint32_t clk_get_rate(struct fh_clk *p_clk);
+void clk_set_rate(struct fh_clk *p_clk,rt_uint32_t rate_value);
+rt_uint32_t sdc_get_phase(struct fh_clk *p_clk);
+rt_uint32_t sdc_set_phase(struct fh_clk *p_clk,rt_uint32_t phase);
+
+#endif

+ 62 - 0
bsp/fh8620/platform/plat-v2/fh_pmu.c

@@ -0,0 +1,62 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#include "rtdebug.h"
+#include "arch.h"
+#include "fh_pmu.h"
+#include "fh_def.h"
+
+#define FH_PMU_WRITEL(offset,value)		SET_REG((PMU_REG_BASE + offset),value)
+#define FH_PMU_WRITEL_MASK(offset,value, mask)	SET_REG_M((PMU_REG_BASE + offset), value, mask)
+#define FH_PMU_READL(offset)			GET_REG((PMU_REG_BASE + offset))
+
+#define PMU_OFFSET_MAX		0x1d0
+
+int fh_pmu_read(rt_uint32_t offset, rt_uint32_t *value)
+{
+	RT_ASSERT(offset < PMU_OFFSET_MAX);
+
+	*value = FH_PMU_READL(offset);
+	return 0;
+}
+
+int  fh_pmu_write(rt_uint32_t offset, const rt_uint32_t value)
+{
+	RT_ASSERT(offset < PMU_OFFSET_MAX);
+
+	FH_PMU_WRITEL(offset, value);
+	return 0;
+}
+
+int fh_pmu_write_mask(rt_uint32_t offset, const rt_uint32_t value,
+		      const rt_uint32_t mask)
+{
+	RT_ASSERT(offset < PMU_OFFSET_MAX);
+
+	FH_PMU_WRITEL_MASK(offset, value, mask);
+	return 0;
+
+}

+ 59 - 0
bsp/fh8620/platform/plat-v2/fh_pmu.h

@@ -0,0 +1,59 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef FH_PMU_H_
+#define FH_PMU_H_
+
+#include <rtdef.h>
+
+#define     REG_PMU_CHIP_ID             (0x000)
+#define     REG_PMU_IP_VER              (0x004)
+#define     REG_PMU_FW_VER              (0x008)
+#define     REG_PMU_SYS_CTRL            (0x00c)
+#define     REG_PMU_PLL0_CTRL           (0x010)
+#define     REG_PMU_PLL1_CTRL           (0x014)
+#define     REG_PMU_ARC_CLK_GATE        (0x018)
+#define     REG_PMU_CLK_GATE        	(0x01c)
+#define     REG_PMU_CLK_SEL             (0x020)
+#define     REG_PMU_CLK_DIV0            (0x024)
+#define     REG_PMU_CLK_DIV1            (0x028)
+#define     REG_PMU_CLK_DIV2            (0x02c)
+#define     REG_PMU_CLK_DIV3            (0x030)
+#define     REG_PMU_CLK_DIV4            (0x034)
+#define     REG_PMU_CLK_DIV5            (0x038)
+#define     REG_PMU_CLK_DIV6            (0x03c)
+#define     REG_PMU_SWRST_MAIN_CTRL     (0x040)
+#define     REG_PMU_SWRST_AXI_CTRL      (0x044)
+#define     REG_PMU_SWRST_AHB_CTRL      (0x048)
+#define     REG_PMU_SWRST_APB_CTRL      (0x04c)
+#define     REG_PMU_VDAC_CTRL           (0x050)
+#define     REG_PMU_MAC_REF_CLK_CFG     (0x0a4)
+
+int fh_pmu_read(rt_uint32_t offset,rt_uint32_t *value);
+int fh_pmu_write(rt_uint32_t offset, const rt_uint32_t value);
+int fh_pmu_write_mask(rt_uint32_t offset,const rt_uint32_t value, const rt_uint32_t mask);
+
+#endif /* FH_PMU_H_ */

+ 284 - 0
bsp/fh8620/platform/plat-v2/iomux.c

@@ -0,0 +1,284 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#include "rtdebug.h"
+#include "iomux.h"
+
+static void fh_iomux_setmfs(Iomux_Pad *pad)
+{
+
+	switch (pad->reg_type) {
+	case 8:
+		(IOMUX_PADTYPE(8)pad->reg)->bit.mfs = pad->func_sel;
+		break;
+	case 13:
+		(IOMUX_PADTYPE(13)pad->reg)->bit.mfs = pad->func_sel;
+		break;
+	case 20:
+		(IOMUX_PADTYPE(20)pad->reg)->bit.mfs = pad->func_sel;
+		break;
+	case 21:
+		(IOMUX_PADTYPE(21)pad->reg)->bit.mfs = pad->func_sel;
+		break;
+	default:
+		break;
+	}
+
+}
+
+#ifdef IOMUX_DEBUG
+
+static int fh_iomux_getmfs(Iomux_Pad *pad)
+{
+	int mfs;
+
+	switch (pad->reg_type) {
+	case 8:
+		mfs = (IOMUX_PADTYPE(8)pad->reg)->bit.mfs;
+		break;
+	case 13:
+		mfs = (IOMUX_PADTYPE(13)pad->reg)->bit.mfs;
+		break;
+	case 20:
+		mfs = (IOMUX_PADTYPE(20)pad->reg)->bit.mfs;
+		break;
+	case 21:
+		mfs = (IOMUX_PADTYPE(21)pad->reg)->bit.mfs;
+		break;
+	default:
+		mfs = -1;
+		break;
+
+	}
+	return mfs;
+}
+
+
+static void fh_iomux_print()
+{
+	int i;
+	UINT32 reg;
+
+
+	for (i = 0; i < ARRAY_SIZE(fh81_iomux_cfg); i++) {
+		int curr_func;
+
+		curr_func = fh81_iomux_getmfs(iomux_obj, &iomux_obj.pads[i]);
+		reg = readl((UINT32)iomux_obj.pads[i].reg);
+
+		if (curr_func < 0)
+			rt_kprintf("\t%d\t\t%-8s(no mfs)\t0x%08x\n", i, iomux_obj.pads[i].func_name[0],
+				   reg);
+		else
+			rt_kprintf("\t%d\t\t%-16s\t0x%08x\n", i, iomux_obj.pads[i].func_name[curr_func],
+				   reg);
+
+	}
+
+}
+
+#endif
+
+static void fh_iomux_setcur(Iomux_Pad *pad)
+{
+
+	switch (pad->reg_type) {
+	case 5:
+		(IOMUX_PADTYPE(5)pad->reg)->bit.e8_e4 = pad->drv_cur;
+		break;
+	case 8:
+		(IOMUX_PADTYPE(8)pad->reg)->bit.e8_e4 = pad->drv_cur;
+		break;
+	case 13:
+		(IOMUX_PADTYPE(13)pad->reg)->bit.e4_e2 = pad->drv_cur;
+		break;
+	case 17:
+		(IOMUX_PADTYPE(17)pad->reg)->bit.e8_e4 = pad->drv_cur;
+		break;
+	case 20:
+		(IOMUX_PADTYPE(20)pad->reg)->bit.e4_e2 = pad->drv_cur;
+		break;
+	case 21:
+		(IOMUX_PADTYPE(21)pad->reg)->bit.e4_e2 = pad->drv_cur;
+		break;
+	default:
+		break;
+	}
+
+}
+
+static void fh_iomux_setpupd(Iomux_Pad *pad)
+{
+
+	switch (pad->reg_type) {
+	case 9:
+		(IOMUX_PADTYPE(9)pad->reg)->bit.pu_pd = pad->pupd;
+		break;
+	case 17:
+		(IOMUX_PADTYPE(17)pad->reg)->bit.pu_pd = pad->pupd;
+		break;
+	case 20:
+		(IOMUX_PADTYPE(20)pad->reg)->bit.pu_pd = pad->pupd;
+		break;
+	case 21:
+		(IOMUX_PADTYPE(21)pad->reg)->bit.pu_pd = pad->pupd;
+		break;
+	default:
+		break;
+	}
+
+}
+
+static void fh_iomux_setrest(Iomux_Pad *pad)
+{
+
+	switch (pad->reg_type) {
+	case 5:
+		(IOMUX_PADTYPE(5)pad->reg)->bit.sr = 0;
+		break;
+	case 8:
+		(IOMUX_PADTYPE(8)pad->reg)->bit.sr = 0;
+		break;
+	case 9:
+		(IOMUX_PADTYPE(9)pad->reg)->bit.ie = 1;
+		(IOMUX_PADTYPE(9)pad->reg)->bit.smt = 1;
+		break;
+	case 13:
+		(IOMUX_PADTYPE(13)pad->reg)->bit.ie = 1;
+		(IOMUX_PADTYPE(13)pad->reg)->bit.smt = 1;
+		break;
+	case 17:
+		(IOMUX_PADTYPE(17)pad->reg)->bit.sr = 0;
+		(IOMUX_PADTYPE(17)pad->reg)->bit.ie = 1;
+		(IOMUX_PADTYPE(17)pad->reg)->bit.e = 1;
+		(IOMUX_PADTYPE(17)pad->reg)->bit.smt = 1;
+		break;
+	case 20:
+		(IOMUX_PADTYPE(20)pad->reg)->bit.sr = 0;
+		(IOMUX_PADTYPE(20)pad->reg)->bit.ie = 1;
+		(IOMUX_PADTYPE(20)pad->reg)->bit.smt = 1;
+		break;
+	case 21:
+		(IOMUX_PADTYPE(21)pad->reg)->bit.sr = 0;
+		(IOMUX_PADTYPE(21)pad->reg)->bit.ie = 1;
+		(IOMUX_PADTYPE(21)pad->reg)->bit.smt = 1;
+		break;
+	default:
+		break;
+	}
+
+}
+
+static Iomux_Object iomux_obj;
+extern Iomux_Pad fh_iomux_cfg[];
+extern const int fh_iomux_cfg_count;
+
+void __fh_setiomux(Iomux_Pad *pad, void *iobase)
+{
+	UINT32 regvalue = 0;
+	pad->reg = &regvalue;
+	fh_iomux_setmfs(pad);
+	fh_iomux_setcur(pad);
+	fh_iomux_setpupd(pad);
+	fh_iomux_setrest(pad);
+	SET_REG(iobase, regvalue);
+}
+
+static UINT32 g_iomux_base;
+
+void fh_iomux_init(UINT32 base)
+{
+
+//	return;
+	int i;
+//	int test_cnt = 0;
+	UINT32 reg;
+	g_iomux_base = base;
+
+	iomux_obj.pbase = (void *)base;
+
+//	iomux_obj.vbase = (UINT32 *)rt_malloc(1024);
+	iomux_obj.pads = fh_iomux_cfg;
+
+	for (i = 0; i < fh_iomux_cfg_count; i++) {
+#if (1)
+		iomux_obj.pads[i].id = i;
+		iomux_obj.pads[i].reg_offset = i * 4;
+		iomux_obj.pads[i].reg = &reg;//(UINT32 *)(iomux_obj.vbase + iomux_obj.pads[i].reg_offset);
+		fh_iomux_setmfs(&fh_iomux_cfg[i]);
+		fh_iomux_setcur(&fh_iomux_cfg[i]);
+		fh_iomux_setpupd(&fh_iomux_cfg[i]);
+		fh_iomux_setrest(&fh_iomux_cfg[i]);
+		SET_REG(iomux_obj.pbase + iomux_obj.pads[i].reg_offset, reg);
+//			*((UINT32 *)(iomux_obj.vbase + iomux_obj.pads[i].reg_offset)));
+		//rt_kprintf("addr: 0x%x, pmu data: 0x%x\n", iomux_obj.pbase + iomux_obj.pads[i].reg_offset, GET_REG(iomux_obj.pbase + iomux_obj.pads[i].reg_offset));
+//		test_cnt++;
+#else
+#ifdef FH_USING_JTAG
+		if (strncmp(fh_iomux_cfg[i].func_name[0], "JTAG", 4) == 0)
+			continue;
+#endif
+/*
+		if (strncmp(fh_iomux_cfg[i].func_name[1], "UART1", 5) == 0)
+			break;
+*/
+
+		__fh_setiomux(&fh_iomux_cfg[i], (void *) base + i * 4);
+#endif
+	}
+
+#ifdef CONFIG_RMII
+	//(IOMUX_PADTYPE(17)(iomux_obj.pads[18]).reg)->bit.e = 1;
+	reg = GET_REG(0xf00000a4);
+	reg |= (1 << 13);
+	SET_REG(0xf00000a4, reg);
+#else
+	//(IOMUX_PADTYPE(17)(iomux_obj.pads[18]).reg)->bit.e = 0;
+	reg = GET_REG(0xf00000a4);
+	reg &= ~(1 << 13);
+	SET_REG(0xf00000a4, reg);
+#endif
+#ifdef IOMUX_DEBUG
+	fh_iomux_print(iomux_obj);
+#endif
+
+
+	//rt_free(iomux_obj.vbase);
+	//iomux_obj.vbase = 0;
+
+}
+
+void fh_iomux_pin_switch(int pin_num, int func_num)
+{
+	RT_ASSERT(pin_num < fh_iomux_cfg_count);
+	__fh_setiomux(&fh_iomux_cfg[pin_num], (void *)g_iomux_base + pin_num * 4);
+	/*
+	   fh_iomux_cfg[pin_num].func_sel = func_num;
+	    fh_iomux_setmfs(&fh_iomux_cfg[pin_num]);
+	    SET_REG(iomux_obj.pbase + iomux_obj.pads[pin_num].reg_offset, *((UINT32 *)(iomux_obj.vbase + iomux_obj.pads[pin_num].reg_offset)));
+	*/
+}
+

+ 314 - 0
bsp/fh8620/platform/plat-v2/iomux.h

@@ -0,0 +1,314 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef IOMUX_H_
+#define IOMUX_H_
+
+
+
+#include "fh_def.h"
+
+#define PMU_PAD_RESETN           (0)
+#define PMU_PAD_TEST             (1)
+#define PMU_PAD_CIS_CLK          (2)
+#define PMU_PAD_CIS_HSYNC        (3)
+#define PMU_PAD_CIS_VSYNC        (4)
+#define PMU_PAD_CIS_PCLK         (5)
+#define PMU_PAD_CIS_D_0          (6)
+#define PMU_PAD_CIS_D_1          (7)
+#define PMU_PAD_CIS_D_2          (8)
+#define PMU_PAD_CIS_D_3          (9)
+#define PMU_PAD_CIS_D_4          (10)
+#define PMU_PAD_CIS_D_5          (11)
+#define PMU_PAD_CIS_D_6          (12)
+#define PMU_PAD_CIS_D_7          (13)
+#define PMU_PAD_CIS_D_8          (14)
+#define PMU_PAD_CIS_D_9          (15)
+#define PMU_PAD_CIS_D_10         (16)
+#define PMU_PAD_CIS_D_11         (17)
+#define PMU_PAD_MAC_REF_CLK      (18)
+#define PMU_PAD_MAC_MDC          (19)
+#define PMU_PAD_MAC_MDIO         (20)
+#define PMU_PAD_MAC_COL          (21)
+#define PMU_PAD_MAC_CRS          (22)
+#define PMU_PAD_MAC_RXCK         (23)
+#define PMU_PAD_MAC_RXD0         (24)
+#define PMU_PAD_MAC_RXD1         (25)
+#define PMU_PAD_MAC_RXD2         (26)
+#define PMU_PAD_MAC_RXD3         (27)
+#define PMU_PAD_MAC_RXDV         (28)
+#define PMU_PAD_MAC_TXCK         (29)
+#define PMU_PAD_MAC_TXD0         (30)
+#define PMU_PAD_MAC_TXD1         (31)
+#define PMU_PAD_MAC_TXD2         (32)
+#define PMU_PAD_MAC_TXD3         (33)
+#define PMU_PAD_MAC_TXEN         (34)
+#define PMU_PAD_MAC_RXER         (35)
+#define PMU_PAD_GPIO_0           (36)
+#define PMU_PAD_GPIO_1           (37)
+#define PMU_PAD_GPIO_2           (38)
+#define PMU_PAD_GPIO_3           (39)
+#define PMU_PAD_GPIO_4           (40)
+#define PMU_PAD_GPIO_5           (41)
+#define PMU_PAD_GPIO_6           (42)
+#define PMU_PAD_GPIO_7           (43)
+#define PMU_PAD_GPIO_8           (44)
+#define PMU_PAD_GPIO_9           (45)
+#define PMU_PAD_GPIO_10          (46)
+#define PMU_PAD_GPIO_11          (47)
+#define PMU_PAD_GPIO_12          (48)
+#define PMU_PAD_GPIO_13          (49)
+#define PMU_PAD_GPIO_14          (50)
+#define PMU_PAD_GPIO_15          (51)
+#define PMU_PAD_GPIO_16          (52)
+#define PMU_PAD_GPIO_17          (53)
+#define PMU_PAD_GPIO_18          (54)
+#define PMU_PAD_GPIO_19          (55)
+#define PMU_PAD_UART0_IN         (56)
+#define PMU_PAD_UART0_OUT        (57)
+#define PMU_PAD_CIS_SCL          (58)
+#define PMU_PAD_CIS_SDA          (59)
+#define PMU_PAD_SCL1             (60)
+#define PMU_PAD_SDA1             (61)
+#define PMU_PAD_SSI0_CLK         (62)
+#define PMU_PAD_SSI0_TXD         (63)
+#define PMU_PAD_SSI0_CSN_0       (64)
+#define PMU_PAD_SSI0_CSN_1       (65)
+#define PMU_PAD_SSI0_RXD         (66)
+#define PMU_PAD_SD0_CD           (67)
+#define PMU_PAD_SD0_WP           (68)
+#define PMU_PAD_SD0_CLK          (69)
+#define PMU_PAD_SD0_CMD_RSP      (70)
+#define PMU_PAD_SD0_DATA_0       (71)
+#define PMU_PAD_SD0_DATA_1       (72)
+#define PMU_PAD_SD0_DATA_2       (73)
+#define PMU_PAD_SD0_DATA_3       (74)
+#define PMU_PAD_SD1_CLK          (75)
+#define PMU_PAD_SD1_CD           (76)
+#define PMU_PAD_SD1_WP           (77)
+#define PMU_PAD_SD1_DATA_0       (78)
+#define PMU_PAD_SD1_DATA_1       (79)
+#define PMU_PAD_SD1_DATA_2       (80)
+#define PMU_PAD_SD1_DATA_3       (81)
+#define PMU_PAD_SD1_CMD_RSP      (82)
+#define PMU_PAD_GPIO_60          (83)
+#define PMU_PAD_GPIO_61          (84)
+#define PMU_PAD_GPIO_62          (85)
+#define PMU_PAD_GPIO_63          (86)
+#define PMU_PAD_CLK_SW0          (87)
+#define PMU_PAD_CLK_SW1          (88)
+#define PMU_PAD_CLK_SW2          (89)
+#define PMU_PAD_CLK_SW3          (90)
+#define PMU_PAD_CRYSTAL          (91)
+#define PMU_PAD_MAC_TXER         (92)
+
+
+#define IOMUX_PADTYPE(n)		(Iomux_PadType##n *)
+#define IOMUX_PUPD_NONE			0
+#define IOMUX_PUPD_DOWN			1
+#define IOMUX_PUPD_UP			2
+#define IOMUX_PUPD_KEEPER		3
+//#define IOMUX_DEBUG
+
+
+typedef union
+{
+	struct
+	{
+		UINT32	sr								:1;
+		UINT32	reserved_3_1					:3;
+
+		UINT32	e8_e4							:2;
+		UINT32	reserved_31_6					:24;
+
+	}bit;
+	UINT32 dw;
+}Iomux_PadType5;
+
+typedef union
+{
+	struct
+	{
+		UINT32	sr								:1;
+		UINT32	reserved_3_1					:3;
+
+		UINT32	e8_e4							:2;
+		UINT32	reserved_7_6					:2;
+
+		UINT32	mfs								:1;
+		UINT32	reserved_31_9					:23;
+
+	}bit;
+	UINT32 dw;
+}Iomux_PadType8;
+
+
+typedef union
+{
+	struct
+	{
+		UINT32	smt								:1;
+		UINT32	reserved_3_1					:3;
+
+		UINT32	ie								:1;
+		UINT32	reserved_7_5					:3;
+
+		UINT32	pu_pd							:2;
+		UINT32	reserved_31_10					:22;
+
+	}bit;
+	UINT32 dw;
+}Iomux_PadType9;
+
+
+typedef union
+{
+	struct
+	{
+		UINT32	e4_e2							:2;
+		UINT32	reserved_3_2					:2;
+
+		UINT32	smt								:1;
+		UINT32	reserved_7_5					:3;
+
+		UINT32	ie								:1;
+		UINT32	reserved_11_9					:3;
+
+		UINT32	mfs								:2;
+		UINT32	reserved_31_14					:18;
+
+	}bit;
+	UINT32 dw;
+}Iomux_PadType13;
+
+typedef union
+{
+	struct
+	{
+		UINT32	sr								:1;
+		UINT32	reserved_3_1					:3;
+
+		UINT32	e8_e4							:2;
+		UINT32	reserved_7_6					:2;
+
+		UINT32	smt								:1;
+		UINT32	reserved_11_9					:3;
+
+		UINT32	ie								:1;
+		UINT32	e								:1;	//only for PAD_MAC_REF_CLK_CFG (0x00a4)
+		UINT32	reserved_15_12					:2;
+
+		UINT32	pu_pd							:2;
+		UINT32	reserved_31_18					:14;
+
+	}bit;
+	UINT32 dw;
+}Iomux_PadType17;
+
+typedef union
+{
+	struct
+	{
+		UINT32	sr								:1;
+		UINT32	reserved_3_1					:3;
+
+		UINT32	e4_e2							:2;
+		UINT32	reserved_7_6					:2;
+
+		UINT32	smt								:1;
+		UINT32	reserved_11_9					:3;
+
+		UINT32	ie								:1;
+		UINT32	reserved_15_13					:3;
+
+		UINT32	pu_pd							:2;
+		UINT32	reserved_19_18					:2;
+
+		UINT32	mfs								:1;
+		UINT32	reserved_31_21					:11;
+
+	}bit;
+	UINT32 dw;
+}Iomux_PadType20;
+
+
+typedef union
+{
+	struct
+	{
+		UINT32	sr								:1;
+		UINT32	reserved_3_1					:3;
+
+		UINT32	e4_e2							:2;
+		UINT32	reserved_7_6					:2;
+
+		UINT32	smt								:1;
+		UINT32	reserved_11_9					:3;
+
+		UINT32	ie								:1;
+		UINT32	reserved_15_13					:3;
+
+		UINT32	pu_pd							:2;
+		UINT32	reserved_19_18					:2;
+
+		UINT32	mfs								:2;
+		UINT32	reserved_31_21					:10;
+
+	}bit;
+	UINT32 dw;
+}Iomux_PadType21;
+
+typedef struct
+{
+    int id;
+	UINT32* reg;
+	UINT32 reg_offset;
+	char* func_name[4];
+	int reg_type;
+	int func_sel;
+	int drv_cur;
+	int pupd;
+	//UINT32 value;
+}Iomux_Pad;
+
+typedef struct
+{
+	void  *vbase;
+	void  *pbase;
+	Iomux_Pad *pads;
+}Iomux_Object;
+
+
+void fh_iomux_init(UINT32 base);
+void fh_iomux_pin_switch(int pin_num, int func_num);
+
+
+
+
+
+#endif /* IOMUX_H_ */
+
+

+ 50 - 0
bsp/fh8620/platform/plat-v2/reset.c

@@ -0,0 +1,50 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#include <rthw.h>
+#include <rtthread.h>
+#include "fh_pmu.h"
+#include "fh_def.h"
+#include "fh_arch.h"
+
+void machine_reset(void)
+{
+	fh_pmu_write(REG_PMU_SWRST_MAIN_CTRL, 0x7fffffff);
+}
+
+void machine_shutdown(void)
+{
+	while(1)
+		;
+
+}
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+FINSH_FUNCTION_EXPORT_ALIAS(rt_hw_cpu_reset, reset, system reset);
+#endif
+
+/*@}*/

+ 109 - 0
bsp/fh8620/platform/plat-v2/timer.c

@@ -0,0 +1,109 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "timer.h"
+#include <rtdevice.h>
+#include "fh_arch.h"
+#include "Libraries/inc/fh_timer.h"
+//#include "fh_pmu.h"
+//#include "chip_reg.h"
+//NEED_CAUTION.
+
+#define TIMER_CLOCK 1000000
+
+#define CONFIG_PAE_PTS_CLOCK   (1000000)
+#define TICKS_PER_USEC         (CONFIG_PAE_PTS_CLOCK / 1000000)
+#define REG_PAE_PTS_REG        (0xec100000 + 0x0040)
+
+static unsigned long lastdec;
+static unsigned long long timestamp;
+
+rt_uint32_t read_pts(void)
+{
+	return GET_REG(REG_PAE_PTS_REG);
+}
+
+unsigned long long get_ticks(void)
+{
+	rt_uint32_t now = read_pts();
+	if (now >= lastdec) {
+		/* normal mode */
+		timestamp += now - lastdec;
+	} else {
+		now = read_pts();
+		if (now >= lastdec)
+			timestamp += now - lastdec;
+		else {
+			/* we have an overflow ... */
+			timestamp += now + 0xffffffff - lastdec;
+		}
+	}
+	lastdec = now;
+	return timestamp / (TICKS_PER_USEC * 10);
+}
+
+void udelay(unsigned long usec)
+{
+	unsigned long long tmp;
+	rt_uint32_t tmo;
+	tmo = (usec + 9) / 10;
+	tmp = get_ticks() + tmo; /* get current timestamp */
+
+	while (get_ticks() < tmp)
+		/* loop till event */
+		/*NOP*/;
+}
+
+void rt_timer_handler(int vector, void *param)
+{
+	timer *tim = param;
+
+	rt_interrupt_enter();
+	timer_get_eoi(tim);
+	rt_tick_increase();
+	rt_interrupt_leave();
+}
+
+/**
+ * This function will init pit for system ticks
+ */
+void rt_hw_timer_init()
+{
+	timer *tim = (timer *) TMR_REG_BASE;
+	timer_init(tim);
+	/* install interrupt handler */
+	rt_hw_interrupt_install(TMR0_IRQn, rt_timer_handler, (void *) tim,
+				"sys_tick");
+	rt_hw_interrupt_umask(TMR0_IRQn);
+
+	timer_set_mode(tim, TIMER_MODE_PERIODIC);
+	timer_set_period(tim, RT_TICK_PER_SECOND, TIMER_CLOCK);
+	//timer_set_period(tim, RT_TIMER_TICK_PER_SECOND, TIMER_CLOCK);
+	timer_enable_irq(tim);
+	timer_enable(tim);
+
+}
+

+ 36 - 0
bsp/fh8620/platform/plat-v2/timer.h

@@ -0,0 +1,36 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef TIMER_H_
+#define TIMER_H_
+
+
+#include <rtdef.h>
+
+
+void rt_hw_timer_init(void);
+
+#endif

+ 81 - 0
bsp/fh8620/platform/platform_def.h

@@ -0,0 +1,81 @@
+/*
+ *  This file is part of FH8620 BSP for RT-Thread distribution.
+ *
+ *	Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. 
+ *	All rights reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *	Visit http://www.fullhan.com to get contact with Fullhan.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef PLATFORM_DEF_H_
+#define PLATFORM_DEF_H_
+
+#include "rtconfig.h"
+
+#ifdef CONFIG_CHIP_FH8620
+#ifdef CONFIG_BOARD_DEV
+#include "fh8620/dev_board/board_def.h"
+#endif
+#endif
+
+#ifdef CONFIG_CHIP_FH8620
+#ifdef CONFIG_BOARD_TEST
+#include "fh8620/test_board/board_def.h"
+#endif
+#endif
+
+#ifdef CONFIG_CHIP_FH8620
+#ifdef CONFIG_BOARD_IOTCAM
+#include "fh8620/iot_cam/board_def.h"
+#endif
+#endif
+
+#ifdef CONFIG_CHIP_FH8620G
+#ifdef CONFIG_BOARD_DEV
+#include "fh8620g/dev_board/board_def.h"
+#endif
+#endif
+
+#ifdef CONFIG_CHIP_FH8620G
+#ifdef CONFIG_BOARD_TEST
+#include "fh8620g/test_board/board_def.h"
+#endif
+#endif
+
+
+#ifdef CONFIG_CHIP_FH8810
+#ifdef CONFIG_BOARD_DEV
+#include "fh8810/dev_board/board_def.h"
+#endif
+#endif
+
+
+
+#ifdef CONFIG_CHIP_FH8810
+#ifdef CONFIG_BOARD_TEST
+#include "fh8810/test_board/board_def.h"
+#endif
+#endif
+
+
+
+
+
+#endif /* TEST_H_ */

+ 208 - 0
bsp/fh8620/rtconfig.h

@@ -0,0 +1,208 @@
+/* RT-Thread config file */
+#ifndef __RTTHREAD_CFG_H__
+#define __RTTHREAD_CFG_H__
+
+// <RDTConfigurator URL="http://www.rt-thread.com/eclipse">
+
+// <integer name="RT_NAME_MAX" description="Maximal size of kernel object name length" default="6" />
+#define RT_NAME_MAX	16
+// <integer name="RT_ALIGN_SIZE" description="Alignment size for CPU architecture data access" default="4" />
+#define RT_ALIGN_SIZE	4
+// <integer name="RT_THREAD_PRIORITY_MAX" description="Maximal level of thread priority" default="32">
+// <item description="8">8</item>
+// <item description="32">32</item>
+// <item description="256">256</item>
+// </integer>
+#define RT_THREAD_PRIORITY_MAX	256
+// <integer name="RT_TICK_PER_SECOND" description="OS tick per second" default="100" />
+#define RT_TICK_PER_SECOND	100
+// <integer name="IDLE_THREAD_STACK_SIZE" description="The stack size of idle thread" default="512" />
+#define IDLE_THREAD_STACK_SIZE	512
+// <bool name="RT_USING_MODULE" description="Using Application Module" default="true" />
+// #define RT_USING_MODULE
+// <bool name="RT_USING_CPU_FFS" description="Using CPU instructions for ffs function" default="true" />
+#define RT_USING_CPU_FFS
+// <section name="RT_DEBUG" description="Kernel Debug Configuration" default="true" >
+#define RT_DEBUG
+// <bool name="RT_THREAD_DEBUG" description="Thread debug enable" default="false" />
+// #define RT_THREAD_DEBUG
+// <bool name="RT_USING_OVERFLOW_CHECK" description="Thread stack over flow detect" default="true" />
+#define RT_USING_OVERFLOW_CHECK
+// </section>
+
+// <bool name="RT_USING_HOOK" description="Using hook functions" default="true" />
+#define RT_USING_HOOK
+// <section name="RT_USING_TIMER_SOFT" description="Using software timer which will start a thread to handle soft-timer" default="true" >
+// #define RT_USING_TIMER_SOFT
+// <integer name="RT_TIMER_THREAD_PRIO" description="The priority level of timer thread" default="4" />
+#define RT_TIMER_THREAD_PRIO	4
+// <integer name="RT_TIMER_THREAD_STACK_SIZE" description="The stack size of timer thread" default="512" />
+#define RT_TIMER_THREAD_STACK_SIZE	512
+// <integer name="RT_TIMER_TICK_PER_SECOND" description="The soft-timer tick per second" default="10" />
+#define RT_TIMER_TICK_PER_SECOND	100
+// </section>
+
+// <section name="IPC" description="Inter-Thread communication" default="always" >
+// <bool name="RT_USING_SEMAPHORE" description="Using semaphore in the system" default="true" />
+#define RT_USING_SEMAPHORE
+// <bool name="RT_USING_MUTEX" description="Using mutex in the system" default="true" />
+#define RT_USING_MUTEX
+// <bool name="RT_USING_EVENT" description="Using event group in the system" default="true" />
+#define RT_USING_EVENT
+// <bool name="RT_USING_MAILBOX" description="Using mailbox in the system" default="true" />
+#define RT_USING_MAILBOX
+// <bool name="RT_USING_MESSAGEQUEUE" description="Using message queue in the system" default="true" />
+#define RT_USING_MESSAGEQUEUE
+// </section>
+
+// <section name="MM" description="Memory Management" default="always" >
+// <bool name="RT_USING_MEMPOOL" description="Using Memory Pool Management in the system" default="true" />
+#define RT_USING_MEMPOOL
+// <bool name="RT_USING_MEMHEAP" description="Using Memory Heap Object in the system" default="true" />
+#define RT_USING_MEMHEAP
+// <bool name="RT_USING_HEAP" description="Using Dynamic Heap Management in the system" default="true" />
+#define RT_USING_HEAP
+// <bool name="RT_USING_SMALL_MEM" description="Optimizing for small memory" default="false" />
+#define RT_USING_SMALL_MEM
+// <bool name="RT_USING_SLAB" description="Using SLAB memory management for large memory" default="false" />
+// #define RT_USING_SLAB
+// </section>
+
+// <section name="RT_USING_DEVICE" description="Using Device Driver Framework" default="true" >
+#define RT_USING_DEVICE
+// <bool name=RT_USING_DEVICE_IPC description="Using IPC in Device Driver Framework" default="true" />
+#define RT_USING_DEVICE_IPC
+// <bool name="RT_USING_SERIAL" description="Using Serial Device Driver Framework" default="true" />
+#define RT_USING_SERIAL
+// <integer name="RT_UART_RX_BUFFER_SIZE" description="The buffer size for UART reception" default="64" />
+#define RT_UART_RX_BUFFER_SIZE    64
+// </section>
+// <bool name="RT_USING_SPI" description="Using SPI Device Driver Framework" default="true" />
+//#define RT_USING_SPI
+// <bool name="RT_USING_I2C" description="Using I2C Device Driver Framework" default="true" />
+#define RT_USING_I2C
+// <bool name="RT_USING_RTC" description="Using RTC Device Driver Framework" default="true" />
+//#define RT_USING_RTC
+// <integer name="RT_MMCSD_THREAD_PREORITY" description="The prority of mmcsd thread" default="15" />
+#define RT_MMCSD_THREAD_PREORITY	15
+// <section name="RT_USING_CONSOLE" description="Using console" default="true" >
+#define RT_USING_CONSOLE
+// <integer name="RT_CONSOLEBUF_SIZE" description="The buffer size for console output" default="128" />
+#define RT_CONSOLEBUF_SIZE	128
+// <string name="RT_CONSOLE_DEVICE_NAME" description="The device name for console" default="uart" />
+#define RT_CONSOLE_DEVICE_NAME	"uart1"
+// </section>
+
+// <bool name="RT_USING_COMPONENTS_INIT" description="Using RT-Thread components initialization" default="true" />
+#define RT_USING_COMPONENTS_INIT
+// <section name="RT_USING_FINSH" description="Using finsh as shell, which is a C-Express shell" default="true" >
+#define RT_USING_FINSH
+#define FINSH_USING_MSH
+// <bool name="FINSH_USING_SYMTAB" description="Using symbol table in finsh shell" default="true" />
+#define FINSH_USING_SYMTAB
+// <bool name="FINSH_USING_DESCRIPTION" description="Keeping description in symbol table" default="true" />
+#define FINSH_USING_DESCRIPTION
+// <integer name="FINSH_THREAD_STACK_SIZE" description="The stack size for finsh thread" default="4096" />
+#define FINSH_THREAD_STACK_SIZE	4096
+// </section>
+
+// <section name="LIBC" description="C Runtime library setting" default="always" >
+// <bool name="RT_USING_LIBC" description="Using C library" default="true" />
+#define RT_USING_LIBC
+// <bool name="RT_USING_PTHREADS" description="Using POSIX threads library" default="true" />
+#define RT_USING_PTHREADS
+// <bool name="RT_USING_CPLUSPLUS" description="Support C++ programming language" default="true" />
+#define RT_USING_CPLUSPLUS
+// </section>
+
+// <section name="RT_USING_DFS" description="Device file system" default="true" >
+//#define RT_USING_DFS
+// <bool name="DFS_USING_WORKDIR" description="Using working directory" default="true" />
+#define DFS_USING_WORKDIR
+// <integer name="DFS_FILESYSTEMS_MAX" description="The maximal number of mounted file system" default="4" />
+#define DFS_FILESYSTEMS_MAX	2
+// <integer name="DFS_FD_MAX" description="The maximal number of opened files" default="4" />
+#define DFS_FD_MAX	16
+// <bool name="RT_USING_DFS_ELMFAT" description="Using ELM FatFs" default="true" />
+#define RT_USING_DFS_ELMFAT
+// <integer name="RT_DFS_ELM_DRIVES" description="The maximal number of drives of FatFs" default="4" />
+#define RT_DFS_ELM_DRIVES    2
+// <bool name="RT_DFS_ELM_REENTRANT" description="Support reentrant" default="true" />
+#define RT_DFS_ELM_REENTRANT
+// <integer name="RT_DFS_ELM_USE_LFN" description="Support long file name" default="0">
+// <item description="LFN with static LFN working buffer">1</item>
+// <item description="LFN with dynamic LFN working buffer on the stack">2</item>
+// <item description="LFN with dynamic LFN working buffer on the heap">3</item>
+// </integer>
+#define RT_DFS_ELM_USE_LFN	3
+// <integer name="RT_DFS_ELM_CODE_PAGE" description="OEM code page" default="936">
+#define RT_DFS_ELM_CODE_PAGE	936
+// <bool name="RT_DFS_ELM_CODE_PAGE_FILE" description="Using OEM code page file" default="false" />
+#define RT_DFS_ELM_CODE_PAGE_FILE
+// <integer name="RT_DFS_ELM_MAX_LFN" description="Maximal size of file name length" default="256" />
+#define RT_DFS_ELM_MAX_LFN	256
+// <integer name="RT_DFS_ELM_MAX_SECTOR_SIZE" description="Maximal size of sector" default="512" />
+#define RT_DFS_ELM_MAX_SECTOR_SIZE  4096
+// <bool name="RT_USING_DFS_YAFFS2" description="Using YAFFS2" default="false" />
+// #define RT_USING_DFS_YAFFS2
+// <bool name="RT_USING_DFS_UFFS" description="Using UFFS" default="false" />
+// #define RT_USING_DFS_UFFS
+// <bool name="RT_USING_DFS_DEVFS" description="Using devfs for device objects" default="true" />
+#define RT_USING_DFS_DEVFS
+// <bool name="RT_USING_DFS_ROMFS" description="Using ROMFS" default="false" />
+//#define RT_USING_DFS_ROMFS
+// </section>
+
+// <section name="RT_USING_LWIP" description="lwip, a lightweight TCP/IP protocol stack" default="true" >
+// #define RT_USING_LWIP
+// <bool name="RT_LWIP_ICMP" description="Enable ICMP protocol" default="true" />
+#define RT_LWIP_ICMP
+// <bool name="RT_LWIP_IGMP" description="Enable IGMP protocol" default="false" />
+// #define RT_LWIP_IGMP
+// <bool name="RT_LWIP_UDP" description="Enable UDP protocol" default="true" />
+#define RT_LWIP_UDP
+// <bool name="RT_LWIP_TCP" description="Enable TCP protocol" default="true" />
+#define RT_LWIP_TCP
+// <bool name="RT_LWIP_DNS" description="Enable DNS protocol" default="true" />
+#define RT_LWIP_DNS
+// <bool name="RT_LWIP_SNMP" description="Enable SNMP protocol" default="false" />
+// #define RT_LWIP_SNMP
+// <bool name="RT_LWIP_DHCP" description="Enable DHCP client to get IP address" default="false" />
+#define RT_LWIP_DHCP
+// <integer name="RT_LWIP_TCPTHREAD_PRIORITY" description="the thread priority of TCP thread" default="128" />
+#define RT_LWIP_TCPTHREAD_PRIORITY	12
+// <integer name="RT_LWIP_TCPTHREAD_MBOX_SIZE" description="the mail box size of TCP thread to wait for" default="32" />
+#define RT_LWIP_TCPTHREAD_MBOX_SIZE	8
+// <integer name="RT_LWIP_TCPTHREAD_STACKSIZE" description="the thread stack size of TCP thread" default="4096" />
+#define RT_LWIP_TCPTHREAD_STACKSIZE	4096
+// <integer name="RT_LWIP_ETHTHREAD_PRIORITY" description="the thread priority of ethnetif thread" default="144" />
+#define RT_LWIP_ETHTHREAD_PRIORITY	14
+// <integer name="RT_LWIP_ETHTHREAD_MBOX_SIZE" description="the mail box size of ethnetif thread to wait for" default="8" />
+#define RT_LWIP_ETHTHREAD_MBOX_SIZE	8
+// <integer name="RT_LWIP_ETHTHREAD_STACKSIZE" description="the stack size of ethnetif thread" default="512" />
+#define RT_LWIP_ETHTHREAD_STACKSIZE	512
+// <ipaddr name="RT_LWIP_IPADDR" description="IP address of device" default="192.168.1.30" />
+#define RT_LWIP_IPADDR0 192
+#define RT_LWIP_IPADDR1 168
+#define RT_LWIP_IPADDR2 1
+#define RT_LWIP_IPADDR3 30
+// <ipaddr name="RT_LWIP_GWADDR" description="Gateway address of device" default="192.168.1.1" />
+#define RT_LWIP_GWADDR0 192
+#define RT_LWIP_GWADDR1 168
+#define RT_LWIP_GWADDR2 1
+#define RT_LWIP_GWADDR3 1
+// <ipaddr name="RT_LWIP_MSKADDR" description="Mask address of device" default="255.255.255.0" />
+#define RT_LWIP_MSKADDR0 255
+#define RT_LWIP_MSKADDR1 255
+#define RT_LWIP_MSKADDR2 255
+#define RT_LWIP_MSKADDR3 0
+// </section>
+
+// </RDTConfigurator>
+
+#define CONFIG_BOARD_IOTCAM
+#define CONFIG_CHIP_FH8620
+#define CONFIG_PLAT_V2
+#define RT_USING_DMA_MEM
+
+#endif

+ 44 - 0
bsp/fh8620/rtconfig.py

@@ -0,0 +1,44 @@
+import os
+import sys
+import re
+
+# toolchains options
+ARCH         = 'arm'
+CPU          = 'armv6'
+OUTPUT_NAME  = 'rtthread'
+CROSS_TOOL   = 'gcc' # we use gcc compiler always
+PLATFORM     = 'gcc'
+LD_NAME      = 'link'
+
+EXEC_PATH    = r'D:\arm-2013.11\bin'
+if os.getenv('RTT_EXEC_PATH'):
+    EXEC_PATH = os.getenv('RTT_EXEC_PATH')
+
+BUILD = 'release'
+
+if PLATFORM == 'gcc':
+    # toolchains
+    PREFIX = 'arm-none-eabi-'
+    CC  = PREFIX + 'gcc'
+    CXX = PREFIX + 'g++'
+    AS  = PREFIX + 'gcc'
+    AR  = PREFIX + 'ar'
+    LINK = PREFIX + 'gcc'
+    TARGET_EXT = '.elf'
+    SIZE = PREFIX + 'size'
+    OBJDUMP = PREFIX + 'objdump'
+    OBJCPY = PREFIX + 'objcopy'
+    DEVICE = ' -mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=soft'
+    CFLAGS = DEVICE + ' -mno-unaligned-access'
+    AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp -D__ASSEMBLY__'
+    LFLAGS = DEVICE + ' -Wl,--gc-sections,-Map='+ OUTPUT_NAME +'.map,-cref,-u,_start -T' + LD_NAME +'.ld'
+    CPATH = ''
+    LPATH = ''
+    if BUILD == 'debug':
+        CFLAGS += ' -O0 -gdwarf-2 '
+        AFLAGS += ' -gdwarf-2'
+    else:
+        CFLAGS += ' -O2'
+
+    CXXFLAGS = CFLAGS
+    POST_ACTION = OBJCPY + ' -O binary $TARGET '+ OUTPUT_NAME +'.bin\n' + SIZE + ' $TARGET \n'

+ 145 - 0
libcpu/arm/armv6/arm_entry_gcc.S

@@ -0,0 +1,145 @@
+/*
+ * File      : arm_entry_gcc.S
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2014-11-07     weety    first version
+ */
+
+#include <rtconfig.h>
+
+#include "armv6.h"
+
+//#define DEBUG
+
+.macro	PRINT, str
+#ifdef DEBUG
+	stmfd	sp!, {r0-r3, ip, lr}
+	add	r0, pc, #4
+	bl	rt_kprintf
+	b	1f
+	.asciz  "UNDEF: \str\n"
+	.balign 4
+1:	ldmfd	sp!, {r0-r3, ip, lr}
+#endif
+	.endm
+
+.macro  PRINT1, str, arg
+#ifdef DEBUG
+	stmfd	sp!, {r0-r3, ip, lr}
+	mov	r1, \arg
+	add	r0, pc, #4
+	bl	rt_kprintf
+	b	1f
+	.asciz  "UNDEF: \str\n"
+	.balign 4
+1:	ldmfd	sp!, {r0-r3, ip, lr}
+#endif
+	.endm
+
+.macro  PRINT3, str, arg1, arg2, arg3
+#ifdef DEBUG
+	stmfd	sp!, {r0-r3, ip, lr}
+	mov	r3, \arg3
+	mov	r2, \arg2
+	mov	r1, \arg1
+	add	r0, pc, #4
+	bl	rt_kprintf
+	b	1f
+	.asciz  "UNDEF: \str\n"
+	.balign 4
+1:	ldmfd	sp!, {r0-r3, ip, lr}
+#endif
+	.endm
+
+.macro	get_current_thread, rd
+	ldr	\rd, .current_thread
+	ldr	\rd, [\rd]
+	.endm
+
+.current_thread:
+	.word	rt_current_thread
+
+#ifdef RT_USING_NEON
+	.align	6
+
+/* is the neon instuction on arm mode? */
+.neon_opcode:
+	.word	0xfe000000			@ mask
+	.word	0xf2000000			@ opcode
+
+	.word	0xff100000			@ mask
+	.word	0xf4000000			@ opcode
+
+	.word	0x00000000			@ end mask
+	.word	0x00000000			@ end opcode
+#endif
+
+/* undefined instruction exception processing */
+.globl undef_entry
+undef_entry:
+	PRINT1 "r0=0x%08x", r0
+	PRINT1 "r2=0x%08x", r2
+	PRINT1 "r9=0x%08x", r9
+	PRINT1 "sp=0x%08x", sp
+
+#ifdef RT_USING_NEON
+	ldr	r6, .neon_opcode
+__check_neon_instruction:
+	ldr	r7, [r6], #4		@ load mask value
+	cmp	r7, #0				@ end mask?
+	beq	__check_vfp_instruction
+	and	r8, r0, r7
+	ldr	r7, [r6], #4		@ load opcode value
+	cmp	r8, r7				@ is NEON instruction?
+	bne	__check_neon_instruction
+	b	vfp_entry
+__check_vfp_instruction:
+#endif
+	tst	r0, #0x08000000			@ only CDP/CPRT/LDC/STC instruction has bit 27
+	tstne	r0, #0x04000000		@ bit 26 set on both ARM and Thumb-2 instruction
+	moveq	pc, lr				@ no vfp coprocessor instruction, return
+	get_current_thread r10
+	and	r8, r0, #0x00000f00		@ get coprocessor number
+	PRINT1 "CP=0x%08x", r8
+	add	pc, pc, r8, lsr #6
+	nop
+	mov pc,	lr				@ CP0
+	mov pc,	lr				@ CP1
+	mov pc,	lr				@ CP2
+	mov pc,	lr				@ CP3
+	mov pc,	lr				@ CP4
+	mov pc,	lr				@ CP5
+	mov pc,	lr				@ CP6
+	mov pc,	lr				@ CP7
+	mov pc,	lr				@ CP8
+	mov pc,	lr				@ CP9
+#ifdef RT_USING_VFP
+	b	vfp_entry			@ CP10 VFP
+	b	vfp_entry			@ CP11 VFP
+#else
+	mov pc,	lr				@ CP10 VFP
+	mov pc,	lr				@ CP11 VFP
+#endif
+	mov pc,	lr				@ CP12
+	mov pc,	lr				@ CP13
+	mov pc,	lr				@ CP14 DEBUG
+	mov pc,	lr				@ CP15 SYS CONTROL
+
+

+ 107 - 0
libcpu/arm/armv6/armv6.h

@@ -0,0 +1,107 @@
+/*
+ * File      : armv6.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+ 
+#ifndef __ARMV6_H__
+#define __ARMV6_H__
+
+
+/*****************************/
+/* CPU Mode                  */
+/*****************************/
+#define USERMODE        0x10
+#define FIQMODE         0x11
+#define IRQMODE         0x12
+#define SVCMODE         0x13
+#define ABORTMODE       0x17
+#define UNDEFMODE       0x1b
+#define MODEMASK        0x1f
+#define NOINT           0xc0
+
+#ifndef __ASSEMBLY__
+struct rt_hw_register
+{
+	rt_uint32_t cpsr;
+    rt_uint32_t r0;
+    rt_uint32_t r1;
+    rt_uint32_t r2;
+    rt_uint32_t r3;
+    rt_uint32_t r4;
+    rt_uint32_t r5;
+    rt_uint32_t r6;
+    rt_uint32_t r7;
+    rt_uint32_t r8;
+    rt_uint32_t r9;
+    rt_uint32_t r10;
+    rt_uint32_t fp;
+    rt_uint32_t ip;
+    rt_uint32_t sp;
+    rt_uint32_t lr;
+    rt_uint32_t pc;
+};
+#if(0)
+struct rt_hw_register{
+	rt_uint32_t r0;
+	rt_uint32_t r1;
+	rt_uint32_t r2;
+	rt_uint32_t r3;
+	rt_uint32_t r4;
+	rt_uint32_t r5;
+	rt_uint32_t r6;
+	rt_uint32_t r7;
+	rt_uint32_t r8;
+	rt_uint32_t r9;
+	rt_uint32_t r10;
+	rt_uint32_t fp;
+	rt_uint32_t ip;
+	rt_uint32_t sp;
+	rt_uint32_t lr;
+	rt_uint32_t pc;
+	rt_uint32_t cpsr;
+	rt_uint32_t ORIG_r0;
+};
+#endif
+#endif
+
+/* rt_hw_register offset */
+#define S_FRAME_SIZE        68
+
+#define S_PC                64
+#define S_LR                60
+#define S_SP                56
+#define S_IP                52
+#define S_FP                48
+#define S_R10               44
+#define S_R9                40
+#define S_R8                36
+#define S_R7                32
+#define S_R6                28
+#define S_R5                24
+#define S_R4                20
+#define S_R3                16
+#define S_R2                12
+#define S_R1                8
+#define S_R0                4
+#define S_CPSR              0
+
+
+#endif

+ 122 - 0
libcpu/arm/armv6/context_gcc.S

@@ -0,0 +1,122 @@
+/*
+ * File      : context.S
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2011-01-13     weety    copy from mini2440
+ */
+
+/*!
+ * \addtogroup ARMv6
+ */
+/*@{*/
+
+#include <rtconfig.h>
+
+#define NOINT          0xc0
+#define FPEXC_EN       (1 << 30) /* VFP enable bit */
+
+/*
+ * rt_base_t rt_hw_interrupt_disable();
+ */
+.globl rt_hw_interrupt_disable
+rt_hw_interrupt_disable:
+    mrs r0, cpsr
+    cpsid if
+    bx  lr
+
+/*
+ * void rt_hw_interrupt_enable(rt_base_t level);
+ */
+.globl rt_hw_interrupt_enable
+rt_hw_interrupt_enable:
+    msr cpsr_c, r0
+    bx  lr
+
+/*
+ * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
+ * r0 --> from
+ * r1 --> to
+ */
+.globl rt_hw_context_switch
+rt_hw_context_switch:
+    stmfd   sp!, {lr}       @ push pc (lr should be pushed in place of PC)
+    stmfd   sp!, {r0-r12, lr}   @ push lr & register file
+
+    mrs r4, cpsr
+    tst lr, #0x01
+    orrne r4, r4, #0x20     @ it's thumb code
+
+    stmfd sp!, {r4}         @ push cpsr
+
+    str sp, [r0]            @ store sp in preempted tasks TCB
+    ldr sp, [r1]            @ get new task stack pointer
+
+    ldmfd sp!, {r4}         @ pop new task cpsr to spsr
+    msr spsr_cxsf, r4
+#ifdef RT_USING_VFP
+    vmrs    r0, fpexc
+    bic     r0, r0, #FPEXC_EN    @ always disable VFP so we can 
+                                 @ lazily save/restore the old state.
+    vmsr    fpexc, r0
+#endif
+_do_switch:
+    ldmfd sp!, {r0-r12, lr, pc}^  @ pop new task r0-r12, lr & pc, copy spsr to cpsr
+
+/*
+ * void rt_hw_context_switch_to(rt_uint32 to);
+ * r0 --> to
+ */
+.globl rt_hw_context_switch_to
+rt_hw_context_switch_to:
+    ldr sp, [r0]            @ get new task stack pointer
+
+    ldmfd sp!, {r4}         @ pop new task spsr
+    msr spsr_cxsf, r4
+
+    bic r4, r4, #0x20       @ must be ARM mode
+    msr cpsr_cxsf, r4
+#ifdef RT_USING_VFP
+    vmrs    r0, fpexc
+    bic     r0, r0, #FPEXC_EN    @ always disable VFP so we can 
+                                 @ lazily save/restore the old state.
+    vmsr    fpexc, r0
+#endif
+    ldmfd sp!, {r0-r12, lr, pc}^   @ pop new task r0-r12, lr & pc
+
+/*
+ * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
+ */
+.globl rt_thread_switch_interrupt_flag
+.globl rt_interrupt_from_thread
+.globl rt_interrupt_to_thread
+.globl rt_hw_context_switch_interrupt
+rt_hw_context_switch_interrupt:
+    ldr r2, =rt_thread_switch_interrupt_flag
+    ldr r3, [r2]
+    cmp r3, #1
+    beq _reswitch
+    mov r3, #1              @ set rt_thread_switch_interrupt_flag to 1
+    str r3, [r2]
+    ldr r2, =rt_interrupt_from_thread   @ set rt_interrupt_from_thread
+    str r0, [r2]
+_reswitch:
+    ldr r2, =rt_interrupt_to_thread     @ set rt_interrupt_to_thread
+    str r1, [r2]
+    bx  lr

+ 248 - 0
libcpu/arm/armv6/cpuport.c

@@ -0,0 +1,248 @@
+/*
+ * File      : cpu.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006, RT-Thread Develop Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2011-01-13     weety      modified from mini2440
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+
+#define ICACHE_MASK	(rt_uint32_t)(1 << 12)
+#define DCACHE_MASK	(rt_uint32_t)(1 << 2)
+
+extern void machine_reset(void);
+extern void machine_shutdown(void);
+
+#ifdef __GNUC__
+rt_inline rt_uint32_t cp15_rd(void)
+{
+	rt_uint32_t i;
+
+	asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
+	return i;
+}
+
+rt_inline void cache_enable(rt_uint32_t bit)
+{
+	__asm__ __volatile__(			\
+		"mrc  p15,0,r0,c1,c0,0\n\t"	\
+		"orr  r0,r0,%0\n\t"			\
+	   	"mcr  p15,0,r0,c1,c0,0"		\
+		:							\
+		:"r" (bit)					\
+		:"memory");
+}
+
+rt_inline void cache_disable(rt_uint32_t bit)
+{
+	__asm__ __volatile__(			\
+		"mrc  p15,0,r0,c1,c0,0\n\t"	\
+		"bic  r0,r0,%0\n\t"			\
+		"mcr  p15,0,r0,c1,c0,0"		\
+		:							\
+		:"r" (bit)					\
+		:"memory");
+}
+
+
+#endif
+
+#ifdef __CC_ARM
+rt_inline rt_uint32_t cp15_rd(void)
+{
+	rt_uint32_t i;
+
+	__asm
+	{
+		mrc p15, 0, i, c1, c0, 0
+	}
+
+	return i;
+}
+
+rt_inline void cache_enable(rt_uint32_t bit)
+{
+	rt_uint32_t value;
+
+	__asm
+	{
+		mrc p15, 0, value, c1, c0, 0
+		orr value, value, bit
+		mcr p15, 0, value, c1, c0, 0
+	}
+}
+
+rt_inline void cache_disable(rt_uint32_t bit)
+{
+	rt_uint32_t value;
+
+	__asm
+	{
+		mrc p15, 0, value, c1, c0, 0
+		bic value, value, bit
+		mcr p15, 0, value, c1, c0, 0
+	}
+}
+#endif
+
+/**
+ * enable I-Cache
+ *
+ */
+void rt_hw_cpu_icache_enable()
+{
+	cache_enable(ICACHE_MASK);
+}
+
+/**
+ * disable I-Cache
+ *
+ */
+void rt_hw_cpu_icache_disable()
+{
+	cache_disable(ICACHE_MASK);
+}
+
+/**
+ * return the status of I-Cache
+ *
+ */
+rt_base_t rt_hw_cpu_icache_status()
+{
+	return (cp15_rd() & ICACHE_MASK);
+}
+
+/**
+ * enable D-Cache
+ *
+ */
+void rt_hw_cpu_dcache_enable()
+{
+	cache_enable(DCACHE_MASK);
+}
+
+/**
+ * disable D-Cache
+ *
+ */
+void rt_hw_cpu_dcache_disable()
+{
+	cache_disable(DCACHE_MASK);
+}
+
+/**
+ * return the status of D-Cache
+ *
+ */
+rt_base_t rt_hw_cpu_dcache_status()
+{
+	return (cp15_rd() & DCACHE_MASK);
+}
+
+/**
+ * reset cpu by dog's time-out
+ *
+ */
+void rt_hw_cpu_reset()
+{
+	
+	rt_kprintf("Restarting system...\n");
+	machine_reset();
+
+	while(1);	/* loop forever and wait for reset to happen */
+
+	/* NEVER REACHED */
+}
+
+/**
+ *  shutdown CPU
+ *
+ */
+void rt_hw_cpu_shutdown()
+{
+	rt_uint32_t level;
+	rt_kprintf("shutdown...\n");
+
+	level = rt_hw_interrupt_disable();
+	machine_shutdown();
+	while (level)
+	{
+		RT_ASSERT(0);
+	}
+}
+
+#ifdef RT_USING_CPU_FFS
+/**
+ * This function finds the first bit set (beginning with the least significant bit) 
+ * in value and return the index of that bit.
+ *
+ * Bits are numbered starting at 1 (the least significant bit).  A return value of 
+ * zero from any of these functions means that the argument was zero.
+ * 
+ * @return return the index of the first bit set. If value is 0, then this function 
+ * shall return 0.
+ */
+#if defined(__CC_ARM)
+int __rt_ffs(int value)
+{
+	register rt_uint32_t x;
+
+	if (value == 0)
+		return value;
+	
+	__asm
+	{
+		rsb x, value, #0
+		and x, x, value
+		clz x, x
+		rsb x, x, #32
+	}
+
+	return x;
+}
+#elif defined(__IAR_SYSTEMS_ICC__)
+int __rt_ffs(int value)
+{
+	if (value == 0)
+		return value;
+
+	__ASM("RSB  r4, r0, #0");
+	__ASM("AND  r4, r4, r0");
+	__ASM("CLZ  r4, r4");
+	__ASM("RSB  r0, r4, #32");
+}
+#elif defined(__GNUC__)
+int __rt_ffs(int value)
+{
+	if (value == 0)
+		return value;
+
+	value &= (-value);
+	asm ("clz %0, %1": "=r"(value) :"r"(value));
+
+	return (32 - value);
+}
+#endif
+
+#endif
+
+
+/*@}*/

+ 562 - 0
libcpu/arm/armv6/mmu.c

@@ -0,0 +1,562 @@
+/*
+ * File      : mmu.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "mmu.h"
+
+#ifdef __CC_ARM
+void mmu_setttbase(rt_uint32_t i)
+{
+	register rt_uint32_t value;
+
+	/* Invalidates all TLBs.Domain access is selected as
+	 * client by configuring domain access register,
+	 * in that case access controlled by permission value
+	 * set by page table entry
+	 */
+	value = 0;
+	__asm
+	{
+		mcr p15, 0, value, c8, c7, 0
+	}
+
+	value = 0x55555555;
+	__asm
+	{
+		mcr p15, 0, value, c3, c0, 0
+			mcr p15, 0, i, c2, c0, 0
+	}
+}
+
+void mmu_set_domain(rt_uint32_t i)
+{
+	__asm
+	{
+		mcr p15,0, i, c3, c0,  0
+	}
+}
+
+void mmu_enable()
+{
+	register rt_uint32_t value;
+
+	__asm
+	{
+		mrc p15, 0, value, c1, c0, 0
+			orr value, value, #0x01
+			mcr p15, 0, value, c1, c0, 0
+	}
+}
+
+void mmu_disable()
+{
+	register rt_uint32_t value;
+
+	__asm
+	{
+		mrc p15, 0, value, c1, c0, 0
+			bic value, value, #0x01
+			mcr p15, 0, value, c1, c0, 0
+	}
+}
+
+void mmu_enable_icache()
+{
+	register rt_uint32_t value;
+
+	__asm
+	{
+		mrc p15, 0, value, c1, c0, 0
+			orr value, value, #0x1000
+			mcr p15, 0, value, c1, c0, 0
+	}
+}
+
+void mmu_enable_dcache()
+{
+	register rt_uint32_t value;
+
+	__asm
+	{
+		mrc p15, 0, value, c1, c0, 0
+			orr value, value, #0x04
+			mcr p15, 0, value, c1, c0, 0
+	}
+}
+
+void mmu_disable_icache()
+{
+	register rt_uint32_t value;
+
+	__asm
+	{
+		mrc p15, 0, value, c1, c0, 0
+			bic value, value, #0x1000
+			mcr p15, 0, value, c1, c0, 0
+	}
+}
+
+void mmu_disable_dcache()
+{
+	register rt_uint32_t value;
+
+	__asm
+	{
+		mrc p15, 0, value, c1, c0, 0
+			bic value, value, #0x04
+			mcr p15, 0, value, c1, c0, 0
+	}
+}
+
+void mmu_enable_alignfault()
+{
+	register rt_uint32_t value;
+
+	__asm
+	{
+		mrc p15, 0, value, c1, c0, 0
+			orr value, value, #0x02
+			mcr p15, 0, value, c1, c0, 0
+	}
+}
+
+void mmu_disable_alignfault()
+{
+	register rt_uint32_t value;
+
+	__asm
+	{
+		mrc p15, 0, value, c1, c0, 0
+			bic value, value, #0x02
+			mcr p15, 0, value, c1, c0, 0
+	}
+}
+
+void mmu_clean_invalidated_cache_index(int index)
+{
+	__asm
+	{
+		mcr p15, 0, index, c7, c14, 2
+	}
+}
+
+void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size)
+{
+	unsigned int ptr;
+
+	ptr = buffer & ~(CACHE_LINE_SIZE - 1);
+
+	while(ptr < buffer + size)
+	{
+		__asm
+		{
+			MCR p15, 0, ptr, c7, c14, 1
+		}
+		ptr += CACHE_LINE_SIZE;
+	}
+}
+
+void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size)
+{
+	unsigned int ptr;
+
+	ptr = buffer & ~(CACHE_LINE_SIZE - 1);
+
+	while (ptr < buffer + size)
+	{
+		__asm
+		{
+			MCR p15, 0, ptr, c7, c10, 1
+		}
+		ptr += CACHE_LINE_SIZE;
+	}
+}
+
+void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size)
+{
+	unsigned int ptr;
+
+	ptr = buffer & ~(CACHE_LINE_SIZE - 1);
+
+	while (ptr < buffer + size)
+	{
+		__asm
+		{
+			MCR p15, 0, ptr, c7, c6, 1
+		}
+		ptr += CACHE_LINE_SIZE;
+	}
+}
+
+void mmu_invalidate_tlb()
+{
+	register rt_uint32_t value;
+
+	value = 0;
+	__asm
+	{
+		mcr p15, 0, value, c8, c7, 0
+	}
+}
+
+void mmu_invalidate_icache()
+{
+	register rt_uint32_t value;
+
+	value = 0;
+
+	__asm
+	{
+		mcr p15, 0, value, c7, c5, 0
+	}
+}
+
+
+void mmu_invalidate_dcache_all()
+{
+	register rt_uint32_t value;
+
+	value = 0;
+
+	__asm
+	{
+		mcr p15, 0, value, c7, c6, 0
+	}
+}
+#elif defined(__GNUC__)
+void mmu_setttbase(register rt_uint32_t i)
+{
+	register rt_uint32_t value;
+
+	/* Invalidates all TLBs.Domain access is selected as
+	 * client by configuring domain access register,
+	 * in that case access controlled by permission value
+	 * set by page table entry
+	 */
+	value = 0;
+	asm ("mcr p15, 0, %0, c8, c7, 0"::"r"(value));
+
+	value = 0x55555555;
+	asm ("mcr p15, 0, %0, c3, c0, 0"::"r"(value));
+	asm ("mcr p15, 0, %0, c2, c0, 0"::"r"(i));
+}
+
+void mmu_set_domain(register rt_uint32_t i)
+{
+	asm ("mcr p15,0, %0, c3, c0,  0": :"r" (i));
+}
+
+void mmu_enable()
+{
+	register rt_uint32_t i;
+
+	/* read control register */
+	asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
+
+	i |= 0x1;
+	/* Enables the extended page tables to be configured for
+	   the hardware page translation mechanism, Subpage AP bits disabled */
+	i |= (1 << 23); /* support for ARMv6 MMU features */
+	i |= (1 << 13); /* High exception vectors selected, address range = 0xFFFF0000-0xFFFF001C */
+
+	/* write back to control register */
+	asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
+}
+
+void mmu_disable()
+{
+	register rt_uint32_t i;
+
+	/* read control register */
+	asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
+
+	i &= ~0x1;
+
+	/* write back to control register */
+	asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
+}
+
+void mmu_enable_icache()
+{
+	register rt_uint32_t i;
+
+	/* read control register */
+	asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
+
+	i |= (1 << 12);
+
+	/* write back to control register */
+	asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
+}
+
+void mmu_enable_dcache()
+{
+	register rt_uint32_t i;
+
+	/* read control register */
+	asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
+
+	i |= (1 << 2);
+
+	/* write back to control register */
+	asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
+}
+
+void mmu_disable_icache()
+{
+	register rt_uint32_t i;
+
+	/* read control register */
+	asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
+
+	i &= ~(1 << 12);
+
+	/* write back to control register */
+	asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
+}
+
+void mmu_disable_dcache()
+{
+	register rt_uint32_t i;
+
+	/* read control register */
+	asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
+
+	i &= ~(1 << 2);
+
+	/* write back to control register */
+	asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
+}
+
+void mmu_enable_alignfault()
+{
+	register rt_uint32_t i;
+
+	/* read control register */
+	asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
+
+	i |= (1 << 1);
+
+	/* write back to control register */
+	asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
+}
+
+void mmu_disable_alignfault()
+{
+	register rt_uint32_t i;
+
+	/* read control register */
+	asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
+
+	i &= ~(1 << 1);
+
+	/* write back to control register */
+	asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
+}
+
+void mmu_clean_invalidated_cache_index(int index)
+{
+	asm ("mcr p15, 0, %0, c7, c14, 2": :"r" (index));
+}
+
+void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size)
+{
+	unsigned int ptr;
+
+	ptr = buffer & ~(CACHE_LINE_SIZE - 1);
+
+	while(ptr < buffer + size)
+	{
+		asm ("mcr p15, 0, %0, c7, c14, 1": :"r" (ptr));
+		ptr += CACHE_LINE_SIZE;
+	}
+}
+
+
+void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size)
+{
+	unsigned int ptr;
+
+	ptr = buffer & ~(CACHE_LINE_SIZE - 1);
+
+	while (ptr < buffer + size)
+	{
+		asm ("mcr p15, 0, %0, c7, c10, 1": :"r" (ptr));
+		ptr += CACHE_LINE_SIZE;
+	}
+}
+
+void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size)
+{
+	unsigned int ptr;
+
+	ptr = buffer & ~(CACHE_LINE_SIZE - 1);
+
+	while (ptr < buffer + size)
+	{
+		asm ("mcr p15, 0, %0, c7, c6, 1": :"r" (ptr));
+		ptr += CACHE_LINE_SIZE;
+	}
+}
+
+void mmu_invalidate_tlb()
+{
+	asm ("mcr p15, 0, %0, c8, c7, 0": :"r" (0));
+}
+
+void mmu_invalidate_icache()
+{
+	asm ("mcr p15, 0, %0, c7, c5, 0": :"r" (0));
+}
+
+void mmu_invalidate_dcache_all()
+{
+	asm ("mcr p15, 0, %0, c7, c6, 0": :"r" (0));
+}
+#endif
+
+/* level1 page table */
+static volatile unsigned int _pgd_table[4*1024] ALIGN(16*1024);
+/*
+ * level2 page table
+ * RT_MMU_PTE_SIZE must be 1024*n
+ */
+#define RT_MMU_PTE_SIZE		4096
+static volatile unsigned int _pte_table[RT_MMU_PTE_SIZE] ALIGN(1*1024);
+
+void mmu_create_pgd(struct mem_desc *mdesc)
+{
+	volatile rt_uint32_t *pTT;
+	volatile int i, nSec;
+	pTT = (rt_uint32_t *)_pgd_table + (mdesc->vaddr_start >> 20);
+	nSec = (mdesc->vaddr_end >> 20) - (mdesc->vaddr_start >> 20);
+	for(i = 0; i <= nSec; i++)
+	{
+		*pTT = mdesc->sect_attr | (((mdesc->paddr_start >> 20) + i) << 20);
+		pTT++;
+	}
+}
+
+void mmu_create_pte(struct mem_desc *mdesc)
+{
+	volatile rt_uint32_t *pTT;
+	volatile rt_uint32_t *p_pteentry;
+	int i;
+	rt_uint32_t vaddr;
+	rt_uint32_t total_page = 0;
+	rt_uint32_t pte_offset = 0;
+	rt_uint32_t sect_attr = 0;
+
+	total_page = (mdesc->vaddr_end >> 12) - (mdesc->vaddr_start >> 12) + 1;
+	pte_offset = mdesc->sect_attr & 0xfffffc00;
+	sect_attr = mdesc->sect_attr & 0x3ff;
+	vaddr = mdesc->vaddr_start;
+
+	for(i = 0; i < total_page; i++)
+	{
+		pTT = (rt_uint32_t *)_pgd_table + (vaddr >> 20);
+		if (*pTT == 0) /* Level 1 page table item not used, now update pgd item */
+		{
+			*pTT = pte_offset | sect_attr;
+			p_pteentry = (rt_uint32_t *)pte_offset +
+				((vaddr & 0x000ff000) >> 12);
+			pte_offset += 1024;
+		}
+		else /* using old Level 1 page table item */
+		{
+			p_pteentry = (rt_uint32_t *)(*pTT & 0xfffffc00) +
+				((vaddr & 0x000ff000) >> 12);
+		}
+
+
+		*p_pteentry = mdesc->page_attr | (((mdesc->paddr_start >> 12) + i) << 12);
+		vaddr += 0x1000;
+	}
+}
+
+static void build_pte_mem_desc(struct mem_desc *mdesc, rt_uint32_t size)
+{
+	rt_uint32_t pte_offset = 0;
+	rt_uint32_t nsec = 0;
+	/* set page table */
+	for (; size > 0; size--)
+	{
+		if (mdesc->mapped_mode == PAGE_MAPPED)
+		{
+			nsec = (RT_ALIGN(mdesc->vaddr_end, 0x100000) - RT_ALIGN_DOWN(mdesc->vaddr_start, 0x100000)) >> 20;
+			mdesc->sect_attr |= (((rt_uint32_t)_pte_table)& 0xfffffc00) + pte_offset;
+			pte_offset += nsec << 10;
+		}
+		if (pte_offset >= RT_MMU_PTE_SIZE)
+		{
+			rt_kprintf("PTE table size too little\n");
+			RT_ASSERT(0);
+		}
+
+		mdesc++;
+	}
+}
+
+
+void rt_hw_mmu_init(struct mem_desc *mdesc, rt_uint32_t size)
+{
+	/* disable I/D cache */
+	mmu_disable_dcache();
+	mmu_disable_icache();
+	mmu_disable();
+	mmu_invalidate_tlb();
+
+	/* clear pgd and pte table */
+	rt_memset((void *)_pgd_table, 0, 16*1024);
+	rt_memset((void *)_pte_table, 0, RT_MMU_PTE_SIZE);
+	build_pte_mem_desc(mdesc, size);
+	/* set page table */
+	for (; size > 0; size--)
+	{
+		if (mdesc->mapped_mode == SECT_MAPPED)
+		{
+			mmu_create_pgd(mdesc);
+		}
+		else
+		{
+			mmu_create_pte(mdesc);
+		}
+
+		mdesc++;
+	}
+
+	/* set MMU table address */
+	mmu_setttbase((rt_uint32_t)_pgd_table);
+
+	/* enables MMU */
+	mmu_enable();
+
+	/* enable Instruction Cache */
+	mmu_enable_icache();
+
+	/* enable Data Cache */
+	mmu_enable_dcache();
+
+	mmu_invalidate_icache();
+	mmu_invalidate_dcache_all();
+}
+

+ 208 - 0
libcpu/arm/armv6/mmu.h

@@ -0,0 +1,208 @@
+/*
+ * File      : mmu.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#ifndef __MMU_H__
+#define __MMU_H__
+
+#include <rtthread.h>
+
+#define CACHE_LINE_SIZE	32
+
+/*
+ * Hardware page table definitions.
+ *
+ * + Level 1 descriptor (PGD)
+ *   - common
+ */
+#define PGD_TYPE_MASK       (3 << 0)
+#define PGD_TYPE_FAULT      (0 << 0)
+#define PGD_TYPE_TABLE      (1 << 0)
+#define PGD_TYPE_SECT       (2 << 0)
+#define PGD_BIT4            (1 << 4)
+#define PGD_DOMAIN(x)       ((x) << 5)
+#define PGD_PROTECTION      (1 << 9)    /* ARMv5 */
+/*
+ *   - section
+ */
+#define PGD_SECT_BUFFERABLE	(1 << 2)
+#define PGD_SECT_CACHEABLE  (1 << 3)
+#define PGD_SECT_XN         (1 << 4)    /* ARMv6 */
+#define PGD_SECT_AP0        (1 << 10)
+#define PGD_SECT_AP1        (1 << 11)
+#define PGD_SECT_TEX(x)     ((x) << 12) /* ARMv5 */
+#define PGD_SECT_APX        (1 << 15)   /* ARMv6 */
+#define PGD_SECT_S          (1 << 16)   /* ARMv6 */
+#define PGD_SECT_nG         (1 << 17)   /* ARMv6 */
+#define PGD_SECT_SUPER      (1 << 18)   /* ARMv6 */
+
+#define PGD_SECT_UNCACHED   (0)
+#define PGD_SECT_BUFFERED   (PGD_SECT_BUFFERABLE)
+#define PGD_SECT_WT         (PGD_SECT_CACHEABLE)
+#define PGD_SECT_WB         (PGD_SECT_CACHEABLE | PGD_SECT_BUFFERABLE)
+#define PGD_SECT_MINICACHE  (PGD_SECT_TEX(1) | PGD_SECT_CACHEABLE)
+#define PGD_SECT_WBWA       (PGD_SECT_TEX(1) | PGD_SECT_CACHEABLE | PGD_SECT_BUFFERABLE)
+#define PGD_SECT_NONSHARED_DEV  (PGD_SECT_TEX(2))
+
+
+/*
+ * + Level 2 descriptor (PTE)
+ *   - common
+ */
+#define PTE_TYPE_MASK       (3 << 0)
+#define PTE_TYPE_FAULT      (0 << 0)
+#define PTE_TYPE_LARGE      (1 << 0)
+#define PTE_TYPE_SMALL      (2 << 0)
+#define PTE_TYPE_EXT        (3 << 0)    /* ARMv5 */
+#define PTE_BUFFERABLE      (1 << 2)
+#define PTE_CACHEABLE       (1 << 3)
+
+/*
+ *   - extended small page/tiny page
+ */
+#define PTE_EXT_XN          (1 << 0)    /* ARMv6 */
+#define PTE_EXT_AP_MASK     (3 << 4)
+#define PTE_EXT_AP0         (1 << 4)
+#define PTE_EXT_AP1         (2 << 4)
+#define PTE_EXT_AP_UNO_SRO  (0 << 4)
+#define PTE_EXT_AP_UNO_SRW  (PTE_EXT_AP0)
+#define PTE_EXT_AP_URO_SRW  (PTE_EXT_AP1)
+#define PTE_EXT_AP_URW_SRW  (PTE_EXT_AP1|PTE_EXT_AP0)
+#define PTE_EXT_TEX(x)      ((x) << 6)  /* ARMv5 */
+#define PTE_EXT_APX         (1 << 9)    /* ARMv6 */
+#define PTE_EXT_SHARED      (1 << 10)   /* ARMv6 */
+#define PTE_EXT_NG          (1 << 11)   /* ARMv6 */
+
+/*
+ *   - small page
+ */
+#define PTE_SMALL_AP_MASK       (0xff << 4)
+#define PTE_SMALL_AP_UNO_SRO    (0x00 << 4)
+#define PTE_SMALL_AP_UNO_SRW    (0x55 << 4)
+#define PTE_SMALL_AP_URO_SRW    (0xaa << 4)
+#define PTE_SMALL_AP_URW_SRW    (0xff << 4)
+
+
+/*
+ *  sector table properities
+ */
+#define SECT_CB          (PGD_SECT_CACHEABLE|PGD_SECT_BUFFERABLE) //cache_on, write_back
+#define SECT_CNB         (PGD_SECT_CACHEABLE)                     //cache_on, write_through
+#define SECT_NCB         (PGD_SECT_BUFFERABLE)                    //cache_off,WR_BUF on
+#define SECT_NCNB        (0 << 2)                                 //cache_off,WR_BUF off
+
+#define SECT_AP_RW       (PGD_SECT_AP0|PGD_SECT_AP1)              //supervisor=RW, user=RW
+#define SECT_AP_RO       (PGD_SECT_AP0|PGD_SECT_AP1|PGD_SECT_APX) //supervisor=RO, user=RO
+
+#define SECT_RWX_CB      (SECT_AP_RW|PGD_DOMAIN(0)|PGD_SECT_WB|PGD_TYPE_SECT) /* Read/Write/executable, cache, write back */
+#define SECT_RWX_CNB     (SECT_AP_RW|PGD_DOMAIN(0)|PGD_SECT_WT|PGD_TYPE_SECT) /* Read/Write/executable, cache, write through */
+#define SECT_RWX_NCNB    (SECT_AP_RW|PGD_DOMAIN(0)|PGD_TYPE_SECT) /* Read/Write/executable without cache and write buffer */
+#define SECT_RWX_FAULT   (SECT_AP_RW|PGD_DOMAIN(1)|PGD_TYPE_SECT) /* Read/Write without cache and write buffer */
+
+#define SECT_RWNX_CB     (SECT_AP_RW|PGD_DOMAIN(0)|PGD_SECT_WB|PGD_TYPE_SECT|PGD_SECT_XN) /* Read/Write, cache, write back */
+#define SECT_RWNX_CNB    (SECT_AP_RW|PGD_DOMAIN(0)|PGD_SECT_WT|PGD_TYPE_SECT|PGD_SECT_XN) /* Read/Write, cache, write through */
+#define SECT_RWNX_NCNB   (SECT_AP_RW|PGD_DOMAIN(0)|PGD_TYPE_SECT|PGD_SECT_XN) /* Read/Write without cache and write buffer */
+#define SECT_RWNX_FAULT  (SECT_AP_RW|PGD_DOMAIN(1)|PGD_TYPE_SECT|PGD_SECT_XN) /* Read/Write without cache and write buffer */
+
+
+#define SECT_ROX_CB      (SECT_AP_RO|PGD_DOMAIN(0)|PGD_SECT_WB|PGD_TYPE_SECT) /* Read Only/executable, cache, write back */
+#define SECT_ROX_CNB     (SECT_AP_RO|PGD_DOMAIN(0)|PGD_SECT_WT|PGD_TYPE_SECT) /* Read Only/executable, cache, write through */
+#define SECT_ROX_NCNB    (SECT_AP_RO|PGD_DOMAIN(0)|PGD_TYPE_SECT) /* Read Only/executable without cache and write buffer */
+#define SECT_ROX_FAULT   (SECT_AP_RO|PGD_DOMAIN(1)|PGD_TYPE_SECT) /* Read Only without cache and write buffer */
+
+#define SECT_RONX_CB     (SECT_AP_RO|PGD_DOMAIN(0)|PGD_SECT_WB|PGD_TYPE_SECT|PGD_SECT_XN) /* Read Only, cache, write back */
+#define SECT_RONX_CNB    (SECT_AP_RO|PGD_DOMAIN(0)|PGD_SECT_WT|PGD_TYPE_SECT|PGD_SECT_XN) /* Read Only, cache, write through */
+#define SECT_RONX_NCNB   (SECT_AP_RO|PGD_DOMAIN(0)|PGD_TYPE_SECT|PGD_SECT_XN) /* Read Only without cache and write buffer */
+#define SECT_RONX_FAULT  (SECT_AP_RO|PGD_DOMAIN(1)|PGD_TYPE_SECT|PGD_SECT_XN) /* Read Only without cache and write buffer */
+
+#define SECT_TO_PAGE     (PGD_DOMAIN(0)|PGD_TYPE_TABLE) /* Level 2 descriptor (PTE) entry properity */
+
+/*
+ * page table properities
+ */
+#define PAGE_CB          (PTE_BUFFERABLE|PTE_CACHEABLE)  //cache_on, write_back
+#define PAGE_CNB         (PTE_CACHEABLE)                 //cache_on, write_through
+#define PAGE_NCB         (PTE_BUFFERABLE)                //cache_off,WR_BUF on
+#define PAGE_NCNB        (0 << 2)                        //cache_off,WR_BUF off
+
+#define PAGE_AP_RW       (PTE_EXT_AP0|PTE_EXT_AP1)             //supervisor=RW, user=RW
+#define PAGE_AP_RO       (PTE_EXT_AP0|PTE_EXT_AP1|PTE_EXT_APX) //supervisor=RO, user=RO
+
+#define PAGE_RWX_CB      (PAGE_AP_RW|PAGE_CB|PTE_TYPE_SMALL) /* Read/Write/executable, cache, write back */
+#define PAGE_RWX_CNB     (PAGE_AP_RW|PAGE_CNB|PTE_TYPE_SMALL) /* Read/Write/executable, cache, write through */
+#define PAGE_RWX_NCNB    (PAGE_AP_RW|PTE_TYPE_SMALL) /* Read/Write/executable without cache and write buffer */
+#define PAGE_RWX_FAULT   (PAGE_AP_RW|PTE_TYPE_SMALL) /* Read/Write without cache and write buffer */
+
+#define PAGE_RWNX_CB     (PAGE_AP_RW|PAGE_CB|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read/Write, cache, write back */
+#define PAGE_RWNX_CNB    (PAGE_AP_RW|PAGE_CNB|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read/Write, cache, write through */
+#define PAGE_RWNX_NCNB   (PAGE_AP_RW|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read/Write without cache and write buffer */
+#define PAGE_RWNX_FAULT  (PAGE_AP_RW|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read/Write without cache and write buffer */
+
+
+#define PAGE_ROX_CB      (PAGE_AP_RO|PAGE_CB|PTE_TYPE_SMALL) /* Read Only/executable, cache, write back */
+#define PAGE_ROX_CNB     (PAGE_AP_RO|PAGE_CNB|PTE_TYPE_SMALL) /* Read Only/executable, cache, write through */
+#define PAGE_ROX_NCNB    (PAGE_AP_RO|PTE_TYPE_SMALL) /* Read Only/executable without cache and write buffer */
+#define PAGE_ROX_FAULT   (PAGE_AP_RO|PTE_TYPE_SMALL) /* Read Only without cache and write buffer */
+
+#define PAGE_RONX_CB     (PAGE_AP_RO|PAGE_CB|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read Only, cache, write back */
+#define PAGE_RONX_CNB    (PAGE_AP_RO|PAGE_CNB|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read Only, cache, write through */
+#define PAGE_RONX_NCNB   (PAGE_AP_RO|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read Only without cache and write buffer */
+#define PAGE_RONX_FAULT  (PAGE_AP_RO|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read Only without cache and write buffer */
+
+
+#define DESC_SEC		(0x2|(1<<4))
+#define CB				(3<<2)  //cache_on, write_back
+#define CNB				(2<<2)  //cache_on, write_through
+#define NCB				(1<<2)  //cache_off,WR_BUF on
+#define NCNB			(0<<2)  //cache_off,WR_BUF off
+#define AP_RW			(3<<10) //supervisor=RW, user=RW
+#define AP_RO			(2<<10) //supervisor=RW, user=RO
+
+#define DOMAIN_FAULT	(0x0)
+#define DOMAIN_CHK		(0x1)
+#define DOMAIN_NOTCHK	(0x3)
+#define DOMAIN0			(0x0<<5)
+#define DOMAIN1			(0x1<<5)
+
+#define DOMAIN0_ATTR	(DOMAIN_CHK<<0)
+#define DOMAIN1_ATTR	(DOMAIN_FAULT<<2)
+
+#define RW_CB		(AP_RW|DOMAIN0|CB|DESC_SEC)		/* Read/Write, cache, write back */
+#define RW_CNB		(AP_RW|DOMAIN0|CNB|DESC_SEC)	/* Read/Write, cache, write through */
+#define RW_NCNB		(AP_RW|DOMAIN0|NCNB|DESC_SEC)	/* Read/Write without cache and write buffer */
+#define RW_FAULT	(AP_RW|DOMAIN1|NCNB|DESC_SEC)	/* Read/Write without cache and write buffer */
+
+struct mem_desc {
+	rt_uint32_t vaddr_start;
+	rt_uint32_t vaddr_end;
+	rt_uint32_t paddr_start;
+	rt_uint32_t sect_attr;   /* when page mapped */
+	rt_uint32_t page_attr;   /* only sector mapped valid */
+	rt_uint32_t mapped_mode;
+#define     SECT_MAPPED  0
+#define     PAGE_MAPPED  1
+};
+
+void rt_hw_mmu_init(struct mem_desc *mdesc, rt_uint32_t size);
+
+#endif
+

+ 79 - 0
libcpu/arm/armv6/stack.c

@@ -0,0 +1,79 @@
+/*
+ * File      : stack.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2011-01-13     weety      copy from mini2440
+ */
+#include <rtthread.h>
+
+/*****************************/
+/* CPU Mode                  */
+/*****************************/
+#define USERMODE		0x10
+#define FIQMODE			0x11
+#define IRQMODE			0x12
+#define SVCMODE			0x13
+#define ABORTMODE		0x17
+#define UNDEFMODE		0x1b
+#define MODEMASK		0x1f
+#define NOINT			0xc0
+
+/**
+ * This function will initialize thread stack
+ *
+ * @param tentry the entry of thread
+ * @param parameter the parameter of entry 
+ * @param stack_addr the beginning stack address
+ * @param texit the function will be called when thread exit
+ *
+ * @return stack address
+ */
+rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter,
+	rt_uint8_t *stack_addr, void *texit)
+{
+	rt_uint32_t *stk;
+
+	stk 	 = (rt_uint32_t*)stack_addr;
+	*(stk) 	 = (rt_uint32_t)tentry;			/* entry point */
+	*(--stk) = (rt_uint32_t)texit;			/* lr */
+	*(--stk) = 0;							/* r12 */
+	*(--stk) = 0;							/* r11 */
+	*(--stk) = 0;							/* r10 */
+	*(--stk) = 0;							/* r9 */
+	*(--stk) = 0;							/* r8 */
+	*(--stk) = 0;							/* r7 */
+	*(--stk) = 0;							/* r6 */
+	*(--stk) = 0;							/* r5 */
+	*(--stk) = 0;							/* r4 */
+	*(--stk) = 0;							/* r3 */
+	*(--stk) = 0;							/* r2 */
+	*(--stk) = 0;							/* r1 */
+	*(--stk) = (rt_uint32_t)parameter;		/* r0 : argument */
+
+	/* cpsr */
+	if ((rt_uint32_t)tentry & 0x01)
+		*(--stk) = SVCMODE | 0x20;			/* thumb mode */
+	else
+		*(--stk) = SVCMODE;					/* arm mode   */
+
+	/* return task's current stack address */
+	return (rt_uint8_t *)stk;
+}
+

+ 161 - 0
libcpu/arm/armv6/vfp.c

@@ -0,0 +1,161 @@
+/*
+ * File      : vfp.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006, RT-Thread Develop Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2014-11-07     weety      first version
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+#include "vfp.h"
+
+#ifdef RT_USING_VFP
+
+rt_uint32_t vfpregs_offset = offsetof(struct rt_thread, vfpregs);
+
+struct vfp_context *last_vfp_context = RT_NULL;
+
+int vfp_switch(rt_uint32_t cmd, struct rt_thread *thread)
+{
+	rt_uint32_t fpexc;
+	//rt_kprintf("%s:%d, %x\n", __func__, cmd, thread);
+
+	switch (cmd) {
+		case THREAD_INIT:
+		{
+			struct vfp_context *vfp = &thread->vfpregs;
+
+			rt_memset(vfp, 0, sizeof(struct vfp_context));
+			vfp->fpexc = FPEXC_EN;
+			vfp->fpscr = FPSCR_RN;
+
+			if (last_vfp_context == vfp)
+				last_vfp_context = RT_NULL;
+			vmsr(FPEXC, vmrs(FPEXC) & ~FPEXC_EN);
+			break;
+		}
+		case THREAD_EXIT:
+		{
+				/* release case: Per-thread VFP cleanup. */
+			struct vfp_context *vfp = &thread->vfpregs;
+
+			if (last_vfp_context == vfp)
+				last_vfp_context = RT_NULL;
+			break;
+		}
+		default:
+			break;
+	}
+
+	return 0;
+}
+
+int vfp_thread_init(struct rt_thread *thread)
+{
+	return vfp_switch(THREAD_INIT, thread);
+}
+
+
+int vfp_thread_exit(struct rt_thread *thread)
+{
+	return vfp_switch(THREAD_EXIT, thread);
+}
+
+rt_uint32_t read_vfp_regs(rt_uint32_t *buf)
+{
+	rt_uint32_t value;
+	rt_uint32_t length;
+	asm  volatile ("vldmia  %0!, {d0-d15}"
+			:
+			:"r"(buf)
+			:"cc");
+	length = 32;
+#ifdef RT_USING_VFPv3
+	asm  volatile ("vmrs  %0, mvfr0"
+			:"=r"(value)
+			:);
+	if ((value & MVFR0_A_SIMD_MASK) == 2)
+	{
+		asm  volatile ("vldmia  %0!, {d16-d31}"
+				:
+				:"r"(buf)
+				:"cc");
+		length = 64;
+	}
+	else
+	{
+		length = 32;
+	}
+#endif
+
+	return length;
+}
+
+void vfp_exception(rt_uint32_t instruction, rt_uint32_t fpexc)
+{
+	int i = 0;
+	int length = 0;
+	rt_uint32_t fpscr, fpsid;
+#ifdef RT_USING_VFPv3
+	unsigned long long vfp_regs[32];
+#else
+	unsigned long long vfp_regs[16];
+#endif
+
+	rt_kprintf("VFP: exception: instruction %08x fpexc %08x\n", instruction, fpexc);
+	fpsid = vmrs(FPSID);
+	fpscr = vmrs(FPSCR);
+	rt_kprintf("VFP: exception: fpsid %08x fpscr %08x\n", fpsid, fpscr);
+
+	length = read_vfp_regs((rt_uint32_t *)vfp_regs);
+	rt_kprintf("VFP: exception registers: {s0~s%d}\n", length - 1);
+	for(i = 0; i < length; i++)
+	{
+		if (i && !(i & 0x3))
+			rt_kprintf("\n");
+		rt_kprintf("0x%08x ", ((rt_uint32_t *)vfp_regs)[i]);
+	}
+	rt_kprintf("\n");
+	
+}
+
+void vfp_init(void)
+{
+	int ret = 0;
+	unsigned int value;
+	asm  volatile ("mrc p15, 0, %0, c1, c0, 2"
+			:"=r"(value)
+			:);
+	value |= 0xf00000;/*enable CP10, CP11 user access*/
+	asm volatile("mcr p15, 0, %0, c1, c0, 2"
+			:
+			:"r"(value));
+#if 0
+	asm volatile("fmrx %0, fpexc"
+			:"=r"(value));
+	value |=(1<<30);
+	asm volatile("fmxr fpexc, %0"
+			:
+			:"r"(value));
+#endif
+}
+
+
+#endif

+ 110 - 0
libcpu/arm/armv6/vfp.h

@@ -0,0 +1,110 @@
+/*
+ * File      : vfp.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006, RT-Thread Develop Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2014-11-07     weety      first version
+ */
+
+#ifndef __VFP_H__
+#define __VFP_H__
+
+/* FPSID register bits */
+#define FPSID_IMPLEMENTER_BIT   (24)
+#define FPSID_IMPLEMENTER_MASK  (0xff << FPSID_IMPLEMENTER_BIT)
+#define FPSID_SW                (1 << 23)
+#define FPSID_FORMAT_BIT        (21)
+#define FPSID_FORMAT_MASK       (0x3 << FPSID_FORMAT_BIT)
+#define FPSID_NODOUBLE          (1 << 20)
+#define FPSID_ARCH_BIT          (16)
+#define FPSID_ARCH_MASK         (0xF << FPSID_ARCH_BIT)
+#define FPSID_PART_BIT          (8)
+#define FPSID_PART_MASK         (0xFF << FPSID_PART_BIT)
+#define FPSID_VARIANT_BIT       (4)
+#define FPSID_VARIANT_MASK      (0xF << FPSID_VARIANT_BIT)
+#define FPSID_REVISION_BIT      (0)
+#define FPSID_REVISION_MASK     (0xF << FPSID_REVISION_BIT)
+
+/* FPSCR register bits */
+#define FPSCR_DN           (1<<25) /* Default NaN mode enable bit */
+#define FPSCR_FZ           (1<<24) /* Flush-to-zero mode enable bit */
+#define FPSCR_RN           (0<<22) /* Round to nearest (RN) mode */
+#define FPSCR_RP           (1<<22) /* Round towards plus infinity (RP) mode */
+#define FPSCR_RM           (2<<22) /* Round towards minus infinity (RM) mode */
+#define FPSCR_RZ           (3<<22) /* Round towards zero (RZ) mode */
+#define FPSCR_RMODE_BIT    (22)
+#define FPSCR_RMODE_MASK   (3 << FPSCR_RMODE_BIT)
+#define FPSCR_STRIDE_BIT   (20)
+#define FPSCR_STRIDE_MASK  (3 << FPSCR_STRIDE_BIT)
+#define FPSCR_LENGTH_BIT   (16)
+#define FPSCR_LENGTH_MASK  (7 << FPSCR_LENGTH_BIT)
+#define FPSCR_IDE          (1<<15) /* Input Subnormal exception trap enable bit */
+#define FPSCR_IXE          (1<<12) /* Inexact exception trap enable bit */
+#define FPSCR_UFE          (1<<11) /* Underflow exception trap enable bit */
+#define FPSCR_OFE          (1<<10) /* Overflow exception trap enable bit */
+#define FPSCR_DZE          (1<<9)  /* Division by Zero exception trap enable bit */
+#define FPSCR_IOE          (1<<8)  /* Invalid Operation exception trap enable bit */
+#define FPSCR_IDC          (1<<7)  /* Input Subnormal cumulative exception flag */
+#define FPSCR_IXC          (1<<4)  /* Inexact cumulative exception flag */
+#define FPSCR_UFC          (1<<3)  /* Underflow cumulative exception flag */
+#define FPSCR_OFC          (1<<2)  /* Overflow cumulative exception flag */
+#define FPSCR_DZC          (1<<1)  /* Division by Zero cumulative exception flag */
+#define FPSCR_IOC          (1<<0)  /* Invalid Operation cumulative exception flag */
+
+/* FPEXC register bits */
+#define FPEXC_EX          (1 << 31) /* When EX is set, the VFP coprocessor is in the exceptional state */
+#define FPEXC_EN          (1 << 30) /* VFP enable bit */
+#define FPEXC_DEX         (1 << 29) /* Defined synchronous instruction exceptional flag */
+#define FPEXC_FP2V        (1 << 28) /*  FPINST2 instruction valid flag */
+#define FPEXC_LENGTH_BIT  (8)
+#define FPEXC_LENGTH_MASK (7 << FPEXC_LENGTH_BIT)
+#define FPEXC_INV         (1 << 7)  /* Input exception flag */
+#define FPEXC_UFC         (1 << 3)  /* Potential underflow flag */
+#define FPEXC_OFC         (1 << 2)  /* Potential overflow flag */
+#define FPEXC_IOC         (1 << 0)  /* Potential invalid operation flag */
+#define FPEXC_TRAP_MASK   (FPEXC_INV|FPEXC_UFC|FPEXC_OFC|FPEXC_IOC)
+
+
+/* MVFR0 register bits */
+#define MVFR0_A_SIMD_BIT    (0)
+#define MVFR0_A_SIMD_MASK   (0xf << MVFR0_A_SIMD_BIT)
+
+
+/* thread switch micro */
+#define THREAD_INIT   0
+#define THREAD_EXIT   1
+
+/*
+ * get VFP register
+ */
+
+#define vmrs(vfp) ({ \
+    rt_uint32_t var; \
+    asm("vmrs  %0, "#vfp"" : "=r" (var) : : "cc"); \
+    var; \
+ })
+
+#define vmsr(vfp, var) \
+    asm("vmsr  "#vfp",  %0"	\
+       : : "r" (var) : "cc")
+
+
+#endif
+
+

Some files were not shown because too many files changed in this diff