Просмотр исходного кода

[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 10 лет назад
Родитель
Сommit
43f68131ce
100 измененных файлов с 23246 добавлено и 0 удалено
  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
+
+

Некоторые файлы не были показаны из-за большого количества измененных файлов