summaryrefslogtreecommitdiff
path: root/bsp/fh8620
diff options
context:
space:
mode:
authorBernard Xiong <[email protected]>2016-04-18 13:52:39 +0800
committerBernard Xiong <[email protected]>2016-04-18 13:52:39 +0800
commit43f68131ce64fbb4c3e476e684f3d06919ebd5af (patch)
tree4bc755c1f350d2fbb30ae7c1c050be4d3d2125a5 /bsp/fh8620
parent6d03ce9a7bfd4ff94665465d1c07f6c816fe19a2 (diff)
[BSP] Add fh8620 bsp from Shanghai Fullhan Microelectronics Co., Ltd.
FH8620 BSP Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. All rights reserved
Diffstat (limited to 'bsp/fh8620')
-rw-r--r--bsp/fh8620/SConscript14
-rw-r--r--bsp/fh8620/SConstruct33
-rw-r--r--bsp/fh8620/applications/SConscript11
-rw-r--r--bsp/fh8620/applications/main.c45
-rw-r--r--bsp/fh8620/drivers/SConscript9
-rw-r--r--bsp/fh8620/drivers/acw.c1386
-rw-r--r--bsp/fh8620/drivers/acw.h232
-rw-r--r--bsp/fh8620/drivers/dma.c170
-rw-r--r--bsp/fh8620/drivers/dma.h107
-rw-r--r--bsp/fh8620/drivers/dma_mem.c122
-rw-r--r--bsp/fh8620/drivers/dma_mem.h76
-rw-r--r--bsp/fh8620/drivers/fh_dma.c1618
-rw-r--r--bsp/fh8620/drivers/fh_dma.h254
-rw-r--r--bsp/fh8620/drivers/gpio.c450
-rw-r--r--bsp/fh8620/drivers/gpio.h188
-rw-r--r--bsp/fh8620/drivers/i2c.c520
-rw-r--r--bsp/fh8620/drivers/i2c.h56
-rw-r--r--bsp/fh8620/drivers/interrupt.c216
-rw-r--r--bsp/fh8620/drivers/interrupt.h40
-rw-r--r--bsp/fh8620/drivers/mem_process.c87
-rw-r--r--bsp/fh8620/drivers/mmc.c710
-rw-r--r--bsp/fh8620/drivers/mmc.h51
-rw-r--r--bsp/fh8620/drivers/pwm.c226
-rw-r--r--bsp/fh8620/drivers/pwm.h57
-rw-r--r--bsp/fh8620/drivers/sadc.c416
-rw-r--r--bsp/fh8620/drivers/sadc.h109
-rw-r--r--bsp/fh8620/drivers/spi_fh_adapt.c212
-rw-r--r--bsp/fh8620/drivers/spi_fh_adapt.h71
-rw-r--r--bsp/fh8620/drivers/ssi.c878
-rw-r--r--bsp/fh8620/drivers/ssi.h134
-rw-r--r--bsp/fh8620/drivers/trap.c197
-rw-r--r--bsp/fh8620/drivers/uart.c292
-rw-r--r--bsp/fh8620/drivers/uart.h33
-rw-r--r--bsp/fh8620/drivers/wdt.c269
-rw-r--r--bsp/fh8620/drivers/wdt.h46
-rw-r--r--bsp/fh8620/libraries/SConscript14
-rw-r--r--bsp/fh8620/libraries/driverlib/SConscript9
-rw-r--r--bsp/fh8620/libraries/driverlib/fh_gpio.c27
-rw-r--r--bsp/fh8620/libraries/driverlib/fh_i2c.c311
-rw-r--r--bsp/fh8620/libraries/driverlib/fh_ictl.c69
-rw-r--r--bsp/fh8620/libraries/driverlib/fh_mmc.c413
-rw-r--r--bsp/fh8620/libraries/driverlib/fh_pwm.c42
-rw-r--r--bsp/fh8620/libraries/driverlib/fh_sdio.c2085
-rw-r--r--bsp/fh8620/libraries/driverlib/fh_spi.c164
-rw-r--r--bsp/fh8620/libraries/driverlib/fh_timer.c144
-rw-r--r--bsp/fh8620/libraries/driverlib/fh_uart.c278
-rw-r--r--bsp/fh8620/libraries/driverlib/fh_wdt.c58
-rw-r--r--bsp/fh8620/libraries/inc/fh_driverlib.h39
-rw-r--r--bsp/fh8620/libraries/inc/fh_gpio.h54
-rw-r--r--bsp/fh8620/libraries/inc/fh_i2c.h226
-rw-r--r--bsp/fh8620/libraries/inc/fh_ictl.h58
-rw-r--r--bsp/fh8620/libraries/inc/fh_mmc.h225
-rw-r--r--bsp/fh8620/libraries/inc/fh_pwm.h44
-rw-r--r--bsp/fh8620/libraries/inc/fh_sdio.h356
-rw-r--r--bsp/fh8620/libraries/inc/fh_spi.h148
-rw-r--r--bsp/fh8620/libraries/inc/fh_timer.h100
-rw-r--r--bsp/fh8620/libraries/inc/fh_uart.h245
-rw-r--r--bsp/fh8620/libraries/inc/fh_wdt.h65
-rw-r--r--bsp/fh8620/libraries/startup/SConscript10
-rw-r--r--bsp/fh8620/libraries/startup/gcc/start_gcc.S416
-rw-r--r--bsp/fh8620/link.ld96
-rw-r--r--bsp/fh8620/platform/SConscript15
-rw-r--r--bsp/fh8620/platform/board.h33
-rw-r--r--bsp/fh8620/platform/board_info.h83
-rw-r--r--bsp/fh8620/platform/common/SConscript8
-rw-r--r--bsp/fh8620/platform/common/board_info.c250
-rw-r--r--bsp/fh8620/platform/common/chkenv.c120
-rw-r--r--bsp/fh8620/platform/fh8620/SConscript15
-rw-r--r--bsp/fh8620/platform/fh8620/arch.h117
-rw-r--r--bsp/fh8620/platform/fh8620/iot_cam/SConscript9
-rw-r--r--bsp/fh8620/platform/fh8620/iot_cam/board.c692
-rw-r--r--bsp/fh8620/platform/fh8620/iot_cam/board_def.h106
-rw-r--r--bsp/fh8620/platform/fh8620/iot_cam/iomux.c668
-rw-r--r--bsp/fh8620/platform/fh8620/iot_cam/readme4
-rw-r--r--bsp/fh8620/platform/fh8620/iot_cam/startup.c123
-rw-r--r--bsp/fh8620/platform/fh_arch.h44
-rw-r--r--bsp/fh8620/platform/fh_def.h90
-rw-r--r--bsp/fh8620/platform/plat-v2/SConscript13
-rw-r--r--bsp/fh8620/platform/plat-v2/arch.h116
-rw-r--r--bsp/fh8620/platform/plat-v2/clock.c2658
-rw-r--r--bsp/fh8620/platform/plat-v2/clock.h62
-rw-r--r--bsp/fh8620/platform/plat-v2/fh_pmu.c62
-rw-r--r--bsp/fh8620/platform/plat-v2/fh_pmu.h59
-rw-r--r--bsp/fh8620/platform/plat-v2/iomux.c284
-rw-r--r--bsp/fh8620/platform/plat-v2/iomux.h314
-rw-r--r--bsp/fh8620/platform/plat-v2/reset.c50
-rw-r--r--bsp/fh8620/platform/plat-v2/timer.c109
-rw-r--r--bsp/fh8620/platform/plat-v2/timer.h36
-rw-r--r--bsp/fh8620/platform/platform_def.h81
-rw-r--r--bsp/fh8620/rtconfig.h208
-rw-r--r--bsp/fh8620/rtconfig.py44
91 files changed, 21504 insertions, 0 deletions
diff --git a/bsp/fh8620/SConscript b/bsp/fh8620/SConscript
new file mode 100644
index 0000000000..fe0ae941ae
--- /dev/null
+++ b/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')
diff --git a/bsp/fh8620/SConstruct b/bsp/fh8620/SConstruct
new file mode 100644
index 0000000000..7f9e572807
--- /dev/null
+++ b/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)
diff --git a/bsp/fh8620/applications/SConscript b/bsp/fh8620/applications/SConscript
new file mode 100644
index 0000000000..85d211cf16
--- /dev/null
+++ b/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')
diff --git a/bsp/fh8620/applications/main.c b/bsp/fh8620/applications/main.c
new file mode 100644
index 0000000000..dd6172051b
--- /dev/null
+++ b/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;
+}
diff --git a/bsp/fh8620/drivers/SConscript b/bsp/fh8620/drivers/SConscript
new file mode 100644
index 0000000000..e9f7715967
--- /dev/null
+++ b/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')
diff --git a/bsp/fh8620/drivers/acw.c b/bsp/fh8620/drivers/acw.c
new file mode 100644
index 0000000000..1d73f1feca
--- /dev/null
+++ b/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
+
diff --git a/bsp/fh8620/drivers/acw.h b/bsp/fh8620/drivers/acw.h
new file mode 100644
index 0000000000..2156d343f4
--- /dev/null
+++ b/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
diff --git a/bsp/fh8620/drivers/dma.c b/bsp/fh8620/drivers/dma.c
new file mode 100644
index 0000000000..394ac2a6a3
--- /dev/null
+++ b/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;
+}
+
+
+
+
diff --git a/bsp/fh8620/drivers/dma.h b/bsp/fh8620/drivers/dma.h
new file mode 100644
index 0000000000..c8c3fbf574
--- /dev/null
+++ b/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
+
diff --git a/bsp/fh8620/drivers/dma_mem.c b/bsp/fh8620/drivers/dma_mem.c
new file mode 100644
index 0000000000..52c9e56b4a
--- /dev/null
+++ b/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
+
diff --git a/bsp/fh8620/drivers/dma_mem.h b/bsp/fh8620/drivers/dma_mem.h
new file mode 100644
index 0000000000..b431703a4a
--- /dev/null
+++ b/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
+
diff --git a/bsp/fh8620/drivers/fh_dma.c b/bsp/fh8620/drivers/fh_dma.c
new file mode 100644
index 0000000000..c50ae1e1df
--- /dev/null
+++ b/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");
+
+}
diff --git a/bsp/fh8620/drivers/fh_dma.h b/bsp/fh8620/drivers/fh_dma.h
new file mode 100644
index 0000000000..faceac2deb
--- /dev/null
+++ b/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_ */
+
diff --git a/bsp/fh8620/drivers/gpio.c b/bsp/fh8620/drivers/gpio.c
new file mode 100644
index 0000000000..d7d325ad00
--- /dev/null
+++ b/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__);
+}
+
+
diff --git a/bsp/fh8620/drivers/gpio.h b/bsp/fh8620/drivers/gpio.h
new file mode 100644
index 0000000000..7fe4d236b7
--- /dev/null
+++ b/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_ */
diff --git a/bsp/fh8620/drivers/i2c.c b/bsp/fh8620/drivers/i2c.c
new file mode 100644
index 0000000000..41f2c059f9
--- /dev/null
+++ b/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
+
diff --git a/bsp/fh8620/drivers/i2c.h b/bsp/fh8620/drivers/i2c.h
new file mode 100644
index 0000000000..9046bd81cb
--- /dev/null
+++ b/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
diff --git a/bsp/fh8620/drivers/interrupt.c b/bsp/fh8620/drivers/interrupt.c
new file mode 100644
index 0000000000..a865af17b3
--- /dev/null
+++ b/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
+
diff --git a/bsp/fh8620/drivers/interrupt.h b/bsp/fh8620/drivers/interrupt.h
new file mode 100644
index 0000000000..575b0a5442
--- /dev/null
+++ b/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_ */
diff --git a/bsp/fh8620/drivers/mem_process.c b/bsp/fh8620/drivers/mem_process.c
new file mode 100644
index 0000000000..4ef7e2d599
--- /dev/null
+++ b/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
diff --git a/bsp/fh8620/drivers/mmc.c b/bsp/fh8620/drivers/mmc.c
new file mode 100644
index 0000000000..399efd5829
--- /dev/null
+++ b/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__);
+}
diff --git a/bsp/fh8620/drivers/mmc.h b/bsp/fh8620/drivers/mmc.h
new file mode 100644
index 0000000000..38a404e857
--- /dev/null
+++ b/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_ */
diff --git a/bsp/fh8620/drivers/pwm.c b/bsp/fh8620/drivers/pwm.c
new file mode 100644
index 0000000000..c6c20a259e
--- /dev/null
+++ b/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__);
+}
+
diff --git a/bsp/fh8620/drivers/pwm.h b/bsp/fh8620/drivers/pwm.h
new file mode 100644
index 0000000000..3693ab7973
--- /dev/null
+++ b/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_ */
diff --git a/bsp/fh8620/drivers/sadc.c b/bsp/fh8620/drivers/sadc.c
new file mode 100644
index 0000000000..bc994e5218
--- /dev/null
+++ b/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
diff --git a/bsp/fh8620/drivers/sadc.h b/bsp/fh8620/drivers/sadc.h
new file mode 100644
index 0000000000..d28ed9ba24
--- /dev/null
+++ b/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_ */
diff --git a/bsp/fh8620/drivers/spi_fh_adapt.c b/bsp/fh8620/drivers/spi_fh_adapt.c
new file mode 100644
index 0000000000..291fe9a4f9
--- /dev/null
+++ b/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;
+}
diff --git a/bsp/fh8620/drivers/spi_fh_adapt.h b/bsp/fh8620/drivers/spi_fh_adapt.h
new file mode 100644
index 0000000000..171fdf7184
--- /dev/null
+++ b/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_ */
+
+
+
+
+
diff --git a/bsp/fh8620/drivers/ssi.c b/bsp/fh8620/drivers/ssi.c
new file mode 100644
index 0000000000..e5cb99042e
--- /dev/null
+++ b/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
diff --git a/bsp/fh8620/drivers/ssi.h b/bsp/fh8620/drivers/ssi.h
new file mode 100644
index 0000000000..6418de1508
--- /dev/null
+++ b/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_ */
diff --git a/bsp/fh8620/drivers/trap.c b/bsp/fh8620/drivers/trap.c
new file mode 100644
index 0000000000..7cdf2dd765
--- /dev/null
+++ b/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");
+}
+
+/*@}*/
diff --git a/bsp/fh8620/drivers/uart.c b/bsp/fh8620/drivers/uart.c
new file mode 100644
index 0000000000..27d812e16f
--- /dev/null
+++ b/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
+
+}
+
+
diff --git a/bsp/fh8620/drivers/uart.h b/bsp/fh8620/drivers/uart.h
new file mode 100644
index 0000000000..d4459f02f8
--- /dev/null
+++ b/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
diff --git a/bsp/fh8620/drivers/wdt.c b/bsp/fh8620/drivers/wdt.c
new file mode 100644
index 0000000000..1d67007a6a
--- /dev/null
+++ b/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
diff --git a/bsp/fh8620/drivers/wdt.h b/bsp/fh8620/drivers/wdt.h
new file mode 100644
index 0000000000..768a2e0739
--- /dev/null
+++ b/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_ */
diff --git a/bsp/fh8620/libraries/SConscript b/bsp/fh8620/libraries/SConscript
new file mode 100644
index 0000000000..cc2296bd47
--- /dev/null
+++ b/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')
diff --git a/bsp/fh8620/libraries/driverlib/SConscript b/bsp/fh8620/libraries/driverlib/SConscript
new file mode 100644
index 0000000000..3fc86c3730
--- /dev/null
+++ b/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')
diff --git a/bsp/fh8620/libraries/driverlib/fh_gpio.c b/bsp/fh8620/libraries/driverlib/fh_gpio.c
new file mode 100644
index 0000000000..e3e58f9a1f
--- /dev/null
+++ b/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
+ */
+
+ \ No newline at end of file
diff --git a/bsp/fh8620/libraries/driverlib/fh_i2c.c b/bsp/fh8620/libraries/driverlib/fh_i2c.c
new file mode 100644
index 0000000000..58aa70206c
--- /dev/null
+++ b/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);
+}
diff --git a/bsp/fh8620/libraries/driverlib/fh_ictl.c b/bsp/fh8620/libraries/driverlib/fh_ictl.c
new file mode 100644
index 0000000000..a53c8dba34
--- /dev/null
+++ b/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));
+
+ }
+
+}
diff --git a/bsp/fh8620/libraries/driverlib/fh_mmc.c b/bsp/fh8620/libraries/driverlib/fh_mmc.c
new file mode 100644
index 0000000000..47ac75239a
--- /dev/null
+++ b/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);
+}
diff --git a/bsp/fh8620/libraries/driverlib/fh_pwm.c b/bsp/fh8620/libraries/driverlib/fh_pwm.c
new file mode 100644
index 0000000000..af19110a46
--- /dev/null
+++ b/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);
+}
diff --git a/bsp/fh8620/libraries/driverlib/fh_sdio.c b/bsp/fh8620/libraries/driverlib/fh_sdio.c
new file mode 100644
index 0000000000..8c9e69e07d
--- /dev/null
+++ b/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;
+}
+
diff --git a/bsp/fh8620/libraries/driverlib/fh_spi.c b/bsp/fh8620/libraries/driverlib/fh_spi.c
new file mode 100644
index 0000000000..14d8039732
--- /dev/null
+++ b/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);
+}
diff --git a/bsp/fh8620/libraries/driverlib/fh_timer.c b/bsp/fh8620/libraries/driverlib/fh_timer.c
new file mode 100644
index 0000000000..f3034adeaa
--- /dev/null
+++ b/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;
+}
diff --git a/bsp/fh8620/libraries/driverlib/fh_uart.c b/bsp/fh8620/libraries/driverlib/fh_uart.c
new file mode 100644
index 0000000000..0d9ad1f35d
--- /dev/null
+++ b/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;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bsp/fh8620/libraries/driverlib/fh_wdt.c b/bsp/fh8620/libraries/driverlib/fh_wdt.c
new file mode 100644
index 0000000000..269f1015c8
--- /dev/null
+++ b/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);
+}
diff --git a/bsp/fh8620/libraries/inc/fh_driverlib.h b/bsp/fh8620/libraries/inc/fh_driverlib.h
new file mode 100644
index 0000000000..9bb6b8c75d
--- /dev/null
+++ b/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"
diff --git a/bsp/fh8620/libraries/inc/fh_gpio.h b/bsp/fh8620/libraries/inc/fh_gpio.h
new file mode 100644
index 0000000000..62d1823eba
--- /dev/null
+++ b/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_ */
diff --git a/bsp/fh8620/libraries/inc/fh_i2c.h b/bsp/fh8620/libraries/inc/fh_i2c.h
new file mode 100644
index 0000000000..f981da431f
--- /dev/null
+++ b/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_ */
diff --git a/bsp/fh8620/libraries/inc/fh_ictl.h b/bsp/fh8620/libraries/inc/fh_ictl.h
new file mode 100644
index 0000000000..9796c99afc
--- /dev/null
+++ b/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
diff --git a/bsp/fh8620/libraries/inc/fh_mmc.h b/bsp/fh8620/libraries/inc/fh_mmc.h
new file mode 100644
index 0000000000..642ed43ac7
--- /dev/null
+++ b/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_ */
diff --git a/bsp/fh8620/libraries/inc/fh_pwm.h b/bsp/fh8620/libraries/inc/fh_pwm.h
new file mode 100644
index 0000000000..011da43905
--- /dev/null
+++ b/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_ */
diff --git a/bsp/fh8620/libraries/inc/fh_sdio.h b/bsp/fh8620/libraries/inc/fh_sdio.h
new file mode 100644
index 0000000000..b268dbd322
--- /dev/null
+++ b/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__
diff --git a/bsp/fh8620/libraries/inc/fh_spi.h b/bsp/fh8620/libraries/inc/fh_spi.h
new file mode 100644
index 0000000000..d81c2428bc
--- /dev/null
+++ b/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_ */
diff --git a/bsp/fh8620/libraries/inc/fh_timer.h b/bsp/fh8620/libraries/inc/fh_timer.h
new file mode 100644
index 0000000000..715a73b252
--- /dev/null
+++ b/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_ */
+
diff --git a/bsp/fh8620/libraries/inc/fh_uart.h b/bsp/fh8620/libraries/inc/fh_uart.h
new file mode 100644
index 0000000000..87da9ee2f7
--- /dev/null
+++ b/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_ */
+
diff --git a/bsp/fh8620/libraries/inc/fh_wdt.h b/bsp/fh8620/libraries/inc/fh_wdt.h
new file mode 100644
index 0000000000..b00343ac6f
--- /dev/null
+++ b/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_ */
diff --git a/bsp/fh8620/libraries/startup/SConscript b/bsp/fh8620/libraries/startup/SConscript
new file mode 100644
index 0000000000..1e4964b3f2
--- /dev/null
+++ b/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')
diff --git a/bsp/fh8620/libraries/startup/gcc/start_gcc.S b/bsp/fh8620/libraries/startup/gcc/start_gcc.S
new file mode 100644
index 0000000000..dccd94b757
--- /dev/null
+++ b/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.*/
+
+/*/*}*/
diff --git a/bsp/fh8620/link.ld b/bsp/fh8620/link.ld
new file mode 100644
index 0000000000..7cd6904aef
--- /dev/null
+++ b/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 = .;
+}
diff --git a/bsp/fh8620/platform/SConscript b/bsp/fh8620/platform/SConscript
new file mode 100644
index 0000000000..4c815c49b8
--- /dev/null
+++ b/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')
diff --git a/bsp/fh8620/platform/board.h b/bsp/fh8620/platform/board.h
new file mode 100644
index 0000000000..46b276b052
--- /dev/null
+++ b/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
diff --git a/bsp/fh8620/platform/board_info.h b/bsp/fh8620/platform/board_info.h
new file mode 100644
index 0000000000..71f8d3c19e
--- /dev/null
+++ b/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
diff --git a/bsp/fh8620/platform/common/SConscript b/bsp/fh8620/platform/common/SConscript
new file mode 100644
index 0000000000..9679d6df56
--- /dev/null
+++ b/bsp/fh8620/platform/common/SConscript
@@ -0,0 +1,8 @@
+from building import *
+
+cwd = GetCurrentDir()
+src = Glob('*.c')
+
+group = DefineGroup('Platform', src, depend = [''])
+
+Return('group')
diff --git a/bsp/fh8620/platform/common/board_info.c b/bsp/fh8620/platform/common/board_info.c
new file mode 100644
index 0000000000..aa56cbac62
--- /dev/null
+++ b/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;
+}
diff --git a/bsp/fh8620/platform/common/chkenv.c b/bsp/fh8620/platform/common/chkenv.c
new file mode 100644
index 0000000000..563b5bb55a
--- /dev/null
+++ b/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
+
+
+
+
diff --git a/bsp/fh8620/platform/fh8620/SConscript b/bsp/fh8620/platform/fh8620/SConscript
new file mode 100644
index 0000000000..4c815c49b8
--- /dev/null
+++ b/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')
diff --git a/bsp/fh8620/platform/fh8620/arch.h b/bsp/fh8620/platform/fh8620/arch.h
new file mode 100644
index 0000000000..df0e7f1965
--- /dev/null
+++ b/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_ */
diff --git a/bsp/fh8620/platform/fh8620/iot_cam/SConscript b/bsp/fh8620/platform/fh8620/iot_cam/SConscript
new file mode 100644
index 0000000000..7f5236ef88
--- /dev/null
+++ b/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')
diff --git a/bsp/fh8620/platform/fh8620/iot_cam/board.c b/bsp/fh8620/platform/fh8620/iot_cam/board.c
new file mode 100644
index 0000000000..f7c9ebdcb1
--- /dev/null
+++ b/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
+}
+
diff --git a/bsp/fh8620/platform/fh8620/iot_cam/board_def.h b/bsp/fh8620/platform/fh8620/iot_cam/board_def.h
new file mode 100644
index 0000000000..48551b7095
--- /dev/null
+++ b/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_ */
diff --git a/bsp/fh8620/platform/fh8620/iot_cam/iomux.c b/bsp/fh8620/platform/fh8620/iot_cam/iomux.c
new file mode 100644
index 0000000000..ee0bb63260
--- /dev/null
+++ b/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);
diff --git a/bsp/fh8620/platform/fh8620/iot_cam/readme b/bsp/fh8620/platform/fh8620/iot_cam/readme
new file mode 100644
index 0000000000..13a46f4c47
--- /dev/null
+++ b/bsp/fh8620/platform/fh8620/iot_cam/readme
@@ -0,0 +1,4 @@
+IoT Camera
+powered by RT-Thread
+V1.0
+2016-3-14 \ No newline at end of file
diff --git a/bsp/fh8620/platform/fh8620/iot_cam/startup.c b/bsp/fh8620/platform/fh8620/iot_cam/startup.c
new file mode 100644
index 0000000000..52c4775da5
--- /dev/null
+++ b/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 ;
+}
diff --git a/bsp/fh8620/platform/fh_arch.h b/bsp/fh8620/platform/fh_arch.h
new file mode 100644
index 0000000000..2cbe36718a
--- /dev/null
+++ b/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_ */
diff --git a/bsp/fh8620/platform/fh_def.h b/bsp/fh8620/platform/fh_def.h
new file mode 100644
index 0000000000..57bedcb9e7
--- /dev/null
+++ b/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_ */
diff --git a/bsp/fh8620/platform/plat-v2/SConscript b/bsp/fh8620/platform/plat-v2/SConscript
new file mode 100644
index 0000000000..40240950c0
--- /dev/null
+++ b/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')
diff --git a/bsp/fh8620/platform/plat-v2/arch.h b/bsp/fh8620/platform/plat-v2/arch.h
new file mode 100644
index 0000000000..bb32d96ea4
--- /dev/null
+++ b/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_ */
diff --git a/bsp/fh8620/platform/plat-v2/clock.c b/bsp/fh8620/platform/plat-v2/clock.c
new file mode 100644
index 0000000000..3b04d69ff3
--- /dev/null
+++ b/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
+
+
diff --git a/bsp/fh8620/platform/plat-v2/clock.h b/bsp/fh8620/platform/plat-v2/clock.h
new file mode 100644
index 0000000000..60b0ed6538
--- /dev/null
+++ b/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
diff --git a/bsp/fh8620/platform/plat-v2/fh_pmu.c b/bsp/fh8620/platform/plat-v2/fh_pmu.c
new file mode 100644
index 0000000000..8f518efd94
--- /dev/null
+++ b/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;
+
+}
diff --git a/bsp/fh8620/platform/plat-v2/fh_pmu.h b/bsp/fh8620/platform/plat-v2/fh_pmu.h
new file mode 100644
index 0000000000..19a6279d1a
--- /dev/null
+++ b/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_ */
diff --git a/bsp/fh8620/platform/plat-v2/iomux.c b/bsp/fh8620/platform/plat-v2/iomux.c
new file mode 100644
index 0000000000..67acf6ca75
--- /dev/null
+++ b/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)));
+ */
+}
+
diff --git a/bsp/fh8620/platform/plat-v2/iomux.h b/bsp/fh8620/platform/plat-v2/iomux.h
new file mode 100644
index 0000000000..e03273b2b8
--- /dev/null
+++ b/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_ */
+
+
diff --git a/bsp/fh8620/platform/plat-v2/reset.c b/bsp/fh8620/platform/plat-v2/reset.c
new file mode 100644
index 0000000000..654a0745e9
--- /dev/null
+++ b/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
+
+/*@}*/
diff --git a/bsp/fh8620/platform/plat-v2/timer.c b/bsp/fh8620/platform/plat-v2/timer.c
new file mode 100644
index 0000000000..d5bd7f09e4
--- /dev/null
+++ b/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);
+
+}
+
diff --git a/bsp/fh8620/platform/plat-v2/timer.h b/bsp/fh8620/platform/plat-v2/timer.h
new file mode 100644
index 0000000000..5ee024a094
--- /dev/null
+++ b/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
diff --git a/bsp/fh8620/platform/platform_def.h b/bsp/fh8620/platform/platform_def.h
new file mode 100644
index 0000000000..b511863981
--- /dev/null
+++ b/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_ */
diff --git a/bsp/fh8620/rtconfig.h b/bsp/fh8620/rtconfig.h
new file mode 100644
index 0000000000..4c0d4579f2
--- /dev/null
+++ b/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
diff --git a/bsp/fh8620/rtconfig.py b/bsp/fh8620/rtconfig.py
new file mode 100644
index 0000000000..6a4d4e3d10
--- /dev/null
+++ b/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'