diff --git a/bsp/x1000/Kconfig b/bsp/x1000/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..0da207221c0991b2bbd05d015b6fa20259db0dbc --- /dev/null +++ b/bsp/x1000/Kconfig @@ -0,0 +1,24 @@ +mainmenu "RT-Thread Configuration" + +config $BSP_DIR + string + option env="BSP_ROOT" + default "." + +config $RTT_DIR + string + option env="RTT_ROOT" + default "E:/rt-thread" + +# you can change the RTT_ROOT default "../.." to your rtthread_root, +# example : default "F:/git_repositories/rt-thread" + +config $PKGS_DIR + string + option env="PKGS_ROOT" + default "packages" + +source "$RTT_DIR/KConfig" +source "$PKGS_DIR/KConfig" +source "$BSP_DIR/drivers/Kconfig" + diff --git a/bsp/x1000/SConstruct b/bsp/x1000/SConstruct index 8e8017bc29da35c6d283818717fe3f128cbb68b1..0b01f4c3d4968e4e59274e7b408aba2c5175ba6f 100644 --- a/bsp/x1000/SConstruct +++ b/bsp/x1000/SConstruct @@ -1,8 +1,12 @@ import os import sys import rtconfig -from rtconfig import RTT_ROOT +if os.getenv('RTT_ROOT'): + RTT_ROOT = os.getenv('RTT_ROOT') +else: + RTT_ROOT = os.path.join(Dir('#').get_abspath(), 'rt-thread') + sys.path = sys.path + [os.path.join(RTT_ROOT, 'tools')] from building import * @@ -11,16 +15,19 @@ TARGET = 'rtthread-x1000.' + rtconfig.TARGET_EXT env = Environment(tools = ['mingw'], AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS, CC = rtconfig.CC, CCFLAGS = rtconfig.CFLAGS, - CXX = rtconfig.CC, CXXFLAGS = rtconfig.CXXFLAGS, + CXX = rtconfig.CXX, CXXFLAGS = rtconfig.CXXFLAGS, AR = rtconfig.AR, ARFLAGS = '-rc', LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS) env.PrependENVPath('PATH', rtconfig.EXEC_PATH) +# add --start-group and --end-group for GNU GCC +env['LINKCOM'] = '$LINK -o $TARGET $LINKFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS -Wl,--start-group $_LIBFLAGS -Wl,--end-group' + Export('RTT_ROOT') Export('rtconfig') # prepare building environment -objs = PrepareBuilding(env, RTT_ROOT) +objs = PrepareBuilding(env, RTT_ROOT, has_libcpu=False) # make a building DoBuilding(TARGET, objs) diff --git a/bsp/x1000/applications/SConscript b/bsp/x1000/applications/SConscript index 21a891dcb0f55760c1167b10187a13bc757f8cd1..01474917fa3befb06e0cb7f44793955ffe0bd32c 100644 --- a/bsp/x1000/applications/SConscript +++ b/bsp/x1000/applications/SConscript @@ -1,13 +1,10 @@ from building import * cwd = GetCurrentDir() -src = Glob('*.c') +src = Glob('*.c') + Glob('*.cpp') CPPPATH = [cwd, str(Dir('#'))] -if not GetDepend("RT_USING_DFS_ROMFS"): - SrcRemove(src, "romfs.c") - group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH) Return('group') diff --git a/bsp/x1000/applications/blink.c b/bsp/x1000/applications/blink.c new file mode 100644 index 0000000000000000000000000000000000000000..8ce45321b2f631f7bebc2dd60b2e6bf30da970cf --- /dev/null +++ b/bsp/x1000/applications/blink.c @@ -0,0 +1,74 @@ +/* + * File : blink.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017-11-8 Tangyuxin first version + */ + +#include + +#include +#include + +void blink_task(void* param) +{ + rt_uint8_t cnt = 0; + + while(1) + { + rt_thread_delay(RT_TICK_PER_SECOND / 4); + + if(cnt & 0x01) + gpio_set_value(BLINK_LED0_PORT,BLINK_LED0_PIN,0); + else + gpio_set_value(BLINK_LED0_PORT,BLINK_LED0_PIN,1); + + if(cnt & 0x02) + gpio_set_value(BLINK_LED1_PORT,BLINK_LED1_PIN,0); + else + gpio_set_value(BLINK_LED1_PORT,BLINK_LED1_PIN,1); + + if(cnt & 0x04) + gpio_set_value(BLINK_LED2_PORT,BLINK_LED2_PIN,0); + else + gpio_set_value(BLINK_LED2_PORT,BLINK_LED2_PIN,1); + + if(cnt & 0x08) + gpio_set_value(BLINK_LED3_PORT,BLINK_LED3_PIN,0); + else + gpio_set_value(BLINK_LED3_PORT,BLINK_LED3_PIN,1); + + cnt ++; + } +} + +int blink_init(void) +{ + rt_thread_t tid; + + tid = rt_thread_create("blink", + blink_task, RT_NULL, + 512, + RT_THREAD_PRIORITY_MAX - 2, + 10); + if (tid != RT_NULL) + rt_thread_startup(tid); +} +INIT_APP_EXPORT(blink_init); diff --git a/bsp/x1000/applications/main.c b/bsp/x1000/applications/main.c index 0ec71c9329244900dbf06bdf6a5ebb33e0ff0568..75068b5adae38bd6e0e2ac97c2b13fb7c73c7bcb 100644 --- a/bsp/x1000/applications/main.c +++ b/bsp/x1000/applications/main.c @@ -1,7 +1,7 @@ /* - * File : _main.c + * File : main.c * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team + * COPYRIGHT (C) 2008 - 2017, RT-Thread Development Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,14 +19,12 @@ * * Change Logs: * Date Author Notes - * 2015-11-19 Urey the first version + * 2017-11-8 Tangyuxin first version */ -#include -#include -int main(int argc, char** argv) -{ - printf("Hello RT-Thread!\n"); +#include +int main(int argc, char** argv) +{ return 0; } diff --git a/bsp/x1000/applications/mnt_init.c b/bsp/x1000/applications/mnt_init.c new file mode 100644 index 0000000000000000000000000000000000000000..a3f564d9593184243739cecbf126aac51f4e55d2 --- /dev/null +++ b/bsp/x1000/applications/mnt_init.c @@ -0,0 +1,72 @@ +/* + * File : mnt_init.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017-11-8 Tangyuxin first version + */ + +#include +#include + +#ifdef RT_USING_DFS +#include + +int mnt_init(void) +{ + rt_kprintf("init filesystem...\n"); +#ifdef RT_USING_MTD_NOR + //mount rootfs + if (dfs_mount("rootfs", "/", "elm", 0, 0) == 0) + { + rt_kprintf("File System on root initialized!\n"); + } + else + { + rt_kprintf("File System on root initialization failed!\n"); + } + + //mount appfs + if (dfs_mount("appfs", "/appfs", "elm", 0, 0) == 0) + { + rt_kprintf("File System on appfs initialized!\n"); + } + else + { + rt_kprintf("File System on appfs initialization failed!\n"); + } +#endif + +#if (defined(RT_USING_SDIO) && defined(RT_USING_MSC0)) + rt_thread_delay(RT_TICK_PER_SECOND/5); + if (dfs_mount("sd0", "/sd", "elm", 0, 0) == 0) + { + rt_kprintf("File System on TF initialized!\n"); + } + else + { + rt_kprintf("File System on TF fail!\n"); + } +#endif + + return 0; +} +INIT_ENV_EXPORT(mnt_init); + +#endif diff --git a/bsp/x1000/applications/rtgui_demo.c b/bsp/x1000/applications/rtgui_demo.c new file mode 100644 index 0000000000000000000000000000000000000000..bd8b64410799e7e371b3de53435fcba5d068e8f0 --- /dev/null +++ b/bsp/x1000/applications/rtgui_demo.c @@ -0,0 +1,154 @@ +/* + * File : rtgui_demo.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017-11-8 Tangyuxin first version + */ + +#include + +// #define DEBUG + +#ifdef DEBUG +#define DEBUG_PRINTF(...) rt_kprintf(__VA_ARGS__) +#else +#define DEBUG_PRINTF(...) +#endif + +#ifdef RT_USING_GUIENGINE + +#include +#include +#include + +#include +#include + +struct rtgui_win *main_win; +rt_bool_t dc_event_handler(struct rtgui_object *object, rtgui_event_t *event); + +static void rt_gui_demo_entry(void *parameter) +{ + struct rtgui_app *app; + + DEBUG_PRINTF("gui demo entry\n"); + + /* create gui app */ + app = rtgui_app_create("gui_demo"); + if (app == RT_NULL) + { + DEBUG_PRINTF("rtgui_app_create faild\n"); + return; + } + + /* create main window */ + main_win = rtgui_mainwin_create(RT_NULL, + "UiWindow", RTGUI_WIN_STYLE_NO_TITLE | RTGUI_WIN_STYLE_NO_BORDER); + if (main_win == RT_NULL) + { + DEBUG_PRINTF("main_win is null\n"); + rtgui_app_destroy(app); + return; + } + + rtgui_object_set_event_handler(RTGUI_OBJECT(main_win), dc_event_handler); + + DEBUG_PRINTF("rtgui_win_show\n"); + rtgui_win_show(main_win, RT_FALSE); + + DEBUG_PRINTF("rtgui_app_run\n"); + rtgui_app_run(app); + + DEBUG_PRINTF("rtgui_win_destroy\n"); + rtgui_win_destroy(main_win); + + DEBUG_PRINTF("rtgui_app_destroy\n"); + rtgui_app_destroy(app); +} + +rt_bool_t dc_event_handler(struct rtgui_object *object, rtgui_event_t *event) +{ + struct rtgui_widget *widget = RTGUI_WIDGET(object); + + if (event->type == RTGUI_EVENT_PAINT) + { + struct rtgui_dc *dc; + rtgui_rect_t rect; + + rt_kprintf("\r\n RTGUI_EVENT_PAINT \r\n"); + rtgui_win_event_handler(RTGUI_OBJECT(widget), event); + + rtgui_widget_get_rect(widget, &rect); + DEBUG_PRINTF("widget react x1: %d, y1: %d, x2: %d, y2: %d\r\n", + rect.x1, rect.y1, rect.x2, rect.y2); + + dc = rtgui_dc_begin_drawing(widget); + if(dc == RT_NULL) + { + DEBUG_PRINTF("\r\n dc is null \r\n"); + return RT_FALSE; + } + + rtgui_dc_draw_line(dc, rect.x1, rect.y1, rect.x2, rect.y2); + rtgui_dc_draw_line(dc, rect.x1, rect.y2, rect.x2, rect.y1); + + rect.x1 += (rect.x2 - rect.x1) / 2; + rect.y1 += (rect.y2 - rect.y1) / 2; + rtgui_dc_draw_text_stroke(dc, __DATE__"--"__TIME__, &rect, HIGH_LIGHT, BLUE); + + rtgui_dc_end_drawing(dc,RT_TRUE); + } + return RT_FALSE; +} + +int rt_gui_demo_init(void) +{ + rt_thread_t tid; + rt_device_t device; + rt_err_t err; + + device = rt_device_find("lcd"); + if(device == RT_NULL) + { + rt_kprintf("Not found LCD driver\n"); + return RT_ERROR; + } + + err = rt_device_open(device, RT_DEVICE_OFLAG_RDWR); + if (err != RT_EOK) + { + rt_kprintf("Open LCD driver fail\n"); + return RT_ERROR; + } + + /* set graphic device */ + rtgui_graphic_set_device(device); + + tid = rt_thread_create("mygui", + rt_gui_demo_entry, RT_NULL, + 2048, 25, 10); + + if (tid != RT_NULL) + rt_thread_startup(tid); + + return 0; +} +INIT_APP_EXPORT(rt_gui_demo_init); +#endif /* RT_USING_GUIENGINE */ diff --git a/bsp/x1000/driver/board.h b/bsp/x1000/driver/board.h deleted file mode 100644 index c92937eedc2d481dc5f4a7bdb5c982d4b6062bba..0000000000000000000000000000000000000000 --- a/bsp/x1000/driver/board.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * File : board.h - * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Change Logs: - * Date Author Notes - * 2015-11-19 Urey the first version - */ - -#ifndef _BOARD_H_ -#define _BOARD_H_ - -#include - -#include "x1000.h" - -#define RT_USING_JZ_X1000 - -// #define BOARD_PHOENIX -// #define BOARD_CANNA - -#ifdef BOARD_PHOENIX -#define RT_USING_EMAC -#endif - -/********************************************************************************************************* -** Clock for Board -*********************************************************************************************************/ -#define BOARD_EXTAL_CLK 24000000 -#define BOARD_RTC_CLK 32768 -#define BOARD_CPU_CLK (1008 * 1000 * 1000UL) - - -/********************************************************************************************************* -** HEAP Setting -*********************************************************************************************************/ -extern unsigned char __bss_start; -extern unsigned char __bss_end; - -#define RT_HW_HEAP_BEGIN (void*)&__bss_end -#define RT_HW_HEAP_END (void*)(0x80000000 + 32 * 1024 * 1024) - -/********************************************************************************************************* -** UART Setting -*********************************************************************************************************/ -#define RT_USING_UART2 - -#endif diff --git a/bsp/x1000/driver/drv_mmc.c b/bsp/x1000/driver/drv_mmc.c deleted file mode 100644 index 6d4656bd3567f10c18817747cdda3051ce62714c..0000000000000000000000000000000000000000 --- a/bsp/x1000/driver/drv_mmc.c +++ /dev/null @@ -1,750 +0,0 @@ -/* - * File : drv_mmc.c - * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2013 - 2015, RT-Thread Development Team - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rt-thread.org/license/LICENSE - * - * Change Logs: - * Date Author Notes - * 2013-03-09 aozima the first version - * 2013-03-29 aozima support Jz4770. - * 2013-04-01 aozima add interrupt support for Jz4770. - */ - -#include -#include -#include - -#include -#include - -#include "board.h" -#include "drv_gpio.h" -#include "drv_clock.h" -#include "drv_mmc.h" - -#define RT_USING_MSC0 -#define RT_USING_MSC1 - -// #define JZ47XX_SDIO_DBG - -#ifdef JZ47XX_SDIO_DBG -#define sdio_dbg(fmt, ...) rt_kprintf("[SDIO]");rt_kprintf(fmt, ##__VA_ARGS__) -#else -#define sdio_dbg(fmt, ...) -#endif - -static void msc_handler(int irqno, void* param) -{ - struct jz47xx_sdio * jz_sdio = (struct jz47xx_sdio *)param; - - /* disable interrupt */ - rt_hw_interrupt_mask(jz_sdio->irqno); - - rt_completion_done(&jz_sdio->completion); -} - -rt_inline void jz_mmc_clk_autoctrl(struct jz47xx_sdio *host, unsigned int on) -{ - if(on) - { - if(!clk_is_enabled(host->clock)) - clk_enable(host->clock); - if(!clk_is_enabled(host->clock_gate)) - clk_enable(host->clock_gate); - } - else - { - if(clk_is_enabled(host->clock_gate)) - clk_disable(host->clock_gate); - if(clk_is_enabled(host->clock)) - clk_disable(host->clock); - } -} - -/* Stop the MMC clock and wait while it happens */ -rt_inline rt_err_t jz_mmc_stop_clock(uint32_t hw_base) -{ - uint16_t value; - int timeout = 10000; - - value = readw(hw_base + MSC_CTRL_OFFSET); - value |= MSC_CTRL_CLOCK_STOP; - writew(value, hw_base + MSC_CTRL_OFFSET); - - while (timeout && (readl(hw_base + MSC_STAT_OFFSET) & MSC_STAT_CLK_EN)) - { - timeout--; - if (timeout == 0) - { - return -RT_ETIMEOUT; - } - rt_thread_delay(1); - } - - return RT_EOK; -} - -/* Start the MMC clock and operation */ -rt_inline void jz_mmc_start_clock(uint32_t hw_base) -{ - uint16_t value; - value = readw(hw_base + MSC_CTRL_OFFSET); - value |= (MSC_CTRL_CLOCK_START | MSC_CTRL_START_OP); - writew(value, hw_base + MSC_CTRL_OFFSET); -} - -static int jz_mmc_hardware_init(struct jz47xx_sdio * jz_sdio) -{ - uint32_t hw_base = jz_sdio->hw_base; - uint32_t value; - - /* reset mmc/sd controller */ - value = readl(hw_base + MSC_CTRL_OFFSET); - value |= MSC_CTRL_RESET; - writel(value, hw_base + MSC_CTRL_OFFSET); - rt_thread_delay(1); - value &= ~MSC_CTRL_RESET; - writel(value, hw_base + MSC_CTRL_OFFSET); - - while(readl(hw_base + MSC_STAT_OFFSET) & MSC_STAT_IS_RESETTING); - - /* mask all IRQs */ - writel(0xffffffff, hw_base + MSC_IMASK_OFFSET); - writel(0xffffffff, hw_base + MSC_IREG_OFFSET); - - /* set timeout */ - writel(0x100, hw_base + MSC_RESTO_OFFSET); - writel(0x1ffffff, hw_base + MSC_RDTO_OFFSET); - - /* stop MMC/SD clock */ - jz_mmc_stop_clock(hw_base); -} - -/* Set the MMC clock frequency */ -void jz_mmc_set_clock(struct jz47xx_sdio * jz_sdio, unsigned int clock) -{ - unsigned int msc_clock = jz_sdio->msc_clock; - - /* calc and set MSC_CLKRT. */ - { - unsigned int div = 0; - while (clock < msc_clock) - { - div++; - msc_clock >>= 1; - } - if(div > 7) div = 7; - - sdio_dbg("msc_clock: %u, SDIO_CLK: %u, MSC_CLKRT: %u\r\n", jz_sdio->msc_clock, clock, div); - writew(div, jz_sdio->hw_base + MSC_CLKRT_OFFSET); - } -} - -/* RT-Thread SDIO interface */ -static void jz47xx_sdio_request(struct rt_mmcsd_host *host, - struct rt_mmcsd_req *req) -{ - struct jz47xx_sdio *sdio = host->private_data; - unsigned int cmdat = 0; - unsigned int stat; - uint32_t hw_base, value; - - hw_base = sdio->hw_base; - jz_mmc_stop_clock(hw_base); - - sdio_dbg("CMD: %d ARG: %08X\n", req->cmd->cmd_code, req->cmd->arg); - - if(sdio->flag & MSC_CMDAT_BUS_WIDTH_4BIT) - { - cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT; - } - - /* auto send stop */ - if (req->stop) - { - sdio_dbg("CMD STOP: %d ARG: %08X\n", req->stop->cmd_code, - req->stop->arg); - cmdat |= MSC_CMDAT_SEND_AS_STOP; - } - - if(req->cmd->cmd_code == GO_IDLE_STATE) - { - cmdat |= MSC_CMDAT_INIT; - } - - /* clear status */ - writew(0xFFFF, hw_base + MSC_IREG_OFFSET); - - /* open interrupt */ - value = readl(hw_base + MSC_IMASK_OFFSET); - value &= ~(MSC_DATA_TRAN_DONE | MSC_PRG_DONE | MSC_END_CMD_RES); - writel(value, hw_base + MSC_IMASK_OFFSET); - - if(req->data) - { - writew(req->data->blksize, hw_base + MSC_BLKLEN_OFFSET); - writew(req->data->blks, hw_base + MSC_NOB_OFFSET); - - cmdat |= MSC_CMDAT_DATA_EN; - if (req->data->flags & DATA_DIR_WRITE) - { - cmdat |= MSC_CMDAT_WRITE; - } - else if (req->data->flags & DATA_DIR_READ) - { - cmdat |= MSC_CMDAT_READ; - } - } - else - { - writew(0, hw_base + MSC_BLKLEN_OFFSET); - writew(0, hw_base + MSC_NOB_OFFSET); - } - - /* set command */ - writeb(req->cmd->cmd_code, hw_base + MSC_CMD_OFFSET); - - /* set argument */ - writel(req->cmd->arg, hw_base + MSC_ARG_OFFSET); - - /* Set response type */ -#ifdef JZ47XX_SDIO_DBG - { - int res_type = req->cmd->flags & RESP_MASK; - sdio_dbg("resp type:%u\r\n", res_type); - } -#endif - - cmdat &= ~(MSC_CMDAT_RESP_FORMAT_MASK); - switch (req->cmd->flags & RESP_MASK) - { - case RESP_NONE: - break; - - case RESP_R1B: - cmdat |= MSC_CMDAT_BUSY; - /*FALLTHRU*/ - case RESP_R1: - cmdat |= MSC_CMDAT_RESPONSE_R1; - break; - case RESP_R2: - cmdat |= MSC_CMDAT_RESPONSE_R2; - break; - case RESP_R3: - cmdat |= MSC_CMDAT_RESPONSE_R3; - break; - case RESP_R4: - cmdat |= MSC_CMDAT_RESPONSE_R4; - break; - case RESP_R5: - cmdat |= MSC_CMDAT_RESPONSE_R5; - break; - case RESP_R6: - cmdat |= MSC_CMDAT_RESPONSE_R6; - case RESP_R7: - cmdat |= MSC_CMDAT_RESPONSE_R7; - break; - default: - break; - } - - /* Set command */ - sdio_dbg("cmdat: %08X\r\n", cmdat); - writel(cmdat, sdio->hw_base + MSC_CMDAT_OFFSET); - writel(MSC_CTRL_START_OP, sdio->hw_base + MSC_CTRL_OFFSET); - - writel(0xFF, sdio->hw_base + MSC_RESTO_OFFSET); - writel(0xFFFFFFFF, sdio->hw_base + MSC_RDTO_OFFSET); - - jz_mmc_start_clock(sdio->hw_base); - req->cmd->err = RT_EOK; - - if(!(readl(sdio->hw_base + MSC_IREG_OFFSET) & MSC_END_CMD_RES)) - { - rt_err_t ret; - - rt_completion_init(&sdio->completion); - rt_hw_interrupt_umask(sdio->irqno); - ret = rt_completion_wait(&sdio->completion, RT_TICK_PER_SECOND); - if(ret == RT_EOK) - { - sdio_dbg("wait END_CMD_RES OK!\r\n"); - } - else - { - uint32_t value; - - value = readl(hw_base + MSC_STAT_OFFSET); - sdio_dbg("stat=0x%08x\n", value); - value = readl(hw_base + MSC_IREG_OFFSET); - sdio_dbg("iflag=0x%08x\n", value); - - req->cmd->err = ret; - sdio_dbg("wait END_CMD_RES timeout[uncompletion]\r\n"); - } - } - else - { - sdio_dbg("no need wait MSC_END_CMD_RES!\r\n"); - } - - stat = readl(hw_base + MSC_STAT_OFFSET); - writew(MSC_END_CMD_RES, hw_base + MSC_IREG_OFFSET); - - /* get response. */ - { - uint8_t buf[16]; - uint32_t data; - - if(req->cmd->err == RT_EOK) - { - if(stat & MSC_STAT_TIME_OUT_RES) - { - sdio_dbg("ERR: MSC_STAT_TIME_OUT_RES\r\n"); - req->cmd->err = -RT_ETIMEOUT; - } - else if(stat & MSC_STAT_CRC_READ_ERR) - { - sdio_dbg("ERR: MSC_STAT_CRC_READ_ERR\r\n"); - req->cmd->err = -1; - } - } - - switch (req->cmd->flags & RESP_MASK) - { - case RESP_R1: - case RESP_R1B: - case RESP_R6: - case RESP_R3: - case RESP_R4: - case RESP_R5: - case RESP_R7: - data = readw(sdio->hw_base + MSC_RES_OFFSET); - buf[1] = data & 0xFF; - - data = readw(sdio->hw_base + MSC_RES_OFFSET); - buf[2] = (data >> 8) & 0xFF; - buf[3] = data & 0xFF; - - data = readw(sdio->hw_base + MSC_RES_OFFSET); - buf[4] = data & 0xFF; - - req->cmd->resp[0] = buf[1] << 24 | buf[2] << 16 - | buf[3] << 8 | buf[4]; - break; - case RESP_R2: - { - uint32_t i, v, w1, w2; - - data = readw(sdio->hw_base + MSC_RES_OFFSET); - v = data & 0xFFFF; - - for(i=0; i<4; i++) - { - data = readw(sdio->hw_base + MSC_RES_OFFSET); - w1 = data & 0xFFFF; - - data = readw(sdio->hw_base + MSC_RES_OFFSET); - w2 = data & 0xFFFF; - - req->cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8; - v = w2; - } - } - break; - default: - break; - } - - sdio_dbg("error:%d cmd->resp [%08X, %08X, %08X, %08X]\r\n\r\n", - req->cmd->err, - req->cmd->resp[0], - req->cmd->resp[1], - req->cmd->resp[2], - req->cmd->resp[3] - ); - } - - if(req->data) - { - unsigned int waligned; - uint32_t len = req->data->blksize * req->data->blks; - - /* word aligned ? */ - waligned = (((unsigned int)req->data->buf & 0x3) == 0); - - if (req->data->flags & DATA_DIR_WRITE) - { - if(waligned) - { - uint32_t i; - uint32_t *src = (uint32_t *)req->data->buf; - - for(i=0; ihw_base + MSC_STAT_OFFSET) & MSC_STAT_DATA_FIFO_FULL); - - writel(*src++, hw_base + MSC_TXFIFO_OFFSET); - } - } - else - { - uint32_t i, data; - uint8_t * src = (uint8_t *)req->data->buf; - - for(i=0; ihw_base + MSC_STAT_OFFSET) & MSC_STAT_DATA_FIFO_FULL); - - data = (*src++ << 0); - data |= (*src++ << 8); - data |= (*src++ << 16); - data |= (*src++ << 24); - - writel(data, hw_base + MSC_TXFIFO_OFFSET); - } - } - - writel(IFLG_PRG_DONE, hw_base + MSC_IREG_OFFSET); - } - else if (req->data->flags & DATA_DIR_READ) - { - if(waligned) - { - uint32_t i; - uint32_t * dst = (uint32_t *)req->data->buf; - - for(i=0; ihw_base + MSC_STAT_OFFSET) & MSC_STAT_DATA_FIFO_EMPTY); - - *dst ++ = readl(sdio->hw_base + MSC_RXFIFO_OFFSET); - } - } - else - { - uint32_t data, i; - uint8_t * dst = (uint8_t *)req->data->buf; - - for(i=0; ihw_base + MSC_STAT_OFFSET) & MSC_STAT_DATA_FIFO_EMPTY); - - data = readl(sdio->hw_base + MSC_RXFIFO_OFFSET); - *dst++ = (uint8_t)(data >> 0); - *dst++ = (uint8_t)(data >> 8); - *dst++ = (uint8_t)(data >> 16); - *dst++ = (uint8_t)(data >> 24); - } - } - - writel(IFLG_DATA_TRAN_DONE, hw_base + MSC_IREG_OFFSET); - } - -#if 0 - value = readl(hw_base + MSC_IMASK_OFFSET); - value &= ~MSC_DATA_TRAN_DONE; - writel(value, hw_base + MSC_IMASK_OFFSET); - - if(!(readl(sdio->hw_base + MSC_IREG_OFFSET) & MSC_DATA_TRAN_DONE)) - { - rt_err_t ret; - - rt_completion_init(&sdio->completion); - sdio_dbg("TRAN_DONE umask\r\n"); - rt_hw_interrupt_umask(sdio->irqno); - - ret = rt_completion_wait(&sdio->completion, RT_TICK_PER_SECOND); - if(ret == RT_EOK) - { - sdio_dbg("wait END_CMD_RES OK!\r\n"); - } - else - { - rt_kprintf("SD DATA: int status 0x%08x\n", readl(sdio->hw_base + MSC_IREG_OFFSET)); - sdio_dbg("wait END_CMD_RES timeout!\r\n"); - } - } - else - { - sdio_dbg("no need wait MSC_DATA_TRAN_DONE!\r\n"); - } -#endif - - /* clear status */ - writew(MSC_DATA_TRAN_DONE, hw_base + MSC_IREG_OFFSET); - } /* if req->data */ - - mmcsd_req_complete(host); -} - - -static void jz47xx_sdio_set_iocfg(struct rt_mmcsd_host *host, - struct rt_mmcsd_io_cfg *io_cfg) -{ - struct jz47xx_sdio * jz_sdio = host->private_data; - rt_uint32_t clkdiv; - - sdio_dbg("set_iocfg clock: %d\n", io_cfg->clock); - - if (io_cfg->bus_width == MMCSD_BUS_WIDTH_4) - { - sdio_dbg("MMC: Setting controller bus width to 4\n"); - jz_sdio->flag |= MSC_CMDAT_BUS_WIDTH_4BIT; - } - else - { - jz_sdio->flag &= ~(MSC_CMDAT_BUS_WIDTH_4BIT); - sdio_dbg("MMC: Setting controller bus width to 1\n"); - } - - if (io_cfg->clock) - { - unsigned int clk_set = 0, clkrt = 0; - unsigned int clk_want = io_cfg->clock; - unsigned int lpm = 0; - - if (io_cfg->clock > 1 * 1000 * 1000) - { - io_cfg->clock = 1000 * 1000; - } - - jz_mmc_clk_autoctrl(jz_sdio, 1); - if (clk_want > 3000000) - { - clk_set_rate(jz_sdio->clock, io_cfg->clock); - } - else - { - clk_set_rate(jz_sdio->clock, 24000000); - } - clk_set = clk_get_rate(jz_sdio->clock); - - while (clk_want < clk_set) - { - clkrt++; - clk_set >>= 1; - } - - if (clkrt > 7) - { - sdio_dbg("invalid value of CLKRT: " - "ios->clock=%d clk_want=%d " - "clk_set=%d clkrt=%X,\n", - io_cfg->clock, clk_want, clk_set, clkrt); - return; - } - - if (!clkrt) - { - sdio_dbg("clk_want: %u, clk_set: %luHz\n", io_cfg->clock, clk_get_rate(jz_sdio->clock)); - } - - writel(clkrt, jz_sdio->hw_base + MSC_CLKRT_OFFSET); - - if (clk_set > 25000000) - { - lpm = (0x2 << LPM_DRV_SEL_SHF) | LPM_SMP_SEL; - } - - if(jz_sdio->sdio_clk) - { - writel(lpm, jz_sdio->hw_base + MSC_LPM_OFFSET); - writel(MSC_CTRL_CLOCK_START, jz_sdio->hw_base + MSC_CTRL_OFFSET); - } - else - { - lpm |= LPM_LPM; - writel(lpm, jz_sdio->hw_base + MSC_LPM_OFFSET); - } - } - else - { - jz_mmc_clk_autoctrl(jz_sdio, 0); - } - - /* maybe switch power to the card */ - switch (io_cfg->power_mode) - { - case MMCSD_POWER_OFF: - sdio_dbg("MMCSD_POWER_OFF\r\n"); - break; - case MMCSD_POWER_UP: - sdio_dbg("MMCSD_POWER_UP\r\n"); - break; - case MMCSD_POWER_ON: - sdio_dbg("MMCSD_POWER_ON\r\n"); - jz_mmc_hardware_init(jz_sdio); - // jz_mmc_set_clock(jz_sdio, io_cfg->clock); - break; - default: - sdio_dbg("unknown power_mode %d\n", io_cfg->power_mode); - break; - } -} - -static rt_int32_t jz47xx_SD_Detect(struct rt_mmcsd_host *host) -{ - sdio_dbg("jz47xx_SD_Detect\n"); -} - -static void jz47xx_sdio_enable_sdio_irq(struct rt_mmcsd_host *host, - rt_int32_t enable) -{ - sdio_dbg("jz47xx_sdio_enable_sdio_irq, enable:%d\n", enable); -} - -static const struct rt_mmcsd_host_ops ops = -{ - jz47xx_sdio_request, - jz47xx_sdio_set_iocfg, - jz47xx_SD_Detect, - jz47xx_sdio_enable_sdio_irq, -}; - -int jz47xx_sdio_init(void) -{ - struct rt_mmcsd_host *host = RT_NULL; - struct jz47xx_sdio * jz_sdio = RT_NULL; - -#ifdef RT_USING_MSC0 - host = mmcsd_alloc_host(); - jz_sdio = rt_malloc(sizeof(struct jz47xx_sdio)); - if(!(host && jz_sdio)) - { - goto err; - } - - rt_memset(jz_sdio, 0, sizeof(struct jz47xx_sdio)); - /* set hardware base firstly */ - jz_sdio->hw_base = MSC0_BASE; - jz_sdio->clock = clk_get("cgu_msc0"); - jz_sdio->clock_gate = clk_get("msc0"); - - /* init GPIO (msc0 boot) - * name pin fun - * X1000 MSC0_D0: PA23 1 - * X1000 MSC0_D1: PA22 1 - * X1000 MSC0_D2: PA21 1 - * X1000 MSC0_D3: PA20 1 - * X1000 MSC0_CMD: PA25 1 - * X1000 MSC0_CLK: PA24 1 - */ - { - gpio_set_func(GPIO_PORT_A, GPIO_Pin_20, GPIO_FUNC_1); - gpio_set_func(GPIO_PORT_A, GPIO_Pin_21, GPIO_FUNC_1); - gpio_set_func(GPIO_PORT_A, GPIO_Pin_22, GPIO_FUNC_1); - gpio_set_func(GPIO_PORT_A, GPIO_Pin_23, GPIO_FUNC_1); - gpio_set_func(GPIO_PORT_A, GPIO_Pin_24, GPIO_FUNC_1); - gpio_set_func(GPIO_PORT_A, GPIO_Pin_25, GPIO_FUNC_1); - } - - /* enable MSC0 clock gate. */ - clk_enable(jz_sdio->clock_gate); - - jz_sdio->msc_clock = 24UL * 1000 * 1000; /* 50Mhz */ - host->freq_min = 400 * 1000; /* min 400Khz. */ - host->freq_max = 24 * 1000 * 1000; /* max 50Mhz. */ - - /* set clock */ - clk_set_rate(jz_sdio->clock, BOARD_EXTAL_CLK); - - host->ops = &ops; - host->valid_ocr = VDD_27_28 | VDD_28_29 | VDD_29_30 | VDD_30_31 | VDD_31_32 | - VDD_32_33 | VDD_33_34 | VDD_34_35 | VDD_35_36; - host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE | MMCSD_SUP_HIGHSPEED; - host->max_seg_size = 65535; - host->max_dma_segs = 2; - host->max_blk_size = 512; - host->max_blk_count = 4096; - host->private_data = jz_sdio; - - jz_sdio->host = host; - jz_sdio->irqno = IRQ_MSC0; - - rt_hw_interrupt_install(jz_sdio->irqno, msc_handler, jz_sdio, "msc0"); - rt_hw_interrupt_mask(jz_sdio->irqno); - - mmcsd_change(host); -#endif // RT_USING_MSC0 - -#ifdef RT_USING_MSC1 - host = mmcsd_alloc_host(); - jz_sdio = rt_malloc(sizeof(struct jz47xx_sdio)); - if(!(host && jz_sdio)) - { - goto err; - } - - rt_memset(jz_sdio, 0, sizeof(struct jz47xx_sdio)); - jz_sdio->hw_base = MSC1_BASE; - jz_sdio->clock = clk_get("cgu_msc1"); - jz_sdio->clock_gate = clk_get("msc1"); - - /* init GPIO (paladin msc1 SDIO wifi) - * name pin fun - * X1000 MSC1_D0: PC02 0 - * X1000 MSC1_D1: PC03 0 - * X1000 MSC1_D2: PC04 0 - * X1000 MSC1_D3: PC05 0 - * X1000 MSC1_CMD: PC01 0 - * X1000 MSC1_CLK: PC00 0 - * - */ - { - gpio_set_func(GPIO_PORT_C, GPIO_Pin_0, GPIO_FUNC_0); - gpio_set_func(GPIO_PORT_C, GPIO_Pin_1, GPIO_FUNC_0); - gpio_set_func(GPIO_PORT_C, GPIO_Pin_2, GPIO_FUNC_0); - gpio_set_func(GPIO_PORT_C, GPIO_Pin_3, GPIO_FUNC_0); - gpio_set_func(GPIO_PORT_C, GPIO_Pin_4, GPIO_FUNC_0); - gpio_set_func(GPIO_PORT_C, GPIO_Pin_5, GPIO_FUNC_0); - } - - /* enable MSC1 clock gate. */ - clk_enable(jz_sdio->clock_gate); - - jz_sdio->msc_clock = 50UL * 1000 * 1000; /* 50Mhz */ - host->freq_min = 400 * 1000; /* min 400Khz. */ - host->freq_max = 50 * 1000 * 1000; /* max 50Mhz. */ - - /* set clock */ - clk_set_rate(jz_sdio->clock, BOARD_EXTAL_CLK); - - host->ops = &ops; - host->valid_ocr = VDD_27_28 | VDD_28_29 | VDD_29_30 | VDD_30_31 | VDD_31_32 | - VDD_32_33 | VDD_33_34 | VDD_34_35 | VDD_35_36; - host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE; - host->max_seg_size = 65535; - host->max_dma_segs = 2; - host->max_blk_size = 512; - host->max_blk_count = 4096; - host->private_data = jz_sdio; - - jz_sdio->host = host; - jz_sdio->irqno = IRQ_MSC1; - - rt_hw_interrupt_install(jz_sdio->irqno, msc_handler, jz_sdio, "msc1"); - rt_hw_interrupt_mask(jz_sdio->irqno); - - mmcsd_change(host); -#endif // RT_USING_MSC1 - - return RT_EOK; - -err: - if(host) - { - mmcsd_free_host(host); - } - if(jz_sdio) - { - rt_free(host); - } - - return -RT_ENOMEM; -} - diff --git a/bsp/x1000/driver/drv_uart.c b/bsp/x1000/driver/drv_uart.c deleted file mode 100644 index ebe144e4b5837b3c7bbcbc1a7f782116af8c1a17..0000000000000000000000000000000000000000 --- a/bsp/x1000/driver/drv_uart.c +++ /dev/null @@ -1,264 +0,0 @@ -/* - * File : drv_uart.c - * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Change Logs: - * Date Author Notes - * 2015-11-19 Urey the first version - */ -#include -#include -#include - -#include "board.h" -#include "drv_uart.h" - -struct jz_uart_s -{ - rt_uint32_t hw_base; - - rt_uint32_t irqno; - char name[RT_NAME_MAX]; -}; - -static rt_err_t uart_configure (struct rt_serial_device *serial, struct serial_configure *cfg); -static rt_err_t uart_control (struct rt_serial_device *serial, int cmd, void *arg); -static int uart_putc (struct rt_serial_device *serial, char c); -static int uart_getc (struct rt_serial_device *serial); -static rt_size_t uart_dma_transmit (struct rt_serial_device *serial, const rt_uint8_t *buf, rt_size_t size, int direction); - -static void uart_irq_handler (int irqno, void *param); - -const struct rt_uart_ops _uart_ops = -{ - uart_configure, - uart_control, - uart_putc, - uart_getc, - uart_dma_transmit -}; - -/* - * UART Initiation - */ -void rt_hw_uart_init(void) -{ - struct rt_serial_device *serial; - struct jz_uart_s *uart; - struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; - -#ifdef RT_USING_UART1 - { - static struct rt_serial_device serial1; - static struct jz_uart_s uart1; - - serial = &serial1; - uart = &uart1; - - serial->ops = &_uart_ops; - serial->config = config; - serial->config.baud_rate = 115200; - - uart->hw_base = UART0_BASE; - uart->irqno = IRQ_UART0; - - rt_hw_serial_register(serial, - "uart1", - RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, - uart); - } -#endif - -#ifdef RT_USING_UART2 - { - static struct rt_serial_device serial2; - static struct jz_uart_s uart2; - - serial = &serial2; - uart = &uart2; - - serial->ops = &_uart_ops; - serial->config = config; - serial->config.baud_rate = 115200; - - uart->hw_base = UART2_BASE; - uart->irqno = IRQ_UART2; - - rt_hw_serial_register(serial, - "uart2", - RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, - uart); - } -#endif - -#ifdef RT_USING_UART3 - { - static struct rt_serial_device serial3; - static struct jz_uart_s uart3; - - serial = &serial3; - uart = &uart3; - - serial->ops = &_uart_ops; - serial->config = config; - serial->config.baud_rate = 115200; - - uart->hw_base = UART3_BASE; - uart->irqno = IRQ_UART3; - - rt_hw_serial_register(serial, - "uart3", - RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, - uart); - } -#endif -} - -/* - * UART interface - */ -static rt_err_t uart_configure (struct rt_serial_device *serial, struct serial_configure *cfg) -{ - rt_uint32_t baud_div; - struct jz_uart_s * uart; - - RT_ASSERT(serial != RT_NULL); - serial->config = *cfg; - - uart = serial->parent.user_data; - RT_ASSERT(uart != RT_NULL); - - /* Init UART Hardware */ - UART_IER(uart->hw_base) = 0; /* clear interrupt */ - UART_FCR(uart->hw_base) = ~UARTFCR_UUE; /* disable UART unite */ - - /* Enable UART clock */ - - /* Set both receiver and transmitter in UART mode (not SIR) */ - UART_SIRCR(uart->hw_base) = ~(SIRCR_RSIRE | SIRCR_TSIRE); - - /* Set databits, stopbits and parity. (8-bit data, 1 stopbit, no parity) */ - UART_LCR(uart->hw_base) = UARTLCR_WLEN_8; - - /* set baudrate */ - #if defined(RT_USING_JZ4750) || defined(RT_USING_JZ4755) || defined(RT_USING_JZ4760) - if(REG_CPM_CPCCR & (1UL << 30)) - { - /* CPCCR.ECS = 1: clock source is EXCLK/2 */ - baud_div = BOARD_EXTAL_CLK / 2 / 16 / cfg->baud_rate; - } - else - #endif - { - /* CPCCR.ECS = 0: clock source is EXCLK */ - baud_div = BOARD_EXTAL_CLK / 16 / cfg->baud_rate; - } - - UART_LCR(uart->hw_base) |= UARTLCR_DLAB; - UART_DLHR(uart->hw_base) = (baud_div >> 8) & 0xff; - UART_DLLR(uart->hw_base) = baud_div & 0xff; - - UART_LCR(uart->hw_base) &= ~UARTLCR_DLAB; - - /* Enable UART unit, enable and clear FIFO */ - UART_FCR(uart->hw_base) = UARTFCR_UUE | UARTFCR_FE | UARTFCR_TFLS | UARTFCR_RFLS; - - return (RT_EOK); -} - -static rt_err_t uart_control (struct rt_serial_device *serial, int cmd, void *arg) -{ - struct jz_uart_s * uart; - - uart = serial->parent.user_data; - - RT_ASSERT(uart != RT_NULL); - - switch (cmd) - { - case RT_DEVICE_CTRL_CLR_INT: - /* Disable the UART Interrupt */ - UART_IER(uart->hw_base) &= ~(UARTIER_RIE | UARTIER_RTIE); - rt_hw_interrupt_mask(uart->irqno); - break; - - case RT_DEVICE_CTRL_SET_INT: - /* install interrupt */ - rt_hw_interrupt_install(uart->irqno, uart_irq_handler, - serial, uart->name); - rt_hw_interrupt_umask(uart->irqno); - - /* Enable the UART Interrupt */ - UART_IER(uart->hw_base) |= (UARTIER_RIE | UARTIER_RTIE); - break; - } - - return (RT_EOK); -} - -static int uart_putc (struct rt_serial_device *serial, char c) -{ - struct jz_uart_s* uart; - - uart = serial->parent.user_data; - - /* FIFO status, contain valid data */ - while (!((UART_LSR(uart->hw_base) & (UARTLSR_TDRQ | UARTLSR_TEMT)) == 0x60)); - /* write data */ - UART_TDR(uart->hw_base) = c; - - return (1); -} - -static int uart_getc (struct rt_serial_device *serial) -{ - struct jz_uart_s* uart = serial->parent.user_data; - - /* Receive Data Available */ - if (UART_LSR(uart->hw_base) & UARTLSR_DR) - { - return UART_RDR(uart->hw_base); - } - - return (-1); -} - -static rt_size_t uart_dma_transmit (struct rt_serial_device *serial, const rt_uint8_t *buf, rt_size_t size, int direction) -{ - return (0); -} - -/* UART ISR */ -static void uart_irq_handler(int irqno, void *param) -{ - rt_ubase_t isr; - struct rt_serial_device *serial = (struct rt_serial_device*)param; - struct jz_uart_s* uart = serial->parent.user_data; - - /* read interrupt status and clear it */ - isr = UART_ISR(uart->hw_base); - if (isr & UARTISR_IID_RDI) /* Receive Data Available */ - { - rt_hw_serial_isr(serial,RT_SERIAL_EVENT_RX_IND); - } - - if(isr & UARTISR_IID_THRI) - { - rt_hw_serial_isr(serial,RT_SERIAL_EVENT_TX_DONE); - } -} diff --git a/bsp/x1000/drivers/Kconfig b/bsp/x1000/drivers/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..3c5a59acba32a924930bcb3928662a2368b450f5 --- /dev/null +++ b/bsp/x1000/drivers/Kconfig @@ -0,0 +1,131 @@ +choice + prompt "Choice bsp board" + default BOARD_HALLEY2_REALBOARD_V2 + + config BOARD_HALLEY2 + bool "Using haller2 board" + + config BOARD_PHOENIX + bool "Using phoenix board" + + config BOARD_CANNA + bool "Using canna board" + + config BOARD_HALLEY2_FIR + bool "Using haller2 fir board" + + config BOARD_HALLEY2_REALBOARD + bool "Using haller2 realboard board" + + config BOARD_HALLEY2_REALBOARD_V2 + bool "Using haller2 realboard v2 board" + + config BOARD_HALLEY2_IDELAN + bool "Using haller2 idelan board" +endchoice + +if RT_USING_SERIAL + config RT_USING_UART0 + bool "Using UART0" + default n + + config RT_USING_UART1 + bool "Using UART1" + default n + + config RT_USING_UART2 + bool "Using UART2" + default y +endif + +if RT_USING_SDIO + config RT_USING_MSC0 + bool "Using MSC0 for sd card" + default y + + config RT_USING_MSC1 + bool "Using MSC1 for wifi" + default y + + config RT_MMCSD_STACK_SIZE + int "Set mmc thread stack size" + default 2048 +endif + +if RT_USING_GUIENGINE + config RT_USING_SLCD + bool "Using lcd display" + default y + + if RT_USING_SLCD + choice + prompt "Choice LCD controller" + default RT_USING_ILI9488 + + config RT_USING_ILI9488 + bool "Using ILI9488 controller" + + config RT_USING_ILI9341 + bool "Using ILI9341 controller" + + config RT_USING_OTM4802 + bool "Using OTM4802 controller" + + config RT_USING_TRULY_TFT240240 + bool "Using TFT240240 controller" + endchoice + endif + + if RT_USING_I2C + config RT_USING_TOUCH + bool "Using touch" + default y + + if RT_USING_TOUCH + choice + prompt "Choice touch controller" + default RT_USING_GT9XX + + config RT_USING_GT9XX + bool "Using GT9XX controller" + + config RT_USING_FT6x06 + bool "Using FT6x06 controller" + endchoice + + config RT_TOUCH_THREAD_PRIORITY + int "Set touch thread priority" + range 2 32 + default 10 + endif + endif +endif + +if RT_USING_I2C + config RT_USING_I2C0 + bool "Using iic0 bus" + default y + + config RT_USING_I2C1 + bool "Using iic1 bus" + default n + + config RT_USING_I2C2 + bool "Using iic2 bus" + default n +endif + +config RT_USING_AUDIO + bool "Using audio" + default n +if RT_USING_AUDIO + config RT_USING_ICODEC + bool "Using icodec" + default n +endif + +config RT_USING_CPU_FFS + bool "Using CPU FFS" + default y + + diff --git a/bsp/x1000/drivers/SConscript b/bsp/x1000/drivers/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..76eff659edc4024278993a06024f032588699a1d --- /dev/null +++ b/bsp/x1000/drivers/SConscript @@ -0,0 +1,28 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') + Glob('*.S') +CPPPATH = [cwd, str(Dir('#'))] + +if not GetDepend('RT_USING_I2C'): + SrcRemove(src, ['drv_i2c.c']) +if not GetDepend('RT_USING_SPI'): + SrcRemove(src, ['drv_spi.c']) +if not GetDepend('RT_USING_WDT'): + SrcRemove(src, ['drv_reset.c']) + +group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH) + +# build for sub-directory +list = os.listdir(cwd) +objs = [] + +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')) +group = group + objs + +Return('group') diff --git a/bsp/x1000/drivers/audio/SConscript b/bsp/x1000/drivers/audio/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..f043a55b360600ebddd522929702a54936fcffab --- /dev/null +++ b/bsp/x1000/drivers/audio/SConscript @@ -0,0 +1,11 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') + Glob('*.S') +CPPPATH = [cwd] + +group = DefineGroup('drv_audio', src, depend = ['RT_USING_AUDIO'], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/x1000/drivers/audio/drv_aic.h b/bsp/x1000/drivers/audio/drv_aic.h new file mode 100644 index 0000000000000000000000000000000000000000..de01acf0e693e642bd84aa4b3b5eccc509eb5970 --- /dev/null +++ b/bsp/x1000/drivers/audio/drv_aic.h @@ -0,0 +1,670 @@ +/* + * File : drv_i2s.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ + + + +#ifndef _DRV_I2S_H_ +#define _DRV_I2S_H_ + +/********************************************************************************************************* +** 头文件 +*********************************************************************************************************/ +#include "x1000.h" + +#include "drv_clock.h" +#include "drv_dma.h" + +/********************************************************************************************************* +** CODEC 配置 +*********************************************************************************************************/ +#define JZ_I2S_USE_INNER_CODEC +#undef JZ_I2S_USE_EX_CODEC + + +/********************************************************************************************************* +** AIC 数据结构 +*********************************************************************************************************/ +enum aic_mode { + AIC_NO_MODE = 0, + AIC_I2S_MODE, + AIC_SPDIF_MODE, + AIC_AC97_MODE +}; + +struct jz_aic_device; +struct jz_aic +{ + struct rt_device parent; + uint32_t base; + + struct clk *clk; + struct clk *clk_gate; + + uint32_t clk_rate; + + /* for interrupt */ + int irqno; + int irqflags; + uint32_t ror; /*counter for debug*/ + uint32_t tur; + uint32_t mask; + + /* for AIC work mode protect */ + enum aic_mode aic_working_mode; + + /* for sub device */ + uint32_t dma_addr; + + struct jz_aic_device *aic_dev; +}; + +struct jz_aic_device +{ + struct rt_device parent; +}; + + +/********************************************************************************************************* +** AIC 指令 +*********************************************************************************************************/ +#define AIC_CMD_SET_MODE 0x20 +#define AIC_CMD_SET_RATE 0x21 +#define AIC_CMD_SET_SUBDEV 0x22 + +/********************************************************************************************************* +** AIC 寄存器操作 +***********************************************************************************************************/ +static void inline jz_aic_write_reg(struct jz_aic *aic,uint32_t reg, uint32_t val) +{ + writel(val, aic->base + reg); +} + +static uint32_t inline jz_aic_read_reg(struct jz_aic *aic,uint32_t reg) +{ + return readl(aic->base + reg); +} + + +/* For AC97 and I2S */ +#define AICFR (0x00) +#define AICCR (0x04) +#define ACCR1 (0x08) +#define ACCR2 (0x0c) +#define I2SCR (0x10) +#define AICSR (0x14) +#define ACSR (0x18) +#define I2SSR (0x1c) +#define ACCAR (0x20) +#define ACCDR (0x24) +#define ACSAR (0x28) +#define ACSDR (0x2c) +#define I2SDIV (0x30) +#define AICDR (0x34) + +/* For SPDIF */ +#define SPENA (0x80) +#define SPCTRL (0x84) +#define SPSTATE (0x88) +#define SPCFG1 (0x8c) +#define SPCFG2 (0x90) +#define SPFIFO (0x94) + +#define I2S_CPM_VALID 0xb0000070 +/* For AICFR */ +#define AICFR_ENB_BIT (0) +#define AICFR_ENB_MASK (1 << AICFR_ENB_BIT) +#define AICFR_SYNCD_BIT (1) +#define AICFR_SYNCD_MASK (1 << AICFR_SYNCD_BIT) +#define AICFR_BCKD_BIT (2) +#define AICFR_BCKD_MASK (1 << AICFR_BCKD_BIT) +#define AICFR_RST_BIT (3) +#define AICFR_RST_MASK (1 << AICFR_RST_BIT) +#define AICFR_AUSEL_BIT (4) +#define AICFR_AUSEL_MASK (1 << AICFR_AUSEL_BIT) +#define AICFR_ICDC_BIT (5) +#define AICFR_ICDC_MASK (1 << AICFR_ICDC_BIT) +#define AICFR_LSMP_BIT (6) +#define AICFR_LSMP_MASK (1 << AICFR_LSMP_BIT) +#define AICFR_CDC_SLV_BIT (7) +#define AICFR_CDC_SLV_MASK (1 << AICFR_CDC_SLV_BIT) +#define AICFR_DMODE_BIT (8) +#define AICFR_DMODE_MASK (1 << AICFR_DMODE_BIT) +#define AICFR_ISYNCD_BIT (9) +#define AICFR_ISYNCD_MASK (1 << AICFR_ISYNCD_BIT) +#define AICFR_IBCKD_BIT (10) +#define AICFR_IBCKD_MASK (1 << AICFR_IBCKD_BIT) +#define AICFR_SYSCLKD_BIT (11) +#define AICFR_SYSCLKD_MASK (1 << AICFR_SYSCLKD_BIT) +#define AICFR_MSB_BIT (12) +#define AICFR_MSB_MASK (1 << AICFR_MSB_BIT) +#define AICFR_TFTH_BIT (16) +#define AICFR_TFTH_MASK (0x1f << AICFR_TFTH_BIT) +#define AICFR_RFTH_BIT (24) +#define AICFR_RFTH_MASK (0x1f << AICFR_RFTH_BIT) + +/* For AICCR */ +#define AICCR_EREC_BIT (0) +#define AICCR_EREC_MASK (1 << AICCR_EREC_BIT) +#define AICCR_ERPL_BIT (1) +#define AICCR_ERPL_MASK (1 << AICCR_ERPL_BIT) +#define AICCR_ENLBF_BIT (2) +#define AICCR_ENLBF_MASK (1 << AICCR_ENLBF_BIT) +#define AICCR_ETFS_BIT (3) +#define AICCR_ETFS_MASK (1 << AICCR_ETFS_BIT) +#define AICCR_ERFS_BIT (4) +#define AICCR_ERFS_MASK (1 << AICCR_ERFS_BIT) +#define AICCR_ETUR_BIT (5) +#define AICCR_ETUR_MASK (1 << AICCR_ETUR_BIT) +#define AICCR_EROR_BIT (6) +#define AICCR_EROR_MASK (1 << AICCR_EROR_BIT) +#define AICCR_EALL_INT_MASK (AICCR_EROR_MASK|AICCR_ETUR_MASK|AICCR_ERFS_MASK|AICCR_ETFS_MASK) +#define AICCR_RFLUSH_BIT (7) +#define AICCR_RFLUSH_MASK (1 << AICCR_RFLUSH_BIT) +#define AICCR_TFLUSH_BIT (8) +#define AICCR_TFLUSH_MASK (1 << AICCR_TFLUSH_BIT) +#define AICCR_ASVTSU_BIT (9) +#define AICCR_ASVTSU_MASK (1 << AICCR_ASVTSU_BIT) +#define AICCR_ENDSW_BIT (10) +#define AICCR_ENDSW_MASK (1 << AICCR_ENDSW_BIT) +#define AICCR_M2S_BIT (11) +#define AICCR_M2S_MASK (1 << AICCR_M2S_BIT) +#define AICCR_TDMS_BIT (14) +#define AICCR_TDMS_MASK (1 << AICCR_TDMS_BIT) +#define AICCR_RDMS_BIT (15) +#define AICCR_RDMS_MASK (1 << AICCR_RDMS_BIT) +#define AICCR_ISS_BIT (16) +#define AICCR_ISS_MASK (0x7 << AICCR_ISS_BIT) +#define AICCR_OSS_BIT (19) +#define AICCR_OSS_MASK (0x7 << AICCR_OSS_BIT) +#define AICCR_CHANNEL_BIT (24) +#define AICCR_CHANNEL_MASK (0x7 << AICCR_CHANNEL_BIT) +#define AICCR_PACK16_BIT (28) +#define AICCR_PACK16_MASK (1 << AICCR_PACK16_BIT) + +/* For ACCR1 */ +#define ACCR1_XS_BIT (0) +#define ACCR1_XS_MASK (0x3ff << ACCR1_XS_BIT) +#define ACCR1_RS_BIT (16) +#define ACCR1_RS_MASK (0x3ff << ACCR1_RS_BIT) + +/* For ACCR2 */ +#define ACCR2_SA_BIT (0) +#define ACCR2_SA_MASK (1 << ACCR2_SA_BIT) +#define ACCR2_SS_BIT (1) +#define ACCR2_SS_MASK (1 << ACCR2_SS_BIT) +#define ACCR2_SR_BIT (2) +#define ACCR2_SR_MASK (1 << ACCR2_SR_BIT) +#define ACCR2_SO_BIT (3) +#define ACCR2_SO_MASK (1 << ACCR2_SO_BIT) +#define ACCR2_ECADT_BIT (16) +#define ACCR2_ECADT_MASK (1 << ACCR2_ECADT_BIT) +#define ACCR2_ECADR_BIT (17) +#define ACCR2_ECADR_MASK (1 << ACCR2_ECADR_BIT) +#define ACCR2_ERSTO_BIT (18) +#define ACCR2_ERSTO_MASK (1 << ACCR2_ERSTO_BIT) + +/* For I2SCR */ +#define I2SCR_AMSL_BIT (0) +#define I2SCR_AMSL_MASK (1 << I2SCR_AMSL_BIT) +#define I2SCR_ESCLK_BIT (4) +#define I2SCR_ESCLK_MASK (1 << I2SCR_ESCLK_BIT) +#define I2SCR_STPBK_BIT (12) +#define I2SCR_STPBK_MASK (1 << I2SCR_STPBK_BIT) +#define I2SCR_ISTPBK_BIT (13) +#define I2SCR_ISTPBK_MASK (1 << I2SCR_ISTPBK_BIT) +#define I2SCR_SWLH_BIT (16) +#define I2SCR_SWLH_MASK (1 << I2SCR_SWLH_BIT) +#define I2SCR_RFIRST_BIT (17) +#define I2SCR_RFIRST_MASK (1 << I2SCR_RFIRST_BIT) + +/* For AICSR */ +#define AICSR_TFS_BIT (3) +#define AICSR_TFS_MASK (1 << AICSR_TFS_BIT) +#define AICSR_RFS_BIT (4) +#define AICSR_RFS_MASK (1 << AICSR_RFS_BIT) +#define AICSR_TUR_BIT (5) +#define AICSR_TUR_MASK (1 << AICSR_TUR_BIT) +#define AICSR_ROR_BIT (6) +#define AICSR_ROR_MASK (1 << AICSR_ROR_BIT) +#define AICSR_ALL_INT_MASK (AICSR_TFS_MASK|AICSR_RFS_MASK|AICSR_TUR_MASK|AICSR_ROR_MASK) +#define AICSR_TFL_BIT (8) +#define AICSR_TFL_MASK (0x3f << AICSR_TFL_BIT) +#define AICSR_RFL_BIT (24) +#define AICSR_RFL_MASK (0x3f << AICSR_RFL_BIT) + +/* For ACSR */ +#define ACSR_CADT_BIT (16) +#define ACSR_CADT_MASK (1 << ACSR_CADT_BIT) +#define ACSR_SADR_BIT (17) +#define ACSR_SADR_MASK (1 << ACSR_SADR_BIT) +#define ACSR_RSTO_BIT (18) +#define ACSR_RSTO_MASK (1 << ACSR_RSTO_BIT) +#define ACSR_CLPM_BIT (19) +#define ACSR_CLPM_MASK (1 << ACSR_CLPM_BIT) +#define ACSR_CRDY_BIT (20) +#define ACSR_CRDY_MASK (1 << ACSR_CRDY_BIT) +#define ACSR_SLTERR_BIT (21) +#define ACSR_SLTERR_MASK (1 << ACSR_SLTERR_BIT) + +/* For I2SSR */ +#define I2SSR_BSY_BIT (2) +#define I2SSR_BSY_MASK (1 << I2SSR_BSY_BIT) +#define I2SSR_RBSY_BIT (3) +#define I2SSR_RBSY_MASK (1 << I2SSR_RBSY_BIT) +#define I2SSR_TBSY_BIT (4) +#define I2SSR_TBSY_MASK (1 << I2SSR_TBSY_BIT) +#define I2SSR_CHBSY_BIT (5) +#define I2SSR_CHBSY_MASK (1 << I2SSR_CHBSY_BIT) + +/* For ACCAR */ +#define ACCAR_CAR_BIT (0) +#define ACCAR_CAR_MASK (0xfffff << ACCAR_CAR_BIT) + +/* For ACCDR */ +#define ACCDR_CDR_BIT (0) +#define ACCDR_CDR_MASK (0xfffff << ACCDR_CDR_BIT) + +/* For ACSAR */ +#define ACSAR_SAR_BIT (0) +#define ACSAR_SAR_MASK (0xfffff << ACSAR_SAR_BIT) + +/* For ACSDR */ +#define ACSDR_SDR_BIT (0) +#define ACSDR_SDR_MASK (0xfffff << ACSDR_SDR_BIT) + +/* For I2SDIV */ +#define I2SDIV_DV_BIT (0) +#define I2SDIV_DV_MASK (0x1ff << I2SDIV_DV_BIT) +#define I2SDIV_IDV_BIT (16) +#define I2SDIV_IDV_MASK (0x1ff << I2SDIV_IDV_BIT) + +/* For AICDR */ +#define AICDR_DATA_BIT (0) +#define AICDR_DATA_MASK (0xfffffff << AICDR_DATA_BIT) + +/* For SPENA */ +#define SPENA_SPEN_BIT (0) +#define SPENA_SPEN_MASK (1 << SPENA_SPEN_BIT) + +/* For SPCTRL */ +#define SPCTRL_M_FFUR_BIT (0) +#define SPCTRL_M_FFUR_MASK (1 << SPCTRL_M_FFUR_BIT) +#define SPCTRL_M_TRIG_BIT (1) +#define SPCTRL_M_TRIG_MASK (1 << SPCTRL_M_TRIG_BIT) +#define SPCTRL_SPDIF_I2S_BIT (10) +#define SPCTRL_SPDIF_I2S_MASK (1 << SPCTRL_SPDIF_I2S_BIT) +#define SPCTRL_SFT_RST_BIT (11) +#define SPCTRL_SFT_RST_MASK (1 << SPCTRL_SFT_RST_BIT) +#define SPCTRL_INVALID_BIT (12) +#define SPCTRL_INVALID_MASK (1 << SPCTRL_INVALID_BIT) +#define SPCTRL_SIGN_N_BIT (13) +#define SPCTRL_SIGN_N_MASK (1 << SPCTRL_SIGN_N_BIT) +#define SPCTRL_D_TYPE_BIT (14) +#define SPCTRL_D_TYPE_MASK (1 << SPCTRL_D_TYPE_BIT) +#define SPCTRL_DMA_EN_BIT (15) +#define SPCTRL_DMA_EN_MASK (1 << SPCTRL_DMA_EN_BIT) + +/* For SPSTATE */ +#define SPSTATE_F_FFUR_BIT (0) +#define SPSTATE_F_FFUR_MASK (1 << SPSTATE_F_FFUR_BIT) +#define SPSTATE_F_TRIG_BIT (1) +#define SPSTATE_F_TRIG_MASK (1 << SPSTATE_F_TRIG_BIT) +#define SPSTATE_BUSY_BIT (7) +#define SPSTATE_BUSY_MASK (1 << SPSTATE_BUSY_BIT) +#define SPSTATE_FIFO_LVL_BIT (8) +#define SPSTATE_FIFO_LVL_MASK (0x7f << SPSTATE_FIFO_LVL_BIT) + +/* For SPCFG1 */ +#define SPCFG1_CH2_NUM_BIT (0) +#define SPCFG1_CH2_NUM_MASK (0xf << SPCFG1_CH2_NUM_BIT) +#define SPCFG1_CH1_NUM_BIT (4) +#define SPCFG1_CH1_NUM_MASK (0xf << SPCFG1_CH1_NUM_BIT) +#define SPCFG1_SRC_NUM_BIT (8) +#define SPCFG1_SRC_NUM_MASK (0xf << SPCFG1_SRC_NUM_BIT) +#define SPCFG1_TRIG_BIT (12) +#define SPCFG1_TRIG_MASK (0x3 << SPCFG1_TRIG_BIT) +#define SPCFG1_ZRO_VLD_BIT (16) +#define SPCFG1_ZRO_VLD_MASK (1 << SPCFG1_ZRO_VLD_BIT) +#define SPCFG1_INIT_LVL_BIT (17) +#define SPCFG1_INIT_LVL_MASK (1 << SPCFG1_INIT_LVL_BIT) + +/* For SPCFG2 */ +#define SPCFG2_CON_PRO_BIT (0) +#define SPCFG2_CON_PRO_MASK (1 << SPCFG2_CON_PRO_BIT) +#define SPCFG2_AUDIO_N_BIT (1) +#define SPCFG2_AUDIO_N_MASK (1 << SPCFG2_AUDIO_N_BIT) +#define SPCFG2_COPY_N_BIT (2) +#define SPCFG2_COPY_N_MASK (1 << SPCFG2_COPY_N_BIT) +#define SPCFG2_PRE_BIT (3) +#define SPCFG2_PRE_MASK (1 << SPCFG2_PRE_BIT) +#define SPCFG2_CH_MD_BIT (6) +#define SPCFG2_CH_MD_MASK (0x3 << SPCFG2_CH_MD_BIT) +#define SPCFG2_CAT_CODE_BIT (8) +#define SPCFG2_CAT_CODE_MASK (0xff << SPCFG2_CAT_CODE_BIT) +#define SPCFG2_CLK_ACU_BIT (16) +#define SPCFG2_CLK_ACU_MASK (0x3 << SPCFG2_CLK_ACU_BIT) +#define SPCFG2_MAX_WL_BIT (18) +#define SPCFG2_MAX_WL_MASK (1 << SPCFG2_MAX_WL_BIT) +#define SPCFG2_SAMPL_WL_BIT (19) +#define SPCFG2_SAMPL_WL_MASK (0x7 << SPCFG2_SAMPL_WL_BIT) +#define SPCFG2_SAMPL_WL_20BITM (0x1 << SPCFG2_SAMPL_WL_BIT) +#define SPCFG2_SAMPL_WL_21BIT (0x6 << SPCFG2_SAMPL_WL_BIT) +#define SPCFG2_SAMPL_WL_22BIT (0x2 << SPCFG2_SAMPL_WL_BIT) +#define SPCFG2_SAMPL_WL_23BIT (0x4 << SPCFG2_SAMPL_WL_BIT) +#define SPCFG2_SAMPL_WL_24BIT (0x5 << SPCFG2_SAMPL_WL_BIT) +#define SPCFG2_SAMPL_WL_16BIT (0x1 << SPCFG2_SAMPL_WL_BIT) +#define SPCFG2_SAMPL_WL_17BIT (0x6 << SPCFG2_SAMPL_WL_BIT) +#define SPCFG2_SAMPL_WL_18BIT (0x2 << SPCFG2_SAMPL_WL_BIT) +#define SPCFG2_SAMPL_WL_19BIT (0x4 << SPCFG2_SAMPL_WL_BIT) +#define SPCFG2_SAMPL_WL_20BITL (0x5 << SPCFG2_SAMPL_WL_BIT) +#define SPCFG2_ORG_FRQ_BIT (22) +#define SPCFG2_ORG_FRQ_MASK (0xf << SPCFG2_ORG_FRQ_BIT) +#define SPCFG2_FS_BIT (26) +#define SPCFG2_FS_MASK (0xf << SPCFG2_FS_BIT) + +#define SPFIFO_DATA_BIT (0) +#define SPFIFO_DATA_MASK (0xffffff << SPFIFO_DATA_BIT) + +#define jz_aic_set_reg(parent, addr, val, mask, offset) \ + do { \ + volatile unsigned int reg_tmp; \ + reg_tmp = jz_aic_read_reg(parent, addr); \ + reg_tmp &= ~(mask); \ + reg_tmp |= (val << offset) & mask; \ + jz_aic_write_reg(parent, addr, reg_tmp); \ + } while(0) + +#define jz_aic_get_reg(parent, addr, mask, offset) \ + ((jz_aic_read_reg(parent, addr) & mask) >> offset) + +/*For ALL*/ +/*aic fr*/ +#define __aic_enable_msb(parent) \ + jz_aic_set_reg(parent, AICFR, 1, AICFR_MSB_MASK, AICFR_MSB_BIT) +#define __aic_disable_msb(parent) \ + jz_aic_set_reg(parent, AICFR, 0, AICFR_MSB_MASK, AICFR_MSB_BIT) +#define __aic_reset(parent) \ + jz_aic_set_reg(parent, AICFR, 1, AICFR_RST_MASK, AICFR_RST_BIT) +/*aic cr*/ +#define __aic_flush_rxfifo(parent) \ + jz_aic_set_reg(parent, AICCR, 1, AICCR_RFLUSH_MASK, AICCR_RFLUSH_BIT) +#define __aic_flush_txfifo(parent) \ + jz_aic_set_reg(parent, AICCR, 1, AICCR_TFLUSH_MASK, AICCR_TFLUSH_BIT) +#define __aic_en_ror_int(parent) \ + jz_aic_set_reg(parent, AICCR, 1, AICCR_EROR_MASK, AICCR_EROR_BIT) +#define __aic_dis_ror_int(parent) \ + jz_aic_set_reg(parent, AICCR, 0, AICCR_EROR_MASK, AICCR_EROR_BIT) +#define __aic_en_tur_int(parent) \ + jz_aic_set_reg(parent, AICCR, 1, AICCR_ETUR_MASK, AICCR_ETUR_BIT) +#define __aic_dis_tur_int(parent) \ + jz_aic_set_reg(parent, AICCR, 0, AICCR_ETUR_MASK, AICCR_ETUR_BIT) +#define __aic_en_rfs_int(parent) \ + jz_aic_set_reg(parent, AICCR, 1, AICCR_ERFS_MASK, AICCR_ERFS_BIT) +#define __aic_dis_rfs_int(parent) \ + jz_aic_set_reg(parent, AICCR, 0, AICCR_ERFS_MASK, AICCR_ERFS_BIT) +#define __aic_en_tfs_int(parent) \ + jz_aic_set_reg(parent, AICCR, 1, AICCR_ETFS_MASK, AICCR_ETFS_BIT) +#define __aic_dis_tfs_int(parent) \ + jz_aic_set_reg(parent, AICCR, 0, AICCR_ETFS_MASK, AICCR_ETFS_BIT) +#define __aic_get_irq_enmask(parent) \ + jz_aic_get_reg(parent, AICCR, AICCR_EALL_INT_MASK, AICCR_ETFS_BIT) +#define __aic_set_irq_enmask(parent, mask) \ + jz_aic_set_reg(parent, AICCR, mask, AICCR_EALL_INT_MASK, AICCR_ETFS_BIT) +/*aic sr*/ +#define __aic_read_rfl(parent) \ + jz_aic_get_reg(parent, AICSR ,AICSR_RFL_MASK, AICSR_RFL_BIT) +#define __aic_read_tfl(parent) \ + jz_aic_get_reg(parent, AICSR, AICSR_TFL_MASK, AICSR_TFL_BIT) +#define __aic_clear_ror(parent) \ + jz_aic_set_reg(parent, AICSR, 0, AICSR_ROR_MASK, AICSR_ROR_BIT) +#define __aic_test_ror(parent) \ + jz_aic_get_reg(parent, AICSR, AICSR_ROR_MASK, AICSR_ROR_BIT) +#define __aic_clear_tur(parent) \ + jz_aic_set_reg(parent, AICSR, 0, AICSR_TUR_MASK, AICSR_TUR_BIT) +#define __aic_test_tur(parent) \ + jz_aic_get_reg(parent, AICSR, AICSR_TUR_MASK, AICSR_TUR_BIT) +#define __aic_clear_rfs(parent) \ + jz_aic_set_reg(parent, AICSR, 0, AICSR_RFS_MASK, AICSR_RFS_BIT) +#define __aic_test_rfs(parent) \ + jz_aic_get_reg(parent, AICSR, AICSR_RFS_MASK, AICSR_RFS_BIT) +#define __aic_clear_tfs(parent) \ + jz_aic_set_reg(parent, AICSR, 0, AICSR_TFS_MASK, AICSR_TFS_BIT) +#define __aic_test_tfs(parent) \ + jz_aic_get_reg(parent, AICSR, AICSR_TFS_MASK, AICSR_TFS_BIT) +#define __aic_get_irq_flag(parent) \ + jz_aic_get_reg(parent, AICSR, AICSR_ALL_INT_MASK, AICSR_TFS_BIT) +#define __aic_clear_all_irq_flag(parent) \ + jz_aic_set_reg(parent, AICSR, AICSR_ALL_INT_MASK, AICSR_ALL_INT_MASK, AICSR_TFS_BIT) +/* aic dr*/ +#define __aic_write_txfifo(parent, n) \ + jz_aic_write_reg(parent, AICDR, (n)) + +/* For SPFIFO */ +#define __spdif_test_underrun(parent) \ + jz_aic_get_reg(parent, SPSTATE, SPSTATE_F_FFUR_MASK, SPSTATE_F_FFUR_BIT) +#define __spdif_clear_underrun(parent) \ + jz_aic_set_reg(parent, SPSTATE, 0, SPSTATE_F_FFUR_MASK, SPSTATE_F_FFUR_BIT) +#define __spdif_is_enable_transmit_dma(parent) \ + jz_aic_get_reg(parent, SPCTRL, SPCTRL_DMA_EN_MASK, SPCTRL_DMA_EN_BIT) +#define __spdif_enable_transmit_dma(parent) \ + jz_aic_set_reg(parent, SPCTRL, 1, SPCTRL_DMA_EN_MASK, SPCTRL_DMA_EN_BIT) +#define __spdif_disable_transmit_dma(parent) \ + jz_aic_set_reg(parent, SPCTRL, 0, SPCTRL_DMA_EN_MASK, SPCTRL_DMA_EN_BIT) +#define __spdif_reset(parent) \ + jz_aic_set_reg(parent, SPCTRL, 1, SPCTRL_SFT_RST_MASK, SPCTRL_SFT_RST_BIT) +#define __spdif_get_reset(parent) \ + jz_aic_get_reg(parent, SPCTRL,SPCTRL_SFT_RST_MASK, SPCTRL_SFT_RST_BIT) +#define __spdif_enable(parent) \ + jz_aic_set_reg(parent, SPENA, 1, SPENA_SPEN_MASK, SPENA_SPEN_BIT) +#define __spdif_disable(parent) \ + jz_aic_set_reg(parent, SPENA, 0, SPENA_SPEN_MASK, SPENA_SPEN_BIT) +#define __spdif_set_dtype(parent, n) \ + jz_aic_set_reg(parent, SPCTRL, n, SPCTRL_D_TYPE_MASK, SPCTRL_D_TYPE_BIT) +#define __spdif_set_trigger(parent, n) \ + jz_aic_set_reg(parent, SPCFG1, n, SPCFG1_TRIG_MASK, SPCFG1_TRIG_BIT) +#define __spdif_set_ch1num(parent, n) \ + jz_aic_set_reg(parent, SPCFG1, n, SPCFG1_CH1_NUM_MASK, SPCFG1_CH1_NUM_BIT) +#define __spdif_set_ch2num(parent, n) \ + jz_aic_set_reg(parent, SPCFG1, n, SPCFG1_CH2_NUM_MASK, SPCFG1_CH2_NUM_BIT) +#define __spdif_set_srcnum(parent, n) \ + jz_aic_set_reg(parent, SPCFG1, n, SPCFG1_SRC_NUM_MASK, SPCFG1_SRC_NUM_BIT) +#define __interface_select_spdif(parent) \ + jz_aic_set_reg(parent, SPCTRL, 1, SPCTRL_SPDIF_I2S_MASK, SPCTRL_SPDIF_I2S_BIT) +#define __spdif_play_lastsample(parent) \ + jz_aic_set_reg(parent, SPCFG1, 1, SPCFG1_ZRO_VLD_MASK, SPCFG1_ZRO_VLD_BIT) +#define __spdif_init_set_low(parent) \ + jz_aic_set_reg(parent, SPCFG1, 0, SPCFG1_INIT_LVL_MASK, SPCFG1_INIT_LVL_BIT) +#define __spdif_choose_consumer(parent) \ + jz_aic_set_reg(parent, SPCFG2, 0, SPCFG2_CON_PRO_MASK, SPCFG2_CON_PRO_BIT) +#define __spdif_clear_audion(parent) \ + jz_aic_set_reg(parent, SPCFG2, 0, SPCFG2_AUDIO_N_MASK, SPCFG2_AUDIO_N_BIT) +#define __spdif_set_copyn(parent) \ + jz_aic_set_reg(parent, SPCFG2, 1, SPCFG2_COPY_N_MASK, SPCFG2_COPY_N_BIT) +#define __spdif_clear_pre(parent) \ + jz_aic_set_reg(parent, SPCFG2, 0, SPCFG2_PRE_MASK, SPCFG2_PRE_BIT) +#define __spdif_choose_chmd(parent) \ + jz_aic_set_reg(parent, SPCFG2, 0, SPCFG2_CH_MD_MASK, SPCFG2_CH_MD_BIT) +#define __spdif_set_category_code_normal(parent) \ + jz_aic_set_reg(parent, SPCFG2, 0, SPCFG2_CAT_CODE_MASK, SPCFG2_CAT_CODE_BIT) +#define __spdif_set_clkacu(parent, n) \ + jz_aic_set_reg(parent, SPCFG2, n, SPCFG2_CLK_ACU_MASK, SPCFG2_CLK_ACU_BIT) +#define __spdif_set_sample_size(parent, n) \ + jz_aic_set_reg(parent, SPCFG2, n, SPCFG2_SAMPL_WL_MASK, SPCFG2_SAMPL_WL_BIT) +#define __spdif_set_max_wl(parent, n) \ + jz_aic_set_reg(parent, SPCFG2, n, SPCFG2_MAX_WL_MASK, SPCFG2_MAX_WL_BIT) +#define __spdif_set_ori_sample_freq(parent, org_frq_tmp) \ + jz_aic_set_reg(parent, SPCFG2, org_frq_tmp, SPCFG2_ORG_FRQ_MASK, SPCFG2_ORG_FRQ_BIT) +#define __spdif_set_sample_freq(parent, fs_tmp) \ + jz_aic_set_reg(parent, SPCFG2, fs_tmp, SPCFG2_FS_MASK, SPCFG2_FS_BIT) +#define __spdif_set_valid(parent) \ + jz_aic_set_reg(parent, SPCTRL, 0, SPCTRL_INVALID_MASK, SPCTRL_INVALID_BIT) +#define __spdif_mask_trig(parent) \ + jz_aic_set_reg(parent, SPCTRL, 1, SPCTRL_M_TRIG_MASK, SPCTRL_M_TRIG_BIT) +#define __spdif_disable_underrun_intr(parent) \ + jz_aic_set_reg(parent, SPCTRL, 1, SPCTRL_M_FFUR_MASK, SPCTRL_M_FFUR_BIT) +#define __spdif_set_signn(parent) \ + jz_aic_set_reg(parent, SPCTRL, 1, SPCTRL_SIGN_N_MASK, SPCTRL_SIGN_N_BIT) +#define __spdif_clear_signn(parent) \ + jz_aic_set_reg(parent, SPCTRL, 0, SPCTRL_SIGN_N_MASK, SPCTRL_SIGN_N_BIT) + +/* For I2S */ +/*aic fr*/ +#define __i2s_is_enable(parent) \ + jz_aic_get_reg(parent, AICFR, AICFR_ENB_MASK, AICFR_ENB_BIT) +#define __aic_enable(parent) \ + jz_aic_set_reg(parent, AICFR, 1, AICFR_ENB_MASK, AICFR_ENB_BIT) + +#define __aic_disable(parent) \ + jz_aic_set_reg(parent, AICFR, 0, AICFR_ENB_MASK, AICFR_ENB_BIT) + +#define __i2s_external_codec(parent) \ + jz_aic_set_reg(parent, AICFR, 0, AICFR_ICDC_MASK, AICFR_ICDC_BIT) + +#define __i2s_bclk_output(parent) \ + jz_aic_set_reg(parent, AICFR, 1, AICFR_BCKD_MASK, AICFR_BCKD_BIT) + +#define __i2s_bclk_input(parent) \ + jz_aic_set_reg(parent, AICFR, 0, AICFR_BCKD_MASK, AICFR_BCKD_BIT) + +#define __i2s_sync_output(parent) \ + jz_aic_set_reg(parent, AICFR, 1, AICFR_SYNCD_MASK, AICFR_SYNCD_BIT) + +#define __i2s_sync_input(parent) \ + jz_aic_set_reg(parent, AICFR, 0, AICFR_SYNCD_MASK, AICFR_SYNCD_BIT) + +#define __aic_select_i2s(parent) \ + jz_aic_set_reg(parent, AICFR, 1, AICFR_AUSEL_MASK, AICFR_AUSEL_BIT) + +#define __aic_select_internal_codec(parent) \ + jz_aic_set_reg(parent, AICFR, 1, AICFR_ICDC_MASK, AICFR_ICDC_BIT) + +#define __aic_select_external_codec(parent) \ + jz_aic_set_reg(parent, AICFR, 0, AICFR_ICDC_MASK, AICFR_ICDC_BIT) + +#define __i2s_play_zero(parent) \ + jz_aic_set_reg(parent, AICFR, 0, AICFR_LSMP_MASK, AICFR_LSMP_BIT) + +#define __i2s_play_lastsample(parent) \ + jz_aic_set_reg(parent, AICFR, 1, AICFR_LSMP_MASK, AICFR_LSMP_BIT) + +#define __i2s_codec_slave(parent) \ + jz_aic_set_reg(parent, AICFR, 1, AICFR_CDC_SLV_MASK, AICFR_CDC_SLV_BIT) + +#define __i2s_codec_master(parent) \ + jz_aic_set_reg(parent, AICFR, 0, AICFR_CDC_SLV_MASK, AICFR_CDC_SLV_BIT) + +#define __i2s_select_sysclk_output(parent) \ + jz_aic_set_reg(parent, AICFR, 0, AICFR_SYSCLKD_MASK, AICFR_SYSCLKD_BIT) + +#define __i2s_select_sysclk_input(parent) \ + jz_aic_set_reg(parent, AICFR, 1, AICFR_SYSCLKD_MASK, AICFR_SYSCLKD_BIT) + +#define __i2s_set_transmit_trigger(parent, n) \ + jz_aic_set_reg(parent, AICFR, n, AICFR_TFTH_MASK, AICFR_TFTH_BIT) + +#define __i2s_set_receive_trigger(parent, n) \ + jz_aic_set_reg(parent, AICFR, n, AICFR_RFTH_MASK, AICFR_RFTH_BIT) +/*aiccr*/ +#define I2S_SS2REG(n) (((n) > 18 ? (n)/6 : (n)/9)) /* n = 8, 16, 18, 20, 24 */ +#define __i2s_aic_packet16(parent) \ + jz_aic_set_reg(parent, AICCR, 1, AICCR_PACK16_MASK, AICCR_PACK16_BIT) +#define __i2s_aic_unpacket16(parent) \ + jz_aic_set_reg(parent, AICCR, 0, AICCR_PACK16_MASK, AICCR_PACK16_BIT) +#define __i2s_channel(parent, n) \ + jz_aic_set_reg(parent, AICCR, ((n) - 1), AICCR_CHANNEL_MASK, AICCR_CHANNEL_BIT) +#define __i2s_set_oss(parent, n) \ + jz_aic_set_reg(parent, AICCR, I2S_SS2REG(n) , AICCR_OSS_MASK, AICCR_OSS_BIT) +#define __i2s_set_iss(parent, n) \ + jz_aic_set_reg(parent, AICCR, I2S_SS2REG(n) , AICCR_ISS_MASK, AICCR_ISS_BIT) +#define __i2s_transmit_dma_is_enable(parent) \ + jz_aic_get_reg(parent, AICCR, AICCR_TDMS_MASK,AICCR_TDMS_BIT) +#define __i2s_disable_transmit_dma(parent) \ + jz_aic_set_reg(parent, AICCR, 0, AICCR_TDMS_MASK, AICCR_TDMS_BIT) +#define __i2s_enable_transmit_dma(parent) \ + jz_aic_set_reg(parent, AICCR, 1, AICCR_TDMS_MASK, AICCR_TDMS_BIT) +#define __i2s_receive_dma_is_enable(parent) \ + jz_aic_get_reg(parent, AICCR, AICCR_RDMS_MASK,AICCR_RDMS_BIT) +#define __i2s_disable_receive_dma(parent) \ + jz_aic_set_reg(parent, AICCR, 0, AICCR_RDMS_MASK, AICCR_RDMS_BIT) +#define __i2s_enable_receive_dma(parent) \ + jz_aic_set_reg(parent, AICCR, 1, AICCR_RDMS_MASK, AICCR_RDMS_BIT) +#define __i2s_m2s_enable(parent) \ + jz_aic_set_reg(parent, AICCR, 1, AICCR_M2S_MASK, AICCR_M2S_BIT) +#define __i2s_m2s_disable(parent) \ + jz_aic_set_reg(parent, AICCR, 0, AICCR_M2S_MASK, AICCR_M2S_BIT) +#define __i2s_endsw_enable(parent) \ + jz_aic_set_reg(parent, AICCR, 1, AICCR_ENDSW_MASK, AICCR_ENDSW_BIT) +#define __i2s_endsw_disable(parent) \ + jz_aic_set_reg(parent, AICCR, 0, AICCR_ENDSW_MASK, AICCR_ENDSW_BIT) +#define __i2s_asvtsu_enable(parent) \ + jz_aic_set_reg(parent, AICCR, 1, AICCR_ASVTSU_MASK, AICCR_ASVTSU_BIT) +#define __i2s_asvtsu_disable(parent) \ + jz_aic_set_reg(parent, AICCR, 0, AICCR_ASVTSU_MASK, AICCR_ASVTSU_BIT) +#define __i2s_enable_replay(parent) \ + jz_aic_set_reg(parent, AICCR, 1, AICCR_ERPL_MASK, AICCR_ERPL_BIT) +#define __i2s_enable_record(parent) \ + jz_aic_set_reg(parent, AICCR, 1, AICCR_EREC_MASK, AICCR_EREC_BIT) +#define __i2s_enable_loopback(parent) \ + jz_aic_set_reg(parent, AICCR, 1, AICCR_ENLBF_MASK, AICCR_ENLBF_BIT) +#define __i2s_disable_replay(parent) \ + jz_aic_set_reg(parent, AICCR, 0, AICCR_ERPL_MASK, AICCR_ERPL_BIT) +#define __i2s_disable_record(parent) \ + jz_aic_set_reg(parent, AICCR, 0, AICCR_EREC_MASK, AICCR_EREC_BIT) +#define __i2s_disable_loopback(parent) \ + jz_aic_set_reg(parent, AICCR, 0, AICCR_ENLBF_MASK, AICCR_ENLBF_BIT) +/*i2scr*/ +#define __i2s_select_i2s_fmt(parent) \ + jz_aic_set_reg(parent, I2SCR, 0, I2SCR_AMSL_MASK, I2SCR_AMSL_BIT) +#define __i2s_select_msb_fmt(parent) \ + jz_aic_set_reg(parent, I2SCR, 1, I2SCR_AMSL_MASK, I2SCR_AMSL_BIT) +#define __i2s_enable_sysclk_output(parent) \ + jz_aic_set_reg(parent, I2SCR, 1, I2SCR_ESCLK_MASK, I2SCR_ESCLK_BIT) +#define __i2s_disable_sysclk_output(parent) \ + jz_aic_set_reg(parent, I2SCR, 0, I2SCR_ESCLK_MASK, I2SCR_ESCLK_BIT) +#define __i2s_stop_bitclk(parent) \ + jz_aic_set_reg(parent, I2SCR, 1, I2SCR_STPBK_MASK, I2SCR_STPBK_BIT) +#define __i2s_start_bitclk(parent) \ + jz_aic_set_reg(parent, I2SCR, 0, I2SCR_STPBK_MASK, I2SCR_STPBK_BIT) +#define __i2s_select_packed_lrswap(parent) \ + jz_aic_set_reg(parent, I2SCR, 1, I2SCR_SWLH_MASK, I2SCR_SWLH_BIT) +#define __i2s_select_packed_lrnorm(parent) \ + jz_aic_set_reg(parent, I2SCR, 0, I2SCR_SWLH_MASK, I2SCR_SWLH_BIT) +#define __i2s_send_rfirst(parent) \ + jz_aic_set_reg(parent, I2SCR, 1, I2SCR_RFIRST_MASK, I2SCR_RFIRST_BIT) +#define __i2s_send_lfirst(parent) \ + jz_aic_set_reg(parent, I2SCR, 0, I2SCR_RFIRST_MASK, I2SCR_RFIRST_BIT) +/*i2ssr*/ +#define __i2s_transmiter_is_busy(parent) \ + (!!(jz_aic_read_reg(parent, I2SSR) & I2SSR_TBSY_MASK)) +#define __i2s_receiver_is_busy(parent) \ + (!!(jz_aic_read_reg(parent, I2SSR) & I2SSR_TBSY_MASK)) + +/*i2s_div*/ +#define __i2s_set_idv(parent, div) \ + jz_aic_set_reg(parent, I2SDIV, div, I2SDIV_IDV_MASK, I2SDIV_IDV_BIT) +#define __i2s_set_dv(parent, div) \ + jz_aic_set_reg(parent, I2SDIV, div, I2SDIV_DV_MASK, I2SDIV_DV_BIT) + + +#endif /* _DRV_I2S_H_ */ diff --git a/bsp/x1000/drivers/audio/drv_aic_i2s.c b/bsp/x1000/drivers/audio/drv_aic_i2s.c new file mode 100644 index 0000000000000000000000000000000000000000..1654b136ed84c0d31fd3194d739101cdf6a46603 --- /dev/null +++ b/bsp/x1000/drivers/audio/drv_aic_i2s.c @@ -0,0 +1,619 @@ +/* + * File : drv_i2s.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ + +#include +#include +#include +#include + +#include "dma.h" + + +#ifdef RT_USING_FINSH +#include +#endif + +#include "board.h" +#include "drv_clock.h" +#include "drv_dma.h" +#include "drv_gpio.h" +#include "drv_aic.h" +#include "drv_aic_i2s.h" + +#define AIC_DEBUG 0 +#if AIC_DEBUG +#define AIC_DBG(...) rt_kprintf("[AIC]"),rt_kprintf(__VA_ARGS__) +#else +#define AIC_DBG(...) +#endif + +static struct jz_aic _g_jz_aic; + +int aic_set_rate(struct jz_aic *aic, uint32_t freq) +{ + int ret; +// clk_disable(aic->clk); + + if (aic->clk_rate != freq) + { + ret = clk_set_rate(aic->clk, freq); + if (!ret) + aic->clk_rate = clk_get_rate(aic->clk); + + } + +// clk_enable(aic->clk); + + AIC_DBG("aic clock = %d\n",clk_get_rate(aic->clk)); + return aic->clk_rate; +} + +static void aic_irq_handler(int vector, void *param) +{ + struct jz_aic *aic = (struct jz_aic *)param; + + aic->mask = __aic_get_irq_enmask(aic); + + if (aic->mask && (aic->mask & __aic_get_irq_flag(aic))) + { + /*Disable all aic interrupt*/ + __aic_set_irq_enmask(aic, 0); + + if ((aic->mask & 0x8) && __aic_test_ror(aic)) + { + aic->ror++; + AIC_DBG("recieve fifo [overrun] interrupt time [%d]\n", + aic->ror); + } + + if ((aic->mask & 0x4) && __aic_test_tur(aic)) + { + aic->tur++; + AIC_DBG("transmit fifo [underrun] interrupt time [%d]\n", + aic->tur); + } + + if ((aic->mask & 0x2) && __aic_test_rfs(aic)) + { + AIC_DBG("[recieve] fifo at or above threshold interrupt time\n"); + } + + if ((aic->mask & 0x1) && __aic_test_tfs(aic)) + { + AIC_DBG("[transmit] fifo at or blow threshold interrupt time\n"); + } + + /*sleep, avoid frequently interrupt*/ + __aic_clear_all_irq_flag(aic); + __aic_set_irq_enmask(aic, aic->mask); + } +} + +struct jz_aic* _aic_init(void) +{ + struct jz_aic *aic = &_g_jz_aic; + struct rt_device *device; + + + aic->base = AIC_BASE; + + aic->clk_gate = clk_get("aic"); + aic->clk = clk_get("cgu_i2s"); + if((aic->clk_gate == RT_NULL) || (aic->clk == RT_NULL)) + { + AIC_DBG("aic or i2s clk error\n"); + + goto aic_init_error; + } + /* set system clock */ + clk_set_rate(aic->clk, 24000000); + aic->clk_rate = 24000000; + + clk_enable(aic->clk_gate); + clk_enable(aic->clk); + aic->irqno = IRQ_AIC0; + aic->irqflags = 0; + + rt_hw_interrupt_install(IRQ_AIC0,aic_irq_handler,aic,"irq_aic"); + rt_hw_interrupt_umask(IRQ_AIC0); + + return aic; + +aic_init_error: + clk_put(aic->clk); + clk_put(aic->clk_gate); + return RT_NULL; +} + +#define I2S_DEBUG 0 +#if I2S_DEBUG +#define I2S_DBG(...) rt_kprintf("[I2S]"),rt_kprintf(__VA_ARGS__) +#else +#define I2S_DBG(...) +#endif + +#define I2S_TFIFO_DEPTH 64 +#define I2S_RFIFO_DEPTH 32 + +#define I2S_OSS_FMT 16 +#define I2S_ISS_FMT 16 + +#define I2S_PALY_CHANEL 2 + +struct jz_i2s _g_jz_i2s = +{ + .aic = 0, + .i2s_init = 0, + .i2s_mode = 0, + .tx_dr_base = ((AIC_BASE + AICDR) & 0x1FFFFFFF), + .channels = 2, + .fmt_width = 16, + .tx_dmac = RT_NULL, + .rx_dmac = RT_NULL, +}; + +#define I2S_DMA_TX_CHAN 2 +#define I2S_DMA_RX_CHAN 3 + +static void aic_i2s_trans_complete(struct rt_dma_channel *dmac, struct dma_message *msg); + +static void dump_registers(struct jz_aic *aic) +{ + rt_kprintf("AIC_FR 0x%08x : 0x%08x\n", (aic->base+AICFR), jz_aic_read_reg(aic, AICFR)); + rt_kprintf("AIC_CR 0x%08x : 0x%08x\n", (aic->base+AICCR), jz_aic_read_reg(aic, AICCR)); + rt_kprintf("AIC_I2SCR 0x%08x : 0x%08x\n", (aic->base+I2SCR), jz_aic_read_reg(aic, I2SCR)); + rt_kprintf("AIC_SR 0x%08x : 0x%08x\n", (aic->base+AICSR), jz_aic_read_reg(aic, AICSR)); + rt_kprintf("AIC_I2SSR 0x%08x : 0x%08x\n", (aic->base+I2SSR), jz_aic_read_reg(aic, I2SSR)); + rt_kprintf("AIC_I2SDIV 0x%08x : 0x%08x\n", (aic->base+I2SDIV), jz_aic_read_reg(aic, I2SDIV)); + rt_kprintf("AIC_DR 0x%08x : 0x%08x\n", (aic->base+AICDR), jz_aic_read_reg(aic, AICDR)); + + rt_kprintf("AIC_I2SCDR\t 0x%08x\n",*(volatile unsigned int*)0xb0000060); + rt_kprintf("AIC_I2SCDR1\t 0x%08x\n",*(volatile unsigned int*)0xb0000070); + rt_kprintf("AICSR\t 0x%08x\n",*(volatile unsigned int*)0xb0020014); + return; +} + +int dump_aic_i2s(void) +{ + dump_registers(_g_jz_i2s.aic); + + return 0; +} +MSH_CMD_EXPORT(dump_aic_i2s,dump i2s registers...); + +#if 0 +int i2scdr_extclk(void) +{ + rt_uint32_t regValue; + + regValue = readl(0xb0000060); + regValue &= ~(0x01 << 30); + writel(regValue,0xb0000060); + + rt_kprintf("AIC_I2SCDR\t 0x%08x\n",*(volatile unsigned int*)0xb0000060); +} +MSH_CMD_EXPORT(i2scdr_extclk,set i2s cdr ext clk...); + +int i2scdr_pllclk(void) +{ + rt_uint32_t regValue; + + regValue = readl(0xb0000060); + regValue |= (0x01 << 30); + writel(regValue,0xb0000060); + + rt_kprintf("AIC_I2SCDR\t 0x%08x\n",*(volatile unsigned int*)0xb0000060); +} +MSH_CMD_EXPORT(i2scdr_pllclk,set i2s cdr pll clk...); +#endif + +static void aic_i2s_start_substream(struct jz_i2s *i2s,int stream) +{ + struct jz_aic *aic = i2s->aic; + + if(stream == AUDIO_STREAM_REPLAY) + { + int i = 4; + I2S_DBG("codec fifo level0 %x\n", jz_aic_read_reg(aic, AICSR)); + for (i= 0; i < I2S_TFIFO_DEPTH ; i++) + { + __aic_write_txfifo(aic, 0x0); + __aic_write_txfifo(aic, 0x0); + } + + __aic_clear_tur(aic); + I2S_DBG("codec fifo level1 %x\n", jz_aic_read_reg(aic, AICSR)); + __i2s_enable_replay(aic); + + while (!__aic_test_tur(aic)) ; + __i2s_enable_transmit_dma(aic); + __aic_clear_tur(aic); +#if I2S_DEBUG + __aic_en_tur_int(aic); +#endif + } + else + { + __aic_flush_rxfifo(aic); + rt_thread_delay(1); + __i2s_enable_record(aic); + __i2s_enable_receive_dma(aic); + +#if I2S_DEBUG + __aic_en_ror_int(aic); +#endif + } + + I2S_DBG("strtup sub stream ok!\n"); +} + +static void aic_i2s_stop_substream(struct jz_i2s *i2s,int stream) +{ + struct jz_aic *aic = i2s->aic; + + if(stream == AUDIO_STREAM_REPLAY) + { +#if I2S_DEBUG + __aic_dis_tur_int(aic); +#endif + if (__i2s_transmit_dma_is_enable(aic)) + { + //wait all dma queue is complete + while(i2s->tx_dmac->get_index != i2s->tx_dmac->put_index) + rt_thread_delay(1); + + __i2s_disable_transmit_dma(aic); + __aic_clear_tur(aic); + /*hrtime mode: stop will be happen in any where, make sure there is + * no data transfer on ahb bus before stop dma + */ + while(!__aic_test_tur(aic)); + } + __i2s_disable_replay(aic); + __aic_clear_tur(aic); + } + else + { +// if (jz_i2s_debug) __aic_dis_ror_int(aic); + + if (__i2s_receive_dma_is_enable(aic)) + { + __i2s_disable_receive_dma(aic); + __aic_clear_ror(aic); + while(!__aic_test_ror(aic)); + } + __i2s_disable_record(aic); + __aic_clear_ror(aic); + } +} + +int aic_i2s_set_clkdiv(struct jz_i2s *i2s,int div_id, int div) +{ + struct jz_aic *aic = i2s->aic; + + I2S_DBG("enter %s div_id %d div %d\n", __func__, div_id , div); + + /*BIT CLK fix 64FS*/ + /*SYS_CLK is 256, 384, 512, 768*/ + if (div != 256 && div != 384 && div != 512 && div != 768) + return -RT_EIO; + + __i2s_set_dv(aic, (div/64) - 1); + __i2s_set_idv(aic, (div/64) - 1); + + return RT_EOK; +} + + +/* + * stream = CODEC_STREAM_PLAYBACK or CODEC_STREAM_CAPTURE + */ +int aic_i2s_startup(struct jz_i2s *i2s,int stream) +{ + struct jz_aic *aic = i2s->aic; + + if(!i2s->i2s_mode) + { + I2S_DBG("start set AIC register....\n"); + __aic_disable(aic); + + __aic_select_i2s(aic); + __i2s_select_i2s_fmt(aic); + +#ifndef CODEC_AS_MASTER + __i2s_bclk_output(aic); + __i2s_sync_output(aic); +#else + __i2s_bclk_input(aic); + __i2s_sync_input(aic); +#endif + + aic_i2s_set_sysclk(i2s,CODEC_DEF_RATE); + + __i2s_play_lastsample(aic); + __i2s_set_transmit_trigger(aic, I2S_TFIFO_DEPTH/4); + __i2s_set_receive_trigger(aic, (I2S_RFIFO_DEPTH/4 - 1)); + __aic_enable(aic); + + } + + /* Set playback or record mode */ + if(stream == AUDIO_STREAM_REPLAY) + { + __i2s_send_rfirst(aic); + __i2s_disable_transmit_dma(aic); + __i2s_disable_replay(aic); + __aic_clear_tur(aic); + i2s->i2s_mode |= I2S_WRITE; + } + else + { + __i2s_disable_receive_dma(aic); + __i2s_disable_record(aic); + __aic_clear_ror(aic); + i2s->i2s_mode |= I2S_READ; + } + + return 0; +} + +int aic_i2s_trigger(struct jz_i2s* i2s,int cmd,int stream) +{ + switch (cmd) + { + case I2S_TRIGGER_START: + case I2S_TRIGGER_RESUME: + case I2S_TRIGGER_PAUSE_RELEASE: + aic_i2s_start_substream(i2s,stream); + break; + case I2S_TRIGGER_STOP: + case I2S_TRIGGER_SUSPEND: + case I2S_TRIGGER_PAUSE_PUSH: + default: + aic_i2s_stop_substream(i2s,stream); + break; + } + + return 0; +} + +int aic_i2s_hw_params(struct jz_i2s* i2s,int stream) +{ + struct jz_aic *aic = i2s->aic; + struct dma_config config; + + int trigger; + int bus_width; + + I2S_DBG("upgrade hw params...\n"); + + if(stream == AUDIO_STREAM_REPLAY) + { + /* channel */ + __i2s_channel(aic, i2s->channels); + + /* format */ + if(i2s->fmt_width == 8) + bus_width = RT_DMA_BUSWIDTH_1_BYTE; + else if(i2s->fmt_width == 16) + bus_width = RT_DMA_BUSWIDTH_2_BYTES; + else + bus_width = RT_DMA_BUSWIDTH_4_BYTES; + + i2s->tx_dmac = rt_dma_get_channel(I2S_DMA_TX_CHAN); + RT_ASSERT(i2s->tx_dmac != RT_NULL); + if(i2s->tx_dmac != RT_NULL) + { + config.direction = RT_DMA_MEM_TO_DEV; + config.src_addr_width = bus_width; + config.src_maxburst = (64 * 1024); + config.dst_addr_width = bus_width; + config.dst_maxburst = (I2S_TFIFO_DEPTH * bus_width)/2; + rt_dma_configture(i2s->tx_dmac,&config); + + i2s->tx_dmac->start = RT_NULL; + i2s->tx_dmac->complete = aic_i2s_trans_complete; + } + + __i2s_set_oss(aic, i2s->fmt_width); + __i2s_set_transmit_trigger(aic, (I2S_TFIFO_DEPTH / 4)); + + I2S_DBG("TX_DMAC config ok!\n"); + } + else + { + /* format */ + if(i2s->fmt_width == 8) + bus_width = RT_DMA_BUSWIDTH_1_BYTE; + else if(i2s->fmt_width == 16) + bus_width = RT_DMA_BUSWIDTH_2_BYTES; + else + bus_width = RT_DMA_BUSWIDTH_4_BYTES; + + i2s->rx_dmac = rt_dma_get_channel(I2S_DMA_RX_CHAN); + if(i2s->rx_dmac != RT_NULL) + { + config.direction = RT_DMA_DEV_TO_MEM; + config.src_addr_width = bus_width; + config.src_maxburst = (I2S_RFIFO_DEPTH * bus_width)/2; + config.dst_addr_width = bus_width; + config.dst_maxburst = (64 * 1024); + rt_dma_configture(i2s->rx_dmac,&config); + + i2s->rx_dmac->start = RT_NULL; + i2s->rx_dmac->complete = aic_i2s_trans_complete; + + I2S_DBG("RX DMA config ok \n"); + } + + __i2s_set_iss(aic, i2s->fmt_width); + __i2s_set_receive_trigger(aic, (I2S_RFIFO_DEPTH/4 - 1)); + + } + + return 0; +} + +void aic_i2s_shutdown(struct jz_i2s *i2s,int stream) +{ + struct jz_aic *aic = i2s->aic; + + aic_i2s_stop_substream(i2s,stream); + + if(stream == AUDIO_STREAM_REPLAY) + i2s->i2s_mode &= ~I2S_WRITE; + else + i2s->i2s_mode &= ~I2S_READ; + + if(!i2s->i2s_mode) + __aic_disable(aic); +} + +int aic_i2s_set_sysclk(struct jz_i2s *i2s,uint32_t freq) +{ + struct jz_aic *aic = i2s->aic; + + +#ifdef RT_USING_ICODEC + __aic_select_internal_codec(aic); +#else + __aic_select_external_codec(aic); +#endif + + __i2s_stop_bitclk(aic); + + aic_set_rate(aic, freq); + + __i2s_start_bitclk(aic); + +#ifdef CFG_AIC_SOC_CLKOUT + /* Master clk output */ + __i2s_select_sysclk_output(aic); + + __i2s_enable_sysclk_output(aic); +#else + /* Master clk input */ + __i2s_select_sysclk_input(aic); + __i2s_disable_sysclk_output(aic); +#endif + + return 0; +} + + +static void aic_i2s_trans_complete(struct rt_dma_channel *dmac, struct dma_message *msg) +{ + I2S_DBG("TAG,%d,%s\n",__LINE__,__func__); + if(msg->complete_cb) + { + if(msg->t_mode == JZDMA_REQ_I2S0_TX) + msg->complete_cb(msg->complete_arg,msg->src_addr); + else + msg->complete_cb(msg->complete_arg,msg->dst_addr); + } +} + +rt_size_t aic_i2s_send(struct jz_i2s *i2s, const void* buffer, rt_size_t size,void (*tx_callback)(void *,void *), void *tx_arg) +{ + struct dma_message message; + + I2S_DBG("TAG,%d,%s\n",__LINE__,__func__); + + message.src_addr = (uint8_t *) (buffer); + message.src_option = RT_DMA_ADDR_INC; + + message.dst_addr = (uint8_t *) (AIC_BASE + AICDR); + message.dst_option = RT_DMA_ADDR_FIX; + + message.t_size = size; + message.t_mode = JZDMA_REQ_I2S0_TX; + + message.complete_cb = (void *)tx_callback; + message.complete_arg= tx_arg; + + I2S_DBG("i2s trans length = %d\n",size); + + if (rt_dma_trans_message(i2s->tx_dmac, &message) == RT_EOK) + return size; + + return 0; +} + +rt_size_t aic_i2s_recv(struct jz_i2s *i2s, void* buffer, rt_size_t size,void (*rx_callback)(void *,void *), void *rx_arg) +{ + struct dma_message message; + + message.src_addr = (uint8_t *) (AIC_BASE + AICDR); + message.src_option = RT_DMA_ADDR_FIX; + + message.dst_addr = (uint8_t *) (buffer); + message.dst_option = RT_DMA_ADDR_INC; + + message.t_size = size; + message.t_mode = JZDMA_REQ_I2S0_RX; + + message.complete_cb = (void *)rx_callback; + message.complete_arg= rx_arg; + + if(rt_dma_trans_message(i2s->rx_dmac,&message) == RT_EOK) + return size; + + return 0; +} + + + +struct jz_i2s *rt_hw_aic_i2s_init(void) +{ + struct jz_aic *aic; + struct jz_i2s *i2s = &_g_jz_i2s; + +#ifndef RT_USING_ICODEC +#ifdef CFG_AIC_SOC_CLKOUT + gpio_set_func(GPIO_PORT_B, GPIO_Pin_0, GPIO_FUNC_1); // I2S_MCLK +#endif + gpio_set_func(GPIO_PORT_B, GPIO_Pin_1, GPIO_FUNC_1); // I2S_BCLK + gpio_set_func(GPIO_PORT_B, GPIO_Pin_2, GPIO_FUNC_1); // I2S_LRCLK + gpio_set_func(GPIO_PORT_B, GPIO_Pin_3, GPIO_FUNC_1); // I2S_DI + gpio_set_func(GPIO_PORT_B, GPIO_Pin_4, GPIO_FUNC_1); // I2S_DO +#endif + + I2S_DBG("TAG,%d,%s\n",__LINE__,__func__); + aic = _aic_init(); + if(aic == RT_NULL) + return RT_NULL; + i2s->aic = aic; + + i2s->i2s_mode = 0; + + I2S_DBG("TAG,%d,%s\n",__LINE__,__func__); + + /* now ,we just support I2S playback */ + aic_i2s_startup(i2s,AUDIO_STREAM_REPLAY); + + aic_i2s_hw_params(i2s,AUDIO_STREAM_REPLAY); + + return i2s; +} + diff --git a/bsp/x1000/drivers/audio/drv_aic_i2s.h b/bsp/x1000/drivers/audio/drv_aic_i2s.h new file mode 100644 index 0000000000000000000000000000000000000000..0ec120a6cf13b4e71c1aedbaec65b352f4c50e5e --- /dev/null +++ b/bsp/x1000/drivers/audio/drv_aic_i2s.h @@ -0,0 +1,94 @@ +/* + * drv_aic_i2s.h + * + * Created on: 2016年4月1日 + * Author: Urey + */ + +#ifndef DRIVER_DRV_AIC_I2S_H_ +#define DRIVER_DRV_AIC_I2S_H_ + +#include "board.h" + + +#ifdef RT_USING_ICODEC +# define CODEC_AS_MASTER + +#define CODEC_DEF_RATE (24000000) +#else +//# undef CODEC_AS_MASTER +//# define CODEC_AS_MASTER + +#define CODEC_DEF_RATE (44100) +#endif + +#ifdef RT_USING_ECODEC_WM8978 +# define CFG_AIC_I2S_EXT_CODEC +#endif + +#define CFG_AIC_SOC_CLKOUT +//#define CFG_AIC_SOC_CLKIN + +#define CFG_I2S_DMA_PAGE_SIZE (32 * 1024) +#define CFG_I2S_DMA_PAGE_NUM 8 + +enum +{ + I2S_TRIGGER_STOP = 0, + I2S_TRIGGER_START , + I2S_TRIGGER_PAUSE_PUSH , + I2S_TRIGGER_PAUSE_RELEASE , + I2S_TRIGGER_SUSPEND , + I2S_TRIGGER_RESUME, +}; + + + +/********************************************************************************************************* +** 数据结构 +*********************************************************************************************************/ +struct jz_i2s +{ + struct jz_aic *aic; + int i2s_init; +#define I2S_WRITE 0x1 +#define I2S_READ 0x2 +#define I2S_INCODEC (0x1 <<4) +#define I2S_EXCODEC (0x2 <<4) +#define I2S_SLAVE (0x1 << 8) +#define I2S_MASTER (0x2 << 8) + int i2s_mode; + uint32_t tx_dr_base; + + int channels; + int fmt_width; + int rates; + + /* used for DMA transform */ + struct rt_dma_channel *tx_dmac; + struct rt_dma_channel *rx_dmac; +}; + +/********************************************************************************************************* +** 函数申明 +*********************************************************************************************************/ +int aic_set_rate(struct jz_aic *aic, uint32_t freq); + +struct jz_i2s *rt_hw_aic_i2s_init(void); + +//void aic_i2s_start_substream(struct jz_i2s *i2s,int stream); +//void aic_i2s_stop_substream(struct jz_i2s *i2s,int stream); +int aic_i2s_set_sysclk(struct jz_i2s *i2s,uint32_t freq); +int aic_i2s_set_clkdiv(struct jz_i2s *i2s,int div_id, int div); +int aic_i2s_startup(struct jz_i2s *i2s,int stream); +int aic_i2s_trigger(struct jz_i2s* i2s,int cmd,int stream); + +int aic_i2s_hw_params(struct jz_i2s* i2s,int stream); +void aic_i2s_shutdown(struct jz_i2s *i2s,int stream); + +rt_size_t aic_i2s_send(struct jz_i2s *i2s, const void* buffer, rt_size_t size,void (*tx_callback)(void *,void *), void *tx_arg); +rt_size_t aic_i2s_recv(struct jz_i2s *i2s, void* buffer, rt_size_t size,void (*rx_callback)(void *,void *), void *rx_arg); + + +void aic_i2s_set_rate(struct jz_i2s *i2s,int rate); +#endif /* DRIVER_DRV_AIC_I2S_H_ */ diff --git a/bsp/x1000/drivers/audio/drv_codec_icodec.c b/bsp/x1000/drivers/audio/drv_codec_icodec.c new file mode 100644 index 0000000000000000000000000000000000000000..b67dd4937f8356a15b1af19ddfa1b33d54f99963 --- /dev/null +++ b/bsp/x1000/drivers/audio/drv_codec_icodec.c @@ -0,0 +1,826 @@ +#include +#include +#include + +#include + +#ifdef RT_USING_FINSH +#include +#endif + +#include "board.h" +#include "dma.h" + +#ifdef RT_USING_ICODEC + +#include "drv_gpio.h" +#include "drv_clock.h" +#include "drv_aic.h" +#include "drv_aic_i2s.h" +#include "drv_codec_icodec.h" + +#define CODEC_DEBUG 0 +#if CODEC_DEBUG +#define CODEC_DBG(...) rt_kprintf("[CODEC]"),rt_kprintf(__VA_ARGS__) +#else +#define CODEC_DBG(...) +#endif + +/* + * Sampling rate + */ +const int sample_attr[] = +{ + 8000, 11025, 12000, 16000, + 22050, 24000, 32000, 44100, + 48000, 88200, 96000, 176400, + 192000, +}; + +static uint8_t _g_icodec_reg_defcache[SCODA_MAX_REG_NUM] = +{ +#if 1 + /* reg 0x0 ... 0x9 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03, + /* reg 0xa ... 0x13 */ + 0x00,0x40,0x30,0x80,0x01,0x00,0x00,0x00,0x0f,0x40, + /* reg 0x14 ... 0x1d */ + 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xff, + /* reg 0x1e ... 0x27 */ + 0x00,0x06,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* reg 0x28 ... 0x31 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* reg 0x32 ... 0x39 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* extern reg */ + 0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x34,0x07,0x44,0x1f,0x00, +#else + /* reg 0x0 ... 0x9 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03, + /* reg 0xa ... 0x13 */ + 0x00,0x00,0x30,0xb0,0x01,0x00,0x00,0x00,0x0F,0x40, + /* reg 0x14 ... 0x1d */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xff, + /* reg 0x1e ... 0x27 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* reg 0x28 ... 0x31 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* reg 0x32 ... 0x39 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* extern reg */ + 0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x34,0x07,0x44,0x1f,0x00, +#endif +}; + +static int jz_icodec_reg_volatile(uint32_t reg) +{ + if (reg > SCODA_MAX_REG_NUM) + return 1; + + switch (reg) + { + case SCODA_REG_SR: + case SCODA_REG_SR2: + case SCODA_REG_SIGR: + case SCODA_REG_SIGR3: + case SCODA_REG_SIGR5: + case SCODA_REG_SIGR7: + case SCODA_REG_MR: + case SCODA_REG_IFR: + case SCODA_REG_IFR2: + case SCODA_REG_SR_ADC_AGCDGL: + case SCODA_REG_SR_ADC_AGCDGR: + case SCODA_REG_SR_ADC_AGCAGL: + case SCODA_REG_SR_ADC_AGCAGR: + case SCODA_REG_SR_TR1: + case SCODA_REG_SR_TR2: + case SCODA_REG_SR_TR_SRCDAC: + return 1; + default: + return 0; + } +} + +static int jz_icodec_reg_writable(uint32_t reg) +{ + if (reg > SCODA_MAX_REG_NUM) + return 0; + + switch (reg) { + case SCODA_REG_SR: + case SCODA_REG_SR2: + case SCODA_REG_SIGR: + case SCODA_REG_SIGR3: + case SCODA_REG_SIGR5: + case SCODA_REG_SIGR7: + case SCODA_REG_MR: + case SCODA_REG_SR_ADC_AGCDGL: + case SCODA_REG_SR_ADC_AGCDGR: + case SCODA_REG_SR_ADC_AGCAGL: + case SCODA_REG_SR_ADC_AGCAGR: + case SCODA_REG_SR_TR1: + case SCODA_REG_SR_TR2: + case SCODA_REG_SR_TR_SRCDAC: + return 0; + default: + return 1; + } +} + +static int jz_icodec_reg_readable(uint32_t reg) +{ + if (reg > SCODA_MAX_REG_NUM) + return 0; + else + return 1; +} + +static uint8_t jz_icodec_reg_read(struct jz_icodec *icodec, uint32_t reg) +{ + int ret = 0; + uint8_t val = 0; + + if (!jz_icodec_reg_volatile(reg)) + { + val = icodec_hw_read(icodec, reg); + if ((reg == SCODA_REG_GCR_DACL) || (reg == SCODA_REG_GCR_DACR)) { + if (val < 32) + val = 31 - val; + else + val = 95 - val; + } + return val; + } + + if (jz_icodec_reg_readable(reg)) + return icodec_hw_read(icodec, reg); + + return 0; +} + +static int jz_icodec_reg_write(struct jz_icodec *codec, uint16_t reg, int value) +{ + int ret = 0; + int val = value; + + if (jz_icodec_reg_writable(reg)) + { + if (!jz_icodec_reg_volatile(reg)) + { + if((reg == SCODA_REG_GCR_DACL)||(reg == SCODA_REG_GCR_DACR)) + { + if(val < 32) + val = 31 - val; + else + val = 95 - val; + } + _g_icodec_reg_defcache[reg] = val; + } + + return icodec_hw_write(codec, reg, val); + } + + return 0; +} + + +static int jz_icodec_reg_update_bits(struct jz_icodec *icodec, uint16_t reg, uint32_t mask, uint16_t value) +{ + uint8_t change; + uint8_t old, new; + + int ret; + + ret = jz_icodec_reg_read(icodec, reg); + if (ret < 0) + return ret; + + old = ret; + new = (old & ~mask) | (value & mask); + change = old != new; + if (change) + ret = jz_icodec_reg_write(icodec, reg, new); + + if (ret < 0) + return ret; + + return change; +} + +static int jz_icodec_set_sampling_rate(struct jz_icodec *icodec, int rate) +{ + /* sampling rate */ + int speed_sel = 0; + if(rate == icodec->replay_config.samplerate) + return rate; + + /* set sampling rate */ + for (speed_sel = 0; rate > sample_attr[speed_sel]; speed_sel++) ; + + jz_icodec_reg_update_bits(icodec, SCODA_REG_FCR_DAC, SCODA_FCR_FREQ_MASK, (speed_sel << SCODA_FCR_FREQ_SHIFT)); + jz_icodec_reg_update_bits(icodec, SCODA_REG_FCR_ADC, SCODA_FCR_FREQ_MASK, (speed_sel << SCODA_FCR_FREQ_SHIFT)); + + rate = sample_attr[speed_sel]; + icodec->replay_config.samplerate = rate; + return rate; +} + +static void jz_icodec_hw_params(struct jz_icodec* icodec,int stream) +{ + int playback = (stream == AUDIO_STREAM_REPLAY); + int speed_sel = 0; + int bit_width_sel = 3; + int aicr_reg = playback ? SCODA_REG_AICR_DAC : SCODA_REG_AICR_ADC; + int fcr_reg = playback ? SCODA_REG_FCR_DAC : SCODA_REG_FCR_ADC; + + /* bit width */ + switch (icodec->replay_config.samplefmt) + { + case AUDIO_FMT_PCM_S16_LE: + bit_width_sel = 0; + break; + case AUDIO_FMT_PCM_S24_LE: + bit_width_sel = 3; + break; + } + + /*sample rate*/ + for (speed_sel = 0; icodec->replay_config.samplerate > sample_attr[speed_sel]; speed_sel++); + + jz_icodec_reg_update_bits(icodec, aicr_reg, SCODA_AICR_DAC_ADWL_MASK,(bit_width_sel << SCODA_AICR_DAC_ADWL_SHIFT)); + jz_icodec_reg_update_bits(icodec, fcr_reg, SCODA_FCR_FREQ_MASK,(speed_sel << SCODA_FCR_FREQ_SHIFT)); +} + + +static int jz_icodec_digital_mute(struct jz_icodec *icodec, int mute) +{ + jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_DAC, SCODA_CR_DAC_SMUTE_MASK, (!!mute) << SCODA_CR_DAC_SMUTE_SHIFT); + jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_ADC, SCODA_CR_ADC_SMUTE_MASK, (!!mute) << SCODA_CR_ADC_SMUTE_SHIFT); + + return 0; +} + +static void jz_icodec_startup(struct jz_icodec *icodec) +{ + /*power on codec*/ + if (jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_MASK, 0)) + rt_thread_delay(rt_tick_from_millisecond(250)); + if (jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_SLEEP_MASK, 0)) + rt_thread_delay(rt_tick_from_millisecond(400)); +} + +static void jz_icodec_shutdown(struct jz_icodec *icodec) +{ + /*power off codec*/ + jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_SLEEP_MASK, 1); + jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_MASK, 1); +} + +static void jz_icodec_mute_stream(struct jz_icodec *icodec, int mute, int stream) +{ + + if(stream == AUDIO_STREAM_REPLAY) + { + jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_DAC, SCODA_CR_DAC_SMUTE_MASK, (!!mute) << SCODA_CR_DAC_SMUTE_SHIFT); + } + else if(stream == AUDIO_STREAM_RECORD) + { + jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_ADC, SCODA_CR_ADC_SMUTE_MASK, (!!mute) << SCODA_CR_ADC_SMUTE_SHIFT); + } +} + +#define VOLUME_MIN 0 +#define VOLUME_MAX 100 + +#define REPLAY_REG_MAX (63) +static int jz_icodec_set_replay_volume(struct jz_icodec *icodec,int val) +{ + int phyValue = 0; + /* get current volume */ + if (val < VOLUME_MIN) + val = VOLUME_MIN; + else if(val >= VOLUME_MAX) + val = VOLUME_MAX; + + phyValue = (val* REPLAY_REG_MAX) / VOLUME_MAX; + + CODEC_DBG("volume = %d\n",val); + jz_icodec_reg_write(icodec,SCODA_REG_GCR_DACL,phyValue); + jz_icodec_reg_write(icodec,SCODA_REG_GCR_DACR,phyValue); + + icodec->user_replay_volume = jz_icodec_reg_read(icodec,SCODA_REG_GCR_DACL); + + if (val == 0) + { + jz_icodec_digital_mute(icodec,1); + } + else + { + jz_icodec_digital_mute(icodec,0); + } + + return val; +} + +#define REPLAY_MIXER_REG_MAX 31 +int jz_icodec_set_replay_mixer_volume(struct jz_icodec *icodec,int val) +{ + int phyValue = 0; + /* get current volume */ + if (val < VOLUME_MIN) + val = VOLUME_MIN; + else if(val >= VOLUME_MAX) + val = VOLUME_MAX; + + phyValue = (val * REPLAY_MIXER_REG_MAX) / VOLUME_MAX; + + jz_icodec_reg_write(icodec,SCODA_REG_GCR_MIXDACL,phyValue); + jz_icodec_reg_write(icodec,SCODA_REG_GCR_MIXDACR,phyValue); + + return val; +} + +#define DIGITAL_CAP_REG_MAX 43 +int jz_icodec_set_digital_capture_volume(struct jz_icodec *icodec,int val) +{ + int phyValue = 0; + /* get current volume */ + if (val < VOLUME_MIN) + val = VOLUME_MIN; + else if(val >= VOLUME_MAX) + val = VOLUME_MAX; + + phyValue = (val * DIGITAL_CAP_REG_MAX) / VOLUME_MAX; + + jz_icodec_reg_write(icodec,SCODA_REG_GCR_ADCL,phyValue); + jz_icodec_reg_write(icodec,SCODA_REG_GCR_ADCR,phyValue); + + return val; +} + +#define DIGITAL_CAP_MIX_REG_MAX 31 +int jz_icodec_set_digital_capture_mixer_volume(struct jz_icodec *icodec,int val) +{ + int phyValue = 0; + /* get current volume */ + if (val < VOLUME_MIN) + val = VOLUME_MIN; + else if(val >= VOLUME_MAX) + val = VOLUME_MAX; + + phyValue = (val * DIGITAL_CAP_MIX_REG_MAX) / VOLUME_MAX; + + jz_icodec_reg_write(icodec,SCODA_REG_GCR_MIXADCL,phyValue); + jz_icodec_reg_write(icodec,SCODA_REG_GCR_MIXADCR,phyValue); + + return val; +} + +#define MIC_REG_MAX 4 +int aic_icodec_set_mic_volume(struct jz_icodec *icodec,int val) +{ + int phyValue = 0; + /* get current volume */ + if (val < VOLUME_MIN) + val = VOLUME_MIN; + else if(val >= VOLUME_MAX) + val = VOLUME_MAX; + + phyValue = MIC_REG_MAX - (val) * MIC_REG_MAX / VOLUME_MAX; + + jz_icodec_reg_write(icodec,SCODA_REG_GCR_MIC1,phyValue); + + return val; +} + + +enum +{ + AMIC_ON = 0, + DMIC_ON = 1, +}; +void jz_icodec_adc_mic_select(struct jz_icodec *icodec, int dmic) +{ + if(dmic == DMIC_ON) + { + jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_ADC, SCODA_CR_ADC_MIC_SEL_MASK, (1 << SCODA_CR_ADC_MIC_SEL_SHIFT)); + } + else + { + jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_ADC, SCODA_CR_ADC_MIC_SEL_MASK, (0 << SCODA_CR_ADC_MIC_SEL_SHIFT)); + } +} + +void jz_icodec_adc_capture_enable(struct jz_icodec *icodec,int enable) +{ + if(enable) + { + jz_icodec_reg_update_bits(icodec, SCODA_REG_AICR_ADC, SCODA_AICR_ADC_SB_MASK, (0 << SCODA_AICR_ADC_SB_SHIFT)); + } + else + { + jz_icodec_reg_update_bits(icodec, SCODA_REG_AICR_ADC, SCODA_AICR_ADC_SB_MASK, (1 << SCODA_AICR_ADC_SB_SHIFT)); + } +} + + + + +/********************************************************************************************************* +** Audio device +*********************************************************************************************************/ + +static rt_err_t icodec_getcaps (struct rt_audio_device *audio,struct rt_audio_caps *caps) +{ + rt_err_t result = RT_EOK; + struct jz_icodec *icodec = (struct jz_icodec *)audio->parent.user_data; + CODEC_DBG("type = %d\n",caps->main_type); + + switch (caps->main_type) + { + case AUDIO_TYPE_QUERY: /* qurey the types of hw_codec device */ + { + switch (caps->sub_type) + { + case AUDIO_TYPE_QUERY: + caps->udata.mask = AUDIO_TYPE_OUTPUT | AUDIO_TYPE_MIXER; + break; + default: + result = -RT_ERROR; + break; + } + + break; + } + case AUDIO_TYPE_OUTPUT: /* Provide capabilities of OUTPUT unit */ + switch (caps->sub_type) + { + case AUDIO_DSP_PARAM: + if (audio->replay == NULL) + { + result = -RT_ERROR; + break; + } + caps->udata.config.channels = icodec->replay_config.channels; + caps->udata.config.samplefmt = icodec->replay_config.samplefmt; + caps->udata.config.samplerate = icodec->replay_config.samplerate; + caps->udata.config.samplefmts = icodec->replay_config.samplefmts; + break; + default: + result = -RT_ERROR; + break; + } + break; + case AUDIO_TYPE_MIXER: /* report the Mixer Units */ + switch (caps->sub_type) + { + case AUDIO_MIXER_QUERY: + caps->udata.mask = AUDIO_MIXER_VOLUME | AUDIO_MIXER_DIGITAL | AUDIO_MIXER_LINE; + break; + case AUDIO_MIXER_VOLUME: + caps->udata.value = icodec->user_replay_volume; + break; + case AUDIO_MIXER_DIGITAL: + + break; + case AUDIO_MIXER_LINE: + + break; + default: + result = -RT_ERROR; + break; + } + break; + default: + result = -RT_ERROR; + break; + } + + return result; +} + +static rt_err_t icodec_configure (struct rt_audio_device *audio,struct rt_audio_caps *caps) +{ + rt_err_t result = RT_EOK; + struct jz_icodec *icodec = (struct jz_icodec *) audio->parent.user_data; + CODEC_DBG("type = %d\n",caps->main_type); + + switch (caps->main_type) + { + case AUDIO_TYPE_MIXER: + switch (caps->sub_type) + { + case AUDIO_MIXER_VOLUME: + { + int volume = caps->udata.value; + + jz_icodec_set_replay_volume(icodec, volume); + } + break; + case AUDIO_MIXER_DIGITAL: + { + int gain = caps->udata.value; + jz_icodec_set_replay_mixer_volume(icodec, gain); + } + break; + case AUDIO_MIXER_LINE: + { + int gain = caps->udata.value; + + //set linein valume... + } + break; + case AUDIO_MIXER_EXTEND: + + break; + default: + result = -RT_ERROR; + break; + } + break; + case AUDIO_TYPE_OUTPUT: + { + switch (caps->sub_type) + { + case AUDIO_DSP_PARAM: + { + CODEC_DBG(" AUDIO_TYPE_OUTPUT:\n");CODEC_DBG(" Number of channels: %u\n", caps->udata.config.channels);CODEC_DBG(" Sample rate: %u\n", caps->udata.config.samplerate);CODEC_DBG(" Sample format: %u\n", caps->udata.config.samplefmt); + + //upgrate codec chip + icodec->i2s->channels = caps->udata.config.channels; + icodec->i2s->rates = caps->udata.config.samplerate; + icodec->i2s->fmt_width = rt_audio_format_to_bits(caps->udata.config.samplefmt); + + aic_i2s_hw_params(icodec->i2s, AUDIO_STREAM_REPLAY); + aic_i2s_set_sysclk(icodec->i2s, icodec->i2s->rates); + + //save config + icodec->replay_config.channels = caps->udata.config.channels; + icodec->replay_config.samplefmt = caps->udata.config.samplefmt; + icodec->replay_config.samplerate = caps->udata.config.samplerate; + icodec->replay_config.samplefmts = caps->udata.config.samplefmts; + break; + } + case AUDIO_DSP_SAMPLERATE: + { + int rate = caps->udata.value; + + jz_icodec_set_sampling_rate(icodec, rate); + break; + } + + default: + result = -RT_ERROR; + break; + } + } + break; + default: + result = -RT_ERROR; + break; + } + + return result; +} + +static rt_err_t icodec_init (struct rt_audio_device *audio) +{ + struct jz_icodec *icodec = (struct jz_icodec *)audio->parent.user_data; + uint16_t i; + + /* disable shutdown */ + gpio_set_value(AUDIO_SHUTDOWN_PORT,AUDIO_SHUTDOWN_PIN,AUDIO_SHUTDOWN_MUTE); + rt_thread_delay(RT_TICK_PER_SECOND / 4); + gpio_set_value(AUDIO_SHUTDOWN_PORT,AUDIO_SHUTDOWN_PIN,!AUDIO_SHUTDOWN_MUTE); + rt_thread_delay(RT_TICK_PER_SECOND / 4); + + /* write default value ... */ + for (i = 0; i < sizeof(_g_icodec_reg_defcache); ++i) + { + jz_icodec_reg_write(icodec, i, _g_icodec_reg_defcache[i]); + } + + /* power off codec */ + jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_SLEEP_MASK, 1); + jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_MASK, 1); + + /* codec select enable 24M clock*/ + jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_CK , SCODA_CR_CK_MCLK_DIV_MASK, 1 << SCODA_CR_CK_MCLK_DIV_SHIFT); + jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_CK , SCODA_CR_CK_SDCLK_MASK, 0 << SCODA_CR_CK_SDCLK_SHIFT); + jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_CK , SCODA_CR_CRYSTAL_MASK, 0 << SCODA_CR_CRYSTAL_SHIFT); + + /*codec select Dac/Adc i2s interface*/ + jz_icodec_reg_update_bits(icodec, SCODA_REG_AICR_DAC, SCODA_AICR_DAC_SLAVE_MASK, 0); + jz_icodec_reg_update_bits(icodec, SCODA_REG_AICR_DAC, SCODA_AICR_DAC_AUDIO_MASK, SCODA_AICR_DAC_AUDIOIF_I2S); + + jz_icodec_reg_update_bits(icodec, SCODA_REG_AICR_ADC, SCODA_AICR_ADC_AUDIO_MASK, 0); + jz_icodec_reg_update_bits(icodec, SCODA_REG_AICR_ADC, SCODA_AICR_ADC_AUDIO_MASK, SCODA_AICR_ADC_AUDIOIF_I2S); + + /*codec generated IRQ is a high level */ + jz_icodec_reg_update_bits(icodec, SCODA_REG_ICR, SCODA_ICR_INT_FORM_MASK, SCODA_ICR_INT_FORM_LOW); + + /*codec irq mask*/ + jz_icodec_reg_write(icodec, SCODA_REG_IMR, SCODA_IMR_COMMON_MASK); + jz_icodec_reg_write(icodec, SCODA_REG_IMR2, SCODA_IMR2_COMMON_MASK); + + /*codec clear all irq*/ + jz_icodec_reg_write(icodec, SCODA_REG_IFR, SCODA_IMR_COMMON_MASK); + jz_icodec_reg_write(icodec, SCODA_REG_IFR2, SCODA_IMR2_COMMON_MASK); + + /* PCM Format */ +#if (ICODEC_PCM_FORMAT == AUDIO_FMT_PCM_S16_LE) + jz_icodec_reg_update_bits(icodec, SCODA_REG_AICR_DAC, SCODA_AICR_DAC_ADWL_MASK, (0 << SCODA_AICR_DAC_ADWL_SHIFT)); + jz_icodec_reg_update_bits(icodec, SCODA_REG_AICR_ADC, SCODA_AICR_ADC_ADWL_MASK, (0 << SCODA_AICR_ADC_ADWL_SHIFT)); +#endif + + /* sampling rate */ + jz_icodec_set_sampling_rate(icodec,ICODEC_SAMPLING_RATE); + + /*power on codec*/ + jz_icodec_digital_mute(icodec,0); + + if (jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_MASK, 0)) + rt_thread_delay(rt_tick_from_millisecond(250)); + if (jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_SLEEP_MASK, 0)) + rt_thread_delay(rt_tick_from_millisecond(400)); + + return RT_EOK; +} + +static rt_err_t icodec_shutdown (struct rt_audio_device *audio) +{ + struct jz_icodec *icodec = (struct jz_icodec *)audio->parent.user_data; + +#ifdef AUDIO_SHUTDOWN_PORT + gpio_set_value(AUDIO_SHUTDOWN_PORT,AUDIO_SHUTDOWN_PIN,AUDIO_SHUTDOWN_MUTE); +#endif + return RT_EOK; +} + +rt_err_t icodec_start (struct rt_audio_device *audio,int stream) +{ + struct jz_icodec *icodec = (struct jz_icodec *)audio->parent.user_data; + + aic_i2s_trigger(icodec->i2s,I2S_TRIGGER_START,stream); + + return RT_EOK; +} + +rt_err_t icodec_stop (struct rt_audio_device *audio,int stream) +{ + struct jz_icodec *icodec = (struct jz_icodec *)audio->parent.user_data; + + aic_i2s_trigger(icodec->i2s,I2S_TRIGGER_STOP,stream); + return RT_EOK; +} + +static rt_err_t icodec_suspend (struct rt_audio_device *audio,int stream) +{ + struct jz_icodec *icodec = (struct jz_icodec *)audio->parent.user_data; + + aic_i2s_trigger(icodec->i2s,I2S_TRIGGER_SUSPEND,stream); + return RT_EOK; +} + +static rt_err_t icodec_resume (struct rt_audio_device *audio,int stream) +{ + struct jz_icodec *icodec = (struct jz_icodec *)audio->parent.user_data; + + aic_i2s_trigger(icodec->i2s,I2S_TRIGGER_RESUME,stream); + return RT_EOK; +} + +static rt_err_t icodec_control (struct rt_audio_device *audio, int cmd, void *args) +{ + rt_err_t result = RT_EOK; + struct jz_icodec *icodec = (struct jz_icodec *)audio->parent.user_data; + + switch (cmd) + { + case AUDIO_CTL_HWRESET: + + break; + case AUDIO_CTL_GETBUFFERINFO: + { + struct rt_audio_buf_info *info = (struct rt_audio_buf_info *)args; + + if(info != RT_NULL) + { + info->buffer_count = CFG_I2S_DMA_PAGE_NUM; + info->buffer_size = CFG_I2S_DMA_PAGE_SIZE; + } + } + break; + default: + result = -RT_ERROR; + break; + } + + return result; +} + +static void codec_write_complete(void *data, void *pbuf) +{ + struct rt_audio_device *audio = (struct rt_audio_device *)data; + + /* notify transmitted complete. */ + rt_audio_tx_complete(audio,pbuf); +} + +static rt_size_t icodec_transmit (struct rt_audio_device *audio,const void *writeBuf,void *readBuf, rt_size_t size) +{ + struct jz_icodec *icodec = (struct jz_icodec *)audio->parent.user_data; + + CODEC_DBG("writeBuf = %x,readBuf=%x,size=%d\n",(rt_uint32_t)writeBuf,(rt_uint32_t)readBuf,size); + + if(writeBuf != RT_NULL) + { + return aic_i2s_send(icodec->i2s, writeBuf, size, codec_write_complete, (void *)audio); + } + return 0; +} + + +static struct jz_icodec _g_jz_icodec = +{ + .mapped_base = AIC_BASE + 0xA0, + .user_replay_volume = 31, +}; + +static struct rt_audio_device _g_audio_device; +const struct rt_audio_ops _g_audio_ops = +{ + .getcaps = icodec_getcaps, + .configure = icodec_configure, + + .init = icodec_init, + .shutdown = icodec_shutdown, + .start = icodec_start, + .stop = icodec_stop, + .suspend = icodec_suspend , + .resume = icodec_resume , + .control = icodec_control, + + .transmit = icodec_transmit, +}; + + +int rt_hw_codec_init(void) +{ + int result; + + struct rt_audio_device *audio = &_g_audio_device; + struct jz_icodec *icodec = &_g_jz_icodec; + struct jz_i2s *i2s; + + rt_kprintf("init i2s....\n"); + i2s = rt_hw_aic_i2s_init(); + if(i2s == RT_NULL) + { + CODEC_DBG("i2s device not found!\r\n"); + return -RT_EIO; + } + icodec->i2s = i2s; + +#ifdef AUDIO_DEVICE_USE_PRIVATE_BUFFER + { + rt_uint8_t *mempool = (rt_uint8_t *)rt_malloc(CODEC_MP_SZ); + + if(mempool == RT_NULL) + { + CODEC_DBG("no memory...\n"); + + return -RT_ENOMEM; + } + rt_mp_init(&icodec->mp,"codecbuf",mempool,CODEC_MP_SZ,CODEC_MP_BLOCK_SZ); + } +#endif /* AUDIO_DEVICE_USE_PRIVATE_BUFFER */ + + //init default configuration + { + icodec->replay_config.channels = 2; + icodec->replay_config.samplefmt = AUDIO_FMT_PCM_S16_LE; + icodec->replay_config.samplerate = 44100; + icodec->replay_config.samplefmts = AUDIO_FMT_PCM_S16_LE; + } + + audio->ops = (struct rt_audio_ops *)&_g_audio_ops; + result = rt_audio_register(audio,"sound0",RT_DEVICE_FLAG_WRONLY,icodec); + if(result != RT_EOK) + { + CODEC_DBG("icodec device register error..\n"); + + return result; + } + + rt_kprintf("codec initialization done!\n"); + return RT_EOK; +} +INIT_DEVICE_EXPORT(rt_hw_codec_init); +#endif /* RT_USING_ICODEC */ diff --git a/bsp/x1000/drivers/audio/drv_codec_icodec.h b/bsp/x1000/drivers/audio/drv_codec_icodec.h new file mode 100644 index 0000000000000000000000000000000000000000..e6ac703393930ccf1a66b9fd1b1ff9fef985ef2a --- /dev/null +++ b/bsp/x1000/drivers/audio/drv_codec_icodec.h @@ -0,0 +1,406 @@ +/* + * drv_codec_icodec.h + * + * Created on: 2017年1月10日 + * Author: Urey + */ + +#ifndef _DRV_CODEC_ICODEC_H_ +#define _DRV_CODEC_ICODEC_H_ + +#include + +#include "x1000.h" +#include "drv_clock.h" + + +struct jz_icodec +{ + struct jz_i2s *i2s; + struct rt_audio_configure replay_config; +#ifdef AUDIO_DEVICE_USE_PRIVATE_BUFFER + struct rt_mempool mp; +#endif /* AUDIO_DEVICE_USE_PRIVATE_BUFFER */ + uint32_t mapped_base; + + /* replay */ + int user_replay_volume; + int dac_user_mute; /*dac user mute state*/ + int aohp_in_pwsq; /*aohp in power up/down seq*/ + int hpl_wished_gain; /*keep original hpl/r gain register value*/ + int hpr_wished_gain; + int linl_wished_gain; /*keep original hpl/r gain register value*/ + int linr_wished_gain; + +}; + +#define ICODEC_PCM_FORMAT AUDIO_FMT_PCM_S16_LE +#define ICODEC_SAMPLING_RATE 44100 + + +/* icodec internal register space */ +enum { + SCODA_REG_SR = 0x0, + SCODA_REG_SR2, + SCODA_REG_SIGR, + SCODA_REG_SIGR2, + SCODA_REG_SIGR3, + SCODA_REG_SIGR5, + SCODA_REG_SIGR7, + SCODA_REG_MR, + SCODA_REG_AICR_DAC, + SCODA_REG_AICR_ADC, + SCODA_REG_CR_DMIC, + SCODA_REG_CR_MIC1, + SCODA_REG_CR_MIC2, + SCODA_REG_CR_DAC, + SCODA_REG_CR_DAC2, + SCODA_REG_CR_ADC, + SCODA_REG_CR_MIX, + SCODA_REG_DR_MIX, + SCODA_REG_CR_VIC, + SCODA_REG_CR_CK, + SCODA_REG_FCR_DAC, + SCODA_REG_SFCCR_DAC, + SCODA_REG_SFFCR_DAC, + SCODA_REG_FCR_ADC, + SCODA_REG_CR_TIMER_MSB, + SCODA_REG_CR_TIMER_LSB, + SCODA_REG_ICR, + SCODA_REG_IMR, + SCODA_REG_IFR, + SCODA_REG_IMR2, + SCODA_REG_IFR2, + SCODA_REG_GCR_DACL, + SCODA_REG_GCR_DACR, + SCODA_REG_GCR_DACL2, + SCODA_REG_GCR_DACR2, + SCODA_REG_GCR_MIC1, + SCODA_REG_GCR_MIC2, + SCODA_REG_GCR_ADCL, + SCODA_REG_GCR_ADCR, + SCODA_REG_GCR_MIXDACL, + SCODA_REG_GCR_MIXDACR, + SCODA_REG_GCR_MIXADCL, + SCODA_REG_GCR_MIXADCR, + SCODA_REG_CR_DAC_AGC, + SCODA_REG_DR_DAC_AGC, + SCODA_REG_CR_DAC2_AGC, + SCODA_REG_DR_DAC2_AGC, + SCODA_REG_CR_ADC_AGC, + SCODA_REG_DR_ADC_AGC, + SCODA_REG_SR_ADC_AGCDGL, + SCODA_REG_SR_ADC_AGCDGR, + SCODA_REG_SR_ADC_AGCAGL, + SCODA_REG_SR_ADC_AGCAGR, + SCODA_REG_CR_TR, + SCODA_REG_DR_TR, + SCODA_REG_SR_TR1, + SCODA_REG_SR_TR2, + SCODA_REG_SR_TR_SRCDAC, + +/* icodec internal register extend space */ + SCODA_MIX_0, + SCODA_MIX_1, + SCODA_MIX_2, + SCODA_MIX_3, + SCODA_MIX_4, + + SCODA_DAC_AGC0, + SCODA_DAC_AGC1, + SCODA_DAC_AGC2, + SCODA_DAC_AGC3, + + SCODA_DAC2_AGC0, + SCODA_DAC2_AGC1, + SCODA_DAC2_AGC2, + SCODA_DAC2_AGC3, + + SCODA_ADC_AGC0, + SCODA_ADC_AGC1, + SCODA_ADC_AGC2, + SCODA_ADC_AGC3, + SCODA_ADC_AGC4, + SCODA_MAX_REG_NUM, +}; + + + +/*aicr dac*/ +#define SCODA_AICR_DAC_ADWL_SHIFT (6) +#define SCODA_AICR_DAC_ADWL_MASK (0x3 << SCODA_AICR_DAC_ADWL_SHIFT) +#define SCODA_AICR_DAC_SLAVE_SHIFT (5) +#define SCODA_AICR_DAC_SLAVE_MASK (0x1 << SCODA_AICR_DAC_SLAVE_SHIFT) +#define SCODA_AICR_DAC_SLAVE (1 << 5) +#define SCODA_AICR_DAC_SB_SHIFT (4) +#define SCODA_AICR_DAC_SB_MASK (0x1 << SCODA_AICR_DAC_SB_SHIFT) +#define SCODA_AICR_DAC_AUDIOIF_SHIFT (0) +#define SCODA_AICR_DAC_AUDIO_MASK (0x3 << SCODA_AICR_DAC_AUDIOIF_SHIFT) +#define SCODA_AICR_DAC_AUDIOIF_I2S (0x3) + +/* aicr adc */ +#define SCODA_AICR_ADC_ADWL_SHIFT (6) +#define SCODA_AICR_ADC_ADWL_MASK (0x3 << SCODA_AICR_ADC_ADWL_SHIFT) +#define SCODA_AICR_ADC_SB_SHIFT (4) +#define SCODA_AICR_ADC_SB_MASK (0x1 << SCODA_AICR_ADC_SB_SHIFT) +#define SCODA_AICR_ADC_AUDIOIF_SHIFT (0) +#define SCODA_AICR_ADC_AUDIO_MASK (0x3 << SCODA_AICR_ADC_AUDIOIF_SHIFT) +#define SCODA_AICR_ADC_AUDIOIF_I2S (0x3) + +/* cr vic */ +#define SCODA_CR_VIC_SB_SHIFT (0) +#define SCODA_CR_VIC_SB_MASK (1 << SCODA_CR_VIC_SB_SHIFT) +#define SCODA_CR_VIC_SB_SLEEP_SHIFT (1) +#define SCODA_CR_VIC_SB_SLEEP_MASK (1 << SCODA_CR_VIC_SB_SLEEP_SHIFT) + +/* fcr adc/dac */ +#define SCODA_FCR_FREQ_SHIFT (0) +#define SCODA_FCR_FREQ_MASK (0xf << SCODA_FCR_FREQ_SHIFT) + +/* cr dac */ +#define SCODA_CR_DAC_SMUTE_SHIFT (7) +#define SCODA_CR_DAC_SMUTE_MASK (0x1 << SCODA_CR_DAC_SMUTE_SHIFT) +#define SCODA_CR_DAC_SB_SHIFT (4) +#define SCODA_CR_DAC_SB_MASK (0x1 << SCODA_CR_DAC_SB_SHIFT) +#define SCODA_CR_DAC_ZERO_SHIFT (0) +#define SCODA_CR_DAC_ZERO_MASK (0x1 << SCODA_CR_DAC_ZERO_SHIFT) + +/* cr dac */ +#define SCODA_CR_ADC_SMUTE_SHIFT (7) +#define SCODA_CR_ADC_SMUTE_MASK (0x1 << SCODA_CR_ADC_SMUTE_SHIFT) +#define SCODA_CR_ADC_MIC_SEL_SHIFT (6) +#define SCODA_CR_ADC_MIC_SEL_MASK (0x1 << SCODA_CR_ADC_MIC_SEL_SHIFT) +#define SCODA_CR_ADC_SB_SHIFT (4) +#define SCODA_CR_ADC_SB_MASK (0x1 << SCODA_CR_ADC_SB_SHIFT) +#define SCODA_CR_ADC_ZERO_SHIFT (0) +#define SCODA_CR_ADC_ZERO_MASK (0x1 << SCODA_CR_ADC_ZERO_SHIFT) + +/* ifr */ +#define SCODA_IFR_DAC_MUTE_SHIFT (0) +#define SCODA_IFR_DAC_MUTE_MASK (0x1 << SCODA_IFR_DAC_MUTE_SHIFT) +#define SCODA_IFR_ADC_MUTE_SHIFT (2) +#define SCODA_IFR_ADC_MUTE_MASK (0x1 << SCODA_IFR_ADC_MUTE_SHIFT) +#define SCODA_IFR_ADAS_LOCK_SHIFT (7) +#define SCODA_IFR_ADAS_LOCK_MASK (0x1 << SCODA_IFR_ADAS_LOCK_SHIFT) + +/* cr ck */ +#define SCODA_CR_CK_MCLK_DIV_SHIFT (6) +#define SCODA_CR_CK_MCLK_DIV_MASK (0x1 << SCODA_CR_CK_MCLK_DIV_SHIFT) +#define SCODA_CR_CK_SDCLK_SHIFT (4) +#define SCODA_CR_CK_SDCLK_MASK (0x1 << SCODA_CR_CK_SDCLK_SHIFT) +#define SCODA_CR_CRYSTAL_SHIFT (0) +#define SCODA_CR_CRYSTAL_MASK (0xf << SCODA_CR_CRYSTAL_SHIFT) + +/* icr */ +#define SCODA_ICR_INT_FORM_SHIFT (6) +#define SCODA_ICR_INT_FORM_MASK (0x3 << SCODA_ICR_INT_FORM_SHIFT) +#define SCODA_ICR_INT_FORM_HIGH (0) +#define SCODA_ICR_INT_FORM_LOW (1) + +/* imr */ +#define SCODA_IMR_COMMON_MASK (0xff) +#define SCODA_IMR2_COMMON_MASK (0xff) + +/*For Codec*/ +#define RGADW (0x4) +#define RGDATA (0x8) + + +static inline void icodec_mapped_reg_set(uint32_t xreg, int xmask, int xval) +{ + int val = readl(xreg); + val &= ~(xmask); + val |= xval; + writel(val, xreg); +} + + +static inline int icodec_mapped_test_bits(uint32_t xreg, int xmask, int xval) +{ + int val = readl(xreg); + val &= xmask; + return (val == xval); +} + + +/* + * RGADW + */ +#define SCODA_RGDIN_BIT (0) +#define SCODA_RGDIN_MASK (0xff << SCODA_RGDIN_BIT) +#define SCODA_RGADDR_BIT (8) +#define SCODA_RGADDR_MASK (0x7f << SCODA_RGADDR_BIT) +#define SCODA_RGWR_BIT (16) +#define SCODA_RGWR_MASK (0x1 << SCODA_RGWR_BIT) + +#define icodec_test_rw_inval(icodec) \ + icodec_mapped_test_bits((icodec->mapped_base + RGADW), SCODA_RGWR_MASK, (1 << SCODA_RGWR_BIT)) +/* + * RGDATA + */ +#define SCODA_RGDOUT_BIT (0) +#define SCODA_RGDOUT_MASK (0xff << SCODA_RGDOUT_BIT) +#define SCODA_IRQ_BIT (8) +#define SCODA_IRQ_MASK (0x1 << SCODA_IRQ_BIT) + +#define icodec_test_irq(icodec) \ + icodec_mapped_test_bits((icodec->mapped_base + RGDATA), SCODA_IRQ_MASK, (1 << SCODA_IRQ_BIT)) + +static inline uint8_t icodec_hw_read_normal(struct jz_icodec *icodec, int reg) +{ + uint32_t mapped_base = icodec->mapped_base; + int reval; + int timeout = 0xfffff; + uint32_t flags; + + while (icodec_test_rw_inval(icodec)) + { + timeout--; + if (!timeout) + { +// rt_kprintf("icodec test_rw_inval timeout\n"); + break; + } + } + + icodec_mapped_reg_set((mapped_base + RGADW), SCODA_RGWR_MASK,(0 << SCODA_RGWR_BIT)); + icodec_mapped_reg_set((mapped_base + RGADW), SCODA_RGADDR_MASK,(reg << SCODA_RGADDR_BIT)); + + reval = readl((mapped_base + RGDATA)); + reval = readl((mapped_base + RGDATA)); + reval = readl((mapped_base + RGDATA)); + reval = readl((mapped_base + RGDATA)); + reval = readl((mapped_base + RGDATA)); + reval = ((reval & SCODA_RGDOUT_MASK) >> SCODA_RGDOUT_BIT); +// rt_kprintf("reg %x = %x\n", reg, reval); + + return (uint8_t) reval; +} + + +static inline int icodec_hw_write_normal(struct jz_icodec *icodec, int reg, int data) +{ + uint32_t mapped_base = icodec->mapped_base; + int ret = 0; + int timeout = 0xfffff; + uint32_t flags; + + + while (icodec_test_rw_inval(icodec)) + { + timeout--; + if (!timeout) + { +// rt_kprintf("icodec test_rw_inval timeout\n"); + break; + } + } + icodec_mapped_reg_set((mapped_base + RGADW), SCODA_RGDIN_MASK | SCODA_RGADDR_MASK, + (data << SCODA_RGDIN_BIT) | (reg << SCODA_RGADDR_BIT)); + icodec_mapped_reg_set((mapped_base + RGADW), SCODA_RGWR_MASK , + 1 << SCODA_RGWR_BIT); + + if (reg != SCODA_REG_IFR && reg != SCODA_REG_IFR2) + { + ret = icodec_hw_read_normal(icodec, reg); + if (data != ret) + { +// rt_kprintf("icdc write reg %x err exp %x now is %x\n", reg, data, ret); + ret = -1; + } + } + return ret; +} + +static int icodec_hw_write_extend(struct jz_icodec *icodec, uint8_t sreg, uint8_t sdata) +{ + int creg, cdata, dreg; + switch (sreg) { + case SCODA_MIX_0 ... SCODA_MIX_4: + creg = SCODA_REG_CR_MIX; + dreg = SCODA_REG_DR_MIX; + sreg -= (SCODA_REG_SR_TR_SRCDAC + 1); + break; + case SCODA_DAC_AGC0 ... SCODA_DAC_AGC3: + creg = SCODA_REG_CR_DAC_AGC; + dreg = SCODA_REG_DR_DAC_AGC; + sreg -= (SCODA_MIX_4 +1); + break; + case SCODA_DAC2_AGC0 ... SCODA_DAC2_AGC3: + creg = SCODA_REG_CR_DAC2; + dreg = SCODA_REG_DR_DAC2_AGC; + sreg -= (SCODA_DAC_AGC3 + 1); + break; + case SCODA_ADC_AGC0 ... SCODA_ADC_AGC4: + creg = SCODA_REG_CR_ADC_AGC; + dreg = SCODA_REG_DR_ADC_AGC; + sreg -= (SCODA_ADC_AGC4 + 1); + break; + default: + return 0; + } +// rt_kprintf("write extend : sreg: %d [0 - 4], creg: %x sdata: %d\n", sreg, creg, sdata); + + cdata = (icodec_hw_read_normal(icodec,creg)&(~0x3f))|((sreg&0x3f)|0x40); + + icodec_hw_write_normal(icodec, creg, cdata); + icodec_hw_write_normal(icodec, dreg, sdata); + if(sdata!=icodec_hw_read_normal(icodec,dreg)) + return -1; + return 0; +} + + +static uint8_t icodec_hw_read_extend(struct jz_icodec *icodec, uint8_t sreg) +{ + int creg, cdata, dreg, ddata; + switch (sreg) + { + case SCODA_MIX_0 ... SCODA_MIX_4: + creg = SCODA_REG_CR_MIX; + dreg = SCODA_REG_DR_MIX; + sreg -= (SCODA_REG_SR_TR_SRCDAC + 1); + break; + case SCODA_DAC_AGC0 ... SCODA_DAC_AGC3: + creg = SCODA_REG_CR_DAC_AGC; + dreg = SCODA_REG_DR_DAC_AGC; + sreg -= (SCODA_MIX_4 +1); + break; + case SCODA_DAC2_AGC0 ... SCODA_DAC2_AGC3: + creg = SCODA_REG_CR_DAC2; + dreg = SCODA_REG_DR_DAC2_AGC; + sreg -= (SCODA_DAC_AGC3 + 1); + break; + case SCODA_ADC_AGC0 ... SCODA_ADC_AGC4: + creg = SCODA_REG_CR_ADC_AGC; + dreg = SCODA_REG_DR_ADC_AGC; + sreg -= (SCODA_ADC_AGC4 + 1); + break; + default: + return 0; + } + cdata = (icodec_hw_read_normal(icodec, creg) & (~0x7f)) | (sreg & 0x3f); + icodec_hw_write_normal(icodec, creg, cdata); + ddata = icodec_hw_read_normal(icodec, dreg); + + return (uint8_t) ddata; +} + + +static inline uint8_t icodec_hw_read(struct jz_icodec *icodec, int reg) +{ + if (reg > SCODA_REG_SR_TR_SRCDAC) + return icodec_hw_read_extend(icodec, reg); + else + return icodec_hw_read_normal(icodec, reg); +} +static inline int icodec_hw_write(struct jz_icodec *icodec, int reg, int data) +{ + if (reg > SCODA_REG_SR_TR_SRCDAC) + return icodec_hw_write_extend(icodec, reg, data); + else + return icodec_hw_write_normal(icodec, reg, data); +} + + +#endif /* _DRV_CODEC_ICODEC_H_ */ diff --git a/bsp/x1000/drivers/audio/drv_dmic.c b/bsp/x1000/drivers/audio/drv_dmic.c new file mode 100644 index 0000000000000000000000000000000000000000..9f8c176d9fd5da5a857ed6b6a912c18d0b990fcf --- /dev/null +++ b/bsp/x1000/drivers/audio/drv_dmic.c @@ -0,0 +1,428 @@ +/* + * File : drv_dmic.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ + +#include +#include +#include +#include + +#ifdef RT_USING_FINSH +# include +#endif + +#include "board.h" +#include "drv_gpio.h" +#include "drv_dma.h" +#include "drv_aic.h" +#include "drv_clock.h" +#include "drv_dmic.h" +#include "dma.h" +#include "audio_pipe.h" + +#define DMIC_DEBUG 0 +#if DMIC_DEBUG +# define DMIC_DBG(...) rt_kprintf("[DMIC]"),rt_kprintf(__VA_ARGS__) +#else +# define DMIC_DBG(...) +#endif + +#define DMIC_DMA_RX_CHAN 4 +#define DMIC_FIFO_DEPTH 64 +#define JZ_DMIC_FORMATS 16 +#define JZ_DMIC_RATE (8000) +ALIGN(32) rt_uint32_t _g_dmic_dma_buffer[DMIC_DMA_PAGE_NUM*DMIC_DMA_PAGE_SIZE/sizeof(rt_uint32_t)]; +static struct jz_dmic _g_jz_dmic= +{ + .io_base = DMIC_BASE, + .dma_buf = (rt_uint8_t *)_g_dmic_dma_buffer, + .dma_offset = 0, +}; + +static void dump_dmic_registers(void) +{ + struct jz_dmic *jz_dmic = &_g_jz_dmic; + rt_kprintf("DMICCR0 %p : 0x%08x\n", (jz_dmic->io_base+DMICCR0),dmic_read_reg(jz_dmic, DMICCR0)); + rt_kprintf("DMICGCR %p : 0x%08x\n", (jz_dmic->io_base+DMICGCR),dmic_read_reg(jz_dmic, DMICGCR)); + rt_kprintf("DMICIMR %p : 0x%08x\n", (jz_dmic->io_base+DMICIMR),dmic_read_reg(jz_dmic, DMICIMR)); + rt_kprintf("DMICINTCR %p : 0x%08x\n", (jz_dmic->io_base+DMICINTCR),dmic_read_reg(jz_dmic, DMICINTCR)); + rt_kprintf("DMICTRICR %p : 0x%08x\n", (jz_dmic->io_base+DMICTRICR),dmic_read_reg(jz_dmic, DMICTRICR)); + rt_kprintf("DMICTHRH %p : 0x%08x\n", (jz_dmic->io_base+DMICTHRH),dmic_read_reg(jz_dmic, DMICTHRH)); + rt_kprintf("DMICTHRL %p : 0x%08x\n", (jz_dmic->io_base+DMICTHRL),dmic_read_reg(jz_dmic, DMICTHRL)); + rt_kprintf("DMICTRIMMAX %p : 0x%08x\n", (jz_dmic->io_base+DMICTRIMMAX),dmic_read_reg(jz_dmic, DMICTRIMMAX)); + rt_kprintf("DMICTRINMAX %p : 0x%08x\n", (jz_dmic->io_base+DMICTRINMAX),dmic_read_reg(jz_dmic, DMICTRINMAX)); + rt_kprintf("DMICDR %p : 0x%08x\n", (jz_dmic->io_base+DMICDR),dmic_read_reg(jz_dmic, DMICDR)); + rt_kprintf("DMICFTHR %p : 0x%08x\n", (jz_dmic->io_base+DMICFTHR),dmic_read_reg(jz_dmic, DMICFTHR)); + rt_kprintf("DMICFSR %p : 0x%08x\n", (jz_dmic->io_base+DMICFSR),dmic_read_reg(jz_dmic, DMICFSR)); + rt_kprintf("DMICCGDIS %p : 0x%08x\n", (jz_dmic->io_base+DMICCGDIS),dmic_read_reg(jz_dmic, DMICCGDIS)); + return; +} +MSH_CMD_EXPORT(dump_dmic_registers,"dump dmic regs...\n"); + +int jz_dmic_set_rate(struct jz_dmic* dmic, int rate) +{ + // rt_kprintf("rate = %d\n",rate); + switch (rate) + { + case 8000: + __dmic_set_sr_8k(dmic); + break; + case 16000: + __dmic_set_sr_16k(dmic); + break; + case 48000: + __dmic_set_sr_48k(dmic); + break; + default: + DMIC_DBG("dmic unsupport rate %d\n", rate); + } + return 0; +} + +int jz_dmic_set_channels(struct jz_dmic* dmic, int channels) +{ + if (channels > 4) + channels = 4; + if (channels <= 1) + channels = 1; + + __dmic_set_chnum(dmic,channels - 1); +} + + +int jz_dmic_set_record_volume(struct jz_dmic* dmic, int vol) +{ + if(vol >= 32) + vol = 31; + __dmic_set_gcr(dmic,vol); + + dmic->record_gain = vol; +} + +static void jz_dmic_dma_complete(struct rt_dma_channel *dmac, struct dma_message *msg) +{ + rt_base_t level; + if(msg->complete_cb) + msg->complete_cb(msg->complete_arg,msg->dst_addr); + + /* restart DMA Job */ + rt_dma_trans_message(dmac,msg); +} + + +void jz_dmic_start_recv(struct jz_dmic* dmic,void (*rx_callback)(void *,void *), void *rx_arg) +{ + rt_base_t level; + rt_uint32_t i; + struct dma_message message; + __dmic_enable_rdms(dmic); + __dmic_enable(dmic); + level = rt_hw_interrupt_disable(); + dmic->dma_offset = 0; + dmic->dma_buf = (rt_uint8_t *)_g_dmic_dma_buffer; + + for (i = 0; i < DMIC_DMA_PAGE_NUM; ++i) + { + message.src_addr = (uint8_t *) (DMIC_BASE + DMICDR); + message.src_option = RT_DMA_ADDR_FIX; + message.dst_addr = (uint8_t *) (dmic->dma_buf + DMIC_DMA_PAGE_SIZE * i); + message.dst_option = RT_DMA_ADDR_INC; + message.t_size = DMIC_DMA_PAGE_SIZE; + message.t_mode = JZDMA_REQ_DMIC_RX; + /* init callback */ + message.complete_cb = rx_callback; + message.complete_arg = rx_arg; + rt_dma_trans_message(dmic->rx_dmac,&message); + } + rt_hw_interrupt_enable(level); + return ; +} + +void jz_dmic_stop_recv(struct jz_dmic* dmic) +{ + if (__dmic_is_enable_rdms(dmic)) + { + __dmic_disable_rdms(dmic); + } + __dmic_disable(dmic); +} + + +void dmic_rx_complete(void *data,void *pbuf) +{ + struct jz_dmic *dmic = (struct jz_dmic *)data; + + rt_device_write(RT_DEVICE(&dmic->pipe),0,pbuf,DMIC_DMA_PAGE_SIZE); +} + +#define CFG_DMIC_PIPE_SIZE (2 * 1024) +struct jz_dmic* rt_hw_dmic_init(void) +{ + struct jz_dmic *dmic = &_g_jz_dmic; + + //init pipe for record + { + rt_uint8_t *buf = rt_malloc(CFG_DMIC_PIPE_SIZE); + + if(buf == RT_NULL) + { + rt_kprintf("request pipe memory error\n"); + + return RT_NULL; + } + + rt_audio_pipe_init(&dmic->pipe,"recdmic",RT_PIPE_FLAG_FORCE_WR | RT_PIPE_FLAG_BLOCK_RD,buf,(CFG_DMIC_PIPE_SIZE)); + + rt_device_open(RT_DEVICE(&dmic->pipe),RT_DEVICE_OFLAG_RDONLY); + } + + /* GPIO config + * PB05 -> FUNC1 DMIC1_IN + * PB21 -> FUNC0 DMIC_CLK + * PB22 -> FUNC0 DMIC0_IN + * */ + gpio_set_func(GPIO_PORT_B,GPIO_Pin_5,GPIO_FUNC_1); + gpio_set_func(GPIO_PORT_B,GPIO_Pin_21,GPIO_FUNC_0); + gpio_set_func(GPIO_PORT_B,GPIO_Pin_22,GPIO_FUNC_0); + + /* enable clock */ + dmic->clk_gate = clk_get("dmic"); + if (dmic->clk_gate == RT_NULL) + { + DMIC_DBG("Failed to get dmic gate clock \n"); + return RT_NULL; + } + clk_enable(dmic->clk_gate); + + /*gain: 0, ..., e*/ + __dmic_reset(dmic); + while (__dmic_get_reset(dmic)) ; + + jz_dmic_set_rate(dmic, 8000); + __dmic_set_chnum(dmic,0); //mono + __dmic_enable_hpf1(dmic); + __dmic_set_gcr(dmic, 27); + __dmic_mask_all_int(dmic); + __dmic_enable_pack(dmic); + __dmic_enable_sw_lr(dmic); + __dmic_enable_lp(dmic); + __dmic_disable_lp(dmic); + __dmic_set_request(dmic, 48); + __dmic_enable_hpf2(dmic); + __dmic_set_thr_high(dmic, 32); + __dmic_set_thr_low(dmic, 16); + __dmic_enable_tri(dmic); + + + //config DMA + { + int trigger; + + /* DMA config */ + struct dma_config config; + dmic->rx_dmac = rt_dma_get_channel(DMIC_DMA_RX_CHAN); + if (dmic->rx_dmac != RT_NULL) + { + DMIC_DBG("config dmic dma rx channel...\n"); + config.direction = RT_DMA_DEV_TO_MEM; + config.src_addr_width = RT_DMA_BUSWIDTH_2_BYTES; + config.src_maxburst = (DMIC_FIFO_DEPTH * RT_DMA_BUSWIDTH_2_BYTES) / 2; + config.dst_addr_width = RT_DMA_BUSWIDTH_2_BYTES; + config.dst_maxburst = (64 * 1024); + rt_dma_configture(dmic->rx_dmac, &config); + + dmic->rx_dmac->start = RT_NULL; + dmic->rx_dmac->complete = jz_dmic_dma_complete; + } + trigger = config.src_maxburst / config.src_addr_width; + __dmic_set_request(dmic, trigger); + } + + jz_dmic_start_recv(dmic,dmic_rx_complete,dmic); + + return dmic; + +_error_exit: + __dmic_disable(dmic); + + rt_audio_pipe_detach(&dmic->pipe); + + clk_disable(dmic->clk_gate); + + return RT_NULL; +} +//INIT_ENV_EXPORT(rt_hw_dmic_init); + + +struct speech_wav_header +{ + char riff_id[4]; //"RIFF" + uint32_t size0; //file len - 8 + char wave_fmt[8]; //"WAVEfmt " + uint32_t size1; //0x10 + uint16_t fmttag; //0x01 + uint16_t channel; //1 + uint32_t samplespersec; //8000 + uint32_t bytepersec; //8000 * 2 + uint16_t blockalign; //1 * 16 / 8 + uint16_t bitpersamples; //16 + char data_id[4]; //"data" + uint32_t size2; //file len - 44 +}; + +static void speech_wav_init_header(struct speech_wav_header *header,rt_uint16_t Channels,int SamplesPerSec,int BitsPerSample) +{ + strcpy(header->riff_id, "RIFF"); + header->size0 = 0; // Final file size not known yet, write 0 + strcpy(header->wave_fmt, "WAVEfmt "); + header->size1 = 16; // Sub-chunk size, 16 for PCM + header->fmttag = 1; // AudioFormat, 1 for PCM + header->channel = Channels; // Number of channels, 1 for mono, 2 for stereo + header->samplespersec = SamplesPerSec; // Sample rate + header->bytepersec = SamplesPerSec * BitsPerSample * Channels / 8; //Byte rate + header->blockalign = Channels * BitsPerSample / 8; // Block align, NumberOfChannels*BitsPerSample/8 + header->bitpersamples = BitsPerSample; + strcpy(header->data_id, "data"); + header->size2 = 0; +} + +static void speech_wav_upgrade_size(struct speech_wav_header *header,rt_uint32_t paylodSize) +{ + header->size0 = paylodSize + 36; + header->size2 = paylodSize; +} + + +#include +#include + +rt_uint8_t rec_buff[2048]; +int dmic_record(int samplingrates) +{ + struct jz_dmic *dmic = &_g_jz_dmic; + rt_device_t dmic_pipe; + struct speech_wav_header wav_header; + rt_uint32_t wav_len = 0; + char *file_name; + int fd; + int i = 0; + int rdlen, wrlen; + + rt_kprintf("samplingrates = %d\n",samplingrates); + if((samplingrates != 8000) && (samplingrates != 16000)) + { + rt_kprintf("un-support this samplingrates\n"); + return -RT_EIO; + } + + dmic_pipe = rt_device_find("recdmic"); + if(dmic_pipe == RT_NULL) + { + rt_kprintf("can't find the record device\n"); + return -RT_ERROR ; + } + + rt_kprintf("pls hold WAKE key to start record...\n"); + while(gpio_get_value(GPIO_PORT_B, GPIO_Pin_31) == 1) + rt_thread_delay(100); + rt_kprintf("OK,start record....\n"); + if(samplingrates == 8000) + file_name = "/appfs/dmic8k.wav"; + else + file_name = "/appfs/dmic16k.wav"; + + fd = open(file_name, O_WRONLY | O_CREAT | O_TRUNC, 0); + if (fd < 0) + { + rt_kprintf("open file for write failed\n"); + return -RT_EIO; + } + + speech_wav_init_header(&wav_header,1,samplingrates,16); + write(fd, &wav_header, wav_len); + + jz_dmic_set_rate(dmic,samplingrates); + wav_len = 0; + while(i++ < 1000) + { + rdlen = rt_device_read(dmic_pipe,0,rec_buff,sizeof(rec_buff)); + + wrlen = write(fd, rec_buff, rdlen); + if (wrlen != rdlen) + { + rt_kprintf("write data failed\n"); + close(fd); + + return -RT_EIO; + } + + wav_len += wrlen; + + if(gpio_get_value(GPIO_PORT_B, GPIO_Pin_31) == 1) + break; + } + rt_kprintf("record complete...\n"); + + //upgrage wav header + lseek(fd,0,SEEK_SET); + speech_wav_upgrade_size(&wav_header,wav_len); + write(fd, &wav_header, sizeof(struct speech_wav_header)); + + close(fd); + + rt_kprintf("WAV file saved ok!\n"); +} +FINSH_FUNCTION_EXPORT(dmic_record,dmic record test); + +#if 0 +int dmic_test(void) +{ + rt_device_t device; + int i = 0; + + device = rt_device_find("recdmic"); + if(device == RT_NULL) + { + rt_kprintf("can't find the record device\n"); + return -RT_ERROR ; + } + + audio_device_set_rate(8000); + + while(i++ < 1000) + { + int len; + uint8_t *sendBuf; + + sendBuf = audio_device_get_buffer(&len); + len = rt_device_read(device,0,sendBuf,len); + + audio_device_write(sendBuf,len); + } + + rt_kprintf("dmic test complete...\n"); + + return 0; +} +MSH_CMD_EXPORT(dmic_test,dmic test ....); +#endif diff --git a/bsp/x1000/drivers/audio/drv_dmic.h b/bsp/x1000/drivers/audio/drv_dmic.h new file mode 100644 index 0000000000000000000000000000000000000000..dd63082ddfd096cfddb2c6095aa3cc56dbb7eb17 --- /dev/null +++ b/bsp/x1000/drivers/audio/drv_dmic.h @@ -0,0 +1,262 @@ +/* + * drv_dmic.h + * + * Created on: 2017年1月11日 + * Author: Urey + */ + +#ifndef _DRV_DMIC_H_ +#define _DRV_DMIC_H_ + +/* + * File : drv_dmic.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ + +#include +#include "audio_pipe.h" +#define DMIC_DMA_PAGE_SIZE 512 +#define DMIC_DMA_PAGE_NUM RT_DMA_MAX_NODES +struct jz_dmic +{ + struct rt_audio_pipe pipe; + struct rt_audio_configure record_config; + uint32_t io_base; + + struct clk *clk_gate; + struct rt_dma_channel *rx_dmac; + + rt_uint8_t *dma_buf; + rt_uint32_t dma_offset; + + /* record */ + int record_gain; +}; +static inline void dmic_write_reg(struct jz_dmic *dmic, uint32_t reg, uint32_t val) +{ + writel(val, dmic->io_base + reg); +} +static inline uint32_t dmic_read_reg(struct jz_dmic *jz_dmic, unsigned int reg) +{ + return readl(jz_dmic->io_base + reg); +} +#define dmic_set_reg(dmic, addr, val, mask, offset)\ + do { \ + int tmp_val = val; \ + int read_val = dmic_read_reg(dmic, addr); \ + read_val &= (~mask); \ + tmp_val = ((tmp_val << offset) & mask); \ + tmp_val |= read_val; \ + dmic_write_reg(dmic, addr, tmp_val); \ + }while(0) +#define dmic_get_reg(dmic, addr, mask, offset) \ + ((dmic_read_reg(dmic, addr) & mask) >> offset) +/********************************************************************************************************* +** +*********************************************************************************************************/ +#define DMICCR0 0x00 +#define DMICGCR 0x04 +#define DMICIMR 0x08 +#define DMICINTCR 0x0c +#define DMICTRICR 0x10 +#define DMICTHRH 0x14 +#define DMICTHRL 0x18 +#define DMICTRIMMAX 0x1c +#define DMICTRINMAX 0x20 +#define DMICDR 0x30 +#define DMICFTHR 0x34 +#define DMICFSR 0x38 +#define DMICCGDIS 0x50 +/* DMICCR0 */ +#define DMIC_RESET 31 +#define DMIC_RESET_MASK (0x1 << DMIC_RESET) +#define DMIC_RESET_TRI 30 +#define DMIC_RESET_TRI_MASK (0x1 << DMIC_RESET_TRI) +#define DMIC_CHNUM 16 +#define DMIC_CHNUM_MASK (0x7 << DMIC_CHNUM) +#define DMIC_UNPACK_MSB 13 +#define DMIC_UNPACK_MSB_MASK (0x1 << DMIC_UNPACK_MSB) +#define DMIC_UNPACK_DIS 12 +#define DMIC_UNPACK_DIS_MASK (0x1 << DMIC_UNPACK_DIS) +#define DMIC_SW_LR 11 +#define DMIC_SW_LR_MASK (0x1 << DMIC_SW_LR) +#define DMIC_SPLIT_DI 10 +#define DMIC_SPLIT_DI_MASK (0x1 << DMIC_SPLIT_DI) +#define DMIC_PACK_EN 8 +#define DMIC_PACK_EN_MASK (0x1 << DMIC_PACK_EN) +#define DMIC_SR 6 +#define DMIC_SR_MASK (0x3 << DMIC_SR) +#define DMIC_LP_MODE 3 +#define DMIC_LP_MODE_MASK (0x1 << DMIC_LP_MODE) +#define DMIC_HPF1_MODE 2 +#define DMIC_HPF1_MODE_MASK (0x1 << DMIC_HPF1_MODE) +#define DMIC_TRI_EN 1 +#define DMIC_TRI_EN_MASK (0x1 << DMIC_TRI_EN) +#define DMIC_EN 0 +#define DMIC_EN_MASK (0x1 << DMIC_EN) +#define __dmic_reset(dmic)\ + dmic_set_reg(dmic,DMICCR0,1,DMIC_RESET_MASK,DMIC_RESET) +#define __dmic_get_reset(dmic)\ + dmic_get_reg(dmic,DMICCR0,DMIC_RESET_MASK,DMIC_RESET) +#define __dmic_reset_tri(dmic)\ + dmic_set_reg(dmic,DMICCR0,1,DMIC_RESET_TRI_MASK,DMIC_RESET_TRI) +#define __dmic_set_chnum(dmic,n)\ + dmic_set_reg(dmic,DMICCR0,n,DMIC_CHNUM_MASK,DMIC_CHNUM) +#define __dmic_get_chnum(dmic,n)\ + dmic_set_reg(dmic,DMICCR0,DMIC_CHNUM_MASK,DMIC_CHNUM) +#define __dmic_unpack_msb(dmic)\ + dmic_set_reg(dmic,DMICCR0,1,DMIC_UNPACK_MSB_MASK,DMIC_UNPACK_MSB) +#define __dmic_unpack_dis(dmic)\ + dmic_set_reg(dmic,DMICCR0,1,DMIC_UNPACK_DIS_MASK,DMIC_UNPACK_DIS) +#define __dmic_enable_sw_lr(dmic)\ + dmic_set_reg(dmic,DMICCR0,1,DMIC_SW_LR_MASK,DMIC_SW_LR) +#define __dmic_disable_sw_lr(dmic)\ + dmic_set_reg(dmic,DMICCR0,0,DMIC_SW_LR_MASK,DMIC_SW_LR) +#define __dmic_split(dmic)\ + dmic_set_reg(dmic,DMICCR0,1,DMIC_SPLIT_DI_MASK,DMIC_SPLIT_DI) +#define __dmic_enable_pack(dmic)\ + dmic_set_reg(dmic,DMICCR0,1,DMIC_PACK_EN_MASK,DMIC_PACK_EN) +#define __dmic_set_sr(dmic,n)\ + dmic_set_reg(dmic,DMICCR0,n,DMIC_SR_MASK,DMIC_SR) +#define __dmic_set_sr_8k(dmic)\ + __dmic_set_sr(dmic,0) +#define __dmic_set_sr_16k(dmic)\ + __dmic_set_sr(dmic,1) +#define __dmic_set_sr_48k(dmic)\ + __dmic_set_sr(dmic,2) +#define __dmic_enable_lp(dmic)\ + dmic_set_reg(dmic,DMICCR0,1,DMIC_LP_MODE_MASK,DMIC_LP_MODE) +#define __dmic_disable_lp(dmic)\ + dmic_set_reg(dmic,DMICCR0,0,DMIC_LP_MODE_MASK,DMIC_LP_MODE) +#define __dmic_enable_hpf1(dmic)\ + dmic_set_reg(dmic,DMICCR0,1,DMIC_HPF1_MODE_MASK,DMIC_HPF1_MODE) +#define __dmic_disable_hpf1(dmic)\ + dmic_set_reg(dmic,DMICCR0,0,DMIC_HPF1_MODE_MASK,DMIC_HPF1_MODE) +#define __dmic_is_enable_tri(dmic)\ + dmic_get_reg(dmic,DMICCR0,DMIC_TRI_EN_MASK,DMIC_TRI_EN) +#define __dmic_enable_tri(dmic)\ + dmic_set_reg(dmic,DMICCR0,1,DMIC_TRI_EN_MASK,DMIC_TRI_EN) +#define __dmic_disable_tri(dmic)\ + dmic_set_reg(dmic,DMICCR0,0,DMIC_TRI_EN_MASK,DMIC_TRI_EN) +#define __dmic_is_enable(dmic)\ + dmic_get_reg(dmic,DMICCR0,DMIC_EN_MASK,DMIC_EN) +#define __dmic_enable(dmic)\ + dmic_set_reg(dmic,DMICCR0,1,DMIC_EN_MASK,DMIC_EN) +#define __dmic_disable(dmic)\ + dmic_set_reg(dmic,DMICCR0,0,DMIC_EN_MASK,DMIC_EN) +/*DMICGCR*/ +#define DMIC_GCR 0 +#define DMIC_GCR_MASK (0Xf << DMIC_GCR) +#define __dmic_set_gcr(dmic,n)\ + dmic_set_reg(dmic, DMICGCR, n, DMIC_GCR_MASK,DMIC_GCR) +/* DMICIMR */ +#define DMIC_FIFO_TRIG_MASK 5 +#define DMIC_FIFO_TRIG_MSK (1 << DMIC_FIFO_TRIG_MASK) +#define DMIC_WAKE_MASK 4 +#define DMIC_WAKE_MSK (1 << DMIC_WAKE_MASK) +#define DMIC_EMPTY_MASK 3 +#define DMIC_EMPTY_MSK (1 << DMIC_EMPTY_MASK) +#define DMIC_FULL_MASK 2 +#define DMIC_FULL_MSK (1 << DMIC_FULL_MASK) +#define DMIC_PRERD_MASK 1 +#define DMIC_PRERD_MSK (1 << DMIC_PRERD_MASK) +#define DMIC_TRI_MASK 0 +#define DMIC_TRI_MSK (1 << DMIC_TRI_MASK) +#define __dmic_mask_all_int(dmic)\ + dmic_set_reg(dmic,DMICIMR, 0x3f, 0x3f, 0) +/*DMICINTCR*/ +#define DMIC_FIFO_TRIG_FLAG 4 +#define DMIC_FIFO_TRIG_FLAG_MASK (1 << DMIC_WAKE_FLAG) +#define DMIC_WAKE_FLAG 4 +#define DMIC_WAKE_FLAG_MASK (1 << DMIC_WAKE_FLAG) +#define DMIC_EMPTY_FLAG 3 +#define DMIC_EMPTY_FLAG_MASK (1 << DMIC_EMPTY_FLAG) +#define DMIC_FULL_FLAG 2 +#define DMIC_FULL_FLAG_MASK (1 << DMIC_FULL_FLAG) +#define DMIC_PRERD_FLAG 1 +#define DMIC_PRERD_FLAG_MASK (1 << DMIC_PRERD_FLAG) +#define DMIC_TRI_FLAG 0 +#define DMIC_TRI_FLAG_MASK (1 << DMIC_TRI_FLAG) +/*DMICTRICR*/ +#define DMIC_TRI_MODE 16 +#define DMIC_TRI_MODE_MASK (0xf << DMIC_TRI_MODE) +#define DMIC_TRI_DEBUG 4 +#define DMIC_TRI_DEBUG_MASK (0x1 << DMIC_TRI_DEBUG) +#define DMIC_HPF2_EN 3 +#define DMIC_HPF2_EN_MASK (0x1 << DMIC_HPF2_EN) +#define DMIC_PREFETCH 1 +#define DMIC_PREFETCH_MASK (0x3 << DMIC_PREFETCH) +#define DMIC_TRI_CLR 0 +#define DMIC_TRI_CLR_MASK (0x1 << DMIC_TRI_CLR) +#define __dmic_enable_hpf2(dmic) \ + dmic_set_reg(dmic, DMICTRICR, 1, DMIC_HPF2_EN_MASK, DMIC_HPF2_EN) +#define __dmic_disable_hpf2(dmic) \ + dmic_set_reg(dmic, DMICTRICR, 0, DMIC_HPF2_EN_MASK, DMIC_HPF2_EN) +/*DMICTHRH*/ +#define DMIC_THR_H 0 +#define DMIC_THR_H_MASK (0xfffff << DMIC_THR_H) +#define __dmic_set_thr_high(dmic,n) \ + dmic_set_reg(dmic, DMICTHRH, n, DMIC_THR_H_MASK, DMIC_THR_H) +/*DMICTHRL*/ +#define DMIC_THR_L 0 +#define DMIC_THR_L_MASK (0xfffff << DMIC_THR_L) +#define __dmic_set_thr_low(dmic,n) \ + dmic_set_reg(dmic, DMICTHRL, n, DMIC_THR_L_MASK, DMIC_THR_L) +/* DMICTRIMMAX */ +#define DMIC_M_MAX 0 +#define DMIC_M_MAX_MASK (0xffffff << DMIC_M_MAX) +/* DMICTRINMAX */ +#define DMIC_N_MAX 0 +#define DMIC_N_MAX_MASK (0xffff << DMIC_N_MAX) +/* DMICFTHR */ +#define DMIC_RDMS 31 +#define DMIC_RDMS_MASK (0x1 << DMIC_RDMS) +#define DMIC_FIFO_THR 0 +#define DMIC_FIFO_THR_MASK (0x3f << DMIC_FIFO_THR) +#define __dmic_is_enable_rdms(dmic)\ + dmic_get_reg(dmic, DMICFTHR,DMIC_RDMS_MASK,DMIC_RDMS) +#define __dmic_enable_rdms(dmic)\ + dmic_set_reg(dmic, DMICFTHR,1,DMIC_RDMS_MASK,DMIC_RDMS) +#define __dmic_disable_rdms(dmic)\ + dmic_set_reg(dmic, DMICFTHR,1,DMIC_RDMS_MASK,DMIC_RDMS) +#define __dmic_set_request(dmic,n) \ + dmic_set_reg(dmic, DMICFTHR, n, DMIC_FIFO_THR_MASK, DMIC_FIFO_THR) +/*DMICFSR*/ +#define DMIC_FULLS 19 +#define DMIC_FULLS_MASK (0x1 << DMIC_FULLS) +#define DMIC_TRIGS 18 +#define DMIC_TRIGS_MASK (0x1 << DMIC_TRIGS) +#define DMIC_PRERDS 17 +#define DMIC_PRERDS_MASK (0x1 << DMIC_PRERDS) +#define DMIC_EMPTYS 16 +#define DMIC_EMPTYS_MASK (0x1 << DMIC_EMPTYS) +#define DMIC_FIFO_LVL 0 +#define DMIC_FIFO_LVL_MASK (0x3f << DMIC_FIFO_LVL) +/********************************************************************************************************* +** +*********************************************************************************************************/ +struct jz_dmic* rt_hw_dmic_init(void); +int jz_dmic_set_rate(struct jz_dmic* dmic, int rate); +int jz_dmic_set_gain(struct jz_dmic* dmic, int vol); +int jz_dmic_set_channels(struct jz_dmic* dmic, int channels); + +#endif /* _DRV_DMIC_H_ */ diff --git a/bsp/x1000/driver/board.c b/bsp/x1000/drivers/board.c similarity index 71% rename from bsp/x1000/driver/board.c rename to bsp/x1000/drivers/board.c index 1dc2a427f39400b9c8d3f31fb26bfe5c30208c50..1f8c5e1e2335c0f1000c632556258d74aff5db0b 100644 --- a/bsp/x1000/driver/board.c +++ b/bsp/x1000/drivers/board.c @@ -24,6 +24,7 @@ #include #include +#include #include "board.h" #include "drv_clock.h" @@ -32,12 +33,38 @@ extern void rt_hw_cache_init(void); +extern unsigned char _iramcopy; +extern unsigned char _iramstart; +extern unsigned char _iramend; + +#ifdef RT_USING_CPLUSPLUS +int cplusplus_system_init(void) +{ + typedef void (*pfunc) (); + extern pfunc __ctors_start__[]; + extern pfunc __ctors_end__[]; + pfunc *p; + for (p = __ctors_end__ - 2; p > __ctors_start__; ) + { + (*p)(); + p--; + } + return 0; +} +#endif + void rt_hw_board_init(void) { + memcpy((void*)&_iramstart, (void*)&_iramcopy, (rt_uint32_t)&_iramend - (rt_uint32_t)&_iramstart); + memset((void*)&__bss_start, 0x0, (rt_uint32_t)&__bss_end - (rt_uint32_t)&__bss_start); + rt_hw_cache_init(); + rt_hw_exception_init(); + /* init hardware interrupt */ rt_hw_interrupt_init(); rt_hw_uart_init(); + #ifdef RT_USING_CONSOLE /* set console device */ rt_console_set_device(RT_CONSOLE_DEVICE_NAME); diff --git a/bsp/x1000/drivers/board.h b/bsp/x1000/drivers/board.h new file mode 100644 index 0000000000000000000000000000000000000000..d91fb2f7c0e7923b414c5d889853360dce90a95e --- /dev/null +++ b/bsp/x1000/drivers/board.h @@ -0,0 +1,102 @@ +/* + * File : board.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ + +#ifndef _BOARD_H_ +#define _BOARD_H_ + +#include +#include +#include "x1000.h" + +#define RT_USING_JZ_X1000 +#define X1000 + +#ifdef BOARD_HALLEY2_FIR +#include "board/halley2_fir/board_halley2_fir.h" +#endif + +#ifdef BOARD_HALLEY2_REALBOARD +#include "board/halley2_realboard/board_halley2_readboard.h" +#endif + +#ifdef BOARD_HALLEY2_REALBOARD_V2 +#include "board/halley2_realboard_v2/board_halley2_readboard_v2.h" +#endif + +#ifdef BOARD_HALLEY2_IDELAN +#include "board/halley2_idelan/board_halley2_idelan.h" +#endif + +#ifdef BOARD_HALLEY2 +#include "board/halley2/board_halley2.h" +#endif + +#ifdef BOARD_PHOENIX +#include "board/phoenix/board_phoenix.h" +#endif + +#ifdef BOARD_CANNA +#include "board/canna/board_canna.h" +#endif + +/* + * Clock setting + */ +#define BOARD_EXTAL_CLK 24000000 +#define BOARD_RTC_CLK 32768 +#define BOARD_CPU_CLK (1008 * 1000 * 1000UL) + +#define BOARD_APLL_FREQ 1008000000 /*If APLL not use mast be set 0*/ +#define BOARD_MPLL_FREQ 600000000 /*If MPLL not use mast be set 0*/ + +/* + * Heap setting + */ +extern unsigned char __bss_start; +extern unsigned char __bss_end; + +#define RT_HW_HEAP_BEGIN (void*)&__bss_end +#define RT_HW_HEAP_END (void*)(0x80000000 + 32 * 1024 * 1024) + +/* HW EVENT */ +#define EVENT_NONE 0x0000 + +#define EVENT_TYPE_MSK 0xFF00 +#define EVENT_VALUE_MSK 0x00FF + +#define EVENT_LINEIN 0x0100 +#define EVENT_LINEIN_INSERT 0x0101 +#define EVENT_LINEIN_REMOVE 0x0102 +#define EVENT_LINEIN_SHUTDOWN 0x0103 + +#define EVENT_BAT 0x0200 +#define EVENT_BAT_ALONE 0x0201 +#define EVENT_BAT_CHARGE_IN 0x0202 +#define EVENT_BAT_CHARGE_FULL 0x0203 +#define EVENT_BAT_ERROR 0x0204 + +#define EVENT_KEY_DOWN 0x0300 +#define EVENT_KEY_UP 0x0400 + +#endif /* _BOARD_H_ */ diff --git a/bsp/x1000/drivers/board/canna/PD_X1000_CANNA_BASEBOARD_V2.1.pdf b/bsp/x1000/drivers/board/canna/PD_X1000_CANNA_BASEBOARD_V2.1.pdf new file mode 100644 index 0000000000000000000000000000000000000000..15a3f892e9a7bf47e00dc087f1fa151e67a3a1df Binary files /dev/null and b/bsp/x1000/drivers/board/canna/PD_X1000_CANNA_BASEBOARD_V2.1.pdf differ diff --git a/bsp/x1000/drivers/board/canna/PD_X1000_CANNA_COREBOARD_V1.0.pdf b/bsp/x1000/drivers/board/canna/PD_X1000_CANNA_COREBOARD_V1.0.pdf new file mode 100644 index 0000000000000000000000000000000000000000..1ce34921a86984ea6637d953ccf0ddcda1c96fc8 Binary files /dev/null and b/bsp/x1000/drivers/board/canna/PD_X1000_CANNA_COREBOARD_V1.0.pdf differ diff --git a/bsp/x1000/drivers/board/canna/board_canna.h b/bsp/x1000/drivers/board/canna/board_canna.h new file mode 100644 index 0000000000000000000000000000000000000000..816abe1f0ec55f6f99a56578253ba8bbba56f5bf --- /dev/null +++ b/bsp/x1000/drivers/board/canna/board_canna.h @@ -0,0 +1,6 @@ +#ifndef BOARD_CANNA_H__ +#define BOARD_CANNA_H__ + + +#endif + diff --git a/bsp/x1000/drivers/board/halley2/board_halley2.h b/bsp/x1000/drivers/board/halley2/board_halley2.h new file mode 100644 index 0000000000000000000000000000000000000000..1a477b14a8afac52614417d538a246b4266a62d6 --- /dev/null +++ b/bsp/x1000/drivers/board/halley2/board_halley2.h @@ -0,0 +1,14 @@ +#ifndef BOARD_HALLEY2_H__ +#define BOARD_HALLEY2_H__ + +#define LCD_RST_PORT GPIO_PORT_D +#define LCD_RST_PIN GPIO_Pin_0 + +#define LCD_BLPWM_PORT GPIO_PORT_C +#define LCD_BLPWM_PIN GPIO_Pin_25 + +#define LCD_BLEN_PORT GPIO_PORT_A +#define LCD_BLEN_PIN GPIO_Pin_25 + +#endif + diff --git a/bsp/x1000/drivers/board/halley2/rd_x1000_halley2_baseboard_v2_0.pdf b/bsp/x1000/drivers/board/halley2/rd_x1000_halley2_baseboard_v2_0.pdf new file mode 100644 index 0000000000000000000000000000000000000000..6e9c31f4c5f653a0de901925e9ac7ab05fb04481 Binary files /dev/null and b/bsp/x1000/drivers/board/halley2/rd_x1000_halley2_baseboard_v2_0.pdf differ diff --git a/bsp/x1000/drivers/board/halley2/rd_x1000_halley2_coreboard_v2_0.pdf b/bsp/x1000/drivers/board/halley2/rd_x1000_halley2_coreboard_v2_0.pdf new file mode 100644 index 0000000000000000000000000000000000000000..1decb4a95be04af9b67ce6e0d8f8f02633954498 Binary files /dev/null and b/bsp/x1000/drivers/board/halley2/rd_x1000_halley2_coreboard_v2_0.pdf differ diff --git a/bsp/x1000/drivers/board/halley2_fir/PD_X1000_FIR_V1.1.pdf b/bsp/x1000/drivers/board/halley2_fir/PD_X1000_FIR_V1.1.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d493cb49ee3b3d6dddc61a5da40c9229f3523c60 Binary files /dev/null and b/bsp/x1000/drivers/board/halley2_fir/PD_X1000_FIR_V1.1.pdf differ diff --git a/bsp/x1000/drivers/board/halley2_fir/board_halley2_fir.h b/bsp/x1000/drivers/board/halley2_fir/board_halley2_fir.h new file mode 100644 index 0000000000000000000000000000000000000000..663a0a342ca363f65e897523a694609d96135534 --- /dev/null +++ b/bsp/x1000/drivers/board/halley2_fir/board_halley2_fir.h @@ -0,0 +1,80 @@ +#ifndef BOARD_HALLEY2_IDELAN_H__ +#define BOARD_HALLEY2_IDELAN_H__ + +#define AUDIO_SHUTDOWN_PORT GPIO_PORT_B +#define AUDIO_SHUTDOWN_PIN GPIO_Pin_7 +#define AUDIO_SHUTDOWN_MUTE 1 + +/* + * IO LCD + */ +#define LCD_PWEN_PORT GPIO_PORT_B +#define LCD_PWEN_PIN GPIO_Pin_19 //原理图不对,实际连接到LCD_TE + +#define LCD_RST_PORT GPIO_PORT_B +#define LCD_RST_PIN GPIO_Pin_14 + +#define LCD_BL_PORT GPIO_PORT_B +#define LCD_BL_PIN GPIO_Pin_9 + +/* + * IO Touch + */ +#define TP_INT_PORT GPIO_PORT_B +#define TP_INT_PIN GPIO_Pin_11 + +#define TP_RST_PORT GPIO_PORT_B +#define TP_RST_PIN GPIO_Pin_12 + +#define TP_PWEN_PORT GPIO_PORT_B +#define TP_PWEN_PIN GPIO_Pin_15 + + +/* + * IO KeyBoard: + */ +#define KEY_WIFI_PORT GPIO_PORT_A +#define KEY_WIFI_PIN GPIO_Pin_20 + +#define KEY_BT_PORT GPIO_PORT_A +#define KEY_BT_PIN GPIO_Pin_21 + +#define KEY_VOLD_PORT GPIO_PORT_A +#define KEY_VOLD_PIN GPIO_Pin_22 + +#define KEY_VOLU_PORT GPIO_PORT_B +#define KEY_VOLU_PIN GPIO_Pin_28 + +#define KEY_WKUP_PORT GPIO_PORT_B +#define KEY_WKUP_PIN GPIO_Pin_31 + +/* + * IO Camera + */ +#define CIM_PWDN_PORT GPIO_PORT_A +#define CIM_PWDN_PIN GPIO_Pin_25 +#define CIM_RST_PORT GPIO_PORT_A +#define CIM_RST_PIN GPIO_Pin_24 +#define CIM_PWEN_PORT GPIO_PORT_A +#define CIM_PWEN_PIN GPIO_Pin_23 +/* + * IO LED Config + */ +#define LED_BT_PORT GPIO_PORT_B +#define LED_BT_PIN GPIO_Pin_6 + +#define LED_WIFI_PORT GPIO_PORT_B +#define LED_WIFI_PIN GPIO_Pin_24 + +#define LED_ZB_PORT GPIO_PORT_C +#define LED_ZB_PIN GPIO_Pin_27 + +/* + * Others + */ + +#define IO_IRQ_FG_PORT GPIO_PORT_B +#define IO_IRQ_FG_PIN GPIO_Pin_13 + + +#endif diff --git a/bsp/x1000/drivers/board/halley2_idelan/DL3223D-WIFIAUDIO-V1.0-SCH.pdf b/bsp/x1000/drivers/board/halley2_idelan/DL3223D-WIFIAUDIO-V1.0-SCH.pdf new file mode 100644 index 0000000000000000000000000000000000000000..88fe788ca30e72918e7bf230dc581c8bf4870be7 Binary files /dev/null and b/bsp/x1000/drivers/board/halley2_idelan/DL3223D-WIFIAUDIO-V1.0-SCH.pdf differ diff --git "a/bsp/x1000/drivers/board/halley2_idelan/MTF0240CMIL-06-SPEC(V4.0)-8\344\275\215\345\261\217.pdf" "b/bsp/x1000/drivers/board/halley2_idelan/MTF0240CMIL-06-SPEC(V4.0)-8\344\275\215\345\261\217.pdf" new file mode 100644 index 0000000000000000000000000000000000000000..baed15fe8134955d0c7b04e7af22590f137be5ce Binary files /dev/null and "b/bsp/x1000/drivers/board/halley2_idelan/MTF0240CMIL-06-SPEC(V4.0)-8\344\275\215\345\261\217.pdf" differ diff --git a/bsp/x1000/drivers/board/halley2_idelan/README_20160819.txt b/bsp/x1000/drivers/board/halley2_idelan/README_20160819.txt new file mode 100644 index 0000000000000000000000000000000000000000..af1be545675ea3f5efa06afed184100dca9be7ad --- /dev/null +++ b/bsp/x1000/drivers/board/halley2_idelan/README_20160819.txt @@ -0,0 +1,6 @@ +2016/08/29发布 +已知的硬件错误: +-I2S 信号分配错误 I2SDI I2SDO反了 核心板的DO是输出 Codec的DO也是输出,核心板的DO需要接到Codec的SDI0上 +-X1 12.288晶振不焊接,R13 需要焊接,核心板提供时钟(layout的时候,晶振保留) +- +-layout问题,整个板子GND走线 很多实连接,手工焊接质量不保证 diff --git a/bsp/x1000/drivers/board/halley2_idelan/board_halley2_idelan.h b/bsp/x1000/drivers/board/halley2_idelan/board_halley2_idelan.h new file mode 100644 index 0000000000000000000000000000000000000000..ad4afc081c0961ac9b59f69c9b45ce05c26200b0 --- /dev/null +++ b/bsp/x1000/drivers/board/halley2_idelan/board_halley2_idelan.h @@ -0,0 +1,5 @@ +#ifndef BOARD_HALLEY2_IDELAN_H__ +#define BOARD_HALLEY2_IDELAN_H__ + + +#endif diff --git a/bsp/x1000/drivers/board/halley2_realboard/board_halley2_readboard.h b/bsp/x1000/drivers/board/halley2_realboard/board_halley2_readboard.h new file mode 100644 index 0000000000000000000000000000000000000000..33cc57f18e8ab345ce4fd6e4908687ae0a616c78 --- /dev/null +++ b/bsp/x1000/drivers/board/halley2_realboard/board_halley2_readboard.h @@ -0,0 +1,14 @@ +#ifndef BOARD_HALLEY2_IDELAN_H__ +#define BOARD_HALLEY2_IDELAN_H__ + +#define AUDIO_SHUTDOWN_PORT GPIO_PORT_B +#define AUDIO_SHUTDOWN_PIN GPIO_Pin_6 +#define AUDIO_SHUTDOWN_MUTE 1 + +#define LCD_RST_PORT GPIO_PORT_C +#define LCD_RST_PIN GPIO_Pin_25 + +#define LCD_BL_PORT GPIO_PORT_B +#define LCD_BL_PIN GPIO_Pin_19 + +#endif diff --git a/bsp/x1000/drivers/board/halley2_realboard_v2/board_halley2_readboard_v2.h b/bsp/x1000/drivers/board/halley2_realboard_v2/board_halley2_readboard_v2.h new file mode 100644 index 0000000000000000000000000000000000000000..65ceab99a9f51728362408645e86a67193a13b82 --- /dev/null +++ b/bsp/x1000/drivers/board/halley2_realboard_v2/board_halley2_readboard_v2.h @@ -0,0 +1,61 @@ +/* + * File : board_halley2_readboard_v2.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017-01-01 Urey first version + */ +#ifndef DRIVER_BOARD_HALLEY2_REALBOARD_V2_BOARD_HALLEY2_READBOARD_V2_H_ +#define DRIVER_BOARD_HALLEY2_REALBOARD_V2_BOARD_HALLEY2_READBOARD_V2_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define AUDIO_SHUTDOWN_PORT GPIO_PORT_C +#define AUDIO_SHUTDOWN_PIN GPIO_Pin_26 +#define AUDIO_SHUTDOWN_MUTE 0 + +#define LCD_RST_PORT GPIO_PORT_C +#define LCD_RST_PIN GPIO_Pin_23 + +#define LCD_BL_PORT GPIO_PORT_D +#define LCD_BL_PIN GPIO_Pin_1 + +#define LCD_TP_INT_PORT GPIO_PORT_C +#define LCD_TP_INT_PIN GPIO_Pin_25 + +/* BLINK LED */ +#define BLINK_LED0_PORT GPIO_PORT_B +#define BLINK_LED0_PIN GPIO_Pin_9 + +#define BLINK_LED1_PORT GPIO_PORT_B +#define BLINK_LED1_PIN GPIO_Pin_8 + +#define BLINK_LED2_PORT GPIO_PORT_B +#define BLINK_LED2_PIN GPIO_Pin_13 + +#define BLINK_LED3_PORT GPIO_PORT_B +#define BLINK_LED3_PIN GPIO_Pin_11 + +#ifdef __cplusplus +} +#endif + +#endif /* DRIVER_BOARD_HALLEY2_REALBOARD_V2_BOARD_HALLEY2_READBOARD_V2_H_ */ diff --git a/bsp/x1000/drivers/board/phoenix/Ingenic Studio User Guide.docx b/bsp/x1000/drivers/board/phoenix/Ingenic Studio User Guide.docx new file mode 100644 index 0000000000000000000000000000000000000000..ff7ef2b0fab0a3f2ccb4c6daf2067788d141ab29 Binary files /dev/null and b/bsp/x1000/drivers/board/phoenix/Ingenic Studio User Guide.docx differ diff --git a/bsp/x1000/drivers/board/phoenix/JDI User Guide.docx b/bsp/x1000/drivers/board/phoenix/JDI User Guide.docx new file mode 100644 index 0000000000000000000000000000000000000000..27085345b70c0a2ffc1ceb6649e76fb681180454 Binary files /dev/null and b/bsp/x1000/drivers/board/phoenix/JDI User Guide.docx differ diff --git a/bsp/x1000/drivers/board/phoenix/RD_X1000_PHOENIX_V2.0.pdf b/bsp/x1000/drivers/board/phoenix/RD_X1000_PHOENIX_V2.0.pdf new file mode 100644 index 0000000000000000000000000000000000000000..a25c2826e6db495d475bb1bd1ab475ad422fada8 Binary files /dev/null and b/bsp/x1000/drivers/board/phoenix/RD_X1000_PHOENIX_V2.0.pdf differ diff --git a/bsp/x1000/drivers/board/phoenix/board_phoenix.h b/bsp/x1000/drivers/board/phoenix/board_phoenix.h new file mode 100644 index 0000000000000000000000000000000000000000..08ea87ae54868f239c3ba87ef6145e84c384ee55 --- /dev/null +++ b/bsp/x1000/drivers/board/phoenix/board_phoenix.h @@ -0,0 +1,4 @@ +#ifndef BOARD_HALLEY2_H__ +#define BOARD_HALLEY2_H__ + +#endif diff --git a/bsp/x1000/drivers/board/phoenix/jz-x1000.gdbinit b/bsp/x1000/drivers/board/phoenix/jz-x1000.gdbinit new file mode 100644 index 0000000000000000000000000000000000000000..1c12b9af7771cb644ff3e2ee5a39f0b4eb286594 --- /dev/null +++ b/bsp/x1000/drivers/board/phoenix/jz-x1000.gdbinit @@ -0,0 +1,11 @@ +#connect to the JDI gdb server +target remote 169.28.23.51:2823 + +#set remote write size +set remotewritesize fixed +set remotewritesize 8192 + +#load the debug image +load + +#debug begin diff --git a/bsp/x1000/drivers/board_io.c b/bsp/x1000/drivers/board_io.c new file mode 100644 index 0000000000000000000000000000000000000000..64ebfc2f322073cc265e71a7a5d6443cb8f9a172 --- /dev/null +++ b/bsp/x1000/drivers/board_io.c @@ -0,0 +1,222 @@ +#include +#include +#include + +#include "drv_gpio.h" + +static void _delay_us(rt_uint32_t ns) +{ + volatile rt_uint16_t delay; + + while(ns--) + { + delay = 200; + while(delay--); + } +} + +static void _delay_ms(rt_uint32_t ms) +{ + volatile rt_uint16_t delay; + + while(ms--) + { + _delay_us(1000); + } +} + +#if defined(RT_USING_WIFI) && (defined(WIFI_USING_AP6212) || defined(WIFI_USING_AP6181)) +/** + * PC16 WL_WAKE_HOST + * PC17 WL_REG_EN + */ +int io_AP6212(void) +{ + gpio_set_func(GPIO_PORT_C, GPIO_Pin_17, GPIO_FUNC_0); + gpio_direction_output(GPIO_PORT_C, GPIO_Pin_17, 0); + + rt_kprintf("Enable WL_REG_EN\n"); + gpio_set_value(GPIO_PORT_C, GPIO_Pin_17, 0); + rt_thread_delay(1); + gpio_set_value(GPIO_PORT_C, GPIO_Pin_17, 1); + + return 0; +} +INIT_DEVICE_EXPORT(io_AP6212); +#endif + +#if defined(RT_USING_BT) && (defined(WIFI_USING_AP6212) || defined(WIFI_USING_AP6181)) +#include +/** + * PC16 32768 clock + */ +int io_AP6212_bt(void) +{ + rtc32k_enable(); + + return 0; +} +INIT_DEVICE_EXPORT(io_AP6212_bt); +#endif + +#if defined(BOARD_CANNA) +int io_canna(void) +{ + /* PC25(1) for Audio Shutdown IO */ + gpio_set_func(GPIO_PORT_C, GPIO_Pin_25, GPIO_FUNC_1); + gpio_direction_output(GPIO_PORT_C,GPIO_Pin_25, 0); + gpio_set_value(GPIO_PORT_C,GPIO_Pin_25, 0); + + return 0; +} +INIT_DEVICE_EXPORT(io_canna); +#endif + +#if defined(BOARD_HALLEY2) +int io_halley2(void) +{ +#ifdef RT_USING_EMAC + /* PC23 for MAC_RST_N */ + gpio_set_func(GPIO_PORT_C, GPIO_Pin_23, GPIO_FUNC_0); + gpio_direction_output(GPIO_PORT_C, GPIO_Pin_23, 0); + rt_thread_delay(1); + gpio_direction_output(GPIO_PORT_C, GPIO_Pin_23, 1); + rt_thread_delay(1); +#endif + + return 0; +} +INIT_DEVICE_EXPORT(io_halley2); +#endif + +#if defined(BOARD_PHOENIX) +int io_phoenix(void) +{ + /* PB0(1) for Audio Shutdown IO */ + gpio_set_func(GPIO_PORT_B, GPIO_Pin_0, GPIO_FUNC_2); + gpio_direction_output(GPIO_PORT_B,GPIO_Pin_0, 0); + gpio_set_value(GPIO_PORT_B,GPIO_Pin_0,0); + + /* PB3 for reset EMAC PHY */ + gpio_set_func(GPIO_PORT_B, GPIO_Pin_3, GPIO_FUNC_2); + gpio_direction_output(GPIO_PORT_B, GPIO_Pin_3, 0); + rt_thread_delay(1); + gpio_direction_output(GPIO_PORT_B, GPIO_Pin_3, 1); + rt_thread_delay(1); + + return 0; +} +INIT_DEVICE_EXPORT(io_phoenix); +#endif + +#if defined(BOARD_OX) +int io_ox(void) +{ + /* PB6 for Audio Shutdown IO */ + gpio_set_func(GPIO_PORT_B, GPIO_Pin_6, GPIO_FUNC_1); + gpio_direction_output(GPIO_PORT_B,GPIO_Pin_6, 0); + gpio_set_value(GPIO_PORT_B,GPIO_Pin_6, 0); + + gpio_direction_output(GPIO_PORT_C, GPIO_Pin_25, GPIO_OUTPUT0); + rt_thread_delay(rt_tick_from_millisecond(100)); + gpio_direction_output(GPIO_PORT_C, GPIO_Pin_25, GPIO_OUTPUT1); + + /* PB19 for LCD black light */ + gpio_direction_output(GPIO_PORT_B,GPIO_Pin_19, GPIO_OUTPUT1); + +#ifdef RT_USING_EMAC + /* PC23 for MAC_RST_N */ + // gpio_set_func(GPIO_PORT_C, GPIO_Pin_23, GPIO_FUNC_0); + gpio_direction_output(GPIO_PORT_C, GPIO_Pin_23, 0); + rt_thread_delay(1); + gpio_direction_output(GPIO_PORT_C, GPIO_Pin_23, 1); + rt_thread_delay(1); +#endif + + return 0; +} +INIT_DEVICE_EXPORT(io_ox); +#endif + +#ifdef BOARD_HALLEY2_REALBOARD +int io_realboard(void) +{ + /* Audio Shutdown IO */ + gpio_direction_output(AUDIO_SHUTDOWN_PORT,AUDIO_SHUTDOWN_PIN, AUDIO_SHUTDOWN_MUTE); + gpio_set_value(AUDIO_SHUTDOWN_PORT,AUDIO_SHUTDOWN_PIN, AUDIO_SHUTDOWN_MUTE); + +#ifdef RT_USING_EMAC + gpio_set_func(GPIO_PORT_B, GPIO_Pin_7, GPIO_OUTPUT0); + gpio_set_func(GPIO_PORT_B, GPIO_Pin_8, GPIO_OUTPUT0); + gpio_set_func(GPIO_PORT_B, GPIO_Pin_9, GPIO_OUTPUT0); + gpio_set_func(GPIO_PORT_B, GPIO_Pin_10, GPIO_OUTPUT0); + gpio_set_func(GPIO_PORT_B, GPIO_Pin_11, GPIO_OUTPUT0); + gpio_set_func(GPIO_PORT_B, GPIO_Pin_12, GPIO_OUTPUT0); + gpio_set_func(GPIO_PORT_B, GPIO_Pin_13, GPIO_INPUT); + gpio_set_func(GPIO_PORT_B, GPIO_Pin_14, GPIO_INPUT); + gpio_set_func(GPIO_PORT_B, GPIO_Pin_15, GPIO_INPUT); + + /* PC23 for MAC_RST_N */ + gpio_direction_output(GPIO_PORT_C, GPIO_Pin_23, 0); + _delay_ms(100); + gpio_direction_output(GPIO_PORT_C, GPIO_Pin_23, 1); + _delay_ms(100); +#endif + return 0; +} +INIT_BOARD_EXPORT(io_realboard); +#endif /* BOARD_HALLEY2_REALBOARD_X1000 */ + +#ifdef BOARD_HALLEY2_REALBOARD_V2 +int io_realboard_v2(void) +{ + /* Audio Shutdown IO */ + gpio_direction_output(AUDIO_SHUTDOWN_PORT,AUDIO_SHUTDOWN_PIN, AUDIO_SHUTDOWN_MUTE); + gpio_set_value(AUDIO_SHUTDOWN_PORT,AUDIO_SHUTDOWN_PIN, AUDIO_SHUTDOWN_MUTE); + + /* Reset lcd,TP,... */ + gpio_direction_output(LCD_TP_INT_PORT, LCD_TP_INT_PIN,1); + _delay_ms(300); + gpio_direction_output(LCD_RST_PORT, LCD_RST_PIN,0); + _delay_ms(100); + gpio_set_value(LCD_RST_PORT, LCD_RST_PIN, 1); + + + /* LED */ + gpio_direction_output(BLINK_LED0_PORT, BLINK_LED0_PIN,1); + gpio_direction_output(BLINK_LED1_PORT, BLINK_LED1_PIN,1); + gpio_direction_output(BLINK_LED2_PORT, BLINK_LED2_PIN,1); + gpio_direction_output(BLINK_LED3_PORT, BLINK_LED3_PIN,1); + + + return 0; +} +INIT_BOARD_EXPORT(io_realboard_v2); +#endif /* BOARD_HALLEY2_REALBOARD_V2 */ + + +#ifdef BOARD_HALLEY2_FIR +int io_halley2_fir(void) +{ + /* Audio Shutdown IO */ + gpio_direction_output(AUDIO_SHUTDOWN_PORT,AUDIO_SHUTDOWN_PIN, AUDIO_SHUTDOWN_MUTE); + + /* LCD */ + rt_kprintf("lcd power enable...\n"); + gpio_direction_output(LCD_PWEN_PORT,LCD_PWEN_PIN, 0); //LCD Power Enable + gpio_direction_output(LCD_RST_PORT,LCD_RST_PIN, 0); + gpio_direction_output(LCD_BL_PORT,LCD_BL_PIN, 0); + + /* Touch */ + gpio_direction_output(TP_PWEN_PORT,TP_PWEN_PIN, 0); + gpio_direction_output(TP_RST_PORT,TP_RST_PIN, 0); + + /* LED */ + gpio_direction_output(LED_BT_PORT,LED_BT_PIN, 1); + gpio_direction_output(LED_WIFI_PORT,LED_WIFI_PIN, 1); + gpio_direction_output(LED_ZB_PORT,LED_ZB_PIN, 1); + + return 0; +} +INIT_BOARD_EXPORT(io_halley2_fir); +#endif /* BOARD_HALLEY2_FIR */ diff --git a/bsp/x1000/drivers/board_key.c b/bsp/x1000/drivers/board_key.c new file mode 100644 index 0000000000000000000000000000000000000000..f96005e5754b7ea04a5e580346bef534e9d95d62 --- /dev/null +++ b/bsp/x1000/drivers/board_key.c @@ -0,0 +1,305 @@ +/* + * File : drv_gpio_keyboard.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ + +/********************************************************************************************************* +** Include Files +*********************************************************************************************************/ +#include +#include +#include + +#include "board.h" +#include "drv_gpio.h" +#include "board_key.h" + +#ifdef RT_USING_AUDIO_PLAYER +#include +#endif + +#define KEY_DEBUG + +#ifdef KEY_DEBUG +#define KEY_DBG(...) rt_kprintf("[KEY]"),rt_kprintf(__VA_ARGS__) +#else +#define KEY_DBG(...) +#endif + +static keyboard_event_handler_t _handler = RT_NULL; + + +#if defined(BOARD_HALLEY2) +/* 4 keys + * SW1 SW2 SW3 SW5 + * Vol- Vol+ Play/Pause Mode/Config + * PA10 PA11 PB28 PB31 + */ +static struct keyboard_io_def keyboard_io_tbl[] = +{ + //Vol-/Next Song + { + GPIO_PORT_A, GPIO_Pin_10 , + KEY_NEXT, KEY_VOLDEC, + }, + + //Vol+/Prev Song + { + GPIO_PORT_A, GPIO_Pin_11 , + KEY_PREV, KEY_VOLINC, + }, + + //Play_Pause + { + GPIO_PORT_B, GPIO_Pin_28 , + KEY_UNKNOWN, KEY_PLAY_PAUSE, + }, + + //Mode/Config + { + GPIO_PORT_B, GPIO_Pin_31, + KEY_CONFIG, KEY_NETWORK_MODE, + }, +}; +#elif defined(BOARD_HALLEY2_REALBOARD) +/* 6 keys + * 11 12 21 22 31 32 + * ON/OFF MODE V+ V- BT/MUTE WIFI + */ +static struct keyboard_io_def keyboard_io_tbl[] = +{ + //ON/OFF + { + GPIO_PORT_B, GPIO_Pin_31, + KEY_UNKNOWN, KEY_PWROFF, + }, + //V+ + { + GPIO_PORT_B, GPIO_Pin_25, + KEY_UNKNOWN, KEY_VOLINC, + }, + //V- + { + GPIO_PORT_B, GPIO_Pin_2, + KEY_UNKNOWN, KEY_VOLDEC, + }, + //BT/MUTE + { + GPIO_PORT_B, GPIO_Pin_3, + KEY_SOURCE, KEY_MUTE, + }, + //WIFI + { + GPIO_PORT_B, GPIO_Pin_28, + KEY_UNKNOWN, KEY_CONFIG, + }, +}; +#elif defined(BOARD_HALLEY2_REALBOARD_V2) +struct keyboard_io_def keyboard_io_tbl[] = +{ + //ON/OFF + { + GPIO_PORT_D, GPIO_Pin_0, + KEY_UNKNOWN, KEY_UNKNOWN, + }, + //V+ + { + GPIO_PORT_B, GPIO_Pin_28, + KEY_UNKNOWN, KEY_UNKNOWN, + }, + //V- + { + GPIO_PORT_B, GPIO_Pin_31, + KEY_UNKNOWN, KEY_UNKNOWN, + }, + //WIFI config + { + GPIO_PORT_D, GPIO_Pin_2, + KEY_UNKNOWN, KEY_UNKNOWN, + }, +}; + +#else +struct keyboard_io_def keyboard_io_tbl[] = +{ + //PWRKEY KEY + { + GPIO_PORT_B, GPIO_Pin_31, + KEY_UNKNOWN, KEY_UNKNOWN + }, +}; +#endif +#define CFG_MAX_KEY_NBR sizeof(keyboard_io_tbl)/sizeof(keyboard_io_tbl[0]) + +static struct rt_mailbox* _keyMb = RT_NULL; + +void keyboard_irq_callback(void *param) +{ + KEY_DBG("%d\n", (int)param); + if (_keyMb) + { + struct keyboard_io_def* key; + int value = (int)param; + + key = &keyboard_io_tbl[value]; + if(rt_mb_send(_keyMb, (rt_uint32_t)param) == RT_EOK) + gpio_mask_irq(key->port, key->pin); + } +} + +#define KEY_EVENT_DOWN 0x01 +#define KEY_EVENT_HOLD 0x02 +#define KEY_EVENT_UP 0x04 + +#define KEY_SCAN_STEP_TIME 10 +#define KEY_SCAN_HOLD_THRESHOLD 2000 + +//Scan the single key +rt_uint8_t key_scan(struct keyboard_io_def *keyIO) +{ + static rt_uint8_t keyTrigger = 0; + static rt_uint8_t keyRelease = 0; + static rt_uint8_t keyHold = 0; + + rt_uint8_t keyValue = 0; + + //elimination buffeting + do + { + keyValue = gpio_get_value(keyIO->port,keyIO->pin); + rt_thread_delay(rt_tick_from_millisecond(KEY_SCAN_STEP_TIME)); + }while(keyValue != gpio_get_value(keyIO->port,keyIO->pin)); + + keyValue ^= 0x01; + keyTrigger = keyValue &(keyValue ^ keyHold); + keyRelease = (keyValue ^ keyTrigger ^ keyHold); + keyHold = keyValue; + +// KEY_DBG("keyValue = %x\n,keyTrigger = %x\n,keyRelese = %x\n,keyHold = %x\n",keyValue,keyTrigger,keyRelease,keyHold); + + if(keyTrigger != 0) + return KEY_EVENT_DOWN; + else if(keyHold != 0) + return KEY_EVENT_HOLD; + + return KEY_EVENT_UP; +} + +void kbd_thread(void* parameter) +{ + int keyId; + rt_uint8_t keyEvent; + rt_uint8_t keyValue; + rt_uint32_t keyHoldTime; + _keyMb = rt_mb_create("key", 4, RT_IPC_FLAG_FIFO); + + while (1) + { + if(rt_mb_recv(_keyMb, (rt_uint32_t*)&keyId, RT_TICK_PER_SECOND) != RT_EOK) + { + //if no key pressed,check power key... + keyId = 0; + } + + { + struct keyboard_io_def* key; + + // Check key ID + if(keyId >= CFG_MAX_KEY_NBR) + { + rt_kprintf("keyID error\n"); + continue; + } + + key = &keyboard_io_tbl[keyId]; + + keyEvent = key_scan(key); + /* No key input */ + if(keyEvent == KEY_EVENT_UP) + { + gpio_unmask_irq(key->port, key->pin); + continue; + } + KEY_DBG("key %d down\n", keyId); + + //Wait for key RELEASE + keyHoldTime = 0; + do + { + keyEvent = key_scan(key); + if(keyEvent == KEY_EVENT_HOLD) + { + keyHoldTime += KEY_SCAN_STEP_TIME; + + if(keyHoldTime > KEY_SCAN_HOLD_THRESHOLD) + break; + } + + } while (keyEvent != KEY_EVENT_UP); + KEY_DBG("key %d up,hold time = %dms\n", keyId,keyHoldTime); + + if(keyHoldTime > KEY_SCAN_HOLD_THRESHOLD) + keyValue = key->longKey; + else + keyValue = key->shortKey; + + //send key event + if (_handler) _handler(EVENT_KEY_DOWN | keyValue); + + //Wait for KEYUP + while (keyEvent != KEY_EVENT_UP) + { + keyEvent = key_scan(key); + rt_thread_delay(RT_TICK_PER_SECOND / 10); + } + + if (_handler) _handler(EVENT_KEY_UP | keyValue); + + gpio_unmask_irq(key->port, key->pin); + } + } +} + +void rt_hw_keyboard_set_handler(keyboard_event_handler_t handler) +{ + _handler = handler; +} + +void rt_hw_keyboard_init(void) +{ + int i; + rt_thread_t tid; + + tid = rt_thread_create("key", kbd_thread, RT_NULL, 2048, 16, 10); + if (tid) + rt_thread_startup(tid); + + /* initialize all IO for keyboard */ + for (i = 0; i < CFG_MAX_KEY_NBR; ++i) + { + gpio_set_func(keyboard_io_tbl[i].port,keyboard_io_tbl[i].pin,GPIO_INPUT_PULL | GPIO_INT_FE); + + gpio_set_irq_callback(keyboard_io_tbl[i].port,keyboard_io_tbl[i].pin,keyboard_irq_callback, (void*)i); + + gpio_unmask_irq(keyboard_io_tbl[i].port,keyboard_io_tbl[i].pin); + } +} diff --git a/bsp/x1000/drivers/board_key.h b/bsp/x1000/drivers/board_key.h new file mode 100644 index 0000000000000000000000000000000000000000..8f09bb55400a59cef35ffe1e30fd8e71b9484429 --- /dev/null +++ b/bsp/x1000/drivers/board_key.h @@ -0,0 +1,48 @@ +#ifndef BOARD_KEY_H__ +#define BOARD_KEY_H__ + +#ifndef RT_USING_AUDIO_PLAYER +enum KEY_VALUE +{ + KEY_VOLINC, + KEY_VOLDEC, + KEY_NEXT, + KEY_PREV, + + KEY_PAUSE, + KEY_PLAY, + KEY_PLAY_PAUSE, + + KEY_MUTE, + + KEY_MIC, + KEY_EQ, + KEY_MENU, + KEY_CHANNEL, + KEY_FAVORITE, + + //system shutdown, wifi config... + KEY_PWROFF, + KEY_CONFIG, + KEY_NETWORK_MODE, + + KEY_SOURCE, + KEY_UNKNOWN, +}; +#endif + +struct keyboard_io_def +{ + enum gpio_port port; + enum gpio_pin pin; + + int longKey; + int shortKey; +}; + +typedef void (*keyboard_event_handler_t)(uint32_t event); + +void rt_hw_keyboard_init(void); +void rt_hw_keyboard_set_handler(keyboard_event_handler_t handler); + +#endif diff --git a/bsp/x1000/drivers/board_led.c b/bsp/x1000/drivers/board_led.c new file mode 100644 index 0000000000000000000000000000000000000000..181aed753623f79a028074e9d792c90a9099ec54 --- /dev/null +++ b/bsp/x1000/drivers/board_led.c @@ -0,0 +1,104 @@ +/* + * File : drv_gpio_led.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2016/05/13 Urey the first version + */ + +#include +#include +#include + +#include "board.h" +#include "drv_gpio.h" + +#if 0 +#include "board_led.h" + +#if defined(BOARD_CANNA) + +#define MAX_LED_NBR 3 + +struct led_io_def led_io_tbl[MAX_LED_NBR] = +{ + //LED_POWER + { + GPIO_PORT_C, + GPIO_Pin_24 + }, + + //LED_WIFI + { + GPIO_PORT_D, + GPIO_Pin_5 + }, + + //LED_CHARGING + { + GPIO_PORT_A, + GPIO_Pin_0 + }, + +}; + +#else +#define MAX_LED_NBR 0 +struct led_io_def led_io_tbl[] = +{ + //LED_POWER + { + GPIO_PORT_B, + GPIO_Pin_6 + }, +}; +#endif + +void rt_hw_led_on(int led) +{ + if((led >= LED_LAST) || (led > MAX_LED_NBR)) + return; + + gpio_set_value(led_io_tbl[led].port,led_io_tbl[led].pin,0); +} + +void rt_hw_led_off(int led) +{ + if((led >= LED_LAST) || (led > MAX_LED_NBR)) + return; + + gpio_set_value(led_io_tbl[led].port,led_io_tbl[led].pin,1); +} + +int rt_hw_led_init(void) +{ + rt_uint8_t i; + + /* Init all IO for keyboard */ + for (i = 0; i < MAX_LED_NBR; ++i) + { + gpio_set_func(led_io_tbl[i].port,led_io_tbl[i].pin,GPIO_OUTPUT1); + } + + return 0; +} +INIT_DEVICE_EXPORT(rt_hw_led_init); + + +#endif diff --git a/bsp/x1000/drivers/board_led.h b/bsp/x1000/drivers/board_led.h new file mode 100644 index 0000000000000000000000000000000000000000..c41dabeca973850edb93cf5f79e8250547b14b3b --- /dev/null +++ b/bsp/x1000/drivers/board_led.h @@ -0,0 +1,13 @@ +#ifndef BOARD_LED_H__ +#define BOARD_LED_H__ + +struct led_io_def +{ + enum gpio_port port; + enum gpio_pin pin; +}; + +void rt_hw_led_off(int led); +void rt_hw_led_on (int led); + +#endif diff --git a/bsp/x1000/drivers/dma.c b/bsp/x1000/drivers/dma.c new file mode 100644 index 0000000000000000000000000000000000000000..9e263de2389cc61825b33365359ca8d4e0ff33bb --- /dev/null +++ b/bsp/x1000/drivers/dma.c @@ -0,0 +1,357 @@ +/* + * File : dma.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ + + +/********************************************************************************************************* +** 头文件 +*********************************************************************************************************/ +#include +#include +#include + +#include "dma.h" + + +/********************************************************************************************************* +** 全局变量 +*********************************************************************************************************/ + + +/********************************************************************************************************* +** 宏定义 +*********************************************************************************************************/ +#define DMA_DEBUG 0 +#if DMA_DEBUG +#include +#define DMA_DBG(...) rt_kprintf("[DMA]"),rt_kprintf(__VA_ARGS__) +#else +#define DMA_DBG(...) +#endif + + + +#define __DMA_CHANNEL_RESET(dmac) do { \ + if (dmac->ops && dmac->ops->reset) {\ + dmac->ops->reset(dmac); \ + } \ + } while (0) + +#define __DMA_CHANNEL_TRANS(dmac, message, ret) do { \ + if (dmac->ops && dmac->ops->trans) { \ + ret = dmac->ops->trans(dmac, message); \ + } \ + } while (0) + +#define __DMA_CHANNEL_STATUS(ch, ret) do { \ + if (dmac->ops && dmac->ops->status) {\ + ret = dmac->ops->status(dmac); \ + } \ + } while (0) + + +/********************************************************************************************************* +** 全局变量 +*********************************************************************************************************/ +struct rt_dma_channel _g_dma_chan_head; +static rt_bool_t rt_dma_init_flag = RT_FALSE; + +/********************************************************************************************************* +** 函数名称: _dma_init +** 功能描述: 初始化 DMA +** 输  入: void +** 返 回: void +** 备 注: NONE +*********************************************************************************************************/ +void _dma_init (void) +{ + _g_dma_chan_head.ch = -1; + rt_list_init(&(_g_dma_chan_head.list)); +} /* _dma_init */ + + +/********************************************************************************************************* +** 函数名称: rt_dma_drv_install +** 功能描述: DMA 通用驱动程序安装 +** 输  入: rt_uint32_t channel,RT_DMA_FUNCS* funcs,rt_size_t maxBurstBytes +** 返 回: rt_err_t +** 备 注: NONE +*********************************************************************************************************/ +rt_err_t rt_dma_drv_install(struct rt_dma_channel *dmac, struct dma_ops *ops,struct dma_config *config,void* user_data) +{ + /* 参数检查 */ + RT_ASSERT(dmac != RT_NULL); + + if(rt_dma_init_flag == RT_FALSE) + { + rt_dma_init_flag = RT_TRUE; + + _dma_init(); + } + + if(ops == RT_NULL) + { + DMA_DBG("dma param invalid.\r\n"); + + return -RT_EIO; + } + /* 挂载到通道列表 */ + rt_list_insert_after(&(_g_dma_chan_head.list),&(dmac->list)); + + dmac->ops = ops; + if(config != RT_NULL) + { + dmac->config.direction = config->direction; + dmac->config.src_addr_width = config->src_addr_width; + dmac->config.src_maxburst = config->src_maxburst; + dmac->config.dst_addr_width = config->dst_addr_width; + dmac->config.dst_maxburst = config->dst_maxburst; + } + + dmac->user_data = user_data; + rt_memset(dmac->msg_list,0,RT_DMA_MAX_NODES * sizeof(struct dma_message)); + __DMA_CHANNEL_RESET(dmac); + return RT_EOK; +} + +struct rt_dma_channel *rt_dma_get_channel(int id) +{ + struct rt_dma_channel *dmac; + struct rt_list_node *node; + + for (node = _g_dma_chan_head.list.next; node != &(_g_dma_chan_head.list); node = node->next) + { + dmac = rt_list_entry(node, struct rt_dma_channel, list); + + if(dmac->ch == id) + return dmac; + } + + return RT_NULL; +} +// +///********************************************************************************************************* +//** 函数名称: rt_dma_flush +//** 功能描述: 删除所有被延迟处理的传输请求 (不调用回调函数) +//** 输  入: rt_uint32_t channel +//** 返 回: rt_err_t +//** 备 注: NONE +//*********************************************************************************************************/ +//rt_err_t rt_dma_flush (struct rt_dma_channel *dmac) +//{ +// rt_size_t data_size; +// struct dma_message *last_message,*message; +// rt_uint16_t next_index; +// /* 参数检查 */ +// RT_ASSERT(dmac != RT_NULL); +// +// +// next_index = dmac->get_index + 1; +// if(next_index >= RT_DMA_MAX_NODES) +// next_index = 0; +// +// +//// while (rt_data_queue_pop(&(dmac->tmsg_queue),(const void **)&message, &data_size, 0) == RT_EOK) +//// { +//// /* 清除 DMA消息 */ +////// if(message->release_cb != RT_NULL) +////// message->release_cb(dmac,message); +//// } +// +// __DMA_CHANNEL_RESET(dmac); +// +//// dmac->tmsg_actived = RT_FALSE; +// return RT_EOK; +//} + +/********************************************************************************************************* +** 函数名称: rt_dma_trans_message +** 功能描述: 添加 一个DMA请求 +** 输  入: rt_uint32_t channel DMA_MSG *pMsg +** 返 回: rt_err_t +** 备 注: NONE +*********************************************************************************************************/ +rt_err_t rt_dma_trans_message (struct rt_dma_channel *dmac,struct dma_message* message) +{ + rt_base_t level; + rt_err_t result; + rt_uint16_t next_index; + struct dma_message *msg_node; + /* 参数检查 */ + RT_ASSERT(dmac != RT_NULL); + RT_ASSERT(message != RT_NULL); + RT_ASSERT(message->t_size <= (64 * 1024)); + + if(message->t_size == 0) + { + if (dmac->complete != RT_NULL) + { + dmac->complete(dmac, message); + } + return RT_EOK; + } + + //判断传输队列是否满 + next_index = dmac->put_index + 1; + if(next_index >= RT_DMA_MAX_NODES) + next_index = 0; + if(next_index == dmac->get_index) + return -RT_ENOMEM; + + level = rt_hw_interrupt_disable(); + + msg_node = &(dmac->msg_list[dmac->put_index]); + dmac->put_index = next_index; + + //保存message + rt_memcpy(msg_node,message,sizeof(struct dma_message)); + + next_index = dmac->get_index + 1; + if(next_index >= RT_DMA_MAX_NODES) + next_index = 0; + /* check message list whether is empty */ + if(next_index == dmac->put_index) + { + rt_hw_interrupt_enable(level); + /* Make a DMA transfer */ + if(dmac->start != RT_NULL) + dmac->start(dmac,message); + + do{ + int ret; + __DMA_CHANNEL_TRANS(dmac, message, ret); /* 初始化传输诸元 */ + (void)ret; + } while (0); + } + else + { + rt_hw_interrupt_enable(level); + } + + return RT_EOK; +} + +/********************************************************************************************************* +** 函数名称: rt_dma_configture +** 功能描述: DMA 通道配置 +** 输  入: struct rt_dma_channel *dmac,struct dma_config *config +** 返 回: rt_err_t +** 备 注: NONE +*********************************************************************************************************/ +rt_err_t rt_dma_configture (struct rt_dma_channel *dmac,struct dma_config *config) +{ + /* 参数检查 */ + RT_ASSERT(dmac != RT_NULL); + RT_ASSERT(config != RT_NULL); + + dmac->config.direction = config->direction; + dmac->config.src_addr_width = config->src_addr_width; + dmac->config.src_maxburst = config->src_maxburst; + dmac->config.dst_addr_width = config->dst_addr_width; + dmac->config.dst_maxburst = config->dst_maxburst; + + __DMA_CHANNEL_RESET(dmac); + + return RT_EOK; +} /* rt_dma_configture */ + +/********************************************************************************************************* +** 函数名称: rt_dma_get_current_message +** 功能描述: DMA 获取当前传输的消息句柄 +** 输  入: struct rt_dma_channel *dmac +** 返 回: struct dma_message * +** 备 注: NONE +*********************************************************************************************************/ +struct dma_message * rt_dma_get_current_message (struct rt_dma_channel *dmac) +{ + rt_base_t level; + struct dma_message *message; + + level = rt_hw_interrupt_disable(); + + message = &(dmac->msg_list[dmac->get_index]); + + rt_hw_interrupt_enable(level); + return message; +} /* rt_dma_get_current_message */ + +/********************************************************************************************************* +** 函数名称: rt_dma_contex_service +** 功能描述: DMA 中断服务 +** 输  入: rt_uint32_t channel +** 返 回: rt_err_t +** 备 注: global +*********************************************************************************************************/ +rt_err_t rt_dma_contex_service (struct rt_dma_channel *dmac,rt_uint32_t event) +{ + rt_base_t level; + rt_size_t data_size; + struct dma_message *last_message,*message; + rt_uint16_t next_index; + + /* 参数检查 */ + RT_ASSERT(dmac != RT_NULL); + switch (event) + { + case RT_DMA_EVENT_COMPLETE: + next_index = dmac->get_index + 1; + if(next_index >= RT_DMA_MAX_NODES) + next_index = 0; + + level = rt_hw_interrupt_disable(); + /* 优先发送 缓冲区中的消息 */ + last_message = &(dmac->msg_list[dmac->get_index]); + dmac->get_index = next_index; + if(dmac->get_index != dmac->put_index) + { + /* 队列中有消息未发送,优先处理 */ + message = &(dmac->msg_list[dmac->get_index]); + + rt_hw_interrupt_enable(level); + /* Make a DMA transfer */ + if(dmac->start != RT_NULL) + dmac->start(dmac,message); + + do{ + int ret; + __DMA_CHANNEL_TRANS(dmac, message, ret); /* 初始化传输诸元 */ + (void)ret; + } while (0); + } + else + { + rt_hw_interrupt_enable(level); + } + + /* 处理上一个消息的回调函数 */ + if (dmac->complete != RT_NULL) + { + dmac->complete(dmac, last_message); + } + break; + default: + break; + } + + return RT_EOK; +} diff --git a/bsp/x1000/drivers/dma.h b/bsp/x1000/drivers/dma.h new file mode 100644 index 0000000000000000000000000000000000000000..14e420004d5142a31f3d0b14863cb7717811a390 --- /dev/null +++ b/bsp/x1000/drivers/dma.h @@ -0,0 +1,155 @@ +/* + * File : dma.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ + +#ifndef _DMA_H_ +#define _DMA_H_ +/********************************************************************************************************* +** 头文件 +*********************************************************************************************************/ +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif +#define RT_DMA_CHANNEL(n) (n) +#ifndef RT_DMA_MAX_NODES +# define RT_DMA_MAX_NODES 8 +#endif + +/********************************************************************************************************* +** DMA 状态定义 +*********************************************************************************************************/ +#define RT_DMA_STATUS_IDLE 0 /* DMA 处于空闲模式 */ +#define RT_DMA_STATUS_BUSY 1 /* DMA 处于正在工作 */ +#define RT_DMA_STATUS_ERROR 2 /* DMA 处于错误状态 */ + +/********************************************************************************************************* +** DMA 地址方向定义 +*********************************************************************************************************/ +#define RT_DMA_ADDR_INC 0 /* 地址增长方式 */ +#define RT_DMA_ADDR_FIX 1 /* 地址不变 */ +#define RT_DMA_ADDR_DEC 2 /* 地址减少方式 */ + +/********************************************************************************************************* +** DMA 传输方向定义 +*********************************************************************************************************/ +#define RT_DMA_MEM_TO_MEM 0 +#define RT_DMA_MEM_TO_DEV 1 +#define RT_DMA_DEV_TO_MEM 2 +#define RT_DMA_DEV_TO_DEV 3 +#define RT_DMA_TRANS_NONE 4 + +/********************************************************************************************************* +** DMA 总线宽度 +*********************************************************************************************************/ +#define RT_DMA_BUSWIDTH_UNDEFINED 0 +#define RT_DMA_BUSWIDTH_1_BYTE 1 +#define RT_DMA_BUSWIDTH_2_BYTES 2 +#define RT_DMA_BUSWIDTH_4_BYTES 4 +#define RT_DMA_BUSWIDTH_8_BYTES 8 + +/********************************************************************************************************* +** DMA 传输 时间 +*********************************************************************************************************/ +#define RT_DMA_EVENT_COMPLETE 0x01 +#define RT_DMA_EVENT_ERROR 0x02 + + +/********************************************************************************************************* +** 数据结构 +*********************************************************************************************************/ +struct rt_dma_channel; +struct dma_message; +struct dma_config; +struct dma_ops +{ + void (*reset)(struct rt_dma_channel *dmac); + rt_size_t (*trans)(struct rt_dma_channel *dmac,struct dma_message *message); + int (*status)(struct rt_dma_channel *dmac); + int (*configure)(struct rt_dma_channel *dmac,struct dma_config *config); +}; + +struct dma_message +{ + rt_uint8_t *src_addr; /* 源端缓冲区地址 */ + rt_uint8_t *dst_addr; /* 目的端缓冲区地址 */ + rt_uint8_t src_option; /* 源端地址方向控制 */ + rt_uint8_t dst_option; /* 目的地址方向控制 */ + rt_size_t t_size; /* 传输的字节数 */ + + rt_uint32_t t_mode; /* 传输模式, 自定义 */ + + void (*complete_cb)(void *data,void *pbuf); + void *complete_arg; +}; + + +struct dma_config +{ + rt_uint32_t direction; + rt_uint32_t src_addr_width; + rt_uint32_t dst_addr_width; + rt_uint32_t src_maxburst; + rt_uint32_t dst_maxburst; +}; + +struct rt_dma_channel +{ + int ch; + rt_list_t list; /* channel list */ + + struct dma_config config; + struct dma_ops *ops; + + struct dma_message msg_list[RT_DMA_MAX_NODES]; + rt_uint16_t get_index; + rt_uint16_t put_index; + + void (*start)(struct rt_dma_channel *dmac,struct dma_message *msg); /* 启动传输 回调函数 */ + void (*complete)(struct rt_dma_channel *dmac,struct dma_message *msg); /* 传输完成 回调函数 */ + + void *user_data; /* 自定义数据 */ +}; + + +/********************************************************************************************************* +** 函数申明 +*********************************************************************************************************/ +rt_err_t rt_dma_drv_install(struct rt_dma_channel *dmac, struct dma_ops *ops,struct dma_config *config,void* user_data); +struct rt_dma_channel *rt_dma_get_channel(int id); +struct dma_message *rt_dma_get_current_message (struct rt_dma_channel *dmac); +rt_err_t rt_dma_reset (struct rt_dma_channel *dmac); +rt_err_t rt_dma_trans_message (struct rt_dma_channel *dmac,struct dma_message* message); +rt_err_t rt_dma_configture (struct rt_dma_channel *dmac,struct dma_config *config); +rt_err_t rt_dma_contex_service (struct rt_dma_channel *dmac,rt_uint32_t event); + + + +#ifdef __cplusplus +} +#endif + +#endif /* _DMA_H_ */ diff --git a/bsp/x1000/driver/drv_clock.c b/bsp/x1000/drivers/drv_clock.c similarity index 94% rename from bsp/x1000/driver/drv_clock.c rename to bsp/x1000/drivers/drv_clock.c index a3110b1be49ef376007af852c251ca8b42e784de..d162ebc4703e019d0a4f58c8bf8a1705edbf8cc5 100644 --- a/bsp/x1000/driver/drv_clock.c +++ b/bsp/x1000/drivers/drv_clock.c @@ -21,16 +21,16 @@ * Date Author Notes * 2015-11-19 Urey the first version */ +#include #include #include #include -#include - #include "board.h" #include "drv_clock.h" + #define DEBUG 0 #if DEBUG #define PRINT(...) rt_kprintf(__VA_ARGS__) @@ -834,8 +834,42 @@ const struct clk_selectors audio_selector[] = [SELECTOR_AUDIO].route = {CLK(EXT1),CLK(SCLKA),CLK(EXT1),CLK(MPLL)}, #undef CLK }; -static int audio_div_apll[64]; -static int audio_div_mpll[64]; +static int audio_div_apll[64] = +{ + 8000 , 1 , 126000 , + 11025 , 2 , 182857 , + 12000 , 1 , 84000 , + 16000 , 1 , 63000 , + 22050 , 4 , 182857 , + 24000 , 1 , 42000 , + 32000 , 1 , 31500 , + 44100 , 7 , 160000 , + 48000 , 1 , 21000 , + 88200 , 21 , 240000 , + 96000 , 1 , 10500 , + 176400 , 42 , 240000 , + 192000 , 1 , 5250 , + + 0 +}; +static int audio_div_mpll[64] = +{ + 8000 , 1 , 75000 , + 11025 , 4 , 217687 , + 12000 , 1 , 50000 , + 16000 , 1 , 37500 , + 22050 , 8 , 217687 , + 24000 , 1 , 25000 , + 32000 , 1 , 18750 , + 44100 , 16 , 217687 , + 48000 , 1 , 12500 , + 88200 , 25 , 170068 , + 96000 , 1 , 6250 , + 176400 , 75 , 255102 , + 192000 , 1 , 3125 , + + 0 +}; struct cgu_audio_clk { @@ -920,13 +954,14 @@ static int get_div_val(int max1,int max2,int machval, int* res1, int* res2) *res2 = tmp2; return 0; } -static int cgu_audio_calculate_set_rate(struct clk* clk, uint32_t rate, uint32_t pid){ + +static int cgu_audio_calculate_set_rate(struct clk* clk, uint32_t rate, uint32_t pid) +{ int i,m,n,d,sync,tmp_val,d_max,sync_max; int no = CLK_CGU_AUDIO_NO(clk->flags); int n_max = cgu_audio_clks[no].maskn >> cgu_audio_clks[no].bitn; int *audio_div; - if(pid == CLK_ID_MPLL) { audio_div = (int*)audio_div_mpll; @@ -946,7 +981,8 @@ static int cgu_audio_calculate_set_rate(struct clk* clk, uint32_t rate, uint32_t PRINT("cgu aduio set rate err!\n"); return -1; } - else{ + else + { m = audio_div[i+1]; if(no == CGU_AUDIO_I2S) { @@ -954,7 +990,7 @@ static int cgu_audio_calculate_set_rate(struct clk* clk, uint32_t rate, uint32_t m*=2; #endif d_max = 0x1ff; - tmp_val = audio_div[i+2]/64; + tmp_val = audio_div[i + 2] / 64; if (tmp_val > n_max) { if (get_div_val(n_max, d_max, tmp_val, &n, &d)) @@ -962,8 +998,8 @@ static int cgu_audio_calculate_set_rate(struct clk* clk, uint32_t rate, uint32_t } else { - n = tmp_val; - d = 1; + n = tmp_val / 4; + d = 4; } tmp_val = cpm_inl(cgu_audio_clks[no].off)&(~(cgu_audio_clks[no].maskm|cgu_audio_clks[no].maskn)); tmp_val |= (m<parent) == CLK_ID_EXT1) - cgu_audio_set_parent(clk,get_clk_from_id(CLK_ID_MPLL)); - clk->parent = get_clk_from_id(CLK_ID_MPLL); + cgu_audio_set_parent(clk,get_clk_from_id(CLK_ID_SCLKA)); + + cgu_audio_calculate_set_rate(clk,rate,CLK_ID_SCLKA); + + clk->parent = get_clk_from_id(CLK_ID_SCLKA); } return 0; } @@ -1124,9 +1163,6 @@ void init_cgu_audio_clk(struct clk *clk) { int no,id,tmp_val; - rt_memcpy(audio_div_apll,(void*)(0xf4000000),256); - rt_memcpy(audio_div_mpll,(void*)(0xf4000000)+256,256); - if (clk->flags & CLK_FLG_PARENT) { id = CLK_PARENT(clk->flags); @@ -1461,3 +1497,61 @@ int init_all_clk(void) return 0; } INIT_BOARD_EXPORT(init_all_clk); + +#ifdef RT_USING_FINSH +#include +#endif + +int clk_dump(int argc, char** argv) +{ + // dump = 1; + rt_kprintf("CCLK:%luMHz L2CLK:%luMhz H0CLK:%luMHz H2CLK:%luMhz PCLK:%luMhz\n", + clk_srcs[CLK_ID_CCLK].rate/1000/1000, + clk_srcs[CLK_ID_L2CLK].rate/1000/1000, + clk_srcs[CLK_ID_H0CLK].rate/1000/1000, + clk_srcs[CLK_ID_H2CLK].rate/1000/1000, + clk_srcs[CLK_ID_PCLK].rate/1000/1000); + + return 0; +} +MSH_CMD_EXPORT(clk_dump, dump clock debug log); + +int clk(int argc, char**argv) +{ + uint32_t value; + + value = cpm_inl(CPM_CLKGR); + rt_kprintf("CLKGR = 0x%08x\n", value); + + value &= ~(1 << 14); + cpm_outl(value, CPM_CLKGR); + + value = cpm_inl(CPM_CLKGR); + rt_kprintf("CLKGR = 0x%08x\n", value); + + return 0; +} +MSH_CMD_EXPORT(clk, clock information dump); + +int uart0_clk(void) +{ + uint32_t value; + + value = cpm_inl(CPM_CLKGR); + value &= ~(1 << 14); + cpm_outl(value, CPM_CLKGR); + + return 0; +} + +int uart1_clk(void) +{ + uint32_t value; + + value = cpm_inl(CPM_CLKGR); + value &= ~(1 << 15); + cpm_outl(value, CPM_CLKGR); + + return 0; +} + diff --git a/bsp/x1000/driver/drv_clock.h b/bsp/x1000/drivers/drv_clock.h similarity index 62% rename from bsp/x1000/driver/drv_clock.h rename to bsp/x1000/drivers/drv_clock.h index 90514c50df94527f21da5a02dd5e8f23464cb8c3..318ac488759d7cae2ea999ff0f6d35721c9808c8 100644 --- a/bsp/x1000/driver/drv_clock.h +++ b/bsp/x1000/drivers/drv_clock.h @@ -27,66 +27,6 @@ #include "board.h" -#define CPM_CPCCR (0x00) -#define CPM_CPCSR (0xd4) - -#define CPM_DDRCDR (0x2c) -#define CPM_I2SCDR (0x60) -#define CPM_I2SCDR1 (0x70) -#define CPM_LPCDR (0x64) -#define CPM_MSC0CDR (0x68) -#define CPM_MSC1CDR (0xa4) -#define CPM_USBCDR (0x50) -#define CPM_MACCDR (0x54) -#define CPM_UHCCDR (0x6c) -#define CPM_SFCCDR (0x74) -#define CPM_CIMCDR (0x7c) -#define CPM_PCMCDR (0x84) -#define CPM_PCMCDR1 (0xe0) -#define CPM_MPHYC (0xe8) - -#define CPM_INTR (0xb0) -#define CPM_INTRE (0xb4) -#define CPM_DRCG (0xd0) -#define CPM_CPSPPR (0x38) -#define CPM_CPPSR (0x34) - -#define CPM_USBPCR (0x3c) -#define CPM_USBRDT (0x40) -#define CPM_USBVBFIL (0x44) -#define CPM_USBPCR1 (0x48) - -#define CPM_CPAPCR (0x10) -#define CPM_CPMPCR (0x14) - -#define CPM_LCR (0x04) -#define CPM_PSWC0ST (0x90) -#define CPM_PSWC1ST (0x94) -#define CPM_PSWC2ST (0x98) -#define CPM_PSWC3ST (0x9c) -#define CPM_CLKGR (0x20) -#define CPM_MESTSEL (0xec) -#define CPM_SRBC (0xc4) -#define CPM_ERNG (0xd8) -#define CPM_RNG (0xdc) -#define CPM_SLBC (0xc8) -#define CPM_SLPC (0xcc) -#define CPM_OPCR (0x24) -#define CPM_RSR (0x08) - -#define LCR_LPM_MASK (0x3) -#define LCR_LPM_SLEEP (0x1) - -#define OPCR_ERCS (0x1<<2) -#define OPCR_PD (0x1<<3) -#define OPCR_IDLE (0x1<<31) - -#define cpm_inl(off) readl(CPM_BASE + (off)) -#define cpm_outl(val,off) writel(val, CPM_BASE + (off)) -#define cpm_test_bit(bit,off) (cpm_inl(off) & 0x1<<(bit)) -#define cpm_set_bit(bit,off) (cpm_outl((cpm_inl(off) | 0x1<<(bit)),off)) -#define cpm_clear_bit(bit,off) (cpm_outl(cpm_inl(off) & ~(0x1 << bit), off)) - #define I2S_PRI_DIV 0xb0020030 #define PCM_PRI_DIV 0xb0030014 diff --git a/bsp/x1000/drivers/drv_dma.c b/bsp/x1000/drivers/drv_dma.c new file mode 100644 index 0000000000000000000000000000000000000000..88cc1f64e957b3e64aa07a76e5d435213c4724ad --- /dev/null +++ b/bsp/x1000/drivers/drv_dma.c @@ -0,0 +1,537 @@ +/* + * File : drv_dma.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ + +/********************************************************************************************************* +** 头文件 +*********************************************************************************************************/ +#include +#include +#include +#include +#include + +#include + +#include "board.h" +#include "drv_clock.h" +#include "drv_dma.h" + +#define JZDMA_DEBUG 0 +#if JZDMA_DEBUG +#include +#define JZDMA_DBG(...) rt_kprintf(__VA_ARGS__) +#else +#define JZDMA_DBG(...) +#endif + +/* 全局变量 */ +static struct jzdma_master _g_jzdma_master; +static struct rt_dma_channel _g_rt_dma_channel[NR_DMA_CHANNELS]; + +/********************************************************************************************************* +** 内联函数 +*********************************************************************************************************/ +const static char dcm_tsz[7] = { 1, 2, 0, 0, 3, 4, 5 }; + +rt_inline int _fls(int x) +{ + __asm__("clz %0, %1" : "=r" (x) : "r" (x)); + + return 32 - x; +} +static inline int ffs(int word) +{ + if (!word) + return 0; + + return _fls(word & -word); +} + +static inline uint16_t get_max_tsz(uint32_t val, uint32_t *dcmp) +{ + + int ord; + + ord = ffs(val) - 1; + if (ord < 0) + ord = 0; + else if (ord > 6) + ord = 6; + + *dcmp &= ~DCM_TSZ_MSK; + *dcmp |= dcm_tsz[ord] << DCM_TSZ_SHF; + +// rt_kprintf("dcmp = %x\n",*dcmp); + + /* if tsz == 8, set it to 4 */ + return ord == 3 ? 4 : 1 << ord; +} + + +static void jzdma_mcu_reset(struct jzdma_master *master) +{ + uint32_t dmcs; + dmcs = readl(master->base + DMCS); + dmcs |= 0x1; + writel(dmcs, master->base + DMCS); +} + +static uint32_t jzdma_get_current_trans_addr(struct jzdma_channel *jz_dmac, + uint32_t* dst_addr, + uint32_t* src_addr, + uint32_t direction) +{ + uint32_t ret_val = 0; + + if (jz_dmac->status == STAT_STOPED || jz_dmac->status == STAT_PREPED) + return 0; + + if (direction == RT_DMA_MEM_TO_DEV) + { + ret_val = readl(jz_dmac->iomem + CH_DSA); + if (src_addr) + *src_addr = ret_val; + if (dst_addr) + *dst_addr = readl(jz_dmac->iomem + CH_DTA); + } + else if (direction == RT_DMA_DEV_TO_MEM) + { + ret_val = readl(jz_dmac->iomem + CH_DTA); + if (dst_addr) + *dst_addr = ret_val; + if (src_addr) + *src_addr = readl(jz_dmac->iomem + CH_DSA); + } + else if (direction == RT_DMA_MEM_TO_MEM) + { + if (dst_addr) + *dst_addr = readl(jz_dmac->iomem + CH_DTA); + if (src_addr) + *src_addr = readl(jz_dmac->iomem + CH_DSA); + } + + return ret_val; +} + + +int jzdma_funcs_status(struct rt_dma_channel *dmac) +{ + struct jzdma_channel *jz_dmac; + + RT_ASSERT(dmac != RT_NULL); + jz_dmac = (struct jzdma_channel *)dmac->user_data; + + switch (jz_dmac->status) + { + case STAT_STOPED: + return RT_DMA_STATUS_IDLE; + break; + default: + break; + } + + return RT_DMA_STATUS_BUSY; +} + + +void jzdma_funcs_reset(struct rt_dma_channel *rt_dmac) +{ + struct jzdma_channel *jz_dmac; + + RT_ASSERT(rt_dmac != RT_NULL); + jz_dmac = (struct jzdma_channel *)rt_dmac->user_data; + /* 终止当前传输 */ + jz_dmac->status = STAT_STOPED; + jz_dmac->desc_nr = 0; + + /* clear dma status */ + writel(0, jz_dmac->iomem + CH_DCS); + + /* 重新设置参数 */ + switch (rt_dmac->config.direction) + { + case RT_DMA_MEM_TO_DEV: + /* MEM_TO_DEV ,按照设备的地址宽度设置DCM */ + switch(rt_dmac->config.dst_addr_width) + { + case RT_DMA_BUSWIDTH_1_BYTE: + jz_dmac->desc.dcm |= DCM_SP_8 | DCM_DP_8; + break; + case RT_DMA_BUSWIDTH_2_BYTES: + jz_dmac->desc.dcm |= DCM_SP_16 | DCM_DP_16; + break; + case RT_DMA_BUSWIDTH_4_BYTES: + jz_dmac->desc.dcm &= ~(DCM_SP_32 | DCM_DP_32); + break; + default: + JZDMA_DBG("bus width error. \r\n"); + return; + } + + break; + default: + /* 其他方式 按照源地址宽度设置 DCM */ + switch(rt_dmac->config.src_addr_width) + { + case RT_DMA_BUSWIDTH_1_BYTE: + jz_dmac->desc.dcm |= DCM_SP_8 | DCM_DP_8; + break; + case RT_DMA_BUSWIDTH_2_BYTES: + jz_dmac->desc.dcm |= DCM_SP_16 | DCM_DP_16; + break; + case RT_DMA_BUSWIDTH_4_BYTES: + jz_dmac->desc.dcm &= ~(DCM_SP_32 | DCM_DP_32); + break; + default: + JZDMA_DBG("bus width error. \r\n"); + return; + } + break; + } + return; +} + +rt_size_t jzdma_funcs_transfer(struct rt_dma_channel *rt_dmac , struct dma_message *message) +{ + struct jzdma_channel *jz_dmac; + uint32_t tsz; + + RT_ASSERT(rt_dmac != RT_NULL); + RT_ASSERT(message != RT_NULL); + + jz_dmac = (struct jzdma_channel *)rt_dmac->user_data; + + if(jz_dmac->status == STAT_RUNNING) + return -RT_EBUSY; + /* 清除硬件寄存器 */ +// writel(0, jz_dmac->iomem + CH_DCM); +// writel(0, jz_dmac->iomem + CH_DCS); + + /* clear dma status */ + writel(0, jz_dmac->iomem + CH_DCS); + + + //刷新cache + switch(rt_dmac->config.direction) + { + case RT_DMA_MEM_TO_DEV: + case RT_DMA_MEM_TO_MEM: + rt_hw_dcache_flush_range((rt_ubase_t)(message->src_addr),message->t_size); + break; + + default: + break; + } +// /* 重新设置参数 */ +// switch (rt_dmac->config.direction) +// { +// case RT_DMA_MEM_TO_DEV: +// /* MEM_TO_DEV ,按照设备的地址宽度设置DCM */ +// switch(rt_dmac->config.dst_addr_width) +// { +// case RT_DMA_BUSWIDTH_1_BYTE: +// jz_dmac->desc.dcm |= DCM_SP_8 | DCM_DP_8; +// break; +// case RT_DMA_BUSWIDTH_2_BYTES: +// jz_dmac->desc.dcm |= DCM_SP_16 | DCM_DP_16; +// break; +// case RT_DMA_BUSWIDTH_4_BYTES: +// jz_dmac->desc.dcm &= ~(DCM_SP_32 | DCM_DP_32); +// break; +// default: +// JZDMA_DBG("bus width error. \r\n"); +// return -1; +// } +// +// break; +// default: +// /* 其他方式 按照源地址宽度设置 DCM */ +// switch(rt_dmac->config.src_addr_width) +// { +// case RT_DMA_BUSWIDTH_1_BYTE: +// jz_dmac->desc.dcm |= DCM_SP_8 | DCM_DP_8; +// break; +// case RT_DMA_BUSWIDTH_2_BYTES: +// jz_dmac->desc.dcm |= DCM_SP_16 | DCM_DP_16; +// break; +// case RT_DMA_BUSWIDTH_4_BYTES: +// jz_dmac->desc.dcm &= ~(DCM_SP_32 | DCM_DP_32); +// break; +// default: +// JZDMA_DBG("bus width error. \r\n"); +// return 0; +// } +// break; +// } + + /* clear LINK bit when issue pending */ + jz_dmac->desc.dcm |= DCM_TIE; + /* Disable desc link */ + jz_dmac->desc.dcm &= ~DCM_LINK; + + /* 识别传输地址控制 */ + switch(message->src_option) + { + case RT_DMA_ADDR_INC: + jz_dmac->desc.dcm |= DCM_SAI; + break; + case RT_DMA_ADDR_FIX: + jz_dmac->desc.dcm &= ~DCM_SAI; + break; + default: + return -RT_EIO; + } + + switch(message->dst_option) + { + case RT_DMA_ADDR_INC: + jz_dmac->desc.dcm |= DCM_DAI; + break; + case RT_DMA_ADDR_FIX: + jz_dmac->desc.dcm &= ~DCM_DAI; + break; + default: + return -RT_EIO; + } + + /* 设置TSZ */ + if(rt_dmac->ch == 1) + { + /* + * for special channel1 tsz = 7 (auto) + */ + jz_dmac->desc.dcm |= 7 << 8; + tsz = message->t_size; + } + else + { + if(rt_dmac->config.direction == RT_DMA_MEM_TO_DEV) + { + tsz = get_max_tsz((uint32_t)(message->src_addr) | message->t_size | rt_dmac->config.dst_maxburst, &jz_dmac->desc.dcm); + tsz = message->t_size / tsz; + } + else + { + tsz = get_max_tsz((uint32_t)(message->dst_addr) | message->t_size | rt_dmac->config.src_maxburst, &jz_dmac->desc.dcm); + tsz = message->t_size / tsz; + } + } + jz_dmac->desc.dsa = (uint32_t)(message->src_addr) & 0x1FFFFFFF; + JZDMA_DBG("dsa = %x\n",jz_dmac->desc.dsa); + jz_dmac->desc.dta = (uint32_t)(message->dst_addr) & 0x1FFFFFFF; + JZDMA_DBG("dta = %x\n",jz_dmac->desc.dta); + jz_dmac->desc.dtc = tsz; + JZDMA_DBG("dtc = %x\n",jz_dmac->desc.dtc); +// jz_dmac->desc.drt = jz_dmac->type; + jz_dmac->desc.drt = (uint32_t)message->t_mode; + JZDMA_DBG("drt = %x\n",jz_dmac->desc.drt); + jz_dmac->desc.sd = 0; + JZDMA_DBG("dcm = %x\n",jz_dmac->desc.dcm); + + /* I don't want to use 8-word descriptors */ + writel(DCS_NDES,jz_dmac->iomem + CH_DCS); + + /* Update DMA Channel Register */ + writel(jz_dmac->desc.dsa, jz_dmac->iomem + CH_DSA); + writel(jz_dmac->desc.dta, jz_dmac->iomem + CH_DTA); + writel(jz_dmac->desc.dtc, jz_dmac->iomem + CH_DTC); + writel(jz_dmac->desc.drt, jz_dmac->iomem + CH_DRT); + + jz_dmac->status = STAT_RUNNING; + jz_dmac->desc.dcm &= ~DCM_LINK; + jz_dmac->desc.dcm |= DCM_TIE; + writel(jz_dmac->desc.dcm, jz_dmac->iomem + CH_DCM); + + /* DCS.CTE = 1 */ + writel(readl(jz_dmac->iomem + CH_DCS) | DCS_CTE,(jz_dmac->iomem + CH_DCS)); + + return message->t_size; +} + +static void jzdma_int_handler(int vector,void *param) +{ + struct jzdma_master *master = &_g_jzdma_master; + uint32_t pending,dcs; + int i; + + pending = readl(master->base + DIRQP); + + for (i = 0; i < NR_DMA_CHANNELS; i++) + { + struct rt_dma_channel *rt_dmac = &_g_rt_dma_channel[i]; + struct jzdma_channel *jz_dmac = (struct jzdma_channel *)rt_dmac->user_data; + + if (!(pending & (1 << i))) + continue; + + dcs = readl(jz_dmac->iomem + CH_DCS); + jz_dmac->dcs_saved = dcs; + + writel(0, jz_dmac->iomem + CH_DCS); + if (jz_dmac->status != STAT_RUNNING) + continue; + + /* Address Error. */ + if(dcs & DCS_AR) + { + JZDMA_DBG("Addr Error: DCS%d=%lx\n",i,dcs); + + rt_dma_contex_service(rt_dmac,RT_DMA_EVENT_ERROR); + } + + /* DMA halt */ + if (dcs & DCS_HLT) + { + JZDMA_DBG("DMA Halt: DCS%d=%lx\n", i, dcs); + } + + /* DMA 传输已完成 */ + if (dcs & DCS_TT) + { + jz_dmac->status = STAT_STOPED; + JZDMA_DBG("DMA CH%d Over\n",i); + + //刷新cache + switch(rt_dmac->config.direction) + { + case RT_DMA_DEV_TO_MEM: + case RT_DMA_MEM_TO_MEM: + { + struct dma_message *message; + message = rt_dma_get_current_message(rt_dmac); + if(message) + { +// r4k_dcache_inv((rt_ubase_t)(message->dst_addr),message->t_size); + rt_hw_dcache_invalidate_range((rt_ubase_t)(message->dst_addr),message->t_size); + } + } + break; + + default: + break; + } + rt_dma_contex_service(rt_dmac,RT_DMA_EVENT_COMPLETE); + } + } + + pending = readl(master->base + DMAC); + pending &= ~(DMAC_HLT | DMAC_AR); + writel(pending, master->base + DMAC); + writel(0, master->base + DIRQP); + +} + +/* not use */ +static void jzdma_link_int_handler(int irq, void *param) +{ + struct jzdma_master *master = &_g_jzdma_master; + uint32_t pending; + int i; + + pending = readl(master->base + DESIRQP); + + JZDMA_DBG("Link INT \n"); + + for (i = 0; i < NR_DMA_CHANNELS; i++) + { + struct rt_dma_channel *rt_dmac = &_g_rt_dma_channel[i]; + struct jzdma_channel *jz_dmac = (struct jzdma_channel *)rt_dmac->user_data; + + if (!(pending & (1 << i))) + continue; + if (jz_dmac->status != STAT_RUNNING) + continue; + } + + writel((readl(master->base + DIC)&(~pending)),master->base + DIC); +} + +/* RTDMA 驱动层 接口*/ +struct dma_ops _g_jzdma_ops = +{ + .reset = jzdma_funcs_reset, + .trans = jzdma_funcs_transfer, + .status = jzdma_funcs_status +}; + + +int rt_hw_jzdma_init(void) +{ + int i; + struct jzdma_master *master = &_g_jzdma_master; + uint32_t pdma_program = 0; + /* 使能DMA 时钟 */ + master->clk = clk_get("pdma"); + clk_enable(master->clk); + + master->base = DMAC_BASE; + master->irq = IRQ_PDMA; + master->irq_pdmad = IRQ_PDMAD; + + /* ??? + * indeed it think we should also enable special channel<0,1> + * but when you guys enable it (set bit1) the main cpu will never get interrupt from dma channel when TC count down to 0 + */ + writel(1 | (0x3f << 16), master->base + DMAC); + + for (i = 0; i < NR_DMA_CHANNELS; i++) + { + struct rt_dma_channel *rt_dmac = &(_g_rt_dma_channel[i]); + struct jzdma_channel *jz_dmac = &(master->channel[i]); + struct dma_config config = + { + .direction = RT_DMA_MEM_TO_MEM, + .src_addr_width = RT_DMA_BUSWIDTH_4_BYTES, + .src_maxburst = (64 * 1024), + .dst_addr_width = RT_DMA_BUSWIDTH_4_BYTES, + .dst_maxburst = (64 * 1024), + }; + + rt_dmac->ch = i; + + jz_dmac->type = JZDMA_REQ_AUTO; + jz_dmac->iomem = master->base + i * 0x20; + jz_dmac->status = STAT_STOPED; + jz_dmac->dcm_def = 0; + + pdma_program |= (0x01 << i); + + rt_dma_drv_install(rt_dmac,&_g_jzdma_ops,&config,jz_dmac); + } + + /* the corresponding dma channel is set programmable */ +// writel(pdma_program, dma->base + DMACP); + + jzdma_mcu_reset(master); + + /* 注册 DMA中断 */ + rt_hw_interrupt_install(IRQ_PDMA,jzdma_int_handler,RT_NULL,"PDMA"); + rt_hw_interrupt_umask(IRQ_PDMA); + + rt_hw_interrupt_install(IRQ_PDMAD,jzdma_link_int_handler,RT_NULL,"PDMAD"); + rt_hw_interrupt_umask(IRQ_PDMAD); + + return RT_EOK; +} +INIT_DEVICE_EXPORT(rt_hw_jzdma_init); diff --git a/bsp/x1000/drivers/drv_dma.h b/bsp/x1000/drivers/drv_dma.h new file mode 100644 index 0000000000000000000000000000000000000000..e6530cd72d2d88543d64091239739b0ba222af58 --- /dev/null +++ b/bsp/x1000/drivers/drv_dma.h @@ -0,0 +1,224 @@ +/* + * File : drv_dma.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ + + +#ifndef _DRV_DMA_H_ +#define _DRV_DMA_H_ +#include + +#define NR_DMA_CHANNELS 8 + + +#define CH_DSA 0x00 +#define CH_DTA 0x04 +#define CH_DTC 0x08 +#define CH_DRT 0x0C +#define CH_DCS 0x10 +#define CH_DCM 0x14 +#define CH_DDA 0x18 +#define CH_DSD 0x1C + +#define TCSM 0x2000 + +#define DMAC 0x1000 +#define DIRQP 0x1004 +#define DESIRQP 0x1010 +#define DIC 0x1014 +#define DDR 0x1008 +#define DDRS 0x100C +#define DMACP 0x101C +#define DSIRQP 0x1020 +#define DSIRQM 0x1024 +#define DCIRQP 0x1028 +#define DCIRQM 0x102C + +/* MCU of PDMA */ +#define DMCS 0x1030 +#define DMNMB 0x1034 +#define DMSMB 0x1038 +#define DMINT 0x103C + +/* MCU of PDMA */ +#define DMINT_S_IP BIT(17) +#define DMINT_N_IP BIT(16) + +#define DMAC_HLT BIT(3) +#define DMAC_AR BIT(2) + +#define DCS_NDES BIT(31) +#define DCS_AR BIT(4) +#define DCS_TT BIT(3) +#define DCS_HLT BIT(2) +#define DCS_CTE BIT(0) + +#define DCM_SAI BIT(23) +#define DCM_DAI BIT(22) +#define DCM_SP_MSK (0x3 << 14) +#define DCM_SP_32 DCM_SP_MSK +#define DCM_SP_16 BIT(15) +#define DCM_SP_8 BIT(14) +#define DCM_DP_MSK (0x3 << 12) +#define DCM_DP_32 DCM_DP_MSK +#define DCM_DP_16 BIT(13) +#define DCM_DP_8 BIT(12) +#define DCM_TSZ_MSK (0x7 << 8) +#define DCM_TSZ_SHF 8 +#define DCM_STDE BIT(2) +#define DCM_TIE BIT(1) +#define DCM_LINK BIT(0) + +#define DCM_CH1_SRC_TCSM (0x0 << 26) +#define DCM_CH1_SRC_NEMC (0x1 << 26) +#define DCM_CH1_SRC_DDR (0x2 << 26) + +#define DCM_CH1_DST_TCSM (0x0 << 24) +#define DCM_CH1_DST_NEMC (0x1 << 24) +#define DCM_CH1_DST_DDR (0x2 << 24) + +#define DCM_CH1_DDR_TO_NAND (DCM_CH1_SRC_DDR | DCM_CH1_DST_NEMC) +#define DCM_CH1_NAND_TO_DDR (DCM_CH1_SRC_NEMC | DCM_CH1_DST_DDR) + +#define DCM_CH1_TCSM_TO_NAND (DCM_CH1_SRC_TCSM | DCM_CH1_DST_NEMC) +#define DCM_CH1_NAND_TO_TCSM (DCM_CH1_SRC_NEMC | DCM_CH1_DST_TCSM) + +#define DCM_CH1_TCSM_TO_DDR (DCM_CH1_SRC_TCSM | DCM_CH1_DST_DDR) +#define DCM_CH1_DDR_TO_TCSM (DCM_CH1_SRC_DDR | DCM_CH1_DST_TCSM) + +#define MCU_MSG_TYPE_NORMAL 0x1 +#define MCU_MSG_TYPE_INTC 0x2 +#define MCU_MSG_TYPE_INTC_MASKA 0x3 + +enum jzdma_req_type { +#define _RTP(NAME) JZDMA_REQ_##NAME##_TX,JZDMA_REQ_##NAME##_RX + JZDMA_REQ_RESERVED0 = 0x03, + _RTP(DMIC), + _RTP(I2S0), + JZDMA_REQ_AUTO_TXRX = 0x08, + JZDMA_REQ_SADC_RX, + JZDMA_REQ_RESERVED1 = 0x0b, + _RTP(UART4), + _RTP(UART3), + _RTP(UART2), + _RTP(UART1), + _RTP(UART0), + _RTP(SSI0), + _RTP(SSI1), + _RTP(MSC0), + _RTP(MSC1), + _RTP(MSC2), + _RTP(PCM0), + _RTP(PCM1), + _RTP(I2C0), + _RTP(I2C1), + _RTP(I2C2), + _RTP(I2C3), + _RTP(I2C4), + _RTP(DES), +#undef _RTP +}; + +enum jzdma_type { + JZDMA_REQ_INVAL = 0, +#define _RTP(NAME) JZDMA_REQ_##NAME = JZDMA_REQ_##NAME##_TX + _RTP(DMIC), + _RTP(I2S0), + JZDMA_REQ_AUTO = JZDMA_REQ_AUTO_TXRX, + JZDMA_REQ_SADC = JZDMA_REQ_SADC_RX, + _RTP(UART4), + _RTP(UART3), + _RTP(UART2), + _RTP(UART1), + _RTP(UART0), + _RTP(SSI0), + _RTP(SSI1), + _RTP(MSC0), + _RTP(MSC1), + _RTP(MSC2), + _RTP(PCM0), + _RTP(PCM1), + _RTP(I2C0), + _RTP(I2C1), + _RTP(I2C2), + _RTP(I2C3), + _RTP(I2C4), + _RTP(DES), + JZDMA_REQ_NAND0 = JZDMA_REQ_AUTO_TXRX | (1 << 16), + JZDMA_REQ_NAND1 = JZDMA_REQ_AUTO_TXRX | (2 << 16), + JZDMA_REQ_NAND2 = JZDMA_REQ_AUTO_TXRX | (3 << 16), + JZDMA_REQ_NAND3 = JZDMA_REQ_AUTO_TXRX | (4 << 16), + JZDMA_REQ_NAND4 = JZDMA_REQ_AUTO_TXRX | (5 << 16), + TYPE_MASK = 0xffff, +#undef _RTP +}; + +#define GET_MAP_TYPE(type) (type & (TYPE_MASK)) + + +enum channel_status +{ + STAT_STOPED,STAT_SUBED,STAT_PREPED,STAT_RUNNING, +}; + +struct jzdma_desc +{ + uint32_t dcm; + uint32_t dsa; + uint32_t dta; + uint32_t dtc; + uint32_t sd; + uint32_t drt; + uint32_t reserved[2]; +}; + +struct jzdma_channel +{ +// int id; + uint32_t iomem; + uint32_t dcs_saved; + uint32_t dcm_def; + + enum jzdma_type type; + enum channel_status status; + + //传输控制描述符 + struct jzdma_desc desc; + uint32_t desc_nr; + +// struct rt_dma_channel *parant; +}; + +struct jzdma_master +{ + uint32_t base; + struct clk *clk; + int irq; + int irq_pdmad; /* irq_pdmad for PDMA_DESC irq */ + + struct jzdma_channel channel[NR_DMA_CHANNELS]; +}; + + +extern struct rt_dma_funcs _g_jzdma_funcs; + +#endif /* _DRV_DMA_H_ */ diff --git a/bsp/x1000/driver/drv_gpio.c b/bsp/x1000/drivers/drv_gpio.c similarity index 91% rename from bsp/x1000/driver/drv_gpio.c rename to bsp/x1000/drivers/drv_gpio.c index 1310f7dfc92465664489ee879ddc686864cc40db..ffbaa7f154f0f3c2d6f1840d8f1422df898356a3 100644 --- a/bsp/x1000/driver/drv_gpio.c +++ b/bsp/x1000/drivers/drv_gpio.c @@ -50,15 +50,19 @@ void gpio_set_func(enum gpio_port port, uint32_t pins, enum gpio_function func) { RT_ASSERT(IS_GPIO_ALL_PORT(port)); - writel(func & 0x8 ? pins : 0, GPIO_PXINTS(port)); - writel(func & 0x4 ? pins : 0, GPIO_PXMSKS(port)); - writel(func & 0x2 ? pins : 0, GPIO_PXPAT1S(port)); - writel(func & 0x1 ? pins : 0, GPIO_PXPAT0S(port)); + // Write to shadow register + writel(func & 0x8 ? pins : 0, GPIO_PXINTS(GPIO_PORT_Z)); + writel(func & 0x4 ? pins : 0, GPIO_PXMSKS(GPIO_PORT_Z)); + writel(func & 0x2 ? pins : 0, GPIO_PXPAT1S(GPIO_PORT_Z)); + writel(func & 0x1 ? pins : 0, GPIO_PXPAT0S(GPIO_PORT_Z)); - writel(func & 0x8 ? 0 : pins, GPIO_PXINTC(port)); - writel(func & 0x4 ? 0 : pins, GPIO_PXMSKC(port)); - writel(func & 0x2 ? 0 : pins, GPIO_PXPAT1C(port)); - writel(func & 0x1 ? 0 : pins, GPIO_PXPAT0C(port)); + writel(func & 0x8 ? 0 : pins, GPIO_PXINTC(GPIO_PORT_Z)); + writel(func & 0x4 ? 0 : pins, GPIO_PXMSKC(GPIO_PORT_Z)); + writel(func & 0x2 ? 0 : pins, GPIO_PXPAT1C(GPIO_PORT_Z)); + writel(func & 0x1 ? 0 : pins, GPIO_PXPAT0C(GPIO_PORT_Z)); + + //Load shadown reigster + writel(port,GPIO_PZGID2LD(GPIO_PORT_Z)); writel(func & 0x10 ? pins : 0, GPIO_PXPENC(port)); writel(func & 0x10 ? 0 : pins, GPIO_PXPENS(port)); @@ -147,7 +151,7 @@ void gpio_mask_irq(enum gpio_port port, enum gpio_pin pin) { RT_ASSERT(IS_GPIO_ALL_PORT(port)); - writel(BIT(pin), GPIO_PXMSKS(port)); + writel(pin, GPIO_PXMSKS(port)); } int gpio_set_irq_type(enum gpio_port port, enum gpio_pin pin, enum gpio_irq_type irq_type) diff --git a/bsp/x1000/driver/drv_gpio.h b/bsp/x1000/drivers/drv_gpio.h similarity index 93% rename from bsp/x1000/driver/drv_gpio.h rename to bsp/x1000/drivers/drv_gpio.h index ceef761aaadb1b8a133709f81ff7a74a473e4711..f020a7f8ff45849519bd41086f1af87646e24708 100644 --- a/bsp/x1000/driver/drv_gpio.h +++ b/bsp/x1000/drivers/drv_gpio.h @@ -27,13 +27,13 @@ #include -#define GPIO_PA(n) (0*32 + n) -#define GPIO_PB(n) (1*32 + n) -#define GPIO_PC(n) (2*32 + n) -#define GPIO_PD(n) (3*32 + n) -#define GPIO_PE(n) (4*32 + n) -#define GPIO_PF(n) (5*32 + n) -#define GPIO_PG(n) (6*32 + n) +//#define GPIO_PA(n) (0*32 + n) +//#define GPIO_PB(n) (1*32 + n) +//#define GPIO_PC(n) (2*32 + n) +//#define GPIO_PD(n) (3*32 + n) +//#define GPIO_PE(n) (4*32 + n) +//#define GPIO_PF(n) (5*32 + n) +//#define GPIO_PG(n) (6*32 + n) #define GPIO_PIN(n) (0x01 << n) @@ -142,8 +142,13 @@ enum gpio_port { GPIO_PORT_D, /* this must be last */ GPIO_NR_PORTS, + GPIO_PORT_Z = 7, }; +//#define IS_GPIO_ALL_PORT(PORT) ( ((PORT) == GPIO_PORT_A) || \ +// ((PORT) == GPIO_PORT_B) || \ +// ((PORT) == GPIO_PORT_C) || \ +// ((PORT) == GPIO_PORT_D) ) #define IS_GPIO_ALL_PORT(PORT) ( (PORT) < GPIO_NR_PORTS ) enum gpio_pin { @@ -203,6 +208,8 @@ void gpio_as_irq_high_level (enum gpio_port port, enum gpio_pin pin); void gpio_as_irq_rise_edge (enum gpio_port port, enum gpio_pin pin); void gpio_as_irq_fall_edge (enum gpio_port port, enum gpio_pin pin); void gpio_ack_irq (enum gpio_port port, enum gpio_pin pin); -void gpio_set_irq_callback(enum gpio_port port, enum gpio_pin pin, void (*irq_cb)(void *),void *irq_arg); +void gpio_set_irq_callback(enum gpio_port port, enum gpio_pin pin, void (*irq_cb)(void *),void *irq_arg); +void gpio_mask_irq(enum gpio_port port, enum gpio_pin pin); +void gpio_unmask_irq(enum gpio_port port, enum gpio_pin pin); #endif /* _BOARD_GPIO_H_ */ diff --git a/bsp/x1000/drivers/drv_i2c.c b/bsp/x1000/drivers/drv_i2c.c new file mode 100644 index 0000000000000000000000000000000000000000..7f19acae557b6cc958618d0bd11ae16a197c12e3 --- /dev/null +++ b/bsp/x1000/drivers/drv_i2c.c @@ -0,0 +1,843 @@ +#include +#include +#include + +#include "board.h" +#include "drv_clock.h" +#include "drv_gpio.h" + + +#define I2C_DEBUG 0 + +#if I2C_DEBUG +#define I2C_DBG(...) rt_kprintf("[I2C]"),rt_kprintf(__VA_ARGS__) +#else +#define I2C_DBG(...) +#endif + +#define I2C_CTRL (0x00) +#define I2C_TAR (0x04) +#define I2C_SAR (0x08) +#define I2C_DC (0x10) +#define I2C_SHCNT (0x14) +#define I2C_SLCNT (0x18) +#define I2C_FHCNT (0x1C) +#define I2C_FLCNT (0x20) +#define I2C_INTST (0x2C) +#define I2C_INTM (0x30) +#define I2C_RXTL (0x38) +#define I2C_TXTL (0x3c) +#define I2C_CINTR (0x40) +#define I2C_CRXUF (0x44) +#define I2C_CRXOF (0x48) +#define I2C_CTXOF (0x4C) +#define I2C_CRXREQ (0x50) +#define I2C_CTXABRT (0x54) +#define I2C_CRXDONE (0x58) +#define I2C_CACT (0x5C) +#define I2C_CSTP (0x60) +#define I2C_CSTT (0x64) +#define I2C_CGC (0x68) +#define I2C_ENB (0x6C) +#define I2C_STA (0x70) +#define I2C_TXFLR (0x74) +#define I2C_RXFLR (0x78) +#define I2C_SDAHD (0x7C) +#define I2C_TXABRT (0x80) +#define I2C_DMACR (0x88) +#define I2C_DMATDLR (0x8c) +#define I2C_DMARDLR (0x90) +#define I2C_SDASU (0x94) +#define I2C_ACKGC (0x98) +#define I2C_ENSTA (0x9C) +#define I2C_FLT (0xA0) + +/* I2C Control Register (I2C_CTRL) */ +#define I2C_CTRL_SLVDIS (1 << 6) /* after reset slave is disabled */ +#define I2C_CTRL_REST (1 << 5) +#define I2C_CTRL_MATP (1 << 4) /* 1: 10bit address 0: 7bit addressing */ +#define I2C_CTRL_SATP (1 << 3) /* 1: 10bit address 0: 7bit address */ +#define I2C_CTRL_SPDF (2 << 1) /* fast mode 400kbps */ +#define I2C_CTRL_SPDS (1 << 1) /* standard mode 100kbps */ +#define I2C_CTRL_MD (1 << 0) /* master enabled */ + +/* I2C Status Register (I2C_STA) */ +#define I2C_STA_SLVACT (1 << 6) /* Slave FSM is not in IDLE state */ +#define I2C_STA_MSTACT (1 << 5) /* Master FSM is not in IDLE state */ +#define I2C_STA_RFF (1 << 4) /* RFIFO if full */ +#define I2C_STA_RFNE (1 << 3) /* RFIFO is not empty */ +#define I2C_STA_TFE (1 << 2) /* TFIFO is empty */ +#define I2C_STA_TFNF (1 << 1) /* TFIFO is not full */ +#define I2C_STA_ACT (1 << 0) /* I2C Activity Status */ + +/* i2c interrupt status (I2C_INTST) */ +#define I2C_INTST_IGC (1 << 11) +#define I2C_INTST_ISTT (1 << 10) +#define I2C_INTST_ISTP (1 << 9) +#define I2C_INTST_IACT (1 << 8) +#define I2C_INTST_RXDN (1 << 7) +#define I2C_INTST_TXABT (1 << 6) +#define I2C_INTST_RDREQ (1 << 5) +#define I2C_INTST_TXEMP (1 << 4) +#define I2C_INTST_TXOF (1 << 3) +#define I2C_INTST_RXFL (1 << 2) +#define I2C_INTST_RXOF (1 << 1) +#define I2C_INTST_RXUF (1 << 0) + +/* i2c interrupt mask status (I2C_INTM) */ +#define I2C_INTM_MIGC (1 << 11) +#define I2C_INTM_MISTT (1 << 10) +#define I2C_INTM_MISTP (1 << 9) +#define I2C_INTM_MIACT (1 << 8) +#define I2C_INTM_MRXDN (1 << 7) +#define I2C_INTM_MTXABT (1 << 6) +#define I2C_INTM_MRDREQ (1 << 5) +#define I2C_INTM_MTXEMP (1 << 4) +#define I2C_INTM_MTXOF (1 << 3) +#define I2C_INTM_MRXFL (1 << 2) +#define I2C_INTM_MRXOF (1 << 1) +#define I2C_INTM_MRXUF (1 << 0) + +#define I2C_DC_REST (1 << 10) +#define I2C_DC_STP (1 << 9) +#define I2C_DC_READ (1 << 8) + +#define I2C_ENB_I2CENB (1 << 0) /* Enable the i2c */ + +#define CONFIG_I2C_FIFO_LEN 64 +#define I2C_FIFO_LEN (CONFIG_I2C_FIFO_LEN) +#define TX_LEVEL (I2C_FIFO_LEN / 2) +#define RX_LEVEL (I2C_FIFO_LEN / 2 - 1) + +#define TIMEOUT 0xff + +/* + * msg_end_type: The bus control which need to be send at end of transfer. + * @MSG_END_STOP: Send stop pulse at end of transfer. + * @MSG_END_REPEAT_START: Send repeat start at end of transfer. + */ +enum msg_end_type +{ + MSG_END_STOP, + MSG_END_CONTINUE, + MSG_END_REPEAT_START, +}; + +/* I2C standard mode high count register(I2CSHCNT) */ +#define I2CSHCNT_ADJUST(n) (((n) - 8) < 6 ? 6 : ((n) - 8)) +/* I2C standard mode low count register(I2CSLCNT) */ +#define I2CSLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1)) +/* I2C fast mode high count register(I2CFHCNT) */ +#define I2CFHCNT_ADJUST(n) (((n) - 8) < 6 ? 6 : ((n) - 8)) +/* I2C fast mode low count register(I2CFLCNT) */ +#define I2CFLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1)) + +/* I2C Transmit Abort Status Register (I2C_TXABRT) */ +static const char *abrt_src[] = +{ + "I2C_TXABRT_ABRT_7B_ADDR_NOACK", + "I2C_TXABRT_ABRT_10ADDR1_NOACK", + "I2C_TXABRT_ABRT_10ADDR2_NOACK", + "I2C_TXABRT_ABRT_XDATA_NOACK", + "I2C_TXABRT_ABRT_GCALL_NOACK", + "I2C_TXABRT_ABRT_GCALL_READ", + "I2C_TXABRT_ABRT_HS_ACKD", + "I2C_TXABRT_SBYTE_ACKDET", + "I2C_TXABRT_ABRT_HS_NORSTRT", + "I2C_TXABRT_SBYTE_NORSTRT", + "I2C_TXABRT_ABRT_10B_RD_NORSTRT", + "I2C_TXABRT_ABRT_MASTER_DIS", + "I2C_TXABRT_ARB_LOST", + "I2C_TXABRT_SLVFLUSH_TXFIFO", + "I2C_TXABRT_SLV_ARBLOST", + "I2C_TXABRT_SLVRD_INTX", +}; + +struct ingenic_i2c_bus +{ + struct rt_i2c_bus_device parent; + + rt_uint32_t hwaddr; + rt_uint32_t irqno; + + struct clk *clk; + + enum msg_end_type w_end_type; + enum msg_end_type r_end_type; + + unsigned char *rbuf; + unsigned char *wbuf; + unsigned int rd_len; + + int len; + unsigned int rate; + + struct rt_completion completion; +}; + +#ifdef RT_USING_I2C0 +static struct ingenic_i2c_bus ingenic_i2c0; +#endif + +#ifdef RT_USING_I2C1 +static struct ingenic_i2c_bus ingenic_i2c1; +#endif + +#ifdef RT_USING_I2C2 +static struct ingenic_i2c_bus ingenic_i2c2; +#endif + +static inline unsigned short i2c_readl(struct ingenic_i2c_bus *i2c, + unsigned short offset) +{ + return readl(i2c->hwaddr + offset); +} + +static inline void i2c_writel(struct ingenic_i2c_bus *i2c, unsigned short offset, + unsigned short value) +{ + writel(value, i2c->hwaddr + offset); +} + +static int ingenic_i2c_disable(struct ingenic_i2c_bus *i2c) +{ + int timeout = TIMEOUT; + + i2c_writel(i2c, I2C_ENB, 0); + + while ((i2c_readl(i2c, I2C_ENSTA) & I2C_ENB_I2CENB) && (--timeout > 0)) + rt_thread_delay(1); + + if (timeout) return 0; + + I2C_DBG("disable i2c failed!\n"); + return -RT_ETIMEOUT; +} + +static int ingenic_i2c_enable(struct ingenic_i2c_bus *i2c) +{ + int timeout = TIMEOUT; + + i2c_writel(i2c, I2C_ENB, 1); + + while (!(i2c_readl(i2c, I2C_ENSTA) & I2C_ENB_I2CENB) && (--timeout > 0)) + rt_thread_delay(1); + + if (timeout) return 0; + + I2C_DBG("enable i2c failed\n"); + return -RT_ETIMEOUT; +} + +static void ingenic_i2c_reset(struct ingenic_i2c_bus *i2c) +{ + i2c_readl(i2c, I2C_CTXABRT); + i2c_readl(i2c, I2C_INTST); + + ingenic_i2c_disable(i2c); + rt_thread_delay(1); + ingenic_i2c_enable(i2c); +} + + +static int ingenic_i2c_set_speed(struct ingenic_i2c_bus *i2c, int rate) +{ + /*ns */ + long dev_clk = clk_get_rate(i2c->clk); + long cnt_high = 0; /* HIGH period count of the SCL clock */ + long cnt_low = 0; /* LOW period count of the SCL clock */ + long setup_time = 0; + long hold_time = 0; + unsigned short tmp; + + i2c->rate = rate; + + if (ingenic_i2c_disable(i2c))I2C_DBG("i2c not disable\n"); + + if (rate <= 100000) + { + tmp = 0x43 | (1 << 5); /* standard speed mode */ + i2c_writel(i2c, I2C_CTRL, tmp); + } + else + { + tmp = 0x45 | (1 << 5); /* fast speed mode */ + i2c_writel(i2c, I2C_CTRL, tmp); + } + + /* high + * ____ ____ ____ ____ + * clk __| | |___| |____| |____| |___ + * | | | + * | | | + * |_|_| _________ ____ + * data __/ | |\___/ \____/ \____ + * setup->| |<| + * ->| |<-hold + */ + + //setup_time = (10 000 000/(rate*4)) + 1; + setup_time = (dev_clk / (rate * 4)); + if (setup_time > 1) setup_time -= 1; + + //hold_time = (10000000/(rate*4)) - 1; + hold_time = (dev_clk / (rate * 4)); + + /* high + * ____ ____ + * clk __| |___| |____ + * low + * |<--period--->| + * + */ + cnt_high = dev_clk / (rate * 2); + cnt_low = dev_clk / (rate * 2); + + if (setup_time > 255) setup_time = 255; + if (setup_time <= 0) setup_time = 1; + if (hold_time > 0xFFFF) hold_time = 0xFFFF; + + if (rate <= 100000) + { + i2c_writel(i2c, I2C_SHCNT, I2CSHCNT_ADJUST(cnt_high)); + i2c_writel(i2c, I2C_SLCNT, I2CSLCNT_ADJUST(cnt_low)); + } + else + { + i2c_writel(i2c, I2C_FHCNT, I2CFHCNT_ADJUST(cnt_high)); + i2c_writel(i2c, I2C_FLCNT, I2CFLCNT_ADJUST(cnt_low)); + } + + i2c_writel(i2c, I2C_SDASU, setup_time & 0xff); + i2c_writel(i2c, I2C_SDAHD, hold_time); + + return 0; +} + +/* function: send read command + * return: 0, successful + * 1, txfifo valid entry is more than receive fifo, before send read command, + * must be read. + * 2, txfifo count is 0 or rxfifo count is 0. + * */ +static inline unsigned int i2c_send_rcmd(struct ingenic_i2c_bus *i2c) +{ + unsigned int tx_count, rx_count, count, tx_valid, rx_valid; + + tx_valid = i2c_readl(i2c, I2C_TXFLR); + rx_valid = i2c_readl(i2c, I2C_RXFLR); + tx_count = I2C_FIFO_LEN - tx_valid; + rx_count = I2C_FIFO_LEN - rx_valid; + + if (tx_valid > rx_count) + { + I2C_DBG("###Warning: I2C transfer fifo valid entry is more receive fifo, " + "before send read cmd, please read data from " + "the read fifo.\n"); + return 1; + } + + if (!tx_count || !rx_count) + { + I2C_DBG("###Warning: I2C receive fifo or transfer fifo is full, " + "before send read cmd, please read data from " + "the read fifo or wait some time.\n\n"); + return 2; + } + + count = (i2c->rd_len < tx_count)? i2c->rd_len : tx_count; + count = (count < rx_count)? count : rx_count; + + i2c->rd_len -= count; + + if (!i2c->rd_len) + { + while (count > 1) + { + i2c_writel(i2c, I2C_DC, I2C_DC_READ); + count--; + } + + if (i2c->r_end_type == MSG_END_STOP) + { + i2c_writel(i2c, I2C_DC, I2C_DC_READ | I2C_DC_STP); + } + else + { + i2c_writel(i2c, I2C_DC, I2C_DC_READ); + } + } + else + { + while (count > 0) + { + i2c_writel(i2c, I2C_DC, I2C_DC_READ); + count--; + } + } + + return 0; +} + +static void txabrt(struct ingenic_i2c_bus *i2c, int src) +{ + int i; + + I2C_DBG("--I2C txabrt:\n"); + for (i = 0; i < 16; i++) + { + if (src & (0x1 << i)) + I2C_DBG("--I2C TXABRT[%d]=%s\n", i, abrt_src[i]); + } +} + +static int i2c_disable_clk(struct ingenic_i2c_bus *i2c) +{ + int timeout = 10; + int tmp = i2c_readl(i2c, I2C_STA); + + while ((tmp & I2C_STA_MSTACT) && (--timeout > 0)) + { + rt_thread_delay(2); + tmp = i2c_readl(i2c, I2C_STA); + } + + if (timeout > 0) + { + clk_disable(i2c->clk); + return 0; + } + else + { + I2C_DBG("--I2C disable clk timeout, I2C_STA = 0x%x\n", tmp); + ingenic_i2c_reset(i2c); + clk_disable(i2c->clk); + + return -RT_ETIMEOUT; + } +} + +static inline int xfer_read(struct ingenic_i2c_bus *i2c, unsigned char *buf, int len, enum msg_end_type end_type) +{ + int ret = 0; + long timeout; + unsigned short tmp; + + rt_memset(buf, 0, len); + + i2c->rd_len = len; + i2c->len = len; + i2c->rbuf = buf; + i2c->r_end_type = end_type; + + i2c_readl(i2c, I2C_CSTP); /* clear STP bit */ + i2c_readl(i2c, I2C_CTXOF); /* clear TXOF bit */ + i2c_readl(i2c, I2C_CTXABRT); /* clear TXABRT bit */ + + I2C_DBG("i2c: read %d len data\n", len); + + if (len <= I2C_FIFO_LEN) + { + i2c_writel(i2c, I2C_RXTL, len - 1); + } + else + { + i2c_writel(i2c, I2C_RXTL, RX_LEVEL); + } +// I2C_DBG("RXTL: %x\n", i2c_readl(i2c, I2C_RXTL)); + + I2C_DBG("read len: %d\n", i2c_readl(i2c, I2C_RXFLR)); + + while (i2c_readl(i2c, I2C_STA) & I2C_STA_RFNE) + { + i2c_readl(i2c, I2C_DC); + } + + if (i2c_send_rcmd(i2c)) + { + I2C_DBG("i2c: send read command failed!\n"); + } + else + { + I2C_DBG("i2c: send read command OK!\n"); + } + + tmp = I2C_INTM_MRXFL | I2C_INTM_MTXABT; + if (end_type == MSG_END_STOP) tmp |= I2C_INTM_MISTP; + i2c_writel(i2c, I2C_INTM, tmp); + + /* wait for finish */ + while(rt_completion_wait(&(i2c->completion), RT_TICK_PER_SECOND) == -RT_ETIMEOUT) + I2C_DBG("fifo len: %d\n", i2c_readl(i2c, I2C_RXFLR)); + + tmp = i2c_readl(i2c, I2C_TXABRT); + if (tmp) + { + txabrt(i2c, tmp); + if (tmp > 0x1 && tmp < 0x10) + ret = -RT_EIO; + else + ret = -RT_EIO; + + /* abort read */ + if (tmp & (1 << 5)) { + ret = -RT_ERROR; + } + i2c_readl(i2c, I2C_CTXABRT); + } + + if (ret < 0) ingenic_i2c_reset(i2c); + + return ret; +} + +static inline int xfer_write(struct ingenic_i2c_bus *i2c, unsigned char *buf, int len, enum msg_end_type end_type) +{ + int ret = 0; + long timeout = TIMEOUT; + unsigned short reg_tmp; + + i2c->wbuf = buf; + i2c->len = len; + + i2c_writel(i2c, I2C_TXTL, TX_LEVEL); + + i2c_readl(i2c, I2C_CSTP); /* clear STP bit */ + i2c_readl(i2c, I2C_CTXOF); /* clear TXOF bit */ + i2c_readl(i2c, I2C_CTXABRT); /* clear TXABRT bit */ + + I2C_DBG("i2c: write %d len data\n", len); + + i2c->w_end_type = end_type; + + while ((i2c_readl(i2c, I2C_STA) & I2C_STA_TFNF) && (i2c->len > 0)) + { + reg_tmp = *i2c->wbuf++; + if (i2c->len == 1) + { + if (end_type == MSG_END_STOP) + { + reg_tmp |= I2C_DC_STP; + } + } + i2c_writel(i2c, I2C_DC, reg_tmp); + + i2c->len -= 1; + } + + if (i2c->len == 0) + { + i2c_writel(i2c, I2C_TXTL, 0); + } + + reg_tmp = I2C_INTM_MTXEMP | I2C_INTM_MTXABT | I2C_INTM_MTXOF; + if (end_type == MSG_END_STOP) reg_tmp |= I2C_INTM_MISTP; + i2c_writel(i2c, I2C_INTM, reg_tmp); + + /* wait for finish */ + rt_completion_wait(&(i2c->completion), rt_tick_from_millisecond(2000)); + + reg_tmp = i2c_readl(i2c, I2C_TXABRT); + if (reg_tmp) + { + txabrt(i2c, reg_tmp); + if (reg_tmp > 0x1 && reg_tmp < 0x10) + ret = -RT_EIO; + else + ret = -RT_EIO; + + //after I2C_TXABRT_ABRT_XDATA_NOACK error,this required core to resend + if (reg_tmp & 8) + { + ret = -RT_ERROR; + } + i2c_readl(i2c, I2C_CTXABRT); + } + + if (ret < 0) ingenic_i2c_reset(i2c); + + return ret; +} + +static rt_size_t ingenic_i2c_xfer(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num) +{ + int i; + int ret = RT_EOK; + struct ingenic_i2c_bus *i2c; + + i2c = (struct ingenic_i2c_bus*)bus; + + clk_enable(i2c->clk); + i2c_writel(i2c, I2C_TAR, msgs[0].addr); + + for (i = 0; i < num; i++) + { + enum msg_end_type end_type = MSG_END_STOP; + + if (i < (num - 1)) + { + if (msgs[i + 1].flags & RT_I2C_NO_START) + { + end_type = MSG_END_CONTINUE; /* have no STOP and START */ + } + else + { + end_type = MSG_END_REPEAT_START; /* have no STOP but have RESTART */ + } + } + + /* initialize completion */ + rt_completion_init(&(i2c->completion)); + + if (msgs[i].flags & RT_I2C_RD) + { + ret = xfer_read(i2c, msgs[i].buf, msgs[i].len, end_type); + } + else + { + ret = xfer_write(i2c, msgs[i].buf, msgs[i].len, end_type); + } + + if (ret < 0) + { + clk_disable(i2c->clk); + goto _ERR; + } + } + + ret = i2c_disable_clk(i2c); + +_ERR: + return ret < 0? ret : i; +} + +static const struct rt_i2c_bus_device_ops i2c_ops = +{ + ingenic_i2c_xfer, + RT_NULL, + RT_NULL +}; + +static void i2c_irq_handler(int irqno, void *param) +{ + unsigned short tmp, intst, intmsk; + struct ingenic_i2c_bus *i2c; + + i2c = (struct ingenic_i2c_bus*)param; + + intst = i2c_readl(i2c, I2C_INTST); + intmsk = i2c_readl(i2c, I2C_INTM); + + I2C_DBG("i2c irq!!\n"); + + if ((intst & I2C_INTST_TXABT) && (intmsk & I2C_INTM_MTXABT)) + { + I2C_DBG("%s %d, I2C transfer error, ABORT interrupt\n", __func__, __LINE__); + goto END_TRSF_IRQ_HND; + } + + if ((intst & I2C_INTST_ISTP) && (intmsk & I2C_INTM_MISTP)) + { + i2c_readl(i2c, I2C_CSTP); /* clear STP bit */ + + if (i2c->len == 0) + goto END_TRSF_IRQ_HND; + } + + if ((intmsk & I2C_INTM_MTXEMP) && (intst & I2C_INTST_TXEMP)) + { + if (!i2c->len) + { + if (i2c->w_end_type == MSG_END_REPEAT_START) + { + goto END_TRSF_IRQ_HND; + } + else + { + tmp = i2c_readl(i2c, I2C_INTM); + tmp &= ~I2C_INTM_MTXEMP; + i2c_writel(i2c, I2C_INTM, tmp); + } + } + else + { + while ((i2c->len > 0) && (i2c_readl(i2c, I2C_STA) & I2C_STA_TFNF)) + { + tmp = *i2c->wbuf++; + if (i2c->len == 1) + { + if (i2c->w_end_type == MSG_END_STOP) + tmp |= I2C_DC_STP; + } + + i2c_writel(i2c, I2C_DC, tmp); + i2c->len -= 1; + } + + if (i2c->len == 0) + { + i2c_writel(i2c, I2C_TXTL, 0); + } + } + } + + if ((intst & I2C_INTST_RXFL) && (intmsk & I2C_INTM_MRXFL)) + { + I2C_DBG("I2C RXFL\n"); + while ((i2c_readl(i2c, I2C_STA) & I2C_STA_RFNE) && (i2c->len > 0)) + { + tmp = i2c_readl(i2c, I2C_DC) & 0xff; + *i2c->rbuf++ = tmp; + i2c->len--; + } + + if (i2c->len == 0) + { + goto END_RECE_IRQ_HND; + } + + if (i2c->len <= I2C_FIFO_LEN) + { + i2c_writel(i2c, I2C_RXTL, i2c->len - 1); + } + + if (i2c_send_rcmd(i2c)) + { + I2C_DBG("%s %d, I2C controller has BUG, RXFLR or TXFLR can not clear\n", __func__, __LINE__); + } + } + + if ((intst & I2C_INTST_RXOF) && (intmsk & I2C_INTM_MRXOF)) + { + I2C_DBG("%s %d, I2C transfer error, RXFIFO over full\n", __func__, __LINE__); + i2c_readl(i2c, I2C_CRXOF); /* clear RXOF bit */ + } + + if ((intst & I2C_INTST_TXOF) && (intmsk & I2C_INTM_MTXOF)) + { + I2C_DBG("%s %d, I2C transfer error, TXFIFO over full\n", __func__, __LINE__); + i2c_readl(i2c, I2C_CTXOF); /* clear TXOF bit */ + goto END_TRSF_IRQ_HND; + } + + return ; + +END_RECE_IRQ_HND: +END_TRSF_IRQ_HND: + i2c_writel(i2c, I2C_INTM, 0); + rt_completion_done(&i2c->completion); +} + +int rt_hw_i2c_init(void) +{ + struct ingenic_i2c_bus *i2c; + struct rt_i2c_bus_device *i2c_bus; + +#ifdef RT_USING_I2C0 + { + i2c = &ingenic_i2c0; + rt_memset((void *)i2c, 0, sizeof(struct ingenic_i2c_bus)); + + i2c->hwaddr = I2C0_BASE; + i2c->irqno = IRQ_I2C0; + + /* Set PB23 PB24 in func0 (I2C0) */ + gpio_set_func(GPIO_PORT_B, GPIO_Pin_24, GPIO_FUNC_0); + gpio_set_func(GPIO_PORT_B, GPIO_Pin_23, GPIO_FUNC_0); + + /* enable clock */ + i2c->clk = clk_get("i2c0"); + clk_enable(i2c->clk); + + i2c_bus = &i2c->parent; + i2c_bus->ops = &i2c_ops; + rt_i2c_bus_device_register(i2c_bus, "i2c0"); + + ingenic_i2c_set_speed(i2c, 400 * 1000); + + /* reset I2C */ + i2c_writel(i2c, I2C_CTRL, i2c_readl(i2c, I2C_CTRL) | I2C_CTRL_REST); + i2c_writel(i2c, I2C_INTM, 0x0); + + ingenic_i2c_enable(i2c); + clk_disable(i2c->clk); + + /* install interrupt */ + rt_hw_interrupt_install(i2c->irqno, i2c_irq_handler, i2c, "i2c0"); + rt_hw_interrupt_umask(i2c->irqno); + } +#endif + +#ifdef RT_USING_I2C1 + { + i2c = &ingenic_i2c1; + rt_memset((void *)i2c, 0, sizeof(struct ingenic_i2c_bus)); + + i2c->hwaddr = I2C1_BASE; + i2c->irqno = IRQ_I2C1; + + /* Set PC26 PC27 in func0 (I2C1) */ + gpio_set_func(GPIO_PORT_C, GPIO_Pin_26, GPIO_FUNC_0); + gpio_set_func(GPIO_PORT_C, GPIO_Pin_27, GPIO_FUNC_0); + + /* enable clock */ + i2c->clk = clk_get("i2c1"); + clk_enable(i2c->clk); + + i2c_bus = &i2c->parent; + i2c_bus->ops = &i2c_ops; + rt_i2c_bus_device_register(i2c_bus, "i2c1"); + + ingenic_i2c_set_speed(i2c, 400 * 1000); + + /* reset I2C */ + i2c_writel(i2c, I2C_CTRL, i2c_readl(i2c, I2C_CTRL) | I2C_CTRL_REST); + i2c_writel(i2c, I2C_INTM, 0x0); + + ingenic_i2c_enable(i2c); + clk_disable(i2c->clk); + + /* install interrupt */ + rt_hw_interrupt_install(i2c->irqno, i2c_irq_handler, i2c, "i2c1"); + rt_hw_interrupt_umask(i2c->irqno); + } +#endif + +#ifdef RT_USING_I2C2 + { + i2c = &ingenic_i2c2; + rt_memset((void *)i2c, 0, sizeof(struct ingenic_i2c_bus)); + + i2c->hwaddr = I2C2_BASE; + i2c->irqno = IRQ_I2C2; + + /* Set PC26 PC27 in func0 (I2C1) */ + gpio_set_func(GPIO_PORT_D, GPIO_Pin_0, GPIO_FUNC_1); + gpio_set_func(GPIO_PORT_D, GPIO_Pin_1, GPIO_FUNC_1); + + /* enable clock */ + i2c->clk = clk_get("i2c2"); + clk_enable(i2c->clk); + + i2c_bus = &i2c->parent; + i2c_bus->ops = &i2c_ops; + rt_i2c_bus_device_register(i2c_bus, "i2c2"); + + ingenic_i2c_set_speed(i2c, 400 * 1000); + + /* reset I2C */ + i2c_writel(i2c, I2C_CTRL, i2c_readl(i2c, I2C_CTRL) | I2C_CTRL_REST); + i2c_writel(i2c, I2C_INTM, 0x0); + + ingenic_i2c_enable(i2c); + clk_disable(i2c->clk); + + /* install interrupt */ + rt_hw_interrupt_install(i2c->irqno, i2c_irq_handler, i2c, "i2c2"); + rt_hw_interrupt_umask(i2c->irqno); + } +#endif + + return 0; +} +INIT_BOARD_EXPORT(rt_hw_i2c_init); diff --git a/bsp/x1000/drivers/drv_i2c.h b/bsp/x1000/drivers/drv_i2c.h new file mode 100644 index 0000000000000000000000000000000000000000..de7062b6db5be33dcb052a8231f9a12837343c1b --- /dev/null +++ b/bsp/x1000/drivers/drv_i2c.h @@ -0,0 +1,4 @@ +#ifndef DRV_I2C_H__ +#define DRV_I2C_H__ + +#endif diff --git a/bsp/x1000/driver/drv_ost.c b/bsp/x1000/drivers/drv_ost.c similarity index 84% rename from bsp/x1000/driver/drv_ost.c rename to bsp/x1000/drivers/drv_ost.c index 181f72d6e1a6fe2bf37e829511b67e071591fb8f..ac07ae40d7f730f2503cdca0a10b2c3a1f96fe99 100644 --- a/bsp/x1000/driver/drv_ost.c +++ b/bsp/x1000/drivers/drv_ost.c @@ -44,7 +44,7 @@ void rt_hw_ost_handler(void) REG_OSTFR = 0; } -void rt_hw_ost_init(void) +int rt_hw_ost_init(void) { rt_uint32_t cnt, div; struct clk *clk; @@ -76,4 +76,19 @@ void rt_hw_ost_init(void) REG_OSTESR = 0x01; clk_put(clk); + + return 0; +} + +#include +int ost(int argc, char** argv) +{ + rt_kprintf("OSTCCR = 0x%08x\n", REG_OSTCCR); + rt_kprintf("OSTER = 0x%08x\n", REG_OSTER); + rt_kprintf("count = 0x%08x\n", REG_OST1CNT); + + rt_kprintf("TCU_TER = 0x%08x\n", REG_TCU_TER); + + return 0; } +MSH_CMD_EXPORT(ost, ost debug); diff --git a/bsp/x1000/driver/drv_ost.h b/bsp/x1000/drivers/drv_ost.h similarity index 99% rename from bsp/x1000/driver/drv_ost.h rename to bsp/x1000/drivers/drv_ost.h index 418ddae34ffdc68004c5d004f195350bde3ff4c4..be45934cfd7551d15b131e40350b1c99cf753958 100644 --- a/bsp/x1000/driver/drv_ost.h +++ b/bsp/x1000/drivers/drv_ost.h @@ -137,6 +137,6 @@ #define OST_DIV4 (0x1) #define OST_DIV16 (0x2) -void rt_hw_ost_init(void); +int rt_hw_ost_init(void); #endif diff --git a/bsp/x1000/drivers/drv_pin.c b/bsp/x1000/drivers/drv_pin.c new file mode 100644 index 0000000000000000000000000000000000000000..e132f8f52890685687ca950125f9639450086f01 --- /dev/null +++ b/bsp/x1000/drivers/drv_pin.c @@ -0,0 +1,97 @@ +/* + * File : drv_pin.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017-01-01 Urey first version + */ + +#include +#include +#include +#include "drv_gpio.h" + +#define CORE_BOARD_PIN_NUMBERS 94 //Halley2 + +#define __X1000_PIN(index, port, pin) { 0, GPIO_PORT_##port, GPIO_Pin_##pin} +#define __X1000_PIN_DEFAULT {-1, 0, 0} + + +struct pin_index +{ + int index; + uint32_t port; + uint32_t pin; +}; + + +static const struct pin_index pins[] = +{ + __X1000_PIN_DEFAULT, //0 NULL + __X1000_PIN_DEFAULT, //1 RST + __X1000_PIN(2,B,26), + __X1000_PIN(3,B,25), + + __X1000_PIN_DEFAULT, + __X1000_PIN_DEFAULT, + __X1000_PIN_DEFAULT, + __X1000_PIN_DEFAULT, + __X1000_PIN_DEFAULT, + __X1000_PIN_DEFAULT, + __X1000_PIN_DEFAULT, + __X1000_PIN_DEFAULT, + __X1000_PIN_DEFAULT, + __X1000_PIN_DEFAULT, + __X1000_PIN_DEFAULT, + __X1000_PIN_DEFAULT, + __X1000_PIN_DEFAULT, + + __X1000_PIN(17,B,7), + __X1000_PIN(18,B,6), + __X1000_PIN(19,B,10), + + __X1000_PIN(20,B,9), + __X1000_PIN(21,B,8), + __X1000_PIN(22,B,13), + __X1000_PIN(23,B,11), + __X1000_PIN(24,B,12), + __X1000_PIN(25,B,15), + __X1000_PIN(26,B,14), + __X1000_PIN(27,B,16), + __X1000_PIN(28,A,1), + __X1000_PIN(29,A,0), + __X1000_PIN(30,B,18), + __X1000_PIN(31,A,3), + __X1000_PIN(32,A,2), + __X1000_PIN_DEFAULT, + __X1000_PIN_DEFAULT, + __X1000_PIN_DEFAULT, + __X1000_PIN_DEFAULT, + __X1000_PIN(37,A,4), + __X1000_PIN(38,A,6), + __X1000_PIN(39,B,17), + __X1000_PIN(40,B,20), + __X1000_PIN(41,A,5), + __X1000_PIN(42,A,7), + __X1000_PIN(43,A,8), + __X1000_PIN(44,A,9), + __X1000_PIN(45,A,11), + __X1000_PIN(46,B,19), + __X1000_PIN(47,A,10), +}; diff --git a/bsp/x1000/drivers/drv_pmu.c b/bsp/x1000/drivers/drv_pmu.c new file mode 100644 index 0000000000000000000000000000000000000000..4ef5f518fe35e2c2a883e7db32efbb1f7f392817 --- /dev/null +++ b/bsp/x1000/drivers/drv_pmu.c @@ -0,0 +1,252 @@ +/* + * File : drv_pmu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2016-03-29 Urey the first version + */ + +#include +#include +#include + +#include + +#include "board.h" +#include "drv_clock.h" +#include "drv_gpio.h" +#include "drv_ost.h" +#include "drv_rtc.h" + +struct sleep_save_register +{ + unsigned int lcr; + unsigned int opcr; + unsigned int sleep_voice_enable; + unsigned int ddr_training_space[20]; +}; + +static struct sleep_save_register s_reg; + + +static void write_aic_register(unsigned int addr,unsigned char val) +{ + while(REG_ICDC_RGADW & (1 << 16)); + REG_ICDC_RGADW = (1 << 16) | (addr << 8) | val; +} + + +static void _delay_us(rt_uint32_t ns) +{ + volatile rt_uint16_t delay; + + while(ns--) + { + delay = 200; + while(delay--); + } +} + +static void _delay_ms(rt_uint32_t ms) +{ + volatile rt_uint16_t delay; + + while(ms--) + { + _delay_us(1000); + } +} + +#if 0 +static int jz_pm_do_sleep(void) +{ + unsigned int div; + unsigned long opcr = REG_CPM_OPCR; + unsigned long icmr0 = REG_INTC_IMCR(0); + unsigned long icmr1 = REG_INTC_IMCR(1); + unsigned long sleep_gpio_save[5*(GPIO_NR_PORTS)]; + unsigned long cpuflags; + unsigned long msc0cdr = REG_CPM_MSC0CDR; + void (*resume_addr)(void); + unsigned int val; + unsigned int gint_mask = REG_GINT_MASK; + unsigned int level = rt_hw_interrupt_disable(); + unsigned int clkgr0 = REG_CPM_CLKGR0; + /* set SLEEP mode */ + //CMSREG32(CPM_LCR, LCR_LPM_SLEEP, LCR_LPM_MASK); + + REG_CPM_CLKGR0 &= ~(1 << 11); + write_aic_register(0x13, 0x10); + write_aic_register(0xd, 0xb1); + write_aic_register(0xe, 0xb5); + + *(volatile unsigned int *)0xb000003c |= (1 << 25) | (1 << 21) | (1 << 20); + REG_CPM_CLKGR0 = 0x0fdefff7; + + /* Mask all interrupts */ + REG_INTC_IMCR(0) = 0xffffffff; + REG_INTC_IMCR(1) = 0xffffffff; + + REG_GINT_MASK = 0; + REG_GINT_MASK = 1 << 31; + *((volatile unsigned int *)(0xb2000038)) = 1; + /* OUTREG32(INTC_ICMCR(0), 0xffffffff); */ + /* /\* unmask rtc interrupts *\/ */ + /* OUTREG32(INTC_ICMCR(1), 0x1); */ + /* Sleep on-board modules */ + jzsoc_do_sleep(sleep_gpio_save); + + /* config_irq_wakeup(); */ + + load_pm_firmware_new(SLEEP_TCSM_SPACE); + sleep_param = (struct sleep_param *)SLEEP_TCSM_SPACE; + + sleep_param->post_resume_pc = (unsigned int)restore_goto; + sleep_param->uart_id = 2; + + memcpy(&s_reg.ddr_training_space,(void*)0x80000000,sizeof(s_reg.ddr_training_space)); + s_reg.opcr = INREG32(CPM_OPCR); + s_reg.lcr = INREG32(CPM_LCR); + + /* + * set OPCR. + */ + val = s_reg.opcr; +#if 0 + val &= ~((1 << 25) | (1 << 22) | (0xfff << 8) | (1 << 7) | (1 << 6) | (1 << 4) | (1 << 3) | (1 << 2)); + val |= (1 << 31) | (1 << 30) | (1 << 25) | (1 << 23) | (0xfff << 8) | (1 << 4) | (1 << 3) | (1 << 2); +#else + val &= ~((1 << 31)|(1 << 30)| (1 << 25) | (1 << 22) | (0xfff << 8) | (1 << 7) | (1 << 6) | (1 << 4) | (1 << 3) | (1 << 2)); + val |= (1 << 25) | (1 << 23) | (0xfff << 8) | (1 << 3) | (1 << 2) | (1 << 4); +#endif + REG_CPM_OPCR = val; + *(volatile unsigned int *)0xb000003c &= ~(1 << 31); + *(volatile unsigned int *)0xb000003c |= (1 << 20); + + val = s_reg.lcr; + val &= ~3; + //val |= 1; + val |= 0xff << 8; /* power stable time */ + REG_CPM_LCR = val; + +// *(volatile unsigned int *)0xb0000010 &= ~(1 << 8); +// *(volatile unsigned int *)0xb0000014 &= ~(1 << 7); + + printf("clkgr = 0x%08x\n", *(volatile unsigned int *)0xb0000020); + printf("opcr = 0x%08x\n", *(volatile unsigned int *)0xb0000024); + printf("otg phy = 0x%08x\n", *(volatile unsigned int *)0xb0000048); + printf("otg = 0x%08x\n", *(volatile unsigned int *)0xb0000050); + mb(); + save_goto((unsigned int)sleep_param->pm_core_enter); + mb(); + + memcpy((void*)0x80000000,&s_reg.ddr_training_space,sizeof(s_reg.ddr_training_space)); + dma_cache_wback_inv(0x80000000,sizeof(s_reg.ddr_training_space)); + + OUTREG32(CPM_LCR, s_reg.lcr); + OUTREG32(CPM_OPCR, s_reg.opcr); + + spin_unlock_irqrestore(sr); + + REG_GINT_MASK = gint_mask; + /* Restore interrupts */ + + //*((volatile unsigned int *)(0xb2000008)) = 1; + REG_CPM_CLKGR0 = clkgr0; + + *((volatile unsigned int *)(0xb2000034)) = 1; + OUTREG32(INTC_ICMR(0), icmr0); + OUTREG32(INTC_ICMR(1), icmr1); + + /* Resume on-board modules */ + jzsoc_do_resume(sleep_gpio_save); + + /* Restore Oscillator and Power Control Register */ + /* OUTREG32(CPM_OPCR, opcr); */ + return 0; +} +#endif +/* + * Function: Keep power for CPU core when reset. + * So that EPC, tcsm and so on can maintain it's status after reset-key pressed. + */ +int reset_keep_power(void) +{ + rtc_write_reg(RTC_BASE + RTC_PWRONCR, rtc_read_reg(RTC_BASE + RTC_PWRONCR) & ~(1 << 0)); + + return 0; +} + +int drv_pmu_get_keypwr(void) +{ + int level = 0; + +#ifdef BOARD_CANNA_OVC + level = gpio_get_value(DET_PWR_PORT,DET_PWR_PIN); + do + { + _delay_ms(5); //去抖 + }while(level != gpio_get_value(DET_PWR_PORT,DET_PWR_PIN)); +#endif + + return level; +} + +void drv_pmu_power_down(void) +{ +#ifdef BOARD_CANNA_OVC + rt_kprintf("SET STB down...\n"); + + gpio_set_value(EXT_DEV_RST_PORT, EXT_DEV_RST_PIN, 0); + gpio_direction_output(CTR_STB_PORT, CTR_STB_PIN, 0); + _delay_ms(100); + gpio_direction_output(CTR_LOCK_PORT, CTR_LOCK_PIN, 1); + _delay_ms(100); + + rt_hw_led_off(LED_GREEN); + rt_hw_led_off(LED_RED); + rt_hw_led_off(LED_BLUE); +#endif +} + +void drv_pmu_power_up(void) +{ + +} + +int drv_pmu_init(void) +{ + volatile unsigned int lcr, opcr; + + /* init opcr and lcr for idle */ + lcr = cpm_inl(CPM_LCR); + lcr &= ~(0x3); /* LCR.SLEEP.DS=0'b0,LCR.LPM=1'b00*/ + lcr |= 0xff << 8; /* power stable time */ + cpm_outl(lcr, CPM_LCR); + + opcr = cpm_inl(CPM_OPCR); + opcr |= 0xff << 8; /* EXCLK stable time */ + opcr &= ~(1 << 4); /* EXCLK stable time */ + cpm_outl(opcr, CPM_OPCR); + + return 0; +} + + + diff --git a/bsp/x1000/driver/board_io.c b/bsp/x1000/drivers/drv_pmu.h similarity index 76% rename from bsp/x1000/driver/board_io.c rename to bsp/x1000/drivers/drv_pmu.h index 2994fdd2b2f27ea8756c4dc4e2f7000ea7188d66..c3d0b0f2798f4cebd428ddb49eee60356591556c 100644 --- a/bsp/x1000/driver/board_io.c +++ b/bsp/x1000/drivers/drv_pmu.h @@ -1,5 +1,5 @@ /* - * File : board_io.c + * File : drv_pmu.h * This file is part of RT-Thread RTOS * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team * @@ -19,9 +19,14 @@ * * Change Logs: * Date Author Notes - * 2015-11-19 Urey the first version + * 2016-08-08 Urey the first version */ -#include -#include -#include "drv_gpio.h" +#ifndef DRIVER_DRV_PMU_H_ +#define DRIVER_DRV_PMU_H_ + +int drv_pmu_init(void); +void drv_pmu_power_up(void); +void drv_pmu_power_down(void); +int drv_pmu_get_keypwr(void); +#endif /* DRIVER_DRV_PMU_H_ */ diff --git a/bsp/x1000/drivers/drv_reset.c b/bsp/x1000/drivers/drv_reset.c new file mode 100644 index 0000000000000000000000000000000000000000..946cd79d7e23b6e5a3d0874d65404f1914b5ebbe --- /dev/null +++ b/bsp/x1000/drivers/drv_reset.c @@ -0,0 +1,355 @@ +/* + * File : drv_reset.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2016年7月29日 Urey the first version + */ + + +#include +#include +#include +#include + +#include "board.h" +#include "drv_clock.h" +#include "drv_ost.h" +#include "drv_pmu.h" +#include "drv_rtc.h" + +static void udelay(uint32_t x) +{ + volatile uint32_t n = 1000; + + while(x--) + { + for (n = 0; n < 1000; ++n); + } +} + +static void mdelay(uint32_t x) +{ + while(x--) + udelay(1000); +} + +#define RECOVERY_SIGNATURE (0x001a1a) +#define REBOOT_SIGNATURE (0x003535) +#define UNMSAK_SIGNATURE (0x7c0000)//do not use these bits + + +void wdt_start_count(int msecs) +{ + int time = BOARD_RTC_CLK / 64 * msecs / 1000; + if(time > 65535) + time = 65535; + + writel(1 << 16,TCU_BASE + TCU_TSCR); + + writel(0,WDT_BASE + WDT_TCNT); //counter + writel(time,WDT_BASE + WDT_TDR); //data + writel((3<<3 | 1<<1),WDT_BASE + WDT_TCSR); + writel(0,WDT_BASE + WDT_TCER); + writel(1,WDT_BASE + WDT_TCER); +} + + +void wdt_stop_count(void) +{ + writel(1 << 16,TCU_BASE + TCU_TSCR); + writel(0,WDT_BASE + WDT_TCNT); //counter + writel(65535,WDT_BASE + WDT_TDR); //data + writel(1 << 16,TCU_BASE + TCU_TSSR); +} + +void wdt_clear(void) +{ + writel(0,WDT_BASE + WDT_TCNT); +} + + +/* + * Function: Keep power for CPU core when reset. + * So that EPC, tcsm and so on can maintain it's status after reset-key pressed. + */ +static int inline reset_keep_power(void) +{ + rtc_write_reg(RTC_BASE + RTC_PWRONCR, rtc_read_reg(RTC_BASE + RTC_PWRONCR) & ~(1 << 0)); + + return 0; +} + + +void x1000_hibernate(void) +{ + uint32_t rtc_rtccr; + rt_base_t level; + + wdt_stop_count(); + level = rt_hw_interrupt_disable(); + + /* Set minimum wakeup_n pin low-level assertion time for wakeup: 1000ms */ + rtc_write_reg(RTC_BASE + RTC_HWFCR, HWFCR_WAIT_TIME(1000)); + + /* Set reset pin low-level assertion time after wakeup: must > 60ms */ + rtc_write_reg(RTC_BASE + RTC_HRCR, HRCR_WAIT_TIME(125)); + + /* clear wakeup status register */ + rtc_write_reg(RTC_BASE + RTC_HWRSR, 0x0); + + rtc_write_reg(RTC_BASE + RTC_HWCR, 0x8); + + /* Put CPU to hibernate mode */ + rtc_write_reg(RTC_BASE + RTC_HCR, 0x1); + + /*poweroff the pmu*/ +// jz_notifier_call(NOTEFY_PROI_HIGH, JZ_POST_HIBERNATION, NULL); + + rtc_rtccr = rtc_read_reg(RTC_BASE + RTC_RTCCR); + rtc_rtccr |= 0x1 << 0; + rtc_write_reg(RTC_BASE + RTC_RTCCR,rtc_rtccr); + + mdelay(200); + + while(1) + { + rt_kprintf("%s:We should NOT come here.%08x\n",__func__, rtc_read_reg(RTC_BASE + RTC_HCR)); + } +} + +void x1000_wdt_restart(char *command) +{ + rt_kprintf("Restarting after 4 ms\n"); + + if ((command != NULL) && !strcmp(command, "recovery")) + { + while (cpm_inl(CPM_CPPSR) != RECOVERY_SIGNATURE) + { + rt_kprintf("set RECOVERY_SIGNATURE\n"); + cpm_outl(0x5a5a, CPM_CPSPPR); + cpm_outl(RECOVERY_SIGNATURE, CPM_CPPSR); + cpm_outl(0x0, CPM_CPSPPR); + udelay(100); + } + } + else + { + //WDT... + cpm_outl(0x5a5a, CPM_CPSPPR); + cpm_outl(REBOOT_SIGNATURE, CPM_CPPSR); + cpm_outl(0x0, CPM_CPSPPR); + } + + wdt_start_count(4); + mdelay(200); + while(1) + rt_kprintf("check wdt.\n"); +} + +void x1000_hibernate_restart(char *command) +{ + rt_base_t level; + uint32_t rtc_rtcsr,rtc_rtccr; + + level = rt_hw_interrupt_disable(); + + if ((command != NULL) && !strcmp(command, "recovery")) + { + x1000_wdt_restart(command); + } + + /* hibernate_restart */ + while(!(rtc_read_reg(RTC_BASE + RTC_RTCCR) & RTCCR_WRDY)); + + rtc_rtcsr = rtc_read_reg(RTC_BASE + RTC_RTCSR); + rtc_rtccr = rtc_read_reg(RTC_BASE + RTC_RTCCR); + + rtc_write_reg(RTC_RTCSAR,rtc_rtcsr + 5); + rtc_rtccr &= ~(1 << 4 | 1 << 1); + rtc_rtccr |= 0x3 << 2; + rtc_write_reg(RTC_BASE + RTC_RTCCR,rtc_rtccr); + + /* Clear reset status */ + cpm_outl(0,CPM_RSR); + + /* Set minimum wakeup_n pin low-level assertion time for wakeup: 1000ms */ + rtc_write_reg(RTC_BASE + RTC_HWFCR, HWFCR_WAIT_TIME(1000)); + + /* Set reset pin low-level assertion time after wakeup: must > 60ms */ + rtc_write_reg(RTC_BASE + RTC_HRCR, HRCR_WAIT_TIME(125)); + + /* clear wakeup status register */ + rtc_write_reg(RTC_BASE + RTC_HWRSR, 0x0); + + rtc_write_reg(RTC_BASE + RTC_HWCR, 0x9); + /* Put CPU to hibernate mode */ + rtc_write_reg(RTC_BASE + RTC_HCR, 0x1); + + rtc_rtccr = rtc_read_reg(RTC_BASE + RTC_RTCCR); + rtc_rtccr |= 0x1 << 0; + rtc_write_reg(RTC_BASE + RTC_RTCCR,rtc_rtccr); + + mdelay(200); + while(1) + rt_kprintf("%s:We should NOT come here.%08x\n",__func__, rtc_read_reg(RTC_BASE + RTC_HCR)); +} + +uint32_t x1000_get_last_reset(void) +{ + return (cpm_inl(CPM_RSR) & 0x0000000F); +} + +/* ============================wdt control proc end =============================== */ +/* ============================reset proc=================================== */ +const char *reset_command[] = {"wdt","hibernate","recovery"}; +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +int x1000_reset(const char *reset_cmd) +{ + rt_base_t level; + int command_size = 0; + int i; + + command_size = ARRAY_SIZE(reset_command); + for (i = 0; i < command_size; i++) + { + if (!strncmp(reset_cmd, reset_command[i], strlen(reset_command[i]))) + break; + } + + if(i == command_size) + return -RT_ERROR; + + level = rt_hw_interrupt_disable(); + switch(i) + { + case 0: + x1000_wdt_restart("wdt"); + break; + case 1: + x1000_hibernate_restart("hibernate"); + break; + case 2: + x1000_wdt_restart("recovery"); + break; + default: + rt_kprintf("not support command %d\n", i); + } + + rt_hw_interrupt_enable(level); + return RT_EOK; +} + + +struct wdt_reset +{ + int msecs; +}; + + +static struct wdt_reset _wdt_param = +{ + .msecs = 1000, +}; + +rt_err_t _wdt_init(rt_watchdog_t *wdt) +{ + return RT_EOK; +} + +rt_err_t _wdt_control(rt_watchdog_t *wdt, int cmd, void *arg) +{ + switch (cmd) + { + case RT_DEVICE_CTRL_WDT_SET_TIMEOUT: + { + int msecs = *(int *)arg * 1000; + + if(msecs < 1000) msecs = 1000; + if(msecs > 30000) msecs = 30000; + + _wdt_param.msecs = msecs; + + rt_kprintf("WDT timeout = %d\n",msecs); + } + break; + case RT_DEVICE_CTRL_WDT_START: + wdt_start_count(_wdt_param.msecs + 1000); + break; + case RT_DEVICE_CTRL_WDT_STOP: + wdt_stop_count(); + break; + case RT_DEVICE_CTRL_WDT_KEEPALIVE: + wdt_clear(); + break; + default: + break; + } + return RT_EOK; +} + +const struct rt_watchdog_ops _wdt_ops = +{ + .init = _wdt_init, + .control = _wdt_control +}; + +static struct rt_watchdog_device _wdt_device = +{ + .ops = (struct rt_watchdog_ops *)&_wdt_ops, +}; + +int reboot(void) +{ + rt_hw_cpu_reset(); + + return 0; +} +MSH_CMD_EXPORT(reboot,reboot system...); + +int shutdown(void) +{ + rt_hw_cpu_shutdown(); +} +MSH_CMD_EXPORT(shutdown,shutdown system...); + +int rt_hw_wdt_init(void) +{ + rt_hw_watchdog_register(&_wdt_device,"WDT",RT_DEVICE_FLAG_STANDALONE,&_wdt_param); + + return 0; +} +INIT_DEVICE_EXPORT(rt_hw_wdt_init); + +void rt_hw_cpu_reset() +{ + /* Disable Base_board */ + drv_pmu_power_down(); + + x1000_reset("wdt"); +} + +void rt_hw_cpu_shutdown() +{ + /* Disable Base_board */ + drv_pmu_power_down(); + + x1000_hibernate(); +} diff --git a/bsp/x1000/applications/mnt.c b/bsp/x1000/drivers/drv_reset.h similarity index 57% rename from bsp/x1000/applications/mnt.c rename to bsp/x1000/drivers/drv_reset.h index df6be29b40d367dc6640a1e5e96d83db1aa0536f..8eb340d65eb86b00d120876f5b5ab8d96b2fc900 100644 --- a/bsp/x1000/applications/mnt.c +++ b/bsp/x1000/drivers/drv_reset.h @@ -1,7 +1,7 @@ /* - * File : mnt.c + * File : drv_reset.h * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,29 +19,31 @@ * * Change Logs: * Date Author Notes - * 2015-11-19 Urey the first version + * 2016年7月29日 Urey the first version */ -#include -#include - -#include - -int mnt_init(void) -{ -#ifdef RT_USING_SDIO - jz47xx_sdio_init(); - rt_thread_delay(RT_TICK_PER_SECOND * 1); - - /* mount sd card fat partition 1 as root directory */ - if (dfs_mount("sd0", "/", "elm", 0, 0) == 0) - { - rt_kprintf("File System initialized!\n"); - } - else - { - rt_kprintf("File System initialzation failed!\n"); - } -#endif -} -INIT_ENV_EXPORT(mnt_init); +#ifndef _DRV_RESET_H_ +#define _DRV_RESET_H_ + +/* WDT */ +void wdt_start_count(int msecs); +void wdt_stop_count(void); +void wdt_clear(void); + +/* hibernate */ +void x1000_hibernate(void); + + +/* Reset */ +/* reset_cmd[] = "wdt","hibernate","recovery" */ +int x1000_reset(const char *reset_cmd); + + +#define RESET_HR_BIT (0x01 << 3) +#define RESET_P0R_BIT (0x01 << 2) +#define RESET_WR_BIT (0x01 << 1) +#define RESET_PR_BIT (0x01 << 0) +uint32_t x1000_get_last_reset(void); + + +#endif /* _DRV_RESET_H_ */ diff --git a/bsp/x1000/drivers/drv_rtc.c b/bsp/x1000/drivers/drv_rtc.c new file mode 100644 index 0000000000000000000000000000000000000000..b5badcde6bed737d4bca848ae697857989672e15 --- /dev/null +++ b/bsp/x1000/drivers/drv_rtc.c @@ -0,0 +1,196 @@ +/* + * File : drv_rtc.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2016/7/28 Urey the first version + */ + +#include +#include +#include + +#include +#include +#include + +#include "board.h" +#include "drv_clock.h" +#include "drv_gpio.h" +#include "drv_ost.h" +#include "drv_rtc.h" + +static rt_base_t rtc32k_ref = 0; + +void rtc32k_enable(void) +{ + if(++rtc32k_ref == 1) + gpio_set_func(GPIO_PORT_B,GPIO_Pin_26,GPIO_FUNC_0); +} + + +void rtc32k_disable(void) +{ + if(--rtc32k_ref == 0) + gpio_set_func(GPIO_PORT_B,GPIO_Pin_26,GPIO_INPUT); +} + +#if 0 /* not enable */ +static void jz_rtc_interrupt(int vector,void *param) +{ + if (rtc_read_reg(RTC_RTCCR) & RTC_RTCCR_AF) /* rtc alarm interrupt */ + { + rtc_clr_reg(RTC_RTCCR, RTC_RTCCR_AF); + +#ifdef AHB_MONITOR_PERIOD + // Stop and log the data, and the 1st of the data is INVALID. + MONITOR_LOG(); + // Start the monitor. + MONITOR_START(MASTER_IPU, MEVENT_BUS_TRANS_CYCLE, MASTER_ALL, MEVENT_BUS_TRANS_CYCLE); + + // Config the RTC alarm for the next time + rtc_write_reg(RTC_RTCSAR, rtc_read_reg(RTC_RTCSR) + AHB_MONITOR_PERIOD); +#else + printf("RTC alarm interrupt clean!\n"); + rtc_alarm_handler(); +#endif + } + else + { + rtc_clr_reg(RTC_RTCCR, RTC_RTCCR_1HZ); + } +} +#endif + +void jz_rtc_init(void) +{ + unsigned int tmpx , flag; + + tmpx = rtc_read_reg(RTC_BASE + RTC_HSPR); + flag = rtc_read_reg(RTC_BASE + RTC_RTCGR) & RTC_RTCGR_NC1HZ_MASK; + if((tmpx != COLD_BOOT_SIG) || (flag != RTCGR_DIV_1HZ)) + { + rt_kprintf("rtc is not configured\n"); + rt_kprintf("please configure with set_date and set_time\n"); + + rtc_write_reg(RTC_BASE + RTC_RTCGR, RTCGR_DIV_1HZ); + rtc_write_reg(RTC_BASE + RTC_HSPR, COLD_BOOT_SIG); + rtc_write_reg(RTC_BASE + RTC_RTCSR, 0x00000000); + rtc_write_reg(RTC_BASE + RTC_RTCSR, 0); + rtc_set_reg(RTC_BASE + RTC_RTCCR, RTC_RTCCR_RTCE); + } + else + { + rt_kprintf("skip init rtc...\n"); + } +} + +void jz_rtc_deinit(void) +{ + rtc_clr_reg(RTC_BASE + RTC_RTCCR, RTC_RTCCR_RTCE); +} + +static rt_err_t rt_rtc_open(rt_device_t dev, rt_uint16_t oflag) +{ + if (dev->rx_indicate != RT_NULL) + { + /* Open Interrupt */ + } + + return RT_EOK; +} + +static rt_size_t rt_rtc_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) +{ + return 0; +} + +static rt_err_t rt_rtc_control(rt_device_t dev, int cmd, void *args) +{ + time_t *time; + RT_ASSERT(dev != RT_NULL); + + switch (cmd) + { + case RT_DEVICE_CTRL_RTC_GET_TIME: + { + const struct tm* tm_now; + struct tm tm_new; + time_t timeNow; + time = (time_t *)args; + + /* Get the current Time */ + timeNow = rtc_read_reg(RTC_BASE + RTC_RTCSR); + tm_now = localtime(&timeNow); + + /* 0-99 range : Years since 1900 */ + rt_memcpy(&tm_new,tm_now,sizeof(struct tm)); + tm_new.tm_year = tm_now->tm_year + 2000 - 1900; + + *time = mktime(&tm_new); + } + break; + + case RT_DEVICE_CTRL_RTC_SET_TIME: + { + const struct tm* tm_now; + struct tm tm_new; + time_t timeNow; + + time = (time_t *)args; + tm_now = localtime(time); + + rt_memcpy(&tm_new,tm_now,sizeof(struct tm)); + + /* 0-99 range : Years since 1900 */ + tm_new.tm_year = tm_now->tm_year + 1900 - 2000; + + timeNow = mktime(&tm_new); + + /* upgrade the current Time */ + rtc_write_reg(RTC_BASE + RTC_RTCSR,timeNow); + } + break; + } + + return RT_EOK; +} + + +int rt_hw_rtc_init(void) +{ + static struct rt_device rtc; + + jz_rtc_init(); + + rtc.type = RT_Device_Class_RTC; + /* register rtc device */ + rtc.init = RT_NULL; + rtc.open = rt_rtc_open; + rtc.close = RT_NULL; + rtc.read = rt_rtc_read; + rtc.write = RT_NULL; + rtc.control = rt_rtc_control; + + /* no private */ + rtc.user_data = RT_NULL; + + rt_device_register(&rtc, "rtc", RT_DEVICE_FLAG_RDWR); +} +INIT_DEVICE_EXPORT(rt_hw_rtc_init); diff --git a/bsp/x1000/drivers/drv_rtc.h b/bsp/x1000/drivers/drv_rtc.h new file mode 100644 index 0000000000000000000000000000000000000000..725668fa703efb631569a75a1ebaf81e44ba7b02 --- /dev/null +++ b/bsp/x1000/drivers/drv_rtc.h @@ -0,0 +1,205 @@ +/* + * drv_rtc.h + * + * Created on: 2016年12月9日 + * Author: Urey + */ + +#ifndef _DRV_RTC_H_ +#define _DRV_RTC_H_ + +#include +#include "x1000.h" + +#ifndef RTC_BASE +#define RTC_BASE 0xB0003000 +#endif + +/************************************************************************* + * RTC + *************************************************************************/ + +#define REG_RTC_RTCCR REG32(RTC_BASE + RTC_RTCCR) +#define REG_RTC_RTCSR REG32(RTC_BASE + RTC_RTCSR) +#define REG_RTC_RTCSAR REG32(RTC_BASE + RTC_RTCSAR) +#define REG_RTC_RTCGR REG32(RTC_BASE + RTC_RTCGR) +#define REG_RTC_HCR REG32(RTC_BASE + RTC_HCR) +#define REG_RTC_HWFCR REG32(RTC_BASE + RTC_HWFCR) +#define REG_RTC_HRCR REG32(RTC_BASE + RTC_HRCR) +#define REG_RTC_HWCR REG32(RTC_BASE + RTC_HWCR) +#define REG_RTC_HWRSR REG32(RTC_BASE + RTC_HWRSR) +#define REG_RTC_HSPR REG32(RTC_BASE + RTC_HSPR) +#define REG_RTC_WENR REG32(RTC_BASE + RTC_WENR) +#define REG_RTC_CKPCR REG32(RTC_BASE + RTC_CKPCR) +#define REG_RTC_OWIPCR REG32(RTC_BASE + RTC_OWIPCR) +#define REG_RTC_PWRONCR REG32(RTC_BASE + RTC_PWRONCR) + +#define COLD_BOOT_SIG 0x12345678 + +/* RTC Control Register */ +#define RTC_RTCCR_WRDY_BIT 7 +#define RTC_RTCCR_WRDY (1 << RTC_RTCCR_WRDY_BIT) /* Write Ready Flag */ +#define RTC_RTCCR_1HZ_BIT 6 +#define RTC_RTCCR_1HZ (1 << RTC_RTCCR_1HZ_BIT) /* 1Hz Flag */ +#define RTC_RTCCR_1HZIE_BIT 5 +#define RTC_RTCCR_1HZIE (1 << RTC_RTCCR_1HZIE_BIT) /* 1Hz Interrupt Enable */ +#define RTC_RTCCR_AF_BIT 4 +#define RTC_RTCCR_AF (1 << RTC_RTCCR_AF_BIT) /* Alarm Flag */ +#define RTC_RTCCR_AIE_BIT 3 +#define RTC_RTCCR_AIE (1 << RTC_RTCCR_AIE_BIT) /* Alarm Interrupt Enable */ +#define RTC_RTCCR_AE_BIT 2 +#define RTC_RTCCR_AE (1 << RTC_RTCCR_AE_BIT) /* Alarm Enable */ +#define RTC_RTCCR_SELEXC_BIT 1 +#define RTC_RTCCR_SELEXC (1 << RTC_RTCCR_SELEXC_BIT) +#define RTC_RTCCR_RTCE_BIT 0 +#define RTC_RTCCR_RTCE (1 << RTC_RTCCR_RTCE_BIT) /* RTC Enable */ + +/* RTC Regulator Register */ +#define RTC_RTCGR_LOCK (1 << 31) /* Lock Bit */ +#define RTC_RTCGR_ADJC_BIT 16 +#define RTC_RTCGR_ADJC_MASK (0x3ff << RTC_RTCGR_ADJC_BIT) +#define RTC_RTCGR_NC1HZ_BIT 0 +#define RTC_RTCGR_NC1HZ_MASK (0xffff << RTC_RTCGR_NC1HZ_BIT) +#define RTCGR_DIV_1HZ ((32767 << RTC_RTCGR_NC1HZ_BIT) & RTC_RTCGR_NC1HZ_MASK ) + +/* Hibernate Control Register */ +#define RTC_HCR_PD (1 << 0) /* Power Down */ + +/* Hibernate Wakeup Filter Counter Register */ +#define RTC_HWFCR_BIT 5 +#define RTC_HWFCR_MASK (0x7ff << RTC_HWFCR_BIT) +#define HWFCR_WAIT_TIME(ms) (((ms) << RTC_HWFCR_BIT) > RTC_HWFCR_MASK ? RTC_HWFCR_MASK : ((ms) << RTC_HWFCR_BIT)) + +/* Hibernate Reset Counter Register */ +#define RTC_HRCR_BIT 5 +#define RTC_HRCR_MASK (0x7f << RTC_HRCR_BIT) +#define HRCR_WAIT_TIME(ms) (((ms) << RTC_HRCR_BIT) > RTC_HRCR_MASK ? RTC_HRCR_MASK : ((ms) << RTC_HRCR_BIT)) + +/* Hibernate Wakeup Control Register */ +#define RTC_HWCR_EALM (1 << 0) /* RTC alarm wakeup enable */ + +/* Hibernate Wakeup Status Register */ +#define RTC_HWRSR_HR (1 << 5) /* Hibernate reset */ +#define RTC_HWRSR_PPR (1 << 4) /* PPR reset */ +#define RTC_HWRSR_PIN (1 << 1) /* Wakeup pin status bit */ +#define RTC_HWRSR_ALM (1 << 0) /* RTC alarm status bit */ + +/* Write Enable Pattern Register */ +#define RTC_WENR_WEN (1 << 31) /* The write enable flag */ +#define RTC_WENR_WENPAT_BIT 0 +#define RTC_WENR_WENPAT_MASK (0xffff << RTC_WENR_WENPAT_BIT) +#define WENR_WENPAT_WRITABLE (0xa55a) + +/* CLK32K Pin Control Register */ +#define RTC_CKPCR_CK32RD (1 << 5) /* Read this bit will return CLK32K pin status. */ +#define RTC_CKPCR_CK32PULL (1 << 4) /* Pull up configures. */ +#define RTC_CKPCR_CK32CTL_BIT 1 +#define RTC_CKPCR_CK32CTL_MASK (0x3 << RTC_CKPCR_CK32CTL_BIT) +#define RTC_CKPCR_CK32D (1 << 0) + +/* Power Monitor Register */ +#define RTC_PMCR_NBF (1 << 0) /* No RTC battery flag */ + +/* Hibernate scratch pattern register(HSPR) */ +#define HSPR_RTCV 0x52544356 /* The value is 'RTCV', means rtc is valid */ + +#ifndef __ASSEMBLER__ +/*************************************************************************** + * RTC ops + ***************************************************************************/ + +#define __rtc_write_ready() ( (REG_RTC_RTCCR & RTC_RTCCR_WRDY) >> RTC_RTCCR_WRDY_BIT ) +#define __rtc_enabled() ( REG_RTC_RTCCR |= RTC_RTCCR_RTCE ) +#define __rtc_disabled() ( REG_RTC_RTCCR &= ~RTC_RTCCR_RTCE ) +#define __rtc_enable_alarm() ( REG_RTC_RTCCR |= RTC_RTCCR_AE ) +#define __rtc_disable_alarm() ( REG_RTC_RTCCR &= ~RTC_RTCCR_AE ) +#define __rtc_enable_alarm_irq() ( REG_RTC_RTCCR |= RTC_RTCCR_AIE ) +#define __rtc_disable_alarm_irq() ( REG_RTC_RTCCR &= ~RTC_RTCCR_AIE ) +#define __rtc_enable_1Hz_irq() ( REG_RTC_RTCCR |= RTC_RTCCR_1HZIE ) +#define __rtc_disable_1Hz_irq() ( REG_RTC_RTCCR &= ~RTC_RTCCR_1HZIE ) + +#define __rtc_get_1Hz_flag() ( (REG_RTC_RTCCR >> RTC_RTCCR_1HZIE_BIT) & 0x1 ) +#define __rtc_clear_1Hz_flag() ( REG_RTC_RTCCR &= ~RTC_RTCCR_1HZ ) +#define __rtc_get_alarm_flag() ( (REG_RTC_RTCCR >> RTC_RTCCR_AF_BIT) & 0x1 ) +#define __rtc_clear_alarm_flag() ( REG_RTC_RTCCR &= ~RTC_RTCCR_AF ) + +#define __rtc_get_second() ( REG_RTC_RTCSR ) +#define __rtc_set_second(v) ( REG_RTC_RTCSR = v ) + +#define __rtc_get_alarm_second() ( REG_RTC_RTCSAR ) +#define __rtc_set_alarm_second(v) ( REG_RTC_RTCSAR = v ) + +#define __rtc_RGR_is_locked() ( (REG_RTC_RTCGR >> RTC_RTCGR_LOCK) ) +#define __rtc_lock_RGR() ( REG_RTC_RTCGR |= RTC_RTCGR_LOCK ) +#define __rtc_unlock_RGR() ( REG_RTC_RTCGR &= ~RTC_RTCGR_LOCK ) +#define __rtc_get_adjc_val() ( (REG_RTC_RTCGR & RTC_RTCGR_ADJC_MASK) >> RTC_RTCGR_ADJC_BIT ) +#define __rtc_set_adjc_val(v) \ + ( REG_RTC_RTCGR = ( (REG_RTC_RTCGR & ~RTC_RTCGR_ADJC_MASK) | (v << RTC_RTCGR_ADJC_BIT) )) +#define __rtc_get_nc1Hz_val() ( (REG_RTC_RTCGR & RTC_RTCGR_NC1HZ_MASK) >> RTC_RTCGR_NC1HZ_BIT ) +#define __rtc_set_nc1Hz_val(v) \ + ( REG_RTC_RTCGR = ( (REG_RTC_RTCGR & ~RTC_RTCGR_NC1HZ_MASK) | (v << RTC_RTCGR_NC1HZ_BIT) )) + +#define __rtc_power_down() ( REG_RTC_HCR |= RTC_HCR_PD ) + +#define __rtc_get_hwfcr_val() ( REG_RTC_HWFCR & RTC_HWFCR_MASK ) +#define __rtc_set_hwfcr_val(v) ( REG_RTC_HWFCR = (v) & RTC_HWFCR_MASK ) +#define __rtc_get_hrcr_val() ( REG_RTC_HRCR & RTC_HRCR_MASK ) +#define __rtc_set_hrcr_val(v) ( REG_RTC_HRCR = (v) & RTC_HRCR_MASK ) + +#define __rtc_enable_alarm_wakeup() ( REG_RTC_HWCR |= RTC_HWCR_EALM ) +#define __rtc_disable_alarm_wakeup() ( REG_RTC_HWCR &= ~RTC_HWCR_EALM ) + +#define __rtc_status_hib_reset_occur() ( (REG_RTC_HWRSR >> RTC_HWRSR_HR) & 0x1 ) +#define __rtc_status_ppr_reset_occur() ( (REG_RTC_HWRSR >> RTC_HWRSR_PPR) & 0x1 ) +#define __rtc_status_wakeup_pin_waken_up() ( (REG_RTC_HWRSR >> RTC_HWRSR_PIN) & 0x1 ) +#define __rtc_status_alarm_waken_up() ( (REG_RTC_HWRSR >> RTC_HWRSR_ALM) & 0x1 ) +#define __rtc_clear_hib_stat_all() ( REG_RTC_HWRSR = 0 ) + +#define __rtc_get_scratch_pattern() (REG_RTC_HSPR) +#define __rtc_set_scratch_pattern(n) (REG_RTC_HSPR = n ) + + +/* Waiting for the RTC register writing finish */ +#define __wait_write_ready() \ +do { \ + unsigned int timeout = 1; \ + while (!(rtc_read_reg(RTC_BASE + RTC_RTCCR) & RTC_RTCCR_WRDY) && timeout++); \ +}while(0); + +/* Waiting for the RTC register writable */ +#define __wait_writable() \ +do { \ + unsigned int timeout = 1; \ + __wait_write_ready(); \ + jz_writel((RTC_BASE + RTC_WENR), WENR_WENPAT_WRITABLE); \ + __wait_write_ready(); \ + while (!(rtc_read_reg(RTC_BASE + RTC_WENR) & RTC_WENR_WEN) && timeout++); \ +}while(0); + +/* Basic RTC ops */ +#define rtc_read_reg(reg) \ +({ \ + unsigned int data; \ + do { \ + data = jz_readl(reg); \ + } while (jz_readl(reg) != data); \ + data; \ +}) + +#define rtc_write_reg(reg, data) \ +do { \ + __wait_writable(); \ + jz_writel(reg, data); \ + __wait_write_ready(); \ +}while(0); + +#define rtc_set_reg(reg, data) rtc_write_reg(reg, rtc_read_reg(reg) | (data)) +#define rtc_clr_reg(reg, data) rtc_write_reg(reg, rtc_read_reg(reg) & ~(data)) + + +#endif /* __ASSEMBLER__ */ + +void rtc32k_enable(void); +void rtc32k_disable(void); + +#endif /* _DRV_RTC_H_ */ diff --git a/bsp/x1000/drivers/drv_spi.c b/bsp/x1000/drivers/drv_spi.c new file mode 100644 index 0000000000000000000000000000000000000000..ccf739f4f42748679a56feb22a7519d080bdcb5b --- /dev/null +++ b/bsp/x1000/drivers/drv_spi.c @@ -0,0 +1,537 @@ +/* + * File : board_spi_master.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ + +/********************************************************************************************************* +** Include Files +*********************************************************************************************************/ +#include +#include + +#include + +#include "board.h" +#include "drv_clock.h" +#include "drv_gpio.h" +#include "drv_spi.h" + +#define SSI_BASE SSI0_BASE + +#define DEBUG 0 +#if DEBUG +#define PRINT(...) rt_kprintf(__VA_ARGS__) +#else +#define PRINT(...) +#endif + + +#define JZ_SPI_RX_BUF(type) \ +uint32_t jz_spi_rx_buf_##type(struct jz_spi *hw) \ +{ \ + uint32_t data = spi_readl(hw, SSI_DR); \ + type * rx = (type *)hw->rx_buf; \ + *rx++ = (type)(data); \ + hw->rx_buf = (uint8_t *)rx; \ + return (uint32_t)data; \ +} + +#define JZ_SPI_TX_BUF(type) \ +uint32_t jz_spi_tx_buf_##type(struct jz_spi *hw) \ +{ \ + uint32_t data; \ + const type * tx = (type *)hw->tx_buf; \ + data = *tx++; \ + hw->tx_buf = (uint8_t *)tx; \ + spi_send_data(hw, data); \ + return (uint32_t)data; \ +} + +JZ_SPI_RX_BUF(u8) +JZ_SPI_TX_BUF(u8) + +JZ_SPI_RX_BUF(u16) +JZ_SPI_TX_BUF(u16) + +JZ_SPI_RX_BUF(u32) +JZ_SPI_TX_BUF(u32) + + + +static rt_err_t jz_spi_configure(struct rt_spi_device* device, struct rt_spi_configuration* configuration); +static rt_uint32_t jz_spi_xfer(struct rt_spi_device* device, struct rt_spi_message* message); + + + +static const struct rt_spi_ops jz_spi_ops = +{ + jz_spi_configure, + jz_spi_xfer +}; + +static struct jz_spi jz_spi0 = +{ + .base = SSI0_BASE, +}; + +static void jz_spi_set_cs(struct jz_spi_cs *cs,int value) +{ +// gpio_set_value(cs->port,cs->pin,!!value); + if(value != 0) + gpio_set_func(cs->port,cs->pin,GPIO_OUTPUT1); + else + gpio_set_func(cs->port,cs->pin,GPIO_OUTPUT0); +} + +/************************************************************* + * jz_spi_set_clk: set the SPI_CLK. + * The min clock is 23438Hz, and the max clock is defined + * by max_clk or max_speed_hz(it is 54MHz for JZ4780, and + * the test max clock is 30MHz). + ************************************************************* */ +static int _spi_set_clk(struct jz_spi *spi_bus, uint32_t hz) +{ + uint16_t cgv; + uint32_t cpm_rate; + + cpm_rate = clk_get_rate(spi_bus->clk); + + if (hz >= 10000000) + clk_set_rate(spi_bus->clk,2 * hz); + else + clk_set_rate(spi_bus->clk, 24000000); + + cpm_rate = clk_get_rate(spi_bus->clk); + + cgv = cpm_rate / (2 * hz); + if (cgv > 0) + cgv -= 1; + + spi_writel(spi_bus, SSI_GR, cgv); + + return 0; +} + +static uint32_t _spi_get_clk(struct jz_spi *spi_bus) +{ + uint16_t cgv; + + cgv = spi_readl(spi_bus, SSI_GR); + + return clk_get_rate(spi_bus->clk) / (2 * (cgv + 1)); +} + +static uint32_t _spi_do_write_fifo(struct jz_spi* spi_bus,uint32_t sendEntries) +{ + uint32_t cnt = 0; + + if((spi_bus->tx_buf != RT_NULL) && (spi_bus->tx_func != RT_NULL)) + { + while (cnt++ < sendEntries) + { + spi_bus->tx_func(spi_bus); + + spi_bus->sendCount += spi_bus->xfer_unit_size; + } + } + else + { + while (cnt++ < sendEntries) + { + spi_send_data(spi_bus,0xFF); + + spi_bus->sendCount += spi_bus->xfer_unit_size; + } + } + +// PRINT("sendCount = %d\n",spi_bus->sendCount); + + return 0; +} + + +static uint32_t _spi_do_read_fifo(struct jz_spi* spi_bus) +{ + uint32_t cnt = 0; + uint32_t dummy; + + if((spi_bus->rx_buf != RT_NULL) && (spi_bus->rx_func != RT_NULL)) + { + while(!spi_is_rxfifo_empty(spi_bus)) + { + spi_bus->rx_func(spi_bus); + spi_bus->recvCount += spi_bus->xfer_unit_size; + cnt ++; + } + } + else + { + while(!spi_is_rxfifo_empty(spi_bus)) + { + dummy = spi_readl(spi_bus, SSI_DR); + cnt ++; + } + } + + PRINT("recvCnt = %d\n",cnt); + return cnt; +} + + +static uint32_t _spi_do_xfer(struct jz_spi* spi_bus) +{ + uint32_t leaveEntries; + uint32_t sendEntries; + uint32_t trigger; + uint8_t intFlag = 0, lastFlag = 0; + + leaveEntries = (spi_bus->totalCount - spi_bus->sendCount) / spi_bus->xfer_unit_size; + + if(spi_bus->is_first == 1) + { + /* CPU Mode should reset SSI triggers at first */ + spi_bus->tx_trigger = SSI_TX_FIFO_THRESHOLD * 8; + spi_bus->rx_trigger = (SSI_RX_FIFO_THRESHOLD - SSI_SAFE_THRESHOLD) * 8; + + spi_set_tx_trigger(spi_bus, spi_bus->tx_trigger); + spi_set_rx_trigger(spi_bus, spi_bus->rx_trigger); + + if(leaveEntries <= JZ_SSI_MAX_FIFO_ENTRIES) + { + sendEntries = leaveEntries; + } + else + { + sendEntries = JZ_SSI_MAX_FIFO_ENTRIES; + + intFlag = 1; + } + + spi_start_transmit(spi_bus); + spi_bus->is_first = 0; + } + else + { + trigger = JZ_SSI_MAX_FIFO_ENTRIES - spi_bus->tx_trigger; + + if (leaveEntries <= trigger) + { + sendEntries = leaveEntries; + + lastFlag = 1; + } + else + { + sendEntries = CPU_ONCE_BLOCK_ENTRIES; + intFlag = 1; + } + } + + _spi_do_write_fifo(spi_bus,sendEntries); + + spi_enable_tx_error_intr(spi_bus); + spi_enable_rx_error_intr(spi_bus); + + if(intFlag) + { + spi_enable_txfifo_half_empty_intr(spi_bus); + spi_enable_rxfifo_half_full_intr(spi_bus); + } + else + { + spi_disable_txfifo_half_empty_intr(spi_bus); + spi_disable_rxfifo_half_full_intr(spi_bus); + } + + if(lastFlag) + spi_enable_rxfifo_half_full_intr(spi_bus); + + return 0; +} + + +static void _spi_irq_handler(int vector, void *param) +{ + struct jz_spi* spi_bus = (struct jz_spi *) param; + uint32_t leftCount = spi_bus->totalCount - spi_bus->sendCount; + uint32_t status; + uint8_t flag = 0; + + PRINT("INT\n"); + + if ( spi_get_underrun(spi_bus) && spi_get_tx_error_intr(spi_bus)) + { + PRINT("UNDR\n"); + spi_disable_tx_error_intr(spi_bus); + + if(leftCount == 0) + { + _spi_do_read_fifo(spi_bus); + + spi_disable_tx_intr(spi_bus); + spi_disable_rx_intr(spi_bus); + + rt_completion_done(&spi_bus->completion); + } + else + { + spi_clear_errors(spi_bus); + spi_enable_tx_error_intr(spi_bus); + } + + flag++; + } + + if ( spi_get_overrun(spi_bus) && spi_get_rx_error_intr(spi_bus) ) + { + PRINT("OVER\n"); + _spi_do_read_fifo(spi_bus); + + flag++; + } + + if ( spi_get_rxfifo_half_full(spi_bus) && spi_get_rxfifo_half_full_intr(spi_bus)) + { + PRINT("RFHF\n"); + _spi_do_read_fifo(spi_bus); + + flag++; + } + + if ( spi_get_txfifo_half_empty(spi_bus) && spi_get_txfifo_half_empty_intr(spi_bus)) + { + PRINT("THFE\n"); + _spi_do_xfer(spi_bus); + + flag++; + } + +// if (!flag) +// { +// rt_completion_done(&spi_bus->completion); +// } + + spi_clear_errors(spi_bus); +} + + +static rt_uint32_t jz_spi_xfer(struct rt_spi_device* device, struct rt_spi_message* message) +{ + rt_base_t level; + int i; + + struct jz_spi* spi_bus = (struct jz_spi *)device->bus; + struct jz_spi_cs* _spi_cs = (struct jz_spi_cs*)device->parent.user_data; + + /* take CS */ + if (message->cs_take) + { + jz_spi_set_cs(_spi_cs,0); + } + + spi_disable_tx_intr(spi_bus); + spi_disable_rx_intr(spi_bus); + spi_start_transmit(spi_bus); + spi_flush_fifo(spi_bus); + spi_enable_receive(spi_bus); + spi_clear_errors(spi_bus); + +#ifdef SSI_DEGUG + dump_spi_reg(hw); +#endif + + spi_bus->is_first = 1; + spi_bus->totalCount = message->length; + spi_bus->sendCount = 0; + spi_bus->recvCount = 0; + + spi_bus->rx_buf = (rt_uint8_t *)message->recv_buf; + spi_bus->tx_buf = (rt_uint8_t *)message->send_buf; + + _spi_do_xfer(spi_bus); + + rt_completion_wait(&spi_bus->completion,RT_WAITING_FOREVER); + + spi_finish_transmit(spi_bus); + spi_clear_errors(spi_bus); + + /* release CS */ + if (message->cs_release) + { + jz_spi_set_cs(_spi_cs,1); + spi_finish_transmit(spi_bus); + } + + return message->length; +} + + +static rt_err_t jz_spi_configure(struct rt_spi_device* device, + struct rt_spi_configuration* configuration) +{ + struct jz_spi * spi_bus = (struct jz_spi *)device->bus; + + /* Disable SSIE */ + spi_disable(spi_bus); + + _spi_set_clk(spi_bus,configuration->max_hz); + configuration->max_hz = _spi_get_clk(spi_bus); + PRINT("spi clk = %d\n",configuration->max_hz); + + if(configuration->data_width <= 8) + { + spi_set_frame_length(spi_bus, FIFO_W8); + + spi_bus->xfer_unit_size = SPI_8BITS; + spi_bus->rx_func = jz_spi_rx_buf_u8; + spi_bus->tx_func = jz_spi_tx_buf_u8; + } + else if(configuration->data_width <= 16) + { + spi_set_frame_length(spi_bus, FIFO_W16); + + spi_bus->xfer_unit_size = SPI_16BITS; + spi_bus->rx_func = jz_spi_rx_buf_u16; + spi_bus->tx_func = jz_spi_tx_buf_u16; + } + else if(configuration->data_width <= 32) + { + spi_set_frame_length(spi_bus, FIFO_W32); + + spi_bus->xfer_unit_size = SPI_32BITS; + spi_bus->rx_func = jz_spi_rx_buf_u32; + spi_bus->tx_func = jz_spi_tx_buf_u32; + } + else + { + return RT_EIO; + } +// spi_set_frame_length(spi_bus,spi_bus->xfer_unit_size); + + /* CPOL */ + if (configuration->mode & RT_SPI_CPHA) + spi_set_clock_phase(spi_bus, 1); + else + spi_set_clock_phase(spi_bus, 0); + /* CPHA */ + if (configuration->mode & RT_SPI_CPOL) + spi_set_clock_polarity(spi_bus, 1); + else + spi_set_clock_polarity(spi_bus, 0); + + /* MSB or LSB */ + if (configuration->mode & RT_SPI_MSB) + { + spi_set_tx_msb(spi_bus); + spi_set_rx_msb(spi_bus); + } + else + { + spi_set_tx_lsb(spi_bus); + spi_set_rx_lsb(spi_bus); + } + /* Enable SSIE */ + spi_enable(spi_bus); + + return RT_EOK; +}; + + + +int rt_hw_spi_master_init(void) +{ + PRINT("init spi bus spi0\n"); + +#ifdef RT_USING_SPI0 +# ifdef RT_SPI0_USE_PA + /* GPIO Initialize (SSI FUNC2) */ +// gpio_set_func(GPIO_PORT_A,GPIO_Pin_25,GPIO_FUNC_2); //CE0 + gpio_set_func(GPIO_PORT_A,GPIO_Pin_26,GPIO_FUNC_2); //CLK +// gpio_set_func(GPIO_PORT_A,GPIO_Pin_27,GPIO_FUNC_2); //CE0 + gpio_set_func(GPIO_PORT_A,GPIO_Pin_28,GPIO_FUNC_2); //DR + gpio_set_func(GPIO_PORT_A,GPIO_Pin_29,GPIO_FUNC_2); //DT + + /* Release HOLD WP */ + gpio_set_func(GPIO_PORT_A, GPIO_Pin_30, GPIO_OUTPUT1); //CE1->WP + gpio_set_func(GPIO_PORT_A, GPIO_Pin_31, GPIO_OUTPUT1); //GPC->HOLD +# else + /* GPIO Initialize (SSI FUNC2) */ +// gpio_set_func(GPIO_PORT_D,GPIO_Pin_1,GPIO_FUNC_0); //CE0 + gpio_set_func(GPIO_PORT_D,GPIO_Pin_0,GPIO_FUNC_0); //CLK + gpio_set_func(GPIO_PORT_D,GPIO_Pin_3,GPIO_FUNC_0); //DR + gpio_set_func(GPIO_PORT_D,GPIO_Pin_2,GPIO_FUNC_0); //DT +# endif +#endif + + /* Init config param */ + jz_spi0.base = SSI_BASE; + + jz_spi0.clk = clk_get("cgu_ssi"); + clk_enable(jz_spi0.clk); + jz_spi0.clk_gate = clk_get("ssi0"); + clk_enable(jz_spi0.clk_gate); + + + rt_completion_init(&jz_spi0.completion); + + + /* disable the SSI controller */ + spi_disable(&jz_spi0); + + /* set default half_intr trigger */ + jz_spi0.tx_trigger = SSI_TX_FIFO_THRESHOLD * 8; + jz_spi0.rx_trigger = SSI_RX_FIFO_THRESHOLD * 8; + spi_set_tx_trigger(&jz_spi0, jz_spi0.tx_trigger); + spi_set_rx_trigger(&jz_spi0, jz_spi0.rx_trigger); + + /* First,mask the interrupt, while verify the status ? */ + spi_disable_tx_intr(&jz_spi0); + spi_disable_rx_intr(&jz_spi0); + + spi_disable_receive(&jz_spi0); + + spi_set_clock_phase(&jz_spi0, 0); + spi_set_clock_polarity(&jz_spi0, 0); + spi_set_tx_msb(&jz_spi0); + spi_set_rx_msb(&jz_spi0); + + spi_set_format(&jz_spi0); + spi_set_frame_length(&jz_spi0, 8); + spi_disable_loopback(&jz_spi0); + spi_flush_fifo(&jz_spi0); + + spi_underrun_auto_clear(&jz_spi0); + spi_clear_errors(&jz_spi0); + + spi_select_ce0(&jz_spi0); + /* enable the SSI controller */ + spi_enable(&jz_spi0); + + rt_spi_bus_register(&jz_spi0.parent,"spi0", &jz_spi_ops); + PRINT("init spi bus spi0 done\n"); + + rt_hw_interrupt_install(IRQ_SSI0,_spi_irq_handler,&jz_spi0,"SSI0"); + rt_hw_interrupt_umask(IRQ_SSI0); + + return RT_EOK; +} +INIT_BOARD_EXPORT(rt_hw_spi_master_init); diff --git a/bsp/x1000/drivers/drv_spi.h b/bsp/x1000/drivers/drv_spi.h new file mode 100644 index 0000000000000000000000000000000000000000..379fd5f2af7acdf606a9a0ce063a38e72cc660a8 --- /dev/null +++ b/bsp/x1000/drivers/drv_spi.h @@ -0,0 +1,635 @@ +/* + * File : board_spi_master.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ + + + +#ifndef DRV_SPI_H__ +#define DRV_SPI_H__ + +#include +#include + +#include "board.h" +#include "drv_gpio.h" + +/* SSI REGISTER */ +#define SSI_DR 0x00 +#define SSI_CR0 0x04 +#define SSI_CR1 0x08 +#define SSI_SR 0x0C +#define SSI_ITR 0x10 +#define SSI_ICR 0x14 +#define SSI_GR 0x18 + +/* SSI Data Register (SSI_DR) */ +#define DR_GPC_BIT 0 +#define DR_GPC_MASK (0x1ff << SSI_DR_GPC_BIT) + +/* SSI Control Register 0 (SSI_CR0) */ +#define CR0_TENDIAN_BIT 18 +#define CR0_TENDIAN_MASK (3 << CR0_TENDIAN_BIT) +#define CR0_RENDIAN_BIT 16 +#define CR0_RENDIAN_MASK (3 << CR0_RENDIAN_BIT) +#define CR0_SSIE (1 << 15) +#define CR0_TIE (1 << 14) +#define CR0_RIE (1 << 13) +#define CR0_TEIE (1 << 12) +#define CR0_REIE (1 << 11) +#define CR0_LOOP (1 << 10) +#define CR0_RFINE (1 << 9) +#define CR0_RFINC (1 << 8) +#define CR0_EACLRUN (1 << 7) /* hardware auto clear underrun when TxFifo no empty */ +#define CR0_FSEL (1 << 6) +#define CR0_VRCNT (1 << 4) +#define CR0_TFMODE (1 << 3) +#define CR0_TFLUSH (1 << 2) +#define CR0_RFLUSH (1 << 1) +#define CR0_DISREV (1 << 0) + +/* SSI Control Register 1 (SSI_CR1) */ +#define CR1_FRMHL_BIT 30 +#define CR1_FRMHL_MASK (0x3 << CR1_FRMHL_BIT) +#define CR1_FRMHL_CELOW_CE2LOW (0 << CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is low valid */ +#define CR1_FRMHL_CEHIGH_CE2LOW (1 << CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is low valid */ +#define CR1_FRMHL_CELOW_CE2HIGH (2 << CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is high valid */ +#define CR1_FRMHL_CEHIGH_CE2HIGH (3 << CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is high valid */ +#define CR1_TFVCK_BIT 28 +#define CR1_TFVCK_MASK (0x3 << CR1_TFVCK_BIT) + #define CR1_TFVCK_0 (0 << CR1_TFVCK_BIT) + #define CR1_TFVCK_1 (1 << CR1_TFVCK_BIT) + #define CR1_TFVCK_2 (2 << CR1_TFVCK_BIT) + #define CR1_TFVCK_3 (3 << CR1_TFVCK_BIT) +#define CR1_TCKFI_BIT 26 +#define CR1_TCKFI_MASK (0x3 << CR1_TCKFI_BIT) + #define CR1_TCKFI_0 (0 << CR1_TCKFI_BIT) + #define CR1_TCKFI_1 (1 << CR1_TCKFI_BIT) + #define CR1_TCKFI_2 (2 << CR1_TCKFI_BIT) + #define CR1_TCKFI_3 (3 << CR1_TCKFI_BIT) +#define CR1_ITFRM (1 << 24) +#define CR1_UNFIN (1 << 23) +#define CR1_FMAT_BIT 20 +#define CR1_FMAT_MASK (0x3 << CR1_FMAT_BIT) + #define CR1_FMAT_SPI (0 << CR1_FMAT_BIT) /* Motorola隆炉s SPI format */ + #define CR1_FMAT_SSP (1 << CR1_FMAT_BIT) /* TI's SSP format */ + #define CR1_FMAT_MW1 (2 << CR1_FMAT_BIT) /* National Microwire 1 format */ + #define CR1_FMAT_MW2 (3 << CR1_FMAT_BIT) /* National Microwire 2 format */ +#define CR1_TTRG_BIT 16 /* SSI1 TX trigger */ +#define CR1_TTRG_MASK (0xf << CR1_TTRG_BIT) +#define CR1_MCOM_BIT 12 +#define CR1_MCOM_MASK (0xf << CR1_MCOM_BIT) +// #define CR1_MCOM_BIT(NO) (##NO## << CR1_MCOM_BIT) /* N-bit command selected */ +#define CR1_RTRG_BIT 8 /* SSI RX trigger */ +#define CR1_RTRG_MASK (0xf << CR1_RTRG_BIT) +#define CR1_FLEN_BIT 3 +#define CR1_FLEN_MASK (0x1f << CR1_FLEN_BIT) + #define CR1_FLEN_2BIT (0x0 << CR1_FLEN_BIT) +#define CR1_PHA (1 << 1) +#define CR1_POL (1 << 0) + +/* SSI Status Register (SSI_SR) */ +#define SR_TFIFONUM_BIT 16 +#define SR_TFIFONUM_MASK (0xff << SR_TFIFONUM_BIT) +#define SR_RFIFONUM_BIT 8 +#define SR_RFIFONUM_MASK (0xff << SR_RFIFONUM_BIT) +#define SR_END (1 << 7) +#define SR_BUSY (1 << 6) +#define SR_TFF (1 << 5) +#define SR_RFE (1 << 4) +#define SR_TFHE (1 << 3) +#define SR_RFHF (1 << 2) +#define SR_UNDR (1 << 1) +#define SR_OVER (1 << 0) + +/* SSI Interval Time Control Register (SSI_ITR) */ +#define ITR_CNTCLK (1 << 15) +#define ITR_IVLTM_BIT 0 +#define ITR_IVLTM_MASK (0x7fff << ITR_IVLTM_BIT) + + + +#define R_MODE 0x1 +#define W_MODE 0x2 +#define RW_MODE (R_MODE | W_MODE) + +#define R_DMA 0x4 +#define W_DMA 0x8 +#define RW_DMA (R_DMA |W_DMA) + +#define SPI_DMA_ACK 0x1 + +#define SPI_DMA_ERROR -3 +#define SPI_CPU_ERROR -4 + +#define SPI_COMPLETE 5 + +#define JZ_SSI_MAX_FIFO_ENTRIES 128 +#define JZ_SSI_DMA_BURST_LENGTH 16 + +#define FIFO_W8 8 +#define FIFO_W16 16 +#define FIFO_W32 32 + +#define SPI_BITS_8 8 +#define SPI_BITS_16 16 +#define SPI_BITS_32 32 + +#define SPI_8BITS 1 +#define SPI_16BITS 2 +#define SPI_32BITS 4 + + +/* tx rx threshold from 0x0 to 0xF */ +#define SSI_FULL_THRESHOLD 0xF +#define SSI_TX_FIFO_THRESHOLD 0x1 +#define SSI_RX_FIFO_THRESHOLD (SSI_FULL_THRESHOLD - SSI_TX_FIFO_THRESHOLD) +#define SSI_SAFE_THRESHOLD 0x1 + +#define CPU_ONCE_BLOCK_ENTRIES ((SSI_FULL_THRESHOLD-SSI_TX_FIFO_THRESHOLD)*8) + +#define MAX_SSI_INTR 10000 + +#define MAX_SSICDR 63 +#define MAX_CGV 255 + +#define SSI_DMA_FASTNESS_CHNL 0 // SSI controller [n] FASTNESS when probe(); + +#define JZ_NEW_CODE_TYPE + +#define BUFFER_SIZE PAGE_SIZE + +#define CONFIG_DMA_ENGINE 1 + +#define SUSPND (1<<0) +#define SPIBUSY (1<<1) +#define RXBUSY (1<<2) +#define TXBUSY (1<<3) + + +struct jz_spi_rx_fifo +{ + /* software fifo */ + rt_uint8_t *buffer; + + rt_uint16_t put_index, get_index; +}; + +struct jz_spi_tx_fifo +{ + struct rt_completion completion; +}; + +struct jz_spi_rx_dma +{ + rt_bool_t activated; +}; + +struct jz_spi_tx_dma +{ + rt_bool_t activated; + struct rt_data_queue data_queue; +}; + + +typedef struct jz_spi +{ + struct rt_spi_bus parent; +// struct rt_semaphore spi_done_sem; + struct rt_completion completion; + + struct clk *clk; + struct clk *clk_gate; + + uint32_t base; + uint8_t is_first; + uint8_t xfer_unit_size; /* 1,2,4 */ + + uint32_t totalCount; + uint32_t sendCount; + uint32_t recvCount; + + uint8_t tx_trigger; /* 0-128 */ + uint8_t rx_trigger; /* 0-128 */ + + uint8_t *rx_buf; + uint8_t *tx_buf; + + uint32_t (*rx_func)(struct jz_spi *); + uint32_t (*tx_func)(struct jz_spi *); +}jz_spi_bus_t; + +struct jz_spi_cs +{ + enum gpio_port port; + enum gpio_pin pin; +}; + +static uint32_t spi_readl(struct jz_spi *spi_bus,uint32_t offset) +{ + return readl(spi_bus->base + offset); +} + +static void spi_writel(struct jz_spi *spi_bus, uint32_t offset,uint32_t value) +{ + writel(value, spi_bus->base + offset); +} + +static inline void spi_set_frmhl(struct jz_spi *spi, unsigned int frmhl) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR1); + tmp = (tmp & ~CR1_FRMHL_MASK) | frmhl; + spi_writel(spi, SSI_CR1, tmp); +} +static inline void spi_set_clock_phase(struct jz_spi *spi, unsigned int cpha) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR1); + tmp = (tmp & ~CR1_PHA) | (cpha ? CR1_PHA : 0); + spi_writel(spi, SSI_CR1, tmp); +} + +static inline void spi_set_clock_polarity(struct jz_spi *spi, unsigned int cpol) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR1); + tmp = (tmp & ~CR1_POL) | (cpol ? CR1_POL : 0); + spi_writel(spi, SSI_CR1, tmp); +} + +static inline void spi_set_tx_msb(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp &= ~CR0_TENDIAN_MASK; + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_set_tx_lsb(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp |= (tmp & ~CR0_TENDIAN_MASK) | (0x3 << CR0_TENDIAN_BIT); + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_set_rx_msb(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp &= ~CR0_RENDIAN_MASK; + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_set_rx_lsb(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp |= (tmp & ~CR0_RENDIAN_MASK) | (0x3 << CR0_RENDIAN_BIT); + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_enable_loopback(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp |= CR0_LOOP; + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_disable_loopback(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp &= ~CR0_LOOP; + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_set_frame_length(struct jz_spi *spi, u32 len) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR1); + tmp = (tmp & ~CR1_FLEN_MASK) | (((len) - 2) << CR1_FLEN_BIT); + spi_writel(spi, SSI_CR1, tmp); +} + +static inline void spi_set_tx_trigger(struct jz_spi *spi, u32 val) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR1); + tmp = (tmp & ~CR1_TTRG_MASK) | ((val)/8) << CR1_TTRG_BIT; + spi_writel(spi, SSI_CR1, tmp); +} + +static inline void spi_set_rx_trigger(struct jz_spi *spi, u32 val) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR1); + tmp = (tmp & ~CR1_RTRG_MASK) | ((val)/8) << CR1_RTRG_BIT; + spi_writel(spi, SSI_CR1, tmp); +} + +static inline void spi_enable_txfifo_half_empty_intr(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp |= CR0_TIE; + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_disable_txfifo_half_empty_intr(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp &= ~CR0_TIE; + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_enable_rxfifo_half_full_intr(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp |= CR0_RIE; + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_disable_rxfifo_half_full_intr(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp &= ~CR0_RIE; + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_enable_tx_intr(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp |= CR0_TIE | CR0_TEIE; + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_disable_tx_intr(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp &= ~(CR0_TIE | CR0_TEIE); + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_enable_rx_intr(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp |= CR0_RIE | CR0_REIE; + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_disable_rx_intr(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp &= ~(CR0_RIE | CR0_REIE); + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_enable_tx_error_intr(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp |= CR0_TEIE; + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_disable_tx_error_intr(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp &= ~CR0_TEIE; + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_enable_rx_error_intr(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp |= CR0_REIE; + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_disable_rx_error_intr(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp &= ~CR0_REIE; + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_underrun_auto_clear(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp |= CR0_EACLRUN; + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_clear_errors(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_SR); + tmp &= ~(SR_UNDR | SR_OVER); + spi_writel(spi, SSI_SR, tmp); +} + +static inline void spi_set_format(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR1); + tmp &= ~CR1_FMAT_MASK; + tmp |= CR1_FMAT_SPI; + tmp &= ~(CR1_TFVCK_MASK | CR1_TCKFI_MASK); + tmp |= (CR1_TFVCK_0 | CR1_TCKFI_0); +// tmp |= (CR1_TFVCK_1 | CR1_TCKFI_1); +// tmp |= (CR1_TFVCK_2 | CR1_TCKFI_2); +// tmp |= (CR1_TFVCK_3 | CR1_TCKFI_3); + spi_writel(spi, SSI_CR1, tmp); +} + +static inline void spi_enable_receive(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp &= ~CR0_DISREV; + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_disable_receive(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp |= CR0_DISREV; + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_flush_fifo(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp |= CR0_TFLUSH | CR0_RFLUSH; + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_finish_transmit(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR1); + tmp &= ~CR1_UNFIN; + spi_writel(spi, SSI_CR1, tmp); +} + +static inline void spi_start_transmit(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR1); + tmp |= CR1_UNFIN; + spi_writel(spi, SSI_CR1, tmp); +} + +static inline int spi_is_rxfifo_empty(struct jz_spi *spi) +{ + return spi_readl(spi, SSI_SR) & SR_RFE; +} + +static inline int spi_check_busy(struct jz_spi *spi) +{ + return spi_readl(spi, SSI_SR) & SR_BUSY; +} + +static inline void spi_disable(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp &= ~CR0_SSIE; + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_enable(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp |= CR0_SSIE; + spi_writel(spi, SSI_CR0, tmp); +} + +static inline u32 spi_get_rxfifo_count(struct jz_spi *spi) +{ + return (spi_readl(spi, SSI_SR) & SR_RFIFONUM_MASK) >> SR_RFIFONUM_BIT; +} + +static inline void spi_flush_txfifo(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp |= CR0_TFLUSH; + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_flush_rxfifo(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp |= CR0_RFLUSH; + spi_writel(spi, SSI_CR0, tmp); +} + +static inline int spi_get_underrun(struct jz_spi *spi) +{ + return spi_readl(spi, SSI_SR) & SR_UNDR; +} + +static inline int spi_get_overrun(struct jz_spi *spi) +{ + return spi_readl(spi, SSI_SR) & SR_OVER; +} + +static inline int spi_get_transfer_end(struct jz_spi *spi) +{ + return spi_readl(spi, SSI_SR) & SR_END; +} + +static inline int spi_get_tx_error_intr(struct jz_spi *spi) +{ + return spi_readl(spi, SSI_CR0) & CR0_TEIE; +} + +static inline int spi_get_rx_error_intr(struct jz_spi *spi) +{ + return spi_readl(spi, SSI_CR0) & CR0_REIE; +} + +static inline int spi_get_rxfifo_half_full(struct jz_spi *spi) +{ + return spi_readl(spi, SSI_SR) & SR_RFHF; +} + +static inline int spi_get_txfifo_half_empty(struct jz_spi *spi) +{ + return spi_readl(spi, SSI_SR) & SR_TFHE; +} + +static inline int spi_get_txfifo_half_empty_intr(struct jz_spi *spi) +{ + return spi_readl(spi, SSI_CR0) & CR0_TIE; +} + +static inline int spi_get_rxfifo_half_full_intr(struct jz_spi *spi) +{ + return spi_readl(spi, SSI_CR0) & CR0_RIE; +} + +static inline void spi_select_ce0(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp &= ~CR0_FSEL; + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_select_ce1(struct jz_spi *spi) +{ + u32 tmp; + tmp = spi_readl(spi, SSI_CR0); + tmp |= CR0_FSEL; + spi_writel(spi, SSI_CR0, tmp); +} + +static inline void spi_send_data(struct jz_spi *spi, u32 value) +{ + spi_writel(spi, SSI_DR, value); +} + +/* the spi->mode bits understood by this driver: */ +#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST | SPI_LOOP) +#define SPI_BITS_SUPPORT (SPI_BITS_8 | SPI_BITS_16 | SPI_BITS_32) + +#endif /* _SPI_MASTER_H_ */ diff --git a/bsp/x1000/drivers/drv_uart.c b/bsp/x1000/drivers/drv_uart.c new file mode 100644 index 0000000000000000000000000000000000000000..4c2ab92dcc5b8797222c540f4628fb2ca1d8bebd --- /dev/null +++ b/bsp/x1000/drivers/drv_uart.c @@ -0,0 +1,514 @@ +/* + * File : drv_uart.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ +#include +#include +#include + +#include + +#include "board.h" +#include "drv_uart.h" +#include "drv_gpio.h" +#include "drv_clock.h" + +struct jz_uart_s +{ + rt_uint32_t hw_base; + + rt_uint32_t irqno; + char name[RT_NAME_MAX]; +}; + +static rt_err_t uart_configure (struct rt_serial_device *serial, struct serial_configure *cfg); +static rt_err_t uart_control (struct rt_serial_device *serial, int cmd, void *arg); +static int uart_putc (struct rt_serial_device *serial, char c); +static int uart_getc (struct rt_serial_device *serial); +static rt_size_t uart_dma_transmit (struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction); + +static void uart_irq_handler (int irqno, void *param); + +const struct rt_uart_ops _uart_ops = +{ + uart_configure, + uart_control, + uart_putc, + uart_getc, + uart_dma_transmit +}; + +struct baudtoregs_t +{ + unsigned int baud; + unsigned short div; + unsigned int umr:5; + unsigned int uacr:12; +}; + +static struct baudtoregs_t baudtoregs[] = +{ + /* + The data is generated by a python, + the script is tools/tty/get_divisor.py + */ + #if (BOARD_EXTAL_CLK == 24000000) + {50,0x7530,0x10,0x0}, + {75,0x4e20,0x10,0x0}, + {110,0x3521,0x10,0x0}, + {134,0x2b9d,0x10,0x0}, + {150,0x2710,0x10,0x0}, + {200,0x1d4c,0x10,0x0}, + {300,0x1388,0x10,0x0}, + {600,0x9c4,0x10,0x0}, + {1200,0x4e2,0x10,0x0}, + {1800,0x340,0x10,0x0}, + {2400,0x271,0x10,0x0}, + {4800,0x138,0x10,0x0}, + {9600,0x9c,0x10,0x0}, + {19200,0x4e,0x10,0x0}, + {38400,0x27,0x10,0x0}, + {57600,0x1a,0x10,0x0}, + {115200,0xd,0x10,0x0}, + {230400,0x6,0x11,0x550}, + {460800,0x3,0x11,0x550}, + {500000,0x3,0x10,0x0}, + {576000,0x3,0xd,0x0}, + {921600,0x2,0xd,0x0}, + {1000000,0x2,0xc,0x0}, + {1152000,0x1,0x14,0x400}, + {1500000,0x1,0x10,0x0}, + {2000000,0x1,0xc,0x0}, + {2500000,0x1,0x9,0x780}, + {3000000,0x1,0x8,0x0}, + {3500000,0x1,0x6,0x400}, + {4000000,0x1,0x6,0x0}, +#elif (BOARD_EXTAL_CLK == 26000000) + {50,0x7ef4,0x10,0x0}, + {75,0x546b,0x10,0x0}, + {110,0x398f,0x10,0x0}, + {134,0x2f40,0x10,0x0}, + {150,0x2a36,0x10,0x0}, + {200,0x1fbd,0x10,0x0}, + {300,0x151b,0x10,0x0}, + {600,0xa8e,0x10,0x0}, + {1200,0x547,0x10,0x0}, + {1800,0x385,0x10,0x0}, + {2400,0x2a4,0x10,0x0}, + {4800,0x152,0x10,0x0}, + {9600,0xa9,0x10,0x0}, + {19200,0x54,0x10,0x2}, + {38400,0x2a,0x10,0x2}, + {57600,0x1c,0x10,0x2}, + {115200,0xe,0x10,0x2}, + {230400,0x7,0x10,0x2}, + {460800,0x4,0xe,0x2}, + {500000,0x3,0x11,0x550}, + {576000,0x3,0xf,0x2}, + {921600,0x2,0xe,0x2}, + {1000000,0x2,0xd,0x0}, + {1152000,0x2,0xb,0x248}, + {1500000,0x1,0x11,0x550}, + {2000000,0x1,0xd,0x0}, + {2500000,0x1,0xa,0x2a0}, + {3000000,0x1,0x8,0x700}, + {3500000,0x1,0x7,0x2a0}, + {4000000,0x1,0x6,0x7c0}, +#elif (BOARD_EXTAL_CLK == 48000000) + {50,0xea60,0x10,0x0}, + {75,0x9c40,0x10,0x0}, + {110,0x6a42,0x10,0x0}, + {134,0x573a,0x10,0x0}, + {150,0x4e20,0x10,0x0}, + {200,0x3a98,0x10,0x0}, + {300,0x2710,0x10,0x0}, + {600,0x1388,0x10,0x0}, + {1200,0x9c4,0x10,0x0}, + {1800,0x67f,0x10,0x0}, + {2400,0x4e2,0x10,0x0}, + {4800,0x271,0x10,0x0}, + {9600,0x138,0x10,0x0}, + {19200,0x9c,0x10,0x0}, + {38400,0x4e,0x10,0x0}, + {57600,0x34,0x10,0x0}, + {115200,0x1a,0x10,0x0}, + {230400,0xd,0x10,0x0}, + {460800,0x6,0x11,0x550}, + {500000,0x6,0x10,0x0}, + {576000,0x5,0x10,0x700}, + {921600,0x3,0x11,0x550}, + {1000000,0x3,0x10,0x0}, + {1152000,0x3,0xd,0x0}, + {1500000,0x2,0x10,0x0}, + {2000000,0x2,0xc,0x0}, + {2500000,0x1,0x13,0x84}, + {3000000,0x1,0x10,0x0}, + {3500000,0x1,0xd,0x600}, + {4000000,0x1,0xc,0x0}, +#endif +}; +static unsigned short quot1[3] = {0}; /* quot[0]:baud_div, quot[1]:umr, quot[2]:uacr */ + +static unsigned short *get_divisor(unsigned int baud) +{ + struct baudtoregs_t *bt; + int index; + + for (index = 0; index < sizeof(baudtoregs)/sizeof(baudtoregs[0]); index ++) + { + bt = &baudtoregs[index]; + if (bt->baud == baud) + { + break; + } + } + + if (index < sizeof(baudtoregs)/sizeof(baudtoregs[0])) + { + quot1[0] = bt->div; + quot1[1] = bt->umr; + quot1[2] = bt->uacr; + return quot1; + } + + return NULL; +} + +/* + * UART Initiation + */ +void rt_hw_uart_init(void) +{ + struct rt_serial_device *serial; + struct jz_uart_s *uart; + struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; + +#ifdef RT_USING_UART0 /* for BT */ + { + static struct rt_serial_device serial0; + static struct jz_uart_s uart0; + + serial = &serial0; + uart = &uart0; + + serial->ops = &_uart_ops; + serial->config = config; + serial->config.bufsz = 2048; + serial->config.baud_rate = 115200; + + uart->hw_base = UART0_BASE; + uart->irqno = IRQ_UART0; + strcpy(uart->name, "uart0"); + + /* PC10/11/12/13 as RXD/TXD/RTS/CTS */ + gpio_set_func(GPIO_PORT_C, GPIO_Pin_10, GPIO_FUNC_0); + gpio_set_func(GPIO_PORT_C, GPIO_Pin_11, GPIO_FUNC_0); + gpio_set_func(GPIO_PORT_C, GPIO_Pin_12, GPIO_FUNC_0); + gpio_set_func(GPIO_PORT_C, GPIO_Pin_13, GPIO_FUNC_0); + + clk_enable(clk_get("uart0")); + { + extern int uart0_clk(void); + + uart0_clk(); + } + + rt_hw_serial_register(serial, + "uart0", + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, + uart); + } +#endif + +#ifdef RT_USING_UART1 + { + static struct rt_serial_device serial1; + static struct jz_uart_s uart1; + + serial = &serial1; + uart = &uart1; + strcpy(uart->name, "uart1"); + + serial->ops = &_uart_ops; + serial->config = config; + serial->config.baud_rate = 115200; + + uart->hw_base = UART1_BASE; + uart->irqno = IRQ_UART1; + + /* PD2/3/4/5 as RXD/TXD/RTS/CTS */ + gpio_set_func(GPIO_PORT_D, GPIO_Pin_2, GPIO_FUNC_1); + gpio_set_func(GPIO_PORT_D, GPIO_Pin_3, GPIO_FUNC_1); + gpio_set_func(GPIO_PORT_D, GPIO_Pin_4, GPIO_FUNC_1); + gpio_set_func(GPIO_PORT_D, GPIO_Pin_5, GPIO_FUNC_1); + + clk_enable(clk_get("uart1")); + { + extern int uart1_clk(void); + + uart1_clk(); + } + + rt_hw_serial_register(serial, + "uart1", + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, + uart); + } +#endif + +#ifdef RT_USING_UART2 + { + static struct rt_serial_device serial2; + static struct jz_uart_s uart2; + + serial = &serial2; + uart = &uart2; + strcpy(uart->name, "uart2"); + +#ifdef CONFIG_SYS_UART2_PD + gpio_set_func(GPIO_PORT_D,GPIO_Pin_4,GPIO_FUNC_0); + gpio_set_func(GPIO_PORT_D,GPIO_Pin_5,GPIO_FUNC_0); +#else + //USE JTAG IO for UART2 + gpio_set_func(GPIO_PORT_C,GPIO_Pin_31,GPIO_FUNC_1); +#endif + + serial->ops = &_uart_ops; + serial->config = config; + serial->config.baud_rate = 115200; + + uart->hw_base = UART2_BASE; + uart->irqno = IRQ_UART2; + + clk_enable(clk_get("uart2")); + + rt_hw_serial_register(serial, + "uart2", + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, + uart); + } +#endif +} + +/* + * UART interface + */ +static rt_err_t uart_configure (struct rt_serial_device *serial, struct serial_configure *cfg) +{ + rt_uint32_t baud_div; + unsigned short *quot1; + struct jz_uart_s * uart; + + RT_ASSERT(serial != RT_NULL); + serial->config = *cfg; + + uart = serial->parent.user_data; + RT_ASSERT(uart != RT_NULL); + + /* Init UART Hardware */ + UART_IER(uart->hw_base) = 0; /* clear interrupt */ + UART_FCR(uart->hw_base) = ~UARTFCR_UUE; /* disable UART unite */ + + /* Enable UART clock */ + + /* Set both receiver and transmitter in UART mode (not SIR) */ + UART_SIRCR(uart->hw_base) = ~(SIRCR_RSIRE | SIRCR_TSIRE); + + /* Set databits, stopbits and parity. (8-bit data, 1 stopbit, no parity) */ + UART_LCR(uart->hw_base) = UARTLCR_WLEN_8; + + /* set baudrate */ + quot1 = get_divisor(cfg->baud_rate); + if (quot1 == RT_NULL) + { +#if defined(RT_USING_JZ4750) || defined(RT_USING_JZ4755) || defined(RT_USING_JZ4760) + if(REG_CPM_CPCCR & (1UL << 30)) + { + /* CPCCR.ECS = 1: clock source is EXCLK/2 */ + baud_div = BOARD_EXTAL_CLK / 2 / 16 / cfg->baud_rate; + } + else +#endif + { + /* CPCCR.ECS = 0: clock source is EXCLK */ + baud_div = BOARD_EXTAL_CLK / 16 / cfg->baud_rate; + } + + UART_DLHR(uart->hw_base) = (baud_div >> 8) & 0xff; + UART_DLLR(uart->hw_base) = baud_div & 0xff; + UART_LCR(uart->hw_base) &= ~UARTLCR_DLAB; + } + else + { + UART_LCR(uart->hw_base) |= UARTLCR_DLAB; + UART_DLHR(uart->hw_base) = (quot1[0] >> 8) & 0xff; + UART_DLLR(uart->hw_base) = quot1[0] & 0xff; + UART_LCR(uart->hw_base) &= ~UARTLCR_DLAB; + + UART_UMR(uart->hw_base) = quot1[1] & 0xff; + UART_UACR(uart->hw_base) = quot1[2] & 0xff; + } + + if (uart->hw_base == UART0_BASE) + { + rt_kprintf("enable uart0 CTS/RTS and hw flow control\n"); + rt_kprintf("baudrate => %d\n", cfg->baud_rate); + + rt_kprintf("div: %d, umr %d, uacr %d\n", quot1[0], quot1[1], quot1[2]); + + /* configure CTS/RTS and hardware flow control */ + UART_MCR(uart->hw_base) |= (UARTMCR_MCE | UARTMCR_FCM); + } + else if (uart->hw_base == UART1_BASE) + { + rt_kprintf("enable uart1 CTS/RTS and hw flow control\n"); + rt_kprintf("baudrate => %d\n", cfg->baud_rate); + + rt_kprintf("div: %d, umr %d, uacr %d\n", quot1[0], quot1[1], quot1[2]); + + /* configure CTS/RTS and hardware flow control */ + UART_MCR(uart->hw_base) |= (UARTMCR_MCE | UARTMCR_FCM); + } + + /* Enable UART unit, enable and clear FIFO */ + UART_FCR(uart->hw_base) = UARTFCR_UUE | UARTFCR_FE | UARTFCR_TFLS | UARTFCR_RFLS; + + return (RT_EOK); +} + +int uart_set_baudrate(int baudrate) +{ + unsigned short *quot1; + struct jz_uart_s * uart; + struct rt_serial_device *serial; + + serial = (struct rt_serial_device *)rt_device_find("uart0"); + uart = serial->parent.user_data; + RT_ASSERT(uart != RT_NULL); + + /* set baudrate */ + quot1 = get_divisor(baudrate); + if (quot1) + { + UART_LCR(uart->hw_base) |= UARTLCR_DLAB; + UART_DLHR(uart->hw_base) = (quot1[0] >> 8) & 0xff; + UART_DLLR(uart->hw_base) = quot1[0] & 0xff; + UART_LCR(uart->hw_base) &= ~UARTLCR_DLAB; + + UART_UMR(uart->hw_base) = quot1[1] & 0xff; + UART_UACR(uart->hw_base) = quot1[2] & 0xff; + } + + rt_kprintf("change baudrate done!\n"); + return 0; +} + +static rt_err_t uart_control (struct rt_serial_device *serial, int cmd, void *arg) +{ + struct jz_uart_s * uart; + + uart = serial->parent.user_data; + + RT_ASSERT(uart != RT_NULL); + + switch (cmd) + { + case RT_DEVICE_CTRL_CLR_INT: + /* Disable the UART Interrupt */ + UART_IER(uart->hw_base) &= ~(UARTIER_RIE | UARTIER_RTIE); + rt_hw_interrupt_mask(uart->irqno); + break; + + case RT_DEVICE_CTRL_SET_INT: + /* install interrupt */ + rt_hw_interrupt_install(uart->irqno, uart_irq_handler, + serial, uart->name); + rt_hw_interrupt_umask(uart->irqno); + + /* Enable the UART Interrupt */ + UART_IER(uart->hw_base) |= (UARTIER_RIE | UARTIER_RTIE); + break; + } + + return (RT_EOK); +} + +static int uart_putc (struct rt_serial_device *serial, char c) +{ + struct jz_uart_s* uart; + int i = 0; + + uart = serial->parent.user_data; + + /* FIFO status, contain valid data */ + while (!((UART_LSR(uart->hw_base) & (UARTLSR_TDRQ | UARTLSR_TEMT)) == 0x60)) + { + i ++; + if (i > 0xfffff) + { + rt_kprintf("uart lst=>0x%02x\n", UART_LSR(uart->hw_base)); + i = 0; + } + } + /* write data */ + UART_TDR(uart->hw_base) = c; + + return (1); +} + +static int uart_getc (struct rt_serial_device *serial) +{ + struct jz_uart_s* uart = serial->parent.user_data; + + /* Receive Data Available */ + if (UART_LSR(uart->hw_base) & UARTLSR_DR) + { + return UART_RDR(uart->hw_base); + } + + return (-1); +} + +static rt_size_t uart_dma_transmit (struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction) +{ + return (0); +} + +/* UART interrupt handler */ +static void uart_irq_handler(int irqno, void *param) +{ + rt_ubase_t isr; + struct rt_serial_device *serial = (struct rt_serial_device*)param; + struct jz_uart_s* uart = serial->parent.user_data; + + /* read interrupt status and clear it */ + isr = UART_ISR(uart->hw_base); + if (isr & UARTISR_IID_RDI) /* Receive Data Available */ + { + rt_hw_serial_isr(serial,RT_SERIAL_EVENT_RX_IND); + } + + if(isr & UARTISR_IID_THRI) + { + rt_hw_serial_isr(serial,RT_SERIAL_EVENT_TX_DONE); + } +} diff --git a/bsp/x1000/driver/drv_uart.h b/bsp/x1000/drivers/drv_uart.h similarity index 95% rename from bsp/x1000/driver/drv_uart.h rename to bsp/x1000/drivers/drv_uart.h index d03f93002050aef86e27478cde87cba6b5960799..ee7038eba88f9070a7d20c17906ff35b85a92ebd 100644 --- a/bsp/x1000/driver/drv_uart.h +++ b/bsp/x1000/drivers/drv_uart.h @@ -1,5 +1,5 @@ /* - * File : board_uart.h + * File : drv_uart.h * This file is part of RT-Thread RTOS * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team * @@ -23,8 +23,8 @@ */ -#ifndef _BOARD_UART_H_ -#define _BOARD_UART_H_ +#ifndef DRV_UART_H_ +#define DRV_UART_H_ /* Uart Register */ #define UART_RDR(base) REG8((base) + 0x00) /* R 8b H'xx */ @@ -41,7 +41,8 @@ #define UART_SPR(base) REG8((base) + 0x1C) /* RW 8b H'00 */ #define UART_MCR(base) REG8((base) + 0x10) /* RW 8b H'00 */ #define UART_SIRCR(base) REG8((base) + 0x20) /* RW 8b H'00 */ - +#define UART_UMR(base) REG8((base) + 0x24) /* W 8b H'00 */ +#define UART_UACR(base) REG8((base) + 0x28) /* W 8b H'00 */ /* * Define macros for UARTIER @@ -121,6 +122,7 @@ #define UARTMCR_OUT1 (1 << 2) /* 0: UARTMSR.RI is set to 0 and RI_ input high */ #define UARTMCR_OUT2 (1 << 3) /* 0: UARTMSR.DCD is set to 0 and DCD_ input high */ #define UARTMCR_LOOP (1 << 4) /* 0: normal 1: loopback mode */ +#define UARTMCR_FCM (1 << 6) /* 0: flow control by software; 1: hardware */ #define UARTMCR_MCE (1 << 7) /* 0: modem function is disable */ /* @@ -149,4 +151,7 @@ void rt_hw_uart_init(void); +/* only used for bt_audio */ +int uart_set_baudrate(int baudrate); + #endif /* _BOARD_UART_H_ */ diff --git a/bsp/x1000/driver/SConscript b/bsp/x1000/drivers/mmc/SConscript similarity index 55% rename from bsp/x1000/driver/SConscript rename to bsp/x1000/drivers/mmc/SConscript index 50a6894b75776c33d7343d4094ae85bc81082510..99543a4cc69052e32ade8303c606327fb21e7d36 100644 --- a/bsp/x1000/driver/SConscript +++ b/bsp/x1000/drivers/mmc/SConscript @@ -4,8 +4,8 @@ from building import * cwd = GetCurrentDir() src = Glob('*.c') -CPPPATH = [cwd, str(Dir('#'))] +CPPPATH = [cwd] -group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH) +group = DefineGroup('drv_mmc', src, depend = ['RT_USING_SDIO'], CPPPATH = CPPPATH) Return('group') diff --git a/bsp/x1000/drivers/mmc/drv_mmc.c b/bsp/x1000/drivers/mmc/drv_mmc.c new file mode 100644 index 0000000000000000000000000000000000000000..469ed939b22d0cfb081aca0a92cc2e3e3e61ccdf --- /dev/null +++ b/bsp/x1000/drivers/mmc/drv_mmc.c @@ -0,0 +1,1134 @@ +/* + * File : drv_mmc.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013 - 2015, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2013-03-09 aozima the first version + * 2013-03-29 aozima support Jz4770. + * 2013-04-01 aozima add interrupt support for Jz4770. + */ + +#include +#include +#include + +#include +#include + +#include "board.h" +#include "drv_gpio.h" +#include "drv_clock.h" +#include "drv_mmc.h" + +#include +#include + +#define DMA_BUFFER +#define DMA_ALIGN (32U) +#define PIO_THRESHOLD 64 /* use pio mode if data length < PIO_THRESHOLD */ + +#define DEBUG_ENABLE +#define DEBUG_SECTION_NAME "[SDIO]" +#define DEBUG_LEVEL DBG_INFO +// #define DEBUG_LEVEL DBG_LOG +#define DEBUG_COLOR + +#include + +/* + * Error status including CRC_READ_ERROR, CRC_WRITE_ERROR, + * CRC_RES_ERR, TIME_OUT_RES, TIME_OUT_READ + */ +#define ERROR_STAT 0x3f + +#define JZMMC_USE_PIO 2 + +/* Register access macros */ +#define msc_readl(host,reg) \ + readl((host)->hw_base + reg) +#define msc_writel(host,reg,value) \ + writel((value), (host)->hw_base + (reg)) + +#define is_pio_mode(host) \ + (host->flags & (1 << JZMMC_USE_PIO)) +#define enable_pio_mode(host) \ + (host->flags |= (1 << JZMMC_USE_PIO)) +#define disable_pio_mode(host) \ + (host->flags &= ~(1 << JZMMC_USE_PIO)) + +/*-------------------End structure and macro define------------------------*/ + +#ifdef DMA_BUFFER +ALIGN(32) +uint8_t _dma_buffer_0[32 * 1024]; +ALIGN(32) +uint8_t _dma_buffer_1[32 * 1024]; +#endif + +struct jzmmc_host *jz_host1 = RT_NULL; +volatile static int stopping_clock = 0; +volatile static int sdio_log = 0; + +/* + * Functional functions. + * + * These small function will be called frequently. + */ +rt_inline void enable_msc_irq(struct jzmmc_host *host, unsigned long bits) +{ + unsigned long imsk; + + imsk = msc_readl(host, MSC_IMASK_OFFSET); + imsk &= ~bits; + msc_writel(host, MSC_IMASK_OFFSET, imsk); +} + +rt_inline void clear_msc_irq(struct jzmmc_host *host, unsigned long bits) +{ + msc_writel(host, MSC_IREG_OFFSET, bits); +} + +rt_inline void disable_msc_irq(struct jzmmc_host *host, unsigned long bits) +{ + unsigned long imsk; + + imsk = msc_readl(host, MSC_IMASK_OFFSET); + imsk |= bits; + msc_writel(host, MSC_IMASK_OFFSET, imsk); +} + +static inline int check_error_status(struct jzmmc_host *host, unsigned int status) +{ + if (status & ERROR_STAT) + { + dbg_log(DBG_LOG, "Error status->0x%08X: cmd=%d\n", status, host->cmd->cmd_code); + return -1; + } + return 0; +} + +/* Stop the MMC clock and wait while it happens */ +rt_inline rt_err_t jzmmc_stop_clock(uint32_t hw_base) +{ + uint16_t value; + int timeout = 10000; + + stopping_clock = 1; + + value = readw(hw_base + MSC_CTRL_OFFSET); + value &= ~MSC_CTRL_CLOCK_CONTROL_MASK; + value |= MSC_CTRL_CLOCK_STOP; + writew(value, hw_base + MSC_CTRL_OFFSET); + + while (timeout && (readl(hw_base + MSC_STAT_OFFSET) & MSC_STAT_CLK_EN)) + { + timeout--; + if (timeout == 0) + { + rt_kprintf("stop clock timeout!\n"); + stopping_clock = 0; + return -RT_ETIMEOUT; + } + rt_thread_delay(1); + } + + stopping_clock = 0; + return RT_EOK; +} + +/* Start the MMC clock and operation */ +rt_inline void jzmmc_start_clock(uint32_t hw_base) +{ + uint16_t value; + value = readw(hw_base + MSC_CTRL_OFFSET); + value |= (MSC_CTRL_CLOCK_START | MSC_CTRL_START_OP); + writew(value, hw_base + MSC_CTRL_OFFSET); +} + +static int jzmmc_polling_status(struct jzmmc_host *host, unsigned int status) +{ + unsigned int cnt = 100 * 1000 * 1000; + + while(!(msc_readl(host, MSC_STAT_OFFSET) & (status | ERROR_STAT)) \ + && (--cnt)); + + if (!cnt) + { + dbg_log(DBG_LOG, "polling status(0x%08X) time out, " + "op=%d, status=0x%08X\n", status, + host->cmd->cmd_code, msc_readl(host, MSC_STAT_OFFSET)); + return -1; + } + + if (msc_readl(host, MSC_STAT_OFFSET) & ERROR_STAT) + { + dbg_log(DBG_LOG, "polling status(0x%08X) error, " + "op=%d, status=0x%08X\n", status, + host->cmd->cmd_code, msc_readl(host, MSC_STAT_OFFSET)); + return -1; + } + + return 0; +} + +rt_inline void jzmmc_stop_dma(struct jzmmc_host *host) +{ + /* + * Theoretically, DMA can't be stopped when transfering, so we can only + * diable it when it is out of DMA request. + */ + msc_writel(host, MSC_DMAC_OFFSET, 0); +} + +static void jzmmc_command_done(struct jzmmc_host *host, struct rt_mmcsd_cmd *cmd) +{ + int i; + unsigned long res; + + uint8_t buf[16]; + uint32_t data; + + memset(cmd->resp, 0x0, sizeof(cmd->resp)); + + if ((host->cmdat & MSC_CMDAT_RESP_FORMAT_MASK) == MSC_CMDAT_RESPONSE_R2) + { + res = msc_readl(host, MSC_RES_OFFSET); + for (i = 0 ; i < 4 ; i++) { + cmd->resp[i] = res << 24; + res = msc_readl(host, MSC_RES_OFFSET); + cmd->resp[i] |= res << 8; + res = msc_readl(host, MSC_RES_OFFSET); + cmd->resp[i] |= res >> 8; + } + } + else if ((host->cmdat & MSC_CMDAT_RESP_FORMAT_MASK) == MSC_CMDAT_RESPONSE_NONE) + { + } + else + { + res = msc_readl(host, MSC_RES_OFFSET); + cmd->resp[0] = res << 24; + res = msc_readl(host, MSC_RES_OFFSET); + cmd->resp[0] |= res << 8; + res = msc_readl(host, MSC_RES_OFFSET); + cmd->resp[0] |= res & 0xff; + } + + dbg_log(DBG_LOG, "error:%d cmd->resp [%08X, %08X, %08X, %08X]\r\n\r\n", + cmd->err, + cmd->resp[0], + cmd->resp[1], + cmd->resp[2], + cmd->resp[3] + ); + + clear_msc_irq(host, IFLG_END_CMD_RES); +} + +static void jzmmc_data_done(struct jzmmc_host *host) +{ + struct rt_mmcsd_data *data = host->data; + + if (host->cmd->err == RT_EOK) + { + data->bytes_xfered = (data->blks * data->blksize); + jzmmc_stop_dma(host); + } + else + { + jzmmc_stop_dma(host); + data->bytes_xfered = 0; + dbg_log(DBG_LOG, "error when request done\n"); + } +} + +#define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ') +static void dump_hex(const rt_uint8_t *ptr, rt_size_t buflen) +{ + unsigned char *buf = (unsigned char*)ptr; + int i, j; + + for (i=0; idma_desc.nda = 0; + host->dma_desc.len = data->blks * data->blksize; + host->dma_desc.da = virt_to_phys(data->buf); + host->dma_desc.dcmd = DMACMD_ENDI | DMACMD_LINK; /* only one DMA descriptor */ + +#ifdef DMA_BUFFER + if ((uint32_t)(data->buf) & (DMA_ALIGN - 1)) + { + /* not align */ + host->dma_desc.da = virt_to_phys(host->_dma_buffer); + if (data->flags & DATA_DIR_WRITE) + { + dbg_log(DBG_LOG, "%d ->", data->blks * data->blksize); + memcpy(host->_dma_buffer, data->buf, data->blks * data->blksize); + rt_hw_dcache_flush_range((rt_ubase_t)(host->_dma_buffer), data->blks * data->blksize); + + dbg_log(DBG_LOG, "| 0x%08x\n", data->buf); + } + } + else + { + if (data->flags & DATA_DIR_WRITE) + { + rt_hw_dcache_flush_range((rt_ubase_t)(data->buf), data->blks * data->blksize); + } + } +#endif + +} + +// #define PERFORMANCE_DMA +rt_inline void jzmmc_dma_start(struct jzmmc_host *host, struct rt_mmcsd_data *data) +{ + volatile int i = 120; + uint32_t dma_addr = virt_to_phys(data->buf); + unsigned int dma_len = data->blks * data->blksize; + unsigned int dmac; +#ifdef PERFORMANCE_DMA + dmac = (0x01 << DMAC_INCR_SHF) | DMAC_DMAEN | DMAC_MODE_SEL; +#else + dmac = (0x01 << DMAC_INCR_SHF) | DMAC_DMAEN; +#endif + +#ifndef DMA_BUFFER + if ((dma_addr & (DMA_ALIGN - 1)) || (dma_len & (DMA_ALIGN - 1))) + { + dbg_log(DBG_LOG, "DMA align, addr=0x%08x\n", dma_addr); + dmac |= DMAC_ALIGNEN; + if (dma_addr & (DMA_ALIGN - 1)) + { + dmac |= (dma_addr & (DMA_ALIGN - 1)) << DMAC_AOFST_SHF; + } + } +#endif + dbg_log(DBG_LOG, "DMA start: nda 0x%08x, da 0x%08x, len 0x%04x, cmd 0x%08x\n", virt_to_phys(&(host->dma_desc)), + host->dma_desc.da, host->dma_desc.len, host->dma_desc.dcmd); + + rt_hw_dcache_flush_range((rt_ubase_t)(&(host->dma_desc)), 32); + while(i--); //TODO:短暂延时,不延时会发生错误 + msc_writel(host, MSC_DMANDA_OFFSET, virt_to_phys(&(host->dma_desc))); + msc_writel(host, MSC_DMAC_OFFSET, dmac); +} + +/*----------------------------End DMA handler------------------------------*/ + +/* + * PIO transfer mode. + * + * Functions of PIO read/write mode that can handle 1, 2 or 3 bytes transfer + * even though the FIFO register is 32-bits width. + * It's better just used for test. + */ +static int wait_cmd_response(struct jzmmc_host *host) +{ + if (!(msc_readl(host, MSC_IREG_OFFSET) & IFLG_END_CMD_RES)) + { + rt_err_t ret; + + rt_completion_init(&host->completion); + + enable_msc_irq(host, IMASK_TIME_OUT_RES | IMASK_END_CMD_RES); + + rt_hw_interrupt_umask(host->irqno); + ret = rt_completion_wait(&host->completion, RT_TICK_PER_SECOND); + + clear_msc_irq(host, IFLG_TIMEOUT_RES | IFLG_END_CMD_RES); + disable_msc_irq(host, IFLG_TIMEOUT_RES | IFLG_END_CMD_RES); + + if(ret == RT_EOK) + { + dbg_log(DBG_LOG, "wait response OK!\r\n"); + } + else + { + uint32_t value; + + value = msc_readl(host, MSC_STAT_OFFSET); + dbg_log(DBG_LOG, "stat=0x%08x\n", value); + value = msc_readl(host, MSC_IREG_OFFSET); + dbg_log(DBG_LOG, "iflag=0x%08x\n", value); + + host->cmd->err = ret; + dbg_log(DBG_LOG, "wait END_CMD_RES timeout[uncompletion]\r\n"); + + return -1; + } + } + + msc_writel(host, MSC_IREG_OFFSET, IFLG_END_CMD_RES); + return 0; +} + +static void do_pio_read(struct jzmmc_host *host, + unsigned int *addr, unsigned int cnt) +{ + int i = 0; + unsigned int status = 0; + + for (i = 0; i < cnt / 4; i++) + { + while (((status = msc_readl(host, MSC_STAT_OFFSET)) + & MSC_STAT_DATA_FIFO_EMPTY)); + + if (check_error_status(host, status)) + { + host->cmd->err = -RT_EIO; + return; + } + *addr++ = msc_readl(host, MSC_RXFIFO_OFFSET); + } + + /* + * These codes handle the last 1, 2 or 3 bytes transfer. + */ + if (cnt & 3) + { + uint32_t n = cnt & 3; + uint32_t data = msc_readl(host, MSC_RXFIFO_OFFSET); + uint8_t *p = (u8 *)addr; + + while (n--) + { + *p++ = data; + data >>= 8; + } + } +} + +static void do_pio_write(struct jzmmc_host *host, + unsigned int *addr, unsigned int cnt) +{ + int i = 0; + unsigned int status = 0; + + for (i = 0; i < (cnt / 4); i++) + { + while (((status = msc_readl(host, MSC_STAT_OFFSET)) + & MSC_STAT_DATA_FIFO_FULL)); + + if (check_error_status(host, status)) + { + host->cmd->err = -RT_EIO; + return; + } + msc_writel(host, MSC_TXFIFO_OFFSET, *addr++); + } + + /* + * These codes handle the last 1, 2 or 3 bytes transfer. + */ + if (cnt & 3) + { + uint32_t data = 0; + uint8_t *p = (uint8_t *)addr; + + for (i = 0; i < (cnt & 3); i++) + data |= *p++ << (8 * i); + + msc_writel(host, MSC_TXFIFO_OFFSET, data); + } +} + +static inline void pio_trans_start(struct jzmmc_host *host, struct rt_mmcsd_data *data) +{ + unsigned int *addr = (unsigned int *)data->buf; + unsigned int cnt = data->blks * data->blksize; + + if (data->flags & DATA_DIR_WRITE) + do_pio_write(host, addr, cnt); + else + do_pio_read(host, addr, cnt); +} + +static void pio_trans_done(struct jzmmc_host *host, struct rt_mmcsd_data *data) +{ + if (host->cmd->err == RT_EOK) + data->bytes_xfered = data->blks * data->blksize; + else + data->bytes_xfered = 0; + + if (host->req->stop) + { + if (jzmmc_polling_status(host, MSC_STAT_AUTO_CMD_DONE) < 0) + host->cmd->err = -RT_EIO; + } + + if (data->flags & DATA_DIR_WRITE) + { + if (jzmmc_polling_status(host, MSC_STAT_PRG_DONE) < 0) + { + host->cmd->err = -RT_EIO; + } + clear_msc_irq(host, IFLG_PRG_DONE); + } + else + { + if (jzmmc_polling_status(host, MSC_STAT_DATA_TRAN_DONE) < 0) + { + host->cmd->err = -RT_EIO; + } + clear_msc_irq(host, IFLG_DATA_TRAN_DONE); + } +} + +/*-------------------------End PIO transfer mode---------------------------*/ + +/* + * Achieve mmc_request here. + */ +static void jzmmc_data_pre(struct jzmmc_host *host, struct rt_mmcsd_data *data) +{ + unsigned int nob = data->blks; + unsigned long cmdat,imsk; + + msc_writel(host, MSC_RDTO_OFFSET, 0xffffff); + msc_writel(host, MSC_NOB_OFFSET, nob); + msc_writel(host, MSC_BLKLEN_OFFSET, data->blksize); + cmdat = MSC_CMDAT_DATA_EN; + + msc_writel(host, MSC_CMDAT_OFFSET, MSC_CMDAT_DATA_EN); + + if (data->flags & DATA_DIR_WRITE) + { + cmdat |= MSC_CMDAT_WRITE; + imsk = IMASK_WR_ALL_DONE | IMASK_CRC_WRITE_ERR; + } + else if (data->flags & DATA_DIR_READ) + { + cmdat &= ~MSC_CMDAT_WRITE; + imsk = IMASK_DMA_DATA_DONE | IMASK_TIME_OUT_READ | IMASK_CRC_READ_ERR; + } + else + { + rt_kprintf("data direction confused\n"); + } + + host->cmdat |= cmdat; + + if (!is_pio_mode(host)) + { + jzmmc_submit_dma(host, data); + clear_msc_irq(host, IFLG_PRG_DONE); + enable_msc_irq(host, imsk); + } +} + +static void jzmmc_data_start(struct jzmmc_host *host, struct rt_mmcsd_data *data) +{ + if (is_pio_mode(host)) + { + pio_trans_start(host, data); + pio_trans_done(host, data); + + disable_pio_mode(host); + } + else + { + rt_err_t ret; + + rt_completion_init(&host->completion); + + /* start DMA */ + disable_msc_irq(host, IFLG_END_CMD_RES); + jzmmc_dma_start(host, data); + + rt_hw_interrupt_umask(host->irqno); + ret = rt_completion_wait(&host->completion, RT_TICK_PER_SECOND); + + if (ret != RT_EOK) + { + rt_kprintf("warning: msc dma timeout\n"); + } + else + { + dbg_log(DBG_LOG, "msc status: 0x%08x\n", msc_readl(host, MSC_STAT_OFFSET)); + + clear_msc_irq(host, IFLG_DATA_TRAN_DONE | IFLG_DMAEND | IFLG_DMA_DATA_DONE | IFLG_TIMEOUT_RES); + disable_msc_irq(host, IMASK_DMA_DATA_DONE | IMASK_CRC_READ_ERR); + +#ifdef DMA_BUFFER + if ((data->flags & DATA_DIR_READ)) + { + if((uint32_t)data->buf & (DMA_ALIGN - 1)) + { + rt_hw_dcache_invalidate_range((rt_ubase_t)(host->_dma_buffer), data->blks * data->blksize); + memcpy(data->buf, host->_dma_buffer, data->blks * data->blksize); + dbg_log(DBG_LOG, "0x%08x <-| %d\n", data->buf, data->blks * data->blksize); + } + else + { + rt_hw_dcache_invalidate_range((rt_ubase_t)(data->buf), data->blks * data->blksize); + } + + } +#endif + } + + jzmmc_data_done(host); + } +} + +static void jzmmc_command_start(struct jzmmc_host *host, struct rt_mmcsd_cmd *cmd) +{ + unsigned long cmdat = 0; + unsigned long imsk; + + /* auto send stop */ + if (host->req->stop) cmdat |= MSC_CMDAT_SEND_AS_STOP; + + /* handle response type */ + switch (cmd->flags & RESP_MASK) + { +#define _CASE(S,D) case RESP_##S: cmdat |= MSC_CMDAT_RESPONSE_##D; break + _CASE(R1, R1); /* r1 */ + _CASE(R2, R2); + _CASE(R3, R3); /* r3 */ + _CASE(R4, R4); /* r4 */ + _CASE(R5, R5); + _CASE(R6, R6); + _CASE(R7, R7); + default: + break; +#undef _CASE + } + if ((cmd->flags & RESP_MASK) == RESP_R1B) cmdat |= MSC_CMDAT_BUSY; + + host->cmdat |= cmdat; + + if (!is_pio_mode(host)) + { + imsk = IMASK_TIME_OUT_RES | IMASK_END_CMD_RES; + enable_msc_irq(host, imsk); + } + + dbg_log(DBG_LOG, "dat: 0x%08x\n", host->cmdat); + dbg_log(DBG_LOG, "resp type: %d\n", cmd->flags & RESP_MASK); + + writel(0xFF, host->hw_base + MSC_RESTO_OFFSET); + writel(0xFFFFFFFF, host->hw_base + MSC_RDTO_OFFSET); + + msc_writel(host, MSC_CMD_OFFSET, cmd->cmd_code); + msc_writel(host, MSC_ARG_OFFSET, cmd->arg); + msc_writel(host, MSC_CMDAT_OFFSET, host->cmdat); + msc_writel(host, MSC_CTRL_OFFSET, MSC_CTRL_START_OP); + + jzmmc_start_clock(host->hw_base); + cmd->err = RT_EOK; + + if (is_pio_mode(host)) + { + wait_cmd_response(host); + jzmmc_command_done(host, host->cmd); + } +} + +static void jzmmc_sdio_request(struct rt_mmcsd_host *mmc, struct rt_mmcsd_req *req) +{ + struct jzmmc_host *host = mmc->private_data; + char direction = '\0'; + + host->req = req; + host->data = req->data; + host->cmd = req->cmd; + host->cmdat = 0; + + dbg_log(DBG_LOG, "CMD: %d ARG: %08X\n", req->cmd->cmd_code, req->cmd->arg); + if (host->data) + { + direction = (host->data->flags & DATA_DIR_WRITE)? 'w' : 'r'; + } + + jzmmc_stop_clock(host->hw_base); + + /* disable pio mode firstly */ + disable_pio_mode(host); + + /* clear status */ + writew(0xFFFF, host->hw_base + MSC_IREG_OFFSET); + disable_msc_irq(host, 0xffffffff); + + if (host->flags & MSC_CMDAT_BUS_WIDTH_4BIT) + { + host->cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT; + } + + if(req->cmd->cmd_code == GO_IDLE_STATE) + { + host->cmdat |= MSC_CMDAT_INIT; + } + + if(host->data) + { + dbg_log(DBG_LOG, "with data, datalen = %d\n", host->data->blksize * host->data->blks); + if (host->data->blksize * host->data->blks < PIO_THRESHOLD) + { + dbg_log(DBG_LOG, " pio mode!\n"); + enable_pio_mode(host); + } + + jzmmc_data_pre(host, host->data); + } + else + { + writew(0, host->hw_base + MSC_BLKLEN_OFFSET); + writew(0, host->hw_base + MSC_NOB_OFFSET); + + enable_pio_mode(host); + } + + jzmmc_command_start(host, host->cmd); + if (host->data) + { + jzmmc_data_start(host, host->data); + } + + mmcsd_req_complete(mmc); +} + +static void jzmmc_isr(int irqno, void* param) +{ + uint32_t pending; + uint32_t pending_; + + struct jzmmc_host * host = (struct jzmmc_host *)param; + + pending_ = msc_readl(host, MSC_IREG_OFFSET); + pending = msc_readl(host, MSC_IREG_OFFSET) & (~ msc_readl(host, MSC_IMASK_OFFSET)); + + if(pending_ & IFLG_CRC_RES_ERR) + { + dbg_log(DBG_WARNING, "RES CRC err\n"); + } + if(pending_ & IFLG_CRC_READ_ERR) + { + dbg_log(DBG_WARNING, "READ CRC err\n"); + } + if(pending_ & IFLG_CRC_WRITE_ERR) + { + dbg_log(DBG_WARNING, "WRITE CRC err\n"); + } + + + if (pending & IFLG_TIMEOUT_RES) + { + host->cmd->err = -RT_ETIMEOUT; + dbg_log(DBG_LOG, "TIMEOUT\n"); + } + else if (pending & IFLG_CRC_READ_ERR) + { + host->cmd->err = -RT_EIO; + dbg_log(DBG_WARNING, "CRC READ\n"); + } + else if (pending & (IFLG_CRC_RES_ERR | IFLG_CRC_WRITE_ERR | IFLG_TIMEOUT_READ)) + { + dbg_log(DBG_ERROR, "MSC ERROR, pending=0x%08x\n", pending); + } + + if (pending & (IFLG_DMA_DATA_DONE | IFLG_WR_ALL_DONE)) + { + dbg_log(DBG_LOG, "msc DMA end!\n"); + + /* disable interrupt */ + rt_hw_interrupt_mask(host->irqno); + rt_completion_done(&host->completion); + } + else if (pending & (MSC_TIME_OUT_RES | MSC_END_CMD_RES)) + { + /* disable interrupt */ + rt_hw_interrupt_mask(host->irqno); + rt_completion_done(&host->completion); + } +} + +rt_inline void jzmmc_clk_autoctrl(struct jzmmc_host *host, unsigned int on) +{ + if(on) + { + if(!clk_is_enabled(host->clock)) + clk_enable(host->clock); + if(!clk_is_enabled(host->clock_gate)) + clk_enable(host->clock_gate); + } + else + { + if(clk_is_enabled(host->clock_gate)) + clk_disable(host->clock_gate); + if(clk_is_enabled(host->clock)) + clk_disable(host->clock); + } +} + +static int jzmmc_hardware_init(struct jzmmc_host *jz_sdio) +{ + uint32_t hw_base = jz_sdio->hw_base; + uint32_t value; + + /* reset mmc/sd controller */ + value = readl(hw_base + MSC_CTRL_OFFSET); + value |= MSC_CTRL_RESET; + writel(value, hw_base + MSC_CTRL_OFFSET); + rt_thread_delay(1); + value &= ~MSC_CTRL_RESET; + writel(value, hw_base + MSC_CTRL_OFFSET); + + while(readl(hw_base + MSC_STAT_OFFSET) & MSC_STAT_IS_RESETTING); + + /* mask all IRQs */ + writel(0xffffffff, hw_base + MSC_IMASK_OFFSET); + writel(0xffffffff, hw_base + MSC_IREG_OFFSET); + + /* set timeout */ + writel(0x100, hw_base + MSC_RESTO_OFFSET); + writel(0x1ffffff, hw_base + MSC_RDTO_OFFSET); + + /* stop MMC/SD clock */ + jzmmc_stop_clock(hw_base); + + return 0; +} + +/* RT-Thread SDIO interface */ +static void jzmmc_sdio_set_iocfg(struct rt_mmcsd_host *host, + struct rt_mmcsd_io_cfg *io_cfg) +{ + struct jzmmc_host * jz_sdio = host->private_data; + rt_uint32_t clkdiv; + + dbg_log(DBG_LOG, "set_iocfg clock: %d\n", io_cfg->clock); + + if (io_cfg->bus_width == MMCSD_BUS_WIDTH_4) + { + dbg_log(DBG_LOG, "MMC: Setting controller bus width to 4\n"); + jz_sdio->flags |= MSC_CMDAT_BUS_WIDTH_4BIT; + } + else + { + jz_sdio->flags &= ~(MSC_CMDAT_BUS_WIDTH_4BIT); + dbg_log(DBG_LOG, "MMC: Setting controller bus width to 1\n"); + } + + if (io_cfg->clock) + { + unsigned int clk_set = 0, clkrt = 0; + unsigned int clk_want = io_cfg->clock; + unsigned int lpm = 0; + + if (io_cfg->clock > 1 * 1000 * 1000) + { + io_cfg->clock = 1000 * 1000; + } + + jzmmc_clk_autoctrl(jz_sdio, 1); + if (clk_want > 3000000) + { + clk_set_rate(jz_sdio->clock, io_cfg->clock); + } + else + { + clk_set_rate(jz_sdio->clock, 24000000); + } + clk_set = clk_get_rate(jz_sdio->clock); + + while (clk_want < clk_set) + { + clkrt++; + clk_set >>= 1; + } + + if (clkrt > 7) + { + dbg_log(DBG_ERROR, "invalid value of CLKRT: " + "ios->clock=%d clk_want=%d " + "clk_set=%d clkrt=%X,\n", + io_cfg->clock, clk_want, clk_set, clkrt); + return; + } + + if (!clkrt) + { + dbg_log(DBG_LOG, "clk_want: %u, clk_set: %luHz\n", io_cfg->clock, clk_get_rate(jz_sdio->clock)); + } + + writel(clkrt, jz_sdio->hw_base + MSC_CLKRT_OFFSET); + + if (clk_set > 25000000) + { + lpm = (0x2 << LPM_DRV_SEL_SHF) | LPM_SMP_SEL; + } + + if(jz_sdio->sdio_clk) + { + writel(lpm, jz_sdio->hw_base + MSC_LPM_OFFSET); + writel(MSC_CTRL_CLOCK_START, jz_sdio->hw_base + MSC_CTRL_OFFSET); + } + else + { + lpm |= LPM_LPM; + writel(lpm, jz_sdio->hw_base + MSC_LPM_OFFSET); + } + } + else + { + jzmmc_clk_autoctrl(jz_sdio, 0); + } + + /* maybe switch power to the card */ + switch (io_cfg->power_mode) + { + case MMCSD_POWER_OFF: + dbg_log(DBG_LOG, "MMCSD_POWER_OFF\r\n"); + break; + case MMCSD_POWER_UP: + dbg_log(DBG_LOG, "MMCSD_POWER_UP\r\n"); + break; + case MMCSD_POWER_ON: + dbg_log(DBG_LOG, "MMCSD_POWER_ON\r\n"); + jzmmc_hardware_init(jz_sdio); + // jz_mmc_set_clock(jz_sdio, io_cfg->clock); + break; + default: + dbg_log(DBG_LOG, "unknown power_mode %d\n", io_cfg->power_mode); + break; + } +} + +static rt_int32_t jzmmc_sdio_detect(struct rt_mmcsd_host *host) +{ + dbg_log(DBG_LOG, "jz47xx_SD_Detect\n"); + + return 0; +} + +static void jzmmc_sdio_enable_sdio_irq(struct rt_mmcsd_host *host, + rt_int32_t enable) +{ + dbg_log(DBG_LOG, "jz47xx_sdio_enable_sdio_irq, enable:%d\n", enable); +} + +static const struct rt_mmcsd_host_ops ops = +{ + jzmmc_sdio_request, + jzmmc_sdio_set_iocfg, + jzmmc_sdio_detect, + jzmmc_sdio_enable_sdio_irq, +}; + +int jzmmc_sdio_init(void) +{ + struct rt_mmcsd_host *host = RT_NULL; + struct jzmmc_host *jz_host = RT_NULL; + +#ifdef RT_USING_MSC0 + host = mmcsd_alloc_host(); + jz_host = rt_malloc_align(sizeof(struct jzmmc_host), 32); + if(!(host && jz_host)) + { + goto err; + } + + rt_memset(jz_host, 0, sizeof(struct jzmmc_host)); + /* set hardware base firstly */ + jz_host->hw_base = MSC0_BASE; + jz_host->clock = clk_get("cgu_msc0"); + jz_host->clock_gate = clk_get("msc0"); +#ifdef DMA_BUFFER + jz_host->_dma_buffer = _dma_buffer_0; +#endif + /* init GPIO (msc0 boot) + * name pin fun + * X1000 MSC0_D0: PA23 1 + * X1000 MSC0_D1: PA22 1 + * X1000 MSC0_D2: PA21 1 + * X1000 MSC0_D3: PA20 1 + * X1000 MSC0_CMD: PA25 1 + * X1000 MSC0_CLK: PA24 1 + */ + { + gpio_set_func(GPIO_PORT_A, GPIO_Pin_20, GPIO_FUNC_1); + gpio_set_func(GPIO_PORT_A, GPIO_Pin_21, GPIO_FUNC_1); + gpio_set_func(GPIO_PORT_A, GPIO_Pin_22, GPIO_FUNC_1); + gpio_set_func(GPIO_PORT_A, GPIO_Pin_23, GPIO_FUNC_1); + gpio_set_func(GPIO_PORT_A, GPIO_Pin_24, GPIO_FUNC_1); + gpio_set_func(GPIO_PORT_A, GPIO_Pin_25, GPIO_FUNC_1); + } + + /* enable MSC0 clock gate. */ + clk_enable(jz_host->clock_gate); + + jz_host->msc_clock = 25UL * 1000 * 1000; /* 25Mhz */ + host->freq_min = 400 * 1000; /* min 400Khz. */ + host->freq_max = 25 * 1000 * 1000; /* max 25Mhz. */ + + // jz_host->msc_clock = 400 * 1000; /* 25Mhz */ + // host->freq_min = 400 * 1000; /* min 400Khz. */ + // host->freq_max = 400 * 1000; /* max 25Mhz. */ + + /* set clock */ + clk_set_rate(jz_host->clock, 50000000); + + host->ops = &ops; + host->valid_ocr = VDD_27_28 | VDD_28_29 | VDD_29_30 | VDD_30_31 | VDD_31_32 | + VDD_32_33 | VDD_33_34 | VDD_34_35 | VDD_35_36; + // host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ | MMCSD_SUP_HIGHSPEED; + host->flags = MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ | MMCSD_SUP_HIGHSPEED; + host->max_seg_size = 65535; + host->max_dma_segs = 2; + host->max_blk_size = 512; + host->max_blk_count = 4096; + host->private_data = jz_host; + + jz_host->host = host; + jz_host->irqno = IRQ_MSC0; + + rt_hw_interrupt_install(jz_host->irqno, jzmmc_isr, jz_host, "msc0"); + rt_hw_interrupt_mask(jz_host->irqno); + + mmcsd_change(host); +#endif // RT_USING_MSC0 + +#ifdef RT_USING_MSC1 + host = mmcsd_alloc_host(); + jz_host = rt_malloc(sizeof(struct jzmmc_host)); + if(!(host && jz_host)) + { + goto err; + } + + jz_host1 = jz_host; // for debug + + rt_memset(jz_host, 0, sizeof(struct jzmmc_host)); + jz_host->hw_base = MSC1_BASE; + jz_host->clock = clk_get("cgu_msc1"); + jz_host->clock_gate = clk_get("msc1"); +#ifdef DMA_BUFFER + jz_host->_dma_buffer = _dma_buffer_1; +#endif + /* init GPIO (paladin msc1 SDIO wifi) + * name pin fun + * X1000 MSC1_D0: PC02 0 + * X1000 MSC1_D1: PC03 0 + * X1000 MSC1_D2: PC04 0 + * X1000 MSC1_D3: PC05 0 + * X1000 MSC1_CMD: PC01 0 + * X1000 MSC1_CLK: PC00 0 + * + */ + { + gpio_set_func(GPIO_PORT_C, GPIO_Pin_0, GPIO_FUNC_0); + gpio_set_func(GPIO_PORT_C, GPIO_Pin_1, GPIO_FUNC_0); + gpio_set_func(GPIO_PORT_C, GPIO_Pin_2, GPIO_FUNC_0); + gpio_set_func(GPIO_PORT_C, GPIO_Pin_3, GPIO_FUNC_0); + gpio_set_func(GPIO_PORT_C, GPIO_Pin_4, GPIO_FUNC_0); + gpio_set_func(GPIO_PORT_C, GPIO_Pin_5, GPIO_FUNC_0); + } + + /* enable MSC1 clock gate. */ + clk_enable(jz_host->clock_gate); + + jz_host->msc_clock = 25UL * 1000 * 1000; /* 25Mhz */ + host->freq_min = 400 * 1000; /* min 400Khz. */ + host->freq_max = 25 * 1000 * 1000; /* max 25Mhz. */ + + /* set clock */ + clk_set_rate(jz_host->clock, BOARD_EXTAL_CLK); + + host->ops = &ops; + host->valid_ocr = VDD_27_28 | VDD_28_29 | VDD_29_30 | VDD_30_31 | VDD_31_32 | + VDD_32_33 | VDD_33_34 | VDD_34_35 | VDD_35_36; + host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ | MMCSD_SUP_HIGHSPEED; + host->max_seg_size = 65535; + host->max_dma_segs = 2; + host->max_blk_size = 512; + host->max_blk_count = 4096; + host->private_data = jz_host; + + jz_host->host = host; + jz_host->irqno = IRQ_MSC1; + + rt_hw_interrupt_install(jz_host->irqno, jzmmc_isr, jz_host, "msc1"); + rt_hw_interrupt_mask(jz_host->irqno); + + mmcsd_change(host); +#endif // RT_USING_MSC1 + + return RT_EOK; + +err: + if(host) + { + mmcsd_free_host(host); + } + if(jz_host) + { + rt_free(jz_host); + } + + return -RT_ENOMEM; +} +INIT_DEVICE_EXPORT(jzmmc_sdio_init); + +#include +int msc_status(void) +{ + uint32_t value; + + if (jz_host1) + { + value = msc_readl(jz_host1, MSC_STAT_OFFSET); + rt_kprintf("status: 0x%08x\n", value); + + value = msc_readl(jz_host1, MSC_IMASK_OFFSET); + rt_kprintf("mask : 0x%08x -> 0x%08x\n", value, ~value); + + value = msc_readl(jz_host1, MSC_IREG_OFFSET); + rt_kprintf("iflag : 0x%08x\n", value); + + rt_kprintf("dma : nda 0x%08x, da 0x%08x, len 0x%04x, cmd 0x%08x\n", msc_readl(jz_host1, MSC_DMANDA_OFFSET), + msc_readl(jz_host1, MSC_DMADA_OFFSET), + msc_readl(jz_host1, MSC_DMALEN_OFFSET), + msc_readl(jz_host1, MSC_DMACMD_OFFSET)); + + rt_kprintf("clock : %s\n", (stopping_clock == 1)? "stopping" : "none stopping"); + } + + return 0; +} +MSH_CMD_EXPORT(msc_status, dump msc status); + +int msc_log(int argc, char** argv) +{ + if (argc == 2) + sdio_log = atoi(argv[1]); + + return 0; +} +MSH_CMD_EXPORT(msc_log, set msc log enable); diff --git a/bsp/x1000/driver/drv_mmc.h b/bsp/x1000/drivers/mmc/drv_mmc.h similarity index 64% rename from bsp/x1000/driver/drv_mmc.h rename to bsp/x1000/drivers/mmc/drv_mmc.h index 06f414344ccf8ff1461ed3e40c756c9d16e3be8e..af12a305133af238cbe5dd2317a1fcb6319f4a38 100644 --- a/bsp/x1000/driver/drv_mmc.h +++ b/bsp/x1000/drivers/mmc/drv_mmc.h @@ -26,13 +26,13 @@ #define MSC_RXFIFO_OFFSET ( 0x38 ) // R, 32, 0x????????, MSC Receive Data FIFO register #define MSC_TXFIFO_OFFSET ( 0x3C ) // W, 32, 0x????????, MSC Transmit Data FIFO register #define MSC_LPM_OFFSET ( 0x40 ) // RW, 32, 0x00000000, MSC Low Power Mode register -#define MSC_DMAC_OFFSET ( 0x44 ) -#define MSC_DMANDA_OFFSET ( 0x48 ) -#define MSC_DMADA_OFFSET ( 0x4C ) -#define MSC_DMALEN_OFFSET ( 0x50 ) -#define MSC_DMACMD_OFFSET ( 0x54 ) -#define MSC_CTRL2_OFFSET ( 0x58 ) -#define MSC_RTCNT_OFFSET ( 0x5C ) +#define MSC_DMAC_OFFSET ( 0x44 ) +#define MSC_DMANDA_OFFSET ( 0x48 ) +#define MSC_DMADA_OFFSET ( 0x4C ) +#define MSC_DMALEN_OFFSET ( 0x50 ) +#define MSC_DMACMD_OFFSET ( 0x54 ) +#define MSC_CTRL2_OFFSET ( 0x58 ) +#define MSC_RTCNT_OFFSET ( 0x5C ) //-------------------------------------------------------------------------- // MMC/SD Control Register field descriptions (MSC_CTRL) @@ -141,75 +141,102 @@ #define MSC_DATA_FIFO_EMP ( 1 << 13 ) #define MSC_DATA_FIFO_FULL ( 1 << 14 ) #define MSC_AUTO_CMD_DONE ( 1 << 15 ) -#define MSC_DMAEND ( 1 << 16 ) -#define MSC_BAR ( 1 << 17 ) -#define MSC_BAE ( 1 << 18 ) -#define MSC_BDE ( 1 << 19 ) -#define MSC_BCE ( 1 << 20 ) -#define MSC_WR_ALL_DONE ( 1 << 23 ) -#define MSC_PIN_LEVEL ( 1 << 24 ) -#define MSC_DMA_DATA_DONE ( 1 << 31 ) +#define MSC_DMAEND ( 1 << 16 ) +#define MSC_BAR ( 1 << 17 ) +#define MSC_BAE ( 1 << 18 ) +#define MSC_BDE ( 1 << 19 ) +#define MSC_BCE ( 1 << 20 ) +#define MSC_WR_ALL_DONE ( 1 << 23 ) +#define MSC_PIN_LEVEL ( 1 << 24 ) +#define MSC_DMA_DATA_DONE ( 1 << 31 ) + +/* MSC Interrupts Mask Register (MSC_IMASK) */ +#define IMASK_DMA_DATA_DONE (1 << 31) +#define IMASK_WR_ALL_DONE (1 << 23) +#define IMASK_AUTO_CMD23_DONE (1 << 30) +#define IMASK_SVS (1 << 29) +#define IMASK_PIN_LEVEL_SHF 24 +#define IMASK_PIN_LEVEL_MASK (0x1f << IMASK_PIN_LEVEL_SHF) +#define IMASK_BCE (1 << 20) +#define IMASK_BDE (1 << 19) +#define IMASK_BAE (1 << 18) +#define IMASK_BAR (1 << 17) +#define IMASK_DMAEND (1 << 16) +#define IMASK_AUTO_CMD12_DONE (1 << 15) +#define IMASK_DATA_FIFO_FULL (1 << 14) +#define IMASK_DATA_FIFO_EMP (1 << 13) +#define IMASK_CRC_RES_ERR (1 << 12) +#define IMASK_CRC_READ_ERR (1 << 11) +#define IMASK_CRC_WRITE_ERR (1 << 10) +#define IMASK_TIME_OUT_RES (1 << 9) +#define IMASK_TIME_OUT_READ (1 << 8) +#define IMASK_SDIO (1 << 7) +#define IMASK_TXFIFO_WR_REQ (1 << 6) +#define IMASK_RXFIFO_RD_REQ (1 << 5) +#define IMASK_END_CMD_RES (1 << 2) +#define IMASK_PRG_DONE (1 << 1) +#define IMASK_DATA_TRAN_DONE (1 << 0) /* MSC Interrupts Status Register (MSC_IREG) */ -#define IFLG_DMA_DATA_DONE (1 << 31) -#define IFLG_WR_ALL_DONE (1 << 23) -#define IFLG_AUTO_CMD23_DONE (1 << 30) -#define IFLG_SVS (1 << 29) -#define IFLG_PIN_LEVEL_SHF 24 -#define IFLG_PIN_LEVEL_MASK (0x1f << IFLG_PIN_LEVEL_SHF) -#define IFLG_BCE (1 << 20) -#define IFLG_BDE (1 << 19) -#define IFLG_BAE (1 << 18) -#define IFLG_BAR (1 << 17) -#define IFLG_DMAEND (1 << 16) -#define IFLG_AUTO_CMD12_DONE (1 << 15) -#define IFLG_DATA_FIFO_FULL (1 << 14) -#define IFLG_DATA_FIFO_EMP (1 << 13) -#define IFLG_CRC_RES_ERR (1 << 12) -#define IFLG_CRC_READ_ERR (1 << 11) -#define IFLG_CRC_WRITE_ERR (1 << 10) -#define IFLG_TIMEOUT_RES (1 << 9) -#define IFLG_TIMEOUT_READ (1 << 8) -#define IFLG_SDIO (1 << 7) -#define IFLG_TXFIFO_WR_REQ (1 << 6) -#define IFLG_RXFIFO_RD_REQ (1 << 5) -#define IFLG_END_CMD_RES (1 << 2) -#define IFLG_PRG_DONE (1 << 1) -#define IFLG_DATA_TRAN_DONE (1 << 0) +#define IFLG_DMA_DATA_DONE (1 << 31) +#define IFLG_WR_ALL_DONE (1 << 23) +#define IFLG_AUTO_CMD23_DONE (1 << 30) +#define IFLG_SVS (1 << 29) +#define IFLG_PIN_LEVEL_SHF 24 +#define IFLG_PIN_LEVEL_MASK (0x1f << IFLG_PIN_LEVEL_SHF) +#define IFLG_BCE (1 << 20) +#define IFLG_BDE (1 << 19) +#define IFLG_BAE (1 << 18) +#define IFLG_BAR (1 << 17) +#define IFLG_DMAEND (1 << 16) +#define IFLG_AUTO_CMD12_DONE (1 << 15) +#define IFLG_DATA_FIFO_FULL (1 << 14) +#define IFLG_DATA_FIFO_EMP (1 << 13) +#define IFLG_CRC_RES_ERR (1 << 12) +#define IFLG_CRC_READ_ERR (1 << 11) +#define IFLG_CRC_WRITE_ERR (1 << 10) +#define IFLG_TIMEOUT_RES (1 << 9) +#define IFLG_TIMEOUT_READ (1 << 8) +#define IFLG_SDIO (1 << 7) +#define IFLG_TXFIFO_WR_REQ (1 << 6) +#define IFLG_RXFIFO_RD_REQ (1 << 5) +#define IFLG_END_CMD_RES (1 << 2) +#define IFLG_PRG_DONE (1 << 1) +#define IFLG_DATA_TRAN_DONE (1 << 0) /* MSC Low Power Mode Register (MSC_LPM) */ -#define LPM_DRV_SEL_SHF 30 -#define LPM_DRV_SEL_MASK (0x3 << LPM_DRV_SEL_SHF) -#define LPM_SMP_SEL (1 << 29) -#define LPM_LPM (1 << 0) +#define LPM_DRV_SEL_SHF 30 +#define LPM_DRV_SEL_MASK (0x3 << LPM_DRV_SEL_SHF) +#define LPM_SMP_SEL (1 << 29) +#define LPM_LPM (1 << 0) /* MSC DMA Control Register (MSC_DMAC) */ -#define DMAC_MODE_SEL (1 << 7) -#define DMAC_AOFST_SHF 5 -#define DMAC_AOFST_MASK (0x3 << DMAC_AOFST_SHF) -#define DMAC_AOFST_0 (0 << DMAC_AOFST_SHF) -#define DMAC_AOFST_1 (1 << DMAC_AOFST_SHF) -#define DMAC_AOFST_2 (2 << DMAC_AOFST_SHF) -#define DMAC_AOFST_3 (3 << DMAC_AOFST_SHF) -#define DMAC_ALIGNEN (1 << 4) -#define DMAC_INCR_SHF 2 -#define DMAC_INCR_MASK (0x3 << DMAC_INCR_SHF) -#define DMAC_INCR_16 (0 << DMAC_INCR_SHF) -#define DMAC_INCR_32 (1 << DMAC_INCR_SHF) -#define DMAC_INCR_64 (2 << DMAC_INCR_SHF) -#define DMAC_DMASEL (1 << 1) -#define DMAC_DMAEN (1 << 0) +#define DMAC_MODE_SEL (1 << 7) +#define DMAC_AOFST_SHF 5 +#define DMAC_AOFST_MASK (0x3 << DMAC_AOFST_SHF) +#define DMAC_AOFST_0 (0 << DMAC_AOFST_SHF) +#define DMAC_AOFST_1 (1 << DMAC_AOFST_SHF) +#define DMAC_AOFST_2 (2 << DMAC_AOFST_SHF) +#define DMAC_AOFST_3 (3 << DMAC_AOFST_SHF) +#define DMAC_ALIGNEN (1 << 4) +#define DMAC_INCR_SHF 2 +#define DMAC_INCR_MASK (0x3 << DMAC_INCR_SHF) +#define DMAC_INCR_16 (0 << DMAC_INCR_SHF) +#define DMAC_INCR_32 (1 << DMAC_INCR_SHF) +#define DMAC_INCR_64 (2 << DMAC_INCR_SHF) +#define DMAC_DMASEL (1 << 1) +#define DMAC_DMAEN (1 << 0) /* MSC DMA Command Register (MSC_DMACMD) */ -#define DMACMD_IDI_SHF 24 -#define DMACMD_IDI_MASK (0xff << DMACMD_IDI_SHF) -#define DMACMD_ID_SHF 16 -#define DMACMD_ID_MASK (0xff << DMACMD_ID_SHF) -#define DMACMD_OFFSET_SHF 9 -#define DMACMD_OFFSET_MASK (0x3 << DMACMD_OFFSET_SHF) -#define DMACMD_ALIGN_EN (1 << 8) -#define DMACMD_ENDI (1 << 1) -#define DMACMD_LINK (1 << 0) +#define DMACMD_IDI_SHF 24 +#define DMACMD_IDI_MASK (0xff << DMACMD_IDI_SHF) +#define DMACMD_ID_SHF 16 +#define DMACMD_ID_MASK (0xff << DMACMD_ID_SHF) +#define DMACMD_OFFSET_SHF 9 +#define DMACMD_OFFSET_MASK (0x3 << DMACMD_OFFSET_SHF) +#define DMACMD_ALIGN_EN (1 << 8) +#define DMACMD_ENDI (1 << 1) +#define DMACMD_LINK (1 << 0) /* Error codes */ enum mmc_result_t { @@ -238,26 +265,42 @@ enum mmc_result_t { MMC_ERROR_DRIVER_FAILURE, }; -struct jz47xx_sdio +struct jz_sdma_desc +{ + volatile rt_uint32_t nda; + volatile rt_uint32_t da; + volatile rt_uint32_t len; + volatile rt_uint32_t dcmd; +}; + +struct jzmmc_host { struct rt_mmcsd_host *host; - struct rt_mmcsd_req *req; - struct rt_mmcsd_cmd *cmd; + struct rt_mmcsd_req *req; + struct rt_mmcsd_cmd *cmd; + struct rt_mmcsd_data *data; uint32_t hw_base; uint32_t msc_clock; uint32_t irqno; - uint32_t flag; - + uint32_t flags; + /* 确保是32字节对齐 */ + struct jz_sdma_desc dma_desc; + //uint32_t reserve[4]; + + unsigned int cmdat; struct rt_completion completion; + - struct clk *clock; - struct clk *clock_gate; + struct clk *clock; + struct clk *clock_gate; - int sdio_clk; /* clock for sdio */ + uint8_t * _dma_buffer; + int sdio_clk; /* clock for sdio */ rt_uint32_t current_status; }; +int jzmmc_sdio_init(void); #endif /* DRV_MMC_H__ */ diff --git a/bsp/x1000/drivers/sfc/SConscript b/bsp/x1000/drivers/sfc/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..6224026358941c8205e36bf63b73419465186c26 --- /dev/null +++ b/bsp/x1000/drivers/sfc/SConscript @@ -0,0 +1,21 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +CPPPATH = [cwd] + +sfc_src = Split(''' +drv_sfc.c +''') +sfc_group = DefineGroup('drv_sfc', sfc_src, depend = ['RT_USING_MTD_NOR'], CPPPATH = CPPPATH) + +part_src = Split(''' +drv_sfc_gd25qxx_mtd_partition.c +drv_sfc_gd25qxx_mtd.c +mtd_nor_partition.c +''') +part_group = DefineGroup('sfc_part', part_src, depend = ['RT_USING_MTD_NOR'], CPPPATH = CPPPATH) + +group = sfc_group + part_group +Return('group') diff --git a/bsp/x1000/drivers/sfc/drv_sfc.c b/bsp/x1000/drivers/sfc/drv_sfc.c new file mode 100644 index 0000000000000000000000000000000000000000..ff6092af70fe454341278f37ee1c3f2d2aaff39a --- /dev/null +++ b/bsp/x1000/drivers/sfc/drv_sfc.c @@ -0,0 +1,1502 @@ +/* + * drv_sfc.c + * + * Created on: 2016年4月5日 + * Author: Urey + */ + +/********************************************************************************************************* +** Include Files +*********************************************************************************************************/ +#include +#include +#include + +#include +#include + +#include "board.h" +#include "drv_clock.h" +#include "drv_gpio.h" +#include "drv_sfc.h" + +//#define SFC_DEBUG +#if defined(SFC_DEBUG) +#define SFC_DBG(...) rt_kprintf("[SFC]"),rt_kprintf(__VA_ARGS__) +#else +#define SFC_DBG(...) +#endif + +#define L2CACHE_ALIGN_SIZE 256 +#define THRESHOLD 32 +#define PAGE_SIZE 4096 + +/* Max time can take up to 3 seconds! */ +#define MAX_READY_WAIT_TIME 3000 /* the time of erase BE(64KB) */ + +#define STATUS_SUSPND (1<<0) + + +#define tCHSH 5 //hold +#define tSLCH 5 //setup +#define tSHSL_RD 20 //interval +#define tSHSL_WR 30 + +static void sfc_writel(struct sfc *sfc, uint16_t offset, u32 value) +{ + writel(value, (uint32_t)sfc->iomem + offset); +} + +static uint32_t sfc_readl(struct sfc *sfc, uint16_t offset) +{ + return readl((uint32_t)sfc->iomem + offset); +} + +static void sfc_init(struct sfc *sfc) +{ + uint32_t n; + for (n = 0; n < N_MAX; n++) + { + sfc_writel(sfc, SFC_TRAN_CONF(n), 0); + sfc_writel(sfc, SFC_DEV_ADDR(n), 0); + sfc_writel(sfc, SFC_DEV_ADDR_PLUS(n), 0); + } + + //sfc_writel(sfc, SFC_GLB, ((1 << 7) | (1 << 3))); + sfc_writel(sfc, SFC_DEV_CONF, 0); + sfc_writel(sfc, SFC_DEV_STA_EXP, 0); + sfc_writel(sfc, SFC_DEV_STA_MSK, 0); + sfc_writel(sfc, SFC_TRAN_LEN, 0); + sfc_writel(sfc, SFC_MEM_ADDR, 0); + sfc_writel(sfc, SFC_TRIG, 0); + sfc_writel(sfc, SFC_SCR, 0); + sfc_writel(sfc, SFC_INTC, 0); + sfc_writel(sfc, SFC_CGE, 0); + sfc_writel(sfc, SFC_RM_DR, 0); +} + +static void sfc_stop(struct sfc*sfc) +{ + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_TRIG); + tmp |= TRIG_STOP; + sfc_writel(sfc, SFC_TRIG, tmp); +} + +static void sfc_start(struct sfc *sfc) +{ + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_TRIG); + tmp |= TRIG_START; + sfc_writel(sfc, SFC_TRIG, tmp); +} + +static void sfc_flush_fifo(struct sfc *sfc) +{ + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_TRIG); + tmp |= TRIG_FLUSH; + sfc_writel(sfc, SFC_TRIG, tmp); +} + +static void sfc_ce_invalid_value(struct sfc *sfc, uint32_t value) +{ + if (value == 0) + { + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_DEV_CONF); + tmp &= ~DEV_CONF_CEDL; + sfc_writel(sfc, SFC_DEV_CONF, tmp); + } + else + { + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_DEV_CONF); + tmp |= DEV_CONF_CEDL; + sfc_writel(sfc, SFC_DEV_CONF, tmp); + } +} + +static void sfc_hold_invalid_value(struct sfc *sfc, uint32_t value) +{ + if (value == 0) + { + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_DEV_CONF); + tmp &= ~DEV_CONF_HOLDDL; + sfc_writel(sfc, SFC_DEV_CONF, tmp); + } + else + { + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_DEV_CONF); + tmp |= DEV_CONF_HOLDDL; + sfc_writel(sfc, SFC_DEV_CONF, tmp); + } +} + +static void sfc_wp_invalid_value(struct sfc *sfc, uint32_t value) +{ + if (value == 0) + { + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_DEV_CONF); + tmp &= ~DEV_CONF_WPDL; + sfc_writel(sfc, SFC_DEV_CONF, tmp); + } + else + { + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_DEV_CONF); + tmp |= DEV_CONF_WPDL; + sfc_writel(sfc, SFC_DEV_CONF, tmp); + } +} + +static void sfc_clear_end_intc(struct sfc *sfc) +{ + uint32_t tmp = 0; + tmp = sfc_readl(sfc, SFC_SCR); + tmp |= CLR_END; + sfc_writel(sfc, SFC_SCR, tmp); + tmp = sfc_readl(sfc, SFC_SCR); +} + +static void sfc_clear_treq_intc(struct sfc *sfc) +{ + uint32_t tmp = 0; + tmp = sfc_readl(sfc, SFC_SCR); + tmp |= CLR_TREQ; + sfc_writel(sfc, SFC_SCR, tmp); +} + +static void sfc_clear_rreq_intc(struct sfc *sfc) +{ + uint32_t tmp = 0; + tmp = sfc_readl(sfc, SFC_SCR); + tmp |= CLR_RREQ; + sfc_writel(sfc, SFC_SCR, tmp); +} + +static void sfc_clear_over_intc(struct sfc *sfc) +{ + uint32_t tmp = 0; + tmp = sfc_readl(sfc, SFC_SCR); + tmp |= CLR_OVER; + sfc_writel(sfc, SFC_SCR, tmp); +} + +static void sfc_clear_under_intc(struct sfc *sfc) +{ + uint32_t tmp = 0; + tmp = sfc_readl(sfc, SFC_SCR); + tmp |= CLR_UNDER; + sfc_writel(sfc, SFC_SCR, tmp); +} + +static void sfc_clear_all_intc(struct sfc *sfc) +{ + sfc_writel(sfc, SFC_SCR, 0x1f); +} + +static void sfc_mask_all_intc(struct sfc *sfc) +{ + sfc_writel(sfc, SFC_INTC, 0x1f); +} + +static void sfc_mode(struct sfc *sfc, uint32_t channel, uint32_t value) +{ + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_TRAN_CONF(channel)); + tmp &= ~(TRAN_CONF_TRAN_MODE_MSK << TRAN_CONF_TRAN_MODE_OFFSET); + tmp |= (value << TRAN_CONF_TRAN_MODE_OFFSET); + sfc_writel(sfc, SFC_TRAN_CONF(channel), tmp); +} + +static void sfc_set_phase_num(struct sfc *sfc,uint32_t num) +{ + uint32_t tmp; + + tmp = sfc_readl(sfc, SFC_GLB); + tmp &= ~GLB_PHASE_NUM_MSK; + tmp |= num << GLB_PHASE_NUM_OFFSET; + sfc_writel(sfc, SFC_GLB, tmp); +} + +static void sfc_clock_phase(struct sfc *sfc, uint32_t value) +{ + if (value == 0) + { + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_DEV_CONF); + tmp &= ~DEV_CONF_CPHA; + sfc_writel(sfc, SFC_DEV_CONF, tmp); + } + else + { + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_DEV_CONF); + tmp |= DEV_CONF_CPHA; + sfc_writel(sfc, SFC_DEV_CONF, tmp); + } +} + +static void sfc_clock_polarity(struct sfc *sfc, uint32_t value) +{ + if (value == 0) + { + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_DEV_CONF); + tmp &= ~DEV_CONF_CPOL; + sfc_writel(sfc, SFC_DEV_CONF, tmp); + } + else + { + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_DEV_CONF); + tmp |= DEV_CONF_CPOL; + sfc_writel(sfc, SFC_DEV_CONF, tmp); + } +} + +static void sfc_threshold(struct sfc *sfc, uint32_t value) +{ + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_GLB); + tmp &= ~GLB_THRESHOLD_MSK; + tmp |= value << GLB_THRESHOLD_OFFSET; + sfc_writel(sfc, SFC_GLB, tmp); +} + + +static void sfc_smp_delay(struct sfc *sfc, uint32_t value) +{ + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_DEV_CONF); + tmp &= ~DEV_CONF_SMP_DELAY_MSK; + tmp |= value << DEV_CONF_SMP_DELAY_OFFSET; + sfc_writel(sfc, SFC_DEV_CONF, tmp); +} + +static void sfc_hold_delay(struct sfc *sfc, uint32_t value) +{ + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_DEV_CONF); + tmp &= ~DEV_CONF_THOLD_MSK; + tmp |= value << DEV_CONF_THOLD_OFFSET; + sfc_writel(sfc, SFC_DEV_CONF, tmp); +} + +static void sfc_setup_delay(struct sfc *sfc, uint32_t value) +{ + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_DEV_CONF); + tmp &= ~DEV_CONF_TSETUP_MSK; + tmp |= value << DEV_CONF_TSETUP_OFFSET; + sfc_writel(sfc, SFC_DEV_CONF, tmp); +} + +static void sfc_interval_delay(struct sfc *sfc, uint32_t value) +{ + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_DEV_CONF); + tmp &= ~DEV_CONF_TSH_MSK; + tmp |= value << DEV_CONF_TSH_OFFSET; + sfc_writel(sfc, SFC_DEV_CONF, tmp); +} + +static void sfc_set_cmd_length(struct sfc *sfc, uint32_t value) +{ + if (value == 1) + { + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_DEV_CONF); + tmp &= ~TRAN_CONF_CMD_LEN; + sfc_writel(sfc, SFC_DEV_CONF, tmp); + } + else + { + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_DEV_CONF); + tmp |= TRAN_CONF_CMD_LEN; + sfc_writel(sfc, SFC_DEV_CONF, tmp); + } +} + +static void sfc_transfer_direction(struct sfc *sfc, uint32_t value) +{ + if (value == GLB_TRAN_DIR_READ) + { + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_GLB); + tmp &= ~GLB_TRAN_DIR; + sfc_writel(sfc, SFC_GLB, tmp); + } + else + { + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_GLB); + tmp |= GLB_TRAN_DIR; + sfc_writel(sfc, SFC_GLB, tmp); + } +} + + +static int set_flash_timing(struct sfc *sfc, uint32_t t_hold, uint32_t t_setup, uint32_t t_shslrd, uint32_t t_shslwr) +{ + uint32_t c_hold; + uint32_t c_setup; + uint32_t t_in, c_in, val; + uint64_t cycle; + + cycle = 1000000000UL / sfc->src_clk; + + c_hold = t_hold / cycle; + if (c_hold > 0) + val = c_hold - 1; + sfc_hold_delay(sfc, val); + + c_setup = t_setup / cycle; + if(c_setup > 0) + val = c_setup - 1; + sfc_setup_delay(sfc, val); + + t_in = max(t_shslrd, t_shslwr); + c_in = t_in / cycle; + if(c_in > 0) + val = c_in - 1; + sfc_interval_delay(sfc, val); + + return 0; +} + +static void sfc_set_length(struct sfc *sfc, uint32_t value) +{ + sfc_writel(sfc, SFC_TRAN_LEN, value); +} + +static void sfc_transfer_mode(struct sfc *sfc, uint32_t value) +{ + if (value == 0) + { + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_GLB); + tmp &= ~GLB_OP_MODE; + sfc_writel(sfc, SFC_GLB, tmp); + } + else + { + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_GLB); + tmp |= GLB_OP_MODE; + sfc_writel(sfc, SFC_GLB, tmp); + } +} + +static void sfc_read_data(struct sfc *sfc, uint32_t *value) +{ + *value = sfc_readl(sfc, SFC_RM_DR); +} + +static void sfc_write_data(struct sfc *sfc, const uint32_t value) +{ + sfc_writel(sfc, SFC_RM_DR, value); +} + +uint32_t sfc_fifo_num(struct sfc *sfc) +{ + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_SR); + tmp &= (0x7f << 16); + tmp = tmp >> 16; + return tmp; +} + +static uint32_t cpu_read_rxfifo(struct sfc *sfc) +{ + uint32_t i; + uint32_t align_len = 0; + uint32_t fifo_num = 0; + uint32_t data[1] = {0}; + uint32_t last_word = 0; + + align_len = RT_ALIGN(sfc->transfer->len, 4); + + if (((align_len - sfc->transfer->cur_len) / 4) > THRESHOLD) + { + fifo_num = THRESHOLD; + last_word = 0; + } + else + { + /* last aligned THRESHOLD data*/ + if (sfc->transfer->len % 4) + { + fifo_num = (align_len - sfc->transfer->cur_len) / 4 - 1; + last_word = 1; + } + else + { + fifo_num = (align_len - sfc->transfer->cur_len) / 4; + last_word = 0; + } + } + + for (i = 0; i < fifo_num; i++) + { + sfc_read_data(sfc, (uint32_t *) sfc->transfer->data); + sfc->transfer->data += 4; + sfc->transfer->cur_len += 4; + } + + /* last word */ + if (last_word == 1) + { + sfc_read_data(sfc, data); + rt_memcpy((void *) sfc->transfer->data, data, sfc->transfer->len % 4); + + sfc->transfer->data += sfc->transfer->len % 4; + sfc->transfer->cur_len += 4; + } + + return 0; +} + +static uint32_t cpu_write_txfifo(struct sfc *sfc) +{ + uint32_t i; + uint32_t align_len = 0; + uint32_t fifo_num = 0; + + + align_len = RT_ALIGN(sfc->transfer->len , 4); + + if (((align_len - sfc->transfer->cur_len) / 4) > THRESHOLD){ + fifo_num = THRESHOLD; + } else { + fifo_num = (align_len - sfc->transfer->cur_len) / 4; + } + + for(i = 0; i < fifo_num; i++) { + sfc_write_data(sfc, *(uint32_t *)sfc->transfer->data); + sfc->transfer->data += 4; + sfc->transfer->cur_len += 4; + } + + return 0; +} + + +static int ssi_underrun(struct sfc *sfc) +{ + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_SR); + if(tmp & CLR_UNDER) + return 1; + else + return 0; +} + +static int ssi_overrun(struct sfc *sfc) +{ + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_SR); + if(tmp & CLR_OVER) + return 1; + else + return 0; +} + +static int rxfifo_rreq(struct sfc *sfc) +{ + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_SR); + if(tmp & CLR_RREQ) + return 1; + else + return 0; +} + +static int txfifo_treq(struct sfc *sfc) +{ + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_SR); + if(tmp & CLR_TREQ) + return 1; + else + return 0; +} + +static int sfc_end(struct sfc *sfc) +{ + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_SR); + if(tmp & CLR_END) + return 1; + else + return 0; +} +static uint32_t sfc_get_sta_rt(struct sfc *sfc) +{ + return sfc_readl(sfc,SFC_DEV_STA_RT); +} +static uint32_t sfc_get_fsm(struct sfc *sfc) +{ + return sfc_readl(sfc,SFC_FSM); +} +static void sfc_set_addr_length(struct sfc *sfc, uint32_t channel, uint32_t value) +{ + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_TRAN_CONF(channel)); + tmp &= ~(ADDR_WIDTH_MSK); + tmp |= (value << ADDR_WIDTH_OFFSET); + sfc_writel(sfc, SFC_TRAN_CONF(channel), tmp); +} + +static void sfc_cmd_enble(struct sfc *sfc, uint32_t channel, uint32_t value) +{ + if (value == ENABLE) + { + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_TRAN_CONF(channel)); + tmp |= TRAN_CONF_CMDEN; + sfc_writel(sfc, SFC_TRAN_CONF(channel), tmp); + } + else + { + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_TRAN_CONF(channel)); + tmp &= ~TRAN_CONF_CMDEN; + sfc_writel(sfc, SFC_TRAN_CONF(channel), tmp); + } +} + +static void sfc_data_en(struct sfc *sfc, uint32_t channel, uint32_t value) +{ + if (value == 1) + { + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_TRAN_CONF(channel)); + tmp |= TRAN_CONF_DATEEN; + sfc_writel(sfc, SFC_TRAN_CONF(channel), tmp); + } + else + { + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_TRAN_CONF(channel)); + tmp &= ~TRAN_CONF_DATEEN; + sfc_writel(sfc, SFC_TRAN_CONF(channel), tmp); + } +} + +static void sfc_phase_format(struct sfc *sfc, uint32_t channel, uint32_t value) +{ + if (value == 1) + { + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_TRAN_CONF(channel)); + tmp |= TRAN_CONF_FMAT; + sfc_writel(sfc, SFC_TRAN_CONF(channel), tmp); + } + else + { + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_TRAN_CONF(channel)); + tmp &= ~TRAN_CONF_FMAT; + sfc_writel(sfc, SFC_TRAN_CONF(channel), tmp); + } +} + +static void sfc_write_cmd(struct sfc *sfc, uint32_t channel, uint32_t value) +{ + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_TRAN_CONF(channel)); + tmp &= ~TRAN_CONF_CMD_MSK; + tmp |= value; + sfc_writel(sfc, SFC_TRAN_CONF(channel), tmp); +} + +static void sfc_dev_addr(struct sfc *sfc, uint32_t channel, uint32_t value) +{ + sfc_writel(sfc, SFC_DEV_ADDR(channel), value); +} + + +static void sfc_dev_data_dummy_bytes(struct sfc *sfc, uint32_t channel, uint32_t value) +{ + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_TRAN_CONF(channel)); + tmp &= ~TRAN_CONF_DMYBITS_MSK; + tmp |= value << DMYBITS_OFFSET; + sfc_writel(sfc, SFC_TRAN_CONF(channel), tmp); +} + +static void sfc_dev_addr_plus(struct sfc *sfc, uint32_t channel, uint32_t value) +{ + sfc_writel(sfc, SFC_DEV_ADDR_PLUS(channel), value); +} + +static void sfc_dev_pollen(struct sfc *sfc, uint32_t channel, uint32_t value) +{ + uint32_t tmp; + tmp = sfc_readl(sfc, SFC_TRAN_CONF(channel)); + if(value == 1) + tmp |= TRAN_CONF_POLLEN; + else + tmp &= ~(TRAN_CONF_POLLEN); + + sfc_writel(sfc, SFC_TRAN_CONF(channel), tmp); +} + +static void sfc_dev_sta_exp(struct sfc *sfc, uint32_t value) +{ + sfc_writel(sfc, SFC_DEV_STA_EXP, value); +} + +static void sfc_dev_sta_msk(struct sfc *sfc, uint32_t value) +{ + sfc_writel(sfc, SFC_DEV_STA_MSK, value); +} + +static void sfc_enable_all_intc(struct sfc *sfc) +{ + sfc_writel(sfc, SFC_INTC, 0); +} + +static void sfc_set_mem_addr(struct sfc *sfc,uint32_t addr ) +{ + sfc_writel(sfc, SFC_MEM_ADDR, addr); +} + +static int sfc_start_transfer(struct sfc *sfc) +{ + int err; + sfc_clear_all_intc(sfc); + sfc_enable_all_intc(sfc); + sfc_start(sfc); + err = rt_completion_wait(&sfc->done,RT_TICK_PER_SECOND * 10); + if (RT_EOK != err) + { + sfc_mask_all_intc(sfc); + sfc_clear_all_intc(sfc); + SFC_DBG("line:%d Timeout for ACK from SFC device\n", __LINE__); + return -RT_ETIMEOUT; + } + return 0; +} + +static void sfc_phase_transfer(struct sfc *sfc,struct sfc_transfer * transfer,uint32_t channel) +{ + sfc_flush_fifo(sfc); + sfc_set_addr_length(sfc,channel,transfer->addr_len); + sfc_cmd_enble(sfc,channel,ENABLE); + sfc_write_cmd(sfc,channel,transfer->cmd_info->cmd); + sfc_dev_data_dummy_bytes(sfc,channel,transfer->data_dummy_bits); + sfc_data_en(sfc,channel,transfer->cmd_info->dataen); + sfc_dev_addr(sfc, channel,transfer->addr); + sfc_dev_addr_plus(sfc,channel,transfer->addr_plus); + sfc_mode(sfc,channel,transfer->sfc_mode); + sfc_phase_format(sfc,channel,0);/*default 0,dummy bits is blow the addr*/ +} +static void common_cmd_request_transfer(struct sfc *sfc,struct sfc_transfer *transfer,uint32_t channel) +{ + sfc_phase_transfer(sfc,transfer,channel); + sfc_dev_sta_exp(sfc,0); + sfc_dev_sta_msk(sfc,0); + sfc_dev_pollen(sfc,channel,DISABLE); +} + +static void poll_cmd_request_transfer(struct sfc *sfc,struct sfc_transfer *transfer,uint32_t channel) +{ + struct cmd_info *cmd = transfer->cmd_info; + sfc_phase_transfer(sfc,transfer,channel); + sfc_dev_sta_exp(sfc,cmd->sta_exp); + sfc_dev_sta_msk(sfc,cmd->sta_msk); + sfc_dev_pollen(sfc,channel,ENABLE); +} +static void sfc_glb_info_config(struct sfc *sfc,struct sfc_transfer *transfer) +{ + sfc_transfer_direction(sfc, transfer->direction); + if ((transfer->ops_mode == DMA_OPS)) + { + sfc_set_length(sfc, transfer->len); + if (transfer->direction == GLB_TRAN_DIR_READ) + r4k_dma_cache_sync((uint32_t) transfer->data, transfer->len, + DMA_FROM_DEVICE); + else + r4k_dma_cache_sync((uint32_t) transfer->data, transfer->len, + DMA_TO_DEVICE); + sfc_set_mem_addr(sfc, PHYS(transfer->data)); + sfc_transfer_mode(sfc, DMA_MODE); + } + else + { + sfc_set_length(sfc, transfer->len); + sfc_set_mem_addr(sfc, 0); + sfc_transfer_mode(sfc, SLAVE_MODE); + } +} + +#ifdef DEBUG +static void dump_transfer(struct sfc_transfer *xfer,uint32_t num) +{ + rt_kprintf("\n"); + rt_kprintf("cmd[%d].cmd = 0x%02x\n",num,xfer->cmd_info->cmd); + rt_kprintf("cmd[%d].addr_len = %d\n",num,xfer->addr_len); + rt_kprintf("cmd[%d].dummy_byte = %d\n",num,xfer->data_dummy_bits); + rt_kprintf("cmd[%d].dataen = %d\n",num,xfer->cmd_info->dataen); + rt_kprintf("cmd[%d].sta_exp = %d\n",num,xfer->cmd_info->sta_exp); + rt_kprintf("cmd[%d].sta_msk = %d\n",num,xfer->cmd_info->sta_msk); + + + rt_kprintf("transfer[%d].addr = 0x%08x\n",num,xfer->addr); + rt_kprintf("transfer[%d].len = %d\n",num,xfer->len); + rt_kprintf("transfer[%d].data = 0x%p\n",num,xfer->data); + rt_kprintf("transfer[%d].direction = %d\n",num,xfer->direction); + rt_kprintf("transfer[%d].sfc_mode = %d\n",num,xfer->sfc_mode); + rt_kprintf("transfer[%d].ops_mode = %d\n",num,xfer->ops_mode); +} +#endif + +static int sfc_sync(struct sfc *sfc, struct sfc_message *message) +{ + struct sfc_transfer *xfer; + int phase_num = 0,ret = 0; + + sfc_set_length(sfc, 0); + + rt_list_for_each_entry(xfer, &message->transfers, transfer_list) + { + if (xfer->cmd_info->sta_msk == 0) + { + common_cmd_request_transfer(sfc, xfer, phase_num); + } + else + { + poll_cmd_request_transfer(sfc, xfer, phase_num); + } + if (xfer->addr_len || xfer->len) + sfc_glb_info_config(sfc, xfer); + phase_num++; + message->actual_length += xfer->len; + if (xfer->len > 0) + sfc->transfer = xfer; + } + sfc_set_phase_num(sfc,phase_num); + ret = sfc_start_transfer(sfc); + rt_list_remove(&message->transfers); + return ret; +} + +static void sfc_transfer_del(struct sfc_transfer *t) +{ + rt_list_remove(&t->transfer_list); +} + +static void sfc_message_add_tail(struct sfc_transfer *t, struct sfc_message *m) +{ + rt_list_insert_before(&m->transfers, &t->transfer_list); +} + +static void sfc_message_init(struct sfc_message *m) +{ + rt_memset(m, 0, sizeof *m); + rt_list_init(&m->transfers); +} + +static void jz_sfc_pio_irq(int vector,void *param) +{ + struct sfc *sfc = (struct sfc *)param; + if (ssi_underrun(sfc)) + { + sfc_clear_under_intc(sfc); + rt_completion_done(&sfc->done); + return ; + } + + if (ssi_overrun(sfc)) + { + sfc_clear_over_intc(sfc); + rt_completion_done(&sfc->done); + return ; + } + + if (rxfifo_rreq(sfc)) + { + sfc_clear_rreq_intc(sfc); + cpu_read_rxfifo(sfc); + return ; + } + + if (txfifo_treq(sfc)) + { + sfc_clear_treq_intc(sfc); + cpu_write_txfifo(sfc); + return ; + } + + if (sfc_end(sfc)) + { + sfc_mask_all_intc(sfc); + sfc_clear_end_intc(sfc); + rt_completion_done(&sfc->done); + return ; + } +} + + +static int jz_sfc_init_setup(struct sfc *sfc) +{ + sfc_init(sfc); + sfc_stop(sfc); + + /*set hold high*/ + sfc_hold_invalid_value(sfc, 1); + /*set wp high*/ + sfc_wp_invalid_value(sfc, 1); + + sfc_clear_all_intc(sfc); + sfc_mask_all_intc(sfc); + + sfc_threshold(sfc, sfc->threshold); + /*config the sfc pin init state*/ + sfc_clock_phase(sfc, 0); + sfc_clock_polarity(sfc, 0); + sfc_ce_invalid_value(sfc, 1); + + + sfc_transfer_mode(sfc, SLAVE_MODE); + if (sfc->src_clk >= 100000000) + { + sfc_smp_delay(sfc, DEV_CONF_HALF_CYCLE_DELAY); + } + return 0; +} + +static struct sfc* jz_sfc_init(void) +{ + struct sfc *sfc = (struct sfc *)rt_malloc(sizeof(struct sfc)); + if(sfc == RT_NULL) + return RT_NULL; + + sfc->iomem = (void *)SFC_BASE; + sfc->irq = IRQ_SFC; + sfc->clk = clk_get("cgu_ssi"); + sfc->clk_gate = clk_get("sfc"); + sfc->src_clk = 100000000L; + if(clk_get_rate(sfc->clk) >= sfc->src_clk) + clk_set_rate(sfc->clk, sfc->src_clk); + else + clk_set_rate(sfc->clk, sfc->src_clk); + + clk_enable(sfc->clk); + clk_enable(sfc->clk_gate); + + sfc->threshold = THRESHOLD; + + /* Init IPC */ + rt_completion_init(&(sfc->done)); + + /* Request SFC IRQ */ + rt_hw_interrupt_install(sfc->irq,jz_sfc_pio_irq,sfc,"SFC"); + rt_hw_interrupt_umask(sfc->irq); + + /* SFC controller initializations for SFC */ + jz_sfc_init_setup(sfc); + rt_completion_init(&sfc->done); + + return sfc; +} + + + +static int sfc_flash_read_id(struct sfc_flash *flash, uint8_t command, uint32_t addr, uint32_t addr_len, size_t len, uint32_t dummy_byte) +{ + + struct sfc_transfer transfer; + struct sfc_message message; + struct cmd_info cmd; + int ret; + uint32_t chip_id = 0; + + sfc_message_init(&message); + rt_memset(&transfer, 0, sizeof(transfer)); + rt_memset(&cmd, 0, sizeof(cmd)); + + cmd.cmd = command; + cmd.dataen = ENABLE; + + transfer.addr_len = addr_len; + transfer.data_dummy_bits = dummy_byte; + transfer.addr = addr; + transfer.len = len; + transfer.data =(uint8_t *)&chip_id; + transfer.ops_mode = CPU_OPS; + transfer.sfc_mode = TM_STD_SPI; + transfer.direction = GLB_TRAN_DIR_READ; + transfer.cmd_info = &cmd; + sfc_message_add_tail(&transfer, &message); + + + ret = sfc_sync(flash->sfc, &message); + if (ret) + { + SFC_DBG("sfc_sync error ! %s %s %d\n", __FILE__, __func__, __LINE__); + ret = -RT_EIO; + } + + return chip_id & 0x00ffffff; +} + + +static uint32_t sfc_flash_do_read(struct sfc_flash *flash,uint8_t command,uint32_t addr,uint32_t addr_len,uint8_t *buf,size_t len,uint32_t dummy_byte) +{ + struct sfc_transfer transfer; + struct sfc_message message; + struct cmd_info cmd; + int ret; + + sfc_message_init(&message); + rt_memset(&transfer, 0, sizeof(transfer)); + rt_memset(&cmd, 0, sizeof(cmd)); + + cmd.cmd = command; + cmd.dataen = ENABLE; + + transfer.addr_len = addr_len; + transfer.data_dummy_bits = dummy_byte; + transfer.addr = addr; + transfer.len = len; + transfer.data = buf; + transfer.cur_len = 0; + if(len >= L2CACHE_ALIGN_SIZE) + transfer.ops_mode = DMA_OPS; + else + transfer.ops_mode = CPU_OPS; + + transfer.sfc_mode = flash->sfc_mode; + transfer.direction = GLB_TRAN_DIR_READ; + transfer.cmd_info = &cmd; + sfc_message_add_tail(&transfer, &message); + + ret = sfc_sync(flash->sfc, &message); + if (ret) + { + SFC_DBG("sfc_sync error ! %s %s %d\n", __FILE__, __func__, __LINE__); + ret = -RT_EIO; + } + /*fix the cache line problem,when use jffs2 filesystem must be flush cache twice*/ + if(transfer.ops_mode == DMA_OPS) + r4k_dma_cache_sync((rt_base_t)buf, len, DMA_FROM_DEVICE); + + return message.actual_length; +} + +static unsigned int sfc_flash_do_write(struct sfc_flash *flash,uint8_t command,uint32_t addr,uint32_t addr_len,const uint8_t *buf,size_t len,uint32_t dummy_byte) +{ + struct sfc_transfer transfer[3]; + struct sfc_message message; + struct cmd_info cmd[3]; + int ret; + + sfc_message_init(&message); + rt_memset(&transfer, 0, sizeof(transfer)); + rt_memset(&cmd, 0, sizeof(cmd)); + + /* write enable */ + cmd[0].cmd = CMD_WREN; + cmd[0].dataen = DISABLE; + + transfer[0].cmd_info = &cmd[0]; + transfer[0].sfc_mode = flash->sfc_mode; + sfc_message_add_tail(&transfer[0], &message); + + /* write ops */ + cmd[1].cmd = command; + cmd[1].dataen = ENABLE; + + transfer[1].addr = addr; + transfer[1].addr_len = addr_len; + transfer[1].len = len; + transfer[1].cur_len = 0; + transfer[1].data_dummy_bits = dummy_byte; + transfer[1].data = buf; + if(len >= L2CACHE_ALIGN_SIZE) + transfer[1].ops_mode = DMA_OPS; + else + transfer[1].ops_mode = CPU_OPS; + transfer[1].sfc_mode = flash->sfc_mode; + transfer[1].direction = GLB_TRAN_DIR_WRITE; + transfer[1].cmd_info = &cmd[1]; + sfc_message_add_tail(&transfer[1], &message); + + cmd[2].cmd = CMD_RDSR; + cmd[2].dataen = DISABLE; + cmd[2].sta_exp = 0; + cmd[2].sta_msk = 0x1; + + transfer[2].cmd_info = &cmd[2]; + sfc_message_add_tail(&transfer[2], &message); + + ret = sfc_sync(flash->sfc, &message); + if (ret) + { + SFC_DBG("sfc_sync error ! %s %s %d\n", __FILE__, __func__, __LINE__); + ret = -RT_EIO; + } + + return message.actual_length; +} + +#ifdef SFC_USE_QUAD +static int sfc_flash_set_quad_mode(struct sfc_flash *flash) +{ + uint8_t command; + uint32_t sent_data,len,dummy_byte; + int ret; + + struct sfc_transfer transfer[3]; + struct sfc_message message; + struct cmd_info cmd[3]; + + + if (flash->quad_mode == NULL) + { + SFC_DBG("quad info is null, use standard spi mode\n"); + flash->sfc_mode = TM_STD_SPI; + return -1; + } + + command = flash->quad_mode->WRSR_CMD; + sent_data = flash->quad_mode->WRSR_DATE; + len = flash->quad_mode->WD_DATE_SIZE; + dummy_byte = flash->quad_mode->dummy_byte; + + sfc_message_init(&message); + rt_memset(&transfer, 0, sizeof(transfer)); + rt_memset(&cmd, 0, sizeof(cmd)); + + /* write enable */ + cmd[0].cmd = CMD_WREN; + cmd[0].dataen = DISABLE; + + transfer[0].cmd_info = &cmd[0]; + transfer[0].sfc_mode = TM_STD_SPI; + sfc_message_add_tail(&transfer[0], &message); + + /* write ops */ + cmd[1].cmd = command; + cmd[1].dataen = ENABLE; + + transfer[1].len = len; + transfer[1].data = (const uint8_t *)&sent_data; + transfer[1].data_dummy_bits = dummy_byte; + transfer[1].ops_mode = CPU_OPS; + transfer[1].sfc_mode = TM_STD_SPI; + transfer[1].direction = GLB_TRAN_DIR_WRITE; + transfer[1].cmd_info = &cmd[1]; + sfc_message_add_tail(&transfer[1], &message); + + cmd[2].cmd = flash->quad_mode->RDSR_CMD; + cmd[2].dataen = DISABLE; + cmd[2].sta_exp = 0x2; + cmd[2].sta_msk = 0x2; + + transfer[2].data_dummy_bits = 0; + transfer[2].cmd_info = &cmd[2]; + sfc_message_add_tail(&transfer[2], &message); + + ret = sfc_sync(flash->sfc, &message); + if (ret) + { + flash->sfc_mode = TM_STD_SPI; + SFC_DBG("sfc_sync error ! %s %s %d\n", __FILE__, __func__, __LINE__); + ret = -RT_EIO; + } + else + { + flash->sfc_mode = flash->quad_mode->sfc_mode; + } + return 0; +} +#endif + +static int sfc_flash_write(struct sfc_flash *flash, rt_off_t to, size_t len, const uint8_t *buf) +{ + uint8_t command; + int dummy_byte = 0; + uint32_t s_len = 0, f_len = 0, a_len = 0; + +#ifdef SFC_USE_QUAD + if((flash->sfc_mode == TM_QI_QO_SPI) || (flash->sfc_mode == TM_QIO_SPI) || (flash->sfc_mode == TM_FULL_QIO_SPI)) + { + command = CMD_PP; + } + else + { + command = CMD_PP; + } +#else + command = CMD_PP; +#endif + + if (len > L2CACHE_ALIGN_SIZE) + { + s_len = RT_ALIGN((uint32_t )buf, L2CACHE_ALIGN_SIZE) - (uint32_t)buf; + if (s_len) + { + sfc_flash_do_write(flash, command, (uint32_t) to, flash->addrsize, buf, s_len, dummy_byte); + } + + a_len = (len - s_len) - (len - s_len) % L2CACHE_ALIGN_SIZE; + if (a_len) + { + sfc_flash_do_write(flash, command, (uint32_t) to + s_len, + flash->addrsize, &buf[s_len], a_len, dummy_byte); + } + + f_len = len - s_len - a_len; + if (f_len) + { + sfc_flash_do_write(flash, command, (uint32_t) to + s_len + a_len, + flash->addrsize, &buf[s_len + a_len], f_len, + dummy_byte); + } + } + else + { + sfc_flash_do_write(flash, command, (uint32_t) to, flash->addrsize, + buf, len, dummy_byte); + } + + return len; +} + +static int sfc_flash_read_cacheline_align(struct sfc_flash *flash,uint8_t command,uint32_t addr,int addr_len,uint8_t *buf,size_t len,int dummy_byte) +{ + uint32_t ret = 0; + uint32_t s_len = 0, f_len = 0, a_len = 0; + + /** + * s_len : start not align length + * a_len : middle align length + * f_len : end not align length + */ + if (len > L2CACHE_ALIGN_SIZE) + { + s_len = RT_ALIGN((uint32_t )buf, L2CACHE_ALIGN_SIZE) - (uint32_t)buf; + if (s_len) + { + ret += sfc_flash_do_read(flash, command, (uint32_t) addr, + flash->addrsize, buf, s_len, dummy_byte); + } + + a_len = (len - s_len) - (len - s_len) % L2CACHE_ALIGN_SIZE; + if (a_len) + { + ret += sfc_flash_do_read(flash, command, (uint32_t) addr + s_len, + flash->addrsize, &buf[s_len], a_len, + dummy_byte); + } + + f_len = len - s_len - a_len; + if (f_len) + { + ret += sfc_flash_do_read(flash, command, + (uint32_t) addr + s_len + a_len, + flash->addrsize, &buf[s_len + a_len], f_len, + dummy_byte); + } + } else { + ret = sfc_flash_do_read(flash, command, (uint32_t)addr, flash->addrsize, buf, len, dummy_byte); + } + + return ret; +} + +static int sfc_flash_read(struct sfc_flash *flash, rt_off_t from, size_t len, uint8_t *buf) +{ + uint8_t command; + int dummy_byte; + int tmp_len = 0, current_len = 0; + +#ifdef SFC_USE_QUAD + if((flash->sfc_mode == TM_QI_QO_SPI) || (flash->sfc_mode == TM_QIO_SPI) || (flash->sfc_mode == TM_FULL_QIO_SPI)) + { + command = flash->quad_mode->cmd_read; + dummy_byte = flash->quad_mode->dummy_byte; + } + else + { + command = CMD_READ; + dummy_byte = 0; + } +#else + command = CMD_READ; + dummy_byte = 0; +#endif + + while (len) + { + tmp_len = sfc_flash_read_cacheline_align(flash, command, + (uint32_t) from + current_len, + flash->addrsize, + &buf[current_len], len, dummy_byte); + current_len += tmp_len; + len -= tmp_len; + } + + return current_len; +} + +int sfc_norflash_set_addr_width_4byte(struct sfc_flash *flash,int on) +{ + struct sfc_transfer transfer; + struct sfc_message message; + struct cmd_info cmd; + int ret; + + sfc_message_init(&message); + rt_memset(&transfer, 0, sizeof(transfer)); + rt_memset(&cmd, 0, sizeof(cmd)); + + cmd.cmd = CMD_EN4B; + cmd.dataen = DISABLE; + + transfer.data_dummy_bits = 0; + transfer.cmd_info = &cmd; + sfc_message_add_tail(&transfer, &message); + + ret = sfc_sync(flash->sfc, &message); + if (ret) + { + SFC_DBG("sfc_sync error ! %s %s %d\n", __FILE__, __func__, __LINE__); + + ret = -RT_EIO; + } + return 0; +} + +size_t sfc_norflash_read(struct sfc_flash *flash, rt_off_t from, uint8_t *buf, size_t len) +{ + size_t retlen; + rt_mutex_take(&flash->lock,RT_WAITING_FOREVER); + retlen = sfc_flash_read(flash, from, len, buf); + rt_mutex_release(&flash->lock); + + return retlen; +} + +int sfc_norflash_read_params(struct sfc_flash *flash, rt_off_t from, size_t len, uint8_t *buf) +{ + struct sfc_transfer transfer; + struct sfc_message message; + struct cmd_info cmd; + uint8_t command; + int dummy_byte = 0,ret; + + + command = CMD_READ; + rt_mutex_take(&flash->lock,RT_WAITING_FOREVER); + + sfc_message_init(&message); + rt_memset(&transfer, 0, sizeof(transfer)); + rt_memset(&cmd, 0, sizeof(cmd)); + + cmd.cmd = command; + cmd.dataen = ENABLE; + + transfer.addr = (uint32_t)from; + transfer.len = len; + transfer.data = buf; + transfer.addr_len = DEFAULT_ADDRSIZE; + transfer.data_dummy_bits = dummy_byte; + transfer.ops_mode = CPU_OPS; + transfer.direction = GLB_TRAN_DIR_READ; + transfer.sfc_mode = TM_STD_SPI; + transfer.cmd_info = &cmd; + sfc_message_add_tail(&transfer, &message); + + ret = sfc_sync(flash->sfc, &message); + if (ret) + { + SFC_DBG("sfc_sync error ! %s %s %d\n", __FILE__, __func__, __LINE__); + ret = -RT_EIO; + } + + /*fix the cache line problem,when use jffs2 filesystem must be flush cache twice*/ + if(transfer.ops_mode == DMA_OPS) + r4k_dma_cache_sync((rt_ubase_t)buf,len, DMA_FROM_DEVICE); + rt_mutex_release(&flash->lock); + return 0; +} + +int sfc_norflash_erase_sector(struct sfc_flash *flash, uint32_t addr) +{ + uint8_t command; + struct sfc_transfer transfer[3]; + struct sfc_message message; + struct cmd_info cmd[3]; + int ret; + + rt_mutex_take(&flash->lock,RT_WAITING_FOREVER); + + sfc_message_init(&message); + rt_memset(&transfer, 0, sizeof(transfer)); + rt_memset(&cmd, 0, sizeof(cmd)); + + /* write enable */ + cmd[0].cmd = CMD_WREN; + cmd[0].dataen = DISABLE; + + transfer[0].sfc_mode = TM_STD_SPI; + transfer[0].cmd_info = &cmd[0]; + sfc_message_add_tail(&transfer[0], &message); + + switch (flash->erasesize) + { + case 0x1000: + command = CMD_BE_4K; + break; + case 0x8000: + command = CMD_BE_32K; + break; + case 0x10000: + command = CMD_BE_64K; + break; + } + + /* erase ops */ + cmd[1].cmd = command; + cmd[1].dataen = DISABLE; + + transfer[1].addr_len = flash->addrsize; + transfer[1].data_dummy_bits = 0; + transfer[1].addr = addr; + transfer[1].sfc_mode = TM_STD_SPI; + transfer[1].direction = GLB_TRAN_DIR_WRITE; + transfer[1].cmd_info = &cmd[1]; + sfc_message_add_tail(&transfer[1], &message); + + cmd[2].cmd = CMD_RDSR; + cmd[2].dataen = DISABLE; + cmd[2].sta_exp = 0; + cmd[2].sta_msk = 0x1; + + transfer[2].cmd_info = &cmd[2]; + sfc_message_add_tail(&transfer[2], &message); + + ret = sfc_sync(flash->sfc, &message); + if (ret) + { + SFC_DBG("sfc_sync error ! %s %s %d\n", __FILE__, __func__, __LINE__); + ret = -RT_EIO; + } + + rt_mutex_release(&flash->lock); + return 0; +} + +size_t sfc_norflash_write(struct sfc_flash *flash, rt_off_t to, const uint8_t *buf, size_t len) +{ + size_t retlen; + u32 page_offset, actual_len; + int ret; + + rt_mutex_take(&flash->lock,RT_WAITING_FOREVER); + + page_offset = to & (flash->pagesize - 1); + /* do all the bytes fit onto one page? */ + if (page_offset + len <= flash->pagesize) + { + ret = sfc_flash_write(flash, to, len, buf); + retlen = ret; + } + else + { + u32 i; + + /* the size of data remaining on the first page */ + actual_len = flash->pagesize - page_offset; + ret = sfc_flash_write(flash,to,actual_len,buf); + retlen += ret; + + /* write everything in flash->page_size chunks */ + for (i = actual_len; i < len; i += flash->writesize) + { + actual_len = len - i; + if (actual_len >= flash->writesize) + actual_len = flash->writesize; + + ret = sfc_flash_write(flash, to + i, actual_len, buf + i); + retlen += ret; + } + } + rt_mutex_release(&flash->lock); + return retlen; +} + +int sfc_norflash_probe(struct sfc_flash *flash) +{ + struct sfc *sfc; + + sfc = flash->sfc = jz_sfc_init(); + if(sfc == RT_NULL) + return -RT_EIO; + + /* GPIO Initialize (SFC FUNC1) */ + gpio_set_func(GPIO_PORT_A,GPIO_Pin_26,GPIO_FUNC_1); //CLK + gpio_set_func(GPIO_PORT_A,GPIO_Pin_27,GPIO_FUNC_1); //CE + gpio_set_func(GPIO_PORT_A,GPIO_Pin_28,GPIO_FUNC_1); //DR + gpio_set_func(GPIO_PORT_A,GPIO_Pin_29,GPIO_FUNC_1); //DT + gpio_set_func(GPIO_PORT_A,GPIO_Pin_30,GPIO_FUNC_1); //WP + gpio_set_func(GPIO_PORT_A,GPIO_Pin_31,GPIO_FUNC_1); //HOLD + + /* init mutex */ + if(rt_mutex_init(&(flash->lock),"norLock",RT_IPC_FLAG_FIFO) != RT_EOK) + { + SFC_DBG("Init mutex error\n"); + RT_ASSERT(0); + } + + rt_mutex_take(&(flash->lock),RT_WAITING_FOREVER); + + //get ID + { + uint8_t command; + int dummy_byte = 0; + int addr_len = 0; + int len = 3; + int addr = 0; + int id; + int i; + struct spi_nor_platform_data *flash_info; + struct spi_board_info *binfo; + + command = CMD_RDID; + + SFC_DBG("Get ID:\n"); + id = sfc_flash_read_id(flash, command, addr, addr_len, len, dummy_byte); + id = ((id & 0xff) << 16) | (((id >> 8) & 0xff) << 8) | ((id >> 16) & 0xff); + SFC_DBG("id = %06x\n",id); + + flash->id = id; + } + +#if 0 + //get UID + { + int i; + sfc_flash_do_read(flash,CMD_RUID,0,3,flash->uid,8,8); + SFC_DBG("uid = "); + for (i = 0; i < 8; ++i) { + SFC_DBG("%02x ",flash->uid[i]); + } + SFC_DBG("\n"); + } +#endif + + rt_mutex_release(&(flash->lock)); + + return 0; +} diff --git a/bsp/x1000/drivers/sfc/drv_sfc.h b/bsp/x1000/drivers/sfc/drv_sfc.h new file mode 100644 index 0000000000000000000000000000000000000000..3905c08d439000f64767973d8351dc54a47ba47a --- /dev/null +++ b/bsp/x1000/drivers/sfc/drv_sfc.h @@ -0,0 +1,287 @@ +/* + * drv_sfc.h + * + * Created on: 2016年4月5日 + * Author: Urey + */ + +#ifndef DRIVER_DRV_SFC_H_ +#define DRIVER_DRV_SFC_H_ + +#include + +#define SFC_USE_SWAP +#define SFC_USE_DMA +#define SFC_USE_QUAD + + +#define UNCACHE(addr) ((((uint32_t)(addr)) | 0xa0000000)) + + +/* SFC register */ +#define SFC_GLB (0x0000) +#define SFC_DEV_CONF (0x0004) +#define SFC_DEV_STA_EXP (0x0008) +#define SFC_DEV_STA_RT (0x000c) +#define SFC_DEV_STA_MSK (0x0010) +#define SFC_TRAN_CONF(n) (0x0014 + (n * 4)) +#define SFC_TRAN_LEN (0x002c) +#define SFC_DEV_ADDR(n) (0x0030 + (n * 4)) +#define SFC_DEV_ADDR_PLUS(n) (0x0048 + (n * 4)) +#define SFC_MEM_ADDR (0x0060) +#define SFC_TRIG (0x0064) +#define SFC_SR (0x0068) +#define SFC_SCR (0x006c) +#define SFC_INTC (0x0070) +#define SFC_FSM (0x0074) +#define SFC_CGE (0x0078) +#define SFC_RM_DR (0x1000) + +/* For SFC_GLB */ +#define GLB_TRAN_DIR (1 << 13) +#define GLB_TRAN_DIR_WRITE (1) +#define GLB_TRAN_DIR_READ (0) +#define GLB_THRESHOLD_OFFSET (7) +#define GLB_THRESHOLD_MSK (0x3f << GLB_THRESHOLD_OFFSET) +#define GLB_OP_MODE (1 << 6) +#define SLAVE_MODE (0x0) +#define DMA_MODE (0x1) +#define GLB_PHASE_NUM_OFFSET (3) +#define GLB_PHASE_NUM_MSK (0x7 << GLB_PHASE_NUM_OFFSET) +#define GLB_WP_EN (1 << 2) +#define GLB_BURST_MD_OFFSET (0) +#define GLB_BURST_MD_MSK (0x3 << GLB_BURST_MD_OFFSET) + +/* For SFC_DEV_CONF */ +#define DEV_CONF_ONE_AND_HALF_CYCLE_DELAY (3) +#define DEV_CONF_ONE_CYCLE_DELAY (2) +#define DEV_CONF_HALF_CYCLE_DELAY (1) +#define DEV_CONF_NO_DELAY (0) +#define DEV_CONF_SMP_DELAY_OFFSET (16) +#define DEV_CONF_SMP_DELAY_MSK (0x3 << DEV_CONF_SMP_DELAY_OFFSET) +#define DEV_CONF_CMD_TYPE (0x1 << 15) +#define DEV_CONF_STA_TYPE_OFFSET (13) +#define DEV_CONF_STA_TYPE_MSK (0x1 << DEV_CONF_STA_TYPE_OFFSET) +#define DEV_CONF_THOLD_OFFSET (11) +#define DEV_CONF_THOLD_MSK (0x3 << DEV_CONF_THOLD_OFFSET) +#define DEV_CONF_TSETUP_OFFSET (9) +#define DEV_CONF_TSETUP_MSK (0x3 << DEV_CONF_TSETUP_OFFSET) +#define DEV_CONF_TSH_OFFSET (5) +#define DEV_CONF_TSH_MSK (0xf << DEV_CONF_TSH_OFFSET) +#define DEV_CONF_CPHA (0x1 << 4) +#define DEV_CONF_CPOL (0x1 << 3) +#define DEV_CONF_CEDL (0x1 << 2) +#define DEV_CONF_HOLDDL (0x1 << 1) +#define DEV_CONF_WPDL (0x1 << 0) + +/* For SFC_TRAN_CONF */ +#define TRAN_CONF_TRAN_MODE_OFFSET (29) +#define TRAN_CONF_TRAN_MODE_MSK (0x7) +#define TRAN_CONF_ADDR_WIDTH_OFFSET (26) +#define TRAN_CONF_ADDR_WIDTH_MSK (0x7 << ADDR_WIDTH_OFFSET) +#define TRAN_CONF_POLLEN (1 << 25) +#define TRAN_CONF_CMDEN (1 << 24) +#define TRAN_CONF_FMAT (1 << 23) +#define TRAN_CONF_DMYBITS_OFFSET (17) +#define TRAN_CONF_DMYBITS_MSK (0x3f << DMYBITS_OFFSET) +#define TRAN_CONF_DATEEN (1 << 16) +#define TRAN_CONF_CMD_OFFSET (0) +#define TRAN_CONF_CMD_MSK (0xffff << CMD_OFFSET) +#define TRAN_CONF_CMD_LEN (1 << 15) + +/* For SFC_TRIG */ +#define TRIG_FLUSH (1 << 2) +#define TRIG_STOP (1 << 1) +#define TRIG_START (1 << 0) + +/* For SFC_SCR */ +#define CLR_END (1 << 4) +#define CLR_TREQ (1 << 3) +#define CLR_RREQ (1 << 2) +#define CLR_OVER (1 << 1) +#define CLR_UNDER (1 << 0) + +/* For SFC_TRAN_CONFx */ +#define TRAN_MODE_OFFSET (29) +#define TRAN_MODE_MSK (0x7 << TRAN_MODE_OFFSET) +#define TRAN_SPI_STANDARD (0x0) +#define TRAN_SPI_DUAL (0x1 ) +#define TRAN_SPI_QUAD (0x5 ) +#define TRAN_SPI_IO_QUAD (0x6 ) + + +#define ADDR_WIDTH_OFFSET (26) +#define ADDR_WIDTH_MSK (0x7 << ADDR_WIDTH_OFFSET) +#define POLLEN (1 << 25) +#define CMDEN (1 << 24) +#define FMAT (1 << 23) +#define DMYBITS_OFFSET (17) +#define DMYBITS_MSK (0x3f << DMYBITS_OFFSET) +#define DATEEN (1 << 16) +#define CMD_OFFSET (0) +#define CMD_MSK (0xffff << CMD_OFFSET) + +#define N_MAX 6 +#define MAX_SEGS 128 + +#define CHANNEL_0 0 +#define CHANNEL_1 1 +#define CHANNEL_2 2 +#define CHANNEL_3 3 +#define CHANNEL_4 4 +#define CHANNEL_5 5 + +#define ENABLE 1 +#define DISABLE 0 + +#define COM_CMD 1 // common cmd +#define POLL_CMD 2 // the cmd will poll the status of flash,ext: read status + +#define DMA_OPS 1 +#define CPU_OPS 0 + +#define TM_STD_SPI 0 +#define TM_DI_DO_SPI 1 +#define TM_DIO_SPI 2 +#define TM_FULL_DIO_SPI 3 +#define TM_QI_QO_SPI 5 +#define TM_QIO_SPI 6 +#define TM_FULL_QIO_SPI 7 + +#define DEFAULT_ADDRSIZE 3 + +#ifndef max +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef min +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +/*SPI NOR FLASH Instructions*/ +#define CMD_WREN 0x06 /* Write Enable */ +#define CMD_WRDI 0x04 /* Write Disable */ +#define CMD_RDSR 0x05 /* Read Status Register */ +#define CMD_RDSR_1 0x35 /* Read Status1 Register */ +#define CMD_RDSR_2 0x15 /* Read Status2 Register */ +#define CMD_WRSR 0x01 /* Write Status Register */ +#define CMD_WRSR_1 0x31 /* Write Status1 Register */ +#define CMD_WRSR_2 0x11 /* Write Status2 Register */ +#define CMD_READ 0x03 /* Read Data */ +#define CMD_DUAL_READ 0x3b /* DUAL Read Data */ +#define CMD_QUAD_READ 0x6b /* QUAD Read Data */ +#define CMD_QUAD_IO_FAST_READ 0xeb /* QUAD FAST Read Data */ +#define CMD_QUAD_IO_WORD_FAST_READ 0xe7 /* QUAD IO WORD Read Data */ +#define CMD_FAST_READ 0x0B /* Read Data at high speed */ +#define CMD_PP 0x02 /* Page Program(write data) */ +#define CMD_QPP 0x32 /* QUAD Page Program(write data) */ +#define CMD_BE_4K 0x20 +#define CMD_BE_32K 0x52 /* Block Erase */ +#define CMD_BE_64K 0XD8 /* Block Erase */ +#define CMD_CE 0xC7 /* Bulk or Chip Erase */ +#define CMD_DP 0xB9 /* Deep Power-Down */ +#define CMD_RES 0xAB /* Release from Power-Down and Read Electronic Signature */ +#define CMD_REMS 0x90 /* Read Manufacture ID/ Device ID */ +#define CMD_RDID 0x9F /* Read Identification */ +#define CMD_NON 0x00 /* Read Identification */ +#define CMD_RUID 0x4B /* ReadUnique ID */ +#define CMD_NON 0x00 /* Read Identification */ +#define CMD_EN4B 0xB7 /* Enter 4 bytes address mode */ +#define CMD_EX4B 0xE9 /* Exit 4 bytes address mode */ + +struct cmd_info +{ + uint32_t cmd; + uint32_t cmd_len;/*reserved; not use*/ + uint32_t dataen; + uint32_t sta_exp; + uint32_t sta_msk; +}; + +struct sfc_transfer +{ + uint32_t direction; + + struct cmd_info *cmd_info; + + uint32_t addr_len; + uint32_t addr; + uint32_t addr_plus; + uint32_t addr_dummy_bits;/*cmd + addr_dummy_bits + addr*/ + + const uint8_t *data; + uint32_t data_dummy_bits;/*addr + data_dummy_bits + data*/ + uint32_t len; + uint32_t cur_len; + + uint32_t sfc_mode; + uint32_t ops_mode; + uint32_t phase_format;/*we just use default value;phase1:cmd+dummy+addr... phase0:cmd+addr+dummy...*/ + + rt_list_t transfer_list; + +}; + +struct sfc_message +{ + rt_list_t transfers; + uint32_t actual_length; + uint32_t status; +}; + + +struct sfc +{ + void *iomem; + int irq; + struct clk *clk; + struct clk *clk_gate; + uint32_t src_clk; + uint32_t threshold; + struct sfc_transfer *transfer; + struct rt_completion done; +}; + +struct sfc_quad_mode +{ + uint8_t RDSR_CMD; + uint32_t RD_DATE_SIZE;//the data is write the spi status register for QE bit + uint8_t sfc_mode; + uint8_t WRSR_CMD; + uint32_t WD_DATE_SIZE;//the data is write the spi status register for QE bit + uint8_t cmd_read; + uint32_t RDSR_DATE;//the data is write the spi status register for QE bit + uint32_t WRSR_DATE;//this bit should be the flash QUAD mode enable + + uint32_t dummy_byte; +}; + +struct sfc_flash +{ + struct rt_mtd_nor_device mtd; + char *name; + uint32_t id; + uint8_t uid[8]; + + uint32_t pagesize; + uint32_t sectorsize; + uint32_t chipsize; + uint32_t erasesize; + uint32_t writesize; + uint32_t addrsize; + + struct sfc *sfc; + uint32_t sfc_mode; +#ifdef SFC_USE_QUAD + struct sfc_quad_mode *quad_mode; +#endif + struct rt_mutex lock; +}; + +int sfc_norflash_probe(struct sfc_flash *flash); +size_t sfc_norflash_read(struct sfc_flash *flash, rt_off_t from, uint8_t *buf, size_t len); +size_t sfc_norflash_write(struct sfc_flash *flash, rt_off_t to, const uint8_t *buf, size_t len); +int sfc_norflash_erase_sector(struct sfc_flash *flash, uint32_t addr); +int sfc_norflash_set_addr_width_4byte(struct sfc_flash *flash,int on); + +#endif /* DRIVER_DRV_SFC_H_ */ diff --git a/bsp/x1000/drivers/sfc/drv_sfc_gd25qxx_mtd.c b/bsp/x1000/drivers/sfc/drv_sfc_gd25qxx_mtd.c new file mode 100644 index 0000000000000000000000000000000000000000..594bba6f6b2f485362d70ce1d93afbd741a6ee37 --- /dev/null +++ b/bsp/x1000/drivers/sfc/drv_sfc_gd25qxx_mtd.c @@ -0,0 +1,192 @@ +/* + * File : drv_sfc_gd25qxx_mtd.c + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * Change Logs: + * Date Author Notes + * 2017年4月19日 Urey the first version + */ + +#include +#include +#include +#include + +#include "board.h" +#include "drv_clock.h" +#include "drv_gpio.h" +#include "drv_sfc.h" + +/* JEDEC Manufacturer's ID */ +#define MF_ID (0xC8) + +/* JEDEC Device ID: Memory type and Capacity */ +#define MTC_GD25Q128 (0x4018) +#define MTC_GD25Q256 (0x4019) + + +/* RT-Thread MTD device interface */ +static rt_base_t mtd_gd25_read_id(struct rt_mtd_nor_device *device) +{ + struct sfc_flash *flash = (struct sfc_flash *)device; + + return (rt_uint32_t)flash->id; +} + +static rt_size_t mtd_gd25_read(struct rt_mtd_nor_device *device, rt_off_t position, rt_uint8_t *data, rt_size_t size) +{ + struct sfc_flash *flash = (struct sfc_flash *)device; + + return sfc_norflash_read(flash,position,data,size); +} + +static rt_size_t mtd_gd25_write(struct rt_mtd_nor_device *device, rt_off_t position, const rt_uint8_t *data, rt_size_t size) +{ + struct sfc_flash *flash = (struct sfc_flash *)device; + + return sfc_norflash_write(flash,position,data,size); +} + + +static rt_err_t mtd_gd25_erase_block(struct rt_mtd_nor_device *device, rt_off_t offset, rt_uint32_t length) +{ + struct sfc_flash *flash = (struct sfc_flash *)device; + + sfc_norflash_erase_sector(flash,offset); + return RT_EOK; +} + +const static struct rt_mtd_nor_driver_ops mtd_gd25_ops = +{ + mtd_gd25_read_id, + mtd_gd25_read, + mtd_gd25_write, + mtd_gd25_erase_block, +}; + +#ifdef SFC_USE_QUAD +struct sfc_quad_mode flash_quad_mode[] = +{ + { + .RDSR_CMD = CMD_RDSR_1, + .WRSR_CMD = CMD_WRSR_1, + .RDSR_DATE = 0x2,//the data is write the spi status register for QE bit + .RD_DATE_SIZE = 1, + .WRSR_DATE = 0x2,//this bit should be the flash QUAD mode enable + .WD_DATE_SIZE = 1, + .cmd_read = CMD_QUAD_READ,// + .sfc_mode = TRAN_SPI_QUAD, + }, + { + .RDSR_CMD = CMD_RDSR, + .WRSR_CMD = CMD_WRSR, + .RDSR_DATE = 0x40,//the data is write the spi status register for QE bit + .RD_DATE_SIZE = 1, + .WRSR_DATE = 0x40,//this bit should be the flash QUAD mode enable + .WD_DATE_SIZE = 1, + .cmd_read = CMD_QUAD_IO_FAST_READ, + .sfc_mode = TRAN_SPI_IO_QUAD, + }, + { + .RDSR_CMD = CMD_RDSR_1, + .WRSR_CMD = CMD_WRSR, + .RDSR_DATE = 0x20,//the data is write the spi status register for QE bit + .RD_DATE_SIZE = 1, + .WRSR_DATE = 0x200,//this bit should be the flash QUAD mode enable + .WD_DATE_SIZE = 2, + .cmd_read = CMD_QUAD_READ, + .sfc_mode = TRAN_SPI_QUAD, + }, + { + .RDSR_CMD = CMD_RDSR, + .WRSR_CMD = CMD_WRSR, + .RDSR_DATE = 0x40,//the data is write the spi status register for QE bit + .RD_DATE_SIZE = 1, + .WRSR_DATE = 0x40,//this bit should be the flash QUAD mode enable + .WD_DATE_SIZE = 1, + .cmd_read = CMD_QUAD_READ, + .sfc_mode = TRAN_SPI_QUAD, + }, + +}; +#endif + +static struct sfc_flash _gd25_flash_info = +{ + .name = "GD25Q128C", + .id = 0xc84018, + .pagesize = 256, + .sectorsize = ( 4 * 1024), + .chipsize = (16 * 1024 * 1024), + .erasesize = ( 4 * 1024), + .writesize = 256, + .addrsize = DEFAULT_ADDRSIZE, + .quad_mode = &flash_quad_mode[0] +}; + +static char flashIdStr[128]; +extern int rt_hw_gd25qxx_mtd_part_init(const char *mtd_name); +int rt_hw_gd25qxx_init(void) +{ + struct sfc_flash *flash = &_gd25_flash_info; + int result; + + result = sfc_norflash_probe(flash); + if(result != RT_EOK) + { + rt_kprintf("GD25 init Failed..\n"); + + return result; + } + + if((flash->id >> 16) != MF_ID) + { + rt_kprintf("Manufacturers ID error!\r\n"); + rt_kprintf("JEDEC Read-ID Data : %06X\r\n", flash->id); + return -RT_ENOSYS; + } + + switch (flash->id & 0xFFFF) + { + case MTC_GD25Q128: + flash->name = "GD25Q128C"; + flash->chipsize = (16 * 1024 * 1024); + flash->addrsize = 3; + flash->quad_mode = &flash_quad_mode[0]; + break; + case MTC_GD25Q256: + flash->name = "GD25Q256C"; + flash->chipsize = (32 * 1024 * 1024); + flash->addrsize = 4; + flash->quad_mode = &flash_quad_mode[3]; + /* enable 4-byte addressing if the device exceeds 16MiB */ + sfc_norflash_set_addr_width_4byte(flash,1); + break; + default: + rt_kprintf("Memory Capacity error!\r\n"); + return -RT_ENOSYS; + break; + } + + //format FLASH UUID... + { + int strSize,i; + + strSize = rt_snprintf(flashIdStr + 0,sizeof(flashIdStr) - 0,"%06X",flash->id); + for(i=0;i<8;i++) + strSize += rt_snprintf(flashIdStr + strSize,sizeof(flashIdStr) - strSize,"%02X",flash->uid[i]); + flashIdStr[strSize] = '\0'; + } + + /* Init device interface ... */ + flash->mtd.block_size = flash->erasesize; + flash->mtd.block_start = 0; + flash->mtd.block_end = flash->chipsize / flash->erasesize; + flash->mtd.ops = &mtd_gd25_ops; + rt_mtd_nor_register_device("gd25mtd",&flash->mtd); + + rt_hw_gd25qxx_mtd_part_init("gd25mtd"); + + return RT_EOK; +} +INIT_DEVICE_EXPORT(rt_hw_gd25qxx_init); diff --git a/bsp/x1000/drivers/sfc/drv_sfc_gd25qxx_mtd_partition.c b/bsp/x1000/drivers/sfc/drv_sfc_gd25qxx_mtd_partition.c new file mode 100644 index 0000000000000000000000000000000000000000..7890a8d58940dc03f44a9eca99181a8480c4b401 --- /dev/null +++ b/bsp/x1000/drivers/sfc/drv_sfc_gd25qxx_mtd_partition.c @@ -0,0 +1,67 @@ +/* + * File : drv_sfc_gd25qxx_mtd_partition.c + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * Change Logs: + * Date Author Notes + * 2017年4月19日 Urey the first version + */ + +#include +#include +#include +#include + +#include "board.h" +#include "drv_clock.h" +#include "drv_gpio.h" +#include "drv_sfc.h" +#include "mtd_nor_partition.h" + +static struct rt_mtd_nor_partition _sf_gd25_parts[] = +{ + { + /* sf01 u-boot 512K */ + .name = "uboot", + .offset = 0x0, + .size = (0x80000), + .mask_flags = PART_FLAG_RDONLY | PART_TYPE_BLK, /* force read-only */ + }, + + { + /* kernel */ + .name = "kernel", + .offset = 0x80000, + .size = 0x380000, + .mask_flags = PART_FLAG_RDONLY | PART_TYPE_BLK, /* force read-only */ + }, + + { + /* rootfs */ + .name = "rootfs", + .offset = 0x400000, + .size = 0x800000, + .mask_flags = PART_FLAG_RDONLY | PART_TYPE_BLK, /* force read-only & Block device */ + }, + + { + /* sf04 appfs 2M*/ + .name = "appfs", + .offset = 0xE00000, + .size = 0x200000, + .mask_flags = PART_FLAG_RDWR | PART_TYPE_BLK, /* force read-only & Block device */ + }, + + //end + { + .name = (char *)0 + } +}; + + +int rt_hw_gd25qxx_mtd_part_init(const char *mtd_name) +{ + mtd_nor_init_partition(mtd_name,_sf_gd25_parts); + + return 0; +} diff --git a/bsp/x1000/drivers/sfc/mtd_nor_partition.c b/bsp/x1000/drivers/sfc/mtd_nor_partition.c new file mode 100644 index 0000000000000000000000000000000000000000..c41201effcd60385842dda286e7b73608533038f --- /dev/null +++ b/bsp/x1000/drivers/sfc/mtd_nor_partition.c @@ -0,0 +1,334 @@ +/** + ****************************************************************************** + * @file rt_mtd_nor_partition.c + * @author Urey + * @version V1.0.0 + * @date 2017年2月11日 + * @brief TODO + ****************************************************************************** +**/ + + + +#include +#include +#include +#include + +#include "mtd_nor_partition.h" + + +// #define MTD_DEBUG 1 +#ifdef MTD_DEBUG +#define MTD_DBG(...) rt_kprintf("[MTD]"),rt_kprintf(__VA_ARGS__) +#else +#define MTD_DBG(...) +#endif + +/* RT-Thread device interface */ +static rt_err_t mtd_part_blk_init(rt_device_t dev) +{ + return RT_EOK; +} + +static rt_err_t mtd_part_blk_open(rt_device_t dev, rt_uint16_t oflag) +{ + return RT_EOK; +} + +static rt_err_t mtd_part_blk_close(rt_device_t dev) +{ + return RT_EOK; +} + +static rt_err_t mtd_part_blk_control(rt_device_t dev, int cmd, void *args) +{ + struct rt_mtd_nor_partition *mtd_part; + struct rt_mtd_nor_device *mtd_nor; + + RT_ASSERT(dev != RT_NULL); + + mtd_part = (struct rt_mtd_nor_partition *)dev; + mtd_nor = (struct rt_mtd_nor_device *)mtd_part->user_data; + + switch (cmd) + { + case RT_DEVICE_CTRL_BLK_GETGEOME: + { + struct rt_device_blk_geometry *geometry; + + geometry = (struct rt_device_blk_geometry *)args; + if (geometry == RT_NULL) + return -RT_ERROR; + + geometry->bytes_per_sector = mtd_nor->block_size; + geometry->sector_count = mtd_part->size / mtd_nor->block_size; + geometry->block_size = mtd_nor->block_size; + + break; + } + default: + break; + } + + return RT_EOK; +} + +static rt_size_t mtd_part_blk_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) +{ + struct rt_mtd_nor_partition *mtd_part; + struct rt_mtd_nor_device *mtd_nor; + rt_size_t read_count = 0; + rt_uint8_t *ptr = (rt_uint8_t *)buffer; + + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(size != 0); + + mtd_part = (struct rt_mtd_nor_partition *)dev; + mtd_nor = (struct rt_mtd_nor_device *)mtd_part->user_data; + + MTD_DBG("%s name = %s,position = %08x,size = %08x\n",__func__,mtd_part->name,pos,size); + + if(!(mtd_part->mask_flags & PART_FLAG_RDONLY)) + { + MTD_DBG("ERROR: this device is unreadable,mask_flags = %04x\n", mtd_part->mask_flags); + return 0; + } + + while(read_count < size) + {/* It'a BLOCK device */ + if(((pos + 1) * mtd_nor->block_size) > (mtd_part->offset + mtd_part->size)) + { + MTD_DBG("ERROR: read overrun!\n"); + break; + } + rt_mtd_nor_read(mtd_nor,pos * mtd_nor->block_size + mtd_part->offset,ptr,mtd_nor->block_size); + + pos++; + ptr += mtd_nor->block_size; + read_count++; + } + + return read_count; +} + +static rt_size_t mtd_part_blk_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) +{ + struct rt_mtd_nor_partition *mtd_part; + struct rt_mtd_nor_device *mtd_nor; + rt_size_t write_count = 0; + rt_uint8_t *ptr = (rt_uint8_t *)buffer; + + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(size != 0); + + mtd_part = (struct rt_mtd_nor_partition *)dev; + mtd_nor = (struct rt_mtd_nor_device *)mtd_part->user_data; + MTD_DBG("%s name = %s,position = %08x,size = %08x\n",__func__,mtd_part->name,pos,size); + if(!(mtd_part->mask_flags & PART_FLAG_WRONLY)) + { + MTD_DBG("ERROR: this device is unwritable,mask_flags = %04x\n", mtd_part->mask_flags); + /* read only partition, ignore this data */ + return size; + } + + while(write_count < size) + {/* It'a BLOCK device */ + if((pos + 1) * mtd_nor->block_size > (mtd_part->offset + mtd_part->size)) + { + MTD_DBG("ERROR: write overrun!\n"); + break; + } + rt_mtd_nor_erase_block(mtd_nor,(pos * mtd_nor->block_size + mtd_part->offset),mtd_nor->block_size); + rt_mtd_nor_write(mtd_nor,(pos * mtd_nor->block_size + mtd_part->offset),ptr,mtd_nor->block_size); + + pos++; + ptr += mtd_nor->block_size; + write_count++; + } + + return write_count; +} + +static rt_base_t mtd_part_mtd_read_id(struct rt_mtd_nor_device *dev) +{ + struct rt_mtd_nor_partition *mtd_part; + struct rt_mtd_nor_device *mtd_nor; + + RT_ASSERT(dev != RT_NULL); + + mtd_part = (struct rt_mtd_nor_partition *)dev; + mtd_nor = (struct rt_mtd_nor_device *)mtd_part->user_data; + + return rt_mtd_nor_read_id(mtd_nor); +} + +static rt_size_t mtd_part_mtd_read(struct rt_mtd_nor_device *dev, rt_off_t offset, rt_uint8_t *buffer, rt_size_t length) +{ + struct rt_mtd_nor_partition *mtd_part; + struct rt_mtd_nor_device *mtd_nor; + + RT_ASSERT(dev != RT_NULL); + + mtd_part = (struct rt_mtd_nor_partition *)dev; + mtd_nor = (struct rt_mtd_nor_device *)mtd_part->user_data; + + MTD_DBG("%s offset = %08x,size = %08x\n",__func__,offset,length); + if(!(mtd_part->mask_flags & PART_FLAG_RDONLY)) + { + MTD_DBG("ERROR: this device is unreadable,mask_flags = %04x\n", mtd_part->mask_flags); + return 0; + } + + if(mtd_part->mask_flags & PART_TYPE_MTD) + {/* It'a MTD device */ + if((offset + length) > mtd_part->size) + { + MTD_DBG("ERROR: read size > partition size, pos=%d, size=%d, partition_size=%d\n", offset, length, mtd_part->size); + return 0; + } + + rt_mtd_nor_read(mtd_nor,(mtd_part->offset + offset),buffer,length); + + return length; + } + + MTD_DBG("ERROR: unknown device type..\n"); + return 0; +} + +static rt_size_t mtd_part_mtd_write(struct rt_mtd_nor_device *dev, rt_off_t offset, const rt_uint8_t *buffer, rt_size_t length) +{ + struct rt_mtd_nor_partition *mtd_part; + struct rt_mtd_nor_device *mtd_nor; + + RT_ASSERT(dev != RT_NULL); + + mtd_part = (struct rt_mtd_nor_partition *)dev; + mtd_nor = (struct rt_mtd_nor_device *)mtd_part->user_data; + + MTD_DBG("%s offset = %08x,size = %08x\n",__func__,offset,length); + + if(!(mtd_part->mask_flags & PART_FLAG_WRONLY)) + { + MTD_DBG("ERROR: this device is unwritable,mask_flags = %04x\n", mtd_part->mask_flags); + /* read only partition, ignore this data */ + return length; + } + + if(mtd_part->mask_flags & PART_TYPE_MTD) + { /* It'a MTD device */ + if((offset + length) > mtd_part->size) + { + MTD_DBG("ERROR: write size > partition size, pos=%d, size=%d, partition_size=%d\n", offset, length, mtd_part->size); + return 0; + } + + /* MTD device skip erase,user do it by himself */ + rt_mtd_nor_write(mtd_nor,(mtd_part->offset + offset),buffer,length); + return length; + } + + MTD_DBG("ERROR: unknown device type..\n"); + return 0; +} + +static rt_err_t mtd_part_mtd_erase_block(struct rt_mtd_nor_device* dev, rt_off_t offset, rt_uint32_t length) +{ + struct rt_mtd_nor_partition *mtd_part; + struct rt_mtd_nor_device *mtd_nor; + + RT_ASSERT(dev != RT_NULL); + + mtd_part = (struct rt_mtd_nor_partition *)dev; + mtd_nor = (struct rt_mtd_nor_device *)mtd_part->user_data; + + MTD_DBG("%s offset = %08x,size = %08x\n",__func__,offset,length); + + if(mtd_part->mask_flags & PART_TYPE_MTD) + { /* It'a MTD device */ + if((offset + length) > mtd_part->size) + { + MTD_DBG("ERROR: erase size > partition size, pos=%d, size=%d, partition_size=%d\n", offset, length, mtd_part->size); + return 0; + } + + if(length % mtd_nor->block_size != 0) + { + MTD_DBG("ERROR: erase size must align to BLOCK SIZE\n"); + return 0; + } + + rt_mtd_nor_erase_block(mtd_nor,(mtd_part->offset + offset),length); + + return length; + } + + MTD_DBG("ERROR: unknown device type..\n"); + return 0; +} + + +const static struct rt_mtd_nor_driver_ops mtd_part_mtd_ops = +{ + mtd_part_mtd_read_id, + mtd_part_mtd_read, + mtd_part_mtd_write, + mtd_part_mtd_erase_block, +}; + + +rt_err_t mtd_nor_init_partition(const char *mtd_name,struct rt_mtd_nor_partition *parts) +{ + struct rt_mtd_nor_partition *mtd_part; + struct rt_mtd_nor_device *mtd_nor; + + mtd_nor = (struct rt_mtd_nor_device *)rt_device_find(mtd_name); + if(mtd_nor == RT_NULL) + return -RT_EIO; + + for (mtd_part = parts; mtd_part->name != RT_NULL; mtd_part++) + { + MTD_DBG("part name: %s\n",mtd_part->name); + /* get partition type */ + if(mtd_part->mask_flags & PART_TYPE_BLK) + { /* It'a a BLOCK device */ + + /* set device interface */ + mtd_part->blk.type = RT_Device_Class_Block; + mtd_part->blk.init = mtd_part_blk_init; + mtd_part->blk.open = mtd_part_blk_open; + mtd_part->blk.read = mtd_part_blk_read; + mtd_part->blk.write = mtd_part_blk_write; + mtd_part->blk.close = mtd_part_blk_close; + mtd_part->blk.control = mtd_part_blk_control; + + mtd_part->user_data = mtd_nor; + + /* register device */ + rt_device_register(&mtd_part->blk,mtd_part->name,RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE); + } + else if(mtd_part->mask_flags & PART_TYPE_MTD) + { /* It's a MTD device */ + MTD_DBG("part name: %s\n",mtd_part->name); + + mtd_part->user_data = mtd_nor; + + /* Init MTD NOR device interface ... */ + mtd_part->mtd.block_size = mtd_nor->block_size; + mtd_part->mtd.block_start = 0; + mtd_part->mtd.block_end = mtd_part->size / mtd_nor->block_size; + mtd_part->mtd.ops = &mtd_part_mtd_ops; + + rt_mtd_nor_register_device(mtd_part->name,&mtd_part->mtd); + } + else + { + MTD_DBG("ERROR: unknown device type..\n"); + } + } + + return RT_EOK; +} + + diff --git a/bsp/x1000/drivers/sfc/mtd_nor_partition.h b/bsp/x1000/drivers/sfc/mtd_nor_partition.h new file mode 100644 index 0000000000000000000000000000000000000000..252d1d372ad0bb4f65c1c96cd262b75653efa40c --- /dev/null +++ b/bsp/x1000/drivers/sfc/mtd_nor_partition.h @@ -0,0 +1,53 @@ +/** + ****************************************************************************** + * @file spi_flash_mtd_partition.h + * @author Urey + * @version V1.0.0 + * @date 2017年2月11日 + * @brief TODO + ****************************************************************************** +**/ + + +#ifndef _SPI_FLASH_MTD_PARTITION_H_ +#define _SPI_FLASH_MTD_PARTITION_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define PART_FLAG_RDONLY 0x0001 +#define PART_FLAG_WRONLY 0x0002 +#define PART_FLAG_RDWR 0x0003 + +#define PART_TYPE_BLK 0x0010 +#define PART_TYPE_MTD 0x0020 + +struct rt_mtd_nor_partition +{ + union + { + struct rt_mtd_nor_device mtd; + struct rt_device blk; + }; + + const char *name; + rt_uint32_t offset; /* offset within the master MTD space */ + rt_uint32_t size; /* partition size */ + rt_uint32_t mask_flags; /* master MTD flags to mask out for this partition */ + void* user_data; /* hold parent device */ +}; + +/* + * functions + */ +extern rt_err_t mtd_nor_init_partition(const char *mtd_name,struct rt_mtd_nor_partition *parts); + + +#ifdef __cplusplus +} +#endif + +#endif /* _SPI_FLASH_MTD_PARTITION_H_ */ diff --git a/bsp/x1000/drivers/slcd/SConscript b/bsp/x1000/drivers/slcd/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..dc43b5a8c85729ed35e192a6b2caee090ffc4b63 --- /dev/null +++ b/bsp/x1000/drivers/slcd/SConscript @@ -0,0 +1,24 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +CPPPATH = [cwd] + +slcd_src = Split(''' +drv_slcdc.c +''') +slcd_group = DefineGroup('drv_slcd', slcd_src, depend = ['RT_USING_SLCD'], CPPPATH = CPPPATH) + +lcm_src = Split(''' +dump_slcd.c +drv_slcd_ili9341.c +drv_slcd_ili9488.c +drv_slcd_otm4802.c +drv_slcd_rm68120.c +drv_slcd_truly_tft240240.c +''') +lcm_group = DefineGroup('drv_lcm', lcm_src, depend = ['RT_USING_SLCD'], CPPPATH = CPPPATH) + +group = slcd_group + lcm_group +Return('group') diff --git a/bsp/x1000/drivers/slcd/drv_slcd_ili9341.c b/bsp/x1000/drivers/slcd/drv_slcd_ili9341.c new file mode 100644 index 0000000000000000000000000000000000000000..1d0ef4ecd912aa9a9d057126c1ee94ce817605ca --- /dev/null +++ b/bsp/x1000/drivers/slcd/drv_slcd_ili9341.c @@ -0,0 +1,252 @@ +/* + * File : drv_slcdc_ili9341.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2016-08-12 fujie The first version + */ + +#include + +#include +#include +#include + +#include "board.h" +#include "drv_gpio.h" +#include "drv_slcdc.h" +#include "drv_clock.h" + +#if defined(RT_USING_ILI9341) + +rt_uint32_t _ili9341_cmd_table[]= +{ + 0x2c2c2c2c, +}; + + +const struct slcd_data_table _ili9341_data_table[] = +{ + {SMART_CONFIG_CMD, 0x11}, + {SMART_CONFIG_UDELAY, 1200}, + + {SMART_CONFIG_CMD, 0xCF}, //Power control B 功耗控制B 【3参数】 + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0xAA}, + {SMART_CONFIG_DATA, 0XB0}, + + {SMART_CONFIG_CMD, 0xED}, //Power on sequence control 电源时序控制B 【4参数】 + {SMART_CONFIG_DATA, 0x64}, + {SMART_CONFIG_DATA, 0x03}, + {SMART_CONFIG_DATA, 0X12}, + {SMART_CONFIG_DATA, 0X81}, + + {SMART_CONFIG_CMD, 0xE8}, //Driver timing control A + {SMART_CONFIG_DATA, 0x85}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x78}, + + {SMART_CONFIG_CMD, 0xCB}, //Power control A + {SMART_CONFIG_DATA, 0x39}, + {SMART_CONFIG_DATA, 0x2C}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x34}, + {SMART_CONFIG_DATA, 0x02}, + + {SMART_CONFIG_CMD, 0xF7}, //Pump ratio control + {SMART_CONFIG_DATA, 0x20}, + + {SMART_CONFIG_CMD, 0xEA}, // Driver timing control B + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x00}, + + {SMART_CONFIG_CMD, 0xb6}, //Display Function Control + {SMART_CONFIG_DATA, 0x0a}, + {SMART_CONFIG_DATA, 0xa2}, + + {SMART_CONFIG_CMD, 0xC0}, //Power control + {SMART_CONFIG_DATA, 0x26}, //VRH[5:0] + + {SMART_CONFIG_CMD, 0xC1}, //Power control + {SMART_CONFIG_DATA, 0x11}, //SAP[2:0];BT[3:0] + + {SMART_CONFIG_CMD, 0xC5}, //VCM control + {SMART_CONFIG_DATA, 0x31}, //对比度调节 0x31 + {SMART_CONFIG_DATA, 0x3C}, + + {SMART_CONFIG_CMD, 0xC7}, //VCM control2 + {SMART_CONFIG_DATA, 0xd3}, + + {SMART_CONFIG_CMD, 0x36}, // Memory Access Control + {SMART_CONFIG_DATA, 0x68}, // ●定义帧存储器的读写扫描方向 //[竖屏]0x48 0x88 [横屏]0x28 0xE8 0x68 //0x08 + + {SMART_CONFIG_CMD, 0x3A}, //COLMOD: Pixel Format Set + {SMART_CONFIG_DATA, 0x55}, + + {SMART_CONFIG_CMD, 0xB1}, //VCM control + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x14}, + + {SMART_CONFIG_CMD, 0xF2}, // 3Gamma Function Disable + {SMART_CONFIG_DATA, 0x00}, + + {SMART_CONFIG_CMD, 0x26}, //Gamma curve selected + {SMART_CONFIG_DATA, 0x01}, + + {SMART_CONFIG_CMD, 0xE0}, //Set Gamma + {SMART_CONFIG_DATA, 0x0F}, + {SMART_CONFIG_DATA, 0x1d}, + {SMART_CONFIG_DATA, 0x1a}, + {SMART_CONFIG_DATA, 0x09}, + {SMART_CONFIG_DATA, 0x0f}, + {SMART_CONFIG_DATA, 0x09}, + {SMART_CONFIG_DATA, 0x46}, + {SMART_CONFIG_DATA, 0x88}, + {SMART_CONFIG_DATA, 0x39}, + {SMART_CONFIG_DATA, 0x05}, + {SMART_CONFIG_DATA, 0x0f}, + {SMART_CONFIG_DATA, 0x03}, + {SMART_CONFIG_DATA, 0x07}, + {SMART_CONFIG_DATA, 0x05}, + {SMART_CONFIG_DATA, 0x00}, + + {SMART_CONFIG_CMD, 0XE1}, //Set Gamma + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x22}, + {SMART_CONFIG_DATA, 0x25}, + {SMART_CONFIG_DATA, 0x06}, + {SMART_CONFIG_DATA, 0x10}, + {SMART_CONFIG_DATA, 0x06}, + {SMART_CONFIG_DATA, 0x39}, + {SMART_CONFIG_DATA, 0x22}, + {SMART_CONFIG_DATA, 0x4a}, + {SMART_CONFIG_DATA, 0x0a}, + {SMART_CONFIG_DATA, 0x10}, + {SMART_CONFIG_DATA, 0x0C}, + {SMART_CONFIG_DATA, 0x38}, + {SMART_CONFIG_DATA, 0x3a}, + {SMART_CONFIG_DATA, 0x0F}, + + {SMART_CONFIG_UDELAY, 5}, + {SMART_CONFIG_CMD, 0x11}, //Exit Sleep + {SMART_CONFIG_UDELAY, 12}, + {SMART_CONFIG_CMD, 0x29}, //Display + + // Write the display data into GRAM here + {SMART_CONFIG_CMD, 0x2A}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0xEF}, + + {SMART_CONFIG_CMD, 0x2B}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x01}, + {SMART_CONFIG_DATA, 0x3F}, + +// {SMART_CONFIG_CMD, 0x2C}, //GRAM start writing + + /* set window */ + {SMART_CONFIG_CMD, 0x2a}, + {SMART_CONFIG_DATA, 0>>8}, + {SMART_CONFIG_DATA, 0&0xFF}, + {SMART_CONFIG_DATA, 320>>8}, + {SMART_CONFIG_DATA, 320&0xFF}, + + {SMART_CONFIG_CMD, 0x2b}, + {SMART_CONFIG_DATA, 0>>8}, + {SMART_CONFIG_DATA, 0&0xFF}, + {SMART_CONFIG_DATA, 240>>8}, + {SMART_CONFIG_DATA, 240&0xFF}, + + {SMART_CONFIG_CMD, 0X2C}, //GRAM start writing +}; + +const struct slcd_configure _ili9341_config = +{ + .reg_write_twice = 0, + .rsply_cmd_high = 0, + .csply_active_high = 0, + /* write graphic ram command, in word, for example 8-bit bus, write_gram_cmd=C3C2C1C0. */ + .newcfg_fmt_conv = 1, + + .width = 320, + .height = 240, + + .bpp = 16, + .bus_width = 8, + + .data_table_num = sizeof(_ili9341_data_table)/sizeof(_ili9341_data_table[0]), + .data_table = &_ili9341_data_table[0], + + .cmd_table = &_ili9341_cmd_table[0], + .cmd_table_num = sizeof(_ili9341_cmd_table)/sizeof(_ili9341_cmd_table[0]), +}; + +void ili9341_bl_set(rt_bool_t isPwrON) +{ + if(isPwrON) + gpio_set_value(GPIO_PORT_B, GPIO_Pin_10, 1); + else + gpio_set_value(GPIO_PORT_B, GPIO_Pin_10, 0); +} + + +int ili9341_init(void) +{ + /* enable backlight */ + gpio_set_func(GPIO_PORT_B, GPIO_Pin_12, GPIO_OUTPUT0); //LCD Light + + /* Reset LCD Driver */ + gpio_set_func(GPIO_PORT_B, GPIO_Pin_10, GPIO_OUTPUT0); + rt_thread_delay(20); + gpio_set_value(GPIO_PORT_B, GPIO_Pin_10, 1); + rt_thread_delay(20); + rt_hw_slcd_init((struct slcd_configure *)&_ili9341_config); +// rt_hw_lcd_set_bl_func(ili9341_bl_set); + return 0; +} + +#include +int bl(int argc, char** argv) +{ + int enable = 0; + + if (argc != 2) return 0; + + enable = atoi(argv[1]); + + if (enable) + { + rt_kprintf("turn on blight\n"); + gpio_set_value(GPIO_PORT_B, GPIO_Pin_12, 1); + } + else + { + rt_kprintf("turn off blight\n"); + gpio_set_value(GPIO_PORT_B, GPIO_Pin_12, 0); + } + + return 0; +} +MSH_CMD_EXPORT(bl, black light); + +#endif //RT_USING_ILI9341 + diff --git a/bsp/x1000/drivers/slcd/drv_slcd_ili9488.c b/bsp/x1000/drivers/slcd/drv_slcd_ili9488.c new file mode 100644 index 0000000000000000000000000000000000000000..3c5482c27d78b4336f01218f37dafbafd961d3f2 --- /dev/null +++ b/bsp/x1000/drivers/slcd/drv_slcd_ili9488.c @@ -0,0 +1,176 @@ +/* + * File : drv_slcdc_ili9488.c + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * Change Logs: + * Date Author Notes + * 2017年5月6日 Urey the first version + */ + +#include +#include + +#include "board.h" +#include "drv_slcdc.h" +#include + +#ifdef RT_USING_ILI9488 + +#define LCD_WIDTH 480 +#define LCD_HEIGHT 320 + +const rt_uint32_t _lcm_cmd_table[]= +{ + 0x2C2C2C2C, +}; + + +const struct slcd_data_table _lcm_data_table[] = +{ + /* LCD init code */ + {SMART_CONFIG_CMD, 0xE0}, //P-Gamma + {SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_DATA,0x07}, + {SMART_CONFIG_DATA,0x0f}, + {SMART_CONFIG_DATA,0x07}, + {SMART_CONFIG_DATA,0x15}, + {SMART_CONFIG_DATA,0x09}, + {SMART_CONFIG_DATA,0x3c}, + {SMART_CONFIG_DATA,0x99}, + {SMART_CONFIG_DATA,0x4b}, + {SMART_CONFIG_DATA,0x09}, + {SMART_CONFIG_DATA,0x10}, + {SMART_CONFIG_DATA,0x0d}, + {SMART_CONFIG_DATA,0x1c}, + {SMART_CONFIG_DATA,0x1e}, + {SMART_CONFIG_DATA,0x0f}, + + {SMART_CONFIG_CMD, 0xE1}, //N-Gamma + {SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_DATA,0x20}, + {SMART_CONFIG_DATA,0x23}, + {SMART_CONFIG_DATA,0x02}, + {SMART_CONFIG_DATA,0x0f}, + {SMART_CONFIG_DATA,0x06}, + {SMART_CONFIG_DATA,0x34}, + {SMART_CONFIG_DATA,0x45}, + {SMART_CONFIG_DATA,0x43}, + {SMART_CONFIG_DATA,0x04}, + {SMART_CONFIG_DATA,0x0a}, + {SMART_CONFIG_DATA,0x08}, + {SMART_CONFIG_DATA,0x30}, + {SMART_CONFIG_DATA,0x37}, + {SMART_CONFIG_DATA,0x0f}, + + {SMART_CONFIG_CMD, 0xC0}, //Power Control 1 + {SMART_CONFIG_DATA, 0x17}, //Vreg1out + {SMART_CONFIG_DATA, 0x15}, //Verg2out + + {SMART_CONFIG_CMD, 0xC1}, //Power Control 2 + {SMART_CONFIG_DATA, 0x41}, //VGH,VGL + + {SMART_CONFIG_CMD, 0xC5}, //Power Control 3 + {SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_DATA,0x12}, + {SMART_CONFIG_DATA,0x80}, + + {SMART_CONFIG_CMD,0x36}, //MemoryAccess + {SMART_CONFIG_DATA,0xE8}, //[竖屏]0x48 0x88 [横屏]0x28 0xE8 0x68 //0x08 + + {SMART_CONFIG_CMD,0x3A}, //InterfacePixelFormat + {SMART_CONFIG_DATA,0x55}, //07 24bpp ,06 18bpp,05 16bpp + + + {SMART_CONFIG_CMD,0xB0}, //Interface Mode Control + {SMART_CONFIG_DATA,0x08}, + {SMART_CONFIG_CMD,0xB1}, //Frame rate 60HZ + {SMART_CONFIG_DATA,0xA0}, + {SMART_CONFIG_DATA,0x11}, + {SMART_CONFIG_CMD,0xB4}, + {SMART_CONFIG_DATA,0x02}, + {SMART_CONFIG_CMD,0xB6}, //RGB/MCU Interface Control + {SMART_CONFIG_DATA,0x02}, + {SMART_CONFIG_DATA,0x02}, + + {SMART_CONFIG_CMD,0xBE}, + {SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_DATA,0x04}, + + {SMART_CONFIG_CMD,0xE9}, + {SMART_CONFIG_DATA,0x00}, + + {SMART_CONFIG_CMD,0xF7}, + {SMART_CONFIG_DATA,0xA9}, + {SMART_CONFIG_DATA,0x51}, + {SMART_CONFIG_DATA,0x2C}, + {SMART_CONFIG_DATA,0x82}, + + {SMART_CONFIG_CMD,0x11}, + {SMART_CONFIG_UDELAY, 120000}, + {SMART_CONFIG_CMD,0x29}, + + //Set Window + {SMART_CONFIG_CMD,0x2A}, //Set X + {SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_DATA,(LCD_WIDTH - 1) >> 8}, + {SMART_CONFIG_DATA,(LCD_WIDTH - 1) & 0xFF}, + + {SMART_CONFIG_CMD,0x2B}, //Set Y + {SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_DATA,(LCD_HEIGHT - 1) >> 8}, + {SMART_CONFIG_DATA,(LCD_HEIGHT - 1) & 0xFF}, + + +// {SMART_CONFIG_CMD, 0x2C} + {SMART_CONFIG_CMD,0x35}, + {SMART_CONFIG_DATA,0x00} +}; + +struct slcd_configure _lcm_config = +{ + .rsply_cmd_high = 0, + .csply_active_high = 0, + .newcfg_fmt_conv = 1, + + .width = LCD_WIDTH, + .height = LCD_HEIGHT, + + .fmt = RTGRAPHIC_PIXEL_FORMAT_RGB565, + .bpp = 16, + .bus_width = 8, + .reg_width = 8, + .refresh = 60, + .data_table = &_lcm_data_table[0], + .data_table_num = sizeof(_lcm_data_table)/sizeof(_lcm_data_table[0]), + + .cmd_table = &_lcm_cmd_table[0], + .cmd_table_num = sizeof(_lcm_cmd_table)/sizeof(_lcm_cmd_table[0]) +}; + +int rt_hw_ili9488_init(void) +{ + rt_thread_delay(rt_tick_from_millisecond(500)); + + /* Power ON */ +// gpio_direction_output(GPIO_PORT_B,GPIO_Pin_16,1); //RD = 1 +// gpio_direction_output(GPIO_PORT_B,GPIO_Pin_18,1); //CS = 1 +// +// gpio_set_value(LCD_RST_PORT, LCD_RST_PIN, 0); +// rt_thread_delay(rt_tick_from_millisecond(20)); +// gpio_set_value(LCD_RST_PORT, LCD_RST_PIN, 1); +// rt_thread_delay(rt_tick_from_millisecond(500)); +// gpio_set_value(GPIO_PORT_B, GPIO_Pin_18, 0); //CS = 0 + + /* enable backlight */ + gpio_direction_output(LCD_BL_PORT, LCD_BL_PIN,1); + + /* init lcd & register lcd device */ + rt_hw_slcd_init(&_lcm_config); + + return 0; +} +INIT_DEVICE_EXPORT(rt_hw_ili9488_init); + +#endif diff --git a/bsp/x1000/drivers/slcd/drv_slcd_otm4802.c b/bsp/x1000/drivers/slcd/drv_slcd_otm4802.c new file mode 100644 index 0000000000000000000000000000000000000000..c73ff9e6225c907a9e470c43f9ce0e5d53b00d1b --- /dev/null +++ b/bsp/x1000/drivers/slcd/drv_slcd_otm4802.c @@ -0,0 +1,247 @@ +/* + * File : drv_slcdc_OTM4802.c + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * Change Logs: + * Date Author Notes + * 2017年5月6日 Urey the first version + */ + +#include +#include + +#include "board.h" +#include "drv_slcdc.h" +#include + +#ifdef RT_USING_OTM4802 + +#define LCD_WIDTH 480 +#define LCD_HEIGHT 320 + +rt_uint32_t _lcm_cmd_table[]= +{ + 0x2C2C2C2C, +}; + + +const struct slcd_data_table _lcm_data_table[] = +{ + /* LCD init code */ + {SMART_CONFIG_CMD, 0xff}, //Command 2 Enable + {SMART_CONFIG_DATA, 0x48}, + {SMART_CONFIG_DATA, 0x02}, + {SMART_CONFIG_DATA, 0x01}, + + {SMART_CONFIG_CMD, 0x00}, + {SMART_CONFIG_DATA, 0x80}, + {SMART_CONFIG_CMD, 0xff}, //ORISE Command Enable + {SMART_CONFIG_DATA, 0x48}, + {SMART_CONFIG_DATA, 0x02}, + + {SMART_CONFIG_CMD, 0x00}, + {SMART_CONFIG_DATA, 0x90}, + {SMART_CONFIG_CMD, 0xFF}, //MPU 16bit setting + {SMART_CONFIG_DATA, 0x01}, //02-16BIT MCU,01-8BIT MCU + + {SMART_CONFIG_CMD, 0x00}, + {SMART_CONFIG_DATA, 0x93}, + {SMART_CONFIG_CMD, 0xFF}, //SW MPU enable + {SMART_CONFIG_DATA, 0x20}, + + {SMART_CONFIG_CMD, 0x00}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_CMD, 0x51}, //Wright Display brightness + {SMART_CONFIG_DATA, 0xf0}, + + {SMART_CONFIG_CMD, 0x00}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_CMD, 0x53}, // Wright CTRL Display + {SMART_CONFIG_DATA, 0x24}, + + {SMART_CONFIG_CMD, 0x00}, + {SMART_CONFIG_DATA, 0xb1}, + {SMART_CONFIG_CMD, 0xc5}, //VSEL setting + {SMART_CONFIG_DATA, 0x00}, + + {SMART_CONFIG_CMD, 0x00}, + {SMART_CONFIG_DATA, 0xB0}, + {SMART_CONFIG_CMD, 0xc4}, //Gate Timing control + {SMART_CONFIG_DATA, 0x02}, + {SMART_CONFIG_DATA, 0x08}, + {SMART_CONFIG_DATA, 0x05}, + {SMART_CONFIG_DATA, 0x00}, + + {SMART_CONFIG_CMD, 0x00}, + {SMART_CONFIG_DATA, 0x90}, + {SMART_CONFIG_CMD, 0xc0}, //TCON MCLK Shift Control + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x0f}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x15}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x17}, + + {SMART_CONFIG_CMD, 0x00}, + {SMART_CONFIG_DATA, 0x82}, + {SMART_CONFIG_CMD, 0xc5}, //Adjust pump phase + {SMART_CONFIG_DATA, 0x01}, + + {SMART_CONFIG_CMD, 0x00}, + {SMART_CONFIG_DATA, 0x90}, + {SMART_CONFIG_CMD, 0xc5}, //Adjust pump phase + {SMART_CONFIG_DATA, 0x47}, + + {SMART_CONFIG_CMD, 0x00}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_CMD, 0xd8}, //GVDD/NGVDD Setting + {SMART_CONFIG_DATA, 0x58}, //58,17V + {SMART_CONFIG_DATA, 0x58}, //58 + + {SMART_CONFIG_CMD, 0x00}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_CMD, 0xd9}, //VCOM Setting + {SMART_CONFIG_DATA, 0xb0}, // + + {SMART_CONFIG_CMD, 0x00}, + {SMART_CONFIG_DATA, 0x91}, + {SMART_CONFIG_CMD, 0xb3}, //Display setting + {SMART_CONFIG_DATA, 0xC0}, + {SMART_CONFIG_DATA, 0x25}, + + {SMART_CONFIG_CMD, 0x00}, + {SMART_CONFIG_DATA, 0x81}, + {SMART_CONFIG_CMD, 0xC1}, //Osillator Adjustment:70Hz + {SMART_CONFIG_DATA, 0x77}, + + {SMART_CONFIG_CMD, 0x00}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_CMD, 0xe1}, //Gamma setting(positive) + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x05}, + {SMART_CONFIG_DATA, 0x09}, + {SMART_CONFIG_DATA, 0x04}, + {SMART_CONFIG_DATA, 0x02}, + {SMART_CONFIG_DATA, 0x0b}, + {SMART_CONFIG_DATA, 0x0a}, + {SMART_CONFIG_DATA, 0x09}, + {SMART_CONFIG_DATA, 0x05}, + {SMART_CONFIG_DATA, 0x08}, + {SMART_CONFIG_DATA, 0x10}, + {SMART_CONFIG_DATA, 0x05}, + {SMART_CONFIG_DATA, 0x06}, + {SMART_CONFIG_DATA, 0x11}, + {SMART_CONFIG_DATA, 0x09}, + {SMART_CONFIG_DATA, 0x01}, + + {SMART_CONFIG_CMD, 0x00}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_CMD, 0xe2}, //Gamma setting(negative) + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x05}, + {SMART_CONFIG_DATA, 0x09}, + {SMART_CONFIG_DATA, 0x04}, + {SMART_CONFIG_DATA, 0x02}, + {SMART_CONFIG_DATA, 0x0b}, + {SMART_CONFIG_DATA, 0x0a}, + {SMART_CONFIG_DATA, 0x09}, + {SMART_CONFIG_DATA, 0x05}, + {SMART_CONFIG_DATA, 0x08}, + {SMART_CONFIG_DATA, 0x10}, + {SMART_CONFIG_DATA, 0x05}, + {SMART_CONFIG_DATA, 0x06}, + {SMART_CONFIG_DATA, 0x11}, + {SMART_CONFIG_DATA, 0x09}, + {SMART_CONFIG_DATA, 0x01}, + + {SMART_CONFIG_CMD, 0x00}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_CMD, 0x00}, //End Gamma setting + {SMART_CONFIG_DATA, 0x00}, + + {SMART_CONFIG_CMD, 0x00}, + {SMART_CONFIG_DATA, 0x80}, + {SMART_CONFIG_CMD, 0xff}, //Orise mode command Disable + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x00}, + + {SMART_CONFIG_CMD, 0x00}, + {SMART_CONFIG_DATA, 0x00}, + + {SMART_CONFIG_CMD, 0xff}, //Command 2 Disable + {SMART_CONFIG_DATA, 0xff}, + {SMART_CONFIG_DATA, 0xff}, + {SMART_CONFIG_DATA, 0xff}, + + //{SMART_CONFIG_CMD, 0x35}, //TE ON + //{SMART_CONFIG_DATA, 0x00}, + + {SMART_CONFIG_CMD, 0x36}, //set X Y refresh direction + {SMART_CONFIG_DATA, 0x60}, + + {SMART_CONFIG_CMD, 0x3A}, //16-bit/pixe 565 + {SMART_CONFIG_DATA, 0x05}, + + {SMART_CONFIG_CMD, 0x2A}, //Frame rate control 320 + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, (LCD_WIDTH -1 ) >> 8}, + {SMART_CONFIG_DATA, (LCD_WIDTH -1 ) & 0xFF}, + + {SMART_CONFIG_CMD, 0x2B}, //Display function control 480 + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, (LCD_WIDTH -1 ) >> 8}, + {SMART_CONFIG_DATA, (LCD_HEIGHT -1 ) & 0xFF}, + + {SMART_CONFIG_CMD, 0x11}, + {SMART_CONFIG_UDELAY, 120}, + {SMART_CONFIG_CMD, 0x29}, //display on + + {SMART_CONFIG_CMD, 0x2c}, +}; + +struct slcd_configure _lcm_config = +{ + .rsply_cmd_high = 0, + .csply_active_high = 0, + .newcfg_fmt_conv = 1, + + .width = LCD_WIDTH, + .height = LCD_HEIGHT, + + .fmt = RTGRAPHIC_PIXEL_FORMAT_RGB565, + .bpp = 16, + .bus_width = 8, + .reg_width = 8, + .refresh = 60, + .data_table = &_lcm_data_table[0], + .data_table_num = sizeof(_lcm_data_table)/sizeof(_lcm_data_table[0]), + + .cmd_table = &_lcm_cmd_table[0], + .cmd_table_num = sizeof(_lcm_cmd_table)/sizeof(_lcm_cmd_table[0]) +}; + +int rt_hw_otm4802_init(void) +{ + rt_thread_delay(rt_tick_from_millisecond(500)); + + /* Power ON */ + gpio_direction_output(GPIO_PORT_B,GPIO_Pin_16,1); //RD = 1 + gpio_direction_output(GPIO_PORT_B,GPIO_Pin_18,1); //CS = 1 + + gpio_set_value(LCD_RST_PORT, LCD_RST_PIN, 0); + rt_thread_delay(rt_tick_from_millisecond(20)); + gpio_set_value(LCD_RST_PORT, LCD_RST_PIN, 1); + rt_thread_delay(rt_tick_from_millisecond(500)); + gpio_set_value(GPIO_PORT_B, GPIO_Pin_18, 0); //CS = 0 + + /* enable backlight */ + gpio_direction_output(LCD_BL_PORT, LCD_BL_PIN,1); + + /* init lcd & register lcd device */ + rt_hw_slcd_init(&_lcm_config); + + return 0; +} +#endif diff --git a/bsp/x1000/drivers/slcd/drv_slcd_rm68120.c b/bsp/x1000/drivers/slcd/drv_slcd_rm68120.c new file mode 100644 index 0000000000000000000000000000000000000000..374372b4832ecb4715097482ff186c175fdea7f6 --- /dev/null +++ b/bsp/x1000/drivers/slcd/drv_slcd_rm68120.c @@ -0,0 +1,536 @@ +/* + * File : slcd_rm68120.c + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * Change Logs: + * Date Author Notes + * 2017年4月11日 Urey the first version + */ + +#include +#include + +#include "board.h" +#include "drv_slcdc.h" +#include + +#ifdef RT_USING_RM68120 + +rt_uint32_t _rm68120_cmd_table[]= +{ + 0x002c002c, +}; + +const struct slcd_data_table _rm68120_data_table[] = +{ + //ENABLE PAGE 1 + {SMART_CONFIG_CMD,0xF000},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xF001},{SMART_CONFIG_DATA,0xAA}, + {SMART_CONFIG_CMD,0xF002},{SMART_CONFIG_DATA,0x52}, + {SMART_CONFIG_CMD,0xF003},{SMART_CONFIG_DATA,0x08}, + {SMART_CONFIG_CMD,0xF004},{SMART_CONFIG_DATA,0x01}, + + //GAMMA SETING RED + {SMART_CONFIG_CMD,0xD100},{SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_CMD,0xD101},{SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_CMD,0xD102},{SMART_CONFIG_DATA,0x1b}, + {SMART_CONFIG_CMD,0xD103},{SMART_CONFIG_DATA,0x44}, + {SMART_CONFIG_CMD,0xD104},{SMART_CONFIG_DATA,0x62}, + {SMART_CONFIG_CMD,0xD105},{SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_CMD,0xD106},{SMART_CONFIG_DATA,0x7b}, + {SMART_CONFIG_CMD,0xD107},{SMART_CONFIG_DATA,0xa1}, + {SMART_CONFIG_CMD,0xD108},{SMART_CONFIG_DATA,0xc0}, + {SMART_CONFIG_CMD,0xD109},{SMART_CONFIG_DATA,0xee}, + {SMART_CONFIG_CMD,0xD10A},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xD10B},{SMART_CONFIG_DATA,0x10}, + {SMART_CONFIG_CMD,0xD10C},{SMART_CONFIG_DATA,0x2c}, + {SMART_CONFIG_CMD,0xD10D},{SMART_CONFIG_DATA,0x43}, + {SMART_CONFIG_CMD,0xD10E},{SMART_CONFIG_DATA,0x57}, + {SMART_CONFIG_CMD,0xD10F},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xD110},{SMART_CONFIG_DATA,0x68}, + {SMART_CONFIG_CMD,0xD111},{SMART_CONFIG_DATA,0x78}, + {SMART_CONFIG_CMD,0xD112},{SMART_CONFIG_DATA,0x87}, + {SMART_CONFIG_CMD,0xD113},{SMART_CONFIG_DATA,0x94}, + {SMART_CONFIG_CMD,0xD114},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xD115},{SMART_CONFIG_DATA,0xa0}, + {SMART_CONFIG_CMD,0xD116},{SMART_CONFIG_DATA,0xac}, + {SMART_CONFIG_CMD,0xD117},{SMART_CONFIG_DATA,0xb6}, + {SMART_CONFIG_CMD,0xD118},{SMART_CONFIG_DATA,0xc1}, + {SMART_CONFIG_CMD,0xD119},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xD11A},{SMART_CONFIG_DATA,0xcb}, + {SMART_CONFIG_CMD,0xD11B},{SMART_CONFIG_DATA,0xcd}, + {SMART_CONFIG_CMD,0xD11C},{SMART_CONFIG_DATA,0xd6}, + {SMART_CONFIG_CMD,0xD11D},{SMART_CONFIG_DATA,0xdf}, + {SMART_CONFIG_CMD,0xD11E},{SMART_CONFIG_DATA,0x95}, + {SMART_CONFIG_CMD,0xD11F},{SMART_CONFIG_DATA,0xe8}, + {SMART_CONFIG_CMD,0xD120},{SMART_CONFIG_DATA,0xf1}, + {SMART_CONFIG_CMD,0xD121},{SMART_CONFIG_DATA,0xfa}, + {SMART_CONFIG_CMD,0xD122},{SMART_CONFIG_DATA,0x02}, + {SMART_CONFIG_CMD,0xD123},{SMART_CONFIG_DATA,0xaa}, + {SMART_CONFIG_CMD,0xD124},{SMART_CONFIG_DATA,0x0b}, + {SMART_CONFIG_CMD,0xD125},{SMART_CONFIG_DATA,0x13}, + {SMART_CONFIG_CMD,0xD126},{SMART_CONFIG_DATA,0x1d}, + {SMART_CONFIG_CMD,0xD127},{SMART_CONFIG_DATA,0x26}, + {SMART_CONFIG_CMD,0xD128},{SMART_CONFIG_DATA,0xaa}, + {SMART_CONFIG_CMD,0xD129},{SMART_CONFIG_DATA,0x30}, + {SMART_CONFIG_CMD,0xD12A},{SMART_CONFIG_DATA,0x3c}, + {SMART_CONFIG_CMD,0xD12B},{SMART_CONFIG_DATA,0x4A}, + {SMART_CONFIG_CMD,0xD12C},{SMART_CONFIG_DATA,0x63}, + {SMART_CONFIG_CMD,0xD12D},{SMART_CONFIG_DATA,0xea}, + {SMART_CONFIG_CMD,0xD12E},{SMART_CONFIG_DATA,0x79}, + {SMART_CONFIG_CMD,0xD12F},{SMART_CONFIG_DATA,0xa6}, + {SMART_CONFIG_CMD,0xD130},{SMART_CONFIG_DATA,0xd0}, + {SMART_CONFIG_CMD,0xD131},{SMART_CONFIG_DATA,0x20}, + {SMART_CONFIG_CMD,0xD132},{SMART_CONFIG_DATA,0x0f}, + {SMART_CONFIG_CMD,0xD133},{SMART_CONFIG_DATA,0x8e}, + {SMART_CONFIG_CMD,0xD134},{SMART_CONFIG_DATA,0xff}, + //GAMMA SETING GREEN + {SMART_CONFIG_CMD,0xD200},{SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_CMD,0xD201},{SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_CMD,0xD202},{SMART_CONFIG_DATA,0x1b}, + {SMART_CONFIG_CMD,0xD203},{SMART_CONFIG_DATA,0x44}, + {SMART_CONFIG_CMD,0xD204},{SMART_CONFIG_DATA,0x62}, + {SMART_CONFIG_CMD,0xD205},{SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_CMD,0xD206},{SMART_CONFIG_DATA,0x7b}, + {SMART_CONFIG_CMD,0xD207},{SMART_CONFIG_DATA,0xa1}, + {SMART_CONFIG_CMD,0xD208},{SMART_CONFIG_DATA,0xc0}, + {SMART_CONFIG_CMD,0xD209},{SMART_CONFIG_DATA,0xee}, + {SMART_CONFIG_CMD,0xD20A},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xD20B},{SMART_CONFIG_DATA,0x10}, + {SMART_CONFIG_CMD,0xD20C},{SMART_CONFIG_DATA,0x2c}, + {SMART_CONFIG_CMD,0xD20D},{SMART_CONFIG_DATA,0x43}, + {SMART_CONFIG_CMD,0xD20E},{SMART_CONFIG_DATA,0x57}, + {SMART_CONFIG_CMD,0xD20F},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xD210},{SMART_CONFIG_DATA,0x68}, + {SMART_CONFIG_CMD,0xD211},{SMART_CONFIG_DATA,0x78}, + {SMART_CONFIG_CMD,0xD212},{SMART_CONFIG_DATA,0x87}, + {SMART_CONFIG_CMD,0xD213},{SMART_CONFIG_DATA,0x94}, + {SMART_CONFIG_CMD,0xD214},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xD215},{SMART_CONFIG_DATA,0xa0}, + {SMART_CONFIG_CMD,0xD216},{SMART_CONFIG_DATA,0xac}, + {SMART_CONFIG_CMD,0xD217},{SMART_CONFIG_DATA,0xb6}, + {SMART_CONFIG_CMD,0xD218},{SMART_CONFIG_DATA,0xc1}, + {SMART_CONFIG_CMD,0xD219},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xD21A},{SMART_CONFIG_DATA,0xcb}, + {SMART_CONFIG_CMD,0xD21B},{SMART_CONFIG_DATA,0xcd}, + {SMART_CONFIG_CMD,0xD21C},{SMART_CONFIG_DATA,0xd6}, + {SMART_CONFIG_CMD,0xD21D},{SMART_CONFIG_DATA,0xdf}, + {SMART_CONFIG_CMD,0xD21E},{SMART_CONFIG_DATA,0x95}, + {SMART_CONFIG_CMD,0xD21F},{SMART_CONFIG_DATA,0xe8}, + {SMART_CONFIG_CMD,0xD220},{SMART_CONFIG_DATA,0xf1}, + {SMART_CONFIG_CMD,0xD221},{SMART_CONFIG_DATA,0xfa}, + {SMART_CONFIG_CMD,0xD222},{SMART_CONFIG_DATA,0x02}, + {SMART_CONFIG_CMD,0xD223},{SMART_CONFIG_DATA,0xaa}, + {SMART_CONFIG_CMD,0xD224},{SMART_CONFIG_DATA,0x0b}, + {SMART_CONFIG_CMD,0xD225},{SMART_CONFIG_DATA,0x13}, + {SMART_CONFIG_CMD,0xD226},{SMART_CONFIG_DATA,0x1d}, + {SMART_CONFIG_CMD,0xD227},{SMART_CONFIG_DATA,0x26}, + {SMART_CONFIG_CMD,0xD228},{SMART_CONFIG_DATA,0xaa}, + {SMART_CONFIG_CMD,0xD229},{SMART_CONFIG_DATA,0x30}, + {SMART_CONFIG_CMD,0xD22A},{SMART_CONFIG_DATA,0x3c}, + {SMART_CONFIG_CMD,0xD22B},{SMART_CONFIG_DATA,0x4a}, + {SMART_CONFIG_CMD,0xD22C},{SMART_CONFIG_DATA,0x63}, + {SMART_CONFIG_CMD,0xD22D},{SMART_CONFIG_DATA,0xea}, + {SMART_CONFIG_CMD,0xD22E},{SMART_CONFIG_DATA,0x79}, + {SMART_CONFIG_CMD,0xD22F},{SMART_CONFIG_DATA,0xa6}, + {SMART_CONFIG_CMD,0xD230},{SMART_CONFIG_DATA,0xd0}, + {SMART_CONFIG_CMD,0xD231},{SMART_CONFIG_DATA,0x20}, + {SMART_CONFIG_CMD,0xD232},{SMART_CONFIG_DATA,0x0f}, + {SMART_CONFIG_CMD,0xD233},{SMART_CONFIG_DATA,0x8e}, + {SMART_CONFIG_CMD,0xD234},{SMART_CONFIG_DATA,0xff}, + + //GAMMA SETING BLUE + {SMART_CONFIG_CMD,0xD300},{SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_CMD,0xD301},{SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_CMD,0xD302},{SMART_CONFIG_DATA,0x1b}, + {SMART_CONFIG_CMD,0xD303},{SMART_CONFIG_DATA,0x44}, + {SMART_CONFIG_CMD,0xD304},{SMART_CONFIG_DATA,0x62}, + {SMART_CONFIG_CMD,0xD305},{SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_CMD,0xD306},{SMART_CONFIG_DATA,0x7b}, + {SMART_CONFIG_CMD,0xD307},{SMART_CONFIG_DATA,0xa1}, + {SMART_CONFIG_CMD,0xD308},{SMART_CONFIG_DATA,0xc0}, + {SMART_CONFIG_CMD,0xD309},{SMART_CONFIG_DATA,0xee}, + {SMART_CONFIG_CMD,0xD30A},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xD30B},{SMART_CONFIG_DATA,0x10}, + {SMART_CONFIG_CMD,0xD30C},{SMART_CONFIG_DATA,0x2c}, + {SMART_CONFIG_CMD,0xD30D},{SMART_CONFIG_DATA,0x43}, + {SMART_CONFIG_CMD,0xD30E},{SMART_CONFIG_DATA,0x57}, + {SMART_CONFIG_CMD,0xD30F},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xD310},{SMART_CONFIG_DATA,0x68}, + {SMART_CONFIG_CMD,0xD311},{SMART_CONFIG_DATA,0x78}, + {SMART_CONFIG_CMD,0xD312},{SMART_CONFIG_DATA,0x87}, + {SMART_CONFIG_CMD,0xD313},{SMART_CONFIG_DATA,0x94}, + {SMART_CONFIG_CMD,0xD314},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xD315},{SMART_CONFIG_DATA,0xa0}, + {SMART_CONFIG_CMD,0xD316},{SMART_CONFIG_DATA,0xac}, + {SMART_CONFIG_CMD,0xD317},{SMART_CONFIG_DATA,0xb6}, + {SMART_CONFIG_CMD,0xD318},{SMART_CONFIG_DATA,0xc1}, + {SMART_CONFIG_CMD,0xD319},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xD31A},{SMART_CONFIG_DATA,0xcb}, + {SMART_CONFIG_CMD,0xD31B},{SMART_CONFIG_DATA,0xcd}, + {SMART_CONFIG_CMD,0xD31C},{SMART_CONFIG_DATA,0xd6}, + {SMART_CONFIG_CMD,0xD31D},{SMART_CONFIG_DATA,0xdf}, + {SMART_CONFIG_CMD,0xD31E},{SMART_CONFIG_DATA,0x95}, + {SMART_CONFIG_CMD,0xD31F},{SMART_CONFIG_DATA,0xe8}, + {SMART_CONFIG_CMD,0xD320},{SMART_CONFIG_DATA,0xf1}, + {SMART_CONFIG_CMD,0xD321},{SMART_CONFIG_DATA,0xfa}, + {SMART_CONFIG_CMD,0xD322},{SMART_CONFIG_DATA,0x02}, + {SMART_CONFIG_CMD,0xD323},{SMART_CONFIG_DATA,0xaa}, + {SMART_CONFIG_CMD,0xD324},{SMART_CONFIG_DATA,0x0b}, + {SMART_CONFIG_CMD,0xD325},{SMART_CONFIG_DATA,0x13}, + {SMART_CONFIG_CMD,0xD326},{SMART_CONFIG_DATA,0x1d}, + {SMART_CONFIG_CMD,0xD327},{SMART_CONFIG_DATA,0x26}, + {SMART_CONFIG_CMD,0xD328},{SMART_CONFIG_DATA,0xaa}, + {SMART_CONFIG_CMD,0xD329},{SMART_CONFIG_DATA,0x30}, + {SMART_CONFIG_CMD,0xD32A},{SMART_CONFIG_DATA,0x3c}, + {SMART_CONFIG_CMD,0xD32B},{SMART_CONFIG_DATA,0x4A}, + {SMART_CONFIG_CMD,0xD32C},{SMART_CONFIG_DATA,0x63}, + {SMART_CONFIG_CMD,0xD32D},{SMART_CONFIG_DATA,0xea}, + {SMART_CONFIG_CMD,0xD32E},{SMART_CONFIG_DATA,0x79}, + {SMART_CONFIG_CMD,0xD32F},{SMART_CONFIG_DATA,0xa6}, + {SMART_CONFIG_CMD,0xD330},{SMART_CONFIG_DATA,0xd0}, + {SMART_CONFIG_CMD,0xD331},{SMART_CONFIG_DATA,0x20}, + {SMART_CONFIG_CMD,0xD332},{SMART_CONFIG_DATA,0x0f}, + {SMART_CONFIG_CMD,0xD333},{SMART_CONFIG_DATA,0x8e}, + {SMART_CONFIG_CMD,0xD334},{SMART_CONFIG_DATA,0xff}, + + //GAMMA SETING RED + {SMART_CONFIG_CMD,0xD400},{SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_CMD,0xD401},{SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_CMD,0xD402},{SMART_CONFIG_DATA,0x1b}, + {SMART_CONFIG_CMD,0xD403},{SMART_CONFIG_DATA,0x44}, + {SMART_CONFIG_CMD,0xD404},{SMART_CONFIG_DATA,0x62}, + {SMART_CONFIG_CMD,0xD405},{SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_CMD,0xD406},{SMART_CONFIG_DATA,0x7b}, + {SMART_CONFIG_CMD,0xD407},{SMART_CONFIG_DATA,0xa1}, + {SMART_CONFIG_CMD,0xD408},{SMART_CONFIG_DATA,0xc0}, + {SMART_CONFIG_CMD,0xD409},{SMART_CONFIG_DATA,0xee}, + {SMART_CONFIG_CMD,0xD40A},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xD40B},{SMART_CONFIG_DATA,0x10}, + {SMART_CONFIG_CMD,0xD40C},{SMART_CONFIG_DATA,0x2c}, + {SMART_CONFIG_CMD,0xD40D},{SMART_CONFIG_DATA,0x43}, + {SMART_CONFIG_CMD,0xD40E},{SMART_CONFIG_DATA,0x57}, + {SMART_CONFIG_CMD,0xD40F},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xD410},{SMART_CONFIG_DATA,0x68}, + {SMART_CONFIG_CMD,0xD411},{SMART_CONFIG_DATA,0x78}, + {SMART_CONFIG_CMD,0xD412},{SMART_CONFIG_DATA,0x87}, + {SMART_CONFIG_CMD,0xD413},{SMART_CONFIG_DATA,0x94}, + {SMART_CONFIG_CMD,0xD414},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xD415},{SMART_CONFIG_DATA,0xa0}, + {SMART_CONFIG_CMD,0xD416},{SMART_CONFIG_DATA,0xac}, + {SMART_CONFIG_CMD,0xD417},{SMART_CONFIG_DATA,0xb6}, + {SMART_CONFIG_CMD,0xD418},{SMART_CONFIG_DATA,0xc1}, + {SMART_CONFIG_CMD,0xD419},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xD41A},{SMART_CONFIG_DATA,0xcb}, + {SMART_CONFIG_CMD,0xD41B},{SMART_CONFIG_DATA,0xcd}, + {SMART_CONFIG_CMD,0xD41C},{SMART_CONFIG_DATA,0xd6}, + {SMART_CONFIG_CMD,0xD41D},{SMART_CONFIG_DATA,0xdf}, + {SMART_CONFIG_CMD,0xD41E},{SMART_CONFIG_DATA,0x95}, + {SMART_CONFIG_CMD,0xD41F},{SMART_CONFIG_DATA,0xe8}, + {SMART_CONFIG_CMD,0xD420},{SMART_CONFIG_DATA,0xf1}, + {SMART_CONFIG_CMD,0xD421},{SMART_CONFIG_DATA,0xfa}, + {SMART_CONFIG_CMD,0xD422},{SMART_CONFIG_DATA,0x02}, + {SMART_CONFIG_CMD,0xD423},{SMART_CONFIG_DATA,0xaa}, + {SMART_CONFIG_CMD,0xD424},{SMART_CONFIG_DATA,0x0b}, + {SMART_CONFIG_CMD,0xD425},{SMART_CONFIG_DATA,0x13}, + {SMART_CONFIG_CMD,0xD426},{SMART_CONFIG_DATA,0x1d}, + {SMART_CONFIG_CMD,0xD427},{SMART_CONFIG_DATA,0x26}, + {SMART_CONFIG_CMD,0xD428},{SMART_CONFIG_DATA,0xaa}, + {SMART_CONFIG_CMD,0xD429},{SMART_CONFIG_DATA,0x30}, + {SMART_CONFIG_CMD,0xD42A},{SMART_CONFIG_DATA,0x3c}, + {SMART_CONFIG_CMD,0xD42B},{SMART_CONFIG_DATA,0x4A}, + {SMART_CONFIG_CMD,0xD42C},{SMART_CONFIG_DATA,0x63}, + {SMART_CONFIG_CMD,0xD42D},{SMART_CONFIG_DATA,0xea}, + {SMART_CONFIG_CMD,0xD42E},{SMART_CONFIG_DATA,0x79}, + {SMART_CONFIG_CMD,0xD42F},{SMART_CONFIG_DATA,0xa6}, + {SMART_CONFIG_CMD,0xD430},{SMART_CONFIG_DATA,0xd0}, + {SMART_CONFIG_CMD,0xD431},{SMART_CONFIG_DATA,0x20}, + {SMART_CONFIG_CMD,0xD432},{SMART_CONFIG_DATA,0x0f}, + {SMART_CONFIG_CMD,0xD433},{SMART_CONFIG_DATA,0x8e}, + {SMART_CONFIG_CMD,0xD434},{SMART_CONFIG_DATA,0xff}, + + //GAMMA SETING GREEN + {SMART_CONFIG_CMD,0xD500},{SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_CMD,0xD501},{SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_CMD,0xD502},{SMART_CONFIG_DATA,0x1b}, + {SMART_CONFIG_CMD,0xD503},{SMART_CONFIG_DATA,0x44}, + {SMART_CONFIG_CMD,0xD504},{SMART_CONFIG_DATA,0x62}, + {SMART_CONFIG_CMD,0xD505},{SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_CMD,0xD506},{SMART_CONFIG_DATA,0x7b}, + {SMART_CONFIG_CMD,0xD507},{SMART_CONFIG_DATA,0xa1}, + {SMART_CONFIG_CMD,0xD508},{SMART_CONFIG_DATA,0xc0}, + {SMART_CONFIG_CMD,0xD509},{SMART_CONFIG_DATA,0xee}, + {SMART_CONFIG_CMD,0xD50A},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xD50B},{SMART_CONFIG_DATA,0x10}, + {SMART_CONFIG_CMD,0xD50C},{SMART_CONFIG_DATA,0x2c}, + {SMART_CONFIG_CMD,0xD50D},{SMART_CONFIG_DATA,0x43}, + {SMART_CONFIG_CMD,0xD50E},{SMART_CONFIG_DATA,0x57}, + {SMART_CONFIG_CMD,0xD50F},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xD510},{SMART_CONFIG_DATA,0x68}, + {SMART_CONFIG_CMD,0xD511},{SMART_CONFIG_DATA,0x78}, + {SMART_CONFIG_CMD,0xD512},{SMART_CONFIG_DATA,0x87}, + {SMART_CONFIG_CMD,0xD513},{SMART_CONFIG_DATA,0x94}, + {SMART_CONFIG_CMD,0xD514},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xD515},{SMART_CONFIG_DATA,0xa0}, + {SMART_CONFIG_CMD,0xD516},{SMART_CONFIG_DATA,0xac}, + {SMART_CONFIG_CMD,0xD517},{SMART_CONFIG_DATA,0xb6}, + {SMART_CONFIG_CMD,0xD518},{SMART_CONFIG_DATA,0xc1}, + {SMART_CONFIG_CMD,0xD519},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xD51A},{SMART_CONFIG_DATA,0xcb}, + {SMART_CONFIG_CMD,0xD51B},{SMART_CONFIG_DATA,0xcd}, + {SMART_CONFIG_CMD,0xD51C},{SMART_CONFIG_DATA,0xd6}, + {SMART_CONFIG_CMD,0xD51D},{SMART_CONFIG_DATA,0xdf}, + {SMART_CONFIG_CMD,0xD51E},{SMART_CONFIG_DATA,0x95}, + {SMART_CONFIG_CMD,0xD51F},{SMART_CONFIG_DATA,0xe8}, + {SMART_CONFIG_CMD,0xD520},{SMART_CONFIG_DATA,0xf1}, + {SMART_CONFIG_CMD,0xD521},{SMART_CONFIG_DATA,0xfa}, + {SMART_CONFIG_CMD,0xD522},{SMART_CONFIG_DATA,0x02}, + {SMART_CONFIG_CMD,0xD523},{SMART_CONFIG_DATA,0xaa}, + {SMART_CONFIG_CMD,0xD524},{SMART_CONFIG_DATA,0x0b}, + {SMART_CONFIG_CMD,0xD525},{SMART_CONFIG_DATA,0x13}, + {SMART_CONFIG_CMD,0xD526},{SMART_CONFIG_DATA,0x1d}, + {SMART_CONFIG_CMD,0xD527},{SMART_CONFIG_DATA,0x26}, + {SMART_CONFIG_CMD,0xD528},{SMART_CONFIG_DATA,0xaa}, + {SMART_CONFIG_CMD,0xD529},{SMART_CONFIG_DATA,0x30}, + {SMART_CONFIG_CMD,0xD52A},{SMART_CONFIG_DATA,0x3c}, + {SMART_CONFIG_CMD,0xD52B},{SMART_CONFIG_DATA,0x4a}, + {SMART_CONFIG_CMD,0xD52C},{SMART_CONFIG_DATA,0x63}, + {SMART_CONFIG_CMD,0xD52D},{SMART_CONFIG_DATA,0xea}, + {SMART_CONFIG_CMD,0xD52E},{SMART_CONFIG_DATA,0x79}, + {SMART_CONFIG_CMD,0xD52F},{SMART_CONFIG_DATA,0xa6}, + {SMART_CONFIG_CMD,0xD530},{SMART_CONFIG_DATA,0xd0}, + {SMART_CONFIG_CMD,0xD531},{SMART_CONFIG_DATA,0x20}, + {SMART_CONFIG_CMD,0xD532},{SMART_CONFIG_DATA,0x0f}, + {SMART_CONFIG_CMD,0xD533},{SMART_CONFIG_DATA,0x8e}, + {SMART_CONFIG_CMD,0xD534},{SMART_CONFIG_DATA,0xff}, + + //GAMMA SETING BLUE + {SMART_CONFIG_CMD,0xD600},{SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_CMD,0xD601},{SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_CMD,0xD602},{SMART_CONFIG_DATA,0x1b}, + {SMART_CONFIG_CMD,0xD603},{SMART_CONFIG_DATA,0x44}, + {SMART_CONFIG_CMD,0xD604},{SMART_CONFIG_DATA,0x62}, + {SMART_CONFIG_CMD,0xD605},{SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_CMD,0xD606},{SMART_CONFIG_DATA,0x7b}, + {SMART_CONFIG_CMD,0xD607},{SMART_CONFIG_DATA,0xa1}, + {SMART_CONFIG_CMD,0xD608},{SMART_CONFIG_DATA,0xc0}, + {SMART_CONFIG_CMD,0xD609},{SMART_CONFIG_DATA,0xee}, + {SMART_CONFIG_CMD,0xD60A},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xD60B},{SMART_CONFIG_DATA,0x10}, + {SMART_CONFIG_CMD,0xD60C},{SMART_CONFIG_DATA,0x2c}, + {SMART_CONFIG_CMD,0xD60D},{SMART_CONFIG_DATA,0x43}, + {SMART_CONFIG_CMD,0xD60E},{SMART_CONFIG_DATA,0x57}, + {SMART_CONFIG_CMD,0xD60F},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xD610},{SMART_CONFIG_DATA,0x68}, + {SMART_CONFIG_CMD,0xD611},{SMART_CONFIG_DATA,0x78}, + {SMART_CONFIG_CMD,0xD612},{SMART_CONFIG_DATA,0x87}, + {SMART_CONFIG_CMD,0xD613},{SMART_CONFIG_DATA,0x94}, + {SMART_CONFIG_CMD,0xD614},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xD615},{SMART_CONFIG_DATA,0xa0}, + {SMART_CONFIG_CMD,0xD616},{SMART_CONFIG_DATA,0xac}, + {SMART_CONFIG_CMD,0xD617},{SMART_CONFIG_DATA,0xb6}, + {SMART_CONFIG_CMD,0xD618},{SMART_CONFIG_DATA,0xc1}, + {SMART_CONFIG_CMD,0xD619},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xD61A},{SMART_CONFIG_DATA,0xcb}, + {SMART_CONFIG_CMD,0xD61B},{SMART_CONFIG_DATA,0xcd}, + {SMART_CONFIG_CMD,0xD61C},{SMART_CONFIG_DATA,0xd6}, + {SMART_CONFIG_CMD,0xD61D},{SMART_CONFIG_DATA,0xdf}, + {SMART_CONFIG_CMD,0xD61E},{SMART_CONFIG_DATA,0x95}, + {SMART_CONFIG_CMD,0xD61F},{SMART_CONFIG_DATA,0xe8}, + {SMART_CONFIG_CMD,0xD620},{SMART_CONFIG_DATA,0xf1}, + {SMART_CONFIG_CMD,0xD621},{SMART_CONFIG_DATA,0xfa}, + {SMART_CONFIG_CMD,0xD622},{SMART_CONFIG_DATA,0x02}, + {SMART_CONFIG_CMD,0xD623},{SMART_CONFIG_DATA,0xaa}, + {SMART_CONFIG_CMD,0xD624},{SMART_CONFIG_DATA,0x0b}, + {SMART_CONFIG_CMD,0xD625},{SMART_CONFIG_DATA,0x13}, + {SMART_CONFIG_CMD,0xD626},{SMART_CONFIG_DATA,0x1d}, + {SMART_CONFIG_CMD,0xD627},{SMART_CONFIG_DATA,0x26}, + {SMART_CONFIG_CMD,0xD628},{SMART_CONFIG_DATA,0xaa}, + {SMART_CONFIG_CMD,0xD629},{SMART_CONFIG_DATA,0x30}, + {SMART_CONFIG_CMD,0xD62A},{SMART_CONFIG_DATA,0x3c}, + {SMART_CONFIG_CMD,0xD62B},{SMART_CONFIG_DATA,0x4A}, + {SMART_CONFIG_CMD,0xD62C},{SMART_CONFIG_DATA,0x63}, + {SMART_CONFIG_CMD,0xD62D},{SMART_CONFIG_DATA,0xea}, + {SMART_CONFIG_CMD,0xD62E},{SMART_CONFIG_DATA,0x79}, + {SMART_CONFIG_CMD,0xD62F},{SMART_CONFIG_DATA,0xa6}, + {SMART_CONFIG_CMD,0xD630},{SMART_CONFIG_DATA,0xd0}, + {SMART_CONFIG_CMD,0xD631},{SMART_CONFIG_DATA,0x20}, + {SMART_CONFIG_CMD,0xD632},{SMART_CONFIG_DATA,0x0f}, + {SMART_CONFIG_CMD,0xD633},{SMART_CONFIG_DATA,0x8e}, + {SMART_CONFIG_CMD,0xD634},{SMART_CONFIG_DATA,0xff}, + + //AVDD VOLTAGE SETTING + {SMART_CONFIG_CMD,0xB000},{SMART_CONFIG_DATA,0x05}, + {SMART_CONFIG_CMD,0xB001},{SMART_CONFIG_DATA,0x05}, + {SMART_CONFIG_CMD,0xB002},{SMART_CONFIG_DATA,0x05}, + //AVEE VOLTAGE SETTING + {SMART_CONFIG_CMD,0xB100},{SMART_CONFIG_DATA,0x05}, + {SMART_CONFIG_CMD,0xB101},{SMART_CONFIG_DATA,0x05}, + {SMART_CONFIG_CMD,0xB102},{SMART_CONFIG_DATA,0x05}, + + //AVDD Boosting + {SMART_CONFIG_CMD,0xB600},{SMART_CONFIG_DATA,0x34}, + {SMART_CONFIG_CMD,0xB601},{SMART_CONFIG_DATA,0x34}, + {SMART_CONFIG_CMD,0xB603},{SMART_CONFIG_DATA,0x34}, + //AVEE Boosting + {SMART_CONFIG_CMD,0xB700},{SMART_CONFIG_DATA,0x24}, + {SMART_CONFIG_CMD,0xB701},{SMART_CONFIG_DATA,0x24}, + {SMART_CONFIG_CMD,0xB702},{SMART_CONFIG_DATA,0x24}, + //VCL Boosting + {SMART_CONFIG_CMD,0xB800},{SMART_CONFIG_DATA,0x24}, + {SMART_CONFIG_CMD,0xB801},{SMART_CONFIG_DATA,0x24}, + {SMART_CONFIG_CMD,0xB802},{SMART_CONFIG_DATA,0x24}, + //VGLX VOLTAGE SETTING + {SMART_CONFIG_CMD,0xBA00},{SMART_CONFIG_DATA,0x14}, + {SMART_CONFIG_CMD,0xBA01},{SMART_CONFIG_DATA,0x14}, + {SMART_CONFIG_CMD,0xBA02},{SMART_CONFIG_DATA,0x14}, + //VCL Boosting + {SMART_CONFIG_CMD,0xB900},{SMART_CONFIG_DATA,0x24}, + {SMART_CONFIG_CMD,0xB901},{SMART_CONFIG_DATA,0x24}, + {SMART_CONFIG_CMD,0xB902},{SMART_CONFIG_DATA,0x24}, + //Gamma Voltage + {SMART_CONFIG_CMD,0xBc00},{SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_CMD,0xBc01},{SMART_CONFIG_DATA,0xa0},//vgmp=5.0 + {SMART_CONFIG_CMD,0xBc02},{SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_CMD,0xBd00},{SMART_CONFIG_DATA,0x00}, + {SMART_CONFIG_CMD,0xBd01},{SMART_CONFIG_DATA,0xa0},//vgmn=5.0 + {SMART_CONFIG_CMD,0xBd02},{SMART_CONFIG_DATA,0x00}, + //VCOM Setting + {SMART_CONFIG_CMD,0xBe01},{SMART_CONFIG_DATA,0x3d},//3 + //ENABLE PAGE 0 + {SMART_CONFIG_CMD,0xF000},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xF001},{SMART_CONFIG_DATA,0xAA}, + {SMART_CONFIG_CMD,0xF002},{SMART_CONFIG_DATA,0x52}, + {SMART_CONFIG_CMD,0xF003},{SMART_CONFIG_DATA,0x08}, + {SMART_CONFIG_CMD,0xF004},{SMART_CONFIG_DATA,0x00}, + //Vivid Color Function Control + {SMART_CONFIG_CMD,0xB400},{SMART_CONFIG_DATA,0x10}, + //Z-INVERSION + {SMART_CONFIG_CMD,0xBC00},{SMART_CONFIG_DATA,0x05}, + {SMART_CONFIG_CMD,0xBC01},{SMART_CONFIG_DATA,0x05}, + {SMART_CONFIG_CMD,0xBC02},{SMART_CONFIG_DATA,0x05}, + + //*************** add on 20111021**********************// + {SMART_CONFIG_CMD,0xB700},{SMART_CONFIG_DATA,0x22},//GATE EQ CONTROL + {SMART_CONFIG_CMD,0xB701},{SMART_CONFIG_DATA,0x22},//GATE EQ CONTROL + + {SMART_CONFIG_CMD,0xC80B},{SMART_CONFIG_DATA,0x2A},//DISPLAY TIMING CONTROL + {SMART_CONFIG_CMD,0xC80C},{SMART_CONFIG_DATA,0x2A},//DISPLAY TIMING CONTROL + {SMART_CONFIG_CMD,0xC80F},{SMART_CONFIG_DATA,0x2A},//DISPLAY TIMING CONTROL + {SMART_CONFIG_CMD,0xC810},{SMART_CONFIG_DATA,0x2A},//DISPLAY TIMING CONTROL + //*************** add on 20111021**********************// + //PWM_ENH_OE =1 + {SMART_CONFIG_CMD,0xd000},{SMART_CONFIG_DATA,0x01}, + //DM_SEL =1 + {SMART_CONFIG_CMD,0xb300},{SMART_CONFIG_DATA,0x10}, + //VBPDA=07h + {SMART_CONFIG_CMD,0xBd02},{SMART_CONFIG_DATA,0x07}, + //VBPDb=07h + {SMART_CONFIG_CMD,0xBe02},{SMART_CONFIG_DATA,0x07}, + //VBPDc=07h + {SMART_CONFIG_CMD,0xBf02},{SMART_CONFIG_DATA,0x07}, + //ENABLE PAGE 2 + {SMART_CONFIG_CMD,0xF000},{SMART_CONFIG_DATA,0x55}, + {SMART_CONFIG_CMD,0xF001},{SMART_CONFIG_DATA,0xAA}, + {SMART_CONFIG_CMD,0xF002},{SMART_CONFIG_DATA,0x52}, + {SMART_CONFIG_CMD,0xF003},{SMART_CONFIG_DATA,0x08}, + {SMART_CONFIG_CMD,0xF004},{SMART_CONFIG_DATA,0x02}, + //SDREG0 =0 + {SMART_CONFIG_CMD,0xc301},{SMART_CONFIG_DATA,0xa9}, + //DS=14 + {SMART_CONFIG_CMD,0xfe01},{SMART_CONFIG_DATA,0x94}, + //OSC =60h + {SMART_CONFIG_CMD,0xf600},{SMART_CONFIG_DATA,0x60}, + //TE ON + {SMART_CONFIG_CMD,0x3500},{SMART_CONFIG_DATA,0x00}, + + //SLEEP OUT + {SMART_CONFIG_CMD,0x1100}, + {SMART_CONFIG_UDELAY,1000}, + //DISPLY ON + {SMART_CONFIG_CMD,0x2900}, + {SMART_CONFIG_UDELAY,1000}, + + //SET BPP +#if CFG_LCD_BPP == USING_16_BPP + {SMART_CONFIG_CMD,0x3A00},{SMART_CONFIG_DATA,0x55},//16BIT PIXEL FORMAT +#elif CFG_LCD_BPP == USING_18_BPP + {SMART_CONFIG_CMD,0x3A00},{SMART_CONFIG_DATA,0x66},//18BIT PIXEL FORMAT +#elif CFG_LCD_BPP == USING_24_BPP + {SMART_CONFIG_CMD,0x3A00},{SMART_CONFIG_DATA,0x77},//24BIT PIXEL FORMAT +#else +#error "unknown bpp setting...\n"; +#endif + +// {SMART_CONFIG_CMD,0x3600},{SMART_CONFIG_DATA,0xe0}, + {SMART_CONFIG_CMD,0x3600},{SMART_CONFIG_DATA,0xA0}, + + {SMART_CONFIG_UDELAY,1000}, + //set block + {SMART_CONFIG_CMD,0x2a00},{SMART_CONFIG_DATA, 0 >> 8}, + {SMART_CONFIG_CMD,0x2a01},{SMART_CONFIG_DATA, 0 & 0xFF}, + {SMART_CONFIG_CMD,0x2a02},{SMART_CONFIG_DATA,800 >> 8}, + {SMART_CONFIG_CMD,0x2a03},{SMART_CONFIG_DATA,800 & 0xFF}, + {SMART_CONFIG_CMD,0x2b00},{SMART_CONFIG_DATA, 0 >> 8}, + {SMART_CONFIG_CMD,0x2b01},{SMART_CONFIG_DATA, 0 & 0xFF}, + {SMART_CONFIG_CMD,0x2b02},{SMART_CONFIG_DATA,480 >> 8}, + {SMART_CONFIG_CMD,0x2b03},{SMART_CONFIG_DATA,480 & 0xFF}, + {SMART_CONFIG_CMD,0x2C00} +}; + +struct slcd_configure _rm68120_config = +{ + .width = 800, + .height = 480, + + .fmt = RTGRAPHIC_PIXEL_FORMAT_RGB565, + .bpp = 16, + .bus_width = 8, + .reg_width = 16, + + .rsply_cmd_high = 0, + .csply_active_high = 0, + /* write graphic ram command, in word, for example 8-bit bus, write_gram_cmd=C3C2C1C0. */ + .newcfg_fmt_conv = 1, + .data_table = &_rm68120_data_table[0], + .data_table_num = sizeof(_rm68120_data_table)/sizeof(_rm68120_data_table[0]), + + .cmd_table = &_rm68120_cmd_table[0], + .cmd_table_num = sizeof(_rm68120_cmd_table)/sizeof(_rm68120_cmd_table[0]) +}; + + +int rt_hw_rm68120_init(void) +{ + /* reset lcd pane */ + gpio_direction_output(LCD_RST_PORT, LCD_RST_PIN, 0); //reset + rt_thread_delay(rt_tick_from_millisecond(250)); + gpio_set_value(LCD_RST_PORT, LCD_RST_PIN, 1); + rt_thread_delay(rt_tick_from_millisecond(100)); + + /* enable backlight */ + gpio_direction_output(LCD_BL_PORT, LCD_BL_PIN,1); + + + /* init lcd & register lcd device */ + rt_hw_slcd_init(&_rm68120_config); + + return 0; +} + +void rt_hw_rm68120_fill(rt_uint16_t color) +{ + rt_uint32_t idx; + rt_uint16_t *ptr = (rt_uint16_t *)((FB_BASE + 4096)); + int fb_size = (_rm68120_config.width * (_rm68120_config.bpp / 8)) * _rm68120_config.height; + + + rt_kprintf("fbbase = %08x,fb_size = %d\n",(rt_uint32_t)ptr,fb_size); + for (idx = 0; idx < (fb_size/2); ++idx) + { + *ptr = (rt_uint16_t)color; + ptr++; + } + rt_hw_dcache_flush_range(FB_BASE + 4096,fb_size); +} +#endif diff --git a/bsp/x1000/drivers/slcd/drv_slcd_truly_tft240240.c b/bsp/x1000/drivers/slcd/drv_slcd_truly_tft240240.c new file mode 100644 index 0000000000000000000000000000000000000000..a6efe645c8bb5c487ba70992640ee523b5de2602 --- /dev/null +++ b/bsp/x1000/drivers/slcd/drv_slcd_truly_tft240240.c @@ -0,0 +1,207 @@ +/* + * File : drv_slcd_truly240240.c + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * Change Logs: + * Date Author Notes + * 2017年4月28日 Urey the first version + */ + +#include +#include + +#include "board.h" +#include "drv_slcdc.h" +#include + +#ifdef RT_USING_TRULY_TFT240240 + +rt_uint32_t _truly_tft240240_cmd_table[]= +{ + 0x2c2c0000, +}; + + +struct slcd_data_table _truly_tft240240_data_table[] = +{ + /* LCD init code */ + {SMART_CONFIG_CMD, 0x01}, //soft reset, 120 ms = 120 000 us + {SMART_CONFIG_UDELAY, 20}, + {SMART_CONFIG_CMD, 0x11}, + {SMART_CONFIG_UDELAY, 10}, /* sleep out 50 ms */ + + {SMART_CONFIG_CMD, 0x36}, +#ifdef CONFIG_TRULY_240X240_ROTATE_180 + {SMART_CONFIG_DATA, 0xd0}, //40 +#else + {SMART_CONFIG_DATA, 0x00}, //40 +#endif + + {SMART_CONFIG_CMD, 0x2a}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0xef}, + + {SMART_CONFIG_CMD, 0x2b}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0xef}, + + {SMART_CONFIG_CMD, 0x3a}, +#if defined(CONFIG_SLCD_TRULY_18BIT) //if 18bit/pixel unusual. try to use 16bit/pixel + {SMART_CONFIG_DATA, 0x06}, //6-6-6 +#else + {SMART_CONFIG_DATA, 0x05}, //5-6-5 +#endif + // {SMART_CONFIG_DATA, 0x55}, + + {SMART_CONFIG_CMD, 0xb2}, + {SMART_CONFIG_DATA, 0x7f}, + {SMART_CONFIG_DATA, 0x7f}, + {SMART_CONFIG_DATA, 0x01}, + {SMART_CONFIG_DATA, 0xde}, + {SMART_CONFIG_DATA, 0x33}, + + {SMART_CONFIG_CMD, 0xb3}, + {SMART_CONFIG_DATA, 0x10}, + {SMART_CONFIG_DATA, 0x05}, + {SMART_CONFIG_DATA, 0x0f}, + + {SMART_CONFIG_CMD, 0xb4}, + {SMART_CONFIG_DATA, 0x0b}, + + {SMART_CONFIG_CMD, 0xb7}, + {SMART_CONFIG_DATA, 0x35}, + + {SMART_CONFIG_CMD, 0xbb}, + {SMART_CONFIG_DATA, 0x28}, //23 + + {SMART_CONFIG_CMD, 0xbc}, + {SMART_CONFIG_DATA, 0xec}, + + {SMART_CONFIG_CMD, 0xc0}, + {SMART_CONFIG_DATA, 0x2c}, + + {SMART_CONFIG_CMD, 0xc2}, + {SMART_CONFIG_DATA, 0x01}, + + {SMART_CONFIG_CMD, 0xc3}, + {SMART_CONFIG_DATA, 0x1e}, //14 + + {SMART_CONFIG_CMD, 0xc4}, + {SMART_CONFIG_DATA, 0x20}, + + {SMART_CONFIG_CMD, 0xc6}, + {SMART_CONFIG_DATA, 0x14}, + + {SMART_CONFIG_CMD, 0xd0}, + {SMART_CONFIG_DATA, 0xa4}, + {SMART_CONFIG_DATA, 0xa1}, + + {SMART_CONFIG_CMD, 0xe0}, + {SMART_CONFIG_DATA, 0xd0}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x08}, + {SMART_CONFIG_DATA, 0x07}, + {SMART_CONFIG_DATA, 0x05}, + {SMART_CONFIG_DATA, 0x29}, + {SMART_CONFIG_DATA, 0x54}, + {SMART_CONFIG_DATA, 0x41}, + {SMART_CONFIG_DATA, 0x3c}, + {SMART_CONFIG_DATA, 0x17}, + {SMART_CONFIG_DATA, 0x15}, + {SMART_CONFIG_DATA, 0x1a}, + {SMART_CONFIG_DATA, 0x20}, + + {SMART_CONFIG_CMD, 0xe1}, + {SMART_CONFIG_DATA, 0xd0}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x00}, + {SMART_CONFIG_DATA, 0x08}, + {SMART_CONFIG_DATA, 0x07}, + {SMART_CONFIG_DATA, 0x04}, + {SMART_CONFIG_DATA, 0x29}, + {SMART_CONFIG_DATA, 0x44}, + {SMART_CONFIG_DATA, 0x42}, + {SMART_CONFIG_DATA, 0x3b}, + {SMART_CONFIG_DATA, 0x16}, + {SMART_CONFIG_DATA, 0x15}, + {SMART_CONFIG_DATA, 0x1b}, + {SMART_CONFIG_DATA, 0x1f}, + + {SMART_CONFIG_CMD, 0x35}, // TE on + {SMART_CONFIG_DATA, 0x00}, // TE mode: 0, mode1; 1, mode2 + // {SMART_CONFIG_CMD, 0x34}, // TE off + + {SMART_CONFIG_CMD, 0x29}, //Display ON + + /* set window size*/ + // {SMART_CONFIG_CMD, 0xcd}, + {SMART_CONFIG_CMD, 0x2a}, + {SMART_CONFIG_DATA, 0}, + {SMART_CONFIG_DATA, 0}, + {SMART_CONFIG_DATA, (239>> 8) & 0xff}, + {SMART_CONFIG_DATA, 239 & 0xff}, +#ifdef CONFIG_TRULY_240X240_ROTATE_180 + {SMART_CONFIG_CMD, 0x2b}, + {SMART_CONFIG_DATA, ((320-240)>>8)&0xff}, + {SMART_CONFIG_DATA, ((320-240)>>0)&0xff}, + {SMART_CONFIG_DATA, ((320-1)>>8) & 0xff}, + {SMART_CONFIG_DATA, ((320-1)>>0) & 0xff}, +#else + {SMART_CONFIG_CMD, 0x2b}, + {SMART_CONFIG_DATA, 0}, + {SMART_CONFIG_DATA, 0}, + {SMART_CONFIG_DATA, (239>> 8) & 0xff}, + {SMART_CONFIG_DATA, 239 & 0xff}, +#endif + + {SMART_CONFIG_CMD, 0X2C}, //GRAM start writing +}; + +struct slcd_configure _truly_tft240240_config = +{ + .width = 240, + .height = 240, + + .fmt = RTGRAPHIC_PIXEL_FORMAT_RGB565, + .bpp = 16, + .bus_width = 8, + .reg_width = 8, + .refresh = 60, + + .reg_write_twice = 0, + .rsply_cmd_high = 0, + .csply_active_high = 0, + /* write graphic ram command, in word, for example 8-bit bus, write_gram_cmd=C3C2C1C0. */ + .newcfg_fmt_conv = 1, + .data_table = &_truly_tft240240_data_table[0], + .data_table_num = sizeof(_truly_tft240240_data_table)/sizeof(_truly_tft240240_data_table[0]), + + .cmd_table = &_truly_tft240240_cmd_table[0], + .cmd_table_num = sizeof(_truly_tft240240_cmd_table)/sizeof(_truly_tft240240_cmd_table[0]) +}; + + +int truly_tft240240_init(void) +{ + /* reset lcd pane */ + gpio_direction_output(LCD_RST_PORT, LCD_RST_PIN, 0); //reset + rt_thread_delay(rt_tick_from_millisecond(50)); + gpio_set_value(LCD_RST_PORT, LCD_RST_PIN, 1); + rt_thread_delay(rt_tick_from_millisecond(50)); + + /* enable backlight */ + gpio_direction_output(LCD_BLEN_PORT, LCD_BLEN_PIN,1); + gpio_direction_output(LCD_BLPWM_PORT, LCD_BLPWM_PIN,1); + + /* init lcd & register lcd device */ + rt_hw_slcd_init(&_truly_tft240240_config); + + return 0; +} + +#endif diff --git a/bsp/x1000/drivers/slcd/drv_slcdc.c b/bsp/x1000/drivers/slcd/drv_slcdc.c new file mode 100644 index 0000000000000000000000000000000000000000..ac1a93f4b4e485050e76d7412d01a45ab92a5ed0 --- /dev/null +++ b/bsp/x1000/drivers/slcd/drv_slcdc.c @@ -0,0 +1,496 @@ +/* + * File : drv_slcd_new.c + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * Change Logs: + * Date Author Notes + * 2017年4月10日 Urey the first version + */ + +#include +#include +#include +#include + +#include "board.h" + +#include "drv_slcdc.h" +#include "drv_clock.h" +#include "drv_gpio.h" + +static struct slcdc_dev_s *_slcd_device; + +static void _slcd_enable(struct slcdc_dev_s *lcd_dev); +static void _slcd_disable(struct slcdc_dev_s *lcd_dev); + +static void udelay(uint32_t x) +{ + volatile uint32_t n ; + + while(x--) + { + for (n = 0; n < 200; ++n); + } +} + +static int _slcd_convert_bpp(uint32_t bpp) +{ + switch (bpp) + { + case 18: + case 24: + return 32; + case 15: + return 16; + default: + return bpp; + } +} + +static uint32_t refresh_pixclock_auto_adapt(struct slcdc_dev_s *lcd_dev) +{ + uint32_t pixclk = 0; + + if((lcd_dev->cfg->refresh < 10) || (lcd_dev->cfg->refresh > 100)) + lcd_dev->cfg->refresh = 60; + + pixclk = lcd_dev->fb_size * lcd_dev->cfg->refresh * 9;// Range 7 to 10 + + return pixclk; +} + +static void _slcd_wait_busy(void) +{ + int count = 10000; + while ((slcd_reg_read(SLCDC_STATE) & SLCDC_STATE_BUSY) && count--); +} +/* Sent a command without data (18-bit bus, 16-bit index) */ +static void _slcd_mcu_send_command(struct slcdc_dev_s *lcd_dev,uint16_t cmd) +{ + _slcd_wait_busy(); + + cmd &= 0xffffff; + slcd_reg_write(SLCDC_DATA, SLCDC_DATA_RS_COMMAND | cmd); +} + +static void _slcd_mcu_send_data(struct slcdc_dev_s *lcd_dev,uint16_t data) +{ + _slcd_wait_busy(); + + data &= 0xffffff; + slcd_reg_write(SLCDC_DATA, SLCDC_DATA_RS_DATA | data); +} + +/* Sent a command with data (18-bit bus, 16-bit index, 16-bit register value) */ +static void _slcd_mcu_set_register(struct slcdc_dev_s *lcd_dev,uint16_t cmd, uint16_t data) +{ + _slcd_mcu_send_command(lcd_dev,cmd); + _slcd_mcu_send_data(lcd_dev,data); +} + +static void _slcd_init_mcu(struct slcdc_dev_s *lcd_dev) +{ + struct slcd_configure *cfg = lcd_dev->cfg; + uint32_t index,j; + uint32_t reg_width = lcd_dev->cfg->reg_width; + uint32_t bus_width = lcd_dev->cfg->bus_width; + + if(reg_width < bus_width) + reg_width = bus_width; + + if (cfg->data_table_num && cfg->data_table) + { + for (index = 0; index < cfg->data_table_num; index ++) + { + uint32_t value = cfg->data_table[index].value; + switch (cfg->data_table[index].type) + { + case SMART_CONFIG_CMD: + for (j = reg_width / bus_width; j > 0; j--) + _slcd_mcu_send_command(lcd_dev, ((value << (32 - bus_width * j)) >> (32 - bus_width))); + break; + case SMART_CONFIG_DATA: + for (j = reg_width / bus_width; j > 0; j--) + _slcd_mcu_send_data(lcd_dev,((value << (32 - bus_width * j))>> (32 - bus_width))); + break; + case SMART_CONFIG_UDELAY: + udelay(cfg->data_table[index].value); + break; + } + } + _slcd_wait_busy(); + } + + if (cfg->bpp / cfg->bus_width != 1) + { + int tmp = slcd_reg_read(SLCDC_CFG_NEW); + tmp &= ~(SMART_LCD_DWIDTH_MASK); //mask the 8~9bit + tmp |= (cfg->bpp / cfg->bus_width) == 2 ? SMART_LCD_NEW_DTIMES_TWICE : SMART_LCD_NEW_DTIMES_THICE ; + slcd_reg_write(SLCDC_CFG_NEW, tmp); + } +} + +static void _slcd_init_mem(struct slcdc_dev_s *lcd_dev) +{ + struct slcd_configure *cfg = lcd_dev->cfg; + int i; + uint32_t bypes_per_panel = (((cfg->width * _slcd_convert_bpp(cfg->bpp) / 8 + 3) >> 2 << 2) * cfg->height); + +#ifdef FB_BASE + lcd_dev->fb_base = FB_BASE; +#else +#ifdef SLCDC_USING_DUAL_BUFFER + lcd_dev->fb_base = (rt_uint32_t)rt_malloc_align((bypes_per_panel + FB_PAGE_SIZE) * 2, 32); +#else + lcd_dev->fb_base = (rt_uint32_t)rt_malloc_align((bypes_per_panel + FB_PAGE_SIZE) * 1, 32); +#endif +#endif + + lcd_dev->desc_cmd = (struct slcdc_dma_descriptor *)(lcd_dev->fb_base + 0 * sizeof(struct slcdc_dma_descriptor)); + lcd_dev->desc_tmp = (struct slcdc_dma_descriptor *)(lcd_dev->fb_base + 1 * sizeof(struct slcdc_dma_descriptor)); + lcd_dev->desc_dat = (struct slcdc_dma_descriptor *)(lcd_dev->fb_base + 2 * sizeof(struct slcdc_dma_descriptor)); + //nop + lcd_dev->fb_cmd = (rt_uint32_t)lcd_dev->fb_base + 4 * sizeof(struct slcdc_dma_descriptor); + + lcd_dev->fb_screen= (rt_uint32_t)lcd_dev->fb_base + FB_PAGE_SIZE; + rt_memset((void *) lcd_dev->fb_screen, 0, bypes_per_panel); + +#ifdef SLCDC_USING_DUAL_BUFFER + lcd_dev->fb_dual = (lcd_dev->fb_screen + bypes_per_panel + FB_PAGE_SIZE) & ~(FB_PAGE_SIZE - 1); + rt_memset((void *)lcd_dev->fb_dual,0,bypes_per_panel); +#endif + + lcd_dev->fb_size = bypes_per_panel; + + /* copy command tbl */ + { + uint32_t* cmd_ptr = (uint32_t*) lcd_dev->fb_cmd; + for (i = 0; i < cfg->cmd_table_num; ++i) + { + cmd_ptr[i] = cfg->cmd_table[i]; + } + } +} + +static void _slcd_init_dma_desc(struct slcdc_dev_s *lcd_dev) +{ + struct slcd_configure *cfg = lcd_dev->cfg; + uint32_t bypes_per_panel = (((cfg->width * _slcd_convert_bpp(cfg->bpp) / 8 + 3) >> 2 << 2) * cfg->height); + + //dmadesc_tmp used to start DMA + lcd_dev->desc_tmp->fdadr = virt_to_phys((void *)lcd_dev->desc_dat); + lcd_dev->desc_tmp->fsadr = 0; + lcd_dev->desc_tmp->fidr = 0xda0c0; + lcd_dev->desc_tmp->ldcmd = LCDC_CMD_CMD | LCDC_CMD_FRM_EN | 0; + lcd_dev->desc_tmp->offsize = 0; + lcd_dev->desc_tmp->page_width = 0; + lcd_dev->desc_tmp->cmd_num = 0; + lcd_dev->desc_tmp->desc_size = 0; + + //dmadesc_cmd used to write CMD + lcd_dev->desc_cmd->fdadr = virt_to_phys((void *)lcd_dev->desc_dat); + lcd_dev->desc_cmd->fsadr = virt_to_phys((void *)lcd_dev->fb_cmd); + lcd_dev->desc_cmd->fidr = 0xda0c1; + lcd_dev->desc_cmd->offsize = 0; + lcd_dev->desc_cmd->page_width = 0; + lcd_dev->desc_cmd->desc_size = 0; + + /* if connect mipi smart lcd, do not sent command by slcdc, send command by mipi dsi controller. */ + switch (cfg->bus_width) + { + case 8: + lcd_dev->desc_cmd->ldcmd = LCDC_CMD_CMD | LCDC_CMD_FRM_EN | 1; + lcd_dev->desc_cmd->cmd_num = 4; + break; + case 9: + case 16: + lcd_dev->desc_cmd->ldcmd = LCDC_CMD_CMD | LCDC_CMD_FRM_EN | 1; + lcd_dev->desc_cmd->cmd_num = 2; + break; + default: + lcd_dev->desc_cmd->ldcmd = LCDC_CMD_CMD | LCDC_CMD_FRM_EN | 1; + lcd_dev->desc_cmd->cmd_num = 1; + break; + } + + //frame_desc[1] used to update GRAM + lcd_dev->desc_dat->fdadr = virt_to_phys((void *)lcd_dev->desc_cmd); + lcd_dev->desc_dat->fsadr = virt_to_phys((void *)lcd_dev->fb_screen); + lcd_dev->desc_dat->fidr = 0xda0d0; + lcd_dev->desc_dat->ldcmd = LCDC_CMD_EOFINT | LCDC_CMD_FRM_EN | (bypes_per_panel / 4); + lcd_dev->desc_dat->offsize = 0; + lcd_dev->desc_dat->page_width = 0; + switch(_slcd_convert_bpp(cfg->bpp)) + { + case 16 : + lcd_dev->desc_dat->cmd_num = LCDC_CPOS_RGB_RGB565 | LCDC_CPOS_BPP_16;; + break; + case 30 : + lcd_dev->desc_dat->cmd_num = LCDC_CPOS_BPP_30; + break; + default: + lcd_dev->desc_dat->cmd_num = LCDC_CPOS_BPP_18_24; + break; + } + + /* data has not been premultied */ + lcd_dev->desc_dat->cmd_num |= LCDC_CPOS_PREMULTI; + /* coef_sle 0 use 1 */ + lcd_dev->desc_dat->cmd_num |= LCDC_CPOS_COEF_SLE_1; + + lcd_dev->desc_dat->desc_size = (((cfg->height - 1) << LCDC_DESSIZE_HEIGHT_BIT) | ((cfg->width - 1) << LCDC_DESSIZE_WIDTH_BIT)); + + slcd_reg_write(LCDC_DA0, virt_to_phys(lcd_dev->desc_cmd)); + + //desc self + rt_hw_flush_cache_all(); +} + +static void _slcd_init_ctrl(struct slcdc_dev_s *lcd_dev) +{ + struct slcd_configure *lcd_cfg = lcd_dev->cfg; + struct clk *clk,*gate_clk; + + uint32_t ctrl; + uint32_t size0; + uint32_t smart_cfg = 0, smart_ctrl = 0; + uint32_t pcfg; + uint32_t smart_new_cfg = 0; + uint32_t smart_wtime = 0, smart_tas = 0; + + /* clear all registers*/ + _slcd_disable(lcd_dev); + slcd_reg_write(SLCDC_CTRL,0); + + /*The SLCD rd and ce function only can be used by set PB16/PB18 as normal GPIO function + * SLCS_D00 PA00 + * ... + * SLCS_D07 PA07 + * + * slcd_rd PB16 (not use,must set high) + * slcd_wr PB17 + * slcd_ce PB18 + * slcd_te PB19 (not use) + * slcd_dc PB20 + * 2. setup SLCD for register mode + * */ + gpio_set_func(GPIO_PORT_A, 0x000000FF, GPIO_FUNC_1); + gpio_set_func(GPIO_PORT_B, (GPIO_Pin_17 | GPIO_Pin_18 | GPIO_Pin_20), GPIO_FUNC_1); +#ifdef CONFIG_SLCDC_USE_TE + gpio_set_func(GPIO_PORT_B, (GPIO_Pin_19), GPIO_FUNC_1); +#endif + gpio_set_func(GPIO_PORT_B, GPIO_Pin_16, GPIO_OUTPUT1); + + /* set clock */ + gate_clk = clk_get("lcd"); + clk = clk_get("cgu_lcd"); + clk_disable(clk); + clk_set_rate(clk, refresh_pixclock_auto_adapt(lcd_dev)); + clk_enable(clk); + clk_enable(gate_clk); + + ctrl = LCDC_CTRL_BST_64 | LCDC_CTRL_OFUM; + if(lcd_cfg->pinmd) + ctrl |= LCDC_CTRL_PINMD; + + smart_cfg = SMART_LCD_DWIDTH_24_BIT_ONCE_PARALLEL; + switch (lcd_cfg->bus_width) + { + case 8: + smart_cfg |= SMART_LCD_CWIDTH_8_BIT_ONCE; + smart_new_cfg |= SMART_LCD_NEW_DWIDTH_8_BIT; + break; + case 9: + smart_cfg |= SMART_LCD_CWIDTH_9_BIT_ONCE; + smart_new_cfg |= SMART_LCD_NEW_DWIDTH_9_BIT; + break; + case 16: + smart_cfg |= SMART_LCD_CWIDTH_16_BIT_ONCE; + smart_new_cfg |= SMART_LCD_NEW_DWIDTH_16_BIT; + break; + case 18: + smart_cfg |= SMART_LCD_CWIDTH_18_BIT_ONCE; + smart_new_cfg |= SMART_LCD_NEW_DWIDTH_18_BIT; + break; + case 24: + smart_cfg |= SMART_LCD_CWIDTH_24_BIT_ONCE; + smart_new_cfg |= SMART_LCD_NEW_DWIDTH_24_BIT; + break; + default: + rt_kprintf("ERR: please check out your bus width config\n"); + break; + } + + if (lcd_cfg->clkply_active_rising) + smart_cfg |= SLCDC_CFG_CLK_ACTIVE_RISING; + if (lcd_cfg->rsply_cmd_high) + smart_cfg |= SLCDC_CFG_RS_CMD_HIGH; + if (lcd_cfg->csply_active_high) + smart_cfg |= SLCDC_CFG_CS_ACTIVE_HIGH; + + /* SLCD DMA mode select 0 */ + smart_ctrl = SLCDC_CTRL_DMA_MODE; + smart_ctrl &= ~SLCDC_CTRL_GATE_MASK; + + smart_ctrl |= (SLCDC_CTRL_NEW_MODE | SLCDC_CTRL_NOT_USE_TE | SLCDC_CTRL_FAST_MODE); //new slcd mode + smart_ctrl &= ~SLCDC_CTRL_MIPI_MODE; + smart_new_cfg |= SMART_LCD_NEW_DTIMES_ONCE; + + if (lcd_cfg->newcfg_6800_md) + smart_new_cfg |= SLCDC_NEW_CFG_6800_MD; + if (lcd_cfg->newcfg_cmd_9bit) + smart_new_cfg |= SLCDC_NEW_CFG_CMD_9BIT; + + slcd_reg_write(LCDC_VAT, (lcd_cfg->width << 16) | lcd_cfg->height); + slcd_reg_write(LCDC_DAH, lcd_cfg->width); + slcd_reg_write(LCDC_DAV, lcd_cfg->height); + + slcd_reg_write(SLCDC_CFG, smart_cfg); + slcd_reg_write(SLCDC_CTRL, smart_ctrl); + slcd_reg_write(SLCDC_CFG_NEW, smart_new_cfg); + slcd_reg_write(SLCDC_WTIME, smart_wtime); + slcd_reg_write(SLCDC_TAS, smart_tas); + slcd_reg_write(SLCDC_SLOW_TIME, 0x0000FFFF); + slcd_reg_write(LCDC_CTRL, ctrl); + + pcfg = 0xC0000000 | (511 << 18) | (400 << 9) | (256 << 0); + slcd_reg_write(LCDC_PCFG, pcfg); + + size0 = (lcd_cfg->width << LCDC_SIZE_WIDTH_BIT) & LCDC_SIZE_WIDTH_MASK; + size0 |= (lcd_cfg->height << LCDC_SIZE_HEIGHT_BIT) & LCDC_SIZE_HEIGHT_MASK; + slcd_reg_write(LCDC_SIZE0, size0); + slcd_reg_write(LCDC_CTRL,slcd_reg_read(LCDC_CTRL) | LCDC_CTRL_ENA); + _slcd_init_dma_desc(lcd_dev); + + _slcd_init_mcu(lcd_dev); + + _slcd_enable(lcd_dev); + + if (lcd_cfg->newcfg_fmt_conv) + { + smart_new_cfg = slcd_reg_read(SLCDC_CFG_NEW); + smart_new_cfg |= SLCDC_NEW_CFG_FMT_CONV_EN; + slcd_reg_write(SLCDC_CFG_NEW, smart_new_cfg); + } + +#ifdef CONFIG_SLCDC_CONTINUA + smart_ctrl &= ~SLCDC_CTRL_DMA_MODE; +#else + smart_ctrl |= SLCDC_CTRL_DMA_START; +#endif + smart_ctrl |= SLCDC_CTRL_DMA_EN; + +#ifdef CONFIG_SLCDC_USE_TE + smart_ctrl &= ~SLCDC_CTRL_NOT_USE_TE; + //smart_ctrl |= SLCDC_CTRL_TE_INV; + smart_ctrl &= ~SLCDC_CTRL_TE_INV; +#endif + slcd_reg_write(SLCDC_CTRL, smart_ctrl); +} + +static void _slcd_enable(struct slcdc_dev_s *lcd_dev) +{ + uint32_t ctrl,state; + int count = 2000; + while ((slcd_reg_read(SLCDC_STATE) & SLCDC_STATE_BUSY) && count--) + { + udelay(10); + } + + slcd_reg_write(LCDC_STATE, 0); + slcd_reg_write(LCDC_CTRL,slcd_reg_read(LCDC_CTRL) | LCDC_CTRL_ENA); +} + +static void _slcd_disable(struct slcdc_dev_s *lcd_dev) +{ + /* SLCD and TVE only support quick disable */ + slcd_reg_write(LCDC_CTRL, slcd_reg_read(LCDC_CTRL) & ~LCDC_CTRL_ENA); +} + +/* common device interface */ +static rt_err_t _slcd_device_control(rt_device_t dev, int cmd, void *args) +{ + struct slcdc_dev_s *slcd; + + uint32_t smart_ctrl = 0; + + slcd = (struct slcdc_dev_s *)dev; + RT_ASSERT(slcd != RT_NULL); + + rt_mutex_take(&(slcd->lock), RT_WAITING_FOREVER); + + switch (cmd) + { + case RTGRAPHIC_CTRL_GET_INFO: + { + struct rt_device_graphic_info *info = (struct rt_device_graphic_info *) args; + + info->bits_per_pixel = slcd->cfg->bpp; + info->pixel_format = slcd->cfg->fmt; +#ifdef SLCDC_USING_DUAL_BUFFER + info->framebuffer = (rt_uint8_t *)(KSEG1ADDR(slcd->fb_dual)); +#else + info->framebuffer = (rt_uint8_t *)(KSEG1ADDR(slcd->fb_screen)); +#endif + + info->width = slcd->cfg->width; + info->height = slcd->cfg->height; + break; + } + + case RTGRAPHIC_CTRL_RECT_UPDATE: + { +#ifdef SLCDC_USING_DUAL_BUFFER + rt_memcpy((void *)(slcd->fb_screen), (void *)(slcd->fb_dual), slcd->fb_size); +#endif + rt_hw_dcache_flush_range((rt_uint32_t)slcd->fb_screen,slcd->fb_size); + + smart_ctrl = slcd_reg_read(SLCDC_CTRL); + smart_ctrl |= SLCDC_CTRL_DMA_START; + slcd_reg_write(SLCDC_CTRL, smart_ctrl); + while (slcd_reg_read(SLCDC_STATE) & SLCDC_STATE_BUSY); + + break; + } + case RTGRAPHIC_CTRL_SET_MODE: + break; + } + + rt_mutex_release(&(slcd->lock)); + + return RT_EOK; +} + +int rt_hw_slcd_init(struct slcd_configure *cfg) +{ + struct slcdc_dev_s *slcd; + + slcd = (struct slcdc_dev_s *)rt_malloc(sizeof(struct slcdc_dev_s)); + if(slcd == RT_NULL) + { + rt_kprintf("error no memory!\n"); + + return -RT_ENOMEM; + } + _slcd_device = slcd; + + slcd->cfg = cfg; + rt_mutex_init(&slcd->lock, "lcdfb", RT_IPC_FLAG_FIFO); + + _slcd_disable(slcd); + _slcd_init_mem(slcd); + _slcd_init_ctrl(slcd); + _slcd_enable(slcd); + /* device support */ + slcd->parent.type = RT_Device_Class_Graphic; + slcd->parent.init = RT_NULL; + slcd->parent.open = RT_NULL; + slcd->parent.close = RT_NULL; + slcd->parent.read = RT_NULL; + slcd->parent.write = RT_NULL; + slcd->parent.control = _slcd_device_control; + + rt_device_register(&slcd->parent, "lcd", RT_DEVICE_FLAG_RDWR); + + return RT_EOK; +} diff --git a/bsp/x1000/drivers/slcd/drv_slcdc.h b/bsp/x1000/drivers/slcd/drv_slcdc.h new file mode 100644 index 0000000000000000000000000000000000000000..21bf9afd55f0ce6cb2d3a3fe2e2606ff0e1d4386 --- /dev/null +++ b/bsp/x1000/drivers/slcd/drv_slcdc.h @@ -0,0 +1,168 @@ +/* + * File : drv_slcdc.h + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * Change Logs: + * Date Author Notes + * 2017年3月21日 Urey the first version + */ +#ifndef _DRV_SLCDC_H_ +#define _DRV_SLCDC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +//#define CONFIG_SLCDC_CONTINUA +#define SLCDC_USING_DUAL_BUFFER +#define CONFIG_SLCDC_USE_TE + +#define FB_BASE 0x80200000 + +#ifndef FB_PAGE_SIZE +# define FB_PAGE_SIZE 4096 +#endif + +/* SLCDC reg ops */ +#define slcd_reg_write(addr,config) writel(config,addr) +#define slcd_reg_read(addr) readl(addr) + + +struct slcdc_dma_descriptor +{ + uint32_t fdadr; /* Frame descriptor address register */ + uint32_t fsadr; /* Frame source address register */ + uint32_t fidr; /* Frame ID register */ + uint32_t ldcmd; /* Command register */ + uint32_t offsize; /* Stride Offsize(in word) */ + uint32_t page_width; /* Stride Pagewidth(in word) */ + uint32_t cmd_num; /* Command Number(for SLCD) */ + uint32_t desc_size; /* Foreground Size */ +}; + +/* smart lcd interface_type */ +enum smart_lcd_type { + SMART_LCD_TYPE_PARALLEL, + SMART_LCD_TYPE_SERIAL, +}; + +/* smart lcd command width */ +enum smart_lcd_cwidth { + SMART_LCD_CWIDTH_16_BIT_ONCE = (0 << 8), + SMART_LCD_CWIDTH_9_BIT_ONCE = SMART_LCD_CWIDTH_16_BIT_ONCE, + SMART_LCD_CWIDTH_8_BIT_ONCE = (0x1 << 8), + SMART_LCD_CWIDTH_18_BIT_ONCE = (0x2 << 8), + SMART_LCD_CWIDTH_24_BIT_ONCE = (0x3 << 8), +}; + +/* smart lcd data width */ +enum smart_lcd_dwidth { + SMART_LCD_DWIDTH_18_BIT_ONCE_PARALLEL_SERIAL = (0 << 10), + SMART_LCD_DWIDTH_16_BIT_ONCE_PARALLEL_SERIAL = (0x1 << 10), + SMART_LCD_DWIDTH_8_BIT_THIRD_TIME_PARALLEL = (0x2 << 10), + SMART_LCD_DWIDTH_8_BIT_TWICE_TIME_PARALLEL = (0x3 << 10), + SMART_LCD_DWIDTH_8_BIT_ONCE_PARALLEL_SERIAL = (0x4 << 10), + SMART_LCD_DWIDTH_24_BIT_ONCE_PARALLEL = (0x5 << 10), + SMART_LCD_DWIDTH_9_BIT_TWICE_TIME_PARALLEL = (0x7 << 10), + SMART_LCD_DWIDTH_MASK = (0x7 << 10), +}; + +/* smart lcd new data width */ +enum smart_lcd_new_dwidth { + SMART_LCD_NEW_DWIDTH_24_BIT = (4 << 13), + SMART_LCD_NEW_DWIDTH_18_BIT = (3 << 13), + SMART_LCD_NEW_DWIDTH_16_BIT = (2 << 13), + SMART_LCD_NEW_DWIDTH_9_BIT = (1 << 13), + SMART_LCD_NEW_DWIDTH_8_BIT = (0 << 13), +}; + +/* smart lcd data times */ +enum smart_lcd_new_dtimes { + SMART_LCD_NEW_DTIMES_ONCE = (0 << 8), + SMART_LCD_NEW_DTIMES_TWICE = (1 << 8), + SMART_LCD_NEW_DTIMES_THICE = (2 << 8), +}; + + +/* smart lcd init code type */ +enum smart_config_type +{ + SMART_CONFIG_CMD = 0, + SMART_CONFIG_DATA = 1, + SMART_CONFIG_UDELAY = 2, +}; + +struct slcd_data_table +{ + enum smart_config_type type; + uint32_t value; +}; + +typedef void (*lcd_bl_func_t)(rt_bool_t isPowerON); + +struct slcd_configure; +struct slcdc_dev_s +{ + struct rt_device parent; + struct rt_mutex lock; + struct slcd_configure *cfg; + + struct slcdc_dma_descriptor *desc_tmp; + struct slcdc_dma_descriptor *desc_cmd; + struct slcdc_dma_descriptor *desc_dat; + struct slcdc_dma_descriptor *desc_self; + + rt_uint32_t fb_base; + rt_uint32_t fb_cmd; + rt_uint32_t fb_screen; +#ifdef SLCDC_USING_DUAL_BUFFER + rt_uint32_t fb_dual; +#endif + rt_uint32_t fb_size; +}; + +struct slcd_configure +{ + unsigned pinmd :1; + unsigned pixclk_falling_edge :1; + unsigned data_enable_active_low :1; + unsigned clkply_active_rising:1; /* smart lcd clock polarity: + 0: Active edge is Falling, + 1: Active edge is Rasing */ + unsigned rsply_cmd_high:1; /* smart lcd RS polarity. + 0: Command_RS=0, Data_RS=1; + 1: Command_RS=1, Data_RS=0 */ + unsigned csply_active_high:1; /* smart lcd CS Polarity. + 0: Active level is low, + 1: Active level is high */ + unsigned newcfg_6800_md:1; + unsigned newcfg_fmt_conv:1; + unsigned newcfg_cmd_9bit:1; + + + rt_uint32_t width; + rt_uint32_t height; + + rt_uint32_t fmt; + rt_uint32_t bpp; + rt_uint32_t bus_width; + rt_uint32_t reg_width; + rt_uint32_t refresh; + + const struct slcd_data_table *data_table; + rt_uint32_t data_table_num; + + const rt_uint32_t *cmd_table; /* write GRAM command */ + rt_uint32_t cmd_table_num; +}; + +int rt_hw_slcd_init (struct slcd_configure *cfg); +void rt_hw_slcd_set_bl_func (lcd_bl_func_t bl_func); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRV_SLCDC_H_ */ diff --git a/bsp/x1000/drivers/slcd/dump_slcd.c b/bsp/x1000/drivers/slcd/dump_slcd.c new file mode 100644 index 0000000000000000000000000000000000000000..9c8c59541c5b962b3665f8e1971dad2f9cf79e2b --- /dev/null +++ b/bsp/x1000/drivers/slcd/dump_slcd.c @@ -0,0 +1,96 @@ +/* + * File : dump_slcd.c + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * Change Logs: + * Date Author Notes + * 2017年4月11日 Urey the first version + */ +#include +#include +#include +#include "x1000_slcdc.h" + +/* SLCDC reg ops */ +#define slcd_reg_write(addr,config) writel(config,addr) +#define slcd_reg_read(addr) readl(addr) + +int dump_slcd_regs(void) +{ + int tmp; + rt_kprintf("$$$dump_lcd_reg\n"); + rt_kprintf("LCDC_CFG:(0x%08x) \t0x%08x\n", LCDC_CFG,slcd_reg_read(LCDC_CFG)); + rt_kprintf("LCDC_CTRL:(0x%08x)\t0x%08x\n",LCDC_CTRL,slcd_reg_read(LCDC_CTRL)); + rt_kprintf("LCDC_STATE:(0x%08x)\t0x%08x\n",LCDC_STATE,slcd_reg_read(LCDC_STATE)); + rt_kprintf("LCDC_OSDC:(0x%08x)\t0x%08x\n", LCDC_OSDC,slcd_reg_read(LCDC_OSDC)); + rt_kprintf("LCDC_OSDCTRL:(0x%08x)\t0x%08x\n",LCDC_OSDCTRL,slcd_reg_read(LCDC_OSDCTRL)); + rt_kprintf("LCDC_OSDS:(0x%08x)\t0x%08x\n",LCDC_OSDS,slcd_reg_read(LCDC_OSDS)); + rt_kprintf("LCDC_BGC0:(0x%08x)\t0x%08x\n",LCDC_BGC0,slcd_reg_read(LCDC_BGC0)); + rt_kprintf("LCDC_BGC1:(0x%08x)\t0x%08x\n",LCDC_BGC1,slcd_reg_read(LCDC_BGC1)); + rt_kprintf("LCDC_KEY0:(0x%08x)\t0x%08x\n",LCDC_KEY0, slcd_reg_read(LCDC_KEY0)); + rt_kprintf("LCDC_KEY1:(0x%08x)\t0x%08x\n",LCDC_KEY1, slcd_reg_read(LCDC_KEY1)); + rt_kprintf("LCDC_ALPHA:(0x%08x)\t0x%08x\n",LCDC_ALPHA, slcd_reg_read(LCDC_ALPHA)); + rt_kprintf("==================================\n"); + tmp = slcd_reg_read(LCDC_VAT); + rt_kprintf("LCDC_VAT:(0x%08x) \t0x%08x, HT = %d, VT = %d\n",LCDC_VAT, tmp, + (tmp & LCDC_VAT_HT_MASK) >> LCDC_VAT_HT_BIT, + (tmp & LCDC_VAT_VT_MASK) >> LCDC_VAT_VT_BIT); + tmp = slcd_reg_read(LCDC_DAH); + rt_kprintf("LCDC_DAH:(0x%08x) \t0x%08x, HDS = %d, HDE = %d\n",LCDC_DAH, tmp, + (tmp & LCDC_DAH_HDS_MASK) >> LCDC_DAH_HDS_BIT, + (tmp & LCDC_DAH_HDE_MASK) >> LCDC_DAH_HDE_BIT); + tmp = slcd_reg_read(LCDC_DAV); + rt_kprintf("LCDC_DAV:(0x%08x) \t0x%08x, VDS = %d, VDE = %d\n",LCDC_DAV, tmp, + (tmp & LCDC_DAV_VDS_MASK) >> LCDC_DAV_VDS_BIT, + (tmp & LCDC_DAV_VDE_MASK) >> LCDC_DAV_VDE_BIT); + tmp = slcd_reg_read(LCDC_HSYNC); + rt_kprintf("LCDC_HSYNC:(0x%08x)\t0x%08x, HPS = %d, HPE = %d\n",LCDC_HSYNC, tmp, + (tmp & LCDC_HSYNC_HPS_MASK) >> LCDC_HSYNC_HPS_BIT, + (tmp & LCDC_HSYNC_HPE_MASK) >> LCDC_HSYNC_HPE_BIT); + tmp = slcd_reg_read(LCDC_VSYNC); + rt_kprintf("LCDC_VSYNC:(0x%08x)\t0x%08x, VPS = %d, VPE = %d\n", LCDC_VSYNC,tmp, + (tmp & LCDC_VSYNC_VPS_MASK) >> LCDC_VSYNC_VPS_BIT, + (tmp & LCDC_VSYNC_VPE_MASK) >> LCDC_VSYNC_VPE_BIT); + rt_kprintf("==================================\n"); + rt_kprintf("LCDC_XYP0:(0x%08x)\t0x%08x\n",LCDC_XYP0, slcd_reg_read(LCDC_XYP0)); + rt_kprintf("LCDC_XYP1:(0x%08x)\t0x%08x\n",LCDC_XYP1, slcd_reg_read(LCDC_XYP1)); + rt_kprintf("LCDC_SIZE0:(0x%08x)\t0x%08x\n",LCDC_SIZE0, slcd_reg_read(LCDC_SIZE0)); + rt_kprintf("LCDC_RGBC:(0x%08x) \t0x%08x\n",LCDC_RGBC, slcd_reg_read(LCDC_RGBC)); + rt_kprintf("LCDC_PS:(0x%08x) \t0x%08x\n",LCDC_PS, slcd_reg_read(LCDC_PS)); + rt_kprintf("LCDC_CLS:(0x%08x) \t0x%08x\n", LCDC_CLS,slcd_reg_read(LCDC_CLS)); + rt_kprintf("LCDC_SPL:(0x%08x) \t0x%08x\n",LCDC_SPL, slcd_reg_read(LCDC_SPL)); + rt_kprintf("LCDC_REV:(0x%08x) \t0x%08x\n",LCDC_REV, slcd_reg_read(LCDC_REV)); + rt_kprintf("LCDC_IID:(0x%08x) \t0x%08x\n",LCDC_IID, slcd_reg_read(LCDC_IID)); + rt_kprintf("==================================\n"); + rt_kprintf("LCDC_DA0:(0x%08x) \t0x%08x\n",LCDC_DA0, slcd_reg_read(LCDC_DA0)); + rt_kprintf("LCDC_SA0:(0x%08x) \t0x%08x\n",LCDC_SA0, slcd_reg_read(LCDC_SA0)); + rt_kprintf("LCDC_FID0:(0x%08x)\t0x%08x\n",LCDC_FID0, slcd_reg_read(LCDC_FID0)); + rt_kprintf("LCDC_CMD0:(0x%08x)\t0x%08x\n",LCDC_CMD0, slcd_reg_read(LCDC_CMD0)); + rt_kprintf("LCDC_OFFS0:(0x%08x)\t0x%08x\n",LCDC_OFFS0, slcd_reg_read(LCDC_OFFS0)); + rt_kprintf("LCDC_PW0:(0x%08x) \t0x%08x\n", LCDC_PW0,slcd_reg_read(LCDC_PW0)); + rt_kprintf("LCDC_CNUM0:(0x%08x)\t0x%08x\n",LCDC_CNUM0, slcd_reg_read(LCDC_CNUM0)); + rt_kprintf("LCDC_DESSIZE0:(0x%08x)\t0x%08x\n",LCDC_DESSIZE0, slcd_reg_read(LCDC_DESSIZE0)); + rt_kprintf("==================================\n"); + rt_kprintf("LCDC_PCFG:(0x%08x)\t0x%08x\n", LCDC_PCFG,slcd_reg_read(LCDC_PCFG)); + rt_kprintf("==================================\n"); + rt_kprintf("SLCDC_CFG:(0x%08x) \t0x%08x\n", SLCDC_CFG,slcd_reg_read(SLCDC_CFG)); + rt_kprintf("SLCDC_CTRL:(0x%08x) \t0x%08x\n", SLCDC_CTRL,slcd_reg_read(SLCDC_CTRL)); + rt_kprintf("SLCDC_STATE:(0x%08x) \t0x%08x\n", SLCDC_STATE,slcd_reg_read(SLCDC_STATE)); + rt_kprintf("SLCDC_DATA:(0x%08x)\t0x%08x\n", SLCDC_DATA,slcd_reg_read(SLCDC_DATA)); + rt_kprintf("SLCDC_CFG_NEW:(0x%08x) \t0x%08x\n", SLCDC_CFG_NEW,slcd_reg_read(SLCDC_CFG_NEW)); + rt_kprintf("SLCDC_WTIME:(0x%08x) \t0x%08x\n", SLCDC_WTIME,slcd_reg_read(SLCDC_WTIME)); + rt_kprintf("SLCDC_TAS:(0x%08x) \t0x%08x\n", SLCDC_TAS,slcd_reg_read(SLCDC_TAS)); + rt_kprintf("==================================\n"); + rt_kprintf("reg:0x10000020 value=0x%08x (24bit) Clock Gate Register0\n", + *(uint32_t *)0xb0000020); + rt_kprintf("reg:0x100000e4 value=0x%08x (5bit_lcdc 21bit_lcdcs) Power Gate Register: \n", + *(uint32_t *)0xb00000e4); + rt_kprintf("reg:0x100000b8 value=0x%08x (10bit) SRAM Power Control Register0 \n", + *(uint32_t *)0xb00000b8); + rt_kprintf("reg:0x10000064 value=0x%08x Lcd pixclock \n", + *(uint32_t *)0xb0000064); + + return 0; +} +MSH_CMD_EXPORT(dump_slcd_regs,dump_slcd_regs); + diff --git a/bsp/x1000/drivers/touch/SConscript b/bsp/x1000/drivers/touch/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..4138c3cb1db706ebba49287065a897c0a48b1f91 --- /dev/null +++ b/bsp/x1000/drivers/touch/SConscript @@ -0,0 +1,22 @@ +from building import * + +cwd = GetCurrentDir() +CPPPATH = [cwd] + +ft_src = Split(""" +focaltech_ts.c +""") + +gt_src = Split(""" +gt9xx.c +""") + +src = () +if GetDepend('RT_USING_FT6x06'): + src = ft_src +if GetDepend('RT_USING_GT9XX'): + src = gt_src + +group = DefineGroup('drv_touch', src, depend = ['RT_USING_TOUCH'], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/x1000/drivers/touch/focaltech_ts.c b/bsp/x1000/drivers/touch/focaltech_ts.c new file mode 100644 index 0000000000000000000000000000000000000000..990c028261782eb514599fc0a123b835ffb51677 --- /dev/null +++ b/bsp/x1000/drivers/touch/focaltech_ts.c @@ -0,0 +1,617 @@ +/* + * File : focaltech_ts.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017-01-01 Urey first version + */ + +#include +#include + +#include +#include + +#include +#include + +#include + +#ifdef RT_USING_FT6x06 +#include "focaltech_ts.h" + +#ifndef BIT +#define BIT(n) (0x01u << (n)) +#endif + +static int fts_init_success = 0; + +#define TP_DEBUG 0 + +#if TP_DEBUG +#define TP_DBG(...) rt_kprintf("[TP]"),rt_kprintf(__VA_ARGS__) +#else +#define TP_DBG(...) +#endif + +/*ic update info*/ +static struct Upgrade_Info fts_updateinfo[] = +{ + {0x55,"FT5x06",TPD_MAX_POINTS_5,AUTO_CLB_NEED,50, 30, 0x79, 0x03, 10, 2000}, + {0x08,"FT5606",TPD_MAX_POINTS_5,AUTO_CLB_NEED,50, 10, 0x79, 0x06, 100, 2000}, + {0x0a,"FT5x16",TPD_MAX_POINTS_5,AUTO_CLB_NEED,50, 30, 0x79, 0x07, 10, 1500}, + {0x06,"FT6x06",TPD_MAX_POINTS_2,AUTO_CLB_NONEED,100, 30, 0x79, 0x08, 10, 2000}, + {0x36,"FT6x36",TPD_MAX_POINTS_2,AUTO_CLB_NONEED,10, 10, 0x79, 0x18, 10, 2000}, + {0x55,"FT5x06i",TPD_MAX_POINTS_5,AUTO_CLB_NEED,50, 30, 0x79, 0x03, 10, 2000}, + {0x14,"FT5336",TPD_MAX_POINTS_5,AUTO_CLB_NONEED,30, 30, 0x79, 0x11, 10, 2000}, + {0x13,"FT3316",TPD_MAX_POINTS_5,AUTO_CLB_NONEED,30, 30, 0x79, 0x11, 10, 2000}, + {0x12,"FT5436i",TPD_MAX_POINTS_5,AUTO_CLB_NONEED,30, 30, 0x79, 0x11, 10, 2000}, + {0x11,"FT5336i",TPD_MAX_POINTS_5,AUTO_CLB_NONEED,30, 30, 0x79, 0x11, 10, 2000}, + {0x54,"FT5x46",TPD_MAX_POINTS_5,AUTO_CLB_NONEED,2, 2, 0x54, 0x2c, 20, 2000}, + {0x58,"FT5x22",TPD_MAX_POINTS_5,AUTO_CLB_NONEED,2, 2, 0x58, 0x2c, 20, 2000}, + {0x59,"FT5x26",TPD_MAX_POINTS_5,AUTO_CLB_NONEED,30, 50, 0x79, 0x10, 1, 2000}, +}; + +static struct Upgrade_Info fts_updateinfo_curr; +static int touch_down_up_status = 0; + +#ifndef TOUCH_MAX_X +# define TOUCH_MAX_X 480 +#endif +#ifndef TOUCH_MAX_Y +# define TOUCH_MAX_Y 320 +#endif + +#define ANDROID_INPUT_PROTOCOL_B +#define FTS_RESET_PIN_NAME "ft3417-rst" +#define FTS_INT_PIN_NAME "ft3417-int" +static uint8_t buf_addr[2] = { 0 }; +static uint8_t buf_value[2] = { 0 }; + +/************************************************************************ +* Name: fts_i2c_Read +* Brief: i2c read +* Input: i2c info, write buf, write len, read buf, read len +* Output: get data in the 3rd buf +* Return: fail <0 +***********************************************************************/ +static int fts_i2c_Read(struct fts_ts_data *fts_ts, char *writebuf, int writelen, char *readbuf, int readlen) +{ + struct rt_i2c_msg msgs[2]; + int ret; + if (writelen > 0) + { + msgs[0].addr = fts_ts->addr; + msgs[0].flags = RT_I2C_WR; + msgs[0].len = writelen; + msgs[0].buf = writebuf; + + msgs[1].addr = fts_ts->addr; + msgs[1].flags = RT_I2C_RD; + msgs[1].len = readlen; + msgs[1].buf = readbuf; + ret = rt_i2c_transfer(fts_ts->i2c_bus, msgs, 2); + if (ret < 0) + { + TP_DBG("f%s: i2c read error. error code = %d \n", __func__, ret); + } + } + else + { + msgs[0].addr = fts_ts->addr; + msgs[0].flags = RT_I2C_RD; + msgs[0].len = readlen; + msgs[0].buf = readbuf; + + ret = rt_i2c_transfer(fts_ts->i2c_bus, msgs, 1); + if (ret < 0) + { + TP_DBG("%s:i2c read error. error code = %d \n", __func__, ret); + } + } + return ret; +} + +/************************************************************************ +* Name: fts_i2c_Write +* Brief: i2c write +* Input: i2c info, write buf, write len +* Output: no +* Return: fail <0 +***********************************************************************/ +static int fts_i2c_Write(struct fts_ts_data *fts_ts, char *writebuf, int writelen) +{ + struct rt_i2c_msg msgs[2]; + int ret; + msgs[0].addr = fts_ts->addr; + msgs[0].flags = RT_I2C_WR; + msgs[0].len = writelen; + msgs[0].buf = writebuf; + + ret = rt_i2c_transfer(fts_ts->i2c_bus, msgs, 1); + if (ret < 0) + { + TP_DBG("%s i2c write error.\n", __func__); + } + return ret; +} + +/************************************************************************ +* Name: fts_read_Touchdata +* Brief: report the point information +* Input: event info +* Output: get touch data in pinfo +* Return: success is zero +***********************************************************************/ +static unsigned int buf_count_add=0; +static unsigned int buf_count_neg=0; +//unsigned int buf_count_add1; +//unsigned int buf_count_neg1; +static uint8_t buf_touch_data[30 * POINT_READ_BUF] = { 0 }; //0xFF +static int fts_read_Touchdata(struct fts_ts_data *fts_ts) +{ + struct fts_event *event = &fts_ts->event; + uint8_t buf[POINT_READ_BUF] = { 0 }; //0xFF + int ret = -1; + int i = 0; + uint8_t pointid = FTS_MAX_ID; + //uint8_t pt00f=0; + ret = fts_i2c_Read(fts_ts, buf, 1, buf, POINT_READ_BUF); + if (ret < 0) + { + TP_DBG("%s read touchdata failed.\n", __func__); + return ret; + } + buf_count_add++; + //buf_count_add1=buf_count_add; + rt_memcpy(buf_touch_data + (((buf_count_add - 1) % 30) * POINT_READ_BUF), + buf, sizeof(uint8_t) * POINT_READ_BUF); + + + + + return 0; +} + +/************************************************************************ +* Name: fts_report_value +* Brief: report the point information +* Input: event info +* Output: no +* Return: success is 0(RT_EOK) +***********************************************************************/ +static struct rtgui_event_mouse emouse = {0}; +static int xx = 0, yy = 0, zz = 0; +static int fts_report_value(struct fts_ts_data *fts_ts) +{ + struct fts_event *event = &fts_ts->event; + int i,result; + int uppoint = 0; + int touchs = 0; + uint8_t pointid = FTS_MAX_ID; + uint8_t buf[POINT_READ_BUF] = { 0 };//0xFF + //struct rtgui_event_mouse emouse; + + static int touch_down = 0; + + buf_count_neg++; + //buf_count_neg1=buf_count_neg; + rt_memcpy(buf, + buf_touch_data + (((buf_count_neg - 1) % 30) * POINT_READ_BUF), + sizeof(uint8_t) * POINT_READ_BUF); + + + rt_memset(event, 0, sizeof(struct fts_event)); + event->touch_point_num = buf[FT_TOUCH_POINT_NUM] & 0x0F; + event->touch_point = 0; + for (i = 0; i < fts_updateinfo_curr.TPD_MAX_POINTS; i++) + { + pointid = (buf[FTS_TOUCH_ID_POS + FTS_TOUCH_STEP * i]) >> 4; + if (pointid >= FTS_MAX_ID) + break; + else + event->touch_point++; + +#if TOUCH_SWAP_XY + event->au16_y[i] = (((int16_t) buf[FTS_TOUCH_X_H_POS + FTS_TOUCH_STEP * i]) & 0x0F) << 8 + | (((int16_t) buf[FTS_TOUCH_X_L_POS + FTS_TOUCH_STEP * i])& 0xFF); + event->au16_x[i] = (((int16_t) buf[FTS_TOUCH_Y_H_POS + FTS_TOUCH_STEP * i]) & 0x0F) << 8 + | (((int16_t) buf[FTS_TOUCH_Y_L_POS + FTS_TOUCH_STEP * i]) & 0xFF); + +#else + event->au16_x[i] = (((int16_t) buf[FTS_TOUCH_X_H_POS + FTS_TOUCH_STEP * i]) & 0x0F) << 8 + | (((int16_t) buf[FTS_TOUCH_X_L_POS + FTS_TOUCH_STEP * i])& 0xFF); + event->au16_y[i] = (((int16_t) buf[FTS_TOUCH_Y_H_POS + FTS_TOUCH_STEP * i]) & 0x0F) << 8 + | (((int16_t) buf[FTS_TOUCH_Y_L_POS + FTS_TOUCH_STEP * i]) & 0xFF); + +#endif + +#if TOUCH_SWAP_Y + + event->au16_y[i] = TOUCH_MAX_Y - event->au16_y[i]; +#endif + TP_DBG("event->au16_x[%d] = %04x\n",i,event->au16_x[i]); + TP_DBG("event->au16_y[%d] = %04x\n",i,event->au16_y[i]); + + event->au8_touch_event[i] = buf[FTS_TOUCH_EVENT_POS + FTS_TOUCH_STEP * i] >> 6; + event->au8_finger_id[i] = (buf[FTS_TOUCH_ID_POS + FTS_TOUCH_STEP * i]) >> 4; + event->pressure[i] = (buf[FTS_TOUCH_XY_POS + FTS_TOUCH_STEP * i]);//cannot constant value + event->area[i] = (buf[FTS_TOUCH_MISC + FTS_TOUCH_STEP * i]) >> 4; + if((event->au8_touch_event[i]==0 || event->au8_touch_event[i]==2)&&((event->touch_point_num==0)||(event->pressure[i]==0 && event->area[i]==0 ))) + return 1; +#ifdef DEBUG + TP_DBG("id=%d event=%d x=%d y=%d pressure=%d area=%d\n", + event->au8_finger_id[i], + event->au8_touch_event[i], + event->au16_x[i], + event->au16_y[i], + event->pressure[i], + event->area[i]); +#endif + } + + /*protocol B*/ + for (i = 0; i < event->touch_point; i++) + { + if (event->au8_touch_event[i]== 0 || event->au8_touch_event[i] == 2) + { +// input_mt_report_slot_state(fts_ts->input_dev, MT_TOOL_FINGER, true); +// input_report_abs(fts_ts->input_dev, ABS_MT_PRESSURE, event->pressure[i]); +// input_report_abs(fts_ts->input_dev, ABS_MT_TOUCH_MAJOR, event->area[i]); +// input_report_abs(fts_ts->input_dev, ABS_MT_POSITION_X, event->au16_x[i]); +// input_report_abs(fts_ts->input_dev, ABS_MT_POSITION_Y, event->au16_y[i]); + touchs |= BIT(event->au8_finger_id[i]); + fts_ts->touchs |= BIT(event->au8_finger_id[i]); + + TP_DBG("finger true\n"); + TP_DBG("report_abs_X = %d, report_abs_Y = %d !\n", event->au16_x[i], event->au16_y[i]); + + + if(touch_down_up_status == 1) + { + //send mouse motion event; + emouse.parent.type = RTGUI_EVENT_MOUSE_MOTION; + emouse.x = event->au16_x[0] > 479 ? 479 : event->au16_x[0]; + emouse.y = event->au16_y[0]; + emouse.ts = rt_tick_get(); + + if (xx != 0 || yy != 0 || (xx == 0 && yy == 0)) + { + if (xx != emouse.x || emouse.y != yy) + { + rtgui_server_post_event(&emouse.parent, sizeof(emouse)); + TP_DBG("RTGUI_EVENT_MOUSE_MOTION x=%d,y=%d\n",event->au16_x[0],event->au16_y[0]); + zz = 0; + } + else + { + zz ++; + } + } + + xx = emouse.x; + yy = emouse.y; + + if (zz >= 10) + { + xx = 0; + yy = 0; + } + } + } + else + { + uppoint++; +// input_mt_report_slot_state(fts_ts->input_dev, MT_TOOL_FINGER, false); + fts_ts->touchs &= ~BIT(event->au8_finger_id[i]); + } + } + + if (0 == (fts_ts->touchs ^ touchs)) + { + for (i = 0; i < CFG_MAX_TOUCH_POINTS; i++) + { + if (BIT(i) & (fts_ts->touchs ^ touchs)) + { +// input_mt_slot(fts_ts->input_dev, i); +// input_mt_report_slot_state(fts_ts->input_dev, MT_TOOL_FINGER, false); + TP_DBG("finger false\n"); + } + } + } + fts_ts->touchs = touchs; + if(event->touch_point == uppoint && touch_down_up_status == 1) + { +// input_report_key(fts_ts->input_dev, BTN_TOUCH, 0); + touch_down_up_status = 0; + TP_DBG("touch up !\n"); + + /* Always send touch up event. */ + emouse.parent.type = RTGUI_EVENT_MOUSE_BUTTON; + emouse.button = RTGUI_MOUSE_BUTTON_LEFT | RTGUI_MOUSE_BUTTON_UP; + emouse.x = event->au16_x[0] > 479 ? 479 : event->au16_x[0]; + emouse.y = event->au16_y[0]; + emouse.ts = rt_tick_get(); + do + { + result = rtgui_server_post_event(&emouse.parent, sizeof(emouse)); + if (result != RT_EOK) + { + rt_thread_delay(RT_TICK_PER_SECOND / 10); + } + } + while (result != RT_EOK); + TP_DBG("RTGUI_MOUSE_BUTTON_UP x=%d,y=%d\n",event->au16_x[0],event->au16_y[0]); + } + else + { +// input_report_key(fts_ts->input_dev, BTN_TOUCH, event->touch_point > 0); + if (touch_down_up_status == 0) + { + touch_down_up_status = 1; + TP_DBG("touch down !\n"); + + //send mouse down event + emouse.parent.sender = RT_NULL; + emouse.wid = RT_NULL; + + emouse.parent.type = RTGUI_EVENT_MOUSE_BUTTON; + emouse.button = RTGUI_MOUSE_BUTTON_LEFT | RTGUI_MOUSE_BUTTON_DOWN; + emouse.x = event->au16_x[0] > 479 ? 479 : event->au16_x[0]; + emouse.y = event->au16_y[0]; + emouse.ts = rt_tick_get(); + emouse.id = emouse.ts; + + do + { + result = rtgui_server_post_event(&emouse.parent, sizeof(emouse)); + if (result != RT_EOK) + { + rt_thread_delay(RT_TICK_PER_SECOND / 10); + } + } + while (result != RT_EOK); + TP_DBG("RTGUI_MOUSE_BUTTON_DOWN x=%d,y=%d\n",event->au16_x[0],event->au16_y[0]); + } + } + + return 0; +} + + + + + +/************************************************************************ +* Name: fts_get_upgrade_array +* Brief: decide which ic +* Input: no +* Output: get ic info in fts_updateinfo_curr +* Return: no +***********************************************************************/ +static void fts_get_upgrade_array(struct fts_ts_data *fts_ts) +{ + uint8_t reg_ofs; + uint8_t chip_id; + uint32_t i; + + reg_ofs = FTS_REG_CHIP_ID; + fts_i2c_Read(fts_ts,®_ofs,1,&chip_id,1); + + TP_DBG("%s chip_id = %x\n", __func__, chip_id); + + for (i = 0; i < sizeof(fts_updateinfo) / sizeof(struct Upgrade_Info); i++) + { + if (chip_id == fts_updateinfo[i].CHIP_ID) + { + memcpy(&fts_updateinfo_curr, &fts_updateinfo[i], sizeof(struct Upgrade_Info)); + break; + } + } + + if(i >= sizeof(fts_updateinfo)/sizeof(struct Upgrade_Info)) + { + memcpy(&fts_updateinfo_curr, &fts_updateinfo[0], sizeof(struct Upgrade_Info)); + } +} + + + + +/************************************************************************ +* Name: fts_ts_probe +* Brief: driver entrance function for initial/power on/create channel +* Input: i2c info, device id +* Output: no +* Return: 0 +***********************************************************************/ +int fts_ts_probe(struct fts_ts_data *fts_ts,struct rt_i2c_bus_device *i2c_bus, const uint8_t addr) +{ + int err = 0; + uint8_t uc_reg_value; + uint8_t uc_reg_addr; + TP_DBG("FT device prob process Start !\n"); + + fts_ts->i2c_bus = i2c_bus; + fts_ts->addr = addr; + fts_ts->init_success = 0; + if (fts_ts->x_max > TOUCH_MAX_X) + fts_ts->x_max = TOUCH_MAX_X; + if (fts_ts->y_max > TOUCH_MAX_Y) + fts_ts->y_max = TOUCH_MAX_Y; + + fts_get_upgrade_array(fts_ts); + + /*get some register information */ + uc_reg_addr = FTS_REG_FW_VER; + err = fts_i2c_Read(fts_ts, &uc_reg_addr, 1, &uc_reg_value, 1); + if (err < 0) + { + fts_ts->init_success = 0; + fts_ts->fw_ver = 0xff; + } + else + { + fts_ts->init_success = 1; + TP_DBG("Firmware version = 0x%x\n", uc_reg_value); + fts_ts->fw_ver = uc_reg_value; + } + + uc_reg_addr = FTS_REG_POINT_RATE; + err = fts_i2c_Read(fts_ts, &uc_reg_addr, 1, &uc_reg_value, 1); + if (err < 0) + fts_ts->init_success = 0; + else + { + fts_ts->init_success = 1; + TP_DBG("report rate is %dHz.\n", uc_reg_value * 10); + } + + uc_reg_addr = FTS_REG_THGROUP; + err = fts_i2c_Read(fts_ts, &uc_reg_addr, 1, &uc_reg_value, 1); + if (err < 0) + fts_ts->init_success = 0; + else + { + fts_ts->init_success = 1; + TP_DBG("touch threshold is %d.\n", uc_reg_value * 4); + } + + uc_reg_addr = FTS_REG_VENDOR_ID; + err = fts_i2c_Read(fts_ts, &uc_reg_addr, 1, &uc_reg_value, 1); + if (err < 0) + fts_ts->init_success = 0; + else + { + fts_ts->init_success = 1; + TP_DBG("VENDOR ID = 0x%x\n", uc_reg_value); + } + + if (fts_ts->init_success == 1) + fts_init_success = 1; + return 0; +} + +/************************************************************************ +* Name: fts_ts_interrupt +* Brief: the focaltech device will signal the host about TRIGGER_FALLING, and processed when the interrupt is asserted. +* Input: irq, device id +* Output: no +* Return: irq handle +***********************************************************************/ +static void fts_ts_interrupt(struct fts_ts_data *fts_ts) +{ + rt_sem_release(&fts_ts->sem); + return ; +} + + +static void thread_fts_ts_service(void *param) +{ + struct fts_ts_data *fts_ts = (struct fts_ts_data *)param; + int ret = 0; + + while(rt_sem_take(&fts_ts->sem,RT_WAITING_FOREVER) == RT_EOK) + { +#ifdef FTS_GESTRUE + i2c_smbus_read_i2c_block_data(fts_ts->client, 0xd0, 1, &state); + /*TP_DBG("tpd fts_read_Gestruedata state=%d\n", state);*/ + if (state == 1) + { + fts_read_Gestruedata(fts_ts); + rt_hw_interrupt_umask(fts_ts->irq); + /*continue;*/ + } + else + { +#endif + //disable_irq_nosync(fts_ts->irq); + ret = fts_read_Touchdata(fts_ts); + if (ret == 0) + fts_report_value(fts_ts); + rt_thread_delay(RT_TICK_PER_SECOND / 30); +#ifdef FTS_GESTRUE + } +#endif + } +} + +static struct fts_ts_data g_fts_ts = +{ + .addr = 0, + .fw_ver = 0, //firmware version + .x_min = 0, + .x_max = 480, + .y_min = 0, + .y_max = 320, + .touchs = 0, + + .init_success = 0, +}; + +int rt_hw_touch_init(void) +{ + struct rt_i2c_bus_device *i2c_bus; +#define TP_INT_PORT GPIO_PORT_C +#define TP_INT_PIN GPIO_Pin_25 + /* init IO */ + gpio_direction_input(TP_INT_PORT,TP_INT_PIN); + gpio_enable_pull(TP_INT_PORT,TP_INT_PIN); + + /* register irq */ + gpio_mask_irq(TP_INT_PORT,TP_INT_PIN); + gpio_set_func(TP_INT_PORT,TP_INT_PIN,GPIO_INPUT_PULL | GPIO_INT_FE); + gpio_set_irq_callback(TP_INT_PORT,TP_INT_PIN,fts_ts_interrupt, (void*)&g_fts_ts); + + /* try to probe device */ + i2c_bus = rt_i2c_bus_device_find("i2c0"); + if (i2c_bus == RT_NULL) + { + rt_kprintf("[TP]:can't find the i2c bus:%s\n", "i2c0"); + return -RT_EIO; + } + + fts_ts_probe(&g_fts_ts,i2c_bus,FTS_SLAVE_ADDR); + if(g_fts_ts.init_success == 1) + { + rt_thread_t tid; + + /* init semaphore wakeup thread... */ + rt_sem_init(&g_fts_ts.sem,"tp_sem",0,RT_IPC_FLAG_FIFO); + + /* create thread for fts device */ + tid = rt_thread_create("tp_srv", + thread_fts_ts_service, (void *) &g_fts_ts, + 2048, + RT_TOUCH_THREAD_PRIORITY, + 10); + if(tid != RT_NULL) + rt_thread_startup(tid); + + /* enable interrupt */ + gpio_unmask_irq(TP_INT_PORT,TP_INT_PIN); + + return RT_EOK; + } + + return -RT_EIO; +} +INIT_DEVICE_EXPORT(rt_hw_touch_init); + +#endif /* RT_USING_FT6x06 */ diff --git a/bsp/x1000/drivers/touch/focaltech_ts.h b/bsp/x1000/drivers/touch/focaltech_ts.h new file mode 100644 index 0000000000000000000000000000000000000000..7a4622d911b8fad998233c5c4fea3b15b2224560 --- /dev/null +++ b/bsp/x1000/drivers/touch/focaltech_ts.h @@ -0,0 +1,145 @@ +/* + * File : focaltech_ts.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017-01-01 Urey first version + */ +#ifndef _FOCALTECH_TS_H_ +#define _FOCALTECH_TS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* -- dirver configure -- */ +#define FTS_SLAVE_ADDR (0x70 >> 1) +#define CFG_MAX_TOUCH_POINTS 10 +#define FTS_PRESS_MAX 0xFF +#define FTS_PRESS 0x08 +#define FTS_NAME "FTS" +#define FTS_INPUT_DEV_NAME "focal-touchscreen" +#define FTS_MAX_ID 0x0F +#define FTS_TOUCH_STEP 6 +#define FTS_TOUCH_X_H_POS 3 +#define FTS_TOUCH_X_L_POS 4 +#define FTS_TOUCH_Y_H_POS 5 +#define FTS_TOUCH_Y_L_POS 6 +#define FTS_TOUCH_XY_POS 7 +#define FTS_TOUCH_MISC 8 +#define FTS_TOUCH_EVENT_POS 3 +#define FTS_TOUCH_ID_POS 5 +#define FT_TOUCH_POINT_NUM 2 +#define POINT_READ_BUF (3 + FTS_TOUCH_STEP * CFG_MAX_TOUCH_POINTS) + +/*register address*/ +#define FTS_REG_CHIP_ID 0xA3 //chip ID +#define FTS_REG_FW_VER 0xA6 +#define FTS_REG_POINT_RATE 0x88 +#define FTS_REG_THGROUP 0x80 +#define FTS_REG_VENDOR_ID 0xA8 + +#define FTS_ENABLE_IRQ 1 +#define FTS_DISABLE_IRQ 0 +#define TPD_MAX_POINTS_2 2 +#define TPD_MAX_POINTS_5 5 +#define TPD_MAXPOINTS_10 10 +#define AUTO_CLB_NEED 1 +#define AUTO_CLB_NONEED 0 + +#define TOUCH_SWAP_XY 1 +#define TOUCH_SWAP_X 0 +#define TOUCH_SWAP_Y 1 + +struct Upgrade_Info +{ + uint8_t CHIP_ID; + uint8_t FTS_NAME_INFO[20]; + uint8_t TPD_MAX_POINTS; + uint8_t AUTO_CLB; + uint16_t delay_aa; /*delay of write FTS_UPGRADE_AA */ + uint16_t delay_55; /*delay of write FTS_UPGRADE_55 */ + uint8_t upgrade_id_1; /*upgrade id 1 */ + uint8_t upgrade_id_2; /*upgrade id 2 */ + uint16_t delay_readid; /*delay of read id */ + uint16_t delay_earse_flash; /*delay of earse flash*/ +}; + +/* The platform data for the Focaltech focaltech touchscreen driver */ +struct fts_platform_data +{ + uint32_t gpio_irq; /* IRQ port*/ + uint32_t irq_cfg; + uint32_t gpio_wakeup; /* Wakeup support*/ + uint32_t wakeup_cfg; + uint32_t gpio_reset; /* Reset support*/ + uint32_t reset_cfg; + int screen_max_x; + int screen_max_y; + int pressure_max; +}; + +struct fts_event +{ + uint16_t au16_x[CFG_MAX_TOUCH_POINTS]; /*x coordinate */ + uint16_t au16_y[CFG_MAX_TOUCH_POINTS]; /*y coordinate */ + uint8_t au8_touch_event[CFG_MAX_TOUCH_POINTS]; /*touch event:0 -- down; 1-- contact; 2 -- contact */ + uint8_t au8_finger_id[CFG_MAX_TOUCH_POINTS]; /*touch ID */ + uint8_t au8_finger_weight[CFG_MAX_TOUCH_POINTS]; /*touch weight */ + uint8_t pressure[CFG_MAX_TOUCH_POINTS]; + uint8_t area[CFG_MAX_TOUCH_POINTS]; + uint8_t touch_point; + uint8_t touch_point_num; +}; + +struct focal_i2c_platform_data +{ + uint16_t version; + int abs_x_min; + int abs_x_max; + int abs_y_min; + int abs_y_max; + int intr_gpio; + int rst_gpio; +}; + +struct fts_ts_data +{ + uint8_t addr; + uint8_t fw_ver; //firmware version + uint32_t x_min,x_max; + uint32_t y_min,y_max; + uint32_t init_success; + struct fts_event event; + + struct rt_i2c_bus_device *i2c_bus; + struct rt_semaphore sem; + int touchs; +}; + +void fts_ts_interrupt_cb(struct fts_ts_data *fts_ts); +int fts_ts_probe(struct fts_ts_data *fts_ts,struct rt_i2c_bus_device *i2c_bus, const uint8_t addr); + +#ifdef __cplusplus +} +#endif + +#endif /* _FOCALTECH_TS_H_ */ diff --git a/bsp/x1000/drivers/touch/gt9xx.c b/bsp/x1000/drivers/touch/gt9xx.c new file mode 100644 index 0000000000000000000000000000000000000000..505173e129b029637434068fea2901b8c8495c8a --- /dev/null +++ b/bsp/x1000/drivers/touch/gt9xx.c @@ -0,0 +1,1749 @@ +/* + * File : gt9xx.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017-01-01 Urey first version + */ + +#include +#include +#include + +#include +#include +#include "gt9xx.h" +#include "gt9xx_cfg.h" +#include "gt9xx_firmware.h" + +#include +#include + +#include +#include +#include + +#ifdef RT_USING_GT9XX + +static int tpd_flag = 0; +int tpd_halt = 0; + +#ifdef TPD_HAVE_BUTTON +static int tpd_keys_local[TPD_KEY_COUNT] = TPD_KEYS; +static int tpd_keys_dim_local[TPD_KEY_COUNT][4] = TPD_KEYS_DIM; +#endif + +#if GTP_GESTURE_WAKEUP +typedef enum +{ + DOZE_DISABLED = 0, + DOZE_ENABLED = 1, + DOZE_WAKEUP = 2, +}DOZE_T; +static DOZE_T doze_status = DOZE_DISABLED; +static int8_t gtp_enter_doze(struct rt_i2c_bus_device *client); +#endif + +#if GTP_HAVE_TOUCH_KEY +const uint16_t touch_key_array[] = GTP_KEY_TAB; +#define GTP_MAX_KEY_NUM ( sizeof( touch_key_array )/sizeof( touch_key_array[0] ) ) +#endif + +#if (defined(TPD_WARP_START) && defined(TPD_WARP_END)) +static int tpd_wb_start_local[TPD_WARP_CNT] = TPD_WARP_START; +static int tpd_wb_end_local[TPD_WARP_CNT] = TPD_WARP_END; +#endif + +#if (defined(TPD_HAVE_CALIBRATION) && !defined(TPD_CUSTOM_CALIBRATION)) +static int tpd_calmat_local[8] = TPD_CALIBRATION_MATRIX; +static int tpd_def_calmat_local[8] = TPD_CALIBRATION_MATRIX; +#endif + +static rt_mailbox_t gt9xx_mb; + +int gtp_send_cfg(struct rt_i2c_bus_device *client); +void gtp_reset_guitar(struct rt_i2c_bus_device *client, int ms); + + +static uint8_t config[GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH] + = {GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff}; + +#pragma pack(1) +typedef struct +{ + u16 pid; //product id // + u16 vid; //version id // +} st_tpd_info; +#pragma pack() + +st_tpd_info tpd_info; +u8 int_type = 0; +u32 abs_x_max = 0; +u32 abs_y_max = 0; +u8 gtp_rawdiff_mode = 0; +u8 cfg_len = 0; +u8 pnl_init_error = 0; + + + +/* proc file system */ +s32 i2c_read_bytes(struct rt_i2c_bus_device *i2c, u16 addr, u8 *rxbuf, int len) +{ + struct rt_i2c_msg msgs[2]; + u8 buffer[MAX_TRANSACTION_LENGTH]; + u8 retry; + u16 left = len; + u16 offset = 0; + + msgs[0].addr = GT910_IIC_ADDR; + msgs[0].flags = RT_I2C_WR; + msgs[0].buf = &buffer[0]; + msgs[0].len = 2; + + msgs[1].addr = GT910_IIC_ADDR; + msgs[1].flags = RT_I2C_RD; + msgs[1].buf = rxbuf; + msgs[1].len = len; + + while(left > 0) + { + buffer[0] = (addr >> 8) & 0xFF; + buffer[1] = (addr >> 0) & 0xFF; + + msgs[1].buf = &rxbuf[offset]; + + if (left > MAX_TRANSACTION_LENGTH) + { + msgs[1].len = MAX_TRANSACTION_LENGTH; + left -= MAX_TRANSACTION_LENGTH; + offset += MAX_TRANSACTION_LENGTH; + } + else + { + msgs[1].len = left; + left = 0; + } + + retry = 0; + + while (rt_i2c_transfer(i2c, &msgs[0], 2) != 2) + { + retry++; + + if (retry == 5) + { + GTP_ERROR("I2C read 0x%X length=%d failed\n", addr + offset, len); + return -1; + } + } + } + + return 0; +} +s32 i2c_write_bytes(struct rt_i2c_bus_device *i2c, u16 addr, u8 *txbuf, int len) +{ + struct rt_i2c_msg msgs[1]; + u8 buffer[MAX_TRANSACTION_LENGTH]; + u16 left = len; + u16 offset = 0; + u8 retry = 0; + + msgs[0].addr = GT910_IIC_ADDR; + msgs[0].flags = RT_I2C_WR; + msgs[0].buf = &buffer[0]; + msgs[0].len = 2; + + GTP_DEBUG("i2c_write_bytes to device %02X address %04X len %d\n", GT910_IIC_ADDR, addr, len); + while (left > 0) + { + retry = 0; + + buffer[0] = ((addr + offset) >> 8) & 0xFF; + buffer[1] = (addr + offset) & 0xFF; + + if (left > MAX_I2C_TRANSFER_SIZE) + { + memcpy(&buffer[GTP_ADDR_LENGTH], &txbuf[offset], MAX_I2C_TRANSFER_SIZE); + msgs[0].len = MAX_TRANSACTION_LENGTH; + left -= MAX_I2C_TRANSFER_SIZE; + offset += MAX_I2C_TRANSFER_SIZE; + } + else + { + memcpy(&buffer[GTP_ADDR_LENGTH], &txbuf[offset], left); + msgs[0].len = left + GTP_ADDR_LENGTH; + left = 0; + } + + //GTP_DEBUG("byte left %d offset %d\n", left, offset); + while (rt_i2c_transfer(i2c, &msgs[0], 1) != 1) + { + retry++; + + //if (retry == 20) + if (retry == 5) + { + GTP_ERROR("I2C write 0x%X%X length=%d failed\n", buffer[0], buffer[1], len); + return -1; + } + } + } + + return 0; +} + +s32 gtp_i2c_write(struct rt_i2c_bus_device *i2c, u8 *buf, s32 len) +{ + s32 ret = -1; + u16 addr = (buf[0] << 8) + buf[1]; + + ret = i2c_write_bytes(i2c, addr, &buf[2], len - 2); + if (!ret) + { + return 1; + } + else + { + #if GTP_GESTURE_WAKEUP + if (DOZE_ENABLED == doze_status) + { + return ret; + } + #endif + #if GTP_COMPATIBLE_MODE + if (CHIP_TYPE_GT9F == gtp_chip_type) + { + gtp_recovery_reset(client); + } + else + #endif + { + gtp_reset_guitar(i2c, 20); + } + return ret; + } +} + +s32 gtp_i2c_read(struct rt_i2c_bus_device *i2c, u8 *buf, s32 len) +{ + s32 ret = -1; + u16 addr = (buf[0] << 8) + buf[1]; + + ret = i2c_read_bytes(i2c, addr, &buf[2], len - 2); + + if (!ret) + { + return 2; + } + else + { +#if GTP_GESTURE_WAKEUP + if (DOZE_ENABLED == doze_status) + { + return ret; + } +#endif +#if GTP_COMPATIBLE_MODE + if (CHIP_TYPE_GT9F == gtp_chip_type) + { + gtp_recovery_reset(client); + } + else +#endif + { + gtp_reset_guitar(i2c, 20); + } + return ret; + } +} + +s32 gtp_i2c_read_dbl_check(struct rt_i2c_bus_device *i2c, u16 addr, u8 *rxbuf, int len) +{ + u8 buf[16] = {0}; + u8 confirm_buf[16] = {0}; + u8 retry = 0; + + while (retry++ < 3) + { + memset(buf, 0xAA, 16); + buf[0] = (u8)(addr >> 8); + buf[1] = (u8)(addr & 0xFF); + gtp_i2c_read(i2c, buf, len + 2); + + memset(confirm_buf, 0xAB, 16); + confirm_buf[0] = (u8)(addr >> 8); + confirm_buf[1] = (u8)(addr & 0xFF); + gtp_i2c_read(i2c, confirm_buf, len + 2); + + if (!memcmp(buf, confirm_buf, len+2)) + { + memcpy(rxbuf, confirm_buf+2, len); + return SUCCESS; + } + } + GTP_ERROR("i2c read 0x%04X, %d bytes, double check failed!", addr, len); + return FAIL; +} + +s32 gtp_send_cfg(struct rt_i2c_bus_device *i2c) +{ + s32 ret = 1; + +#if GTP_DRIVER_SEND_CFG + s32 retry = 0; + + if (pnl_init_error) + { + GTP_INFO("Error occurred in init_panel, no config sent!"); + return 0; + } + + GTP_INFO("Driver Send Config"); + for (retry = 0; retry < 5; retry++) + { + ret = gtp_i2c_write(i2c, config, GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH); + + if (ret > 0) + { + break; + } + } +#endif + return ret; +} + +#if GTP_CHARGER_SWITCH +static int gtp_send_chr_cfg(struct rt_i2c_bus_device *i2c) +{ + s32 ret = 1; +#if GTP_DRIVER_SEND_CFG + s32 retry = 0; + + if (pnl_init_error) { + GTP_INFO("Error occurred in init_panel, no config sent!"); + return 0; + } + + GTP_INFO("Driver Send Config"); + for (retry = 0; retry < 5; retry++) { + ret = gtp_i2c_write(i2c, gtp_charger_config, GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH); + if (ret > 0) { + break; + } + } +#endif + return ret; +} +#endif + + +s32 gtp_read_version(struct rt_i2c_bus_device *i2c, u16 *version) +{ + s32 ret = -1; + s32 i; + u8 buf[8] = {GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff}; + + GTP_DEBUG_FUNC(); + + ret = gtp_i2c_read(i2c, buf, sizeof(buf)); + + if (ret < 0) + { + GTP_ERROR("GTP read version failed"); + return ret; + } + + if (version) + { + *version = (buf[7] << 8) | buf[6]; + } + + tpd_info.vid = *version; + tpd_info.pid = 0x00; + + for (i = 0; i < 4; i++) + { + if (buf[i + 2] < 0x30)break; + + tpd_info.pid |= ((buf[i + 2] - 0x30) << ((3 - i) * 4)); + } + + if (buf[5] == 0x00) + { + GTP_INFO("IC VERSION: %c%c%c_%02x%02x", + buf[2], buf[3], buf[4], buf[7], buf[6]); + } + else + { + GTP_INFO("IC VERSION:%c%c%c%c_%02x%02x", + buf[2], buf[3], buf[4], buf[5], buf[7], buf[6]); + } + return ret; +} + +static s32 gtp_init_panel(struct rt_i2c_bus_device *i2c) +{ + s32 ret = 0; + +#if GTP_DRIVER_SEND_CFG + s32 i; + u8 check_sum = 0; + u8 opr_buf[16]; + u8 sensor_id = 0; + u8 drv_cfg_version; + u8 flash_cfg_version; + + u8 cfg_info_group0[] = CTP_CFG_GROUP0; + u8 cfg_info_group1[] = CTP_CFG_GROUP1; + u8 cfg_info_group2[] = CTP_CFG_GROUP2; + u8 cfg_info_group3[] = CTP_CFG_GROUP3; + u8 cfg_info_group4[] = CTP_CFG_GROUP4; + u8 cfg_info_group5[] = CTP_CFG_GROUP5; + u8 *send_cfg_buf[] = { + cfg_info_group0, + cfg_info_group1, + cfg_info_group2, + cfg_info_group3, + cfg_info_group4, + cfg_info_group5 + }; + u8 cfg_info_len[] = { + CFG_GROUP_LEN(cfg_info_group0), + CFG_GROUP_LEN(cfg_info_group1), + CFG_GROUP_LEN(cfg_info_group2), + CFG_GROUP_LEN(cfg_info_group3), + CFG_GROUP_LEN(cfg_info_group4), + CFG_GROUP_LEN(cfg_info_group5) + }; +#if GTP_CHARGER_SWITCH + const u8 cfg_grp0_charger[] = GTP_CFG_GROUP0_CHARGER; + const u8 cfg_grp1_charger[] = GTP_CFG_GROUP1_CHARGER; + const u8 cfg_grp2_charger[] = GTP_CFG_GROUP2_CHARGER; + const u8 cfg_grp3_charger[] = GTP_CFG_GROUP3_CHARGER; + const u8 cfg_grp4_charger[] = GTP_CFG_GROUP4_CHARGER; + const u8 cfg_grp5_charger[] = GTP_CFG_GROUP5_CHARGER; + const u8 *cfgs_charger[] = { + cfg_grp0_charger, + cfg_grp1_charger, + cfg_grp2_charger, + cfg_grp3_charger, + cfg_grp4_charger, + cfg_grp5_charger + }; + u8 cfg_lens_charger[] = { + CFG_GROUP_LEN(cfg_grp0_charger), + CFG_GROUP_LEN(cfg_grp1_charger), + CFG_GROUP_LEN(cfg_grp2_charger), + CFG_GROUP_LEN(cfg_grp3_charger), + CFG_GROUP_LEN(cfg_grp4_charger), + CFG_GROUP_LEN(cfg_grp5_charger) + }; +#endif + + GTP_DEBUG("Config Groups\' Lengths: %d, %d, %d, %d, %d, %d", + cfg_info_len[0], + cfg_info_len[1], + cfg_info_len[2], + cfg_info_len[3], + cfg_info_len[4], + cfg_info_len[5] ); + + if ((!cfg_info_len[1]) && (!cfg_info_len[2]) && (!cfg_info_len[3]) && (!cfg_info_len[4]) && (!cfg_info_len[5])) + { + sensor_id = 0; + } + else + { +#if GTP_COMPATIBLE_MODE + if (CHIP_TYPE_GT9F == gtp_chip_type) + { + rt_thread_delay(rt_tick_from_millisecond(50)); + } +#endif + ret = gtp_i2c_read_dbl_check(i2c, GTP_REG_SENSOR_ID, &sensor_id, 1); + if (SUCCESS == ret) + { + if (sensor_id >= 0x06) + { + GTP_ERROR("Invalid sensor_id(0x%02X), No Config Sent!", sensor_id); + pnl_init_error = 1; + return -1; + } + } + else + { + GTP_ERROR("Failed to get sensor_id, No config sent!"); + pnl_init_error = 1; + return -1; + } + GTP_INFO("Sensor_ID: %d", sensor_id); + } + + cfg_len = cfg_info_len[sensor_id]; + + GTP_INFO("CTP_CONFIG_GROUP%d used, config length: %d", sensor_id, cfg_len); + + if (cfg_len < GTP_CONFIG_MIN_LENGTH) + { + GTP_ERROR("CTP_CONFIG_GROUP%d is INVALID CONFIG GROUP! NO Config Sent! You need to check you header file CFG_GROUP section!", + sensor_id); + pnl_init_error = 1; + return -1; + } + +#if GTP_COMPATIBLE_MODE + if (CHIP_TYPE_GT9F != gtp_chip_type) +#endif + { + ret = gtp_i2c_read_dbl_check(i2c, GTP_REG_CONFIG_DATA, &opr_buf[0], 1); + if (ret == SUCCESS) + { + GTP_DEBUG("CFG_CONFIG_GROUP%d Config Version: %d, 0x%02X; IC Config Version: %d, 0x%02X", + sensor_id, + send_cfg_buf[sensor_id][0], + send_cfg_buf[sensor_id][0], + opr_buf[0], + opr_buf[0]); + + flash_cfg_version = opr_buf[0]; + drv_cfg_version = send_cfg_buf[sensor_id][0]; // backup config version + + if (flash_cfg_version < 90 && flash_cfg_version > drv_cfg_version) + { + send_cfg_buf[sensor_id][0] = 0x00; + } + } + else + { + GTP_ERROR("Failed to get ic config version!No config sent!"); + return -1; + } + } + memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH); + memcpy(&config[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id], cfg_len); + +#if GTP_CUSTOM_CFG + config[RESOLUTION_LOC] = (u8)GTP_MAX_WIDTH; + config[RESOLUTION_LOC + 1] = (u8)(GTP_MAX_WIDTH>>8); + config[RESOLUTION_LOC + 2] = (u8)GTP_MAX_HEIGHT; + config[RESOLUTION_LOC + 3] = (u8)(GTP_MAX_HEIGHT>>8); + + if (GTP_INT_TRIGGER == 0) //RISING + { + config[TRIGGER_LOC] &= 0xfe; + } + else if (GTP_INT_TRIGGER == 1) //FALLING + { + config[TRIGGER_LOC] |= 0x01; + } +#endif // GTP_CUSTOM_CFG + + check_sum = 0; + for (i = GTP_ADDR_LENGTH; i < cfg_len; i++) + { + check_sum += config[i]; + } + config[cfg_len] = (~check_sum) + 1; + +#if GTP_CHARGER_SWITCH + GTP_DEBUG("Charger Config Groups Length: %d, %d, %d, %d, %d, %d", + cfg_lens_charger[0], cfg_lens_charger[1], + cfg_lens_charger[2], cfg_lens_charger[3], + cfg_lens_charger[4], cfg_lens_charger[5]); + + memset(>p_charger_config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH); + if (cfg_lens_charger[sensor_id] == cfg_len) + memcpy(>p_charger_config[GTP_ADDR_LENGTH], cfgs_charger[sensor_id], cfg_len); + +#if GTP_CUSTOM_CFG + gtp_charger_config[RESOLUTION_LOC] = (u8) GTP_MAX_WIDTH; + gtp_charger_config[RESOLUTION_LOC + 1] = (u8) (GTP_MAX_WIDTH >> 8); + gtp_charger_config[RESOLUTION_LOC + 2] = (u8) GTP_MAX_HEIGHT; + gtp_charger_config[RESOLUTION_LOC + 3] = (u8) (GTP_MAX_HEIGHT >> 8); + + if (GTP_INT_TRIGGER == 0) /* RISING */ + gtp_charger_config[TRIGGER_LOC] &= 0xfe; + else if (GTP_INT_TRIGGER == 1) /* FALLING */ + gtp_charger_config[TRIGGER_LOC] |= 0x01; +#endif /* END GTP_CUSTOM_CFG */ + if (cfg_lens_charger[sensor_id] != cfg_len) + memset(>p_charger_config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH); + + check_sum = 0; + for (i = GTP_ADDR_LENGTH; i < cfg_len; i++) + { + check_sum += gtp_charger_config[i]; + } + gtp_charger_config[cfg_len] = (~check_sum) + 1; + +#endif /* END GTP_CHARGER_SWITCH */ + +#else // DRIVER NOT SEND CONFIG + cfg_len = GTP_CONFIG_MAX_LENGTH; + ret = gtp_i2c_read(client, config, cfg_len + GTP_ADDR_LENGTH); + if (ret < 0) + { + GTP_ERROR("Read Config Failed, Using DEFAULT Resolution & INT Trigger!"); + abs_x_max = GTP_MAX_WIDTH; + abs_y_max = GTP_MAX_HEIGHT; + int_type = GTP_INT_TRIGGER; + } +#endif // GTP_DRIVER_SEND_CFG + + GTP_DEBUG_FUNC(); + if ((abs_x_max == 0) && (abs_y_max == 0)) + { + abs_x_max = (config[RESOLUTION_LOC + 1] << 8) + config[RESOLUTION_LOC]; + abs_y_max = (config[RESOLUTION_LOC + 3] << 8) + config[RESOLUTION_LOC + 2]; + int_type = (config[TRIGGER_LOC]) & 0x03; + } + +#if GTP_COMPATIBLE_MODE + if (CHIP_TYPE_GT9F == gtp_chip_type) + { + u8 have_key = 0; + if (is_950) + { + driver_num = config[GTP_REG_MATRIX_DRVNUM - GTP_REG_CONFIG_DATA + 2]; + sensor_num = config[GTP_REG_MATRIX_SENNUM - GTP_REG_CONFIG_DATA + 2]; + } + else + { + driver_num = (config[CFG_LOC_DRVA_NUM]&0x1F) + (config[CFG_LOC_DRVB_NUM]&0x1F); + sensor_num = (config[CFG_LOC_SENS_NUM]&0x0F) + ((config[CFG_LOC_SENS_NUM]>>4)&0x0F); + } + + have_key = config[GTP_REG_HAVE_KEY - GTP_REG_CONFIG_DATA + 2] & 0x01; // have key or not + if (1 == have_key) + { + driver_num--; + } + + GTP_INFO("Driver * Sensor: %d * %d(Key: %d), X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x", + driver_num, sensor_num, have_key, abs_x_max,abs_y_max,int_type); + } + else +#endif + { +#if GTP_DRIVER_SEND_CFG + ret = gtp_send_cfg(i2c); + if (ret < 0) + { + GTP_ERROR("Send config error."); + } +#if GTP_COMPATIBLE_MODE + if (CHIP_TYPE_GT9F != gtp_chip_type) +#endif + { + /* for resume to send config */ + if (flash_cfg_version < 90 && flash_cfg_version > drv_cfg_version) + { + config[GTP_ADDR_LENGTH] = drv_cfg_version; + check_sum = 0; + for (i = GTP_ADDR_LENGTH; i < cfg_len; i++) + { + check_sum += config[i]; + } + config[cfg_len] = (~check_sum) + 1; + } + } +#endif + GTP_INFO("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x", abs_x_max, abs_y_max, int_type); + } + + rt_thread_delay(RT_TICK_PER_SECOND / 20); + return 0; +} + +static s8 gtp_i2c_test(struct rt_i2c_bus_device *i2c) +{ + u8 retry = 0; + s8 ret = -1; + u32 hw_info = 0; + + GTP_DEBUG_FUNC(); + + while (retry++ < 5) + { + ret = i2c_read_bytes(i2c, GTP_REG_HW_INFO, (u8 *)&hw_info, sizeof(hw_info)); + + if ((!ret) && (hw_info == 0x00900600)) //20121212 + { + return ret; + } + + GTP_ERROR("GTP_REG_HW_INFO : %08X", hw_info); + GTP_ERROR("GTP i2c test failed time %d.", retry); + rt_thread_delay(rt_tick_from_millisecond(10)); + } + + return -1; +} + + +void gtp_int_sync(s32 ms) +{ + gpio_direction_output(GTP_INT_PORT,GTP_INT_PIN,0); + rt_thread_delay(rt_tick_from_millisecond(ms)); + gpio_set_func(GTP_INT_PORT, GTP_INT_PIN, GPIO_INPUT | GPIO_INT_FE); +} + +void gtp_reset_guitar(struct rt_i2c_bus_device *i2c, s32 ms) +{ + GTP_INFO("GTP RESET!\n"); + + /* RESET skip */ +// GTP_GPIO_OUTPUT(GTP_RST_PORT, 0); +// rt_thread_delay(rt_tick_from_millisecond(ms)); +// GTP_GPIO_OUTPUT(GTP_INT_PORT, client->addr == 0x14); +// +// rt_thread_delay(rt_tick_from_millisecond(2)); +// GTP_GPIO_OUTPUT(GTP_RST_PORT, 1); + + +#if GTP_COMPATIBLE_MODE + if (CHIP_TYPE_GT9F == gtp_chip_type) + { + return; + } +#endif + + gtp_int_sync(50); +} + +#if GTP_GESTURE_WAKEUP +static s8 gtp_enter_doze(struct rt_i2c_bus_device *i2c) +{ + s8 ret = -1; + s8 retry = 0; + u8 i2c_control_buf[3] = {(u8)(GTP_REG_SLEEP >> 8), (u8)GTP_REG_SLEEP, 8}; + + GTP_DEBUG_FUNC(); + + GTP_DEBUG("Entering gesture mode..."); + while(retry++ < 5) + { + i2c_control_buf[0] = 0x80; + i2c_control_buf[1] = 0x46; + ret = gtp_i2c_write(i2c, i2c_control_buf, 3); + if (ret < 0) + { + GTP_DEBUG("Failed to set gesture flag into 0x8046, %d", retry); + continue; + } + i2c_control_buf[0] = 0x80; + i2c_control_buf[1] = 0x40; + ret = gtp_i2c_write(i2c, i2c_control_buf, 3); + if (ret > 0) + { + doze_status = DOZE_ENABLED; + GTP_INFO("Gesture mode enabled."); + return ret; + } + rt_thread_delay(rt_tick_from_millisecond(10)); + } + GTP_ERROR("GTP send gesture cmd failed."); + return ret; +} + +#else +/******************************************************* +Function: + Eter sleep function. + +Input: + client:i2c_client. + +Output: + Executive outcomes.0--success,non-0--fail. +*******************************************************/ +static s8 gtp_enter_sleep(struct rt_i2c_bus_device *i2c) +{ +#if GTP_COMPATIBLE_MODE + if (CHIP_TYPE_GT9F == gtp_chip_type) + { + u8 i2c_status_buf[3] = {0x80, 0x44, 0x00}; + s32 ret = 0; + + ret = gtp_i2c_read(i2c, i2c_status_buf, 3); + if(ret <= 0) + { + GTP_ERROR("[gtp_enter_sleep]Read ref status reg error."); + } + + if (i2c_status_buf[2] & 0x80) + { + //Store bak ref + ret = gtp_bak_ref_proc(i2c, GTP_BAK_REF_STORE); + if(FAIL == ret) + { + GTP_ERROR("[gtp_enter_sleep]Store bak ref failed."); + } + } + } +#endif +#if GTP_POWER_CTRL_SLEEP + + GTP_GPIO_OUTPUT(GTP_RST_PORT, 0); + GTP_GPIO_OUTPUT(GTP_INT_PORT, 0); + rt_thread_delay(rt_tick_from_millisecond(10)); + +#ifdef MT6573 + mt_set_gpio_mode(GPIO_CTP_EN_PIN, GPIO_CTP_EN_PIN_M_GPIO); + mt_set_gpio_dir(GPIO_CTP_EN_PIN, GPIO_DIR_OUT); + mt_set_gpio_out(GPIO_CTP_EN_PIN, GPIO_OUT_ZERO); + rt_thread_delay(rt_tick_from_millisecond(30)); +#else // ( defined(MT6575) || defined(MT6577) || defined(MT6589) ) + + #ifdef TPD_POWER_SOURCE_1800 + hwPowerDown(TPD_POWER_SOURCE_1800, "TP"); + #endif + + #ifdef TPD_POWER_SOURCE_CUSTOM + hwPowerDown(TPD_POWER_SOURCE_CUSTOM, "TP"); + #else + hwPowerDown(MT65XX_POWER_LDO_VGP2, "TP"); + #endif +#endif + + GTP_INFO("GTP enter sleep by poweroff!"); + return 0; + +#else + { + s8 ret = -1; + s8 retry = 0; + u8 i2c_control_buf[3] = {(u8)(GTP_REG_SLEEP >> 8), (u8)GTP_REG_SLEEP, 5}; + + + GTP_GPIO_OUTPUT(GTP_INT_PORT, 0); + rt_thread_delay(rt_tick_from_millisecond(5)); + + while (retry++ < 5) + { + ret = gtp_i2c_write(i2c, i2c_control_buf, 3); + + if (ret > 0) + { + GTP_INFO("GTP enter sleep!"); + + return ret; + } + + rt_thread_delay(rt_tick_from_millisecond(10)); + } + + GTP_ERROR("GTP send sleep cmd failed."); + return ret; + } +#endif +} +#endif + +static s8 gtp_wakeup_sleep(struct rt_i2c_bus_device *i2c) +{ + u8 retry = 0; + s8 ret = -1; + + GTP_DEBUG("GTP wakeup begin."); + +#if (GTP_POWER_CTRL_SLEEP) + +#if GTP_COMPATIBLE_MODE + if (CHIP_TYPE_GT9F == gtp_chip_type) + { + force_reset_guitar(); + GTP_INFO("Esd recovery wakeup."); + return 0; + } +#endif + + while (retry++ < 5) + { + ret = tpd_power_on(client); + + if (ret < 0) + { + GTP_ERROR("I2C Power on ERROR!"); + continue; + } + GTP_INFO("Ic wakeup by poweron"); + return 0; + } +#else + +#if GTP_COMPATIBLE_MODE + if (CHIP_TYPE_GT9F == gtp_chip_type) + { + u8 opr_buf[2] = {0}; + + while (retry++ < 10) + { + GTP_GPIO_OUTPUT(GTP_INT_PORT, 1); + rt_thread_delay(rt_tick_from_millisecond(5)); + + ret = gtp_i2c_test(client); + + if (ret >= 0) + { + // Hold ss51 & dsp + opr_buf[0] = 0x0C; + ret = i2c_write_bytes(i2c, 0x4180, opr_buf, 1); + if (ret < 0) + { + GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry); + continue; + } + + // Confirm hold + opr_buf[0] = 0x00; + ret = i2c_read_bytes(i2c, 0x4180, opr_buf, 1); + if (ret < 0) + { + GTP_DEBUG("confirm ss51 & dsp hold, I2C error,retry:%d", retry); + continue; + } + if (0x0C != opr_buf[0]) + { + GTP_DEBUG("ss51 & dsp not hold, val: %d, retry: %d", opr_buf[0], retry); + continue; + } + GTP_DEBUG("ss51 & dsp has been hold"); + + ret = gtp_fw_startup(i2c); + if (FAIL == ret) + { + GTP_ERROR("[gtp_wakeup_sleep]Startup fw failed."); + continue; + } + GTP_INFO("flashless wakeup sleep success"); + return ret; + } + force_reset_guitar(); + retry = 0; + break; + } + if (retry >= 10) + { + GTP_ERROR("wakeup retry timeout, process esd reset"); + force_reset_guitar(); + } + GTP_ERROR("GTP wakeup sleep failed."); + return ret; + } +#endif + while (retry++ < 10) + { +#if GTP_GESTURE_WAKEUP + if (DOZE_WAKEUP != doze_status) + { + GTP_INFO("Powerkey wakeup."); + } + else + { + GTP_INFO("Gesture wakeup."); + } + doze_status = DOZE_DISABLED; + + gtp_reset_guitar(i2c, 20); +#else + + GTP_GPIO_OUTPUT(GTP_INT_PORT, 1); + rt_thread_delay(rt_tick_from_millisecond(5)); +#endif + + ret = gtp_i2c_test(i2c); + + if (ret >= 0) + { + GTP_INFO("GTP wakeup sleep."); +#if (!GTP_GESTURE_WAKEUP) + { + gtp_int_sync(25); +#if GTP_ESD_PROTECT + gtp_init_ext_watchdog(client); +#endif + } +#endif + + return ret; + } + gtp_reset_guitar(i2c, 20); + } +#endif + GTP_ERROR("GTP wakeup sleep failed."); + return ret; +} + +static struct rtgui_event_mouse emouse = {0}; +static int xx = 0, yy = 0, zz = 0; +static int touch_down_up_status; +static void tpd_down(s32 x, s32 y, s32 size, s32 id) +{ + int result; + + if ((!size) && (!id)) + { +// input_report_abs(tpd->dev, ABS_MT_PRESSURE, 100); +// input_report_abs(tpd->dev, ABS_MT_TOUCH_MAJOR, 100); + } + else + { +// input_report_abs(tpd->dev, ABS_MT_PRESSURE, size); +// input_report_abs(tpd->dev, ABS_MT_TOUCH_MAJOR, size); +// /* track id Start 0 */ +// input_report_abs(tpd->dev, ABS_MT_TRACKING_ID, id); + } + +// input_report_key(tpd->dev, BTN_TOUCH, 1); +// input_report_abs(tpd->dev, ABS_MT_POSITION_X, x); +// input_report_abs(tpd->dev, ABS_MT_POSITION_Y, y); +// input_mt_sync(tpd->dev); +// TPD_EM_PRINT(x, y, x, y, id, 1); + + x = x + y; + y = x - y; + x = x - y; + x = 479 - x; + + if(touch_down_up_status) + { + emouse.parent.type = RTGUI_EVENT_MOUSE_MOTION; + emouse.x = x; + emouse.y = y; + emouse.ts = rt_tick_get(); + + if (xx != 0 || yy != 0 || (xx == 0 && yy == 0)) + { + if (xx != emouse.x || emouse.y != yy) + { + rtgui_server_post_event(&emouse.parent, sizeof(emouse)); + zz = 0; + } + else + { + zz ++; + } + } + + xx = emouse.x; + yy = emouse.y; + + if (zz >= 10) + { + xx = 0; + yy = 0; + } + } + else + { + touch_down_up_status = 1; + + //send mouse down event + emouse.parent.sender = RT_NULL; + emouse.wid = RT_NULL; + + emouse.parent.type = RTGUI_EVENT_MOUSE_BUTTON; + emouse.button = RTGUI_MOUSE_BUTTON_LEFT | RTGUI_MOUSE_BUTTON_DOWN; + emouse.x = x; + emouse.y = y; + emouse.ts = rt_tick_get(); + emouse.id = emouse.ts; + + do + { + result = rtgui_server_post_event(&emouse.parent, sizeof(emouse)); + if (result != RT_EOK) + { + rt_thread_delay(RT_TICK_PER_SECOND / 10); + } + } + while (result != RT_EOK); + } + +} + +static void tpd_up(s32 x, s32 y, s32 id) +{ + int result; +// input_report_key(tpd->dev, BTN_TOUCH, 0); +// input_mt_sync(tpd->dev); +// TPD_EM_PRINT(x, y, x, y, id, 0); + +#if (defined(MT6575) || defined(MT6577)) + + if (FACTORY_BOOT == get_boot_mode() || RECOVERY_BOOT == get_boot_mode()) + { + tpd_button(x, y, 0); + } + +#endif + + touch_down_up_status = 0; + /* Always send touch up event. */ + emouse.parent.type = RTGUI_EVENT_MOUSE_BUTTON; + emouse.button = RTGUI_MOUSE_BUTTON_LEFT | RTGUI_MOUSE_BUTTON_UP; + emouse.x = xx; + emouse.y = yy; + emouse.ts = rt_tick_get(); + do + { + result = rtgui_server_post_event(&emouse.parent, sizeof(emouse)); + if (result != RT_EOK) + { + rt_thread_delay(RT_TICK_PER_SECOND / 10); + } + } + while (result != RT_EOK); +} + +static int tpd_power_on(struct rt_i2c_bus_device *client) +{ + int ret = 0; + int reset_count = 0; + +reset_proc: + GTP_GPIO_OUTPUT(GTP_RST_PORT, 0); + GTP_GPIO_OUTPUT(GTP_INT_PORT, 0); + rt_thread_delay(rt_tick_from_millisecond(10)); + + gtp_reset_guitar(client, 20); + +#if GTP_COMPATIBLE_MODE + gtp_get_chip_type(client); + + if (CHIP_TYPE_GT9F == gtp_chip_type) + { + ret = gup_fw_download_proc(NULL, GTP_FL_FW_BURN); + + if(FAIL == ret) + { + GTP_ERROR("[tpd_power_on]Download fw failed."); + if(reset_count++ < TPD_MAX_RESET_COUNT) + { + goto reset_proc; + } + else + { + return -1; + } + } + + ret = gtp_fw_startup(client); + if(FAIL == ret) + { + GTP_ERROR("[tpd_power_on]Startup fw failed."); + if(reset_count++ < TPD_MAX_RESET_COUNT) + { + goto reset_proc; + } + else + { + return -1; + } + } + } + else +#endif + { + ret = gtp_i2c_test(client); + + if (ret < 0) + { + GTP_ERROR("I2C communication ERROR!"); + + if (reset_count < TPD_MAX_RESET_COUNT) + { + reset_count++; + goto reset_proc; + } + } + } + return ret; +} + + +static int tpd_local_init(void) +{ +#if GTP_ESD_PROTECT + clk_tick_cnt = 2 * HZ; // HZ: clock ticks in 1 second generated by system + GTP_DEBUG("Clock ticks for an esd cycle: %d", clk_tick_cnt); + INIT_DELAYED_WORK(>p_esd_check_work, gtp_esd_check_func); + gtp_esd_check_workqueue = create_workqueue("gtp_esd_check"); + spin_lock_init(&esd_lock); // 2.6.39 & later + // esd_lock = SPIN_LOCK_UNLOCKED; // 2.6.39 & before +#endif + +#ifdef TPD_HAVE_BUTTON + tpd_button_setting(TPD_KEY_COUNT, tpd_keys_local, tpd_keys_dim_local);// initialize tpd button data +#endif + +#if (defined(TPD_WARP_START) && defined(TPD_WARP_END)) + TPD_DO_WARP = 1; + memcpy(tpd_wb_start, tpd_wb_start_local, TPD_WARP_CNT * 4); + memcpy(tpd_wb_end, tpd_wb_start_local, TPD_WARP_CNT * 4); +#endif + +#if (defined(TPD_HAVE_CALIBRATION) && !defined(TPD_CUSTOM_CALIBRATION)) +// memcpy(tpd_calmat, tpd_def_calmat_local, 8 * 4); +// memcpy(tpd_def_calmat, tpd_def_calmat_local, 8 * 4); +#endif + + GTP_INFO("end %s, %d\n", __FUNCTION__, __LINE__); +} + +static void tpd_int_srv(void *param) +{ + if(gt9xx_mb) + { + rt_mb_send(gt9xx_mb, 0); + + gpio_mask_irq(GTP_INT_PORT, GTP_INT_PIN); + } +} + + +static void tpd_event_process(void *param) +{ + struct rt_i2c_bus_device *i2c = (struct rt_i2c_bus_device *)param; + + u8 end_cmd[3] = {GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF, 0}; + u8 point_data[2 + 1 + 8 * GTP_MAX_TOUCH + 1] = {GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF}; + u8 touch_num = 0; + u8 finger = 0; + static u8 pre_touch = 0; + static u8 pre_key = 0; +#if GTP_WITH_PEN + u8 pen_active = 0; + static u8 pre_pen = 0; +#endif + u8 key_value = 0; + u8 *coor_data = NULL; + s32 input_x = 0; + s32 input_y = 0; + s32 input_w = 0; + s32 id = 0; + s32 i = 0; + s32 ret = -1; + +#if GTP_COMPATIBLE_MODE + u8 rqst_data[3] = {(u8)(GTP_REG_RQST >> 8), (u8)(GTP_REG_RQST & 0xFF), 0}; +#endif + +#ifdef TPD_PROXIMITY + s32 err = 0; + hwm_sensor_data sensor_data; + u8 proximity_status; +#endif + +#if GTP_GESTURE_WAKEUP + u8 doze_buf[3] = {0x81, 0x4B}; +#endif + + while(1) + { + while (tpd_halt) + { +#if GTP_GESTURE_WAKEUP + if (DOZE_ENABLED == doze_status) + { + break; + } +#endif + tpd_flag = 0; + rt_thread_delay(rt_tick_from_millisecond(20)); + } + +// wait_event_interruptible(waiter, tpd_flag != 0); + /* wait */ + tpd_flag = 0; + +#if GTP_CHARGER_SWITCH + gtp_charger_switch(0); +#endif + +#if GTP_GESTURE_WAKEUP + if (DOZE_ENABLED == doze_status) + { + ret = gtp_i2c_read(i2c, doze_buf, 3); + GTP_DEBUG("0x814B = 0x%02X", doze_buf[2]); + if (ret > 0) + { + if ((doze_buf[2] == 'a') || (doze_buf[2] == 'b') || (doze_buf[2] == 'c') || + (doze_buf[2] == 'd') || (doze_buf[2] == 'e') || (doze_buf[2] == 'g') || + (doze_buf[2] == 'h') || (doze_buf[2] == 'm') || (doze_buf[2] == 'o') || + (doze_buf[2] == 'q') || (doze_buf[2] == 's') || (doze_buf[2] == 'v') || + (doze_buf[2] == 'w') || (doze_buf[2] == 'y') || (doze_buf[2] == 'z') || + (doze_buf[2] == 0x5E) /* ^ */ + ) + { + if (doze_buf[2] != 0x5E) + { + GTP_INFO("Wakeup by gesture(%c), light up the screen!", doze_buf[2]); + } + else + { + GTP_INFO("Wakeup by gesture(^), light up the screen!"); + } + doze_status = DOZE_WAKEUP; +// input_report_key(tpd->dev, KEY_POWER, 1); +// input_sync(tpd->dev); +// input_report_key(tpd->dev, KEY_POWER, 0); +// input_sync(tpd->dev); + // clear 0x814B + doze_buf[2] = 0x00; + gtp_i2c_write(i2c, doze_buf, 3); + } + else if ( (doze_buf[2] == 0xAA) || (doze_buf[2] == 0xBB) || + (doze_buf[2] == 0xAB) || (doze_buf[2] == 0xBA) ) + { + char *direction[4] = {"Right", "Down", "Up", "Left"}; + u8 type = ((doze_buf[2] & 0x0F) - 0x0A) + (((doze_buf[2] >> 4) & 0x0F) - 0x0A) * 2; + + GTP_INFO("%s slide to light up the screen!", direction[type]); + doze_status = DOZE_WAKEUP; +// input_report_key(tpd->dev, KEY_POWER, 1); +// input_sync(tpd->dev); +// input_report_key(tpd->dev, KEY_POWER, 0); +// input_sync(tpd->dev); + // clear 0x814B + doze_buf[2] = 0x00; + gtp_i2c_write(i2c, doze_buf, 3); + } + else if (0xCC == doze_buf[2]) + { + GTP_INFO("Double click to light up the screen!"); + doze_status = DOZE_WAKEUP; +// input_report_key(tpd->dev, KEY_POWER, 1); +// input_sync(tpd->dev); +// input_report_key(tpd->dev, KEY_POWER, 0); +// input_sync(tpd->dev); + // clear 0x814B + doze_buf[2] = 0x00; + gtp_i2c_write(i2c, doze_buf, 3); + } + else + { + // clear 0x814B + doze_buf[2] = 0x00; + gtp_i2c_write(i2c, doze_buf, 3); + gtp_enter_doze(i2c); + } + } + continue; + } +#endif + ret = gtp_i2c_read(i2c, point_data, 12); + if (ret < 0) + { + GTP_ERROR("I2C transfer error. errno:%d\n ", ret); + continue; + } + finger = point_data[GTP_ADDR_LENGTH]; + +#if GTP_COMPATIBLE_MODE + if ((finger == 0x00) && (CHIP_TYPE_GT9F == gtp_chip_type)) + { + ret = gtp_i2c_read(i2c_client_point, rqst_data, 3); + + if(ret < 0) + { + GTP_ERROR("I2C transfer error. errno:%d\n ", ret); + continue; + } + switch (rqst_data[2]) + { + case GTP_RQST_BAK_REF: + GTP_INFO("Request Ref."); + rqst_processing = 1; + ret = gtp_bak_ref_proc(i2c_client_point, GTP_BAK_REF_SEND); + if(SUCCESS == ret) + { + GTP_INFO("Send ref success."); + rqst_data[2] = GTP_RQST_RESPONDED; + gtp_i2c_write(i2c_client_point, rqst_data, 3); + rqst_processing = 0; + } + goto exit_work_func; + + case GTP_RQST_CONFIG: + GTP_INFO("Request Config."); + ret = gtp_send_cfg(i2c_client_point); + if (ret < 0) + { + GTP_ERROR("Send config error."); + } + else + { + GTP_INFO("Send config success."); + rqst_data[2] = GTP_RQST_RESPONDED; + gtp_i2c_write(i2c_client_point, rqst_data, 3); + } + goto exit_work_func; + + case GTP_RQST_MAIN_CLOCK: + GTP_INFO("Request main clock."); + rqst_processing = 1; + ret = gtp_main_clk_proc(i2c_client_point); + if(SUCCESS == ret) + { + GTP_INFO("Send main clk success."); + + rqst_data[2] = GTP_RQST_RESPONDED; + gtp_i2c_write(i2c_client_point, rqst_data, 3); + rqst_processing = 0; + } + goto exit_work_func; + + case GTP_RQST_RESET: + GTP_INFO("Request Reset."); + gtp_recovery_reset(i2c_client_point); + goto exit_work_func; + + default: + GTP_INFO("Undefined request code: 0x%02X", rqst_data[2]); + rqst_data[2] = GTP_RQST_RESPONDED; + gtp_i2c_write(i2c_client_point, rqst_data, 3); + break; + } + } +#endif + + if (finger == 0x00) + { + continue; + } + + if ((finger & 0x80) == 0) + { + goto exit_work_func; + } + +#ifdef TPD_PROXIMITY + if (tpd_proximity_flag == 1) + { + proximity_status = point_data[GTP_ADDR_LENGTH]; + GTP_DEBUG("REG INDEX[0x814E]:0x%02X\n", proximity_status); + + if (proximity_status & 0x60) //proximity or large touch detect,enable hwm_sensor. + { + tpd_proximity_detect = 0; + //sensor_data.values[0] = 0; + } + else + { + tpd_proximity_detect = 1; + //sensor_data.values[0] = 1; + } + + //get raw data + GTP_DEBUG(" ps change\n"); + GTP_DEBUG("PROXIMITY STATUS:0x%02X\n", tpd_proximity_detect); + //map and store data to hwm_sensor_data + sensor_data.values[0] = tpd_get_ps_value(); + sensor_data.value_divide = 1; + sensor_data.status = SENSOR_STATUS_ACCURACY_MEDIUM; + //report to the up-layer + ret = hwmsen_get_interrupt_data(ID_PROXIMITY, &sensor_data); + + if (ret) + { + GTP_ERROR("Call hwmsen_get_interrupt_data fail = %d\n", err); + } + } + +#endif + + touch_num = finger & 0x0f; + + if (touch_num > GTP_MAX_TOUCH) + { + goto exit_work_func; + } + + if (touch_num > 1) + { + u8 buf[8 * GTP_MAX_TOUCH] = {(GTP_READ_COOR_ADDR + 10) >> 8, (GTP_READ_COOR_ADDR + 10) & 0xff}; + + ret = gtp_i2c_read(i2c, buf, 2 + 8 * (touch_num - 1)); + memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1)); + } + +#if (GTP_HAVE_TOUCH_KEY || GTP_PEN_HAVE_BUTTON) + key_value = point_data[3 + 8 * touch_num]; + + if (key_value || pre_key) + { + #if GTP_PEN_HAVE_BUTTON + if (key_value == 0x40) + { + GTP_DEBUG("BTN_STYLUS & BTN_STYLUS2 Down."); + input_report_key(pen_dev, BTN_STYLUS, 1); + input_report_key(pen_dev, BTN_STYLUS2, 1); + pen_active = 1; + } + else if (key_value == 0x10) + { + GTP_DEBUG("BTN_STYLUS Down, BTN_STYLUS2 Up."); + input_report_key(pen_dev, BTN_STYLUS, 1); + input_report_key(pen_dev, BTN_STYLUS2, 0); + pen_active = 1; + } + else if (key_value == 0x20) + { + GTP_DEBUG("BTN_STYLUS Up, BTN_STYLUS2 Down."); + input_report_key(pen_dev, BTN_STYLUS, 0); + input_report_key(pen_dev, BTN_STYLUS2, 1); + pen_active = 1; + } + else + { + GTP_DEBUG("BTN_STYLUS & BTN_STYLUS2 Up."); + input_report_key(pen_dev, BTN_STYLUS, 0); + input_report_key(pen_dev, BTN_STYLUS2, 0); + if ( (pre_key == 0x40) || (pre_key == 0x20) || + (pre_key == 0x10) + ) + { + pen_active = 1; + } + } + if (pen_active) + { + touch_num = 0; // shield pen point + //pre_touch = 0; // clear last pen status + } +#endif +#if GTP_HAVE_TOUCH_KEY + if (!pre_touch) + { + for (i = 0; i < GTP_MAX_KEY_NUM; i++) + { + input_report_key(tpd->dev, touch_key_array[i], key_value & (0x01 << i)); + } + touch_num = 0; // shiled fingers + } +#endif + } +#endif + pre_key = key_value; + + GTP_DEBUG("pre_touch:%02x, finger:%02x.", pre_touch, finger); + + if (touch_num) + { + for (i = 0; i < touch_num; i++) + { + coor_data = &point_data[i * 8 + 3]; + + id = coor_data[0] & 0x0F; + input_x = coor_data[1] | coor_data[2] << 8; + input_y = coor_data[3] | coor_data[4] << 8; + input_w = coor_data[5] | coor_data[6] << 8; + + input_x = TPD_WARP_X(abs_x_max, input_x); + input_y = TPD_WARP_Y(abs_y_max, input_y); + +#if GTP_WITH_PEN + id = coor_data[0]; + if ((id & 0x80)) // pen/stylus is activated + { + GTP_DEBUG("Pen touch DOWN!"); + pre_pen = 1; + //id &= 0x7F; + id = 0; + GTP_DEBUG("(%d)(%d, %d)[%d]", id, input_x, input_y, input_w); + gtp_pen_down(input_x, input_y, input_w, id); + pen_active = 1; + } + else +#endif + { + GTP_DEBUG(" (%d)(%d, %d)[%d]", id, input_x, input_y, input_w); + tpd_down(input_x, input_y, input_w, id); + } + } + } + else + { + if (pre_touch) + { +#if GTP_WITH_PEN + if (pre_pen) + { + GTP_DEBUG("Pen touch UP!"); + gtp_pen_up(); + pre_pen = 0; + pen_active = 1; + } + else +#endif + { + GTP_DEBUG("Touch Release!"); + tpd_up(0, 0, 0); + } + } + } + pre_touch = touch_num; + +#if GTP_WITH_PEN + if (pen_active) + { + pen_active = 0; + input_sync(pen_dev); + } + else +#endif + { +// input_sync(tpd->dev); + } + +exit_work_func: + + if (!gtp_rawdiff_mode) + { + ret = gtp_i2c_write(i2c, end_cmd, 3); + + if (ret < 0) + { + GTP_INFO("I2C write end_cmd error!"); + } + } + + } +} + +static int tpd_i2c_probe(struct rt_i2c_bus_device *i2c) +{ + s32 err = 0; + s32 ret = 0; + + u16 version_info; +#if GTP_HAVE_TOUCH_KEY + s32 idx = 0; +#endif +#ifdef TPD_PROXIMITY + struct hwmsen_object obj_ps; +#endif + + ret = tpd_power_on(i2c); + if (ret < 0) + { + GTP_ERROR("I2C communication ERROR!"); + } + + ret = gtp_read_version(i2c, &version_info); + if (ret < 0) + { + GTP_ERROR("Read version failed."); + } + + ret = gtp_init_panel(i2c); + if (ret < 0) + { + GTP_ERROR("GTP init panel failed."); + } + + +#if GTP_HAVE_TOUCH_KEY + + for (idx = 0; idx < GTP_MAX_KEY_NUM; idx++) + { + input_set_capability(tpd->dev, EV_KEY, touch_key_array[idx]); + } + +#endif +#if GTP_GESTURE_WAKEUP +// input_set_capability(tpd->dev, EV_KEY, KEY_POWER); +#endif + +#if GTP_WITH_PEN + gtp_pen_init(); +#endif + + // set INT mode + gpio_direction_input(GTP_INT_PORT, GTP_INT_PIN); + gpio_set_func(GTP_INT_PORT, GTP_INT_PIN, GPIO_INPUT | GPIO_INT_FE); + gpio_set_irq_callback(GTP_INT_PORT, GTP_INT_PIN, tpd_int_srv, RT_NULL); + rt_thread_delay(50); + gpio_unmask_irq(GTP_INT_PORT, GTP_INT_PIN); + +#if GTP_ESD_PROTECT + gtp_esd_switch(client, SWITCH_ON); +#endif + +#if GTP_AUTO_UPDATE + ret = gup_init_update_proc(client); + + if (ret < 0) + { + GTP_ERROR("Create update thread error."); + } +#endif + +#ifdef TPD_PROXIMITY + //obj_ps.self = cm3623_obj; + obj_ps.polling = 0; //0--interrupt mode;1--polling mode; + obj_ps.sensor_operate = tpd_ps_operate; + + if ((err = hwmsen_attach(ID_PROXIMITY, &obj_ps))) + { + GTP_ERROR("hwmsen attach fail, return:%d.", err); + } + +#endif + + return 0; +} + + +/******************************************************************************/ +// Description: rt_hw_touch_init +// Dependence: +// Note: GPIO_PROD_TP_INT_ID +/******************************************************************************/ +int rt_hw_touch_init(void) +{ + uint32_t reset_count; + rt_thread_t tid; + + struct rt_i2c_bus_device *i2c_bus; + + i2c_bus = rt_i2c_bus_device_find("i2c0"); + if(i2c_bus == RT_NULL) + { + rt_kprintf("can't find the i2c bus:%s\n","i2c0"); + return -RT_EIO; + } + + gt9xx_mb = rt_mb_create("tp_mb",8,RT_IPC_FLAG_FIFO); + tid = rt_thread_create("tp_serv", + tpd_event_process, i2c_bus, + 4096, + RT_TOUCH_THREAD_PRIORITY,10); + if (tid != RT_NULL) + rt_thread_startup(tid); + + tpd_i2c_probe(i2c_bus); + + return RT_EOK; +} +INIT_DEVICE_EXPORT(rt_hw_touch_init); + +#endif \ No newline at end of file diff --git a/bsp/x1000/drivers/touch/gt9xx.h b/bsp/x1000/drivers/touch/gt9xx.h new file mode 100644 index 0000000000000000000000000000000000000000..f6d1d55c79b7695497a029ff6efe17c3d36073d2 --- /dev/null +++ b/bsp/x1000/drivers/touch/gt9xx.h @@ -0,0 +1,71 @@ +/* + * File : gt9xx.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017-01-01 Urey first version + */ +#ifndef _GT9XX_H_ +#define _GT9XX_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define GT910_ADDR_BABBH +//#define GT910_ADDR_2829H + +#ifdef GT910_ADDR_BABBH +#define GT910_IIC_ADDR 0x14//0x14//0x5D// +//#define GT910_IIC_RADDR 0x29 +//#define GT910_IIC_WADDR 0x28 +#else +#define GT910_IIC_RADDR 0x29 +#define GT910_IIC_WADDR 0x28 +#endif + +extern uint16_t show_len; +extern uint16_t total_len; +extern uint8_t gtp_rawdiff_mode; + +extern int tpd_halt; +extern int gtp_send_cfg(struct rt_i2c_bus_device *i2c); +extern void gtp_reset_guitar(struct rt_i2c_bus_device *i2c, int ms); +extern void gtp_int_sync(int ms); +extern uint8_t gup_init_update_proc(struct rt_i2c_bus_device *i2c); +extern uint8_t gup_init_fw_proc(struct rt_i2c_bus_device *i2c); + +extern int gtp_i2c_read(struct rt_i2c_bus_device *i2c, uint8_t *buf, int len); +extern int gtp_i2c_write(struct rt_i2c_bus_device *i2c,uint8_t *buf,int len); +extern int i2c_write_bytes(struct rt_i2c_bus_device *i2c, uint16_t addr, uint8_t *txbuf, int len); +extern int i2c_read_bytes(struct rt_i2c_bus_device *i2c, uint16_t addr, uint8_t *rxbuf, int len); +extern int i2c_read_dbl_check(struct rt_i2c_bus_device *i2c, uint16_t addr, uint8_t *rxbuf, int len); +extern int gtp_i2c_read_dbl_check(struct rt_i2c_bus_device *i2c, uint16_t addr, uint8_t *rxbuf, int len); + +extern void mt65xx_eint_unmask(uint32_t line); +extern void mt65xx_eint_mask(uint32_t line); + +#ifdef __cplusplus +} +#endif + +#endif /* _GT9XX_H_ */ diff --git a/bsp/x1000/drivers/touch/gt9xx_cfg.h b/bsp/x1000/drivers/touch/gt9xx_cfg.h new file mode 100644 index 0000000000000000000000000000000000000000..9f5bf7d57462410daf3af69fdaa57b106bfd362d --- /dev/null +++ b/bsp/x1000/drivers/touch/gt9xx_cfg.h @@ -0,0 +1,326 @@ +/* + * File : gt9xx_cfg.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017-01-01 Urey first version + */ +#ifndef DRIVER_TOUCH_GT9XX_CFG_H_ +#define DRIVER_TOUCH_GT9XX_CFG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Pre-defined definition */ +#define TPD_KEY_COUNT 4 +#define key_1 60,850 //auto define +#define key_2 180,850 +#define key_3 300,850 +#define key_4 420,850 + +#define TPD_KEYS {KEY_BACK, KEY_HOME, KEY_MENU, KEY_SEARCH} +#define TPD_KEYS_DIM {{key_1,50,30},{key_2,50,30},{key_3,50,30},{key_4,50,30}} + +//***************************PART1:ON/OFF define******************************* +#define GTP_CUSTOM_CFG 0 +#define GTP_DRIVER_SEND_CFG 1 // driver send config to TP in intilization +#define GTP_HAVE_TOUCH_KEY 0 +#define GTP_POWER_CTRL_SLEEP 0 // turn off/on power on suspend/resume + +#define GTP_AUTO_UPDATE 0 // auto updated fw by .bin file +#define GTP_HEADER_FW_UPDATE 0 // auto updated fw by gtp_default_FW in gt9xx_firmware.h, function together with GTP_AUTO_UDPATE +#define GTP_AUTO_UPDATE_CFG 0 // auto update config by .cfg file, function together with GTP_AUTO_UPDATE + +#define GTP_SUPPORT_I2C_DMA 1 // if gt9xxf, better enable it if hardware platform supported +#define GTP_COMPATIBLE_MODE 0 // compatible with GT9XXF + +#define GTP_CREATE_WR_NODE 0 +#define GTP_ESD_PROTECT 0 // esd protection with a cycle of 2 seconds +#define GTP_CHARGER_SWITCH 0 // charger plugin & plugout detect + +#define GTP_WITH_PEN 0 +#define GTP_PEN_HAVE_BUTTON 0 // active pen has buttons, functions together with GTP_WITH_PEN + +#define GTP_GESTURE_WAKEUP 1 + +//#define TPD_PROXIMITY +//#define TPD_HAVE_BUTTON // report key as coordinate,Vibration feedback +//#define TPD_WARP_X // mirrored x coordinate +//#define TPD_WARP_Y // mirrored y coordinate +#define GTP_DEBUG_ON 1 +#define GTP_DEBUG_ARRAY_ON 0 +#define GTP_DEBUG_FUNC_ON 0 + +//***************************PART2:TODO define********************************** +//STEP_1(REQUIRED):Change config table. +// Sensor_ID Map: +/* sensor_opt1 sensor_opt2 Sensor_ID + GND GND 0 + VDDIO GND 1 + NC GND 2 + GND NC/300K 3 + VDDIO NC/300K 4 + NC NC/300K 5 +*/ +// TODO: define your own default or for Sensor_ID == 0 config here. +// The predefined one is just a sample config, which is not suitable for your tp in most cases. +#define CTP_CFG_GROUP0 {\ + 0x50,0x40,0x01,0xE0,0x01,0x05,0x05,0x00,0x02,0x2A,0x28,0x0F,0x50,0x41,0x03,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x86,0x26,0x08,0x23,0x20,0x05,0x0D,0x00,0x00,0x00,0x9A,0x03,0x2D,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0x5A,0x94,0xC5,0x02,0x07,0x00,0x00,0x04,0x91,0x1C,0x00,0x6F,0x25,0x00,0x58,0x2F,0x00,0x45,0x3D,0x00,0x36,0x4F,0x00,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0E,0x10,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x04,0x06,0x08,0x0A,0x1D,0x1E,0x1F,0x20,0x21,0x22,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC3,0x01\ + } + +#define GTP_CFG_GROUP0_CHARGER {\ + 0x47,0xD0,0x02,0x00,0x05,0x05,0x34,0x00,0x01,0x8C,\ +0x1E,0x0C,0x50,0x3C,0x03,0x07,0x01,0x01,0x00,0x00,\ +0x00,0x00,0x00,0x18,0x1A,0x1E,0x14,0x8B,0x2B,0x0C,\ +0x50,0x52,0xD6,0x09,0x00,0x00,0x00,0x9C,0x32,0x1D,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0xF4,0x4A,0x64,0x9E,0xE5,0x01,0x14,0x00,0x00,0x04,\ +0x74,0x4C,0x00,0x70,0x50,0x00,0x69,0x55,0x00,0x63,\ +0x5B,0x00,0x5E,0x61,0x00,0x5E,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x01,0x1B,0x14,0x0D,0x14,0x03,0x0F,0x0A,0x03,\ +0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0E,0x10,\ +0x12,0x14,0x16,0x18,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\ +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\ +0xFF,0xFF,0x00,0x01,0x02,0x04,0x06,0x07,0x08,0x09,\ +0x0A,0x0C,0x0E,0x1D,0x1E,0x1F,0x20,0x22,0x24,0x25,\ +0x26,0x28,0x29,0x2A,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\ +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\ +0xFF,0xFF,0xFF,0xFF,0xB5,0x01\ +} + +// TODO: define your config for Sensor_ID == 1 here, if needed +#define CTP_CFG_GROUP1 {\ + } + +#define GTP_CFG_GROUP1_CHARGER {\ +} + +// TODO: define your config for Sensor_ID == 2 here, if needed +#define CTP_CFG_GROUP2 {\ + } + +#define GTP_CFG_GROUP2_CHARGER {\ +} + + +// TODO: define your config for Sensor_ID == 3 here, if needed +#define CTP_CFG_GROUP3 {\ + } + +#define GTP_CFG_GROUP3_CHARGER {\ +} + + +// TODO: define your config for Sensor_ID == 4 here, if needed +#define CTP_CFG_GROUP4 {\ + } + +#define GTP_CFG_GROUP4_CHARGER {\ +} + +// TODO: define your config for Sensor_ID == 5 here, if needed +#define CTP_CFG_GROUP5 {\ + } + +#define GTP_CFG_GROUP5_CHARGER {\ +} + + +// STEP_2(REQUIRED): Customize your I/O ports & I/O operations here +#define TPD_POWER_SOURCE_CUSTOM MT65XX_POWER_LDO_VGP4 // define your power source for tp if needed +#define GTP_RST_PORT GPIO_PORT_C +#define GTP_INT_PORT GPIO_PORT_C +#define GTP_INT_PIN GPIO_Pin_25 + +#define GTP_GPIO_AS_INPUT(pin) +#define GTP_GPIO_AS_INT(pin) +#define GTP_GPIO_OUTPUT(pin,level) +#define GTP_GPIO_GET_VALUE(pin) + +#define GTP_GPIO_REQUEST(pin, label) gpio_request(pin, label) +#define GTP_GPIO_FREE(pin) gpio_free(pin) +#define GTP_IRQ_TAB {IRQ_TYPE_EDGE_RISING, IRQ_TYPE_EDGE_FALLING, IRQ_TYPE_LEVEL_LOW, IRQ_TYPE_LEVEL_HIGH} + +// STEP_3(optional):Custom set some config by themself,if need. +#if GTP_CUSTOM_CFG + #define GTP_MAX_HEIGHT 800 + #define GTP_MAX_WIDTH 480 + #define GTP_INT_TRIGGER 0 //0:Rising 1:Falling +#else + #define GTP_MAX_HEIGHT 4096 + #define GTP_MAX_WIDTH 4096 + #define GTP_INT_TRIGGER 1 +#endif +#define GTP_MAX_TOUCH 1 // Configure maximum touch points +#define VELOCITY_CUSTOM +#define TPD_VELOCITY_CUSTOM_X 15 +#define TPD_VELOCITY_CUSTOM_Y 15 + +//STEP_4(optional):If this project have touch key,Set touch key config. +#if GTP_HAVE_TOUCH_KEY + #define GTP_KEY_TAB {KEY_MENU, KEY_HOME, KEY_BACK, KEY_SEND} +#endif + +//***************************PART3:OTHER define********************************* +#define GTP_DRIVER_VERSION "V2.4<2014/11/28>" +#define GTP_I2C_NAME "Goodix-TS" +#define GT91XX_CONFIG_PROC_FILE "gt9xx_config" +#define GTP_POLL_TIME 10 +#define GTP_ADDR_LENGTH 2 +#define GTP_CONFIG_MIN_LENGTH 186 +#define GTP_CONFIG_MAX_LENGTH 240 +#define FAIL 0 +#define SUCCESS 1 +#define SWITCH_OFF 0 +#define SWITCH_ON 1 + +#define CFG_GROUP_LEN(p_cfg_grp) (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0])) + +//******************** For GT9XXF Start **********************// +#if GTP_COMPATIBLE_MODE +typedef enum +{ + CHIP_TYPE_GT9 = 0, + CHIP_TYPE_GT9F = 1, +} CHIP_TYPE_T; +#endif + +#define GTP_REG_MATRIX_DRVNUM 0x8069 +#define GTP_REG_MATRIX_SENNUM 0x806A +#define GTP_REG_RQST 0x8043 +#define GTP_REG_BAK_REF 0x99D0 +#define GTP_REG_MAIN_CLK 0x8020 +#define GTP_REG_CHIP_TYPE 0x8000 +#define GTP_REG_HAVE_KEY 0x804E + +#define GTP_FL_FW_BURN 0x00 +#define GTP_FL_ESD_RECOVERY 0x01 +#define GTP_FL_READ_REPAIR 0x02 + +#define GTP_BAK_REF_SEND 0 +#define GTP_BAK_REF_STORE 1 +#define CFG_LOC_DRVA_NUM 29 +#define CFG_LOC_DRVB_NUM 30 +#define CFG_LOC_SENS_NUM 31 + +#define GTP_CHK_FW_MAX 1000 +#define GTP_CHK_FS_MNT_MAX 300 +#define GTP_BAK_REF_PATH "/data/gtp_ref.bin" +#define GTP_MAIN_CLK_PATH "/data/gtp_clk.bin" +#define GTP_RQST_CONFIG 0x01 +#define GTP_RQST_BAK_REF 0x02 +#define GTP_RQST_RESET 0x03 +#define GTP_RQST_MAIN_CLOCK 0x04 +#define GTP_RQST_RESPONDED 0x00 +#define GTP_RQST_IDLE 0xFF + +//******************** For GT9XXF End **********************// + +//Register define +#define GTP_READ_COOR_ADDR 0x814E +#define GTP_REG_SLEEP 0x8040 +#define GTP_REG_SENSOR_ID 0x814A +#define GTP_REG_CONFIG_DATA 0x8047 +#define GTP_REG_VERSION 0x8140 +#define GTP_REG_HW_INFO 0x4220 + +#define RESOLUTION_LOC 3 +#define TRIGGER_LOC 8 + +#define I2C_MASTER_CLOCK 300 +#define I2C_BUS_NUMBER 1 // I2C Bus for TP, mt6572 +#define GTP_DMA_MAX_TRANSACTION_LENGTH 255 // for DMA mode +#define GTP_DMA_MAX_I2C_TRANSFER_SIZE (GTP_DMA_MAX_TRANSACTION_LENGTH - GTP_ADDR_LENGTH) +#define MAX_TRANSACTION_LENGTH 8 +#define MAX_I2C_TRANSFER_SIZE (MAX_TRANSACTION_LENGTH - GTP_ADDR_LENGTH) +#define TPD_MAX_RESET_COUNT 3 +#define TPD_CALIBRATION_MATRIX {962,0,0,0,1600,0,0,0}; + + +#define TPD_RESET_ISSUE_WORKAROUND +#define TPD_HAVE_CALIBRATION +#define TPD_NO_GPIO +#define TPD_RESET_ISSUE_WORKAROUND + +#ifdef TPD_WARP_X +#undef TPD_WARP_X +#define TPD_WARP_X(x_max, x) ( x_max - 1 - x ) +#else +#define TPD_WARP_X(x_max, x) x +#endif + +#ifdef TPD_WARP_Y +#undef TPD_WARP_Y +#define TPD_WARP_Y(y_max, y) ( y_max - 1 - y ) +#else +#define TPD_WARP_Y(y_max, y) y +#endif + + +#ifdef GTP_DEBUG_EN +#define GTP_INFO(fmt,arg...) printf("<<-GTP-INFO->> "fmt"\n",##arg) +#define GTP_ERROR(fmt,arg...) printf("<<-GTP-ERROR->> "fmt"\n",##arg) +#define GTP_DEBUG(fmt,arg...) do{\ + if(GTP_DEBUG_ON)\ + printf("<<-GTP-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\ + }while(0) +#define GTP_DEBUG_ARRAY(array, num) do{\ + s32 i;\ + u8* a = array;\ + if(GTP_DEBUG_ARRAY_ON)\ + {\ + printf("<<-GTP-DEBUG-ARRAY->>\n");\ + for (i = 0; i < (num); i++)\ + {\ + printf("%02x ", (a)[i]);\ + if ((i + 1 ) %10 == 0)\ + {\ + printf("\n");\ + }\ + }\ + printf("\n");\ + }\ + }while(0) +#define GTP_DEBUG_FUNC() do{\ + if(GTP_DEBUG_FUNC_ON)\ + printf("<<-GTP-FUNC->> Func:%s@Line:%d\n",__func__,__LINE__);\ + }while(0) +#define GTP_SWAP(x, y) do{\ + typeof(x) z = x;\ + x = y;\ + y = z;\ + }while (0) +#else +//Log define +#define GTP_INFO(fmt,arg...) +#define GTP_ERROR(fmt,arg...) +#define GTP_DEBUG(fmt,arg...) +#define GTP_DEBUG_ARRAY(array, num) +#define GTP_DEBUG_FUNC() +#define GTP_SWAP(x, y) + +#endif +#ifdef __cplusplus +} +#endif + +#endif /* DRIVER_TOUCH_GT9XX_CFG_H_ */ diff --git a/bsp/x1000/drivers/touch/gt9xx_firmware.h b/bsp/x1000/drivers/touch/gt9xx_firmware.h new file mode 100644 index 0000000000000000000000000000000000000000..aa87dd08246b0d0ac205c2665cae8cb2eafdc858 --- /dev/null +++ b/bsp/x1000/drivers/touch/gt9xx_firmware.h @@ -0,0 +1,74 @@ +/* + * File : gt9xx_firmware.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017-01-01 Urey first version + */ +#ifndef _GT9XX_FIRMWARE_H_ +#define _GT9XX_FIRMWARE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "gt9xx.h" + +#if GTP_HEADER_FW_UPDATE +unsigned char gtp_default_FW[] = +{ + //TODO:Puts your update firmware data here! +}; +#endif + +/* +*[HW INFO]00900600 +*[PID]910 +*[VID]1010 +*[GENERATED]2013/08/27 20:59:13 +*/ +#if GTP_COMPATIBLE_MODE +unsigned char gtp_default_FW_fl[] = { + 0x50, 0x40, 0x01, 0xE0, 0x01, 0x05, 0x05, 0x00, 0x02, 0x2A, 0x28, 0x0F, 0x50, + 0x41, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x86, 0x26, 0x08, 0x23, 0x20, 0x05, + 0x0D, 0x00, 0x00, 0x00, 0x9A, 0x03, 0x2D, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x5A, + 0x94, 0xC5, 0x02, 0x07, 0x00, 0x00, 0x04, 0x91, 0x1C, 0x00, + 0x6F, 0x25, 0x00, 0x58, 0x2F, 0x00, 0x45, 0x3D, 0x00, 0x36, + 0x4F, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x04, 0x06, 0x08, 0x0A, 0x1D, 0x1E, 0x1F, 0x20, 0x21, + 0x22, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xC3, 0x01 }; +#endif + + +#ifdef __cplusplus +} +#endif + +#endif /* _GT9XX_FIRMWARE_H_ */ diff --git a/bsp/x1000/drivers/usbd/SConscript b/bsp/x1000/drivers/usbd/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..24d01e093ccbcd51a4325c9ee1fd3870ac3933a9 --- /dev/null +++ b/bsp/x1000/drivers/usbd/SConscript @@ -0,0 +1,11 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd] + +group = DefineGroup('DriversUSBD', src, depend = ['RT_USING_USB_DEVICE'], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/x1000/drivers/usbd/drv_usbd.c b/bsp/x1000/drivers/usbd/drv_usbd.c new file mode 100644 index 0000000000000000000000000000000000000000..cb8c0ea4b707a7acab380931d963fe1e96ffdf05 --- /dev/null +++ b/bsp/x1000/drivers/usbd/drv_usbd.c @@ -0,0 +1,362 @@ +/* + * drv_usbd.c + * + * Created on: 2017年2月1日 + * Author: Urey + */ + +#include +#include + +#include "x1000.h" +#include "x1000_dwc.h" + +static struct udcd __x1000_usbd; +static dwc_handle __dwc_hdl; + +//#define USBD_DEBUG +#ifdef USBD_DEBUG +#define USBD_DBG(fmt, args...) rt_kprintf(fmt ,##args) +#else +#define USBD_DBG(fmt, args...) +#endif + +static void __delay(void) +{ + int i; + + for (i = 0; i < 1000; i++); +} + +static struct ep_id __ep_pool[] = +{ + {0x00, USB_EP_ATTR_CONTROL, USB_DIR_INOUT, 64, ID_ASSIGNED}, +#if DWC_FORCE_SPEED_FULL + {0x01, USB_EP_ATTR_INT, USB_DIR_IN, 64, ID_UNASSIGNED}, + {0x02, USB_EP_ATTR_BULK, USB_DIR_OUT, 64, ID_UNASSIGNED}, + {0x02, USB_EP_ATTR_BULK, USB_DIR_IN, 64, ID_UNASSIGNED}, + {0x04, USB_EP_ATTR_BULK, USB_DIR_OUT, 64, ID_UNASSIGNED}, + {0x04, USB_EP_ATTR_BULK, USB_DIR_IN, 64, ID_UNASSIGNED}, +#else + {0x01, USB_EP_ATTR_INT, USB_DIR_IN, 512, ID_UNASSIGNED}, + {0x01, USB_EP_ATTR_INT, USB_DIR_OUT, 512, ID_UNASSIGNED}, + + {0x02, USB_EP_ATTR_BULK, USB_DIR_OUT, 512, ID_UNASSIGNED}, + {0x02, USB_EP_ATTR_BULK, USB_DIR_IN, 512, ID_UNASSIGNED}, + + {0x04, USB_EP_ATTR_BULK, USB_DIR_OUT, 512, ID_UNASSIGNED}, + {0x04, USB_EP_ATTR_BULK, USB_DIR_IN, 512, ID_UNASSIGNED}, + + {0x06, USB_EP_ATTR_BULK, USB_DIR_OUT, 512, ID_UNASSIGNED}, + {0x06, USB_EP_ATTR_BULK, USB_DIR_IN, 512, ID_UNASSIGNED}, +#endif + {0xFF, USB_EP_ATTR_TYPE_MASK, USB_DIR_MASK, 0, ID_ASSIGNED} +}; + +#define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ') +static void dump_hex(const rt_uint8_t *ptr, rt_size_t buflen) +{ + unsigned char *buf = (unsigned char*)ptr; + int i, j; + for (i=0; iep_desc != RT_NULL); + RT_DEBUG_LOG(RT_DEBUG_USB,("%s ,address = %02x\n", __func__,EP_ADDRESS(ep))); + + if(ep->id->dir == USB_DIR_IN) + dwc_enable_in_ep(&__dwc_hdl,ep->id->addr); + else + dwc_enable_out_ep(&__dwc_hdl,ep->id->addr); + + return RT_EOK; +} + +static rt_err_t __ep_disable(uep_t ep) +{ + RT_ASSERT(ep != RT_NULL); + RT_ASSERT(ep->ep_desc != RT_NULL); + RT_DEBUG_LOG(RT_DEBUG_USB,("%s\n", __func__)); + + // USB_DisableEP(EP_ADDRESS(ep)); + + return RT_EOK; +} + +static rt_size_t __ep_read_prepare(rt_uint8_t address, void *buffer, rt_size_t size) +{ + dwc_ep *pep ; + RT_DEBUG_LOG(RT_DEBUG_USB,("%s address = %02x,size = %d\n", __func__,address,size)); + + pep = __dwc_hdl.dep[address & 0x0F + DWC_EP_OUT_OFS]; + pep->ep_state = EP_DATA; + pep->xfer_len = size; +// pep->xfer_buff = buffer; + pep->xfer_count = 0; + dwc_handle_ep_data_out_phase(&__dwc_hdl, address); + return size; +} + +static rt_size_t __ep_read(rt_uint8_t address, void *buffer) +{ + rt_size_t size = 0; + + RT_ASSERT(buffer != RT_NULL); + RT_DEBUG_LOG(RT_DEBUG_USB,("%s\n", __func__)); + + size = HW_GetPKT(&__dwc_hdl,address,(uint8_t *)buffer,0); + + return size; +} + +static rt_size_t __ep_write(rt_uint8_t address, void *buffer, rt_size_t size) +{ + RT_DEBUG_LOG(RT_DEBUG_USB,("%s address = %02x,buffer = %08x ,size = %d\n", __func__,address,(uint32_t)buffer,size)); + + size = HW_SendPKT(&__dwc_hdl,address,(const uint8_t *)buffer,size); + return size; +} + +static rt_err_t __ep0_send_status(void) +{ + RT_DEBUG_LOG(RT_DEBUG_USB,("%s\n", __func__)); + + HW_SendPKT(&__dwc_hdl,0,0,0); + return RT_EOK; +} + +static rt_err_t __suspend(void) +{ + RT_DEBUG_LOG(RT_DEBUG_USB,("%s\n", __func__)); + + return RT_EOK; +} + +static rt_err_t __wakeup(void) +{ + RT_DEBUG_LOG(RT_DEBUG_USB,("%s\n", __func__)); + + return RT_EOK; +} + + +static rt_err_t __init(rt_device_t device) +{ + int epidx = 0, epnum = 0; + + __dwc_hdl.status.b.state = USB_CABLE_DISCONNECT; + /* clear all dep */ + for (epidx = 0; epidx < 32; epidx++) + { + __dwc_hdl.dep[epidx] = RT_NULL; + } + + for (epidx = 0; __ep_pool[epidx].addr != 0xFF; ++epidx) + { + dwc_ep *pep = RT_NULL; + rt_uint8_t *pXfer = RT_NULL; + if(epidx == 0) + { /* EP0 is IN-OUT */ + pep = (dwc_ep *) rt_malloc(sizeof(dwc_ep)); + if (!pep) + { + rt_kprintf("ERROR: no memory for pep\n"); + while (1) ; + } + /* malloc memory for EP */ + pXfer = rt_malloc_align(__ep_pool[epidx].maxpacket * 2, 32); + if (!pXfer) + { + rt_kprintf("ERROR: no memory for pXfer\n"); + while (1) ; + } + /* init pep */ + { + pep->num = 0; + pep->ep_state = EP_SETUP; + pep->is_in = 0; + pep->active = 0; + pep->type = DWC_OTG_EP_TYPE_CONTROL; + pep->maxpacket = __ep_pool[epidx].maxpacket; + pep->xfer_buff = (void *)UNCACHED(pXfer); + pep->xfer_len = 0; + pep->xfer_count = 0; + } + + __dwc_hdl.dep[0 + DWC_EP_IN_OFS] = pep; + __dwc_hdl.dep[0 + DWC_EP_OUT_OFS] = pep; + } + else + { + pep = (dwc_ep *) rt_malloc(sizeof(dwc_ep)); + if (!pep) + { + rt_kprintf("ERROR: no memory for pep\n"); + while (1) ; + } + + /* malloc memory for EP */ + pXfer = rt_malloc_align(__ep_pool[epidx].maxpacket * 2, 32); + if (!pXfer) + { + rt_kprintf("ERROR: no memory for pXfer\n"); + while (1) ; + } + + /* init pep */ + { + pep->num = __ep_pool[epidx].addr; + pep->ep_state = EP_IDLE; + pep->is_in = (__ep_pool[epidx].dir == USB_DIR_IN) ? 1 : 0; + pep->active = 0; + pep->type = __ep_pool[epidx].type; + pep->maxpacket = __ep_pool[epidx].maxpacket; + pep->xfer_buff = (void *)UNCACHED(pXfer); + pep->xfer_len = 0; + pep->xfer_count = 0; + } + if(__ep_pool[epidx].dir == USB_DIR_OUT) + epnum = __ep_pool[epidx].addr + DWC_EP_OUT_OFS; + else + epnum = __ep_pool[epidx].addr + DWC_EP_IN_OFS; + __dwc_hdl.dep[epnum] = pep; + } + } + x1000_usbd_init(&__dwc_hdl); + + { + dwc_ep *pep = __dwc_hdl.dep[18]; + // rt_kprintf("18 pep->is_in = %d\n",pep->is_in); + // rt_kprintf("18 xfer_buff = %08x\n",(uint32_t)pep->xfer_buff); + } + return RT_EOK; +} + + +static struct udcd_ops __x1000_usbd_ops = +{ + __set_address, + __set_config, + __ep_set_stall, + __ep_clear_stall, + __ep_enable, + __ep_disable, + __ep_read_prepare, + __ep_read, + __ep_write, + __ep0_send_status, + __suspend, + __wakeup, +}; + + +void x1000_usbd_event_cb(uint8_t address,uint32_t event,void *arg) +{ + switch (event) + { + case USB_EVT_SETUP: + USBD_DBG("USB_EVT_SETUP\n"); + if(address == 0) + { + rt_usbd_ep0_setup_handler(&__x1000_usbd, (struct urequest*)arg); + } + break; + case USB_EVT_OUT: + USBD_DBG("USB_EVT_OUT\n"); + if(address == 0) + rt_usbd_ep0_out_handler(&__x1000_usbd, (rt_size_t)arg); + else + rt_usbd_ep_out_handler(&__x1000_usbd, USB_DIR_OUT | address, 0); + break; + case USB_EVT_IN: + USBD_DBG("USB_EVT_IN\n"); + if(address == 0) + rt_usbd_ep0_in_handler(&__x1000_usbd); + else + rt_usbd_ep_in_handler(&__x1000_usbd, USB_DIR_IN | address,__dwc_hdl.dep[DWC_EP_IN_OFS + address]->xfer_count); + break; + case USB_EVT_SOF: + rt_usbd_sof_handler(&__x1000_usbd); + break; + default: + break; + } +} + +int x1000_usbd_register(void) +{ + rt_memset((void *)&__x1000_usbd, 0, sizeof(struct udcd)); + + __x1000_usbd.parent.type = RT_Device_Class_USBDevice; + __x1000_usbd.parent.init = __init; + + __x1000_usbd.ops = &__x1000_usbd_ops; + + /* Register endpoint infomation */ + __x1000_usbd.ep_pool = __ep_pool; + __x1000_usbd.ep0.id = &__ep_pool[0]; + + + rt_device_register(&__x1000_usbd.parent, "usbd", 0); + rt_usb_device_init(); + + return RT_EOK; +} +INIT_ENV_EXPORT(x1000_usbd_register); diff --git a/bsp/x1000/drivers/usbd/x1000_dwc.c b/bsp/x1000/drivers/usbd/x1000_dwc.c new file mode 100644 index 0000000000000000000000000000000000000000..76f03c1eb25dd1359113845342b67453e3ac4b8b --- /dev/null +++ b/bsp/x1000/drivers/usbd/x1000_dwc.c @@ -0,0 +1,2027 @@ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "x1000_dwc.h" + + +//#define DWC_DEBUG +#ifdef DWC_DEBUG +#define DWC_DBG(fmt, args...) rt_kprintf(fmt ,##args) +#else +#define DWC_DBG(fmt, args...) +#endif + + +#define UdcID (('U' << 24) | ('D' << 16) | ('C' << 16) | (':' << 16)) +#define IS_SLAVE_MODE 0 +#define IS_INTERN_DMA 2 +#define IS_EXTERN_DMA 1 + +const char *ep0_state_string[] = +{ + "EP_SETUP", + "EP_DATA", + "EP_STATUS", + "EP_SETUP_PHASEDONE", +}; + +#if DWC_FORCE_SPEED_FULL +#define DEP_EP_MAXPKT(n) \ + ({ \ + int v = 0; \ + if (n) \ + v = 64; \ + else \ + v = 64; \ + v; \ + }) +#else +#define DEP_EP_MAXPKT(n) \ + ({ \ + int v = 0; \ + if (n) \ + v = 512; \ + else \ + v = 64; \ + v; \ + }) +#endif + +#define MAX_PKT_CNT 1023 + +ALIGN(32) +//static uint32_t setup_packet[64] = {0, 0, 0, 0, 0}; +static int sleep_flag = 0; + + + +/* + * static functions + */ +static void dwc_otg_device_init(dwc_handle *dwc); +static void dwc_otg_core_reset(dwc_handle *dwc); +static void dwc_otg_core_init(dwc_handle *dwc,uint8_t dma_enable); +static void dwc_otg_phy_suspend(int suspend); + + +static void udelay(uint32_t x) +{ + volatile uint32_t n = 1000; + + while(x--) + { + for (n = 0; n < 1000; ++n); + } +} + +static void mdelay(uint32_t x) +{ + while(x--) + udelay(1000); +} + +static int dwc_get_utmi_width(dwc_handle *dwc) +{ + return (REG_GHW_CFG4 >> 14) & 0x3; +} + +static void dwc_otg_select_phy_width(dwc_handle *dwc) +{ + REG_GUSB_CFG &= ~USBCFG_TRDTIME_MASK; + REG_GUSB_CFG |= (1 << 3); + REG_GUSB_CFG |= USBCFG_TRDTIME_6; + REG_CPM_USBPCR1 |= (3 << 18); +} + + +static void dwc_otg_write_packet(dwc_handle *dwc, uint8_t epnum) +{ + int i; + uint32_t dwords; + uint32_t byte_count; + dwc_ep *pep; + + epnum &= DWC_EPNO_MASK; + pep = dwc->dep[DWC_EP_IN_OFS + epnum]; + + byte_count = pep->xfer_len - pep->xfer_count; + + if (byte_count > DEP_EP_MAXPKT(epnum)) + byte_count = DEP_EP_MAXPKT(epnum); + + dwords = (byte_count + 3) / 4; + + for (i = 0; i < dwords; i++) + { + REG_EP_FIFO(epnum) = REG32((uint32_t * )(pep->xfer_buff) + i); + } + + pep->xfer_count += byte_count; + pep->xfer_buff += byte_count; +} + + +void dwc_read_ep_packet(dwc_handle *dwc, uint8_t epnum, uint32_t count) +{ + int i; + int dwords = (count + 3) / 4; + dwc_ep *pep; + + epnum &= DWC_EPNO_MASK; + pep = dwc->dep[DWC_EP_OUT_OFS + epnum]; + + for (i = 0; i < dwords; i++) + REG32((uint32_t *)(pep->xfer_buff + pep->xfer_count / 4) + i) = REG_EP_FIFO(epnum); + + pep->xfer_count += count; +} + + +void dwc_write_ep_packet(dwc_handle *dwc,uint8_t epnum) +{ + uint32_t xfersize, finish, insize; + uint32_t dwords; + uint32_t txstatus = REG_DIEP_TXFSTS(epnum & 0x0F); + dwc_ep *pep; + + epnum &= DWC_EPNO_MASK; + pep = dwc->dep[DWC_EP_IN_OFS + epnum]; + + insize = pep->xfer_len; + if (pep->xfer_len > DEP_EP_MAXPKT(epnum)) + xfersize = DEP_EP_MAXPKT(epnum); + else + xfersize = pep->xfer_len; + + dwords = (xfersize + 3) / 4; + DWC_DBG("txstatus (%x) dwords (%x) length (%x) xfer_count (%x) \n", txstatus, dwords, pep->xfer_len, pep->xfer_count); + + while ((txstatus > dwords) && (pep->xfer_len > 0) && (pep->xfer_count < pep->xfer_len) ) + { + dwc_otg_write_packet(dwc, epnum); + xfersize = pep->xfer_len - pep->xfer_count; + if (xfersize > DEP_EP_MAXPKT(epnum)) + xfersize = DEP_EP_MAXPKT(epnum); + dwords = (xfersize + 3) / 4; + txstatus = REG_DIEP_TXFSTS(epnum); + } + finish = pep->xfer_count; + + if (insize > finish) + { + uint32_t intr = REG_DIEP_INT(epnum); + while (!(intr & DEP_TXFIFO_EMPTY)) + { + intr = REG_DIEP_INT(epnum); + } + HW_SendPKT(dwc,epnum, pep->xfer_buff, insize - finish); + } + return; +} + +void dwc_handle_ep_data_in_phase(dwc_handle *dwc, uint8_t epnum) +{ + uint32_t pktcnt, xfersize; + uint32_t dma_addr, dma_len; + dwc_ep *pep; + + DWC_DBG("%s %d\n",__func__,__LINE__); + DWC_DBG("epnum = %d\n",epnum); + epnum &= DWC_EPNO_MASK; + pep = dwc->dep[DWC_EP_IN_OFS + epnum]; + + xfersize = pep->xfer_len; + pktcnt = (xfersize + DEP_EP_MAXPKT(epnum) - 1) / DEP_EP_MAXPKT(epnum); + + if (pktcnt > 1023) + { + DWC_DBG("WARNING...\n"); + while (1) ; + } + + if (epnum == 0) + { + REG_DIEP_SIZE(epnum) &= ~(0x1fffff); + REG_DIEP_SIZE(epnum) |= (pktcnt << 19) | xfersize; + } + else + { + REG_DIEP_SIZE(epnum) &= ~(0x1fffffff); + REG_DIEP_SIZE(epnum) |= (pktcnt << 19) | xfersize; + } + + if (dwc->is_dma != 0) + { + dma_addr = (uint32_t)(pep->xfer_buff); + dma_len = (((pep->xfer_len + 7) >> 3) << 3); + + //dump data... + DWC_DBG("IN:\n"); + { + int i; + for (i = 0; i < dma_len; ++i) + { + DWC_DBG("%02x ", *(unsigned char *)(dma_addr+i)); + if ((i + 1) % 16 == 0) + DWC_DBG("\n"); + } + } + DWC_DBG("\n"); + + REG_DIEP_DMA(epnum) = PHYS(pep->xfer_buff); + REG_DIEP_CTL(epnum) |= (DEP_ENA_BIT | DEP_CLEAR_NAK); + } + else + { + REG_DIEP_CTL(epnum) |= (DEP_ENA_BIT | DEP_CLEAR_NAK); + REG_DIEP_EMPMSK |= (1 << epnum); + } + + return ; +} + + +void dwc_handle_ep_status_in_phase(dwc_handle *dwc, uint8_t epnum) +{ + dwc_ep *pep; + + DWC_DBG("%s %d\n",__func__,__LINE__); + DWC_DBG("epnum = %d\n",epnum); + epnum &= DWC_EPNO_MASK; + pep = dwc->dep[DWC_EP_IN_OFS + epnum]; + + pep->xfer_len = 0; + pep->xfer_count = 0; + + if (epnum == 0) + { + REG_DIEP_SIZE(epnum) &= ~(0x1fffff); + REG_DIEP_SIZE(epnum) |= DOEPSIZE0_PKTCNT_BIT | (pep->xfer_len); // pktcnt->1 xfersize->0 + } + else + { + REG_DIEP_SIZE(epnum) &= ~(0x1FFFFFFF); + REG_DIEP_SIZE(epnum) |= DOEPSIZE0_PKTCNT_BIT | (pep->xfer_len); // pktcnt->1 xfersize->0 + } + + if (dwc->is_dma == IS_INTERN_DMA) + { +// pep->xfer_buff = (void *)0xFFFFFFFF; +// REG_DIEP_DMA(epnum) = PHYS(pep->xfer_buff); + REG_DIEP_DMA(epnum) = PHYS(0xFFFFFFFF); + REG_DIEP_CTL(epnum) |= DEP_ENA_BIT | DEP_CLEAR_NAK; + } + else + { + REG_DIEP_CTL(epnum) |= DEP_ENA_BIT | DEP_CLEAR_NAK; + } + return ; +} + + + +void dwc_handle_ep_data_out_phase(dwc_handle *dwc,uint8_t epnum) +{ + uint32_t dma_addr, dma_len; + uint32_t pktcnt; + dwc_ep *pep; + + DWC_DBG("%s %d\n",__func__,__LINE__); + DWC_DBG("epnum = %d\n",epnum); + + epnum &= DWC_EPNO_MASK; + pep = dwc->dep[DWC_EP_OUT_OFS + epnum]; + + if (epnum == 0) + { + if (dwc->is_dma == IS_INTERN_DMA) + { + dma_len = pep->maxpacket; + dma_addr = (uint32_t) (pep->xfer_buff); + rt_hw_dcache_flush_range(dma_addr,dma_len); + REG_DOEP_DMA(epnum) = PHYS(pep->xfer_buff); + } + REG_DOEP_SIZE(epnum) = DOEPSIZE0_SUPCNT_3 | DOEPSIZE0_PKTCNT_BIT | (pep->maxpacket); + REG_DOEP_CTL(epnum) |= DEP_ENA_BIT | DEP_CLEAR_NAK; + } + else + { + if (pep->xfer_len > 0) + { + if (pep->xfer_len > MAX_PKT_CNT * DEP_EP_MAXPKT(epnum)) + pep->xfer_len = MAX_PKT_CNT * DEP_EP_MAXPKT(epnum); + pktcnt = (pep->xfer_len + DEP_EP_MAXPKT(epnum) - 1) / DEP_EP_MAXPKT(epnum); + if (pktcnt > 1023) + { + DWC_DBG("WARNING...\n"); + while (1) ; + } + + REG_DOEP_SIZE(epnum) &= ~(0x1fffffff); + REG_DOEP_SIZE(epnum) |= (pktcnt << 19) | (pep->xfer_len); + } + + if (dwc->is_dma == IS_INTERN_DMA) + { + dma_len = (((pep->xfer_len + 7) >> 3) << 3); + dma_addr = (uint32_t)(pep->xfer_buff); + rt_hw_dcache_flush_range(dma_addr, dma_len); + REG_DOEP_DMA(epnum) = PHYS(pep->xfer_buff); + } + /* Program the DOEPCTLn Register with endpoint charateristics, + * and set the Endpoint Enable and Clear NAK bit */ + REG_DOEP_CTL(epnum) |= DEP_ENA_BIT | DEP_CLEAR_NAK; + } +} + +int HW_SendPKT(dwc_handle *dwc, uint8_t epnum, const uint8_t *buf, int size) +{ + uint32_t dma_addr, dma_len; + dwc_ep *pep; + rt_base_t level; + + DWC_DBG("HW_SendPKT addr = %02x,size = %d\n",epnum,size); + + epnum &= DWC_EPNO_MASK; + pep = dwc->dep[DWC_EP_IN_OFS + epnum]; + + pep->xfer_len = size; /* number of bytes to transfer */ + pep->xfer_count = 0; /* number of bytes transfered */ +// pep->xfer_buff = (uint8_t *)buf; /* pointer to transfer buffer */ + if(size > 0) + { + memcpy(pep->xfer_buff,buf,size); + rt_hw_dcache_flush_range((rt_uint32_t)pep->xfer_buff,(rt_uint32_t)size); + } + + if (pep->xfer_len > MAX_PKT_CNT * DEP_EP_MAXPKT(epnum)) + pep->xfer_len = MAX_PKT_CNT * DEP_EP_MAXPKT(epnum); + + pep->xfer_count = 0; + + switch (pep->type) + { + case DWC_OTG_EP_TYPE_CONTROL: + if (pep->xfer_len > 0) + pep->ep_state = EP_DATA; + else + pep->ep_state = EP_STATUS; + + /* 2 Stage */ + if (pep->ep_state == EP_STATUS && pep->xfer_len == 0) /*EP_SETUP 0 EP_DATA 1 EP_STATUS 2*/ + { + DWC_DBG("%s %d ep_state = %s\n", __func__, __LINE__, ep0_state_string[pep->ep_state]); + + dwc_handle_ep_status_in_phase(dwc, 0); + + return 0; + } + + /* 3 Stage */ + if (pep->ep_state == EP_DATA) + { + /* enable in data phase */ + dwc_handle_ep_data_in_phase(dwc, epnum); + } + break; + case DWC_OTG_EP_TYPE_BULK: + if (pep->ep_state == EP_IDLE || pep->ep_state == EP_TRANSFERED) + { + pep->ep_state = EP_TRANSFERING; + if (pep->xfer_len == 0) + { + dwc_handle_ep_status_in_phase(dwc, epnum); + return 0; + } + dwc_handle_ep_data_in_phase(dwc, epnum); + } + break; + } + + return pep->xfer_len; +} + +int HW_GetPKT(dwc_handle *dwc, uint8_t epnum, uint8_t *buf,int size) +{ + int i; + dwc_ep *pep; + + DWC_DBG("HW_GetPKT:%d %d\n", epnum, dwc->is_dma); + + epnum &= DWC_EPNO_MASK; + pep = dwc->dep[DWC_EP_OUT_OFS + epnum]; + + if ((size == 0) || (size > pep->xfer_count)) + size = pep->xfer_count; + + if (dwc->is_dma == IS_INTERN_DMA) + { + DWC_DBG("HW_GetPKT:%x %x \n", pep->ctrl_req_addr, UNCACHED(pep->xfer_buff)); + memcpy((uint8_t*) buf, (uint8_t *) UNCACHED(pep->xfer_buff), size); + } + else + { + memcpy((uint8_t*) buf, (uint8_t *) (pep->xfer_buff), size); + } + + return size; +} + +static void dwc_otg_flush_rx_fifo(dwc_handle *dwc) +{ + ; +} + +static void dwc_otg_flush_tx_fifo(dwc_handle *dwc,uint8_t epnum) +{ + uint32_t gintsts; + uint32_t grstctl; + uint32_t cnt; + + gintsts = REG_GINT_STS; + /* Step1: Check that GINTSTS.GinNakEff=0 if this + * bit is cleared then set Dctl.SGNPInNak = 1. + * Nak effective interrupt = H indicating the core + * is not reading from fifo*/ + if ((gintsts & GINTSTS_GINNAK_EFF)) + { + REG_OTG_DCTL |= DCTL_SGNPINNAK; + + /* Step2: wait for GINTSTS.GINNakEff=1,which indicates + * the NAK setting has taken effect to all IN endpoints */ + while (!(REG_GINT_STS & GINTSTS_GINNAK_EFF)) + udelay(1); + } + + /* Step3: wait for ahb master idle state */ + while (!(REG_GRST_CTL & RSTCTL_AHB_IDLE)) + udelay(1); + + /* Step4: Check that GrstCtl.TxFFlsh=0, if it is 0, then write + * the TxFIFO number you want to flush to GrstCTL.TxFNum*/ + grstctl = REG_GRST_CTL; + if (!(grstctl & RSTCTL_TXFIFO_FLUSH)) + { + REG_GRST_CTL |= ((epnum & 0x0F) << 6); + } + + /* Step5: Set GRSTCTL.TxFFlsh=1 and wait for it to clear */ + REG_GRST_CTL |= RSTCTL_TXFIFO_FLUSH; + + while (REG_GRST_CTL & RSTCTL_TXFIFO_FLUSH) + { + udelay(1); + } + + /* Step6: Set the DCTL.GCNPinNak bit */ + REG_OTG_DCTL |= DCTL_CLR_GNPINNAK; +} + +static void dwc_set_in_nak(dwc_handle *dwc, int epnum) +{ + int timeout = 5000; + + epnum &= DWC_EPNO_MASK; + + REG_DIEP_CTL(epnum) |= DEP_SET_NAK; + do + { + udelay(1); + if (timeout < 2) + { + DWC_DBG("dwc set in nak timeout epnum %d\n", epnum); + } + } while ((!(REG_DIEP_INT(epnum) & DEP_INEP_NAKEFF)) && (--timeout > 0)); +} + +static void dwc_set_out_nak(dwc_handle *dwc,int epnum) +{ + epnum &= DWC_EPNO_MASK; + REG_DOEP_CTL(epnum) |= DEP_SET_NAK; +} + +static void dwc_disable_in_ep(dwc_handle *dwc,int epnum) +{ + int timeout = 100000; + + epnum &= DWC_EPNO_MASK; + + if (!(REG_DIEP_CTL(epnum) & DEP_ENA_BIT)) + return ; + + /*step 1 : set nak*/ + dwc_set_in_nak(dwc,epnum); + + /*step 2: disable endpoint*/ + REG_DIEP_CTL(epnum) |= DEP_DISENA_BIT; + + do + { + udelay(1); + if (timeout < 2) + { + DWC_DBG("dwc disable in ep timeout epnum : %d\n", epnum); + } + } while ( (!(REG_DIEP_INT(epnum) & DEP_EPDIS_INT)) && (--timeout > 0)); + + REG_DIEP_INT(epnum) = DEP_EPDIS_INT; + + /*step 3: flush tx fifo*/ + dwc_otg_flush_tx_fifo(dwc, epnum); + + REG_DIEP_SIZE(epnum) = 0x0; + + /*step 4: clear nak*/ + if (epnum == 1) + REG_DIEP_CTL(1) |= DEP_CLEAR_NAK; +} + +int dwc_enable_in_ep(dwc_handle *dwc,uint8_t epnum) +{ + dwc_ep *pep = RT_NULL; + + epnum &= DWC_EPNO_MASK; + pep = dwc->dep[DWC_EP_IN_OFS + epnum]; + + + /* Program the endpoint register to configure them with the characteristics of valid endpoints */ + REG_DIEP_CTL(epnum) &= ~DEP_PKTSIZE_MASK; + REG_DIEP_CTL(epnum) &= ~DEP_TYPE_MASK; + + switch (dwc->speed) + { + case USB_SPEED_FULL: + case USB_SPEED_LOW: + REG_DIEP_CTL(epnum) |= DEP_FS_PKTSIZE; + break; + case USB_SPEED_HIGH: + REG_DIEP_CTL(epnum) |= DEP_HS_PKTSIZE; + break; + } + + //tx fifo number + REG_DIEP_CTL(epnum) |= (epnum << 22); + + //ep type + switch (pep->type) + { + case DWC_OTG_EP_TYPE_CONTROL: + REG_DIEP_CTL(epnum) |= USB_ACTIVE_EP | DEP_TYPE_CNTL; + break; + case DWC_OTG_EP_TYPE_ISOC: + REG_DIEP_CTL(epnum) |= USB_ACTIVE_EP | DEP_TYPE_ISO; + break; + case DWC_OTG_EP_TYPE_BULK: + REG_DIEP_CTL(epnum) |= USB_ACTIVE_EP | DEP_TYPE_BULK; + break; + case DWC_OTG_EP_TYPE_INTR: + REG_DIEP_CTL(epnum) |= USB_ACTIVE_EP | DEP_TYPE_INTR; + break; + } + + /* DATA0 */ + REG_DIEP_CTL(epnum) |= (1 << 28); + + /* Enable EP INT */ + REG_DAINT_MASK |= (0x01 << (DWC_EP_IN_OFS + epnum)); + + return 0; +} + +int dwc_enable_out_ep(dwc_handle *dwc,uint8_t epnum) +{ + uint32_t xfersize; + uint32_t dma_addr, dma_len, pktcnt; + dwc_ep *pep = RT_NULL; + + epnum &= DWC_EPNO_MASK; + pep = dwc->dep[DWC_EP_OUT_OFS + epnum]; + + /* Program the endpoint register to configure them with the characteristics of valid endpoints */ + REG_DOEP_CTL(epnum) &= ~DEP_PKTSIZE_MASK; + REG_DOEP_CTL(epnum) &= ~DEP_TYPE_MASK; + + switch (dwc->speed) + { + case USB_SPEED_FULL: + case USB_SPEED_LOW: + REG_DOEP_CTL(epnum) |= DEP_FS_PKTSIZE; + break; + case USB_SPEED_HIGH: + REG_DOEP_CTL(epnum) |= DEP_HS_PKTSIZE; + break; + } + + //ep type + switch (pep->type) + { + case DWC_OTG_EP_TYPE_CONTROL: + REG_DOEP_CTL(epnum) |= USB_ACTIVE_EP | DEP_TYPE_CNTL; + break; + case DWC_OTG_EP_TYPE_ISOC: + REG_DOEP_CTL(epnum) |= USB_ACTIVE_EP | DEP_TYPE_ISO; + break; + case DWC_OTG_EP_TYPE_BULK: + REG_DOEP_CTL(epnum) |= USB_ACTIVE_EP | DEP_TYPE_BULK; + break; + case DWC_OTG_EP_TYPE_INTR: + REG_DOEP_CTL(epnum) |= USB_ACTIVE_EP | DEP_TYPE_INTR; + break; + } + + /* DATA0 */ + REG_DOEP_CTL(epnum) |= (1 << 28); + + /* Enable EP INT */ + REG_DAINT_MASK |= (0x01 << (DWC_EP_OUT_OFS + epnum)); + + /* OUT-EP must init xfer buffer */ + xfersize = pep->maxpacket * 2; + pktcnt = xfersize / DEP_EP_MAXPKT(epnum); + + pep->xfer_len = xfersize; + pep->xfer_count = 0; + /* xfer_buffer has been initialized by up-layer */ +// pep->xfer_buff = pep->xfer_buff; + + DWC_DBG("%s %d xfer_buff: %x %x\n", __FUNCTION__, __LINE__, pep->xfer_buff, PHYS(pep->xfer_buff)); + + /* Program the DOEPSIZn register for the transfer size and corresponding packet count */ + REG_DOEP_SIZE(epnum) &= ~(0x1fffffff); + REG_DOEP_SIZE(epnum) = (pktcnt << 19) | xfersize; + if (dwc->is_dma == IS_INTERN_DMA) + { + dma_addr = (uint32_t) (pep->xfer_buff); + dma_len = (((xfersize + 7) >> 3) << 3); //pep->xfer_len; + rt_hw_dcache_flush_range(dma_addr, dma_len); + /* Additionally, in DMA mode, program the DOEPDMAn register */ + REG_DOEP_DMA(epnum) = PHYS(pep->xfer_buff); + } + + /* Program the DOEPCTLn Register with endpoint charateristics, + * and set the Endpoint Enable and Clear NAK bit */ + REG_DOEP_CTL(epnum) |= DEP_ENA_BIT | DEP_CLEAR_NAK; + + return 0; +} + +void dwc_set_address(dwc_handle *dwc,uint8_t address) +{ + sleep_flag = 1; + REG_OTG_DCFG &= ~DCFG_DEV_ADDR_MASK; + REG_OTG_DCFG |= address << DCFG_DEV_ADDR_BIT; +} + + +void dwc_otg_ep0_out_start(dwc_handle *dwc) +{ + dwc_ep *pep = dwc->dep[DWC_EP_OUT_OFS + 0]; + + DWC_DBG("%s %d\n",__func__,__LINE__); + pep->xfer_len = 64; + pep->xfer_count = 0; + pep->maxpacket = 64; +// pep->ctrl_req_addr = (uint32_t)(&setup_packet[0]); + pep->xfer_buff = pep->xfer_buff; + + if (dwc->is_dma == IS_INTERN_DMA) + { + REG_DOEP_SIZE(0) = DOEPSIZE0_SUPCNT_3 | DOEPSIZE0_PKTCNT_BIT | (pep->maxpacket); +// REG_DOEP_DMA(0) = PHYS(pep->ctrl_req_addr); + REG_DOEP_DMA(0) = PHYS(pep->xfer_buff); + } + else + { + REG_DOEP_SIZE(0) = DOEPSIZE0_SUPCNT_3 | DOEPSIZE0_PKTCNT_BIT | (pep->maxpacket); + } +} + +static void dwc_calculate_fifo_size(dwc_handle *dwc) +{ + /* + * TODO: we are use "Dedicated FIFO Mode with No Thresholding" + * if need thresholding, the calculation algorithm may need change + */ + + /** + * 3.2.1.1 FIFO SPRAM(Single-Port RAM) mapping: + * + * 1. One common RxFIFO, used in Host and Device modes + * 2. One common Periodic TxFIFO, used in Host mode + * 3. Separate IN endpoint transmit FIFO for each Device mode IN endpoints in Dedicated Transmit FIFO + * operation (OTG_EN_DED_TX_FIFO = 1) + * 4. The FIFO SPRAM is also used for storing some register values to save gates. In Scatter/Gather DMA + * mode, four SPRAM locations (four 35-bit words) are reserved for this. In DMA and Slave modes + * (non-Scatter/Gather mode), one SPRAM location (one 35-bit word) is used for storing the DMA epnum. + * + * NOTE: when the device is operating in Scatter/Gather mode, then the last + * locations of the SPRAM store the Base Descriptor epnum, Current + * Descriptor epnum, Current Buffer epnum and status quadlet + * information for each endpoint direction (4 locations per Endpoint). + * If an endpoint is bidirectional, then 4 locations will be used for IN, + * and another 4 for OUT + * 3.2.4.4 Endpoint Information Controller + * The last locations in the SPRAM are used to hold register values. + * Device Buffer DMA Mode: + * one location per endpoint direction is used in SPRAM to store the + * DIEPDMA and DOEPDMA value. The application writes data and then reads + * it from the same location + * For example, if there are ten bidirectional endpoints, then the last + * 20 SPRAM locations are reserved for storing the DMA epnum for IN + * and OUT endpoints + * Scatter/Gather DMA Mode: + * Four locations per endpoint direction are used in SPRAM to store the + * Base Descriptor epnum, Current Descriptor epnum, Current Buffer + * Pointer and the Status Quadlet. + * The application writes data to the base descriptor epnum. + * When the application reads the location where it wrote the base + * descriptor epnum, it receives the current descriptor epnum. + * For example, if there are ten bidirectional endpoints, then the last 80 + * locations are reserved for storing these values. + * + * Figure 3-13 + * ________________________ + * | | + * | DI/OEPDMAn Register | Depends on the value of OTG_NUM_EPS + * | and Descriptor Status | and OTG_EP_DIRn, see not above + * | values | + * ------------------------- + * | TxFIFO #n Packets | DIEPTXFn + * ------------------------- + * | | + * | ................ | + * | | + * ------------------------- + * | TxFIFO #1 Packets | DIEPTXF1 + * ------------------------- + * | TxFIFO #0 Packets | + * |( up to3 SETUP Packets)| GNPTXFSIZ + * ------------------------ + * | | + * | Rx Packets | GRXFSIZ + * | | + * ------------------------- epnum = 0, Rx starting epnum fixed to 0 + * + */ + + /** + * Rx FIFO Allocation (rx_fifo_size) + * + * RAM for SETUP Packets: 4 * n + 6 locations must be Reserved in the receive FIFO to receive up to + * n SETUP packets on control endpoints, where n is the number of control endpoints the device + * core supports. + * + * One location for Global OUT NAK + * + * Status information is written to the FIFO along with each received packet. Therefore, a minimum + * space of (Largest Packet Size / 4) + 1 must be allotted to receive packets. If a high-bandwidth + * endpoint is enabled, or multiple isochronous endpoints are enabled, then at least two (Largest + * Packet Size / 4) + 1 spaces must be allotted to receive back-to-back packets. Typically, two + * (Largest Packet Size / 4) + 1 spaces are recommended so that when the previous packet is being + * transferred to AHB, the USB can receive the subsequent packet. If AHB latency is high, you must + * allocate enough space to receive multiple packets. This is critical to prevent dropping of any + * isochronous packets. + * + * Typically, one location for each OUT endpoint is recommended. + * + * one location for eatch endpoint for EPDisable is required + */ + + /** + * Tx FIFO Allocation (tx_fifo_size[n]) + * + * The minimum RAM space required for each IN Endpoint Transmit FIFO is the maximum packet size + * for that particular IN endpoint. + * + * More space allocated in the transmit IN Endpoint FIFO results in a better performance on the USB + *and can hide latencies on the AHB. + */ + uint32_t rx_fifo_size, i; + uint32_t np_txfifo_size = 0; + uint32_t tx_fifo_size; + uint16_t startaddr; + uint16_t fifocfg; + const int x = 1; + + /* Step1: Recevice FIFO Size Register (GRXFSIZ) */ + rx_fifo_size = (4 * 1 + 6) + (2) * (1024 / 4 + 1) + (2 * dwc->hwcfg2.b.num_dev_ep) + 1; + + REG_GRXFIFO_SIZE = rx_fifo_size; + + /* Step2: Program device in ep transmit fifo0 size register (GNPTXFSIZ) */ + np_txfifo_size |= ((1 + 1) * (64 / 4) << 16); //depth + np_txfifo_size |= rx_fifo_size; //startaddr + REG_GNPTXFIFO_SIZE = np_txfifo_size; + +#define DWC_TX_FIFO_SIZE ((1 + 1) * (512 / 4)) + + startaddr = ((1 + 1) * (64 / 4) << 16) + rx_fifo_size; + for (i=1; ihwcfg4.b.num_in_eps; i++) + { + tx_fifo_size |= (DWC_TX_FIFO_SIZE << 16) | startaddr; + REG_GDIEP_TXF(i) = tx_fifo_size; + startaddr += DWC_TX_FIFO_SIZE; + } + + /* Configure fifo start addr and depth for endpoint information controller */ + REG_GDFIFO_CFG |= startaddr << 16; + fifocfg = REG_GHW_CFG3; + fifocfg = (fifocfg >> 16); + REG_GDFIFO_CFG |= fifocfg; + /* flush tx and rx fifo */ + dwc_otg_flush_rx_fifo(dwc); + + dwc_otg_flush_tx_fifo(dwc,0x10); + +} + + + + +static void dwc_handle_enum_done_intr(dwc_handle *dwc) +{ + dwc_ep *pep = dwc->dep[0]; + + /* Step1: Read the DSTS register to determine the enumeration speed */ + uint32_t dsts = REG_OTG_DSTS; + uint32_t diep0ctl = REG_DIEP_CTL(0); + diep0ctl &= ~(0x3); + + switch (dsts & DSTS_ENUM_SPEED_MASK) + { + case DSTS_ENUM_SPEED_HIGH: + DWC_DBG("High speed.\n"); + dwc->speed = USB_SPEED_HIGH; + pep->maxpacket = 64; + diep0ctl |= DEP_EP0_MPS_64; + REG_OTG_DCFG &= ~1; + break; + case DSTS_ENUM_SPEED_FULL_30OR60: + case DSTS_ENUM_SPEED_FULL_48: + DWC_DBG("Full speed.\n"); + dwc->speed = USB_SPEED_FULL; + pep->maxpacket = 64; + diep0ctl |= DEP_EP0_MPS_64; + REG_OTG_DCFG |= 1; + break; + case DSTS_ENUM_SPEED_LOW: + DWC_DBG("Low speed.\n"); + dwc->speed = USB_SPEED_LOW; + pep->maxpacket = 8; + diep0ctl |= DEP_EP0_MPS_8; + break; + default: + DWC_DBG("Fault speed enumration\n"); + break; + } + REG_OTG_DCTL |= DCTL_CLR_GNPINNAK; + + /* Step2: Program the DIEPCTL0.MPS to set the maximum packet size */ + REG_DIEP_CTL(0) = diep0ctl; + + /* Step3: In Dma mode program the DOEPCTL0 register + * to enable control ouctrl_req_addrt endpoint0 to receive setup + * packet .*/ +// dwc_otg_ep0_out_start(dwc); + if (dwc->is_dma == IS_INTERN_DMA) + { + rt_hw_dcache_flush_all(); + DWC_DBG("0 doepsize %x ctl %x\n", REG_DOEP_SIZE(0), REG_DOEP_CTL(0)); + REG_DOEP_CTL(0) |= DEP_ENA_BIT | DEP_CLEAR_NAK; + } + else + { + REG_DOEP_CTL(0) |= DEP_ENA_BIT | DEP_CLEAR_NAK; + } + + /* Step4: unmask the SOF interrupt */ + REG_GINT_MASK |= GINTMSK_START_FRAM; + + REG_GINT_STS = GINTSTS_ENUM_DONE; + // dump_global_dwcreg(); + return; +} + +static void dwc_handle_early_suspend_intr(dwc_handle *dwc) +{ + DWC_DBG("Handle early suspend intr.\n"); + + REG_GINT_STS = GINTSTS_USB_EARLYSUSPEND; + + if (REG_OTG_DSTS & DSTS_ERRATIC_ERROR) + { + REG_OTG_DCTL |= DCTL_SOFT_DISCONN; + mdelay(100); + dwc_otg_core_reset(dwc); + dwc_otg_core_init(dwc,1); + dwc_otg_device_init(dwc); + dwc_calculate_fifo_size(dwc); + } +} + +static void dwc_handle_suspend_intr(dwc_handle *dwc) +{ + DWC_DBG("Handle suspend intr.\n"); + REG_GINT_STS = GINTSTS_USB_SUSPEND; + DWC_DBG("==>%s,sleep_flag = %d\n",__func__,sleep_flag); +#if 0 + if(sleep_flag) + { + while(!(REG_OTG_DSTS & 1)) + { + printf("REG_OTG_DSTS is 0x%x\n",REG_OTG_DSTS); + } + sleep_flag = 0; + enable_irq(IRQ_OTG); + jz_pm_sleep(); + } +#endif +} + +static void dwc_handle_start_frame_intr(dwc_handle *dwc) +{ + REG_GINT_STS = GINTSTS_START_FRAM; +} + +static void dwc_handle_reset_intr(dwc_handle *dwc) +{ + int i; + + /* Step1: NAK OUT ep */ + for (i=0; ihwcfg2.b.num_dev_ep; i++) + { + REG_DOEP_CTL(i) |= DEP_SET_NAK; + } + + /* Step2: unmask the following interrupt bits */ + REG_DAINT_MASK = 0; + REG_DOEP_MASK = 0; + REG_DIEP_MASK = 0; + + REG_DAINT_MASK |= (1 << 0) | (1 << 16); //inep0 outep0 + REG_DOEP_MASK |= DEP_XFER_COMP | DEP_SETUP_PHASE_DONE | DEP_AHB_ERR; // xfercompl setupdone + REG_DIEP_MASK |= DEP_XFER_COMP | DEP_TIME_OUT | DEP_AHB_ERR; // xfercompl ahberr timeout + + dwc->dep[0]->ep_state = EP_SETUP; + + /* Step3: Device initalization */ + dwc_otg_device_init(dwc); + + /* Step4: Set up the data fifo ram for each of the fifo */ + //dwc_calculate_fifo_size(); + + /* Step5: Reset Device Address */ + REG_OTG_DCFG &= (~DCFG_DEV_ADDR_MASK); + + /* Step6: setup EP0 to receive SETUP packets */ + dwc_otg_ep0_out_start(dwc); + if (dwc->is_dma == IS_INTERN_DMA) + { + rt_hw_dcache_flush_all(); + REG_DOEP_CTL(0) |= DEP_ENA_BIT | DEP_CLEAR_NAK; + } + else + { + REG_DOEP_CTL(0) |= DEP_ENA_BIT | DEP_CLEAR_NAK; + } + dwc_disable_in_ep(dwc,0); + + REG_GINT_STS = GINTSTS_USB_RESET; + + return; +} + +void dwc_handle_rxfifo_nempty(dwc_handle *dwc) +{ + dwc_ep *pep; + uint32_t *setup_buf; + uint32_t count; + uint32_t rxsts_pop = REG_GRXSTS_POP; + uint8_t epnum = (rxsts_pop & 0xf); + + switch (rxsts_pop & GRXSTSP_PKSTS_MASK) + { + case GRXSTSP_PKSTS_GOUT_NAK: + DWC_DBG("GRXSTSP_PKSTS_GOUT_NAK.\n"); + break; + case GRXSTSP_PKSTS_GOUT_RECV: + DWC_DBG("GRXSTSP_PKSTS_GOUT_RECV. - "); + + count = (rxsts_pop & GRXSTSP_BYTE_CNT_MASK) >> GRXSTSP_BYTE_CNT_BIT; + if (count) + { + DWC_DBG("count:%d\n", count); + dwc_read_ep_packet(dwc,epnum, count); + } + + break; + case GRXSTSP_PKSTS_TX_COMP: + DWC_DBG("GRXSTSP_PKSTS_TX_COMP.\n"); + break; + case GRXSTSP_PKSTS_SETUP_COMP: + DWC_DBG("GRXSTSP_PKSTS_SETUP_COMP.\n"); + break; + case GRXSTSP_PKSTS_SETUP_RECV: + DWC_DBG("GRXSTSP_PKSTS_SETUP_RECV. - "); +// setup_packet[0] = REG_EP_FIFO(0); +// setup_packet[1] = REG_EP_FIFO(0); +// DWC_DBG("%x %x\n", setup_packet[0], setup_packet[1]); + ((uint8_t *)dwc->dep[0]->xfer_buff)[0] = REG_EP_FIFO(0); + ((uint8_t *)dwc->dep[0]->xfer_buff)[1] = REG_EP_FIFO(1); + DWC_DBG("%x %x\n", ((uint8_t *)dwc->dep[0]->xfer_buff)[0], ((uint8_t *)dwc->dep[0]->xfer_buff)[1]); + break; + default: + break; + } + REG_GINT_STS = GINTSTS_RXFIFO_NEMPTY; +} + + +void dwc_ep0_in_intr(dwc_handle *dwc, uint8_t epnum) +{ + uint32_t updated_size; + uint32_t dma_addr, dma_len; + uint8_t *ptr; + uint32_t intr = REG_DIEP_INT(epnum & 0x0F); + dwc_ep *pep ; + + DWC_DBG("ep0 in intr:%x\n", intr); + + epnum &= DWC_EPNO_MASK; + pep = dwc->dep[DWC_EP_IN_OFS + epnum]; + udelay(1); + + /* When the transfer size if 0 and the packet count is 0, + * the transfer complete interrupt for the endpoint is generated + * and the endpoint enable is cleared */ + if (intr & DEP_XFER_COMP) + { + DWC_DBG("XFER_COMP\n"); + REG_DIEP_INT(epnum) = DEP_XFER_COMP; // clear int + if (dwc->is_dma == IS_SLAVE_MODE) + REG_DIEP_EMPMSK &= ~(1 << epnum); + + updated_size = (REG_DIEP_SIZE(epnum) & 0x7f); + pep->xfer_count = pep->xfer_len - updated_size; // number of bytes transfered + DWC_DBG("in xfer_count:%d xfer_len:%d updated_size:%d\n", pep->xfer_count, pep->xfer_len, updated_size); + + if (pep->xfer_count != pep->xfer_len) + { + DWC_DBG("in xfer_count:%d xfer_len:%d updated_size:%d\n", pep->xfer_count, pep->xfer_len, updated_size); + pep->xfer_len -= pep->xfer_count; + ptr = (uint8_t *)pep->xfer_buff + pep->xfer_count; + HW_SendPKT(dwc, 0, ptr, pep->xfer_len); + return; + } + + DWC_DBG("pep->ep_state = %s\n",ep0_state_string[pep->ep_state]); + + switch(pep->ep_state) + { + case EP_DATA: +#if 1 + /* 3 Stage */ + if(pep->xfer_len == pep->maxpacket) + { + x1000_usbd_event_cb(0, USB_EVT_IN, RT_NULL); + } + else +#endif + { + pep->ep_state = EP_STATUS; + dwc_handle_ep_data_out_phase(dwc,0); + } + break; + case EP_STATUS: + pep->ep_state = EP_SETUP; + dwc_handle_ep_data_out_phase(dwc,0); + break; + } + } + + if (dwc->is_dma == IS_SLAVE_MODE) + { + if ((intr & DEP_TXFIFO_EMPTY) && (REG_DIEP_EMPMSK & (1 << epnum))) + { + if (pep->xfer_len) + { + dwc_write_ep_packet(dwc,epnum); + } + REG_DIEP_INT(epnum) = DEP_TXFIFO_EMPTY; + } + } + + if (intr & DEP_AHB_ERR) + { + DWC_DBG("1 AHB ERR\n"); + REG_DIEP_INT(epnum) = DEP_AHB_ERR; + } + + + if (intr & DEP_TIME_OUT) + { + DWC_DBG("IN TIME_OUT.\n"); + REG_DIEP_INT(epnum) = DEP_TIME_OUT; + } +} + +void dwc_epn_in_intr(dwc_handle *dwc, uint8_t epnum) +{ + uint32_t intr = REG_DIEP_INT(epnum & 0x0F); + uint32_t updated_size; + + /* When the transfer size if 0 and the packet count is 0, + * the transfer complete interrupt for the endpoint is generated + * and the endpoint enable is cleared */ + dwc_ep *pep; + + epnum &= DWC_EPNO_MASK; + pep = dwc->dep[DWC_EP_IN_OFS + epnum]; + + if (intr & DEP_XFER_COMP) + { + DWC_DBG("1 IN XFER_COMP. %x\n", REG_DIEP_SIZE(epnum)); + REG_DIEP_INT(epnum) = DEP_XFER_COMP; + REG_DIEP_CTL(epnum) |= DEP_SET_NAK; + if (pep->ep_state == EP_TRANSFERING) + { + if (dwc->is_dma == IS_SLAVE_MODE) + REG_DIEP_EMPMSK &= ~(1 << epnum); + updated_size = (REG_DIEP_SIZE(epnum) & 0x7ffff); + pep->xfer_count = pep->xfer_len - updated_size; + pep->ep_state = EP_TRANSFERED; + +// rt_kprintf("updated_size = %d,xfer_len = %d,xfer_count = %d\n",updated_size,pep->xfer_len, pep->xfer_count); +// BusNotify(arg, UDC_PROTAL_SEND_FINISH, NULL, 0); + x1000_usbd_event_cb(epnum,USB_EVT_IN,0); + } + } + if (dwc->is_dma == IS_SLAVE_MODE) + { + if ((intr & DEP_TXFIFO_EMPTY) && (REG_DIEP_EMPMSK & (1 << epnum))) + { + REG_DIEP_EMPMSK &= ~(1 << epnum); +// DWC_DBG("TX FIFO EMPTY intr.\n"); + if (pep->xfer_len) + { + dwc_write_ep_packet(dwc,epnum); + } + REG_DIEP_INT(epnum) = DEP_TXFIFO_EMPTY; + } + } + if (intr & DEP_AHB_ERR) + { + DWC_DBG("1 AHB ERR\n"); + REG_DIEP_INT(epnum) = DEP_AHB_ERR; + } + + if (intr & DEP_TIME_OUT) + { + DWC_DBG("IN TIME_OUT.\n"); + REG_DIEP_INT(epnum) = DEP_TIME_OUT; + } +} + +/* + * ep0 control transfer: + * 3 Stage: + * SetupPhase-------->IN DataPhase ---------> OUT StatusPhase + * Or 2 Stage: + * SetupPhase-------->IN StatusPhase + * */ + +typedef struct { + u8 bmRequestType; + u8 bRequest; + u16 wValue; + u16 wIndex; + u16 wLength; +} __attribute__ ((packed)) dwc_DeviceRequest; + +int dwc_ep0_out_intr(dwc_handle *dwc, uint8_t epnum) +{ + uint32_t intr, doep0size, dma_addr, dma_len; + uint8_t rem_supcnt, xfersize; + + dwc_ep *pep = RT_NULL; + + epnum &= DWC_EPNO_MASK; + pep = dwc->dep[DWC_EP_OUT_OFS + epnum]; + + intr = REG_DOEP_INT(epnum); +// printf("ep0 out intr:%x\n", intr); + udelay(1); + + /* comp intrerrupt indeicates completion of the status out phase */ + if (intr & DEP_XFER_COMP) + { + REG_DOEP_INT(epnum) = DEP_XFER_COMP; + + DWC_DBG("pep->ep_state = %s\n",ep0_state_string[pep->ep_state]); + + if (pep->ep_state == EP_STATUS) + { + pep->ep_state = EP_SETUP; + dwc_handle_ep_data_out_phase(dwc,0); + } + else if (pep->ep_state == EP_DATA) + { + DWC_DBG("*** EP0 DATA ***\n"); + pep->xfer_count = pep->maxpacket - (REG_DOEP_SIZE(epnum) & 0x7ffff); + DWC_DBG("pep->xfer_count = %d\n",pep->xfer_count); + x1000_usbd_event_cb(0,USB_EVT_OUT,0); + } + else if (!(intr & (DEP_SETUP_PHASE_DONE | (1 << 15)))) + { + DWC_DBG("error\n"); + pep->ep_state = EP_SETUP; + dwc_handle_ep_data_out_phase(dwc, epnum); + } + else if (pep->ep_state != EP_SETUP) + { + DWC_DBG("ep0 state mismatch\n"); + } + } + + //IN Token + if (intr & DEP_INTOKEN_EPMISATCH) + { + if (pep->ep_state == EP_DATA) + { + pep->ep_state = EP_STATUS; + dwc_handle_ep_status_in_phase(dwc, epnum); + } + REG_DOEP_INT(epnum) = DEP_INTOKEN_EPMISATCH; + } + + if (intr & DEP_AHB_ERR) + { + DWC_DBG("AHB ERR\n"); + REG_DOEP_INT(0) = DEP_AHB_ERR; + } + + if (intr & DEP_NAK_INT) + { + REG_DOEP_INT(0) = DEP_NAK_INT; + } + + if (intr & (DEP_SETUP_PHASE_DONE | (1 << 15))) + { + DWC_DBG("SETUP_PHASE_DONE.\n"); + + /* read the DOEPTSIZn to determine the number of setup packets + * recevied and process the last recevied setup packet */ + REG_DOEP_INT(epnum) = DEP_SETUP_PHASE_DONE | (1 << 15); + + doep0size = REG_DOEP_SIZE(epnum); + xfersize = doep0size & 0x7ffff; + rem_supcnt = (doep0size & (0x3 << 29)) >> 29; + DWC_DBG("xfersize = %d,rem_supcnt = %d\n",xfersize,rem_supcnt); + + if (intr & DEP_B2B_SETUP_RECV) + { + DWC_DBG("back to back setup recevie\n"); + } + else + { + /* Read out the last packet from the rxfifo */ +// rt_hw_dcache_invalidate_range((uint32_t)(pep->ctrl_req_addr), sizeof(dwc_DeviceRequest)); + rt_hw_dcache_invalidate_range((uint32_t)(pep->xfer_buff), sizeof(dwc_DeviceRequest)); +#if 0 + { + dwc_DeviceRequest* device_req = (dwc_DeviceRequest *)(pep->ctrl_req_addr); + rt_kprintf("\n-------------\n"); + rt_kprintf("bRequest: %x\n", device_req->bRequest); + rt_kprintf("bRequestType: %x\n", device_req->bmRequestType); + rt_kprintf("wIndex: %x\n", device_req->wIndex); + rt_kprintf("wLength: %x\n", device_req->wLength); + rt_kprintf("wValue: %x\n", device_req->wValue); + rt_kprintf("-------------\n"); + } +#endif + + /* At the end of the Setup stage, the appliaction must reporgram the + * DOEPTSIZn.SUPCnt field to 3 receive the next SETUP packet */ + if (pep->ep_state == EP_SETUP) + { + if (dwc->is_dma == 2) + { + //printf("1 doepsize %x ctl %x\n", REG_DOEP_SIZE(0), REG_DOEP_CTL(0)); + REG_DOEP_SIZE(epnum) = DOEPSIZE0_SUPCNT_3 | DOEPSIZE0_PKTCNT_BIT | (pep->maxpacket); +// REG_DOEP_DMA(epnum) = PHYS(pep->ctrl_req_addr); + REG_DOEP_DMA(epnum) = PHYS(pep->xfer_buff); + } + else + { + REG_DOEP_SIZE(epnum) = DOEPSIZE0_SUPCNT_3 | DOEPSIZE0_PKTCNT_BIT | (pep->maxpacket); + } + } + + + /* Setup Finish */ + pep->xfer_count = sizeof(dwc_DeviceRequest); +// pep->xfer_buff = (void *) (pep->ctrl_req_addr); +// x1000_usbd_event_cb(0, USB_EVT_SETUP, (void *) (pep->ctrl_req_addr)); + x1000_usbd_event_cb(0, USB_EVT_SETUP, pep->xfer_buff); + + REG_DOEP_CTL(epnum) |= DEP_DISENA_BIT; +// REG_DOEP_CTL(epnum) |= DEP_SET_NAK; + } + } + return 0; +} + +int dwc_epn_out_intr(dwc_handle *dwc, uint8_t epnum) +{ + uint32_t intr, updated_size; + dwc_ep *pep ; + + epnum &= DWC_EPNO_MASK; + pep = dwc->dep[DWC_EP_OUT_OFS + epnum]; + udelay(1); + DWC_DBG("ep%d out_intr\n",epnum); + + intr = REG_DOEP_INT(epnum); + if (intr & DEP_XFER_COMP) + { + REG_DOEP_INT(epnum) = DEP_XFER_COMP; + updated_size = REG_DOEP_SIZE(epnum) & 0x7ffff; + pep->xfer_count = pep->xfer_len - updated_size; + + DWC_DBG("xfer_count = %d\n",pep->xfer_count); +// BusNotify((uint32_t)arg,UDC_PROTAL_RECEIVE_FINISH, (uint8_t *)pep->xfer_buff, pep->xfer_count); + x1000_usbd_event_cb(epnum,USB_EVT_OUT,0); + +#if 0 + pep->xfer_len = pep->maxpacket; /* number of bytes to transfer */ + pep->xfer_count = 0; /* number of bytes transfered */ +// pep->xfer_buff = pep->xfer_buff; /* pointer to transfer buffer */ + dwc_handle_ep_data_out_phase(dwc, epnum); + DWC_DBG("REG_DOEP_SIZE: %x \n", REG_DOEP_SIZE(epnum)); +#endif + } + + if (intr & DEP_AHB_ERR) + { + DWC_DBG("1 AHB ERR\n"); + REG_DOEP_INT(epnum) = DEP_AHB_ERR; + } + return 0; +} + +static void dwc_handle_inep_intr(dwc_handle *dwc) +{ + uint32_t ep_intr; + uint8_t epnum = 0; + + ep_intr = (REG_OTG_DAINT & 0xffff); + DWC_DBG("\n\nEp IN %x - \n", ep_intr); + + while (ep_intr) + { + if (ep_intr & 0x01) + { + if (epnum == 0) + { + dwc_ep0_in_intr(dwc, epnum); + } + else + { + dwc_epn_in_intr(dwc, epnum); + } + } + epnum++; + ep_intr >>= 1; + } + REG_GINT_STS = GINTSTS_IEP_INTR; + return ; +} + +static void dwc_handle_outep_intr(dwc_handle *dwc) +{ + uint32_t ep_intr, epnum = 0; + ep_intr = (REG_OTG_DAINT & 0xffff0000) >> 16; + DWC_DBG("\n\nEp OUT %x - \n", ep_intr); + while (ep_intr) + { + if (ep_intr & 0x01) + { + if (epnum == 0) + { + dwc_ep0_out_intr(dwc, 0); + } + else + { + dwc_epn_out_intr(dwc, epnum); + } + } + epnum ++; + ep_intr >>= 1; + } + REG_GINT_STS = GINTSTS_OEP_INTR; +} + +static void dwc_otg_intr(dwc_handle *dwc) +{ + REG_GINT_STS = GINTSTS_OTG_INTR; +} + +void dwc_common_intr(dwc_handle *dwc,uint32_t intsts) +{ + if (intsts & GINTSTS_USB_EARLYSUSPEND) + { + dwc_handle_early_suspend_intr(dwc); + } + + if (intsts & GINTSTS_USB_SUSPEND) + { + dwc_handle_suspend_intr(dwc); + } + + if (intsts & GINTSTS_USB_RESET) + { + dwc_handle_reset_intr(dwc); + } + + if (intsts & GINTSTS_ENUM_DONE) + { + dwc_handle_enum_done_intr(dwc); + } + + if (intsts & GINTSTS_START_FRAM) + { + dwc_handle_start_frame_intr(dwc); + } +} + +void dwc_handle_resume_intr(dwc_handle *dwc) +{ + DWC_DBG("Handle resume intr.\n"); + REG_GINT_STS = GINTSTS_RSUME_DETE; + +// dwc_otg_phy_suspend(0); +} + +static void dwc_irq_handler(int vector,void *arg) +{ + dwc_handle *dwc = (dwc_handle *)arg; + + RT_ASSERT(dwc != RT_NULL); + + rt_hw_interrupt_mask(IRQ_OTG); + + rt_sem_release(dwc->isr_sem); +} + +static void dwc_otg_core_reset(dwc_handle *dwc) +{ + uint32_t greset = 0; + uint32_t cnt = 0; + + REG_GRST_CTL |= RSTCTL_CORE_RST; + do + { + greset = REG_GRST_CTL; + if (cnt++ > 100000) + { + DWC_DBG("GRESET wait reset timeout.\n"); + return; + } + udelay(10); + } while (greset & RSTCTL_CORE_RST); + + cnt = 0; + + do + { + udelay(10); + greset = REG_GRST_CTL; + if (cnt++ > 100000) + { + DWC_DBG("GRESET wait IDLE timeout.\n"); + return; + } + } while ((greset & RSTCTL_AHB_IDLE) == 0); + + /* wait for 3 phy clocks */ + udelay(100); +} + +static int dwc_otg_phy_is_suspend(void) +{ + return (!(cpm_test_bit(7, CPM_OPCR))); +} + +static void dwc_otg_phy_suspend(int suspend) +{ + if (!suspend && dwc_otg_phy_is_suspend()) + { + DWC_DBG("EN PHY\n"); + cpm_set_bit(7, CPM_OPCR); + udelay(45); + } + else if (suspend && !dwc_otg_phy_is_suspend()) + { + DWC_DBG("DIS PHY\n"); + cpm_clear_bit(7, CPM_OPCR); + udelay(5); + } +} + +static void dwc_otg_device_init(dwc_handle *dwc) +{ + uint32_t dcfg = 0; + uint32_t pcgcctl; + uint32_t rx_fifo_size; + + /* Restart the phy clock */ + if (REG_PCGC_CTL & 0x1) + { + DWC_DBG("<<<<<< pcgcctl %x >>>>>\n", REG_PCGC_CTL); + REG_PCGC_CTL &= ~(0x1 | (1 << 2) | (1 << 3)); + } + + /* In dma mode GINTMSK_NPTXFIFO_EMPTY , GINTMSK_RXFIFO_NEMPTY must be masked*/ + if (dwc->is_dma == IS_INTERN_DMA) + { + if (REG_GINT_MASK & (GINTMSK_NPTXFIFO_EMPTY | GINTMSK_RXFIFO_NEMPTY)) + { + REG_GINT_MASK &= ~(GINTMSK_NPTXFIFO_EMPTY | GINTMSK_RXFIFO_NEMPTY); + } + } + else + { + REG_GINT_MASK |= (GINTMSK_NPTXFIFO_EMPTY | GINTMSK_RXFIFO_NEMPTY); + } + + /* Program the DCFG register */ + if (dwc->hwcfg4.b.desc_dma) + { + dcfg |= DCFG_DEV_DESC_DMA; + } + +#if DWC_FORCE_SPEED_FULL + REG_OTG_DCFG |= 1; //dma buffer mode full speed +#else + REG_OTG_DCFG &= ~3; //dma buffer mode HIGH speed +#endif + + /* Clear the DCTL.SftDiscon bit the core issues aconnect after ths bit is cleared */ + REG_OTG_DCTL &= ~DCTL_SOFT_DISCONN; + + REG_GINT_STS = 0xffffffff; + /* Program the GINTMSK */ + REG_GINT_MASK |= GINTMSK_IEP_INTR | GINTMSK_OEP_INTR |GINTMSK_USB_RESET | GINTMSK_ENUM_DONE |GINTMSK_USB_EARLYSUSPEND | GINTMSK_USB_SUSPEND | (1 << 31); +} + +static void dwc_otg_core_init(dwc_handle *dwc,uint8_t dma_enable) +{ + uint32_t ahbcfg = 0, gusbcfg = 0, curmod = 0, tmp; + uint8_t arch; + + DWC_DBG("Core Init...\n"); + /* Step1: Read the GHWCFG1,2,3,4 to find the configuration parameters selected for DWC_otg core */ + dwc->hwcfg1.d32 = REG_GHW_CFG1; + dwc->hwcfg2.d32 = REG_GHW_CFG2; + dwc->hwcfg3.d32 = REG_GHW_CFG3; + dwc->hwcfg4.d32 = REG_GHW_CFG4; + + DWC_DBG("cfg1:%x 2:%x 3:%x 4:%x\n", dwc->hwcfg1, dwc->hwcfg2, dwc->hwcfg3, dwc->hwcfg4); + DWC_DBG("cfg2->arch %x\n", dwc->hwcfg2.b.architecture); + arch = dwc->hwcfg2.b.architecture; + switch (arch) + { + case IS_SLAVE_MODE: + dwc->is_dma = IS_SLAVE_MODE; + break; + case IS_EXTERN_DMA: + dwc->is_dma = IS_EXTERN_DMA; + break; + case IS_INTERN_DMA: + dwc->is_dma = IS_INTERN_DMA; + break; + } + /* Step2: Program the GAHBCFG register */ + + /* DMA Mode bit and Burst Length */ + if (dwc->is_dma == IS_EXTERN_DMA) + { + DWC_DBG("DWC IS_EXTERN_DMA\n"); + ahbcfg |= AHBCFG_DMA_ENA; + } + else if (dwc->is_dma == IS_INTERN_DMA) + { + if (dma_enable) + { + DWC_DBG("DWC IS_INTERN_DMA\n"); + ahbcfg |= AHBCFG_DMA_ENA | (DWC_GAHBCFG_INT_DMA_BURST_INCR16 << 1); + } + else + { + ahbcfg |= AHBCFG_TXFE_LVL; + dwc->is_dma = 0; + } + } + else + { + DWC_DBG("DWC IS_SLAVE_MODE\n"); + } + + /* Step3: Program the GINTMSK register */ + REG_GINT_MASK = 0; + + /* Step4: Program the GUSBCFG register */ + gusbcfg = REG_GUSB_CFG; + + gusbcfg &= ~((1 << 4) | (1 << 6) | (1 << 8) | (1 << 9)); + REG_GUSB_CFG = gusbcfg; // HNP SRP not support and select UTMI+ + dwc_otg_select_phy_width(dwc); + + dwc_otg_core_reset(dwc); + + /* Global Interrupt Mask bit = 1 */ + ahbcfg |= AHBCFG_GLOBLE_INTRMASK; + REG_GAHB_CFG = ahbcfg; + + /* Step5: The software must unmask OTG Interrupt Mask bit , + * MOde mismatch interrupt Mask bit in the GINTMSK */ + REG_GINT_MASK |= (GINTMSK_MODE_MISMATCH | GINTMSK_OTG_INTR); +} + + +int dwc_set_config(dwc_handle *dwc) +{ + return 0; +} + +int dwc_set_ep_stall(dwc_handle *dwc,uint8_t epnum) +{ + depctl_data_t depctl; + daint_data_t daintmsk; + dwc_ep *pep = RT_NULL; + + if(epnum & USB_DIR_IN) + { + pep = dwc->dep[epnum & 0x0F + DWC_EP_IN_OFS]; + } + else + { + pep = dwc->dep[epnum & 0x0F + DWC_EP_OUT_OFS]; + } + epnum &= DWC_EPNO_MASK; + + if (pep->is_in) + { + depctl.d32 = REG_DIEP_CTL(epnum); + depctl.b.stall = 1; + REG_DIEP_CTL(epnum) = depctl.d32; + } + else + { + depctl.d32 = REG_DOEP_CTL(epnum); + depctl.b.stall = 1; + REG_DOEP_CTL(epnum) = depctl.d32; + } + + return 0; +} + +int dwc_clr_ep_stall(dwc_handle *dwc,uint8_t epnum) +{ + depctl_data_t depctl; + daint_data_t daintmsk; + dwc_ep *pep = RT_NULL; + if(epnum & USB_DIR_IN) + { + pep = dwc->dep[epnum & 0x0F + DWC_EP_IN_OFS]; + } + else + { + pep = dwc->dep[epnum & 0x0F + DWC_EP_OUT_OFS]; + } + epnum &= DWC_EPNO_MASK; + + if (pep->is_in) + { + depctl.d32 = REG_DIEP_CTL(epnum); + depctl.b.stall = 0; + REG_DIEP_CTL(epnum) = depctl.d32; + } + else + { + depctl.d32 = REG_DOEP_CTL(epnum); + depctl.b.stall = 0; + REG_DOEP_CTL(epnum) = depctl.d32; + } + + return 0; +} + + + +int dwc_ep_disable(dwc_handle *dwc,uint8_t epnum) +{ + depctl_data_t depctl; + daint_data_t daintmsk; + dwc_ep *pep = RT_NULL; + + DWC_DBG("%s epnum = %02x \n",epnum); + + if(epnum & USB_DIR_IN) + { + pep = dwc->dep[epnum & 0x0F + DWC_EP_IN_OFS]; + } + else + { + pep = dwc->dep[epnum & 0x0F + DWC_EP_OUT_OFS]; + } + epnum &= DWC_EPNO_MASK; + + /* EP0 can not deactivate! */ + if (epnum == 0) + return -1; + + daintmsk.d32 = REG_DAINT_MASK; + if (pep->is_in) + { + depctl.d32 = REG_DIEP_CTL(epnum); + daintmsk.ep.in &= ~(1 << epnum); + } + else + { + depctl.d32 = REG_DOEP_CTL(epnum); + daintmsk.ep.out &= ~(1 << epnum); + } + if (!depctl.b.usbactep) + { + DWC_DBG("EP %d already deactivated\n", pep->num); + return 0; + } + + depctl.b.usbactep = 0; + if (pep->is_in) + { + REG_DIEP_CTL(epnum) = depctl.d32; + } + else + { + REG_DOEP_CTL(epnum) = depctl.d32; + } + + /* mask EP interrupts */ + REG_DAINT_MASK = daintmsk.d32; + + if(pep->is_in) + {/* Disable IN-EP */ + + } + else + { + /* Disable IN-EP */ + } + + DWC_DBG("EP %d deactivated\n", pep->num); + return 0; +} + + +static void x1000_usb_phy_switch(dwc_handle *dwc,uint8_t is_on) +{ + uint32_t value; + if (is_on) + { + value = REG_CPM_OPCR; + REG_CPM_OPCR |= OPCR_OTGPHY0_ENABLE; + mdelay(1); + } + else + { + value = REG_CPM_OPCR; + REG_CPM_OPCR &= ~OPCR_OTGPHY0_ENABLE; + + mdelay(1); + } +} + +static void x1000_usb_set_device_only_mode(dwc_handle *dwc) +{ + REG_CPM_USBPCR &= ~USBPCR_USB_MODE; + REG_CPM_USBPCR &= ~USBPCR_OTG_DISABLE; +} + +static void x1000_usb_phy_init(dwc_handle *dwc) +{ + REG_CPM_USBPCR |= USBPCR_POR; + mdelay(1); + + REG_CPM_USBPCR &= ~USBPCR_POR; + mdelay(1); +} + + + +/* usb device init */ +static void dwc_gadget_init(dwc_handle *dwc) +{ + uint32_t curmod; + int err; + // REG_CPM_CLKGR0 &= ~(1 << 2); + + rt_hw_interrupt_mask(IRQ_OTG); + + /* usb_cpm_init(); */ + { + uint32_t ref_clk_div = 24 / 24; //24 / 24; + uint32_t usbpcr1; + + /* select dwc otg */ + REG_CPM_USBPCR1 |= USBPCR1_USB_SEL; + + /* select utmi data bus width of port0 to 16bit/30M */ + REG_CPM_USBPCR1 |= USBPCR1_WORD_IF0; + + usbpcr1 = REG_CPM_USBPCR1; + usbpcr1 &= ~(0x3 << 24); + usbpcr1 |= (ref_clk_div << 24); + REG_CPM_USBPCR1 = usbpcr1; + + /* fil */ + REG_CPM_USBVBFIL = 0; + + /* rdt */ + REG_CPM_USBRDT = 0x96; + + /* rdt - filload_en */ + REG_CPM_USBRDT |= USBRDT_VBFIL_LD_EN; + + /* TXRISETUNE & TXVREFTUNE. */ + REG_CPM_USBPCR = 0x3f; + REG_CPM_USBPCR = 0x35; + +#if 1 + REG_CPM_USBPCR &= ~(1 << 31); + REG_CPM_USBPCR |= (1 << 23) | (1 << 24); +#endif + + /* enable tx pre-emphasis */ + REG_CPM_USBPCR |= USBPCR_TXPREEMPHTUNE; + + /* OTGTUNE adjust */ + REG_CPM_USBPCR = (7 << 14); + } + REG_CPM_USBPCR |= 1 << 20; + + /* force usb device mode */ + x1000_usb_set_device_only_mode(dwc); + + x1000_usb_phy_init(dwc); + + x1000_usb_phy_switch(dwc,1); + + /* soft disconnect and soft reset */ + REG_OTG_DCTL |= DCTL_SOFT_DISCONN; + udelay(3000); + + /* reset dwc register */ + dwc_otg_core_reset(dwc); + + /* DWC OTG Core init */ + dwc_otg_core_init(dwc,1); + + /* Read Gintsts confirm the device or host mode */ + curmod = REG_GINT_STS; + if (curmod & 0x1) + { + DWC_DBG("Curmod: Host Mode\n"); + } + else + { + DWC_DBG("Curmod: Device Mode\n"); + + /* DWC OTG Device init */ + dwc_otg_device_init(dwc); + + /* DWC OTG Fifo init */ + dwc_calculate_fifo_size(dwc); + } + + /* End-point has been inited */ +// dwc_init_endpoint(dwc); + +} + +static void x1000_usbd_isr_service(void *param) +{ + dwc_handle *dwc = (dwc_handle *)param; + uint8_t err; + uint32_t intsts; + + RT_ASSERT(dwc != RT_NULL); + + while (1) + { + rt_sem_take(dwc->isr_sem, RT_WAITING_FOREVER); + + intsts = REG_GINT_STS; + + if (intsts & GINTSTS_OTG_INTR) + { + DWC_DBG("OTG_INTR\n"); + dwc_otg_intr(dwc); + } + + if ((intsts & GINTSTS_USB_EARLYSUSPEND) + || (intsts & GINTSTS_USB_SUSPEND) + || (intsts & GINTSTS_START_FRAM) + || (intsts & GINTSTS_USB_RESET) + || (intsts & GINTSTS_ENUM_DONE)) + { + dwc_common_intr(dwc, intsts); + } + + /* dwc in pio mode not dma mode */ + if (intsts & GINTSTS_RXFIFO_NEMPTY) + { + DWC_DBG("GINTSTS_RXFIFO_NEMPTY!!\n"); + if (dwc->is_dma == IS_SLAVE_MODE) dwc_handle_rxfifo_nempty(dwc); + + REG_GINT_STS = GINTSTS_RXFIFO_NEMPTY; + } + + if (intsts & GINTSTS_IEP_INTR) + { + DWC_DBG("IEP_INTR!!!\n"); + dwc_handle_inep_intr(dwc); + } + + if (intsts & GINTSTS_OEP_INTR) + { + DWC_DBG("OEP_INTR!!!\n"); + dwc_handle_outep_intr(dwc); + } + + if (intsts & GINTSTS_RSUME_DETE) + { + DWC_DBG("RESUME_INTR\n"); + dwc_handle_resume_intr(dwc); + } + + if (intsts & (1 << 31)) + { + REG_GINT_STS = 1 << 31; + } + + rt_hw_interrupt_umask(IRQ_OTG); + } +} + + +void x1000_usbd_init(dwc_handle *dwc) +{ + uint32_t curmod = 0; + + DWC_DBG("Init UDC %s %s\n",__DATE__,__TIME__); + + if(dwc->isr_sem == RT_NULL) + { + dwc->isr_sem = rt_sem_create("dwcSem",0,RT_IPC_FLAG_FIFO); + if (!dwc->isr_sem) + { + DWC_DBG("%s %d sem create err\n", __func__, __LINE__); + while (1) ; + } + + dwc->status.b.state = USB_CABLE_DISCONNECT; + dwc->status.b.event = 0; + } + + dwc_gadget_init(dwc); + + /* create a ISR service task */ + { + rt_thread_t tid; + tid = rt_thread_create("dwcIntSv", + x1000_usbd_isr_service, (void *) dwc, + 2048, + RT_THREAD_PRIORITY_MAX/5, + 20); + if (tid != RT_NULL) rt_thread_startup(tid); + rt_kprintf("dwc interrupt service init done...\n"); + } + + /* request irq */ + rt_hw_interrupt_install(IRQ_OTG,dwc_irq_handler,(void *)dwc,"otgISR"); + rt_hw_interrupt_umask(IRQ_OTG); + DWC_DBG("[DWC] DWC request IRQ success %x\n", REG_GINT_MASK); +} diff --git a/bsp/x1000/drivers/usbd/x1000_dwc.h b/bsp/x1000/drivers/usbd/x1000_dwc.h new file mode 100644 index 0000000000000000000000000000000000000000..125ba6d3f6a5fdbdef25edd3fc67736bbee872b1 --- /dev/null +++ b/bsp/x1000/drivers/usbd/x1000_dwc.h @@ -0,0 +1,598 @@ +/* + * x1000_dwc.h + * + * Created on: 2017年2月3日 + * Author: Urey + */ + +#ifndef _X1000_DWC_H_ +#define _X1000_DWC_H_ + +#define DWC_FORCE_SPEED_FULL 0 + +#if DWC_FORCE_SPEED_FULL +#define ENDPOINT_PACKET_SIZE 64 +#define CONTROL_MAX_PACKET_SIZE 64 +#else +#define ENDPOINT_PACKET_SIZE 512 +#define CONTROL_MAX_PACKET_SIZE 64 +#endif + +#define DWC_EP_IN_OFS 0 +#define DWC_EP_OUT_OFS 16 + +#define DWC_EPNO_MASK 0x7f + +typedef struct dwc_ep_t +{ + uint8_t num; /* ep number used for register address lookup */ +#define EP_IDLE 0 +#define EP_TRANSFERED 1 +#define EP_TRANSFERING 2 + +#define EP_SETUP 0 +#define EP_DATA 1 +#define EP_STATUS 2 +#define EP_SETUP_PHASEDONE 3 + uint32_t ep_state; + uint32_t is_in; /* ep dir 1 = out */ + + uint32_t active; /* ep active */ + uint32_t type; /* ep type */ +#define DWC_OTG_EP_TYPE_CONTROL 0 +#define DWC_OTG_EP_TYPE_ISOC 1 +#define DWC_OTG_EP_TYPE_BULK 2 +#define DWC_OTG_EP_TYPE_INTR 3 + + uint32_t maxpacket; /* max packet bytes */ +// uint32_t ctrl_req_addr; + void* xfer_buff; /* pointer to transfer buffer */ + + uint32_t xfer_len; /* number of bytes to transfer */ + + uint32_t xfer_count; /* number of bytes transfered */ + +} dwc_ep; + +typedef union hwcfg1_data { + uint32_t d32; + + struct { + unsigned ep_dir0:2; + unsigned ep_dir1:2; + unsigned ep_dir2:2; + unsigned ep_dir3:2; + unsigned ep_dir4:2; + unsigned ep_dir5:2; + unsigned ep_dir6:2; + unsigned ep_dir7:2; + unsigned ep_dir8:2; + unsigned ep_dir9:2; + unsigned ep_dir10:2; + unsigned ep_dir11:2; + unsigned ep_dir12:2; + unsigned ep_dir13:2; + unsigned ep_dir14:2; + unsigned ep_dir15:2; + } b; +#define DWC_HWCFG1_DIR_BIDIR 0x0 +#define DWC_HWCFG1_DIR_IN 0x1 +#define DWC_HWCFG1_DIR_OUT 0x2 +} hwcfg1_data_t; + +/** + * This union represents the bit fields in the User HW Config2 + * Register. Read the register into the d32 element then read + * out the bits using the bit elements. + */ +typedef union hwcfg2_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /* GHWCFG2 */ + unsigned op_mode:3; +#define DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG 0 +#define DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG 1 +#define DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG 2 +#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3 +#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4 +#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST 5 +#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6 + + unsigned architecture:2; + unsigned point2point:1; + unsigned hs_phy_type:2; +#define DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0 +#define DWC_HWCFG2_HS_PHY_TYPE_UTMI 1 +#define DWC_HWCFG2_HS_PHY_TYPE_ULPI 2 +#define DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3 + + unsigned fs_phy_type:2; + unsigned num_dev_ep:4; + unsigned num_host_chan:4; + unsigned perio_ep_supported:1; + unsigned dynamic_fifo:1; + unsigned multi_proc_int:1; + unsigned reserved21:1; + unsigned nonperio_tx_q_depth:2; + unsigned host_perio_tx_q_depth:2; + unsigned dev_token_q_depth:5; + unsigned otg_enable_ic_usb:1; + } b; +} hwcfg2_data_t; + + +/** + * This union represents the bit fields in the User HW Config3 + * Register. Read the register into the d32 element then read + * out the bits using the bit elements. + */ +typedef union hwcfg3_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /* GHWCFG3 */ + unsigned xfer_size_cntr_width:4; + unsigned packet_size_cntr_width:3; + unsigned otg_func:1; + unsigned i2c:1; + unsigned vendor_ctrl_if:1; + unsigned optional_features:1; + unsigned synch_reset_type:1; + unsigned adp_supp:1; + unsigned otg_enable_hsic:1; + unsigned bc_support:1; + unsigned otg_lpm_en:1; + unsigned dfifo_depth:16; + } b; +} hwcfg3_data_t; + + +/** + * This union represents the bit fields in the User HW Config4 + * Register. Read the register into the d32 element then read + * out the bits using the bit elements. + */ +typedef union hwcfg4_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned num_dev_perio_in_ep:4; + unsigned power_optimiz:1; + unsigned min_ahb_freq:1; + unsigned part_power_down:1; + unsigned reserved:7; + unsigned utmi_phy_data_width:2; + unsigned num_dev_mode_ctrl_ep:4; + unsigned iddig_filt_en:1; + unsigned vbus_valid_filt_en:1; + unsigned a_valid_filt_en:1; + unsigned b_valid_filt_en:1; + unsigned session_end_filt_en:1; + unsigned ded_fifo_en:1; + unsigned num_in_eps:4; + unsigned desc_dma:1; + unsigned desc_dma_dyn:1; + } b; +} hwcfg4_data_t; + +typedef union dwc_state { + uint8_t d8; + + struct { + unsigned event:1; +#define USB_CABLE_DISCONNECT 0 +#define USB_CABLE_CONNECT 1 +#define USB_CABLE_SUSPEND 2 +#define USB_CONFIGURED 3 + unsigned state:7; + }b; + +} dwc_st; + +typedef struct dwc_cfg_if_t +{ + hwcfg1_data_t hwcfg1; + hwcfg2_data_t hwcfg2; + hwcfg3_data_t hwcfg3; + hwcfg4_data_t hwcfg4; + dwc_st status; +#define USB_SPEED_HIGH 0 +#define USB_SPEED_FULL 1 +#define USB_SPEED_LOW 2 + uint8_t speed; + uint8_t is_dma; +// uint8_t ep0State; + dwc_ep *dep[32]; + + rt_sem_t isr_sem; +} dwc_handle; + +/** + * This union represents the bit fields in the Device Control + * Register. Read the register into the d32 member then + * set/clear the bits using the bit elements. + */ +typedef union dctl_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /** Remote Wakeup */ + unsigned rmtwkupsig:1; + /** Soft Disconnect */ + unsigned sftdiscon:1; + /** Global Non-Periodic IN NAK Status */ + unsigned gnpinnaksts:1; + /** Global OUT NAK Status */ + unsigned goutnaksts:1; + /** Test Control */ + unsigned tstctl:3; + /** Set Global Non-Periodic IN NAK */ + unsigned sgnpinnak:1; + /** Clear Global Non-Periodic IN NAK */ + unsigned cgnpinnak:1; + /** Set Global OUT NAK */ + unsigned sgoutnak:1; + /** Clear Global OUT NAK */ + unsigned cgoutnak:1; + /** Power-On Programming Done */ + unsigned pwronprgdone:1; + /** Reserved */ + unsigned reserved:1; + /** Global Multi Count */ + unsigned gmc:2; + /** Ignore Frame Number for ISOC EPs */ + unsigned ifrmnum:1; + /** NAK on Babble */ + unsigned nakonbble:1; + /** Enable Continue on BNA */ + unsigned encontonbna:1; + + unsigned reserved18_31:14; + } b; +} dctl_data_t; + +/** + * This union represents the bit fields of the Core Interrupt Mask + * Register (GINTMSK). Set/clear the bits using the bit fields then + * write the d32 value to the register. + */ +typedef union gintmsk_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned reserved0:1; + unsigned modemismatch:1; + unsigned otgintr:1; + unsigned sofintr:1; + unsigned rxstsqlvl:1; + unsigned nptxfempty:1; + unsigned ginnakeff:1; + unsigned goutnakeff:1; + unsigned ulpickint:1; + unsigned i2cintr:1; + unsigned erlysuspend:1; + unsigned usbsuspend:1; + unsigned usbreset:1; + unsigned enumdone:1; + unsigned isooutdrop:1; + unsigned eopframe:1; + unsigned restoredone:1; + unsigned epmismatch:1; + unsigned inepintr:1; + unsigned outepintr:1; + unsigned incomplisoin:1; + unsigned incomplisoout:1; + unsigned fetsusp:1; + unsigned resetdet:1; + unsigned portintr:1; + unsigned hcintr:1; + unsigned ptxfempty:1; + unsigned lpmtranrcvd:1; + unsigned conidstschng:1; + unsigned disconnect:1; + unsigned sessreqintr:1; + unsigned wkupintr:1; + } b; +} gintmsk_data_t; + +/** + * This union represents the bit fields in the Device EP Control + * Register. Read the register into the d32 member then + * set/clear the bits using the bit elements. + */ +typedef union depctl_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /** Maximum Packet Size + * IN/OUT EPn + * IN/OUT EP0 - 2 bits + * 2'b00: 64 Bytes + * 2'b01: 32 + * 2'b10: 16 + * 2'b11: 8 */ + unsigned mps:11; +#define DWC_DEP0CTL_MPS_64 0 +#define DWC_DEP0CTL_MPS_32 1 +#define DWC_DEP0CTL_MPS_16 2 +#define DWC_DEP0CTL_MPS_8 3 + + /** Next Endpoint + * IN EPn/IN EP0 + * OUT EPn/OUT EP0 - reserved */ + unsigned nextep:4; + + /** USB Active Endpoint */ + unsigned usbactep:1; + + /** Endpoint DPID (INTR/Bulk IN and OUT endpoints) + * This field contains the PID of the packet going to + * be received or transmitted on this endpoint. The + * application should program the PID of the first + * packet going to be received or transmitted on this + * endpoint , after the endpoint is + * activated. Application use the SetD1PID and + * SetD0PID fields of this register to program either + * D0 or D1 PID. + * + * The encoding for this field is + * - 0: D0 + * - 1: D1 + */ + unsigned dpid:1; + + /** NAK Status */ + unsigned naksts:1; + + /** Endpoint Type + * 2'b00: Control + * 2'b01: Isochronous + * 2'b10: Bulk + * 2'b11: Interrupt */ + unsigned eptype:2; + + /** Snoop Mode + * OUT EPn/OUT EP0 + * IN EPn/IN EP0 - reserved */ + unsigned snp:1; + + /** Stall Handshake */ + unsigned stall:1; + + /** Tx Fifo Number + * IN EPn/IN EP0 + * OUT EPn/OUT EP0 - reserved */ + unsigned txfnum:4; + + /** Clear NAK */ + unsigned cnak:1; + /** Set NAK */ + unsigned snak:1; + /** Set DATA0 PID (INTR/Bulk IN and OUT endpoints) + * Writing to this field sets the Endpoint DPID (DPID) + * field in this register to DATA0. Set Even + * (micro)frame (SetEvenFr) (ISO IN and OUT Endpoints) + * Writing to this field sets the Even/Odd + * (micro)frame (EO_FrNum) field to even (micro) + * frame. + */ + unsigned setd0pid:1; + /** Set DATA1 PID (INTR/Bulk IN and OUT endpoints) + * Writing to this field sets the Endpoint DPID (DPID) + * field in this register to DATA1 Set Odd + * (micro)frame (SetOddFr) (ISO IN and OUT Endpoints) + * Writing to this field sets the Even/Odd + * (micro)frame (EO_FrNum) field to odd (micro) frame. + */ + unsigned setd1pid:1; + + /** Endpoint Disable */ + unsigned epdis:1; + /** Endpoint Enable */ + unsigned epena:1; + } b; +} depctl_data_t; + +/** + * This union represents the bit fields in the Device IN EP Interrupt + * Register and the Device IN EP Common Mask Register. + * + * - Read the register into the d32 member then set/clear the + * bits using the bit elements. + */ +typedef union diepint_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /** Transfer complete mask */ + unsigned xfercompl:1; + /** Endpoint disable mask */ + unsigned epdisabled:1; + /** AHB Error mask */ + unsigned ahberr:1; + /** TimeOUT Handshake mask (non-ISOC EPs) */ + unsigned timeout:1; + /** IN Token received with TxF Empty mask */ + unsigned intktxfemp:1; + /** IN Token Received with EP mismatch mask */ + unsigned intknepmis:1; + /** IN Endpoint NAK Effective mask */ + unsigned inepnakeff:1; + /** Reserved */ + unsigned emptyintr:1; + + unsigned txfifoundrn:1; + + /** BNA Interrupt mask */ + unsigned bna:1; + + unsigned reserved10_12:3; + /** BNA Interrupt mask */ + unsigned nak:1; + + unsigned reserved14_31:18; + } b; +} diepint_data_t; + +/** + * This union represents the bit fields in the Device IN EP + * Common/Dedicated Interrupt Mask Register. + */ +typedef union diepint_data diepmsk_data_t; + +/** + * This union represents the bit fields in the Device OUT EP Interrupt + * Registerand Device OUT EP Common Interrupt Mask Register. + * + * - Read the register into the d32 member then set/clear the + * bits using the bit elements. + */ +typedef union doepint_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /** Transfer complete */ + unsigned xfercompl:1; + /** Endpoint disable */ + unsigned epdisabled:1; + /** AHB Error */ + unsigned ahberr:1; + /** Setup Phase Done (contorl EPs) */ + unsigned setup:1; + /** OUT Token Received when Endpoint Disabled */ + unsigned outtknepdis:1; + + unsigned stsphsercvd:1; + /** Back-to-Back SETUP Packets Received */ + unsigned back2backsetup:1; + + unsigned reserved7:1; + /** OUT packet Error */ + unsigned outpkterr:1; + /** BNA Interrupt */ + unsigned bna:1; + + unsigned reserved10:1; + /** Packet Drop Status */ + unsigned pktdrpsts:1; + /** Babble Interrupt */ + unsigned babble:1; + /** NAK Interrupt */ + unsigned nak:1; + /** NYET Interrupt */ + unsigned nyet:1; + + unsigned reserved15_31:17; + } b; +} doepint_data_t; + +/** + * This union represents the bit fields in the Device OUT EP + * Common/Dedicated Interrupt Mask Register. + */ +typedef union doepint_data doepmsk_data_t; + +/** + * This union represents the bit fields in the Device All EP Interrupt + * and Mask Registers. + * - Read the register into the d32 member then set/clear the + * bits using the bit elements. + */ +typedef union daint_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /** IN Endpoint bits */ + unsigned in:16; + /** OUT Endpoint bits */ + unsigned out:16; + } ep; + struct { + /** IN Endpoint bits */ + unsigned inep0:1; + unsigned inep1:1; + unsigned inep2:1; + unsigned inep3:1; + unsigned inep4:1; + unsigned inep5:1; + unsigned inep6:1; + unsigned inep7:1; + unsigned inep8:1; + unsigned inep9:1; + unsigned inep10:1; + unsigned inep11:1; + unsigned inep12:1; + unsigned inep13:1; + unsigned inep14:1; + unsigned inep15:1; + /** OUT Endpoint bits */ + unsigned outep0:1; + unsigned outep1:1; + unsigned outep2:1; + unsigned outep3:1; + unsigned outep4:1; + unsigned outep5:1; + unsigned outep6:1; + unsigned outep7:1; + unsigned outep8:1; + unsigned outep9:1; + unsigned outep10:1; + unsigned outep11:1; + unsigned outep12:1; + unsigned outep13:1; + unsigned outep14:1; + unsigned outep15:1; + } b; +} daint_data_t; + +/* + * Functions + */ +/* USB Endpoint Callback Events */ +#define USB_EVT_SETUP 1 /* Setup Packet */ +#define USB_EVT_OUT 2 /* OUT Packet */ +#define USB_EVT_IN 3 /* IN Packet */ +#define USB_EVT_OUT_NAK 4 /* OUT Packet - Not Acknowledged */ +#define USB_EVT_IN_NAK 5 /* IN Packet - Not Acknowledged */ +#define USB_EVT_OUT_STALL 6 /* OUT Packet - Stalled */ +#define USB_EVT_IN_STALL 7 /* IN Packet - Stalled */ +#define USB_EVT_OUT_DMA_EOT 8 /* DMA OUT EP - End of Transfer */ +#define USB_EVT_IN_DMA_EOT 9 /* DMA IN EP - End of Transfer */ +#define USB_EVT_OUT_DMA_NDR 10 /* DMA OUT EP - New Descriptor Request */ +#define USB_EVT_IN_DMA_NDR 11 /* DMA IN EP - New Descriptor Request */ +#define USB_EVT_OUT_DMA_ERR 12 /* DMA OUT EP - Error */ +#define USB_EVT_IN_DMA_ERR 13 /* DMA IN EP - Error */ +#define USB_EVT_SOF 14 + +void x1000_usbd_init(dwc_handle *dwc); +void dwc_set_address(dwc_handle *dwc,uint8_t address); +int dwc_ep_disable(dwc_handle *dwc,uint8_t epnum); +int dwc_ep_enable(dwc_handle *dwc,uint8_t epnum); + +int dwc_set_ep_stall(dwc_handle *dwc,uint8_t epnum); +int dwc_clr_ep_stall(dwc_handle *dwc,uint8_t epnum); +int dwc_enable_in_ep(dwc_handle *dwc,uint8_t epnum); +int dwc_enable_out_ep(dwc_handle *dwc,uint8_t epnum); +void dwc_ep0_status(dwc_handle *dwc); +void dwc_otg_ep0_out_start(dwc_handle *dwc); + +void dwc_handle_ep_data_in_phase(dwc_handle *dwc, uint8_t epnum); +void dwc_handle_ep_status_in_phase(dwc_handle *dwc, uint8_t epnum); +void dwc_handle_ep_data_out_phase(dwc_handle *dwc,uint8_t epnum); + +void dwc_ep_out_start(dwc_handle *dwc,uint8_t epnum); +int HW_GetPKT(dwc_handle *dwc, uint8_t epnum, uint8_t *buf,int size); +int HW_SendPKT(dwc_handle *dwc, uint8_t epnum, const uint8_t *buf, int size); + +extern void x1000_usbd_event_cb(uint8_t epnum,uint32_t event,void *arg); +#endif /* _X1000_DWC_H_ */ diff --git a/bsp/x1000/rtconfig.h b/bsp/x1000/rtconfig.h index fb83405dfb446fd522cac2dbf92597e5d0e31687..33f8d7dd89d63c56717676076e5f22d13ca43fbb 100644 --- a/bsp/x1000/rtconfig.h +++ b/bsp/x1000/rtconfig.h @@ -1,217 +1,235 @@ -#ifndef __RTTHREAD_CFG_H__ -#define __RTTHREAD_CFG_H__ - -// - -// -#define RT_NAME_MAX 8 -// -#define RT_ALIGN_SIZE 4 -// -// 8 -// 32 -// 256 -// -#define RT_THREAD_PRIORITY_MAX 32 -// -#define RT_TICK_PER_SECOND 100 -// -#define IDLE_THREAD_STACK_SIZE 1024 - -//
+#ifndef RT_CONFIG_H__ +#define RT_CONFIG_H__ + +/* Automatically generated file; DO NOT EDIT. */ +/* RT-Thread Configuration */ + +/* RT-Thread Kernel */ + +#define RT_NAME_MAX 8 +#define RT_ALIGN_SIZE 8 +#define RT_THREAD_PRIORITY_MAX 32 +#define RT_TICK_PER_SECOND 1000 #define RT_DEBUG -// -#define RT_DEBUG_SCHEDULER 0 -// #define RT_USING_OVERFLOW_CHECK -//
- -// +#define RT_DEBUG_INIT 0 +#define RT_DEBUG_THREAD 0 #define RT_USING_HOOK +#define IDLE_THREAD_STACK_SIZE 1024 +#define RT_USING_TIMER_SOFT +#define RT_TIMER_THREAD_PRIO 4 +#define RT_TIMER_THREAD_STACK_SIZE 1024 -//
-// #define RT_USING_TIMER_SOFT -// -#define RT_TIMER_THREAD_PRIO 4 -// -#define RT_TIMER_THREAD_STACK_SIZE 512 -//
+/* Inter-Thread communication */ -//
-// #define RT_USING_SEMAPHORE -// #define RT_USING_MUTEX -// #define RT_USING_EVENT -// #define RT_USING_MAILBOX -// #define RT_USING_MESSAGEQUEUE -//
+/* RT_USING_SIGNALS is not set */ + +/* Memory Management */ -//
-// #define RT_USING_MEMPOOL -// -// #define RT_USING_MEMHEAP -// +/* RT_USING_MEMHEAP is not set */ #define RT_USING_HEAP -// #define RT_USING_SMALL_MEM -// -// #define RT_USING_SLAB -//
+/* RT_USING_SLAB is not set */ + +/* Kernel Device Object */ -//
#define RT_USING_DEVICE -// -#define RT_USING_SERIAL -// -// #define RT_USING_SPI -// -#define RT_USING_DEVICE_IPC -// -#define RT_USING_SDIO -// -//#define RT_USING_USB_DEVICE -// -//#define RT_USB_DEVICE_CDC -//#define USB_VENDOR_ID 0x0483 -//#define USB_PRODUCT_ID 0x5740 -//
- -//
+/* RT_USING_INTERRUPT_INFO is not set */ #define RT_USING_CONSOLE -// -#define RT_CONSOLEBUF_SIZE 128 -// -#define RT_CONSOLE_DEVICE_NAME "uart2" -//
+#define RT_CONSOLEBUF_SIZE 128 +#define RT_CONSOLE_DEVICE_NAME "uart2" +/* RT_USING_MODULE is not set */ + +/* RT-Thread Components */ + +#define RT_USING_COMPONENTS_INIT +#define RT_USING_USER_MAIN + +/* C++ features */ + +/* RT_USING_CPLUSPLUS is not set */ + +/* Command shell */ -//
#define RT_USING_FINSH -// +#define FINSH_USING_HISTORY #define FINSH_USING_SYMTAB -// #define FINSH_USING_DESCRIPTION -// +#define FINSH_THREAD_PRIORITY 20 #define FINSH_THREAD_STACK_SIZE 4096 -// +#define FINSH_CMD_SIZE 80 +/* FINSH_USING_AUTH is not set */ #define FINSH_USING_MSH -// #define FINSH_USING_MSH_DEFAULT -// -// #define FINSH_USING_MSH_ONLY -//
+/* FINSH_USING_MSH_ONLY is not set */ -//
-// -#define RT_USING_LIBC -// -#define RT_USING_PTHREADS -// -#define RT_USING_COMPONENTS_INIT -// -#define RT_USING_USER_MAIN -//
+/* Device virtual file system */ -//
#define RT_USING_DFS -// #define DFS_USING_WORKDIR -// -#define DFS_FILESYSTEMS_MAX 4 -// -#define DFS_FD_MAX 8 -// +#define DFS_FILESYSTEMS_MAX 4 +#define DFS_FD_MAX 4 #define RT_USING_DFS_ELMFAT -// -#define RT_DFS_ELM_DRIVES 4 -// + +/* elm-chan's FatFs, Generic FAT Filesystem Module */ + +#define RT_DFS_ELM_CODE_PAGE 437 +#define RT_DFS_ELM_WORD_ACCESS +/* RT_DFS_ELM_USE_LFN_0 is not set */ +/* RT_DFS_ELM_USE_LFN_1 is not set */ +/* RT_DFS_ELM_USE_LFN_2 is not set */ +#define RT_DFS_ELM_USE_LFN_3 +#define RT_DFS_ELM_USE_LFN 3 +#define RT_DFS_ELM_MAX_LFN 255 +#define RT_DFS_ELM_DRIVES 4 +#define RT_DFS_ELM_MAX_SECTOR_SIZE 4096 +/* RT_DFS_ELM_USE_ERASE is not set */ #define RT_DFS_ELM_REENTRANT -// -// 0 -// 1 -// 2 -// 3 -// -#define RT_DFS_ELM_USE_LFN 3 -// -#define RT_DFS_ELM_CODE_PAGE 437 -// -#define RT_DFS_ELM_MAX_LFN 255 -// -// #define RT_USING_DFS_YAFFS2 -// -// #define RT_USING_DFS_UFFS -// #define RT_USING_DFS_DEVFS -// -// #define RT_USING_DFS_NFS -// -#define RT_NFS_HOST_EXPORT "192.168.1.5:/" -// -// #define RT_USING_DFS_LWIP -//
- -//
-// #define RT_USING_LWIP -// -#define RT_LWIP_PBUF_POOL_BUFSIZE (1536) -// -#define RT_LWIP_ICMP -// -// #define RT_LWIP_IGMP -// -#define RT_LWIP_UDP -// -#define RT_LWIP_TCP -// -#define RT_LWIP_DNS -// -#define RT_LWIP_TCP_PCB_NUM 8 -// -#define RT_LWIP_TCP_SND_BUF 8192 -// -#define RT_LWIP_TCP_WND 8192 -// -// #define RT_LWIP_SNMP -// -#define RT_LWIP_DHCP -// -#define RT_LWIP_TCPTHREAD_PRIORITY 12 -// -#define RT_LWIP_TCPTHREAD_MBOX_SIZE 8 -// -#define RT_LWIP_TCPTHREAD_STACKSIZE 4096 -// -#define RT_LWIP_ETHTHREAD_PRIORITY 14 -// -#define RT_LWIP_ETHTHREAD_MBOX_SIZE 8 -// -#define RT_LWIP_ETHTHREAD_STACKSIZE 512 -// -#define RT_LWIP_IPADDR0 192 -#define RT_LWIP_IPADDR1 168 -#define RT_LWIP_IPADDR2 10 -#define RT_LWIP_IPADDR3 222 -// -#define RT_LWIP_GWADDR0 192 -#define RT_LWIP_GWADDR1 168 -#define RT_LWIP_GWADDR2 10 -#define RT_LWIP_GWADDR3 1 -// -#define RT_LWIP_MSKADDR0 255 -#define RT_LWIP_MSKADDR1 255 -#define RT_LWIP_MSKADDR2 255 -#define RT_LWIP_MSKADDR3 0 -//
- -//
+/* RT_USING_DFS_NET is not set */ +/* RT_USING_DFS_ROMFS is not set */ +/* RT_USING_DFS_RAMFS is not set */ +/* RT_USING_DFS_UFFS is not set */ + +/* Device Drivers */ + +#define RT_USING_DEVICE_IPC +#define RT_USING_SERIAL +/* RT_USING_CAN is not set */ +/* RT_USING_HWTIMER is not set */ +#define RT_USING_I2C +/* RT_USING_I2C_BITOPS is not set */ +#define RT_USING_PIN +#define RT_USING_MTD_NOR +/* RT_USING_MTD_NAND is not set */ +/* RT_USING_RTC is not set */ +#define RT_USING_SDIO +#define RT_USING_SPI +/* RT_USING_SFUD is not set */ +/* RT_USING_W25QXX is not set */ +/* RT_USING_GD is not set */ +/* RT_USING_ENC28J60 is not set */ +/* RT_USING_SPI_WIFI is not set */ +#define RT_USING_WDT +/* RT_USING_USB_HOST is not set */ +#define RT_USING_USB_DEVICE +#define RT_USB_DEVICE_CDC +/* RT_USB_DEVICE_MSTORAGE is not set */ + +/* POSIX layer and C standard library */ + +#define RT_USING_LIBC +/* RT_USING_PTHREADS is not set */ +#define RT_USING_POSIX +/* RT_USING_POSIX_MMAP is not set */ +/* RT_USING_POSIX_TERMIOS is not set */ +/* Network stack */ + +/* light weight TCP/IP stack */ + +/* RT_USING_LWIP is not set */ + +/* Modbus master and slave stack */ + +/* RT_USING_MODBUS is not set */ + +/* RT-Thread UI Engine */ + +#define RT_USING_GUIENGINE +#define RTGUI_NAME_MAX 16 +/* RTGUI_USING_TTF is not set */ +#define RTGUI_USING_FONT16 +#define RTGUI_USING_FONT12 +/* RTGUI_USING_FONTHZ is not set */ +/* RTGUI_IMAGE_XPM is not set */ +#define RTGUI_IMAGE_JPEG_NONE +/* RTGUI_IMAGE_JPEG is not set */ +/* RTGUI_IMAGE_TJPGD is not set */ +#define RTGUI_IMAGE_PNG_NONE +/* RTGUI_IMAGE_PNG is not set */ +/* RTGUI_IMAGE_LODEPNG is not set */ +/* RTGUI_IMAGE_BMP is not set */ +/* RTGUI_IMAGE_CONTAINER is not set */ + +/* VBUS(Virtual Software BUS) */ + +/* RT_USING_VBUS is not set */ + +/* RT-Thread online packages */ + +/* system packages */ + +/* PKG_USING_PARTITION is not set */ +/* PKG_USING_SQLITE is not set */ + +/* IoT - internet of things */ + +/* PKG_USING_PAHOMQTT is not set */ +/* PKG_USING_WEBCLIENT is not set */ +/* PKG_USING_MONGOOSE is not set */ +/* PKG_USING_WEBTERMINAL is not set */ +/* PKG_USING_CJSON is not set */ +/* PKG_USING_EZXML is not set */ + +/* Marvell WiFi */ + +/* PKG_USING_MARVELLWIFI is not set */ + +/* security packages */ + +/* PKG_USING_MBEDTLS is not set */ + +/* language packages */ + +/* PKG_USING_JERRYSCRIPT is not set */ + +/* multimedia packages */ + +/* PKG_USING_FASTLZ is not set */ + +/* tools packages */ + +/* PKG_USING_CMBACKTRACE is not set */ +/* PKG_USING_EASYLOGGER is not set */ +/* PKG_USING_SYSTEMVIEW is not set */ + +/* miscellaneous packages */ + +/* PKG_USING_HELLO is not set */ +/* BOARD_HALLEY2 is not set */ +/* BOARD_PHOENIX is not set */ +/* BOARD_CANNA is not set */ +/* BOARD_HALLEY2_FIR is not set */ +/* BOARD_HALLEY2_REALBOARD is not set */ +#define BOARD_HALLEY2_REALBOARD_V2 +/* BOARD_HALLEY2_IDELAN is not set */ +#define RT_USING_UART0 +#define RT_USING_UART1 +#define RT_USING_UART2 +#define RT_USING_MSC0 +#define RT_USING_MSC1 +#define RT_MMCSD_STACK_SIZE 2048 +#define RT_USING_SLCD +#define RT_USING_ILI9488 +/* RT_USING_ILI9341 is not set */ +/* RT_USING_OTM4802 is not set */ +/* RT_USING_TRULY_TFT240240 is not set */ +#define RT_USING_TOUCH +#define RT_USING_GT9XX +/* RT_USING_FT6x06 is not set */ +#define RT_TOUCH_THREAD_PRIORITY 10 +#define RT_USING_I2C0 +#define RT_USING_I2C1 +#define RT_USING_I2C2 +#define RT_USING_AUDIO +#define RT_USING_ICODEC #define RT_USING_CPU_FFS -#define RT_CFG_MAX_DMA_CHANNELS 8 #endif - diff --git a/bsp/x1000/rtconfig.py b/bsp/x1000/rtconfig.py index 628fa71db4b14087cb885b448c739493d8f6145f..845de2bee5e8522766565e6e588765c3d641ce9d 100644 --- a/bsp/x1000/rtconfig.py +++ b/bsp/x1000/rtconfig.py @@ -2,20 +2,20 @@ import os # toolchains options ARCH ='mips' -CPU ='xburst' +CPU ='x1000' CROSS_TOOL ='gcc' if os.getenv('RTT_ROOT'): RTT_ROOT = os.getenv('RTT_ROOT') else: - RTT_ROOT = r'../..' + RTT_ROOT = r'E:\rt-thread' if os.getenv('RTT_CC'): CROSS_TOOL = os.getenv('RTT_CC') if CROSS_TOOL == 'gcc': PLATFORM = 'gcc' - EXEC_PATH = r'c:/embStudio/tools/mips-2015.11/bin' + EXEC_PATH = r'E:\work\env\tools\gnu_gcc\mips_gcc\mips-2016.05\bin' else: print 'Please make sure your toolchains is GNU GCC!' exit(0) @@ -23,7 +23,13 @@ else: if os.getenv('RTT_EXEC_PATH'): EXEC_PATH = os.getenv('RTT_EXEC_PATH') -BUILD = 'debug' + +# BUILD = 'debug' +# BUILD = 'release' +BUILD = 'release_O3' + +# FLOAT = 'soft' +FLOAT = 'hard' if PLATFORM == 'gcc': # toolchains @@ -32,14 +38,19 @@ if PLATFORM == 'gcc': CXX = PREFIX + 'g++' AS = PREFIX + 'gcc' AR = PREFIX + 'ar' - LINK = PREFIX + 'gcc' + LINK = PREFIX + 'g++' TARGET_EXT = 'elf' SIZE = PREFIX + 'size' OBJDUMP = PREFIX + 'objdump' OBJCPY = PREFIX + 'objcopy' + STRIP = PREFIX + 'strip' - DEVICE = ' -mips32 -msoft-float' - CFLAGS = DEVICE + ' -EL -G0 -mno-abicalls -fno-pic -fno-builtin -fno-exceptions -ffunction-sections -fomit-frame-pointer' + if FLOAT == 'soft': + DEVICE = ' -mips32r2 -msoft-float -mfp32' + else: + DEVICE = ' -mips32r2 -mhard-float -mfp32' + + CFLAGS = DEVICE + ' -EL -G0 -mno-abicalls -fno-pic -fno-builtin -fno-exceptions -ffunction-sections -fno-omit-frame-pointer' AFLAGS = ' -c' + DEVICE + ' -EL -x assembler-with-cpp' LFLAGS = DEVICE + ' -EL -Wl,--gc-sections,-Map=rtthread_x1000.map,-cref,-u,Reset_Handler -T x1000_ram.lds' CPATH = '' @@ -48,10 +59,18 @@ if PLATFORM == 'gcc': if BUILD == 'debug': CFLAGS += ' -O0 -gdwarf-2' AFLAGS += ' -gdwarf-2' + elif BUILD == 'release_O3': + CFLAGS += ' -O3' else: CFLAGS += ' -O2' CXXFLAGS = CFLAGS + M_CFLAGS = DEVICE + ' -EL -G0 -O2 -mno-abicalls -fno-common -fno-exceptions -fno-omit-frame-pointer -mlong-calls -fno-pic ' + M_CXXFLAGS = M_CFLAGS + M_LFLAGS = DEVICE + ' -EL -r -Wl,--gc-sections,-z,max-page-size=0x4' +\ + ' -nostartfiles -static-libgcc' + M_POST_ACTION = STRIP + ' -R .hash $TARGET\n' + SIZE + ' $TARGET \n' + DUMP_ACTION = OBJDUMP + ' -D -S $TARGET > rtt.asm\n' POST_ACTION = OBJCPY + ' -O binary $TARGET rtthread.bin\n' + SIZE + ' $TARGET \n' diff --git a/bsp/x1000/x1000_ram.lds b/bsp/x1000/x1000_ram.lds index 9c575903ecfcf6abc6b03703f6d1f5f2981f9e1a..8cab15bb5752d96e7bfeb37ca77f49e68faf7e00 100644 --- a/bsp/x1000/x1000_ram.lds +++ b/bsp/x1000/x1000_ram.lds @@ -34,8 +34,6 @@ MEMORY ENTRY(_start) SECTIONS { - . = 0x80800000 ; - .start : { *(.start); @@ -71,6 +69,12 @@ SECTIONS __rt_init_end = .; . = ALIGN(4); + /* section information for modules */ + . = ALIGN(4); + __rtmsymtab_start = .; + KEEP(*(RTMSymTab)) + __rtmsymtab_end = .; + . = ALIGN(4); _etext = .; } > DRAM @@ -79,10 +83,26 @@ SECTIONS { *(.eh_frame_hdr) *(.eh_frame_entry) + *(.eh_frame_entry.*) } > DRAM .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } > DRAM . = ALIGN(4); + .ctors : + { + PROVIDE(__ctors_start__ = .); + KEEP(*(SORT(.ctors.*))) + KEEP(*(.ctors)) + PROVIDE(__ctors_end__ = .); + } > DRAM + + .dtors : + { + PROVIDE(__dtors_start__ = .); + KEEP(*(SORT(.dtors.*))) + KEEP(*(.dtors)) + PROVIDE(__dtors_end__ = .); + } > DRAM .data : {