diff options
| author | Bernard Xiong <[email protected]> | 2016-04-18 13:52:39 +0800 |
|---|---|---|
| committer | Bernard Xiong <[email protected]> | 2016-04-18 13:52:39 +0800 |
| commit | 43f68131ce64fbb4c3e476e684f3d06919ebd5af (patch) | |
| tree | 4bc755c1f350d2fbb30ae7c1c050be4d3d2125a5 /bsp | |
| parent | 6d03ce9a7bfd4ff94665465d1c07f6c816fe19a2 (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')
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, + ð_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 = ®value; + 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 = ®//(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' |
