[bsp]update x1000 bsp driver
@@ -0,0 +1,24 @@
+mainmenu "RT-Thread Configuration"
+
+config $BSP_DIR
+ string
+ option env="BSP_ROOT"
+ default "."
+config $RTT_DIR
+ 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
+ option env="PKGS_ROOT"
+ default "packages"
+source "$RTT_DIR/KConfig"
+source "$PKGS_DIR/KConfig"
+source "$BSP_DIR/drivers/Kconfig"
@@ -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)
@@ -1,13 +1,10 @@
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')
@@ -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 <rtthread.h>
+#include <board.h>
+#include <drv_gpio.h>
+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);
+ gpio_set_value(BLINK_LED1_PORT,BLINK_LED1_PIN,1);
+ if(cnt & 0x04)
+ gpio_set_value(BLINK_LED2_PORT,BLINK_LED2_PIN,0);
+ gpio_set_value(BLINK_LED2_PORT,BLINK_LED2_PIN,1);
+ if(cnt & 0x08)
+ gpio_set_value(BLINK_LED3_PORT,BLINK_LED3_PIN,0);
+ 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);
@@ -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
*
* This 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
*/
-#include <stdio.h>
-#include <stdlib.h>
-int main(int argc, char** argv)
-{
- printf("Hello RT-Thread!\n");
+int main(int argc, char** argv)
return 0;
}
@@ -0,0 +1,72 @@
+ * File : mnt_init.c
+#include <rtdevice.h>
+#ifdef RT_USING_DFS
+#include <dfs_fs.h>
+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");
+ 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");
+ 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");
+ rt_kprintf("File System on TF fail!\n");
+ return 0;
+INIT_ENV_EXPORT(mnt_init);
@@ -0,0 +1,154 @@
+ * File : rtgui_demo.c
+// #define DEBUG
+#ifdef DEBUG
+#define DEBUG_PRINTF(...) rt_kprintf(__VA_ARGS__)
+#else
+#define DEBUG_PRINTF(...)
+#ifdef RT_USING_GUIENGINE
+#include <rtgui/rtgui.h>
+#include <rtgui/rtgui_system.h>
+#include <rtgui/rtgui_app.h>
+#include <rtgui/widgets/window.h>
+#include <rtgui/dc.h>
+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);
+ 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");
+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);
+int rt_gui_demo_init(void)
+ 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");
+ /* set graphic device */
+ rtgui_graphic_set_device(device);
+ tid = rt_thread_create("mygui",
+ rt_gui_demo_entry, RT_NULL,
+ 2048, 25, 10);
+INIT_APP_EXPORT(rt_gui_demo_init);
+#endif /* RT_USING_GUIENGINE */
@@ -1,63 +0,0 @@
-/*
- * File : board.h
- * This file is part of RT-Thread RTOS
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- * Change Logs:
- * Date Author Notes
- */
-#ifndef _BOARD_H_
-#define _BOARD_H_
-#include <stdint.h>
-#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
@@ -1,750 +0,0 @@
- * File : drv_mmc.c
- * 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
- * 2013-03-09 aozima the first version
- * 2013-03-29 aozima support Jz4770.
- * 2013-04-01 aozima add interrupt support for Jz4770.
-#include <rthw.h>
-#include <rtthread.h>
-#include <rtdevice.h>
-#include <drivers/mmcsd_core.h>
-#include <drivers/sdio.h>
-#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, ...)
-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)
- value |= (MSC_CTRL_CLOCK_START | MSC_CTRL_START_OP);
-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);
- value &= ~MSC_CTRL_RESET;
- 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;
- 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;
- 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 */
- int res_type = req->cmd->flags & RESP_MASK;
- sdio_dbg("resp type:%u\r\n", res_type);
- 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;
- case RESP_R2:
- cmdat |= MSC_CMDAT_RESPONSE_R2;
- case RESP_R3:
- cmdat |= MSC_CMDAT_RESPONSE_R3;
- case RESP_R4:
- cmdat |= MSC_CMDAT_RESPONSE_R4;
- case RESP_R5:
- cmdat |= MSC_CMDAT_RESPONSE_R5;
- case RESP_R6:
- cmdat |= MSC_CMDAT_RESPONSE_R6;
- case RESP_R7:
- cmdat |= MSC_CMDAT_RESPONSE_R7;
- default:
- /* 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");
- 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");
- 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;
- data = readw(sdio->hw_base + MSC_RES_OFFSET);
- buf[1] = data & 0xFF;
- buf[2] = (data >> 8) & 0xFF;
- buf[3] = data & 0xFF;
- buf[4] = data & 0xFF;
- req->cmd->resp[0] = buf[1] << 24 | buf[2] << 16
- | buf[3] << 8 | buf[4];
- uint32_t i, v, w1, w2;
- v = data & 0xFFFF;
- for(i=0; i<4; i++)
- w1 = data & 0xFFFF;
- w2 = data & 0xFFFF;
- req->cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8;
- v = w2;
- 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]
- );
- unsigned int waligned;
- uint32_t len = req->data->blksize * req->data->blks;
- /* word aligned ? */
- waligned = (((unsigned int)req->data->buf & 0x3) == 0);
- if(waligned)
- uint32_t i;
- uint32_t *src = (uint32_t *)req->data->buf;
- for(i=0; i<len; i+=4)
- while (readl(sdio->hw_base + MSC_STAT_OFFSET) & MSC_STAT_DATA_FIFO_FULL);
- writel(*src++, hw_base + MSC_TXFIFO_OFFSET);
- uint32_t i, data;
- uint8_t * src = (uint8_t *)req->data->buf;
- 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);
- uint32_t * dst = (uint32_t *)req->data->buf;
- while (readl(sdio->hw_base + MSC_STAT_OFFSET) & MSC_STAT_DATA_FIFO_EMPTY);
- *dst ++ = readl(sdio->hw_base + MSC_RXFIFO_OFFSET);
- uint32_t data, i;
- uint8_t * dst = (uint8_t *)req->data->buf;
- 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 &= ~MSC_DATA_TRAN_DONE;
- if(!(readl(sdio->hw_base + MSC_IREG_OFFSET) & MSC_DATA_TRAN_DONE))
- sdio_dbg("TRAN_DONE umask\r\n");
- 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");
- sdio_dbg("no need wait MSC_DATA_TRAN_DONE!\r\n");
- 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;
- 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);
- 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);
- lpm |= LPM_LPM;
- 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");
- case MMCSD_POWER_UP:
- sdio_dbg("MMCSD_POWER_UP\r\n");
- 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);
- sdio_dbg("unknown power_mode %d\n", io_cfg->power_mode);
-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");
- mmcsd_change(host);
-#endif // RT_USING_MSC0
-#ifdef RT_USING_MSC1
- 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)
- * 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. */
- jz_sdio->msc_clock = 50UL * 1000 * 1000; /* 50Mhz */
- host->freq_max = 50 * 1000 * 1000; /* max 50Mhz. */
- host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE;
- jz_sdio->irqno = IRQ_MSC1;
- rt_hw_interrupt_install(jz_sdio->irqno, msc_handler, jz_sdio, "msc1");
-#endif // RT_USING_MSC1
-err:
- if(host)
- mmcsd_free_host(host);
- if(jz_sdio)
- rt_free(host);
- return -RT_ENOMEM;
@@ -1,264 +0,0 @@
- * File : drv_uart.c
- * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team
-#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);
-#ifdef RT_USING_UART2
- static struct rt_serial_device serial2;
- static struct jz_uart_s uart2;
- serial = &serial2;
- uart = &uart2;
- uart->hw_base = UART2_BASE;
- uart->irqno = IRQ_UART2;
- "uart2",
-#ifdef RT_USING_UART3
- static struct rt_serial_device serial3;
- static struct jz_uart_s uart3;
- serial = &serial3;
- uart = &uart3;
- uart->hw_base = UART3_BASE;
- uart->irqno = IRQ_UART3;
- "uart3",
- * 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;
- #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)
- 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);
- 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);
-static int uart_putc (struct rt_serial_device *serial, char c)
- struct jz_uart_s* uart;
- /* 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;
- /* 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);
@@ -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"
+ config RT_USING_UART2
+ bool "Using UART2"
+ default y
+endif
+if RT_USING_SDIO
+ config RT_USING_MSC0
+ bool "Using MSC0 for sd card"
+ config RT_USING_MSC1
+ bool "Using MSC1 for wifi"
+ config RT_MMCSD_STACK_SIZE
+ int "Set mmc thread stack size"
+ default 2048
+if RT_USING_GUIENGINE
+ config RT_USING_SLCD
+ bool "Using lcd display"
+ 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"
+ if RT_USING_TOUCH
+ prompt "Choice touch controller"
+ default RT_USING_GT9XX
+ config RT_USING_GT9XX
+ bool "Using GT9XX controller"
+ config RT_USING_FT6x06
+ bool "Using FT6x06 controller"
+ config RT_TOUCH_THREAD_PRIORITY
+ int "Set touch thread priority"
+ range 2 32
+ default 10
+if RT_USING_I2C
+ config RT_USING_I2C0
+ bool "Using iic0 bus"
+ config RT_USING_I2C1
+ bool "Using iic1 bus"
+ config RT_USING_I2C2
+ bool "Using iic2 bus"
+config RT_USING_AUDIO
+ bool "Using audio"
+if RT_USING_AUDIO
+ config RT_USING_ICODEC
+ bool "Using icodec"
+config RT_USING_CPU_FFS
+ bool "Using CPU FFS"
@@ -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')
@@ -0,0 +1,11 @@
+CPPPATH = [cwd]
+group = DefineGroup('drv_audio', src, depend = ['RT_USING_AUDIO'], CPPPATH = CPPPATH)
@@ -0,0 +1,670 @@
+ * File : drv_i2s.h
+ * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team
+ * 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
+** 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 */
+#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) \
+#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) \
+/*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_ */
@@ -0,0 +1,619 @@
+ * File : drv_i2s.c
+#include <rthw.h>
+#include <drivers/audio.h>
+#include "dma.h"
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+#include "board.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__)
+#define AIC_DBG(...)
+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__)
+#define I2S_DBG(...)
+#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);
+int dump_aic_i2s(void)
+ dump_registers(_g_jz_i2s.aic);
+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);
+MSH_CMD_EXPORT(i2scdr_extclk,set i2s cdr ext clk...);
+int i2scdr_pllclk(void)
+ regValue |= (0x01 << 30);
+MSH_CMD_EXPORT(i2scdr_pllclk,set i2s cdr pll clk...);
+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_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_en_tur_int(aic);
+ __aic_flush_rxfifo(aic);
+ rt_thread_delay(1);
+ __i2s_enable_record(aic);
+ __i2s_enable_receive_dma(aic);
+ __aic_en_ror_int(aic);
+ I2S_DBG("strtup sub stream ok!\n");
+static void aic_i2s_stop_substream(struct jz_i2s *i2s,int stream)
+ __aic_dis_tur_int(aic);
+ if (__i2s_transmit_dma_is_enable(aic))
+ //wait all dma queue is complete
+ while(i2s->tx_dmac->get_index != i2s->tx_dmac->put_index)
+ __i2s_disable_transmit_dma(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);
+// 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);
+int aic_i2s_set_clkdiv(struct jz_i2s *i2s,int div_id, int div)
+ 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)
+ 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);
+ __i2s_bclk_input(aic);
+ __i2s_sync_input(aic);
+ 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 */
+ __i2s_send_rfirst(aic);
+ i2s->i2s_mode |= I2S_WRITE;
+ i2s->i2s_mode |= I2S_READ;
+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);
+int aic_i2s_hw_params(struct jz_i2s* i2s,int stream)
+ struct dma_config config;
+ int trigger;
+ int bus_width;
+ I2S_DBG("upgrade hw params...\n");
+ /* 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;
+ 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");
+ 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_maxburst = (I2S_RFIFO_DEPTH * bus_width)/2;
+ 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);
+void aic_i2s_shutdown(struct jz_i2s *i2s,int stream)
+ i2s->i2s_mode &= ~I2S_WRITE;
+ i2s->i2s_mode &= ~I2S_READ;
+int aic_i2s_set_sysclk(struct jz_i2s *i2s,uint32_t freq)
+#ifdef RT_USING_ICODEC
+ __aic_select_internal_codec(aic);
+ __aic_select_external_codec(aic);
+ __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);
+ /* Master clk input */
+ __i2s_select_sysclk_input(aic);
+ __i2s_disable_sysclk_output(aic);
+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);
+ 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;
+ 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;
+rt_size_t aic_i2s_recv(struct jz_i2s *i2s, void* buffer, rt_size_t size,void (*rx_callback)(void *,void *), void *rx_arg)
+ 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_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)
+struct jz_i2s *rt_hw_aic_i2s_init(void)
+ struct jz_aic *aic;
+ struct jz_i2s *i2s = &_g_jz_i2s;
+#ifndef RT_USING_ICODEC
+ gpio_set_func(GPIO_PORT_B, GPIO_Pin_0, GPIO_FUNC_1); // I2S_MCLK
+ 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
+ aic = _aic_init();
+ if(aic == RT_NULL)
+ i2s->aic = aic;
+ i2s->i2s_mode = 0;
+ /* now ,we just support I2S playback */
+ aic_i2s_startup(i2s,AUDIO_STREAM_REPLAY);
+ aic_i2s_hw_params(i2s,AUDIO_STREAM_REPLAY);
+ return i2s;
@@ -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_
+# define CODEC_AS_MASTER
+#define CODEC_DEF_RATE (24000000)
+//# undef CODEC_AS_MASTER
+//# define CODEC_AS_MASTER
+#define CODEC_DEF_RATE (44100)
+#ifdef RT_USING_ECODEC_WM8978
+# define CFG_AIC_I2S_EXT_CODEC
+#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
+ 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_ */
@@ -0,0 +1,826 @@
+#include "drv_codec_icodec.h"
+#define CODEC_DEBUG 0
+#if CODEC_DEBUG
+#define CODEC_DBG(...) rt_kprintf("[CODEC]"),rt_kprintf(__VA_ARGS__)
+#define CODEC_DBG(...)
+ * 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,
+ 0x34,0x07,0x44,0x1f,0x00,
+ 0x00,0x00,0x30,0xb0,0x01,0x00,0x00,0x00,0x0F,0x40,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xff,
+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:
+static int jz_icodec_reg_writable(uint32_t reg)
+ switch (reg) {
+static int jz_icodec_reg_readable(uint32_t reg)
+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;
+ val = 95 - val;
+ return val;
+ if (jz_icodec_reg_readable(reg))
+ return icodec_hw_read(icodec, reg);
+static int jz_icodec_reg_write(struct jz_icodec *codec, uint16_t reg, int value)
+ int val = value;
+ if (jz_icodec_reg_writable(reg))
+ if((reg == SCODA_REG_GCR_DACL)||(reg == SCODA_REG_GCR_DACR))
+ if(val < 32)
+ _g_icodec_reg_defcache[reg] = val;
+ return icodec_hw_write(codec, reg, val);
+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;
+ 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);
+ 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;
+static void jz_icodec_hw_params(struct jz_icodec* icodec,int stream)
+ int playback = (stream == AUDIO_STREAM_REPLAY);
+ 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;
+ case AUDIO_FMT_PCM_S24_LE:
+ bit_width_sel = 3;
+ /*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);
+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)
+ else if(stream == AUDIO_STREAM_RECORD)
+#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);
+ jz_icodec_digital_mute(icodec,0);
+#define REPLAY_MIXER_REG_MAX 31
+int jz_icodec_set_replay_mixer_volume(struct jz_icodec *icodec,int val)
+ 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);
+#define DIGITAL_CAP_REG_MAX 43
+int jz_icodec_set_digital_capture_volume(struct jz_icodec *icodec,int val)
+ 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);
+#define DIGITAL_CAP_MIX_REG_MAX 31
+int jz_icodec_set_digital_capture_mixer_volume(struct jz_icodec *icodec,int val)
+ 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);
+#define MIC_REG_MAX 4
+int aic_icodec_set_mic_volume(struct jz_icodec *icodec,int val)
+ phyValue = MIC_REG_MAX - (val) * MIC_REG_MAX / VOLUME_MAX;
+ jz_icodec_reg_write(icodec,SCODA_REG_GCR_MIC1,phyValue);
+ 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));
+ 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));
+ 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;
+ result = -RT_ERROR;
+ case AUDIO_TYPE_OUTPUT: /* Provide capabilities of OUTPUT unit */
+ case AUDIO_DSP_PARAM:
+ if (audio->replay == NULL)
+ 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;
+ case AUDIO_TYPE_MIXER: /* report the Mixer Units */
+ case AUDIO_MIXER_QUERY:
+ caps->udata.mask = AUDIO_MIXER_VOLUME | AUDIO_MIXER_DIGITAL | AUDIO_MIXER_LINE;
+ case AUDIO_MIXER_VOLUME:
+ caps->udata.value = icodec->user_replay_volume;
+ case AUDIO_MIXER_DIGITAL:
+ case AUDIO_MIXER_LINE:
+ return result;
+static rt_err_t icodec_configure (struct rt_audio_device *audio,struct rt_audio_caps *caps)
+ struct jz_icodec *icodec = (struct jz_icodec *) audio->parent.user_data;
+ case AUDIO_TYPE_MIXER:
+ int volume = caps->udata.value;
+ jz_icodec_set_replay_volume(icodec, volume);
+ int gain = caps->udata.value;
+ jz_icodec_set_replay_mixer_volume(icodec, gain);
+ //set linein valume...
+ case AUDIO_MIXER_EXTEND:
+ case AUDIO_TYPE_OUTPUT:
+ 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;
+ case AUDIO_DSP_SAMPLERATE:
+ int rate = caps->udata.value;
+ jz_icodec_set_sampling_rate(icodec, rate);
+static rt_err_t icodec_init (struct rt_audio_device *audio)
+ uint16_t i;
+ /* disable shutdown */
+ gpio_set_value(AUDIO_SHUTDOWN_PORT,AUDIO_SHUTDOWN_PIN,AUDIO_SHUTDOWN_MUTE);
+ gpio_set_value(AUDIO_SHUTDOWN_PORT,AUDIO_SHUTDOWN_PIN,!AUDIO_SHUTDOWN_MUTE);
+ /* 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 */
+ /* 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));
+ jz_icodec_set_sampling_rate(icodec,ICODEC_SAMPLING_RATE);
+static rt_err_t icodec_shutdown (struct rt_audio_device *audio)
+#ifdef AUDIO_SHUTDOWN_PORT
+rt_err_t icodec_start (struct rt_audio_device *audio,int stream)
+ aic_i2s_trigger(icodec->i2s,I2S_TRIGGER_START,stream);
+rt_err_t icodec_stop (struct rt_audio_device *audio,int stream)
+ aic_i2s_trigger(icodec->i2s,I2S_TRIGGER_STOP,stream);
+static rt_err_t icodec_suspend (struct rt_audio_device *audio,int stream)
+ aic_i2s_trigger(icodec->i2s,I2S_TRIGGER_SUSPEND,stream);
+static rt_err_t icodec_resume (struct rt_audio_device *audio,int stream)
+ aic_i2s_trigger(icodec->i2s,I2S_TRIGGER_RESUME,stream);
+static rt_err_t icodec_control (struct rt_audio_device *audio, int cmd, void *args)
+ case AUDIO_CTL_HWRESET:
+ 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;
+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)
+ 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);
+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");
+ 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");
+ rt_kprintf("codec initialization done!\n");
+INIT_DEVICE_EXPORT(rt_hw_codec_init);
+#endif /* RT_USING_ICODEC */
@@ -0,0 +1,406 @@
+ * drv_codec_icodec.h
+ * Created on: 2017Äê1ÔÂ10ÈÕ
+#ifndef _DRV_CODEC_ICODEC_H_
+#define _DRV_CODEC_ICODEC_H_
+#include <stdint.h>
+struct jz_icodec
+ struct rt_audio_configure replay_config;
+ struct rt_mempool mp;
+ 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)
+#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)
+ 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");
+ 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 = ((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)
+ 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;
+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);
+ case SCODA_DAC_AGC0 ... SCODA_DAC_AGC3:
+ creg = SCODA_REG_CR_DAC_AGC;
+ dreg = SCODA_REG_DR_DAC_AGC;
+ sreg -= (SCODA_MIX_4 +1);
+ case SCODA_DAC2_AGC0 ... SCODA_DAC2_AGC3:
+ creg = SCODA_REG_CR_DAC2;
+ dreg = SCODA_REG_DR_DAC2_AGC;
+ sreg -= (SCODA_DAC_AGC3 + 1);
+ case SCODA_ADC_AGC0 ... SCODA_ADC_AGC4:
+ creg = SCODA_REG_CR_ADC_AGC;
+ dreg = SCODA_REG_DR_ADC_AGC;
+ sreg -= (SCODA_ADC_AGC4 + 1);
+// 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;
+static uint8_t icodec_hw_read_extend(struct jz_icodec *icodec, uint8_t sreg)
+ int creg, cdata, dreg, ddata;
+ switch (sreg)
+ cdata = (icodec_hw_read_normal(icodec, creg) & (~0x7f)) | (sreg & 0x3f);
+ 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);
+ return icodec_hw_read_normal(icodec, reg);
+static inline int icodec_hw_write(struct jz_icodec *icodec, int reg, int data)
+ return icodec_hw_write_extend(icodec, reg, data);
+ return icodec_hw_write_normal(icodec, reg, data);
+#endif /* _DRV_CODEC_ICODEC_H_ */
@@ -0,0 +1,428 @@
+ * File : drv_dmic.c
+# include <finsh.h>
+#include "drv_dmic.h"
+#include "audio_pipe.h"
+#define DMIC_DEBUG 0
+#if DMIC_DEBUG
+# define DMIC_DBG(...) rt_kprintf("[DMIC]"),rt_kprintf(__VA_ARGS__)
+# define DMIC_DBG(...)
+#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));
+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);
+ case 16000:
+ __dmic_set_sr_16k(dmic);
+ case 48000:
+ __dmic_set_sr_48k(dmic);
+ DMIC_DBG("dmic unsupport rate %d\n", rate);
+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;
+ /* 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_uint32_t i;
+ __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.dst_addr = (uint8_t *) (dmic->dma_buf + DMIC_DMA_PAGE_SIZE * i);
+ 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");
+ 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");
+ 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
+ /* DMA 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.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;
+ 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:
+ rt_audio_pipe_detach(&dmic->pipe);
+ clk_disable(dmic->clk_gate);
+//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 <dfs_posix.h>
+rt_uint8_t rec_buff[2048];
+int dmic_record(int samplingrates)
+ 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");
+ 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";
+ 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");
+ 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);
+ wav_len += wrlen;
+ if(gpio_get_value(GPIO_PORT_B, GPIO_Pin_31) == 1)
+ 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));
+ rt_kprintf("WAV file saved ok!\n");
+FINSH_FUNCTION_EXPORT(dmic_record,dmic record test);
+int dmic_test(void)
+ device = rt_device_find("recdmic");
+ audio_device_set_rate(8000);
+ 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");
+MSH_CMD_EXPORT(dmic_test,dmic test ....);
@@ -0,0 +1,262 @@
+ * drv_dmic.h
+ * Created on: 2017Äê1ÔÂ11ÈÕ
+#ifndef _DRV_DMIC_H_
+#define _DRV_DMIC_H_
+ * File : drv_dmic.h
+ * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team
+#include <dma.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;
+ 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)\
+ 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)\
+#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_ */
@@ -24,6 +24,7 @@
#include <rthw.h>
#include <rtthread.h>
+#include <string.h>
#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--;
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);
@@ -0,0 +1,102 @@
+ * File : board.h
+#ifndef _BOARD_H_
+#define _BOARD_H_
+#define RT_USING_JZ_X1000
+#define X1000
+#ifdef BOARD_HALLEY2_FIR
+#include "board/halley2_fir/board_halley2_fir.h"
+#ifdef BOARD_HALLEY2_REALBOARD
+#include "board/halley2_realboard/board_halley2_readboard.h"
+#ifdef BOARD_HALLEY2_REALBOARD_V2
+#include "board/halley2_realboard_v2/board_halley2_readboard_v2.h"
+#ifdef BOARD_HALLEY2_IDELAN
+#include "board/halley2_idelan/board_halley2_idelan.h"
+#ifdef BOARD_HALLEY2
+#include "board/halley2/board_halley2.h"
+#ifdef BOARD_PHOENIX
+#include "board/phoenix/board_phoenix.h"
+#ifdef BOARD_CANNA
+#include "board/canna/board_canna.h"
+ * 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_ */
@@ -0,0 +1,6 @@
+#ifndef BOARD_CANNA_H__
+#define BOARD_CANNA_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
@@ -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
+2016/08/29发布
+已知的硬件错误:
+-I2S 信号分配错误 I2SDI I2SDO反了 核心板的DO是输出 Codec的DO也是输出,核心板的DO需要接到Codec的SDI0上
+-X1 12.288晶振不焊接,R13 需要焊接,核心板提供时钟(layout的时候,晶振保留)
+-
+-layout问题,整个板子GND走线 很多实连接,手工焊接质量不保证
@@ -0,0 +1,5 @@
+#define AUDIO_SHUTDOWN_PIN GPIO_Pin_6
+#define LCD_RST_PORT GPIO_PORT_C
+#define LCD_RST_PIN GPIO_Pin_25
+#define LCD_BL_PIN GPIO_Pin_19
@@ -0,0 +1,61 @@
+ * File : board_halley2_readboard_v2.h
+ * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team
+ * 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" {
+#define AUDIO_SHUTDOWN_PORT GPIO_PORT_C
+#define AUDIO_SHUTDOWN_PIN GPIO_Pin_26
+#define AUDIO_SHUTDOWN_MUTE 0
+#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
+#endif /* DRIVER_BOARD_HALLEY2_REALBOARD_V2_BOARD_HALLEY2_READBOARD_V2_H_ */
@@ -0,0 +1,4 @@
+#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
@@ -0,0 +1,222 @@
+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)
+ 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);
+ gpio_set_value(GPIO_PORT_C, GPIO_Pin_17, 1);
+INIT_DEVICE_EXPORT(io_AP6212);
+#if defined(RT_USING_BT) && (defined(WIFI_USING_AP6212) || defined(WIFI_USING_AP6181))
+#include <drv_rtc.h>
+ * PC16 32768 clock
+int io_AP6212_bt(void)
+ rtc32k_enable();
+INIT_DEVICE_EXPORT(io_AP6212_bt);
+#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);
+INIT_DEVICE_EXPORT(io_canna);
+#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);
+ gpio_direction_output(GPIO_PORT_C, GPIO_Pin_23, 1);
+INIT_DEVICE_EXPORT(io_halley2);
+#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);
+ gpio_direction_output(GPIO_PORT_B, GPIO_Pin_3, 1);
+INIT_DEVICE_EXPORT(io_phoenix);
+#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);
+ // gpio_set_func(GPIO_PORT_C, GPIO_Pin_23, GPIO_FUNC_0);
+INIT_DEVICE_EXPORT(io_ox);
+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);
+ 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);
+ _delay_ms(100);
+INIT_BOARD_EXPORT(io_realboard);
+#endif /* BOARD_HALLEY2_REALBOARD_X1000 */
+int io_realboard_v2(void)
+ /* 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);
+ 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);
+INIT_BOARD_EXPORT(io_realboard_v2);
+#endif /* BOARD_HALLEY2_REALBOARD_V2 */
+int io_halley2_fir(void)
+ /* 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);
+ 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);
+INIT_BOARD_EXPORT(io_halley2_fir);
+#endif /* BOARD_HALLEY2_FIR */
@@ -0,0 +1,305 @@
+ * File : drv_gpio_keyboard.c
+** Include Files
+#include "board_key.h"
+#ifdef RT_USING_AUDIO_PLAYER
+#include <player_app.h>
+#define KEY_DEBUG
+#ifdef KEY_DEBUG
+#define KEY_DBG(...) rt_kprintf("[KEY]"),rt_kprintf(__VA_ARGS__)
+#define KEY_DBG(...)
+static keyboard_event_handler_t _handler = RT_NULL;
+/* 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
+ //ON/OFF
+ 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[] =
+ GPIO_PORT_D, GPIO_Pin_0,
+ KEY_UNKNOWN, KEY_UNKNOWN,
+ //WIFI config
+ GPIO_PORT_D, GPIO_Pin_2,
+ //PWRKEY KEY
+ KEY_UNKNOWN, KEY_UNKNOWN
+#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;
+ // 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);
+ KEY_DBG("key %d down\n", keyId);
+ //Wait for key RELEASE
+ keyHoldTime = 0;
+ if(keyEvent == KEY_EVENT_HOLD)
+ keyHoldTime += KEY_SCAN_STEP_TIME;
+ if(keyHoldTime > KEY_SCAN_HOLD_THRESHOLD)
+ } while (keyEvent != KEY_EVENT_UP);
+ KEY_DBG("key %d up,hold time = %dms\n", keyId,keyHoldTime);
+ keyValue = key->longKey;
+ keyValue = key->shortKey;
+ //send key event
+ if (_handler) _handler(EVENT_KEY_DOWN | keyValue);
+ //Wait for KEYUP
+ while (keyEvent != KEY_EVENT_UP)
+ rt_thread_delay(RT_TICK_PER_SECOND / 10);
+ if (_handler) _handler(EVENT_KEY_UP | keyValue);
+void rt_hw_keyboard_set_handler(keyboard_event_handler_t handler)
+ _handler = handler;
+void rt_hw_keyboard_init(void)
+ int i;
+ tid = rt_thread_create("key", kbd_thread, RT_NULL, 2048, 16, 10);
+ if (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);
@@ -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,
+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);
@@ -0,0 +1,104 @@
+ * File : drv_gpio_led.c
+ * 2016/05/13 Urey the first version
+#include "board_led.h"
+#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
+#define MAX_LED_NBR 0
+struct led_io_def led_io_tbl[] =
+ GPIO_PORT_B,
+ GPIO_Pin_6
+void rt_hw_led_on(int led)
+ if((led >= LED_LAST) || (led > MAX_LED_NBR))
+ gpio_set_value(led_io_tbl[led].port,led_io_tbl[led].pin,0);
+void rt_hw_led_off(int led)
+ 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);
+INIT_DEVICE_EXPORT(rt_hw_led_init);
@@ -0,0 +1,13 @@
+#ifndef BOARD_LED_H__
+#define BOARD_LED_H__
+struct led_io_def
+void rt_hw_led_off(int led);
+void rt_hw_led_on (int led);
@@ -0,0 +1,357 @@
+ * File : dma.c
+** 全局变量
+** 宏定义
+#define DMA_DEBUG 0
+#if DMA_DEBUG
+#include <stdio.h>
+#define DMA_DBG(...) rt_kprintf("[DMA]"),rt_kprintf(__VA_ARGS__)
+#define DMA_DBG(...)
+#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); \
+#define __DMA_CHANNEL_STATUS(ch, ret) do { \
+ if (dmac->ops && dmac->ops->status) {\
+ ret = dmac->ops->status(dmac); \
+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
+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");
+ /* 挂载到通道列表 */
+ 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);
+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;
+//
+///*********************************************************************************************************
+//** 函数名称: 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 rt_dma_trans_message (struct rt_dma_channel *dmac,struct dma_message* message)
+ rt_err_t result;
+ rt_uint16_t next_index;
+ struct dma_message *msg_node;
+ 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);
+ //判断传输队列是否满
+ next_index = dmac->put_index + 1;
+ if(next_index >= RT_DMA_MAX_NODES)
+ next_index = 0;
+ if(next_index == dmac->get_index)
+ 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;
+ /* check message list whether is empty */
+ if(next_index == dmac->put_index)
+ /* Make a DMA transfer */
+ if(dmac->start != RT_NULL)
+ dmac->start(dmac,message);
+ do{
+ __DMA_CHANNEL_TRANS(dmac, message, ret); /* 初始化传输诸元 */
+ (void)ret;
+ } while (0);
+** 函数名称: rt_dma_configture
+** 功能描述: DMA 通道配置
+** 输 入: struct rt_dma_channel *dmac,struct dma_config *config
+rt_err_t rt_dma_configture (struct rt_dma_channel *dmac,struct dma_config *config)
+ RT_ASSERT(config != RT_NULL);
+} /* rt_dma_configture */
+** 函数名称: rt_dma_get_current_message
+** 功能描述: DMA 获取当前传输的消息句柄
+** 输 入: struct rt_dma_channel *dmac
+** 返 回: struct dma_message *
+struct dma_message * rt_dma_get_current_message (struct rt_dma_channel *dmac)
+ struct dma_message *message;
+ message = &(dmac->msg_list[dmac->get_index]);
+ return message;
+} /* rt_dma_get_current_message */
+** 函数名称: rt_dma_contex_service
+** 功能描述: DMA 中断服务
+** 输 入: rt_uint32_t channel
+** 备 注: global
+rt_err_t rt_dma_contex_service (struct rt_dma_channel *dmac,rt_uint32_t event)
+ rt_size_t data_size;
+ struct dma_message *last_message,*message;
+ switch (event)
+ case RT_DMA_EVENT_COMPLETE:
+ /* 优先发送 缓冲区中的消息 */
+ last_message = &(dmac->msg_list[dmac->get_index]);
+ dmac->get_index = next_index;
+ if(dmac->get_index != dmac->put_index)
+ /* 队列中有消息未发送,优先处理 */
+ /* 处理上一个消息的回调函数 */
+ dmac->complete(dmac, last_message);
@@ -0,0 +1,155 @@
+ * File : dma.h
+#ifndef _DMA_H_
+#define _DMA_H_
+#include <stdlib.h>
+#include <rtdef.h>
+extern "C"{
+#define RT_DMA_CHANNEL(n) (n)
+#ifndef RT_DMA_MAX_NODES
+# define RT_DMA_MAX_NODES 8
+** 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_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);
+#endif /* _DMA_H_ */
@@ -21,16 +21,16 @@
* 2015-11-19 Urey the first version
#include <rtdevice.h>
-#include <x1000.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 ,
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;
-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{
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<<cgu_audio_clks[no].bitm)|(n<<cgu_audio_clks[no].bitn);
@@ -975,8 +1011,9 @@ static int cgu_audio_calculate_set_rate(struct clk* clk, uint32_t rate, uint32_t
cgu_audio_clks[no].cache = tmp_val;
- writel(d - 1,I2S_PRI_DIV);
+ cpm_outl(0,CPM_I2SCDR1);
+ writel(d - 1,I2S_PRI_DIV);
else if (no == CGU_AUDIO_PCM)
@@ -1094,10 +1131,12 @@ static int cgu_audio_set_rate(struct clk *clk, uint32_t rate)
- cgu_audio_calculate_set_rate(clk,rate,CLK_ID_MPLL);
if(get_clk_id(clk->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);
@@ -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)
INIT_BOARD_EXPORT(init_all_clk);
+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);
+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);
+MSH_CMD_EXPORT(clk, clock information dump);
+int uart0_clk(void)
+int uart1_clk(void)
+ value &= ~(1 << 15);
@@ -27,66 +27,6 @@
-#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
@@ -0,0 +1,537 @@
+ * File : drv_dma.c
+#include <cache.h>
+#define JZDMA_DEBUG 0
+#if JZDMA_DEBUG
+#define JZDMA_DBG(...) rt_kprintf(__VA_ARGS__)
+#define JZDMA_DBG(...)
+/* 全局变量 */
+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 _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)
+ 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);
+ *dst_addr = ret_val;
+ *src_addr = readl(jz_dmac->iomem + CH_DSA);
+ else if (direction == RT_DMA_MEM_TO_MEM)
+ return ret_val;
+int jzdma_funcs_status(struct rt_dma_channel *dmac)
+ struct jzdma_channel *jz_dmac;
+ jz_dmac = (struct jzdma_channel *)dmac->user_data;
+ switch (jz_dmac->status)
+ case STAT_STOPED:
+ return RT_DMA_STATUS_IDLE;
+ return RT_DMA_STATUS_BUSY;
+void jzdma_funcs_reset(struct rt_dma_channel *rt_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;
+ case RT_DMA_BUSWIDTH_2_BYTES:
+ jz_dmac->desc.dcm |= DCM_SP_16 | DCM_DP_16;
+ case RT_DMA_BUSWIDTH_4_BYTES:
+ jz_dmac->desc.dcm &= ~(DCM_SP_32 | DCM_DP_32);
+ JZDMA_DBG("bus width error. \r\n");
+ /* 其他方式 按照源地址宽度设置 DCM */
+ switch(rt_dmac->config.src_addr_width)
+rt_size_t jzdma_funcs_transfer(struct rt_dma_channel *rt_dmac , struct dma_message *message)
+ uint32_t tsz;
+ if(jz_dmac->status == STAT_RUNNING)
+ return -RT_EBUSY;
+ /* 清除硬件寄存器 */
+// writel(0, jz_dmac->iomem + CH_DCM);
+// writel(0, jz_dmac->iomem + CH_DCS);
+ //刷新cache
+ switch(rt_dmac->config.direction)
+ case RT_DMA_MEM_TO_MEM:
+ rt_hw_dcache_flush_range((rt_ubase_t)(message->src_addr),message->t_size);
+// /* 重新设置参数 */
+// 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;
+// case RT_DMA_BUSWIDTH_4_BYTES:
+// jz_dmac->desc.dcm &= ~(DCM_SP_32 | DCM_DP_32);
+// default:
+// JZDMA_DBG("bus width error. \r\n");
+// return -1;
+// }
+// /* 其他方式 按照源地址宽度设置 DCM */
+// switch(rt_dmac->config.src_addr_width)
+// return 0;
+ /* 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;
+ case RT_DMA_ADDR_FIX:
+ jz_dmac->desc.dcm &= ~DCM_SAI;
+ switch(message->dst_option)
+ jz_dmac->desc.dcm |= DCM_DAI;
+ jz_dmac->desc.dcm &= ~DCM_DAI;
+ /* 设置TSZ */
+ if(rt_dmac->ch == 1)
+ /*
+ * for special channel1 tsz = 7 (auto)
+ jz_dmac->desc.dcm |= 7 << 8;
+ tsz = message->t_size;
+ 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;
+ tsz = get_max_tsz((uint32_t)(message->dst_addr) | message->t_size | rt_dmac->config.src_maxburst, &jz_dmac->desc.dcm);
+ 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;
+ 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;
+ 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)))
+ dcs = readl(jz_dmac->iomem + CH_DCS);
+ jz_dmac->dcs_saved = dcs;
+ if (jz_dmac->status != STAT_RUNNING)
+ /* 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)
+ JZDMA_DBG("DMA CH%d Over\n",i);
+ case RT_DMA_DEV_TO_MEM:
+ 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);
+ 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)
+ uint32_t pending;
+ pending = readl(master->base + DESIRQP);
+ JZDMA_DBG("Link INT \n");
+ 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)
+ 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);
+ 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->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);
+INIT_DEVICE_EXPORT(rt_hw_jzdma_init);
@@ -0,0 +1,224 @@
+ * File : drv_dma.h
+#ifndef _DRV_DMA_H_
+#define _DRV_DMA_H_
+#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
+#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
+ JZDMA_REQ_AUTO = JZDMA_REQ_AUTO_TXRX,
+ JZDMA_REQ_SADC = JZDMA_REQ_SADC_RX,
+ 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,
+#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
+ 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_ */
@@ -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)
- 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)
@@ -27,13 +27,13 @@
#include <stdint.h>
-#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_ */
@@ -0,0 +1,843 @@
+#define I2C_DEBUG 0
+#if I2C_DEBUG
+#define I2C_DBG(...) rt_kprintf("[I2C]"),rt_kprintf(__VA_ARGS__)
+#define I2C_DBG(...)
+#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;
+ enum msg_end_type w_end_type;
+ enum msg_end_type r_end_type;
+ unsigned char *rbuf;
+ unsigned char *wbuf;
+ unsigned int rd_len;
+ unsigned int rate;
+ struct rt_completion completion;
+#ifdef RT_USING_I2C0
+static struct ingenic_i2c_bus ingenic_i2c0;
+#ifdef RT_USING_I2C1
+static struct ingenic_i2c_bus ingenic_i2c1;
+#ifdef RT_USING_I2C2
+static struct ingenic_i2c_bus ingenic_i2c2;
+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))
+ if (timeout) return 0;
+ I2C_DBG("disable i2c failed!\n");
+ return -RT_ETIMEOUT;
+static int ingenic_i2c_enable(struct ingenic_i2c_bus *i2c)
+ i2c_writel(i2c, I2C_ENB, 1);
+ while (!(i2c_readl(i2c, I2C_ENSTA) & I2C_ENB_I2CENB) && (--timeout > 0))
+ I2C_DBG("enable i2c failed\n");
+static void ingenic_i2c_reset(struct ingenic_i2c_bus *i2c)
+ i2c_readl(i2c, I2C_CTXABRT);
+ i2c_readl(i2c, I2C_INTST);
+ ingenic_i2c_disable(i2c);
+ 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);
+ tmp = 0x45 | (1 << 5); /* fast speed mode */
+ /* 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));
+ * ____ ____
+ * 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;
+ i2c_writel(i2c, I2C_SHCNT, I2CSHCNT_ADJUST(cnt_high));
+ i2c_writel(i2c, I2C_SLCNT, I2CSLCNT_ADJUST(cnt_low));
+ 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);
+/* 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");
+ if (!tx_count || !rx_count)
+ I2C_DBG("###Warning: I2C receive fifo or transfer fifo is full, "
+ "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);
+ while (count > 0)
+static void txabrt(struct ingenic_i2c_bus *i2c, int src)
+ 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);
+ I2C_DBG("--I2C disable clk timeout, I2C_STA = 0x%x\n", tmp);
+ ingenic_i2c_reset(i2c);
+static inline int xfer_read(struct ingenic_i2c_bus *i2c, unsigned char *buf, int len, enum msg_end_type end_type)
+ long timeout;
+ 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);
+ 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");
+ 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;
+ /* abort read */
+ if (tmp & (1 << 5)) {
+ ret = -RT_ERROR;
+ if (ret < 0) ingenic_i2c_reset(i2c);
+static inline int xfer_write(struct ingenic_i2c_bus *i2c, unsigned char *buf, int len, enum msg_end_type end_type)
+ long timeout = TIMEOUT;
+ unsigned short reg_tmp;
+ i2c->wbuf = buf;
+ i2c_writel(i2c, I2C_TXTL, TX_LEVEL);
+ 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);
+ 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)
+ //after I2C_TXABRT_ABRT_XDATA_NOACK error,this required core to resend
+ if (reg_tmp & 8)
+static rt_size_t ingenic_i2c_xfer(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num)
+ 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 */
+ 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);
+ ret = xfer_write(i2c, msgs[i].buf, msgs[i].len, end_type);
+ 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;
+ 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))
+ if ((intmsk & I2C_INTM_MTXEMP) && (intst & I2C_INTST_TXEMP))
+ if (!i2c->len)
+ if (i2c->w_end_type == MSG_END_REPEAT_START)
+ tmp = i2c_readl(i2c, I2C_INTM);
+ tmp &= ~I2C_INTM_MTXEMP;
+ while ((i2c->len > 0) && (i2c_readl(i2c, I2C_STA) & I2C_STA_TFNF))
+ tmp = *i2c->wbuf++;
+ if (i2c->w_end_type == MSG_END_STOP)
+ tmp |= I2C_DC_STP;
+ i2c_writel(i2c, I2C_DC, tmp);
+ 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--;
+ goto END_RECE_IRQ_HND;
+ if (i2c->len <= I2C_FIFO_LEN)
+ i2c_writel(i2c, I2C_RXTL, i2c->len - 1);
+ 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__);
+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 rt_i2c_bus_device *i2c_bus;
+ 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);
+ i2c->clk = clk_get("i2c0");
+ 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);
+ /* install interrupt */
+ rt_hw_interrupt_install(i2c->irqno, i2c_irq_handler, i2c, "i2c0");
+ rt_hw_interrupt_umask(i2c->irqno);
+ i2c = &ingenic_i2c1;
+ 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);
+ i2c->clk = clk_get("i2c1");
+ rt_i2c_bus_device_register(i2c_bus, "i2c1");
+ rt_hw_interrupt_install(i2c->irqno, i2c_irq_handler, i2c, "i2c1");
+ i2c = &ingenic_i2c2;
+ i2c->hwaddr = I2C2_BASE;
+ i2c->irqno = IRQ_I2C2;
+ gpio_set_func(GPIO_PORT_D, GPIO_Pin_0, GPIO_FUNC_1);
+ gpio_set_func(GPIO_PORT_D, GPIO_Pin_1, GPIO_FUNC_1);
+ i2c->clk = clk_get("i2c2");
+ rt_i2c_bus_device_register(i2c_bus, "i2c2");
+ rt_hw_interrupt_install(i2c->irqno, i2c_irq_handler, i2c, "i2c2");
+INIT_BOARD_EXPORT(rt_hw_i2c_init);
+#ifndef DRV_I2C_H__
+#define DRV_I2C_H__
@@ -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);
+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);
+MSH_CMD_EXPORT(ost, ost debug);
@@ -137,6 +137,6 @@
#define OST_DIV4 (0x1)
#define OST_DIV16 (0x2)
-void rt_hw_ost_init(void);
+int rt_hw_ost_init(void);
@@ -0,0 +1,97 @@
+ * File : drv_pin.c
+#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(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(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),
@@ -0,0 +1,252 @@
+ * File : drv_pmu.c
+ * 2016-03-29 Urey the first version
+#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 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;
+ 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);
+ 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);
+ 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);
+ 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); */
+ * 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));
+int drv_pmu_get_keypwr(void)
+ int level = 0;
+#ifdef BOARD_CANNA_OVC
+ level = gpio_get_value(DET_PWR_PORT,DET_PWR_PIN);
+ _delay_ms(5); //È¥¶¶
+ }while(level != gpio_get_value(DET_PWR_PORT,DET_PWR_PIN));
+ return level;
+void drv_pmu_power_down(void)
+ 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);
+ gpio_direction_output(CTR_LOCK_PORT, CTR_LOCK_PIN, 1);
+ rt_hw_led_off(LED_GREEN);
+ rt_hw_led_off(LED_RED);
+ rt_hw_led_off(LED_BLUE);
+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);
@@ -1,5 +1,5 @@
- * File : board_io.c
+ * File : drv_pmu.h
* COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team
@@ -19,9 +19,14 @@
+ * 2016-08-08 Urey the first version
-#include <board.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_ */
@@ -0,0 +1,355 @@
+ * File : drv_reset.c
+ * 2016Äê7ÔÂ29ÈÕ Urey the first version
+#include "drv_pmu.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)
+ 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(65535,WDT_BASE + WDT_TDR); //data
+ writel(1 << 16,TCU_BASE + TCU_TSSR);
+void wdt_clear(void)
+ writel(0,WDT_BASE + WDT_TCNT);
+static int inline reset_keep_power(void)
+void x1000_hibernate(void)
+ uint32_t rtc_rtccr;
+ wdt_stop_count();
+ /* 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);
+ 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);
+ //WDT...
+ cpm_outl(REBOOT_SIGNATURE, CPM_CPPSR);
+ wdt_start_count(4);
+ rt_kprintf("check wdt.\n");
+void x1000_hibernate_restart(char *command)
+ uint32_t rtc_rtcsr,rtc_rtccr;
+ 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_write_reg(RTC_RTCSAR,rtc_rtcsr + 5);
+ rtc_rtccr &= ~(1 << 4 | 1 << 1);
+ rtc_rtccr |= 0x3 << 2;
+ /* Clear reset status */
+ cpm_outl(0,CPM_RSR);
+ rtc_write_reg(RTC_BASE + RTC_HWCR, 0x9);
+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)
+ int command_size = 0;
+ command_size = ARRAY_SIZE(reset_command);
+ for (i = 0; i < command_size; i++)
+ if (!strncmp(reset_cmd, reset_command[i], strlen(reset_command[i])))
+ if(i == command_size)
+ return -RT_ERROR;
+ switch(i)
+ case 0:
+ x1000_wdt_restart("wdt");
+ case 1:
+ x1000_hibernate_restart("hibernate");
+ case 2:
+ x1000_wdt_restart("recovery");
+ rt_kprintf("not support command %d\n", i);
+struct wdt_reset
+ int msecs;
+static struct wdt_reset _wdt_param =
+ .msecs = 1000,
+rt_err_t _wdt_init(rt_watchdog_t *wdt)
+rt_err_t _wdt_control(rt_watchdog_t *wdt, int cmd, void *arg)
+ 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);
+ case RT_DEVICE_CTRL_WDT_START:
+ wdt_start_count(_wdt_param.msecs + 1000);
+ case RT_DEVICE_CTRL_WDT_STOP:
+ case RT_DEVICE_CTRL_WDT_KEEPALIVE:
+ wdt_clear();
+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();
+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);
+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()
+ x1000_hibernate();
- * File : mnt.c
+ * File : drv_reset.h
@@ -19,29 +19,31 @@
-#include <dfs_fs.h>
-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");
- rt_kprintf("File System initialzation failed!\n");
-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_ */
@@ -0,0 +1,196 @@
+ * File : drv_rtc.c
+ * 2016/7/28 Urey the first version
+#include <time.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);
+ printf("RTC alarm interrupt clean!\n");
+ rtc_alarm_handler();
+ rtc_clr_reg(RTC_RTCCR, RTC_RTCCR_1HZ);
+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);
+ 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 */
+static rt_size_t rt_rtc_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+static rt_err_t rt_rtc_control(rt_device_t dev, int cmd, void *args)
+ time_t *time;
+ RT_ASSERT(dev != RT_NULL);
+ 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);
+ case RT_DEVICE_CTRL_RTC_SET_TIME:
+ tm_now = localtime(time);
+ 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);
+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);
@@ -0,0 +1,205 @@
+ * drv_rtc.h
+ * Created on: 2016Äê12ÔÂ9ÈÕ
+#ifndef _DRV_RTC_H_
+#define _DRV_RTC_H_
+#ifndef RTC_BASE
+#define RTC_BASE 0xB0003000
+/*************************************************************************
+ * 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() \
+ __wait_write_ready(); \
+ jz_writel((RTC_BASE + RTC_WENR), WENR_WENPAT_WRITABLE); \
+ while (!(rtc_read_reg(RTC_BASE + RTC_WENR) & RTC_WENR_WEN) && timeout++); \
+/* Basic RTC ops */
+#define rtc_read_reg(reg) \
+({ \
+ unsigned int data; \
+ data = jz_readl(reg); \
+ } while (jz_readl(reg) != data); \
+ data; \
+})
+#define rtc_write_reg(reg, data) \
+ __wait_writable(); \
+ jz_writel(reg, data); \
+#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_ */
+ * File : board_spi_master.c
+#include "drv_spi.h"
+#define SSI_BASE SSI0_BASE
+#define DEBUG 0
+#if DEBUG
+#define PRINT(...) rt_kprintf(__VA_ARGS__)
+#define PRINT(...)
+#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); \
+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);
+ 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);
+ clk_set_rate(spi_bus->clk, 24000000);
+ cgv = cpm_rate / (2 * hz);
+ if (cgv > 0)
+ cgv -= 1;
+ spi_writel(spi_bus, SSI_GR, cgv);
+static uint32_t _spi_get_clk(struct jz_spi *spi_bus)
+ 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;
+ spi_send_data(spi_bus,0xFF);
+// PRINT("sendCount = %d\n",spi_bus->sendCount);
+static uint32_t _spi_do_read_fifo(struct jz_spi* spi_bus)
+ 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;
+ dummy = spi_readl(spi_bus, SSI_DR);
+ 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;
+ sendEntries = JZ_SSI_MAX_FIFO_ENTRIES;
+ intFlag = 1;
+ spi_start_transmit(spi_bus);
+ spi_bus->is_first = 0;
+ trigger = JZ_SSI_MAX_FIFO_ENTRIES - spi_bus->tx_trigger;
+ if (leaveEntries <= trigger)
+ lastFlag = 1;
+ sendEntries = CPU_ONCE_BLOCK_ENTRIES;
+ _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);
+ spi_disable_txfifo_half_empty_intr(spi_bus);
+ spi_disable_rxfifo_half_full_intr(spi_bus);
+ if(lastFlag)
+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);
+ spi_clear_errors(spi_bus);
+ flag++;
+ if ( spi_get_overrun(spi_bus) && spi_get_rx_error_intr(spi_bus) )
+ PRINT("OVER\n");
+ if ( spi_get_rxfifo_half_full(spi_bus) && spi_get_rxfifo_half_full_intr(spi_bus))
+ PRINT("RFHF\n");
+ if ( spi_get_txfifo_half_empty(spi_bus) && spi_get_txfifo_half_empty_intr(spi_bus))
+ PRINT("THFE\n");
+ _spi_do_xfer(spi_bus);
+// if (!flag)
+// rt_completion_done(&spi_bus->completion);
+static rt_uint32_t jz_spi_xfer(struct rt_spi_device* device, struct rt_spi_message* message)
+ 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_flush_fifo(spi_bus);
+ spi_enable_receive(spi_bus);
+#ifdef SSI_DEGUG
+ dump_spi_reg(hw);
+ 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;
+ rt_completion_wait(&spi_bus->completion,RT_WAITING_FOREVER);
+ spi_finish_transmit(spi_bus);
+ /* release CS */
+ if (message->cs_release)
+ jz_spi_set_cs(_spi_cs,1);
+ 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;
+ 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);
+ spi_set_clock_phase(spi_bus, 0);
+ /* CPHA */
+ if (configuration->mode & RT_SPI_CPOL)
+ spi_set_clock_polarity(spi_bus, 1);
+ 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);
+ spi_set_tx_lsb(spi_bus);
+ spi_set_rx_lsb(spi_bus);
+ /* Enable SSIE */
+ spi_enable(spi_bus);
+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_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
+ /* 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);
+INIT_BOARD_EXPORT(rt_hw_spi_master_init);
@@ -0,0 +1,635 @@
+ * File : board_spi_master.h
+#ifndef DRV_SPI_H__
+#define DRV_SPI_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 jz_spi_rx_dma
+ rt_bool_t activated;
+struct jz_spi_tx_dma
+ struct rt_data_queue data_queue;
+typedef struct jz_spi
+ struct rt_spi_bus parent;
+// struct rt_semaphore spi_done_sem;
+ 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
+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)
+ tmp = (tmp & ~CR1_PHA) | (cpha ? CR1_PHA : 0);
+static inline void spi_set_clock_polarity(struct jz_spi *spi, unsigned int cpol)
+ tmp = (tmp & ~CR1_POL) | (cpol ? CR1_POL : 0);
+static inline void spi_set_tx_msb(struct jz_spi *spi)
+ 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)
+ tmp |= (tmp & ~CR0_TENDIAN_MASK) | (0x3 << CR0_TENDIAN_BIT);
+static inline void spi_set_rx_msb(struct jz_spi *spi)
+ tmp &= ~CR0_RENDIAN_MASK;
+static inline void spi_set_rx_lsb(struct jz_spi *spi)
+ tmp |= (tmp & ~CR0_RENDIAN_MASK) | (0x3 << CR0_RENDIAN_BIT);
+static inline void spi_enable_loopback(struct jz_spi *spi)
+ tmp |= CR0_LOOP;
+static inline void spi_disable_loopback(struct jz_spi *spi)
+ tmp &= ~CR0_LOOP;
+static inline void spi_set_frame_length(struct jz_spi *spi, u32 len)
+ tmp = (tmp & ~CR1_FLEN_MASK) | (((len) - 2) << CR1_FLEN_BIT);
+static inline void spi_set_tx_trigger(struct jz_spi *spi, u32 val)
+ tmp = (tmp & ~CR1_TTRG_MASK) | ((val)/8) << CR1_TTRG_BIT;
+static inline void spi_set_rx_trigger(struct jz_spi *spi, u32 val)
+ tmp = (tmp & ~CR1_RTRG_MASK) | ((val)/8) << CR1_RTRG_BIT;
+static inline void spi_enable_txfifo_half_empty_intr(struct jz_spi *spi)
+ tmp |= CR0_TIE;
+static inline void spi_disable_txfifo_half_empty_intr(struct jz_spi *spi)
+ tmp &= ~CR0_TIE;
+static inline void spi_enable_rxfifo_half_full_intr(struct jz_spi *spi)
+ tmp |= CR0_RIE;
+static inline void spi_disable_rxfifo_half_full_intr(struct jz_spi *spi)
+ tmp &= ~CR0_RIE;
+static inline void spi_enable_tx_intr(struct jz_spi *spi)
+ tmp |= CR0_TIE | CR0_TEIE;
+static inline void spi_disable_tx_intr(struct jz_spi *spi)
+ tmp &= ~(CR0_TIE | CR0_TEIE);
+static inline void spi_enable_rx_intr(struct jz_spi *spi)
+ tmp |= CR0_RIE | CR0_REIE;
+static inline void spi_disable_rx_intr(struct jz_spi *spi)
+ tmp &= ~(CR0_RIE | CR0_REIE);
+static inline void spi_enable_tx_error_intr(struct jz_spi *spi)
+ tmp |= CR0_TEIE;
+static inline void spi_disable_tx_error_intr(struct jz_spi *spi)
+ tmp &= ~CR0_TEIE;
+static inline void spi_enable_rx_error_intr(struct jz_spi *spi)
+ tmp |= CR0_REIE;
+static inline void spi_disable_rx_error_intr(struct jz_spi *spi)
+ tmp &= ~CR0_REIE;
+static inline void spi_underrun_auto_clear(struct jz_spi *spi)
+ tmp |= CR0_EACLRUN;
+static inline void spi_clear_errors(struct jz_spi *spi)
+ 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)
+ 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);
+static inline void spi_enable_receive(struct jz_spi *spi)
+ tmp &= ~CR0_DISREV;
+static inline void spi_disable_receive(struct jz_spi *spi)
+ tmp |= CR0_DISREV;
+static inline void spi_flush_fifo(struct jz_spi *spi)
+ tmp |= CR0_TFLUSH | CR0_RFLUSH;
+static inline void spi_finish_transmit(struct jz_spi *spi)
+ tmp &= ~CR1_UNFIN;
+static inline void spi_start_transmit(struct jz_spi *spi)
+ tmp |= CR1_UNFIN;
+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)
+ tmp &= ~CR0_SSIE;
+static inline void spi_enable(struct jz_spi *spi)
+ tmp |= CR0_SSIE;
+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)
+ tmp |= CR0_TFLUSH;
+static inline void spi_flush_rxfifo(struct jz_spi *spi)
+ tmp |= CR0_RFLUSH;
+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)
+ tmp &= ~CR0_FSEL;
+static inline void spi_select_ce1(struct jz_spi *spi)
+ tmp |= CR0_FSEL;
+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_ */
@@ -0,0 +1,514 @@
+ * File : drv_uart.c
+#include "drv_uart.h"
+struct jz_uart_s
+ rt_uint32_t hw_base;
+ 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},
+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;
+ for (index = 0; index < sizeof(baudtoregs)/sizeof(baudtoregs[0]); index ++)
+ bt = &baudtoregs[index];
+ if (bt->baud == baud)
+ 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);
+#ifdef RT_USING_UART1
+ static struct rt_serial_device serial1;
+ static struct jz_uart_s uart1;
+ serial = &serial1;
+ uart = &uart1;
+ strcpy(uart->name, "uart1");
+ 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();
+ "uart1",
+#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);
+ //USE JTAG IO for UART2
+ gpio_set_func(GPIO_PORT_C,GPIO_Pin_31,GPIO_FUNC_1);
+ uart->hw_base = UART2_BASE;
+ uart->irqno = IRQ_UART2;
+ clk_enable(clk_get("uart2"));
+ "uart2",
+ * 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;
+ /* 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;
+ 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_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");
+ /* 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)
+ serial = (struct rt_serial_device *)rt_device_find("uart0");
+ quot1 = get_divisor(baudrate);
+ if (quot1)
+ rt_kprintf("change baudrate done!\n");
+static rt_err_t uart_control (struct rt_serial_device *serial, int cmd, void *arg)
+ 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);
+ case RT_DEVICE_CTRL_SET_INT:
+ 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);
+static int uart_putc (struct rt_serial_device *serial, char c)
+ struct jz_uart_s* uart;
+ /* 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;
+ /* 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);
- * File : board_uart.h
+ * File : drv_uart.h
* 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_ */
@@ -4,8 +4,8 @@ from building import *
src = Glob('*.c')
-CPPPATH = [cwd, str(Dir('#'))]
-group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH)
+group = DefineGroup('drv_mmc', src, depend = ['RT_USING_SDIO'], CPPPATH = CPPPATH)
@@ -0,0 +1,1134 @@
+ * File : drv_mmc.c
+ * 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
+ * 2013-03-09 aozima the first version
+ * 2013-03-29 aozima support Jz4770.
+ * 2013-04-01 aozima add interrupt support for Jz4770.
+#include <drivers/mmcsd_core.h>
+#include <drivers/sdio.h>
+#include "drv_mmc.h"
+#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 <rtdbg.h>
+ * 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];
+uint8_t _dma_buffer_1[32 * 1024];
+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)
+ imsk |= bits;
+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);
+/* 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))
+ if (timeout == 0)
+ rt_kprintf("stop clock timeout!\n");
+ stopping_clock = 0;
+/* Start the MMC clock and operation */
+rt_inline void jzmmc_start_clock(uint32_t hw_base)
+ value |= (MSC_CTRL_CLOCK_START | MSC_CTRL_START_OP);
+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));
+ if (msc_readl(host, MSC_STAT_OFFSET) & ERROR_STAT)
+ dbg_log(DBG_LOG, "polling status(0x%08X) error, "
+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)
+ 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;
+ cmd->resp[i] |= res << 8;
+ cmd->resp[i] |= res >> 8;
+ else if ((host->cmdat & MSC_CMDAT_RESP_FORMAT_MASK) == MSC_CMDAT_RESPONSE_NONE)
+ cmd->resp[0] = res << 24;
+ cmd->resp[0] |= res << 8;
+ 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);
+ 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; i<buflen; i+=16)
+ rt_kprintf("%08X: ", i);
+ for (j=0; j<16; j++)
+ if (i+j < buflen)
+ rt_kprintf("%02X ", buf[i+j]);
+ rt_kprintf(" ");
+ rt_kprintf("%c", __is_print(buf[i+j]) ? buf[i+j] : '.');
+ rt_kprintf("\n");
+/*------------------------End functional functions-------------------------*/
+rt_inline void jzmmc_submit_dma(struct jzmmc_host *host, struct rt_mmcsd_data *data)
+ host->dma_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 */
+ 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);
+ rt_hw_dcache_flush_range((rt_ubase_t)(data->buf), data->blks * data->blksize);
+// #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;
+ dmac = (0x01 << DMAC_INCR_SHF) | DMAC_DMAEN;
+#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;
+ 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");
+ 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");
+ msc_writel(host, MSC_IREG_OFFSET, IFLG_END_CMD_RES);
+static void do_pio_read(struct jzmmc_host *host,
+ unsigned int *addr, unsigned int cnt)
+ 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;
+ *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,
+ for (i = 0; i < (cnt / 4); i++)
+ & MSC_STAT_DATA_FIFO_FULL));
+ msc_writel(host, MSC_TXFIFO_OFFSET, *addr++);
+ 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;
+ do_pio_write(host, addr, cnt);
+ do_pio_read(host, addr, cnt);
+static void pio_trans_done(struct jzmmc_host *host, struct rt_mmcsd_data *data)
+ data->bytes_xfered = data->blks * data->blksize;
+ if (host->req->stop)
+ if (jzmmc_polling_status(host, MSC_STAT_AUTO_CMD_DONE) < 0)
+ if (jzmmc_polling_status(host, MSC_STAT_PRG_DONE) < 0)
+ clear_msc_irq(host, IFLG_PRG_DONE);
+ if (jzmmc_polling_status(host, MSC_STAT_DATA_TRAN_DONE) < 0)
+ 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);
+ 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;
+ rt_kprintf("data direction confused\n");
+ host->cmdat |= cmdat;
+ if (!is_pio_mode(host))
+ jzmmc_submit_dma(host, data);
+ 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);
+ /* start DMA */
+ disable_msc_irq(host, IFLG_END_CMD_RES);
+ jzmmc_dma_start(host, data);
+ if (ret != RT_EOK)
+ rt_kprintf("warning: msc dma timeout\n");
+ 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);
+ 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);
+ rt_hw_dcache_invalidate_range((rt_ubase_t)(data->buf), data->blks * data->blksize);
+ jzmmc_data_done(host);
+static void jzmmc_command_start(struct jzmmc_host *host, struct rt_mmcsd_cmd *cmd)
+ unsigned long cmdat = 0;
+ /* 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);
+#undef _CASE
+ if ((cmd->flags & RESP_MASK) == RESP_R1B) cmdat |= MSC_CMDAT_BUSY;
+ imsk = IMASK_TIME_OUT_RES | IMASK_END_CMD_RES;
+ 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;
+ 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 */
+ /* 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);
+ writew(0, host->hw_base + MSC_BLKLEN_OFFSET);
+ writew(0, host->hw_base + MSC_NOB_OFFSET);
+ jzmmc_command_start(host, host->cmd);
+ jzmmc_data_start(host, host->data);
+ mmcsd_req_complete(mmc);
+static void jzmmc_isr(int irqno, void* param)
+ 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)
+ 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))
+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);
+ 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;
+ /* reset mmc/sd controller */
+ value = readl(hw_base + MSC_CTRL_OFFSET);
+ value |= MSC_CTRL_RESET;
+ writel(value, hw_base + MSC_CTRL_OFFSET);
+ value &= ~MSC_CTRL_RESET;
+ 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);
+/* 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;
+ 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);
+ 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);
+ 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);
+ lpm |= LPM_LPM;
+ 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");
+ case MMCSD_POWER_UP:
+ dbg_log(DBG_LOG, "MMCSD_POWER_UP\r\n");
+ 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);
+ dbg_log(DBG_LOG, "unknown power_mode %d\n", io_cfg->power_mode);
+static rt_int32_t jzmmc_sdio_detect(struct rt_mmcsd_host *host)
+ dbg_log(DBG_LOG, "jz47xx_SD_Detect\n");
+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");
+ jz_host->_dma_buffer = _dma_buffer_0;
+ /* 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
+ jz_host = rt_malloc(sizeof(struct jzmmc_host));
+ jz_host1 = jz_host; // for debug
+ jz_host->hw_base = MSC1_BASE;
+ jz_host->clock = clk_get("cgu_msc1");
+ jz_host->clock_gate = clk_get("msc1");
+ jz_host->_dma_buffer = _dma_buffer_1;
+ /* init GPIO (paladin msc1 SDIO wifi)
+ * 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_set_rate(jz_host->clock, BOARD_EXTAL_CLK);
+ host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ | MMCSD_SUP_HIGHSPEED;
+ jz_host->irqno = IRQ_MSC1;
+ rt_hw_interrupt_install(jz_host->irqno, jzmmc_isr, jz_host, "msc1");
+#endif // RT_USING_MSC1
+err:
+ if(host)
+ mmcsd_free_host(host);
+ if(jz_host)
+ rt_free(jz_host);
+INIT_DEVICE_EXPORT(jzmmc_sdio_init);
+int msc_status(void)
+ 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");
+MSH_CMD_EXPORT(msc_status, dump msc status);
+int msc_log(int argc, char** argv)
+ if (argc == 2)
+ sdio_log = atoi(argv[1]);
+MSH_CMD_EXPORT(msc_log, set msc log enable);
@@ -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;
+ /* È·±£ÊÇ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__ */
@@ -0,0 +1,21 @@
+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
@@ -0,0 +1,1502 @@
+ * drv_sfc.c
+ * Created on: 2016Äê4ÔÂ5ÈÕ
+#include <sys/types.h>
+#include "drv_sfc.h"
+//#define SFC_DEBUG
+#if defined(SFC_DEBUG)
+#define SFC_DBG(...) rt_kprintf("[SFC]"),rt_kprintf(__VA_ARGS__)
+#define SFC_DBG(...)
+#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)
+ tmp |= TRIG_START;
+static void sfc_flush_fifo(struct sfc *sfc)
+ tmp |= TRIG_FLUSH;
+static void sfc_ce_invalid_value(struct sfc *sfc, uint32_t value)
+ if (value == 0)
+ tmp = sfc_readl(sfc, SFC_DEV_CONF);
+ tmp &= ~DEV_CONF_CEDL;
+ sfc_writel(sfc, SFC_DEV_CONF, tmp);
+ tmp |= DEV_CONF_CEDL;
+static void sfc_hold_invalid_value(struct sfc *sfc, uint32_t value)
+ tmp &= ~DEV_CONF_HOLDDL;
+ tmp |= DEV_CONF_HOLDDL;
+static void sfc_wp_invalid_value(struct sfc *sfc, uint32_t value)
+ tmp &= ~DEV_CONF_WPDL;
+ tmp |= DEV_CONF_WPDL;
+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);
+static void sfc_clear_treq_intc(struct sfc *sfc)
+ tmp |= CLR_TREQ;
+static void sfc_clear_rreq_intc(struct sfc *sfc)
+ tmp |= CLR_RREQ;
+static void sfc_clear_over_intc(struct sfc *sfc)
+ tmp |= CLR_OVER;
+static void sfc_clear_under_intc(struct sfc *sfc)
+ tmp |= CLR_UNDER;
+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)
+ 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)
+ 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)
+ tmp &= ~DEV_CONF_CPHA;
+ tmp |= DEV_CONF_CPHA;
+static void sfc_clock_polarity(struct sfc *sfc, uint32_t value)
+ tmp &= ~DEV_CONF_CPOL;
+ tmp |= DEV_CONF_CPOL;
+static void sfc_threshold(struct sfc *sfc, uint32_t value)
+ tmp &= ~GLB_THRESHOLD_MSK;
+ tmp |= value << GLB_THRESHOLD_OFFSET;
+static void sfc_smp_delay(struct sfc *sfc, uint32_t value)
+ tmp &= ~DEV_CONF_SMP_DELAY_MSK;
+ tmp |= value << DEV_CONF_SMP_DELAY_OFFSET;
+static void sfc_hold_delay(struct sfc *sfc, uint32_t value)
+ tmp &= ~DEV_CONF_THOLD_MSK;
+ tmp |= value << DEV_CONF_THOLD_OFFSET;
+static void sfc_setup_delay(struct sfc *sfc, uint32_t value)
+ tmp &= ~DEV_CONF_TSETUP_MSK;
+ tmp |= value << DEV_CONF_TSETUP_OFFSET;
+static void sfc_interval_delay(struct sfc *sfc, uint32_t value)
+ tmp &= ~DEV_CONF_TSH_MSK;
+ tmp |= value << DEV_CONF_TSH_OFFSET;
+static void sfc_set_cmd_length(struct sfc *sfc, uint32_t value)
+ if (value == 1)
+ tmp &= ~TRAN_CONF_CMD_LEN;
+ tmp |= TRAN_CONF_CMD_LEN;
+static void sfc_transfer_direction(struct sfc *sfc, uint32_t value)
+ if (value == GLB_TRAN_DIR_READ)
+ tmp &= ~GLB_TRAN_DIR;
+ tmp |= GLB_TRAN_DIR;
+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);
+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)
+ tmp &= ~GLB_OP_MODE;
+ tmp |= GLB_OP_MODE;
+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)
+ 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;
+ /* last aligned THRESHOLD data*/
+ if (sfc->transfer->len % 4)
+ fifo_num = (align_len - sfc->transfer->cur_len) / 4 - 1;
+ last_word = 1;
+ fifo_num = (align_len - sfc->transfer->cur_len) / 4;
+ 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;
+static uint32_t cpu_write_txfifo(struct sfc *sfc)
+ align_len = RT_ALIGN(sfc->transfer->len , 4);
+ if (((align_len - sfc->transfer->cur_len) / 4) > THRESHOLD){
+ } else {
+ for(i = 0; i < fifo_num; i++) {
+ sfc_write_data(sfc, *(uint32_t *)sfc->transfer->data);
+static int ssi_underrun(struct sfc *sfc)
+ if(tmp & CLR_UNDER)
+static int ssi_overrun(struct sfc *sfc)
+ if(tmp & CLR_OVER)
+static int rxfifo_rreq(struct sfc *sfc)
+ if(tmp & CLR_RREQ)
+static int txfifo_treq(struct sfc *sfc)
+ if(tmp & CLR_TREQ)
+static int sfc_end(struct sfc *sfc)
+ if(tmp & CLR_END)
+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)
+ tmp &= ~(ADDR_WIDTH_MSK);
+ tmp |= (value << ADDR_WIDTH_OFFSET);
+static void sfc_cmd_enble(struct sfc *sfc, uint32_t channel, uint32_t value)
+ if (value == ENABLE)
+ tmp |= TRAN_CONF_CMDEN;
+ tmp &= ~TRAN_CONF_CMDEN;
+static void sfc_data_en(struct sfc *sfc, uint32_t channel, uint32_t value)
+ tmp |= TRAN_CONF_DATEEN;
+ tmp &= ~TRAN_CONF_DATEEN;
+static void sfc_phase_format(struct sfc *sfc, uint32_t channel, uint32_t value)
+ tmp |= TRAN_CONF_FMAT;
+ tmp &= ~TRAN_CONF_FMAT;
+static void sfc_write_cmd(struct sfc *sfc, uint32_t channel, uint32_t value)
+ tmp &= ~TRAN_CONF_CMD_MSK;
+ tmp |= value;
+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)
+ tmp &= ~TRAN_CONF_DMYBITS_MSK;
+ tmp |= value << DMYBITS_OFFSET;
+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)
+ if(value == 1)
+ tmp |= TRAN_CONF_POLLEN;
+ tmp &= ~(TRAN_CONF_POLLEN);
+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)
+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_DBG("line:%d Timeout for ACK from SFC device\n", __LINE__);
+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_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);
+ DMA_TO_DEVICE);
+ sfc_set_mem_addr(sfc, PHYS(transfer->data));
+ sfc_transfer_mode(sfc, DMA_MODE);
+ sfc_set_mem_addr(sfc, 0);
+ sfc_transfer_mode(sfc, SLAVE_MODE);
+static void dump_transfer(struct sfc_transfer *xfer,uint32_t num)
+ 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);
+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);
+ 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);
+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);
+ if (ssi_overrun(sfc))
+ sfc_clear_over_intc(sfc);
+ if (rxfifo_rreq(sfc))
+ sfc_clear_rreq_intc(sfc);
+ cpu_read_rxfifo(sfc);
+ if (txfifo_treq(sfc))
+ sfc_clear_treq_intc(sfc);
+ cpu_write_txfifo(sfc);
+ if (sfc_end(sfc))
+ sfc_clear_end_intc(sfc);
+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_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);
+ if (sfc->src_clk >= 100000000)
+ sfc_smp_delay(sfc, DEV_CONF_HALF_CYCLE_DELAY);
+static struct sfc* jz_sfc_init(void)
+ struct sfc *sfc = (struct sfc *)rt_malloc(sizeof(struct sfc));
+ if(sfc == 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);
+ 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;
+ 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__);
+ 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)
+ transfer.data = buf;
+ transfer.cur_len = 0;
+ if(len >= L2CACHE_ALIGN_SIZE)
+ transfer.ops_mode = DMA_OPS;
+ transfer.sfc_mode = flash->sfc_mode;
+ /*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 cmd_info cmd[3];
+ /* 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;
+ transfer[1].ops_mode = DMA_OPS;
+ 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);
+#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;
+ if (flash->quad_mode == NULL)
+ SFC_DBG("quad info is null, use standard spi mode\n");
+ flash->sfc_mode = TM_STD_SPI;
+ 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;
+ transfer[0].sfc_mode = TM_STD_SPI;
+ transfer[1].data = (const uint8_t *)&sent_data;
+ transfer[1].sfc_mode = TM_STD_SPI;
+ cmd[2].cmd = flash->quad_mode->RDSR_CMD;
+ cmd[2].sta_exp = 0x2;
+ cmd[2].sta_msk = 0x2;
+ transfer[2].data_dummy_bits = 0;
+ flash->sfc_mode = flash->quad_mode->sfc_mode;
+static int sfc_flash_write(struct sfc_flash *flash, rt_off_t to, size_t len, const uint8_t *buf)
+ int dummy_byte = 0;
+ uint32_t s_len = 0, f_len = 0, a_len = 0;
+ if((flash->sfc_mode == TM_QI_QO_SPI) || (flash->sfc_mode == TM_QIO_SPI) || (flash->sfc_mode == TM_FULL_QIO_SPI))
+ command = CMD_PP;
+ 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);
+ 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;
+ /**
+ * s_len : start not align length
+ * a_len : middle align length
+ * f_len : end not align length
+ ret += sfc_flash_do_read(flash, command, (uint32_t) addr,
+ flash->addrsize, buf, s_len, dummy_byte);
+ ret += sfc_flash_do_read(flash, command, (uint32_t) addr + s_len,
+ flash->addrsize, &buf[s_len], a_len,
+ ret += sfc_flash_do_read(flash, command,
+ (uint32_t) addr + s_len + a_len,
+ ret = sfc_flash_do_read(flash, command, (uint32_t)addr, flash->addrsize, buf, len, dummy_byte);
+static int sfc_flash_read(struct sfc_flash *flash, rt_off_t from, size_t len, uint8_t *buf)
+ int dummy_byte;
+ int tmp_len = 0, current_len = 0;
+ command = flash->quad_mode->cmd_read;
+ command = CMD_READ;
+ dummy_byte = 0;
+ 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)
+ cmd.cmd = CMD_EN4B;
+ cmd.dataen = DISABLE;
+ transfer.data_dummy_bits = 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)
+ int dummy_byte = 0,ret;
+ transfer.addr = (uint32_t)from;
+ transfer.addr_len = DEFAULT_ADDRSIZE;
+ r4k_dma_cache_sync((rt_ubase_t)buf,len, DMA_FROM_DEVICE);
+int sfc_norflash_erase_sector(struct sfc_flash *flash, uint32_t addr)
+ switch (flash->erasesize)
+ case 0x1000:
+ command = CMD_BE_4K;
+ case 0x8000:
+ command = CMD_BE_32K;
+ case 0x10000:
+ command = CMD_BE_64K;
+ /* erase ops */
+ cmd[1].dataen = DISABLE;
+ transfer[1].addr_len = flash->addrsize;
+ transfer[1].data_dummy_bits = 0;
+size_t sfc_norflash_write(struct sfc_flash *flash, rt_off_t to, const uint8_t *buf, size_t len)
+ u32 page_offset, actual_len;
+ 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;
+ 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);
+int sfc_norflash_probe(struct sfc_flash *flash)
+ struct sfc *sfc;
+ sfc = flash->sfc = jz_sfc_init();
+ /* 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
+ int addr_len = 0;
+ int len = 3;
+ int addr = 0;
+ int id;
+ 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;
+ //get UID
+ 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");
+ rt_mutex_release(&(flash->lock));
@@ -0,0 +1,287 @@
+ * drv_sfc.h
+#ifndef DRIVER_DRV_SFC_H_
+#define DRIVER_DRV_SFC_H_
+#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))
+#ifndef min
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+/*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_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;
+struct sfc
+ void *iomem;
+ 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_quad_mode *quad_mode;
+ 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_ */
@@ -0,0 +1,192 @@
+ * File : drv_sfc_gd25qxx_mtd.c
+ * 2017Äê4ÔÂ19ÈÕ Urey the first version
+#include <drivers/mtd_nor.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)
+ 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)
+ 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)
+ sfc_norflash_erase_sector(flash,offset);
+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,
+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
+ .WRSR_DATE = 0x40,//this bit should be the flash QUAD mode enable
+ .cmd_read = CMD_QUAD_IO_FAST_READ,
+ .sfc_mode = TRAN_SPI_IO_QUAD,
+ .RDSR_DATE = 0x20,//the data is write the spi status register for QE bit
+ .WRSR_DATE = 0x200,//this bit should be the flash QUAD mode enable
+ .WD_DATE_SIZE = 2,
+ .cmd_read = CMD_QUAD_READ,
+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;
+ result = sfc_norflash_probe(flash);
+ rt_kprintf("GD25 init Failed..\n");
+ 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];
+ 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);
+ rt_kprintf("Memory Capacity error!\r\n");
+ //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");
+INIT_DEVICE_EXPORT(rt_hw_gd25qxx_init);
@@ -0,0 +1,67 @@
+ * File : drv_sfc_gd25qxx_mtd_partition.c
+#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,
+ /* 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);
@@ -0,0 +1,334 @@
+ ******************************************************************************
+ * @file rt_mtd_nor_partition.c
+ * @author Urey
+ * @version V1.0.0
+ * @date 2017Äê2ÔÂ11ÈÕ
+ * @brief TODO
+**/
+// #define MTD_DEBUG 1
+#ifdef MTD_DEBUG
+#define MTD_DBG(...) rt_kprintf("[MTD]"),rt_kprintf(__VA_ARGS__)
+#define MTD_DBG(...)
+/* RT-Thread device interface */
+static rt_err_t mtd_part_blk_init(rt_device_t dev)
+static rt_err_t mtd_part_blk_open(rt_device_t dev, rt_uint16_t oflag)
+static rt_err_t mtd_part_blk_close(rt_device_t dev)
+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;
+ mtd_part = (struct rt_mtd_nor_partition *)dev;
+ mtd_nor = (struct rt_mtd_nor_device *)mtd_part->user_data;
+ case RT_DEVICE_CTRL_BLK_GETGEOME:
+ struct rt_device_blk_geometry *geometry;
+ geometry = (struct rt_device_blk_geometry *)args;
+ if (geometry == RT_NULL)
+ 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;
+static rt_size_t mtd_part_blk_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+ rt_size_t read_count = 0;
+ rt_uint8_t *ptr = (rt_uint8_t *)buffer;
+ RT_ASSERT(size != 0);
+ 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);
+ 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");
+ 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)
+ rt_size_t write_count = 0;
+ 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 */
+ while(write_count < size)
+ if((pos + 1) * mtd_nor->block_size > (mtd_part->offset + mtd_part->size))
+ MTD_DBG("ERROR: write overrun!\n");
+ 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);
+ write_count++;
+ return write_count;
+static rt_base_t mtd_part_mtd_read_id(struct rt_mtd_nor_device *dev)
+ 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)
+ 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: read size > partition size, pos=%d, size=%d, partition_size=%d\n", offset, length, mtd_part->size);
+ rt_mtd_nor_read(mtd_nor,(mtd_part->offset + offset),buffer,length);
+ return length;
+ MTD_DBG("ERROR: unknown device type..\n");
+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)
+ { /* It'a MTD device */
+ MTD_DBG("ERROR: write size > partition size, pos=%d, size=%d, partition_size=%d\n", offset, length, mtd_part->size);
+ /* MTD device skip erase,user do it by himself */
+ rt_mtd_nor_write(mtd_nor,(mtd_part->offset + offset),buffer,length);
+static rt_err_t mtd_part_mtd_erase_block(struct rt_mtd_nor_device* dev, rt_off_t offset, rt_uint32_t length)
+ MTD_DBG("ERROR: erase size > partition size, pos=%d, size=%d, partition_size=%d\n", offset, length, mtd_part->size);
+ if(length % mtd_nor->block_size != 0)
+ MTD_DBG("ERROR: erase size must align to BLOCK SIZE\n");
+ rt_mtd_nor_erase_block(mtd_nor,(mtd_part->offset + offset),length);
+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)
+ mtd_nor = (struct rt_mtd_nor_device *)rt_device_find(mtd_name);
+ if(mtd_nor == RT_NULL)
+ 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 */
+ /* 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);
@@ -0,0 +1,53 @@
+ * @file spi_flash_mtd_partition.h
+#ifndef _SPI_FLASH_MTD_PARTITION_H_
+#define _SPI_FLASH_MTD_PARTITION_H_
+#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_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);
+#endif /* _SPI_FLASH_MTD_PARTITION_H_ */
+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
+ * File : drv_slcdc_ili9341.c
+ * 2016-08-12 fujie The first version
+#include "drv_slcdc.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, 0x78},
+ {SMART_CONFIG_CMD, 0xCB}, //Power control A
+ {SMART_CONFIG_DATA, 0x39},
+ {SMART_CONFIG_DATA, 0x2C},
+ {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_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, 0x14},
+ {SMART_CONFIG_CMD, 0xF2}, // 3Gamma Function Disable
+ {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, 0x46},
+ {SMART_CONFIG_DATA, 0x88},
+ {SMART_CONFIG_DATA, 0x05},
+ {SMART_CONFIG_DATA, 0x07},
+ {SMART_CONFIG_CMD, 0XE1}, //Set Gamma
+ {SMART_CONFIG_DATA, 0x22},
+ {SMART_CONFIG_DATA, 0x25},
+ {SMART_CONFIG_DATA, 0x06},
+ {SMART_CONFIG_DATA, 0x10},
+ {SMART_CONFIG_DATA, 0x4a},
+ {SMART_CONFIG_DATA, 0x0C},
+ {SMART_CONFIG_DATA, 0x38},
+ {SMART_CONFIG_DATA, 0x3a},
+ {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, 0xEF},
+ {SMART_CONFIG_CMD, 0x2B},
+ {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, 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);
+ 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 */
+ rt_thread_delay(20);
+ rt_hw_slcd_init((struct slcd_configure *)&_ili9341_config);
+// rt_hw_lcd_set_bl_func(ili9341_bl_set);
+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);
+ rt_kprintf("turn off blight\n");
+ gpio_set_value(GPIO_PORT_B, GPIO_Pin_12, 0);
+MSH_CMD_EXPORT(bl, black light);
+#endif //RT_USING_ILI9341
@@ -0,0 +1,176 @@
+ * File : drv_slcdc_ili9488.c
+ * 2017Äê5ÔÂ6ÈÕ Urey the first version
+#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,0x15},
+ {SMART_CONFIG_DATA,0x09},
+ {SMART_CONFIG_DATA,0x3c},
+ {SMART_CONFIG_DATA,0x99},
+ {SMART_CONFIG_DATA,0x4b},
+ {SMART_CONFIG_DATA,0x10},
+ {SMART_CONFIG_DATA,0x0d},
+ {SMART_CONFIG_DATA,0x1c},
+ {SMART_CONFIG_DATA,0x1e},
+ {SMART_CONFIG_CMD, 0xE1}, //N-Gamma
+ {SMART_CONFIG_DATA,0x20},
+ {SMART_CONFIG_DATA,0x23},
+ {SMART_CONFIG_DATA,0x02},
+ {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_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,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_CMD,0xB1}, //Frame rate 60HZ
+ {SMART_CONFIG_DATA,0xA0},
+ {SMART_CONFIG_DATA,0x11},
+ {SMART_CONFIG_CMD,0xB4},
+ {SMART_CONFIG_CMD,0xB6}, //RGB/MCU Interface Control
+ {SMART_CONFIG_CMD,0xBE},
+ {SMART_CONFIG_CMD,0xE9},
+ {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,(LCD_WIDTH - 1) >> 8},
+ {SMART_CONFIG_DATA,(LCD_WIDTH - 1) & 0xFF},
+ {SMART_CONFIG_CMD,0x2B}, //Set Y
+ {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 =
+ .width = LCD_WIDTH,
+ .height = LCD_HEIGHT,
+ .fmt = RTGRAPHIC_PIXEL_FORMAT_RGB565,
+ .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
+ gpio_direction_output(LCD_BL_PORT, LCD_BL_PIN,1);
+ /* init lcd & register lcd device */
+ rt_hw_slcd_init(&_lcm_config);
+INIT_DEVICE_EXPORT(rt_hw_ili9488_init);
@@ -0,0 +1,247 @@
+ * File : drv_slcdc_OTM4802.c
+#ifdef RT_USING_OTM4802
+rt_uint32_t _lcm_cmd_table[]=
+ {SMART_CONFIG_CMD, 0xff}, //Command 2 Enable
+ {SMART_CONFIG_DATA, 0x48},
+ {SMART_CONFIG_CMD, 0x00},
+ {SMART_CONFIG_DATA, 0x80},
+ {SMART_CONFIG_CMD, 0xff}, //ORISE Command Enable
+ {SMART_CONFIG_DATA, 0x90},
+ {SMART_CONFIG_CMD, 0xFF}, //MPU 16bit setting
+ {SMART_CONFIG_DATA, 0x01}, //02-16BIT MCU,01-8BIT MCU
+ {SMART_CONFIG_DATA, 0x93},
+ {SMART_CONFIG_CMD, 0xFF}, //SW MPU enable
+ {SMART_CONFIG_CMD, 0x51}, //Wright Display brightness
+ {SMART_CONFIG_DATA, 0xf0},
+ {SMART_CONFIG_CMD, 0x53}, // Wright CTRL Display
+ {SMART_CONFIG_DATA, 0x24},
+ {SMART_CONFIG_DATA, 0xb1},
+ {SMART_CONFIG_CMD, 0xc5}, //VSEL setting
+ {SMART_CONFIG_DATA, 0xB0},
+ {SMART_CONFIG_CMD, 0xc4}, //Gate Timing control
+ {SMART_CONFIG_DATA, 0x08},
+ {SMART_CONFIG_CMD, 0xc0}, //TCON MCLK Shift Control
+ {SMART_CONFIG_DATA, 0x15},
+ {SMART_CONFIG_DATA, 0x17},
+ {SMART_CONFIG_DATA, 0x82},
+ {SMART_CONFIG_CMD, 0xc5}, //Adjust pump phase
+ {SMART_CONFIG_DATA, 0x47},
+ {SMART_CONFIG_CMD, 0xd8}, //GVDD/NGVDD Setting
+ {SMART_CONFIG_DATA, 0x58}, //58,17V
+ {SMART_CONFIG_DATA, 0x58}, //58
+ {SMART_CONFIG_CMD, 0xd9}, //VCOM Setting
+ {SMART_CONFIG_DATA, 0xb0}, //
+ {SMART_CONFIG_DATA, 0x91},
+ {SMART_CONFIG_CMD, 0xb3}, //Display setting
+ {SMART_CONFIG_DATA, 0xC0},
+ {SMART_CONFIG_DATA, 0x81},
+ {SMART_CONFIG_CMD, 0xC1}, //Osillator Adjustment:70Hz
+ {SMART_CONFIG_DATA, 0x77},
+ {SMART_CONFIG_CMD, 0xe1}, //Gamma setting(positive)
+ {SMART_CONFIG_DATA, 0x04},
+ {SMART_CONFIG_DATA, 0x0b},
+ {SMART_CONFIG_DATA, 0x11},
+ {SMART_CONFIG_CMD, 0xe2}, //Gamma setting(negative)
+ {SMART_CONFIG_CMD, 0x00}, //End Gamma setting
+ {SMART_CONFIG_CMD, 0xff}, //Orise mode command Disable
+ {SMART_CONFIG_CMD, 0xff}, //Command 2 Disable
+ {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_CMD, 0x2A}, //Frame rate control 320
+ {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, (LCD_HEIGHT -1 ) & 0xFF},
+ {SMART_CONFIG_UDELAY, 120},
+ {SMART_CONFIG_CMD, 0x29}, //display on
+ {SMART_CONFIG_CMD, 0x2c},
+int rt_hw_otm4802_init(void)
+ 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(GPIO_PORT_B, GPIO_Pin_18, 0); //CS = 0
@@ -0,0 +1,536 @@
+ * File : slcd_rm68120.c
+ * 2017Äê4ÔÂ11ÈÕ Urey the first version
+#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},
+ {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},
+ {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},
+ {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},
+ {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,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
+ //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,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},
+ //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
+#error "unknown bpp setting...\n";
+// {SMART_CONFIG_CMD,0x3600},{SMART_CONFIG_DATA,0xe0},
+ {SMART_CONFIG_CMD,0x3600},{SMART_CONFIG_DATA,0xA0},
+ //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,
+ .reg_width = 16,
+ .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_hw_slcd_init(&_rm68120_config);
+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);
@@ -0,0 +1,207 @@
+ * File : drv_slcd_truly240240.c
+ * 2017Äê4ÔÂ28ÈÕ Urey the first version
+#ifdef RT_USING_TRULY_TFT240240
+rt_uint32_t _truly_tft240240_cmd_table[]=
+ 0x2c2c0000,
+struct slcd_data_table _truly_tft240240_data_table[] =
+ {SMART_CONFIG_CMD, 0x01}, //soft reset, 120 ms = 120 000 us
+ {SMART_CONFIG_UDELAY, 20},
+ {SMART_CONFIG_UDELAY, 10}, /* sleep out 50 ms */
+ {SMART_CONFIG_CMD, 0x36},
+#ifdef CONFIG_TRULY_240X240_ROTATE_180
+ {SMART_CONFIG_DATA, 0xd0}, //40
+ {SMART_CONFIG_DATA, 0x00}, //40
+ {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
+ {SMART_CONFIG_DATA, 0x05}, //5-6-5
+ // {SMART_CONFIG_DATA, 0x55},
+ {SMART_CONFIG_CMD, 0xb2},
+ {SMART_CONFIG_DATA, 0x7f},
+ {SMART_CONFIG_DATA, 0xde},
+ {SMART_CONFIG_DATA, 0x33},
+ {SMART_CONFIG_CMD, 0xb3},
+ {SMART_CONFIG_CMD, 0xb4},
+ {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_CMD, 0xc3},
+ {SMART_CONFIG_DATA, 0x1e}, //14
+ {SMART_CONFIG_CMD, 0xc4},
+ {SMART_CONFIG_CMD, 0xc6},
+ {SMART_CONFIG_CMD, 0xd0},
+ {SMART_CONFIG_DATA, 0xa4},
+ {SMART_CONFIG_DATA, 0xa1},
+ {SMART_CONFIG_CMD, 0xe0},
+ {SMART_CONFIG_DATA, 0xd0},
+ {SMART_CONFIG_DATA, 0x29},
+ {SMART_CONFIG_DATA, 0x54},
+ {SMART_CONFIG_DATA, 0x41},
+ {SMART_CONFIG_DATA, 0x3c},
+ {SMART_CONFIG_CMD, 0xe1},
+ {SMART_CONFIG_DATA, 0x44},
+ {SMART_CONFIG_DATA, 0x42},
+ {SMART_CONFIG_DATA, 0x3b},
+ {SMART_CONFIG_DATA, 0x16},
+ {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_DATA, 0},
+ {SMART_CONFIG_DATA, (239>> 8) & 0xff},
+ {SMART_CONFIG_DATA, 239 & 0xff},
+ {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},
+struct slcd_configure _truly_tft240240_config =
+ .width = 240,
+ .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)
+ rt_thread_delay(rt_tick_from_millisecond(50));
+ gpio_direction_output(LCD_BLEN_PORT, LCD_BLEN_PIN,1);
+ gpio_direction_output(LCD_BLPWM_PORT, LCD_BLPWM_PIN,1);
+ rt_hw_slcd_init(&_truly_tft240240_config);
@@ -0,0 +1,496 @@
+ * File : drv_slcd_new.c
+ * 2017Äê4ÔÂ10ÈÕ Urey the first version
+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);
+ volatile uint32_t n ;
+ 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;
+ 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)
+ 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)));
+ case SMART_CONFIG_DATA:
+ _slcd_mcu_send_data(lcd_dev,((value << (32 - bus_width * j))>> (32 - bus_width)));
+ case SMART_CONFIG_UDELAY:
+ udelay(cfg->data_table[index].value);
+ 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)
+ 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;
+#ifdef SLCDC_USING_DUAL_BUFFER
+ lcd_dev->fb_base = (rt_uint32_t)rt_malloc_align((bypes_per_panel + FB_PAGE_SIZE) * 2, 32);
+ lcd_dev->fb_base = (rt_uint32_t)rt_malloc_align((bypes_per_panel + FB_PAGE_SIZE) * 1, 32);
+ 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);
+ 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);
+ 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)
+ //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;
+ case 9:
+ case 16:
+ lcd_dev->desc_cmd->cmd_num = 2;
+ lcd_dev->desc_cmd->cmd_num = 1;
+ //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;;
+ case 30 :
+ lcd_dev->desc_dat->cmd_num = LCDC_CPOS_BPP_30;
+ lcd_dev->desc_dat->cmd_num = LCDC_CPOS_BPP_18_24;
+ /* 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);
+ gpio_set_func(GPIO_PORT_B, GPIO_Pin_16, GPIO_OUTPUT1);
+ 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)
+ smart_cfg |= SMART_LCD_CWIDTH_8_BIT_ONCE;
+ smart_new_cfg |= SMART_LCD_NEW_DWIDTH_8_BIT;
+ smart_cfg |= SMART_LCD_CWIDTH_9_BIT_ONCE;
+ smart_new_cfg |= SMART_LCD_NEW_DWIDTH_9_BIT;
+ smart_cfg |= SMART_LCD_CWIDTH_16_BIT_ONCE;
+ smart_new_cfg |= SMART_LCD_NEW_DWIDTH_16_BIT;
+ smart_cfg |= SMART_LCD_CWIDTH_18_BIT_ONCE;
+ smart_new_cfg |= SMART_LCD_NEW_DWIDTH_18_BIT;
+ smart_cfg |= SMART_LCD_CWIDTH_24_BIT_ONCE;
+ smart_new_cfg |= SMART_LCD_NEW_DWIDTH_24_BIT;
+ rt_kprintf("ERR: please check out your bus width config\n");
+ 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;
+#ifdef CONFIG_SLCDC_CONTINUA
+ smart_ctrl &= ~SLCDC_CTRL_DMA_MODE;
+ smart_ctrl |= SLCDC_CTRL_DMA_START;
+ smart_ctrl |= SLCDC_CTRL_DMA_EN;
+ smart_ctrl &= ~SLCDC_CTRL_NOT_USE_TE;
+ //smart_ctrl |= SLCDC_CTRL_TE_INV;
+ smart_ctrl &= ~SLCDC_CTRL_TE_INV;
+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);
+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);
+ 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;
+ info->framebuffer = (rt_uint8_t *)(KSEG1ADDR(slcd->fb_dual));
+ info->framebuffer = (rt_uint8_t *)(KSEG1ADDR(slcd->fb_screen));
+ info->width = slcd->cfg->width;
+ info->height = slcd->cfg->height;
+ case RTGRAPHIC_CTRL_RECT_UPDATE:
+ rt_memcpy((void *)(slcd->fb_screen), (void *)(slcd->fb_dual), slcd->fb_size);
+ rt_hw_dcache_flush_range((rt_uint32_t)slcd->fb_screen,slcd->fb_size);
+ smart_ctrl = slcd_reg_read(SLCDC_CTRL);
+ while (slcd_reg_read(SLCDC_STATE) & SLCDC_STATE_BUSY);
+ case RTGRAPHIC_CTRL_SET_MODE:
+ rt_mutex_release(&(slcd->lock));
+int rt_hw_slcd_init(struct slcd_configure *cfg)
+ slcd = (struct slcdc_dev_s *)rt_malloc(sizeof(struct slcdc_dev_s));
+ if(slcd == RT_NULL)
+ rt_kprintf("error no memory!\n");
+ _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);
@@ -0,0 +1,168 @@
+ * File : drv_slcdc.h
+ * 2017Äê3ÔÂ21ÈÕ Urey the first version
+#ifndef _DRV_SLCDC_H_
+#define _DRV_SLCDC_H_
+//#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
+/* 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;
+typedef void (*lcd_bl_func_t)(rt_bool_t isPowerON);
+struct slcd_configure;
+struct slcdc_dev_s
+ 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;
+ rt_uint32_t fb_dual;
+ 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);
+#endif /* _DRV_SLCDC_H_ */
@@ -0,0 +1,96 @@
+ * File : dump_slcd.c
+#include <x1000.h>
+#include "x1000_slcdc.h"
+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("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("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("LCDC_PCFG:(0x%08x)\t0x%08x\n", LCDC_PCFG,slcd_reg_read(LCDC_PCFG));
+ 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("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);
+MSH_CMD_EXPORT(dump_slcd_regs,dump_slcd_regs);
@@ -0,0 +1,22 @@
+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)
@@ -0,0 +1,617 @@
+ * File : focaltech_ts.c
+#include <rtgui/event.h>
+#include <rtgui/rtgui_server.h>
+#ifdef RT_USING_FT6x06
+#include "focaltech_ts.h"
+#ifndef BIT
+#define BIT(n) (0x01u << (n))
+static int fts_init_success = 0;
+#define TP_DEBUG 0
+#if TP_DEBUG
+#define TP_DBG(...) rt_kprintf("[TP]"),rt_kprintf(__VA_ARGS__)
+#define TP_DBG(...)
+/*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
+#ifndef TOUCH_MAX_Y
+# define TOUCH_MAX_Y 320
+#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];
+ 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);
+ TP_DBG("f%s: i2c read error. error code = %d \n", __func__, ret);
+ msgs[0].flags = RT_I2C_RD;
+ msgs[0].len = readlen;
+ msgs[0].buf = readbuf;
+ ret = rt_i2c_transfer(fts_ts->i2c_bus, msgs, 1);
+ TP_DBG("%s:i2c read error. error code = %d \n", __func__, ret);
+* Name: fts_i2c_Write
+* Brief: i2c write
+* Input: i2c info, write buf, write len
+* Output: no
+static int fts_i2c_Write(struct fts_ts_data *fts_ts, char *writebuf, int writelen)
+ TP_DBG("%s i2c write error.\n", __func__);
+* 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;
+ uint8_t pointid = FTS_MAX_ID;
+ //uint8_t pt00f=0;
+ ret = fts_i2c_Read(fts_ts, buf, 1, buf, POINT_READ_BUF);
+ TP_DBG("%s read touchdata failed.\n", __func__);
+ 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);
+* Name: fts_report_value
+* 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)
+ int i,result;
+ int uppoint = 0;
+ int touchs = 0;
+ 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)
+ 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);
+ event->au16_x[i] = (((int16_t) buf[FTS_TOUCH_X_H_POS + FTS_TOUCH_STEP * i]) & 0x0F) << 8
+ event->au16_y[i] = (((int16_t) buf[FTS_TOUCH_Y_H_POS + FTS_TOUCH_STEP * i]) & 0x0F) << 8
+#if TOUCH_SWAP_Y
+ event->au16_y[i] = TOUCH_MAX_Y - event->au16_y[i];
+ 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 )))
+ 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]);
+ /*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;
+ zz ++;
+ xx = emouse.x;
+ yy = emouse.y;
+ if (zz >= 10)
+ xx = 0;
+ yy = 0;
+ 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);
+ 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;
+ result = rtgui_server_post_event(&emouse.parent, sizeof(emouse));
+ if (result != RT_EOK)
+ while (result != RT_EOK);
+ TP_DBG("RTGUI_MOUSE_BUTTON_UP x=%d,y=%d\n",event->au16_x[0],event->au16_y[0]);
+// 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.button = RTGUI_MOUSE_BUTTON_LEFT | RTGUI_MOUSE_BUTTON_DOWN;
+ emouse.id = emouse.ts;
+ TP_DBG("RTGUI_MOUSE_BUTTON_DOWN x=%d,y=%d\n",event->au16_x[0],event->au16_y[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;
+ 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));
+ 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
+* 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->fw_ver = 0xff;
+ 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;
+ TP_DBG("report rate is %dHz.\n", uc_reg_value * 10);
+ uc_reg_addr = FTS_REG_THGROUP;
+ TP_DBG("touch threshold is %d.\n", uc_reg_value * 4);
+ uc_reg_addr = FTS_REG_VENDOR_ID;
+ TP_DBG("VENDOR ID = 0x%x\n", uc_reg_value);
+ if (fts_ts->init_success == 1)
+ fts_init_success = 1;
+* 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
+* Return: irq handle
+static void fts_ts_interrupt(struct fts_ts_data *fts_ts)
+ rt_sem_release(&fts_ts->sem);
+static void thread_fts_ts_service(void *param)
+ struct fts_ts_data *fts_ts = (struct fts_ts_data *)param;
+ 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;*/
+ //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);
+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)
+#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");
+ fts_ts_probe(&g_fts_ts,i2c_bus,FTS_SLAVE_ADDR);
+ if(g_fts_ts.init_success == 1)
+ /* 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,
+ if(tid != RT_NULL)
+ /* enable interrupt */
+ gpio_unmask_irq(TP_INT_PORT,TP_INT_PIN);
+INIT_DEVICE_EXPORT(rt_hw_touch_init);
+#endif /* RT_USING_FT6x06 */
@@ -0,0 +1,145 @@
+ * File : focaltech_ts.h
+#ifndef _FOCALTECH_TS_H_
+#define _FOCALTECH_TS_H_
+/* -- 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_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);
+#endif /* _FOCALTECH_TS_H_ */
@@ -0,0 +1,1749 @@
+ * File : gt9xx.c
+#include "gt9xx.h"
+#include "gt9xx_cfg.h"
+#include "gt9xx_firmware.h"
+#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;
+#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);
+#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] ) )
+#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;
+#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;
+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)
+ u8 buffer[MAX_TRANSACTION_LENGTH];
+ u8 retry;
+ u16 left = len;
+ u16 offset = 0;
+ msgs[0].addr = GT910_IIC_ADDR;
+ msgs[0].buf = &buffer[0];
+ msgs[0].len = 2;
+ msgs[1].addr = GT910_IIC_ADDR;
+ 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;
+ 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);
+s32 i2c_write_bytes(struct rt_i2c_bus_device *i2c, u16 addr, u8 *txbuf, int len)
+ struct rt_i2c_msg msgs[1];
+ u8 retry = 0;
+ GTP_DEBUG("i2c_write_bytes to device %02X address %04X len %d\n", GT910_IIC_ADDR, addr, len);
+ while (left > 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;
+ memcpy(&buffer[GTP_ADDR_LENGTH], &txbuf[offset], left);
+ msgs[0].len = left + GTP_ADDR_LENGTH;
+ //GTP_DEBUG("byte left %d offset %d\n", left, offset);
+ while (rt_i2c_transfer(i2c, &msgs[0], 1) != 1)
+ //if (retry == 20)
+ GTP_ERROR("I2C write 0x%X%X length=%d failed\n", buffer[0], buffer[1], len);
+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 GTP_GESTURE_WAKEUP
+ if (DOZE_ENABLED == doze_status)
+ #endif
+ #if GTP_COMPATIBLE_MODE
+ if (CHIP_TYPE_GT9F == gtp_chip_type)
+ gtp_recovery_reset(client);
+ gtp_reset_guitar(i2c, 20);
+s32 gtp_i2c_read(struct rt_i2c_bus_device *i2c, u8 *buf, s32 len)
+ ret = i2c_read_bytes(i2c, addr, &buf[2], len - 2);
+#if GTP_COMPATIBLE_MODE
+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};
+ 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!");
+ 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)
+#if GTP_CHARGER_SWITCH
+static int gtp_send_chr_cfg(struct rt_i2c_bus_device *i2c)
+ if (pnl_init_error) {
+ for (retry = 0; retry < 5; retry++) {
+ ret = gtp_i2c_write(i2c, gtp_charger_config, GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH);
+ if (ret > 0) {
+s32 gtp_read_version(struct rt_i2c_bus_device *i2c, u16 *version)
+ s32 i;
+ u8 buf[8] = {GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff};
+ GTP_DEBUG_FUNC();
+ ret = gtp_i2c_read(i2c, buf, sizeof(buf));
+ GTP_ERROR("GTP read version failed");
+ 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]);
+ GTP_INFO("IC VERSION:%c%c%c%c_%02x%02x",
+ buf[2], buf[3], buf[4], buf[5], buf[7], buf[6]);
+static s32 gtp_init_panel(struct rt_i2c_bus_device *i2c)
+ s32 ret = 0;
+ 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)
+ 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)
+ 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;
+ 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;
+ GTP_ERROR("Failed to get sensor_id, No config sent!");
+ 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);
+ if (CHIP_TYPE_GT9F != gtp_chip_type)
+ 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],
+ 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;
+ GTP_ERROR("Failed to get ic config version!No config sent!");
+ 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;
+ 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);
+ 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)
+ 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);
+ 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
+ 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;
+ 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];
+ 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);
+ ret = gtp_send_cfg(i2c);
+ GTP_ERROR("Send config error.");
+ /* for resume to send config */
+ config[GTP_ADDR_LENGTH] = drv_cfg_version;
+ 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);
+static s8 gtp_i2c_test(struct rt_i2c_bus_device *i2c)
+ s8 ret = -1;
+ u32 hw_info = 0;
+ while (retry++ < 5)
+ ret = i2c_read_bytes(i2c, GTP_REG_HW_INFO, (u8 *)&hw_info, sizeof(hw_info));
+ if ((!ret) && (hw_info == 0x00900600)) //20121212
+ 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));
+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);
+ gtp_int_sync(50);
+static s8 gtp_enter_doze(struct rt_i2c_bus_device *i2c)
+ s8 retry = 0;
+ u8 i2c_control_buf[3] = {(u8)(GTP_REG_SLEEP >> 8), (u8)GTP_REG_SLEEP, 8};
+ 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);
+ GTP_DEBUG("Failed to set gesture flag into 0x8046, %d", retry);
+ i2c_control_buf[1] = 0x40;
+ doze_status = DOZE_ENABLED;
+ GTP_INFO("Gesture mode enabled.");
+ GTP_ERROR("GTP send gesture cmd failed.");
+/*******************************************************
+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)
+ u8 i2c_status_buf[3] = {0x80, 0x44, 0x00};
+ 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.");
+#if GTP_POWER_CTRL_SLEEP
+ GTP_GPIO_OUTPUT(GTP_RST_PORT, 0);
+ GTP_GPIO_OUTPUT(GTP_INT_PORT, 0);
+#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");
+ #ifdef TPD_POWER_SOURCE_CUSTOM
+ hwPowerDown(TPD_POWER_SOURCE_CUSTOM, "TP");
+ #else
+ hwPowerDown(MT65XX_POWER_LDO_VGP2, "TP");
+ GTP_INFO("GTP enter sleep by poweroff!");
+ u8 i2c_control_buf[3] = {(u8)(GTP_REG_SLEEP >> 8), (u8)GTP_REG_SLEEP, 5};
+ rt_thread_delay(rt_tick_from_millisecond(5));
+ GTP_INFO("GTP enter sleep!");
+ GTP_ERROR("GTP send sleep cmd failed.");
+static s8 gtp_wakeup_sleep(struct rt_i2c_bus_device *i2c)
+ GTP_DEBUG("GTP wakeup begin.");
+#if (GTP_POWER_CTRL_SLEEP)
+ force_reset_guitar();
+ GTP_INFO("Esd recovery wakeup.");
+ ret = tpd_power_on(client);
+ GTP_ERROR("I2C Power on ERROR!");
+ GTP_INFO("Ic wakeup by poweron");
+ u8 opr_buf[2] = {0};
+ while (retry++ < 10)
+ GTP_GPIO_OUTPUT(GTP_INT_PORT, 1);
+ ret = gtp_i2c_test(client);
+ if (ret >= 0)
+ // Hold ss51 & dsp
+ opr_buf[0] = 0x0C;
+ ret = i2c_write_bytes(i2c, 0x4180, opr_buf, 1);
+ GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry);
+ // Confirm hold
+ opr_buf[0] = 0x00;
+ ret = i2c_read_bytes(i2c, 0x4180, opr_buf, 1);
+ GTP_DEBUG("confirm ss51 & dsp hold, I2C error,retry:%d", retry);
+ if (0x0C != opr_buf[0])
+ GTP_DEBUG("ss51 & dsp not hold, val: %d, retry: %d", opr_buf[0], retry);
+ GTP_DEBUG("ss51 & dsp has been hold");
+ ret = gtp_fw_startup(i2c);
+ if (FAIL == ret)
+ GTP_ERROR("[gtp_wakeup_sleep]Startup fw failed.");
+ GTP_INFO("flashless wakeup sleep success");
+ if (retry >= 10)
+ GTP_ERROR("wakeup retry timeout, process esd reset");
+ GTP_ERROR("GTP wakeup sleep failed.");
+ if (DOZE_WAKEUP != doze_status)
+ GTP_INFO("Powerkey wakeup.");
+ GTP_INFO("Gesture wakeup.");
+ doze_status = DOZE_DISABLED;
+ ret = gtp_i2c_test(i2c);
+ GTP_INFO("GTP wakeup sleep.");
+#if (!GTP_GESTURE_WAKEUP)
+ gtp_int_sync(25);
+#if GTP_ESD_PROTECT
+ gtp_init_ext_watchdog(client);
+static int touch_down_up_status;
+static void tpd_down(s32 x, s32 y, s32 size, s32 id)
+ if ((!size) && (!id))
+// input_report_abs(tpd->dev, ABS_MT_PRESSURE, 100);
+// input_report_abs(tpd->dev, ABS_MT_TOUCH_MAJOR, 100);
+// 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.x = x;
+ emouse.y = y;
+static void tpd_up(s32 x, s32 y, s32 id)
+// input_report_key(tpd->dev, BTN_TOUCH, 0);
+// 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);
+ emouse.x = xx;
+ emouse.y = yy;
+static int tpd_power_on(struct rt_i2c_bus_device *client)
+ int reset_count = 0;
+reset_proc:
+ gtp_reset_guitar(client, 20);
+ gtp_get_chip_type(client);
+ ret = gup_fw_download_proc(NULL, GTP_FL_FW_BURN);
+ GTP_ERROR("[tpd_power_on]Download fw failed.");
+ if(reset_count++ < TPD_MAX_RESET_COUNT)
+ goto reset_proc;
+ ret = gtp_fw_startup(client);
+ GTP_ERROR("[tpd_power_on]Startup fw failed.");
+ GTP_ERROR("I2C communication ERROR!");
+ if (reset_count < TPD_MAX_RESET_COUNT)
+ reset_count++;
+static int tpd_local_init(void)
+ 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
+ tpd_button_setting(TPD_KEY_COUNT, tpd_keys_local, tpd_keys_dim_local);// initialize tpd button data
+ 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);
+// memcpy(tpd_calmat, tpd_def_calmat_local, 8 * 4);
+// memcpy(tpd_def_calmat, tpd_def_calmat_local, 8 * 4);
+ 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;
+ 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;
+ u8 rqst_data[3] = {(u8)(GTP_REG_RQST >> 8), (u8)(GTP_REG_RQST & 0xFF), 0};
+#ifdef TPD_PROXIMITY
+ s32 err = 0;
+ hwm_sensor_data sensor_data;
+ u8 proximity_status;
+ u8 doze_buf[3] = {0x81, 0x4B};
+ while (tpd_halt)
+ tpd_flag = 0;
+// wait_event_interruptible(waiter, tpd_flag != 0);
+ /* wait */
+ gtp_charger_switch(0);
+ ret = gtp_i2c_read(i2c, doze_buf, 3);
+ GTP_DEBUG("0x814B = 0x%02X", doze_buf[2]);
+ 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]);
+ 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);
+ // 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]);
+ else if (0xCC == doze_buf[2])
+ GTP_INFO("Double click to light up the screen!");
+ gtp_enter_doze(i2c);
+ ret = gtp_i2c_read(i2c, point_data, 12);
+ GTP_ERROR("I2C transfer error. errno:%d\n ", ret);
+ finger = point_data[GTP_ADDR_LENGTH];
+ if ((finger == 0x00) && (CHIP_TYPE_GT9F == gtp_chip_type))
+ ret = gtp_i2c_read(i2c_client_point, rqst_data, 3);
+ if(ret < 0)
+ 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);
+ GTP_INFO("Send config success.");
+ case GTP_RQST_MAIN_CLOCK:
+ GTP_INFO("Request main clock.");
+ ret = gtp_main_clk_proc(i2c_client_point);
+ GTP_INFO("Send main clk success.");
+ case GTP_RQST_RESET:
+ GTP_INFO("Request Reset.");
+ gtp_recovery_reset(i2c_client_point);
+ GTP_INFO("Undefined request code: 0x%02X", rqst_data[2]);
+ if (finger == 0x00)
+ if ((finger & 0x80) == 0)
+ 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;
+ 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);
+ GTP_ERROR("Call hwmsen_get_interrupt_data fail = %d\n", err);
+ touch_num = finger & 0x0f;
+ if (touch_num > GTP_MAX_TOUCH)
+ 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_STYLUS2, 0);
+ else if (key_value == 0x20)
+ GTP_DEBUG("BTN_STYLUS Up, BTN_STYLUS2 Down.");
+ input_report_key(pen_dev, BTN_STYLUS, 0);
+ GTP_DEBUG("BTN_STYLUS & BTN_STYLUS2 Up.");
+ if ( (pre_key == 0x40) || (pre_key == 0x20) ||
+ (pre_key == 0x10)
+ if (pen_active)
+ touch_num = 0; // shield pen point
+ //pre_touch = 0; // clear last pen status
+ 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
+ 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);
+ 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);
+ GTP_DEBUG(" (%d)(%d, %d)[%d]", id, input_x, input_y, input_w);
+ tpd_down(input_x, input_y, input_w, id);
+ if (pre_touch)
+ if (pre_pen)
+ GTP_DEBUG("Pen touch UP!");
+ gtp_pen_up();
+ pre_pen = 0;
+ GTP_DEBUG("Touch Release!");
+ tpd_up(0, 0, 0);
+ pre_touch = touch_num;
+ pen_active = 0;
+ input_sync(pen_dev);
+exit_work_func:
+ if (!gtp_rawdiff_mode)
+ ret = gtp_i2c_write(i2c, end_cmd, 3);
+ GTP_INFO("I2C write end_cmd error!");
+static int tpd_i2c_probe(struct rt_i2c_bus_device *i2c)
+ u16 version_info;
+ s32 idx = 0;
+ struct hwmsen_object obj_ps;
+ ret = tpd_power_on(i2c);
+ ret = gtp_read_version(i2c, &version_info);
+ GTP_ERROR("Read version failed.");
+ ret = gtp_init_panel(i2c);
+ GTP_ERROR("GTP init panel failed.");
+ for (idx = 0; idx < GTP_MAX_KEY_NUM; idx++)
+ input_set_capability(tpd->dev, EV_KEY, touch_key_array[idx]);
+// input_set_capability(tpd->dev, EV_KEY, KEY_POWER);
+ gtp_pen_init();
+ // set INT mode
+ gpio_direction_input(GTP_INT_PORT, GTP_INT_PIN);
+ 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);
+ gtp_esd_switch(client, SWITCH_ON);
+#if GTP_AUTO_UPDATE
+ ret = gup_init_update_proc(client);
+ GTP_ERROR("Create update thread error.");
+ //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);
+/******************************************************************************/
+// Description: rt_hw_touch_init
+// Dependence:
+// Note: GPIO_PROD_TP_INT_ID
+ uint32_t reset_count;
+ if(i2c_bus == RT_NULL)
+ rt_kprintf("can't find the i2c bus:%s\n","i2c0");
+ 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);
+ tpd_i2c_probe(i2c_bus);
@@ -0,0 +1,71 @@
+ * File : gt9xx.h
+#ifndef _GT9XX_H_
+#define _GT9XX_H_
+#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
+#define GT910_IIC_RADDR 0x29
+#define GT910_IIC_WADDR 0x28
+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);
+#endif /* _GT9XX_H_ */
@@ -0,0 +1,326 @@
+ * File : gt9xx_cfg.h
+#ifndef DRIVER_TOUCH_GT9XX_CFG_H_
+#define DRIVER_TOUCH_GT9XX_CFG_H_
+/* 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,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,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.
+ #define GTP_MAX_HEIGHT 800
+ #define GTP_MAX_WIDTH 480
+ #define GTP_INT_TRIGGER 0 //0:Rising 1:Falling
+ #define GTP_MAX_HEIGHT 4096
+ #define GTP_MAX_WIDTH 4096
+ #define GTP_INT_TRIGGER 1
+#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.
+ #define GTP_KEY_TAB {KEY_MENU, KEY_HOME, KEY_BACK, KEY_SEND}
+//***************************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 **********************//
+ CHIP_TYPE_GT9 = 0,
+ CHIP_TYPE_GT9F = 1,
+} CHIP_TYPE_T;
+#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
+#ifdef TPD_WARP_X
+#undef TPD_WARP_X
+#define TPD_WARP_X(x_max, x) ( x_max - 1 - x )
+#define TPD_WARP_X(x_max, x) x
+#ifdef TPD_WARP_Y
+#undef TPD_WARP_Y
+#define TPD_WARP_Y(y_max, y) ( y_max - 1 - y )
+#define TPD_WARP_Y(y_max, y) y
+#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);\
+#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");\
+ }\
+#define GTP_DEBUG_FUNC() do{\
+ if(GTP_DEBUG_FUNC_ON)\
+ printf("<<-GTP-FUNC->> Func:%s@Line:%d\n",__func__,__LINE__);\
+#define GTP_SWAP(x, y) do{\
+ typeof(x) z = x;\
+ x = y;\
+ y = z;\
+ }while (0)
+//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 /* DRIVER_TOUCH_GT9XX_CFG_H_ */
+ * File : gt9xx_firmware.h
+#ifndef _GT9XX_FIRMWARE_H_
+#define _GT9XX_FIRMWARE_H_
+#if GTP_HEADER_FW_UPDATE
+unsigned char gtp_default_FW[] =
+ //TODO:Puts your update firmware data here!
+*[HW INFO]00900600
+*[PID]910
+*[VID]1010
+*[GENERATED]2013/08/27 20:59:13
+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, 0x02,
+ 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 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, 0xC3, 0x01 };
+#endif /* _GT9XX_FIRMWARE_H_ */
+src = Glob('*.c')
+group = DefineGroup('DriversUSBD', src, depend = ['RT_USING_USB_DEVICE'], CPPPATH = CPPPATH)
@@ -0,0 +1,362 @@
+ * drv_usbd.c
+ * Created on: 2017Äê2ÔÂ1ÈÕ
+#include <drivers/usb_device.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)
+#define USBD_DBG(fmt, args...)
+static void __delay(void)
+ 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},
+ {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},
+ {0xFF, USB_EP_ATTR_TYPE_MASK, USB_DIR_MASK, 0, ID_ASSIGNED}
+ rt_kprintf("%06x: ", i);
+ rt_kprintf("%02x ", buf[i+j]);
+static rt_err_t __ep_set_stall(rt_uint8_t address)
+// RT_ASSERT(address != 0);
+ RT_DEBUG_LOG(RT_DEBUG_USB, ("ep set_stall, address 0x%x\n", address));
+ dwc_set_ep_stall(&__dwc_hdl, address);
+static rt_err_t __ep_clear_stall(rt_uint8_t address)
+ RT_DEBUG_LOG(RT_DEBUG_USB, ("ep clear_stall, address 0x%x\n", address));
+ dwc_clr_ep_stall(&__dwc_hdl, address);
+static rt_err_t __set_address(rt_uint8_t address)
+ RT_DEBUG_LOG(RT_DEBUG_USB,("set address, 0x%x\n", address));
+ dwc_set_address(&__dwc_hdl,address);
+static rt_err_t __set_config(rt_uint8_t address)
+ RT_DEBUG_LOG(RT_DEBUG_USB,("%s, 0x%x\n", __func__,address));
+ //init EP0
+ __dwc_hdl.status.b.state = USB_CONFIGURED;
+static rt_err_t __ep_enable(uep_t ep)
+ dwc_ep* dwc_ep;
+ RT_ASSERT(ep != RT_NULL);
+ RT_ASSERT(ep->ep_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);
+ dwc_enable_out_ep(&__dwc_hdl,ep->id->addr);
+static rt_err_t __ep_disable(uep_t ep)
+ RT_DEBUG_LOG(RT_DEBUG_USB,("%s\n", __func__));
+ // USB_DisableEP(EP_ADDRESS(ep));
+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);
+static rt_size_t __ep_read(rt_uint8_t address, void *buffer)
+ rt_size_t size = 0;
+ RT_ASSERT(buffer != RT_NULL);
+ size = HW_GetPKT(&__dwc_hdl,address,(uint8_t *)buffer,0);
+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);
+static rt_err_t __ep0_send_status(void)
+ HW_SendPKT(&__dwc_hdl,0,0,0);
+static rt_err_t __suspend(void)
+static rt_err_t __wakeup(void)
+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");
+ /* 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;
+ __dwc_hdl.dep[0 + DWC_EP_IN_OFS] = pep;
+ __dwc_hdl.dep[0 + DWC_EP_OUT_OFS] = 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->type = __ep_pool[epidx].type;
+ if(__ep_pool[epidx].dir == USB_DIR_OUT)
+ epnum = __ep_pool[epidx].addr + DWC_EP_OUT_OFS;
+ 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);
+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)
+ case USB_EVT_SETUP:
+ USBD_DBG("USB_EVT_SETUP\n");
+ if(address == 0)
+ rt_usbd_ep0_setup_handler(&__x1000_usbd, (struct urequest*)arg);
+ case USB_EVT_OUT:
+ USBD_DBG("USB_EVT_OUT\n");
+ rt_usbd_ep0_out_handler(&__x1000_usbd, (rt_size_t)arg);
+ rt_usbd_ep_out_handler(&__x1000_usbd, USB_DIR_OUT | address, 0);
+ case USB_EVT_IN:
+ USBD_DBG("USB_EVT_IN\n");
+ rt_usbd_ep0_in_handler(&__x1000_usbd);
+ rt_usbd_ep_in_handler(&__x1000_usbd, USB_DIR_IN | address,__dwc_hdl.dep[DWC_EP_IN_OFS + address]->xfer_count);
+ case USB_EVT_SOF:
+ rt_usbd_sof_handler(&__x1000_usbd);
+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();
+INIT_ENV_EXPORT(x1000_usbd_register);
@@ -0,0 +1,2027 @@
+#include <mips_regs.h>
+//#define DWC_DEBUG
+#ifdef DWC_DEBUG
+#define DWC_DBG(fmt, args...) rt_kprintf(fmt ,##args)
+#define DWC_DBG(fmt, args...)
+#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",
+#define DEP_EP_MAXPKT(n) \
+ ({ \
+ int v = 0; \
+ if (n) \
+ v = 64; \
+ else \
+ v; \
+ })
+ v = 512; \
+#define MAX_PKT_CNT 1023
+//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 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)
+ 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 dwords = (count + 3) / 4;
+ pep = dwc->dep[DWC_EP_OUT_OFS + epnum];
+ 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 txstatus = REG_DIEP_TXFSTS(epnum & 0x0F);
+ insize = pep->xfer_len;
+ if (pep->xfer_len > DEP_EP_MAXPKT(epnum))
+ xfersize = DEP_EP_MAXPKT(epnum);
+ 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))
+ 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);
+void dwc_handle_ep_data_in_phase(dwc_handle *dwc, uint8_t epnum)
+ uint32_t pktcnt, xfersize;
+ uint32_t dma_addr, dma_len;
+ DWC_DBG("%s %d\n",__func__,__LINE__);
+ DWC_DBG("epnum = %d\n",epnum);
+ pktcnt = (xfersize + DEP_EP_MAXPKT(epnum) - 1) / DEP_EP_MAXPKT(epnum);
+ if (pktcnt > 1023)
+ DWC_DBG("WARNING...\n");
+ if (epnum == 0)
+ REG_DIEP_SIZE(epnum) &= ~(0x1fffff);
+ REG_DIEP_SIZE(epnum) |= (pktcnt << 19) | xfersize;
+ REG_DIEP_SIZE(epnum) &= ~(0x1fffffff);
+ 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");
+ for (i = 0; i < dma_len; ++i)
+ DWC_DBG("%02x ", *(unsigned char *)(dma_addr+i));
+ if ((i + 1) % 16 == 0)
+ DWC_DBG("\n");
+ REG_DIEP_DMA(epnum) = PHYS(pep->xfer_buff);
+ REG_DIEP_CTL(epnum) |= (DEP_ENA_BIT | DEP_CLEAR_NAK);
+ REG_DIEP_EMPMSK |= (1 << epnum);
+void dwc_handle_ep_status_in_phase(dwc_handle *dwc, uint8_t epnum)
+ REG_DIEP_SIZE(epnum) |= DOEPSIZE0_PKTCNT_BIT | (pep->xfer_len); // pktcnt->1 xfersize->0
+ REG_DIEP_SIZE(epnum) &= ~(0x1FFFFFFF);
+ 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;
+void dwc_handle_ep_data_out_phase(dwc_handle *dwc,uint8_t epnum)
+ uint32_t pktcnt;
+ 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;
+ 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);
+ REG_DOEP_SIZE(epnum) &= ~(0x1fffffff);
+ REG_DOEP_SIZE(epnum) |= (pktcnt << 19) | (pep->xfer_len);
+ rt_hw_dcache_flush_range(dma_addr, dma_len);
+ /* Program the DOEPCTLn Register with endpoint charateristics,
+ * and set the Endpoint Enable and Clear NAK bit */
+int HW_SendPKT(dwc_handle *dwc, uint8_t epnum, const uint8_t *buf, int size)
+ DWC_DBG("HW_SendPKT addr = %02x,size = %d\n",epnum,size);
+ 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);
+ switch (pep->type)
+ case DWC_OTG_EP_TYPE_CONTROL:
+ 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);
+ /* 3 Stage */
+ if (pep->ep_state == EP_DATA)
+ /* enable in data phase */
+ dwc_handle_ep_data_in_phase(dwc, epnum);
+ 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 pep->xfer_len;
+int HW_GetPKT(dwc_handle *dwc, uint8_t epnum, uint8_t *buf,int size)
+ DWC_DBG("HW_GetPKT:%d %d\n", epnum, dwc->is_dma);
+ if ((size == 0) || (size > pep->xfer_count))
+ size = pep->xfer_count;
+ 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);
+ memcpy((uint8_t*) buf, (uint8_t *) (pep->xfer_buff), 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))
+ /* 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)
+ /* 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;
+ REG_DIEP_CTL(epnum) |= DEP_SET_NAK;
+ 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)
+ REG_DOEP_CTL(epnum) |= DEP_SET_NAK;
+static void dwc_disable_in_ep(dwc_handle *dwc,int epnum)
+ int timeout = 100000;
+ if (!(REG_DIEP_CTL(epnum) & DEP_ENA_BIT))
+ /*step 1 : set nak*/
+ dwc_set_in_nak(dwc,epnum);
+ /*step 2: disable endpoint*/
+ REG_DIEP_CTL(epnum) |= DEP_DISENA_BIT;
+ 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)
+ /* 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;
+ case USB_SPEED_HIGH:
+ REG_DIEP_CTL(epnum) |= DEP_HS_PKTSIZE;
+ //tx fifo number
+ REG_DIEP_CTL(epnum) |= (epnum << 22);
+ //ep type
+ REG_DIEP_CTL(epnum) |= USB_ACTIVE_EP | DEP_TYPE_CNTL;
+ case DWC_OTG_EP_TYPE_ISOC:
+ REG_DIEP_CTL(epnum) |= USB_ACTIVE_EP | DEP_TYPE_ISO;
+ REG_DIEP_CTL(epnum) |= USB_ACTIVE_EP | DEP_TYPE_BULK;
+ case DWC_OTG_EP_TYPE_INTR:
+ REG_DIEP_CTL(epnum) |= USB_ACTIVE_EP | DEP_TYPE_INTR;
+ /* DATA0 */
+ REG_DIEP_CTL(epnum) |= (1 << 28);
+ /* Enable EP INT */
+ REG_DAINT_MASK |= (0x01 << (DWC_EP_IN_OFS + epnum));
+int dwc_enable_out_ep(dwc_handle *dwc,uint8_t epnum)
+ uint32_t xfersize;
+ uint32_t dma_addr, dma_len, pktcnt;
+ REG_DOEP_CTL(epnum) &= ~DEP_PKTSIZE_MASK;
+ REG_DOEP_CTL(epnum) &= ~DEP_TYPE_MASK;
+ REG_DOEP_CTL(epnum) |= DEP_FS_PKTSIZE;
+ REG_DOEP_CTL(epnum) |= DEP_HS_PKTSIZE;
+ REG_DOEP_CTL(epnum) |= USB_ACTIVE_EP | DEP_TYPE_CNTL;
+ REG_DOEP_CTL(epnum) |= USB_ACTIVE_EP | DEP_TYPE_ISO;
+ REG_DOEP_CTL(epnum) |= USB_ACTIVE_EP | DEP_TYPE_BULK;
+ REG_DOEP_CTL(epnum) |= USB_ACTIVE_EP | DEP_TYPE_INTR;
+ REG_DOEP_CTL(epnum) |= (1 << 28);
+ 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;
+ /* 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) = (pktcnt << 19) | xfersize;
+ dma_len = (((xfersize + 7) >> 3) << 3); //pep->xfer_len;
+ /* Additionally, in DMA mode, program the DOEPDMAn register */
+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];
+ pep->xfer_len = 64;
+ pep->maxpacket = 64;
+// pep->ctrl_req_addr = (uint32_t)(&setup_packet[0]);
+ pep->xfer_buff = pep->xfer_buff;
+ 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);
+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; i<dwc->hwcfg4.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;
+ diep0ctl |= DEP_EP0_MPS_64;
+ REG_OTG_DCFG &= ~1;
+ case DSTS_ENUM_SPEED_FULL_30OR60:
+ case DSTS_ENUM_SPEED_FULL_48:
+ DWC_DBG("Full speed.\n");
+ dwc->speed = USB_SPEED_FULL;
+ REG_OTG_DCFG |= 1;
+ case DSTS_ENUM_SPEED_LOW:
+ DWC_DBG("Low speed.\n");
+ dwc->speed = USB_SPEED_LOW;
+ pep->maxpacket = 8;
+ diep0ctl |= DEP_EP0_MPS_8;
+ DWC_DBG("Fault speed enumration\n");
+ /* 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);
+ 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;
+ /* Step4: unmask the SOF interrupt */
+ REG_GINT_MASK |= GINTMSK_START_FRAM;
+ REG_GINT_STS = GINTSTS_ENUM_DONE;
+ // dump_global_dwcreg();
+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(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();
+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)
+ /* Step1: NAK OUT ep */
+ for (i=0; i<dwc->hwcfg2.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 */
+ /* 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);
+ dwc_disable_in_ep(dwc,0);
+ REG_GINT_STS = GINTSTS_USB_RESET;
+void dwc_handle_rxfifo_nempty(dwc_handle *dwc)
+ 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");
+ 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);
+ case GRXSTSP_PKSTS_TX_COMP:
+ DWC_DBG("GRXSTSP_PKSTS_TX_COMP.\n");
+ case GRXSTSP_PKSTS_SETUP_COMP:
+ DWC_DBG("GRXSTSP_PKSTS_SETUP_COMP.\n");
+ 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]);
+ REG_GINT_STS = GINTSTS_RXFIFO_NEMPTY;
+void dwc_ep0_in_intr(dwc_handle *dwc, uint8_t epnum)
+ uint32_t updated_size;
+ uint8_t *ptr;
+ uint32_t intr = REG_DIEP_INT(epnum & 0x0F);
+ DWC_DBG("ep0 in intr:%x\n", intr);
+ /* 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)
+ pep->xfer_len -= pep->xfer_count;
+ ptr = (uint8_t *)pep->xfer_buff + pep->xfer_count;
+ HW_SendPKT(dwc, 0, ptr, pep->xfer_len);
+ DWC_DBG("pep->ep_state = %s\n",ep0_state_string[pep->ep_state]);
+ switch(pep->ep_state)
+ case EP_DATA:
+ if(pep->xfer_len == pep->maxpacket)
+ x1000_usbd_event_cb(0, USB_EVT_IN, RT_NULL);
+ dwc_handle_ep_data_out_phase(dwc,0);
+ case EP_STATUS:
+ 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)
+ DWC_DBG("1 IN XFER_COMP. %x\n", REG_DIEP_SIZE(epnum));
+ REG_DIEP_INT(epnum) = DEP_XFER_COMP;
+ if (pep->ep_state == EP_TRANSFERING)
+ 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);
+// DWC_DBG("TX FIFO EMPTY intr.\n");
+ * 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;
+ intr = REG_DOEP_INT(epnum);
+// printf("ep0 out intr:%x\n", intr);
+ /* comp intrerrupt indeicates completion of the status out phase */
+ REG_DOEP_INT(epnum) = DEP_XFER_COMP;
+ if (pep->ep_state == EP_STATUS)
+ 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");
+ 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)
+ REG_DOEP_INT(epnum) = DEP_INTOKEN_EPMISATCH;
+ 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");
+ /* 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));
+ 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");
+ /* 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_DMA(epnum) = PHYS(pep->ctrl_req_addr);
+ /* 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;
+int dwc_epn_out_intr(dwc_handle *dwc, uint8_t epnum)
+ uint32_t intr, updated_size;
+ DWC_DBG("ep%d out_intr\n",epnum);
+ updated_size = REG_DOEP_SIZE(epnum) & 0x7ffff;
+ 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);
+ pep->xfer_len = pep->maxpacket; /* number of bytes to transfer */
+// pep->xfer_buff = pep->xfer_buff; /* pointer to transfer buffer */
+ DWC_DBG("REG_DOEP_SIZE: %x \n", REG_DOEP_SIZE(epnum));
+ REG_DOEP_INT(epnum) = DEP_AHB_ERR;
+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)
+ dwc_ep0_in_intr(dwc, epnum);
+ dwc_epn_in_intr(dwc, epnum);
+ epnum++;
+ ep_intr >>= 1;
+ REG_GINT_STS = GINTSTS_IEP_INTR;
+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);
+ dwc_ep0_out_intr(dwc, 0);
+ dwc_epn_out_intr(dwc, epnum);
+ epnum ++;
+ 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;
+ REG_GRST_CTL |= RSTCTL_CORE_RST;
+ greset = REG_GRST_CTL;
+ if (cnt++ > 100000)
+ DWC_DBG("GRESET wait reset timeout.\n");
+ } while (greset & RSTCTL_CORE_RST);
+ cnt = 0;
+ DWC_DBG("GRESET wait IDLE timeout.\n");
+ } while ((greset & RSTCTL_AHB_IDLE) == 0);
+ /* wait for 3 phy clocks */
+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 (REG_GINT_MASK & (GINTMSK_NPTXFIFO_EMPTY | GINTMSK_RXFIFO_NEMPTY))
+ REG_GINT_MASK &= ~(GINTMSK_NPTXFIFO_EMPTY | GINTMSK_RXFIFO_NEMPTY);
+ REG_GINT_MASK |= (GINTMSK_NPTXFIFO_EMPTY | GINTMSK_RXFIFO_NEMPTY);
+ /* Program the DCFG register */
+ if (dwc->hwcfg4.b.desc_dma)
+ dcfg |= DCFG_DEV_DESC_DMA;
+ REG_OTG_DCFG |= 1; //dma buffer mode full speed
+ REG_OTG_DCFG &= ~3; //dma buffer mode HIGH speed
+ /* 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;
+ case IS_EXTERN_DMA:
+ dwc->is_dma = IS_EXTERN_DMA;
+ case IS_INTERN_DMA:
+ dwc->is_dma = IS_INTERN_DMA;
+ /* 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);
+ ahbcfg |= AHBCFG_TXFE_LVL;
+ dwc->is_dma = 0;
+ DWC_DBG("DWC IS_SLAVE_MODE\n");
+ /* Step3: Program the GINTMSK register */
+ /* 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);
+ /* 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)
+int dwc_set_ep_stall(dwc_handle *dwc,uint8_t epnum)
+ depctl_data_t depctl;
+ daint_data_t daintmsk;
+ if(epnum & USB_DIR_IN)
+ pep = dwc->dep[epnum & 0x0F + DWC_EP_IN_OFS];
+ pep = dwc->dep[epnum & 0x0F + DWC_EP_OUT_OFS];
+ if (pep->is_in)
+ depctl.d32 = REG_DIEP_CTL(epnum);
+ depctl.b.stall = 1;
+ REG_DIEP_CTL(epnum) = depctl.d32;
+ depctl.d32 = REG_DOEP_CTL(epnum);
+ REG_DOEP_CTL(epnum) = depctl.d32;
+int dwc_clr_ep_stall(dwc_handle *dwc,uint8_t epnum)
+ depctl.b.stall = 0;
+int dwc_ep_disable(dwc_handle *dwc,uint8_t epnum)
+ DWC_DBG("%s epnum = %02x \n",epnum);
+ /* EP0 can not deactivate! */
+ daintmsk.d32 = REG_DAINT_MASK;
+ daintmsk.ep.in &= ~(1 << epnum);
+ daintmsk.ep.out &= ~(1 << epnum);
+ if (!depctl.b.usbactep)
+ DWC_DBG("EP %d already deactivated\n", pep->num);
+ depctl.b.usbactep = 0;
+ /* mask EP interrupts */
+ REG_DAINT_MASK = daintmsk.d32;
+ if(pep->is_in)
+ {/* Disable IN-EP */
+ /* Disable IN-EP */
+ DWC_DBG("EP %d deactivated\n", pep->num);
+static void x1000_usb_phy_switch(dwc_handle *dwc,uint8_t is_on)
+ if (is_on)
+ value = REG_CPM_OPCR;
+ REG_CPM_OPCR |= OPCR_OTGPHY0_ENABLE;
+ mdelay(1);
+ REG_CPM_OPCR &= ~OPCR_OTGPHY0_ENABLE;
+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;
+ REG_CPM_USBPCR &= ~USBPCR_POR;
+/* usb device init */
+static void dwc_gadget_init(dwc_handle *dwc)
+ uint32_t curmod;
+ // REG_CPM_CLKGR0 &= ~(1 << 2);
+ /* 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;
+ REG_CPM_USBPCR &= ~(1 << 31);
+ REG_CPM_USBPCR |= (1 << 23) | (1 << 24);
+ /* 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 */
+ udelay(3000);
+ /* reset dwc register */
+ /* DWC OTG Core init */
+ /* Read Gintsts confirm the device or host mode */
+ curmod = REG_GINT_STS;
+ if (curmod & 0x1)
+ DWC_DBG("Curmod: Host Mode\n");
+ DWC_DBG("Curmod: Device Mode\n");
+ /* DWC OTG Device init */
+ /* DWC OTG Fifo init */
+ /* 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_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);
+ 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__);
+ dwc->status.b.state = USB_CABLE_DISCONNECT;
+ dwc->status.b.event = 0;
+ dwc_gadget_init(dwc);
+ /* create a ISR service task */
+ tid = rt_thread_create("dwcIntSv",
+ x1000_usbd_isr_service, (void *) dwc,
+ 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");
+ DWC_DBG("[DWC] DWC request IRQ success %x\n", REG_GINT_MASK);
@@ -0,0 +1,598 @@
+ * x1000_dwc.h
+ * Created on: 2017Äê2ÔÂ3ÈÕ
+#ifndef _X1000_DWC_H_
+#define _X1000_DWC_H_
+#define DWC_FORCE_SPEED_FULL 0
+#define ENDPOINT_PACKET_SIZE 64
+#define CONTROL_MAX_PACKET_SIZE 64
+#define ENDPOINT_PACKET_SIZE 512
+#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 <i>d32</i> element then read
+ * out the bits using the <i>b</i>it elements.
+typedef union hwcfg2_data {
+ /** raw register data */
+ /** register bits */
+ /* 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;
+} hwcfg2_data_t;
+ * This union represents the bit fields in the User HW Config3
+typedef union hwcfg3_data {
+ /* 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;
+} hwcfg3_data_t;
+ * This union represents the bit fields in the User HW Config4
+typedef union hwcfg4_data {
+ 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;
+} hwcfg4_data_t;
+typedef union dwc_state {
+ uint8_t d8;
+ 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 <i>d32</i> member then
+ * set/clear the bits using the <i>b</i>it elements.
+typedef union dctl_data {
+ /** 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;
+} 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 <i>d32</i> value to the register.
+typedef union gintmsk_data {
+ 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;
+} gintmsk_data_t;
+ * This union represents the bit fields in the Device EP Control
+typedef union depctl_data {
+ /** 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
+ 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)
+ * field in this register to DATA1 Set Odd
+ * (micro)frame (SetOddFr) (ISO IN and OUT Endpoints)
+ * (micro)frame (EO_FrNum) field to odd (micro) frame.
+ unsigned setd1pid:1;
+ /** Endpoint Disable */
+ unsigned epdis:1;
+ /** Endpoint Enable */
+ unsigned epena:1;
+} 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 <i>d32</i> member then set/clear the
+ * bits using the <i>b</i>it elements.
+typedef union diepint_data {
+ /** 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;
+ unsigned emptyintr:1;
+ unsigned txfifoundrn:1;
+ /** BNA Interrupt mask */
+ unsigned bna:1;
+ unsigned reserved10_12:3;
+ unsigned nak:1;
+ unsigned reserved14_31:18;
+} 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.
+typedef union doepint_data {
+ /** Transfer complete */
+ /** Endpoint disable */
+ /** AHB Error */
+ /** 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 reserved10:1;
+ /** Packet Drop Status */
+ unsigned pktdrpsts:1;
+ /** Babble Interrupt */
+ unsigned babble:1;
+ /** NAK Interrupt */
+ /** NYET Interrupt */
+ unsigned nyet:1;
+ unsigned reserved15_31:17;
+} doepint_data_t;
+ * This union represents the bit fields in the Device OUT EP
+typedef union doepint_data doepmsk_data_t;
+ * This union represents the bit fields in the Device All EP Interrupt
+ * and Mask Registers.
+typedef union daint_data {
+ /** IN Endpoint bits */
+ unsigned in:16;
+ /** OUT Endpoint bits */
+ unsigned out:16;
+ } ep;
+ 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;
+ 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;
+} 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_ */
@@ -1,217 +1,235 @@
-#ifndef __RTTHREAD_CFG_H__
-#define __RTTHREAD_CFG_H__
-// <RDTConfigurator URL="http://www.rt-thread.com/eclipse">
-// <integer name="RT_NAME_MAX" description="Maximal size of kernel object name length" default="6" />
-#define RT_NAME_MAX 8
-// <integer name="RT_ALIGN_SIZE" description="Alignment size for CPU architecture data access" default="4" />
-#define RT_ALIGN_SIZE 4
-// <integer name="RT_THREAD_PRIORITY_MAX" description="Maximal level of thread priority" default="32">
-// <item description="8">8</item>
-// <item description="32">32</item>
-// <item description="256">256</item>
-// </integer>
-#define RT_THREAD_PRIORITY_MAX 32
-// <integer name="RT_TICK_PER_SECOND" description="OS tick per second" default="100" />
-#define RT_TICK_PER_SECOND 100
-// <integer name="IDLE_THREAD_STACK_SIZE" description="The stack size of idle thread" default="512" />
-#define IDLE_THREAD_STACK_SIZE 1024
-// <section name="RT_DEBUG" description="Kernel Debug Configuration" default="true" >
+#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
-// <integer name="RT_DEBUG_SCHEDULER" description="Enable scheduler debug information" default="0" />
-#define RT_DEBUG_SCHEDULER 0
-// <bool name="RT_USING_OVERFLOW_CHECK" description="Thread stack over flow detect" default="true" />
#define RT_USING_OVERFLOW_CHECK
-// </section>
-// <bool name="RT_USING_HOOK" description="Using hook functions" default="true" />
+#define RT_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
-// <section name="RT_USING_TIMER_SOFT" description="Using software timer which will start a thread to handle soft-timer" default="true" >
-// #define RT_USING_TIMER_SOFT
-// <integer name="RT_TIMER_THREAD_PRIO" description="The priority level of timer thread" default="4" />
-#define RT_TIMER_THREAD_PRIO 4
-// <integer name="RT_TIMER_THREAD_STACK_SIZE" description="The stack size of timer thread" default="512" />
-#define RT_TIMER_THREAD_STACK_SIZE 512
+/* Inter-Thread communication */
-// <section name="IPC" description="Inter-Thread communication" default="always" >
-// <bool name="RT_USING_SEMAPHORE" description="Using semaphore in the system" default="true" />
#define RT_USING_SEMAPHORE
-// <bool name="RT_USING_MUTEX" description="Using mutex in the system" default="true" />
#define RT_USING_MUTEX
-// <bool name="RT_USING_EVENT" description="Using event group in the system" default="true" />
#define RT_USING_EVENT
-// <bool name="RT_USING_MAILBOX" description="Using mailbox in the system" default="true" />
#define RT_USING_MAILBOX
-// <bool name="RT_USING_MESSAGEQUEUE" description="Using message queue in the system" default="true" />
#define RT_USING_MESSAGEQUEUE
+/* RT_USING_SIGNALS is not set */
+/* Memory Management */
-// <section name="MM" description="Memory Management" default="always" >
-// <bool name="RT_USING_MEMPOOL" description="Using Memory Pool Management in the system" default="true" />
#define RT_USING_MEMPOOL
-// <bool name="RT_USING_MEMHEAP" description="Using Memory Heap Object in the system" default="true" />
-// #define RT_USING_MEMHEAP
-// <bool name="RT_USING_HEAP" description="Using Dynamic Heap Management in the system" default="true" />
+/* RT_USING_MEMHEAP is not set */
#define RT_USING_HEAP
-// <bool name="RT_USING_SMALL_MEM" description="Optimizing for small memory" default="false" />
#define RT_USING_SMALL_MEM
-// <bool name="RT_USING_SLAB" description="Using SLAB memory management for large memory" default="false" />
-// #define RT_USING_SLAB
+/* RT_USING_SLAB is not set */
+/* Kernel Device Object */
-// <section name="RT_USING_DEVICE" description="Using Device Driver Framework" default="true" >
#define RT_USING_DEVICE
-// <bool name="RT_USING_SERIAL" description="Using serial frame work" default="true" />
-#define RT_USING_SERIAL
-// <bool name="RT_USING_SPI" description="Using SPI frame work" default="true" />
-// #define RT_USING_SPI
-// <bool name="RT_USING_DEVICE_IPC" description="Using IPC for device driver" default="true" />
-#define RT_USING_DEVICE_IPC
-// <bool name="RT_USING_SDIO" description="Using SDIO frame work for SD, MMC, SDIO wifi" default="true" />
-#define RT_USING_SDIO
-// <bool name="RT_USING_USB_DEVICE" description="Using USB Device Stack" default="true" />
-//#define RT_USING_USB_DEVICE
-//#define RT_USB_DEVICE_CDC
-//#define USB_VENDOR_ID 0x0483
-//#define USB_PRODUCT_ID 0x5740
-// <section name="RT_USING_CONSOLE" description="Using console" default="true" >
+/* RT_USING_INTERRUPT_INFO is not set */
#define RT_USING_CONSOLE
-// <integer name="RT_CONSOLEBUF_SIZE" description="The buffer size for console output" default="128" />
-#define RT_CONSOLEBUF_SIZE 128
-// <string name="RT_CONSOLE_DEVICE_NAME" description="The device name for console" default="uart1" />
-#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 */
-// <section name="RT_USING_FINSH" description="Using finsh as shell, which is a C-Express shell" default="true" >
#define RT_USING_FINSH
-// <bool name="FINSH_USING_SYMTAB" description="Using symbol table in finsh shell" default="true" />
+#define FINSH_USING_HISTORY
#define FINSH_USING_SYMTAB
-// <bool name="FINSH_USING_DESCRIPTION" description="Keeping description in symbol table" default="true" />
#define FINSH_USING_DESCRIPTION
-// <integer name="FINSH_THREAD_STACK_SIZE" description="The stack size for finsh thread" default="2048" />
+#define FINSH_THREAD_PRIORITY 20
#define FINSH_THREAD_STACK_SIZE 4096
-// <bool name="FINSH_USING_MSH" description="Using module shell" default="true" />
+#define FINSH_CMD_SIZE 80
+/* FINSH_USING_AUTH is not set */
#define FINSH_USING_MSH
-// <bool name="FINSH_USING_MSH_DEFAULT" description="Using msh in default" default="true" />
#define FINSH_USING_MSH_DEFAULT
-// <bool name="FINSH_USING_MSH_ONLY" description="Only using msh" default="true" />
-// #define FINSH_USING_MSH_ONLY
+/* FINSH_USING_MSH_ONLY is not set */
-// <section name="LIBC" description="C Runtime library setting" default="always" >
-// <bool name="RT_USING_LIBC" description="Using C library" default="true" />
-#define RT_USING_LIBC
-// <bool name="RT_USING_PTHREADS" description="Using POSIX threads library" default="true" />
-#define RT_USING_PTHREADS
-// <bool name="RT_USING_COMPONENTS_INIT" description="Using automatically component initialization." default="true" />
-#define RT_USING_COMPONENTS_INIT
-// <bool name="RT_USING_USER_MAIN" description="Using main() as user entry" default="true" />
-#define RT_USING_USER_MAIN
+/* Device virtual file system */
-// <section name="RT_USING_DFS" description="Device file system" default="true" >
#define RT_USING_DFS
-// <bool name="DFS_USING_WORKDIR" description="Using working directory" default="true" />
#define DFS_USING_WORKDIR
-// <integer name="DFS_FILESYSTEMS_MAX" description="The maximal number of mounted file system" default="4" />
-#define DFS_FILESYSTEMS_MAX 4
-// <integer name="DFS_FD_MAX" description="The maximal number of opened files" default="4" />
-#define DFS_FD_MAX 8
-// <bool name="RT_USING_DFS_ELMFAT" description="Using ELM FatFs" default="true" />
+#define DFS_FILESYSTEMS_MAX 4
+#define DFS_FD_MAX 4
#define RT_USING_DFS_ELMFAT
-// <integer name="RT_DFS_ELM_DRIVES" description="The maximal number of drives of FatFs" default="4" />
-#define RT_DFS_ELM_DRIVES 4
-// <bool name="RT_DFS_ELM_REENTRANT" description="Support reentrant" default="true" />
+/* 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
-// <integer name="RT_DFS_ELM_USE_LFN" description="Support long file name" default="0">
-// <item description="Disable LFN feature. _MAX_LFN and _LFN_UNICODE have no effect">0</item>
-// <item description="Enable LFN with static working buffer on the BSS. Always NOT reentrant">1</item>
-// <item description="Enable LFN with dynamic working buffer on the STACK">2</item>
-// <item description="Enable LFN with dynamic working buffer on the HEAP">3</item>
-#define RT_DFS_ELM_USE_LFN 3
-// <integer name="RT_DFS_ELM_CODE_PAGE" description="OEM code page" default="936">
-#define RT_DFS_ELM_CODE_PAGE 437
-// <integer name="RT_DFS_ELM_MAX_LFN" description="Maximal size of file name length" default="255" />
-#define RT_DFS_ELM_MAX_LFN 255
-// <bool name="RT_USING_DFS_YAFFS2" description="Using YAFFS2" default="false" />
-// #define RT_USING_DFS_YAFFS2
-// <bool name="RT_USING_DFS_UFFS" description="Using UFFS" default="false" />
-// #define RT_USING_DFS_UFFS
-// <bool name="RT_USING_DFS_DEVFS" description="Using devfs for device objects" default="true" />
#define RT_USING_DFS_DEVFS
-// <bool name="RT_USING_DFS_NFS" description="Using NFS v3 client file system" default="false" />
-// #define RT_USING_DFS_NFS
-// <string name="RT_NFS_HOST_EXPORT" description="NFSv3 host export" default="192.168.1.5:/" />
-#define RT_NFS_HOST_EXPORT "192.168.1.5:/"
-// <bool name="RT_USING_DFS_LWIP" description="Enable lwIP socket operators in file system" default="true" />
-// #define RT_USING_DFS_LWIP
-// <section name="RT_USING_LWIP" description="lwip, a lightweight TCP/IP protocol stack" default="true" >
-// #define RT_USING_LWIP
-// <integer name="RT_LWIP_PBUF_POOL_BUFSIZE" description="the buffer size of pbuf pool" default="1500" />
-#define RT_LWIP_PBUF_POOL_BUFSIZE (1536)
-// <bool name="RT_LWIP_ICMP" description="Enable ICMP protocol" default="true" />
-#define RT_LWIP_ICMP
-// <bool name="RT_LWIP_IGMP" description="Enable IGMP protocol" default="false" />
-// #define RT_LWIP_IGMP
-// <bool name="RT_LWIP_UDP" description="Enable UDP protocol" default="true" />
-#define RT_LWIP_UDP
-// <bool name="RT_LWIP_TCP" description="Enable TCP protocol" default="true" />
-#define RT_LWIP_TCP
-// <bool name="RT_LWIP_DNS" description="Enable DNS protocol" default="true" />
-#define RT_LWIP_DNS
-// <integer name="RT_LWIP_TCP_PCB_NUM" description="Maximal number of simultaneously active TCP connections" default="5" />
-#define RT_LWIP_TCP_PCB_NUM 8
-// <integer name="RT_LWIP_TCP_SND_BUF" description="TCP sender buffer size" default="8192" />
-#define RT_LWIP_TCP_SND_BUF 8192
-// <integer name="RT_LWIP_TCP_WND" description="TCP receive window" default="8192" />
-#define RT_LWIP_TCP_WND 8192
-// <bool name="RT_LWIP_SNMP" description="Enable SNMP protocol" default="false" />
-// #define RT_LWIP_SNMP
-// <bool name="RT_LWIP_DHCP" description="Enable DHCP client to get IP address" default="false" />
-#define RT_LWIP_DHCP
-// <integer name="RT_LWIP_TCPTHREAD_PRIORITY" description="the thread priority of TCP thread" default="128" />
-#define RT_LWIP_TCPTHREAD_PRIORITY 12
-// <integer name="RT_LWIP_TCPTHREAD_MBOX_SIZE" description="the mail box size of TCP thread to wait for" default="32" />
-#define RT_LWIP_TCPTHREAD_MBOX_SIZE 8
-// <integer name="RT_LWIP_TCPTHREAD_STACKSIZE" description="the thread stack size of TCP thread" default="4096" />
-#define RT_LWIP_TCPTHREAD_STACKSIZE 4096
-// <integer name="RT_LWIP_ETHTHREAD_PRIORITY" description="the thread priority of ethnetif thread" default="144" />
-#define RT_LWIP_ETHTHREAD_PRIORITY 14
-// <integer name="RT_LWIP_ETHTHREAD_MBOX_SIZE" description="the mail box size of ethnetif thread to wait for" default="8" />
-#define RT_LWIP_ETHTHREAD_MBOX_SIZE 8
-// <integer name="RT_LWIP_ETHTHREAD_STACKSIZE" description="the stack size of ethnetif thread" default="512" />
-#define RT_LWIP_ETHTHREAD_STACKSIZE 512
-// <ipaddr name="RT_LWIP_IPADDR" description="IP address of device" default="192.168.1.30" />
-#define RT_LWIP_IPADDR0 192
-#define RT_LWIP_IPADDR1 168
-#define RT_LWIP_IPADDR2 10
-#define RT_LWIP_IPADDR3 222
-// <ipaddr name="RT_LWIP_GWADDR" description="Gateway address of device" default="192.168.1.1" />
-#define RT_LWIP_GWADDR0 192
-#define RT_LWIP_GWADDR1 168
-#define RT_LWIP_GWADDR2 10
-#define RT_LWIP_GWADDR3 1
-// <ipaddr name="RT_LWIP_MSKADDR" description="Mask address of device" default="255.255.255.0" />
-#define RT_LWIP_MSKADDR0 255
-#define RT_LWIP_MSKADDR1 255
-#define RT_LWIP_MSKADDR2 255
-#define RT_LWIP_MSKADDR3 0
-// </RDTConfigurator>
+/* 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