diff --git a/bsp/x1000/README.md b/bsp/x1000/README.md new file mode 100644 index 0000000000000000000000000000000000000000..4a0af7c70ae83458b6f2fca86da704153927e193 --- /dev/null +++ b/bsp/x1000/README.md @@ -0,0 +1 @@ +# RT-Thread for Ingenic X1000 porting. \ No newline at end of file diff --git a/bsp/x1000/SConscript b/bsp/x1000/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..c7ef7659ecea92b1dd9b71a97736a8552ee02551 --- /dev/null +++ b/bsp/x1000/SConscript @@ -0,0 +1,14 @@ +# for module compiling +import os +from building import * + +cwd = GetCurrentDir() +objs = [] +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) + +Return('objs') diff --git a/bsp/x1000/SConstruct b/bsp/x1000/SConstruct new file mode 100644 index 0000000000000000000000000000000000000000..8e8017bc29da35c6d283818717fe3f128cbb68b1 --- /dev/null +++ b/bsp/x1000/SConstruct @@ -0,0 +1,26 @@ +import os +import sys +import rtconfig +from rtconfig import RTT_ROOT + +sys.path = sys.path + [os.path.join(RTT_ROOT, 'tools')] +from building import * + +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, + AR = rtconfig.AR, ARFLAGS = '-rc', + LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS) +env.PrependENVPath('PATH', rtconfig.EXEC_PATH) + +Export('RTT_ROOT') +Export('rtconfig') + +# prepare building environment +objs = PrepareBuilding(env, RTT_ROOT) + +# make a building +DoBuilding(TARGET, objs) diff --git a/bsp/x1000/applications/SConscript b/bsp/x1000/applications/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..21a891dcb0f55760c1167b10187a13bc757f8cd1 --- /dev/null +++ b/bsp/x1000/applications/SConscript @@ -0,0 +1,13 @@ +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') + +CPPPATH = [cwd, str(Dir('#'))] + +if not GetDepend("RT_USING_DFS_ROMFS"): + SrcRemove(src, "romfs.c") + +group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/x1000/applications/main.c b/bsp/x1000/applications/main.c new file mode 100644 index 0000000000000000000000000000000000000000..0ec71c9329244900dbf06bdf6a5ebb33e0ff0568 --- /dev/null +++ b/bsp/x1000/applications/main.c @@ -0,0 +1,32 @@ +/* + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ +#include +#include + +int main(int argc, char** argv) +{ + printf("Hello RT-Thread!\n"); + + return 0; +} diff --git a/bsp/x1000/applications/mnt.c b/bsp/x1000/applications/mnt.c new file mode 100644 index 0000000000000000000000000000000000000000..4e09a6e2a02e0d48407975928c432ca993827e8b --- /dev/null +++ b/bsp/x1000/applications/mnt.c @@ -0,0 +1,50 @@ +/* + * File : mnt.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ + +#include +#include + +#include + +int mnt_init(void) +{ +#ifdef RT_USING_SDIO + rt_mmcsd_core_init(); + rt_mmcsd_blk_init(); + + jz47xx_sdio_init(); + rt_thread_delay(RT_TICK_PER_SECOND * 1); + + /* mount sd card fat partition 1 as root directory */ + if (dfs_mount("sd0", "/", "elm", 0, 0) == 0) + { + rt_kprintf("File System initialized!\n"); + } + else + { + rt_kprintf("File System initialzation failed!\n"); + } +#endif +} +INIT_ENV_EXPORT(mnt_init); diff --git a/bsp/x1000/driver/SConscript b/bsp/x1000/driver/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..50a6894b75776c33d7343d4094ae85bc81082510 --- /dev/null +++ b/bsp/x1000/driver/SConscript @@ -0,0 +1,11 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd, str(Dir('#'))] + +group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/x1000/driver/board.c b/bsp/x1000/driver/board.c new file mode 100644 index 0000000000000000000000000000000000000000..1dc2a427f39400b9c8d3f31fb26bfe5c30208c50 --- /dev/null +++ b/bsp/x1000/driver/board.c @@ -0,0 +1,56 @@ +/* + * File : board.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ + +#include +#include + +#include "board.h" +#include "drv_clock.h" +#include "drv_uart.h" +#include "drv_ost.h" + +extern void rt_hw_cache_init(void); + +void rt_hw_board_init(void) +{ + rt_hw_cache_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); +#endif /* RT_USING_CONSOLE */ + +#ifdef RT_USING_HEAP + /* init memory system */ + rt_system_heap_init(RT_HW_HEAP_BEGIN, RT_HW_HEAP_END); +#endif + +#ifdef RT_USING_COMPONENTS_INIT + rt_components_board_init(); +#endif + + rt_hw_ost_init(); +} diff --git a/bsp/x1000/driver/board.h b/bsp/x1000/driver/board.h new file mode 100644 index 0000000000000000000000000000000000000000..c92937eedc2d481dc5f4a7bdb5c982d4b6062bba --- /dev/null +++ b/bsp/x1000/driver/board.h @@ -0,0 +1,63 @@ +/* + * File : board.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ + +#ifndef _BOARD_H_ +#define _BOARD_H_ + +#include + +#include "x1000.h" + +#define RT_USING_JZ_X1000 + +// #define BOARD_PHOENIX +// #define BOARD_CANNA + +#ifdef BOARD_PHOENIX +#define RT_USING_EMAC +#endif + +/********************************************************************************************************* +** Clock for Board +*********************************************************************************************************/ +#define BOARD_EXTAL_CLK 24000000 +#define BOARD_RTC_CLK 32768 +#define BOARD_CPU_CLK (1008 * 1000 * 1000UL) + + +/********************************************************************************************************* +** HEAP Setting +*********************************************************************************************************/ +extern unsigned char __bss_start; +extern unsigned char __bss_end; + +#define RT_HW_HEAP_BEGIN (void*)&__bss_end +#define RT_HW_HEAP_END (void*)(0x80000000 + 32 * 1024 * 1024) + +/********************************************************************************************************* +** UART Setting +*********************************************************************************************************/ +#define RT_USING_UART2 + +#endif diff --git a/bsp/x1000/driver/board_io.c b/bsp/x1000/driver/board_io.c new file mode 100644 index 0000000000000000000000000000000000000000..2994fdd2b2f27ea8756c4dc4e2f7000ea7188d66 --- /dev/null +++ b/bsp/x1000/driver/board_io.c @@ -0,0 +1,27 @@ +/* + * File : board_io.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ +#include +#include + +#include "drv_gpio.h" diff --git a/bsp/x1000/driver/drv_clock.c b/bsp/x1000/driver/drv_clock.c new file mode 100644 index 0000000000000000000000000000000000000000..a3110b1be49ef376007af852c251ca8b42e784de --- /dev/null +++ b/bsp/x1000/driver/drv_clock.c @@ -0,0 +1,1463 @@ +/* + * File : drv_clock.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ + +#include +#include +#include + +#include + +#include "board.h" +#include "drv_clock.h" + +#define DEBUG 0 +#if DEBUG +#define PRINT(...) rt_kprintf(__VA_ARGS__) +#else +#define PRINT(...) +#endif +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +enum { + CLK_ID_EXT = 0, + CLK_ID_EXT0, +#define CLK_NAME_EXT0 "ext0" + CLK_ID_EXT1, +#define CLK_NAME_EXT1 "ext1" + CLK_ID_OTGPHY, +#define CLK_NAME_OTGPHY "otg_phy" + + CLK_ID_PLL, + CLK_ID_APLL, +#define CLK_NAME_APLL "apll" + CLK_ID_MPLL, +#define CLK_NAME_MPLL "mpll" + CLK_ID_SCLKA, +#define CLK_NAME_SCLKA "sclka" +/**********************************************************************************/ + CLK_ID_CPPCR, + CLK_ID_CCLK, +#define CLK_NAME_CCLK "cclk" + CLK_ID_L2CLK, +#define CLK_NAME_L2CLK "l2clk" + CLK_ID_H0CLK, +#define CLK_NAME_H0CLK "h0clk" + CLK_ID_H2CLK, +#define CLK_NAME_H2CLK "h2clk" + CLK_ID_PCLK, +#define CLK_NAME_PCLK "pclk" + CLK_ID_MSC, +#define CLK_NAME_MSC "msc" +/**********************************************************************************/ +/**********************************************************************************/ + CLK_ID_CGU, + CLK_ID_CGU_PCM1, +#define CLK_NAME_CGU_PCM1 "cgu_pcm1" + CLK_ID_CGU_PCM, +#define CLK_NAME_CGU_PCM "cgu_pcm" + CLK_ID_CGU_CIM, +#define CLK_NAME_CGU_CIM "cgu_cim" + CLK_ID_CGU_SFC, +#define CLK_NAME_CGU_SFC "cgu_ssi" + CLK_ID_CGU_MSC_MUX, +#define CLK_NAME_CGU_MSC_MUX "cgu_msc_mux" + CLK_ID_CGU_USB, +#define CLK_NAME_CGU_USB "cgu_usb" + CLK_ID_CGU_MSC1, +#define CLK_NAME_CGU_MSC1 "cgu_msc1" + CLK_ID_CGU_MSC0, +#define CLK_NAME_CGU_MSC0 "cgu_msc0" + CLK_ID_CGU_LCD, +#define CLK_NAME_CGU_LCD "cgu_lcd" + CLK_ID_CGU_I2S1, +#define CLK_NAME_CGU_I2S1 "cgu_i2s1" + CLK_ID_CGU_I2S, +#define CLK_NAME_CGU_I2S "cgu_i2s" + CLK_ID_CGU_MACPHY, +#define CLK_NAME_CGU_MACPHY "cgu_macphy" + CLK_ID_CGU_DDR, +#define CLK_NAME_CGU_DDR "cgu_ddr" + +/**********************************************************************************/ + CLK_ID_DEVICES, + CLK_ID_DDR, +#define CLK_NAME_DDR "ddr" + CLK_ID_CPU, +#define CLK_NAME_CPU "cpu" + CLK_ID_AHB0, +#define CLK_NAME_AHB0 "ahb0" + CLK_ID_APB0, +#define CLK_NAME_APB0 "apb0" + CLK_ID_RTC, +#define CLK_NAME_RTC "rtc" + CLK_ID_PCM, +#define CLK_NAME_PCM "pcm" + CLK_ID_MAC, +#define CLK_NAME_MAC "mac" + CLK_ID_AES, +#define CLK_NAME_AES "aes" + CLK_ID_LCD, +#define CLK_NAME_LCD "lcd" + CLK_ID_CIM, +#define CLK_NAME_CIM "cim" + CLK_ID_PDMA, +#define CLK_NAME_PDMA "pdma" + CLK_ID_SYS_OST, +#define CLK_NAME_SYS_OST "sys_ost" + CLK_ID_SSI, +#define CLK_NAME_SSI "ssi0" + CLK_ID_TCU, +#define CLK_NAME_TCU "tcu" + CLK_ID_DMIC, +#define CLK_NAME_DMIC "dmic" + CLK_ID_UART2, +#define CLK_NAME_UART2 "uart2" + CLK_ID_UART1, +#define CLK_NAME_UART1 "uart1" + CLK_ID_UART0, +#define CLK_NAME_UART0 "uart0" + CLK_ID_SADC, +#define CLK_NAME_SADC "sadc" + CLK_ID_VPU, +#define CLK_NAME_VPU "vpu" + CLK_ID_AIC, +#define CLK_NAME_AIC "aic" + CLK_ID_I2C3, +#define CLK_NAME_I2C3 "i2c3" + CLK_ID_I2C2, +#define CLK_NAME_I2C2 "i2c2" + CLK_ID_I2C1, +#define CLK_NAME_I2C1 "i2c1" + CLK_ID_I2C0, +#define CLK_NAME_I2C0 "i2c0" + CLK_ID_SCC, +#define CLK_NAME_SCC "scc" + CLK_ID_MSC1, +#define CLK_NAME_MSC1 "msc1" + CLK_ID_MSC0, +#define CLK_NAME_MSC0 "msc0" + CLK_ID_OTG, +#define CLK_NAME_OTG "otg1" + CLK_ID_SFC, +#define CLK_NAME_SFC "sfc" + CLK_ID_EFUSE, +#define CLK_NAME_EFUSE "efuse" + CLK_ID_NEMC, +#define CLK_NAME_NEMC "nemc" + + CLK_ID_STOP, + CLK_ID_INVALID, +}; + +enum { + CGU_PCM1,CGU_CIM,CGU_SFC, + CGU_USB,CGU_MSC1,CGU_MSC0,CGU_LCD, + CGU_MACPHY,CGU_DDR, + CGU_MSC_MUX +}; + +enum { + CDIV = 0,L2CDIV,H0DIV,H2DIV,PDIV,SCLKA, +}; + +enum { + CGU_AUDIO_I2S,CGU_AUDIO_I2S1,CGU_AUDIO_PCM,CGU_AUDIO_PCM1 +}; + +/* + * 31 ... 24 GATE_ID or CPCCR_ID or CGU_ID or PLL_ID or CGU_ID. + * 23 ... 16 PARENR_ID or RELATIVE_ID. + * 16 ... 0 some FLG. + */ + +static struct clk clk_srcs[] = { +#define GATE(x) (((x)<<24) | CLK_FLG_GATE) +#define CPCCR(x) (((x)<<24) | CLK_FLG_CPCCR) +#define CGU(no) (((no)<<24) | CLK_FLG_CGU) +#define CGU_AUDIO(no) (((no)<<24) | CLK_FLG_CGU_AUDIO) +#define PLL(no) (((no)<<24) | CLK_FLG_PLL) +#define PARENT(P) (((CLK_ID_##P)<<16) | CLK_FLG_PARENT) +#define RELATIVE(P) (((CLK_ID_##P)<<16) | CLK_FLG_RELATIVE) +#define DEF_CLK(N,FLAG) \ + [CLK_ID_##N] = { .name = CLK_NAME_##N, .flags = FLAG, } + + DEF_CLK(EXT0, CLK_FLG_NOALLOC), + DEF_CLK(EXT1, CLK_FLG_NOALLOC), + DEF_CLK(OTGPHY, CLK_FLG_NOALLOC), + + DEF_CLK(APLL, PLL(CPM_CPAPCR)), + DEF_CLK(MPLL, PLL(CPM_CPMPCR)), + + DEF_CLK(SCLKA, CPCCR(SCLKA)), + DEF_CLK(CCLK, CPCCR(CDIV)), + DEF_CLK(L2CLK, CPCCR(L2CDIV)), + DEF_CLK(H0CLK, CPCCR(H0DIV)), + DEF_CLK(H2CLK, CPCCR(H2DIV)), + DEF_CLK(PCLK, CPCCR(PDIV)), + + DEF_CLK(NEMC, GATE(0) | PARENT(H2CLK)), + DEF_CLK(EFUSE, GATE(1) | PARENT(H2CLK)), + DEF_CLK(SFC, GATE(2) | PARENT(CGU_SFC)), + DEF_CLK(OTG, GATE(3)), + DEF_CLK(MSC0, GATE(4) | PARENT(PCLK)), + DEF_CLK(MSC1, GATE(5) | PARENT(PCLK)), + DEF_CLK(SCC, GATE(6) | PARENT(PCLK)), + DEF_CLK(I2C0, GATE(7) | PARENT(PCLK)), + DEF_CLK(I2C1, GATE(8) | PARENT(PCLK)), + DEF_CLK(I2C2, GATE(9) | PARENT(PCLK)), + DEF_CLK(I2C3, GATE(10) | PARENT(PCLK)), + DEF_CLK(AIC, GATE(11)), + DEF_CLK(VPU, GATE(12) | PARENT(LCD)), + DEF_CLK(SADC, GATE(13)), + DEF_CLK(UART0, GATE(14) | PARENT(EXT1)), + DEF_CLK(UART1, GATE(15) | PARENT(EXT1)), + DEF_CLK(UART2, GATE(16) | PARENT(EXT1)), + DEF_CLK(DMIC, GATE(17)), + DEF_CLK(TCU, GATE(18)), + DEF_CLK(SSI, GATE(19)), + DEF_CLK(SYS_OST, GATE(20)), + DEF_CLK(PDMA, GATE(21)), + DEF_CLK(CIM, GATE(22) | PARENT(LCD)), + DEF_CLK(LCD, GATE(23)), + DEF_CLK(AES, GATE(24)), + DEF_CLK(MAC, GATE(25)), + DEF_CLK(PCM, GATE(26)), + DEF_CLK(RTC, GATE(27)), + DEF_CLK(APB0, GATE(28)), + DEF_CLK(AHB0, GATE(29)), + DEF_CLK(CPU, GATE(30)), + DEF_CLK(DDR, GATE(31)), + + DEF_CLK(CGU_MSC_MUX, CGU(CGU_MSC_MUX)), + DEF_CLK(CGU_PCM, CGU_AUDIO(CGU_AUDIO_PCM)), + DEF_CLK(CGU_CIM, CGU(CGU_CIM)), + DEF_CLK(CGU_SFC, CGU(CGU_SFC)), + DEF_CLK(CGU_USB, CGU(CGU_USB)), + DEF_CLK(CGU_MSC1, CGU(CGU_MSC1)| PARENT(CGU_MSC_MUX)), + DEF_CLK(CGU_MSC0, CGU(CGU_MSC0)| PARENT(CGU_MSC_MUX)), + DEF_CLK(CGU_LCD, CGU(CGU_LCD)), + DEF_CLK(CGU_I2S, CGU_AUDIO(CGU_AUDIO_I2S)), + DEF_CLK(CGU_MACPHY, CGU(CGU_MACPHY)), + DEF_CLK(CGU_DDR, CGU(CGU_DDR)), +#undef GATE +#undef CPCCR +#undef CGU +#undef CGU_AUDIO +#undef PARENT +#undef DEF_CLK +#undef RELATIVE +}; + +int get_clk_sources_size(void) +{ + return ARRAY_SIZE(clk_srcs); +} + +struct clk *get_clk_from_id(int clk_id) +{ + return &clk_srcs[clk_id]; +} + +int get_clk_id(struct clk *clk) +{ + return (clk - &clk_srcs[0]); +} + +/********************************************************************************************************* +** PLL +*********************************************************************************************************/ + +static uint32_t pll_get_rate(struct clk *clk) { + uint32_t offset; + uint32_t cpxpcr; + uint32_t m,n,od; + uint32_t rate; + + + if (clk->CLK_ID == CLK_ID_APLL) + offset = 8; + else if (clk->CLK_ID == CLK_ID_MPLL) + offset = 7; + else + offset = 0; + + cpxpcr = cpm_inl(CLK_PLL_NO(clk->flags)); + if(cpxpcr >> offset & 1) + { + clk->flags |= CLK_FLG_ENABLE; + m = ((cpxpcr >> 24) & 0x7f) + 1; + n = ((cpxpcr >> 18) & 0x1f) + 1; + od = ((cpxpcr >> 16) & 0x3); + od = 1 << od; + rate = clk->parent->rate * m / n / od; + } + else + { + clk->flags &= ~(CLK_FLG_ENABLE); + rate = 0; + } + return rate; +} + +static struct clk_ops clk_pll_ops = { + .get_rate = pll_get_rate, + .set_rate = RT_NULL, +}; + +void init_ext_pll(struct clk *clk) +{ + switch (get_clk_id(clk)) + { + case CLK_ID_EXT0: + clk->rate = BOARD_RTC_CLK; + clk->flags |= CLK_FLG_ENABLE; + break; + case CLK_ID_EXT1: + clk->rate = BOARD_EXTAL_CLK; + clk->flags |= CLK_FLG_ENABLE; + break; + case CLK_ID_OTGPHY: + clk->rate = 48 * 1000 * 1000; + clk->flags |= CLK_FLG_ENABLE; + break; + default: + clk->parent = get_clk_from_id(CLK_ID_EXT1); + clk->rate = pll_get_rate(clk); + clk->ops = &clk_pll_ops; + break; + } +} + +/********************************************************************************************************* +** CPCCR +*********************************************************************************************************/ +struct cpccr_clk +{ + uint16_t off,sel,ce; +}; +static struct cpccr_clk cpccr_clks[] = +{ +#define CPCCR_CLK(N,O,D,E) \ + [N] = { .off = O, .sel = D, .ce = E} + CPCCR_CLK(CDIV, 0, 28,22), + CPCCR_CLK(L2CDIV, 4, 28,22), + CPCCR_CLK(H0DIV, 8, 26,21), + CPCCR_CLK(H2DIV, 12, 24,20), + CPCCR_CLK(PDIV, 16, 24,20), + CPCCR_CLK(SCLKA,-1, -1,30), +#undef CPCCR_CLK +}; + + +static uint32_t cpccr_selector[4] = {0,CLK_ID_SCLKA,CLK_ID_MPLL,0}; + +static uint32_t cpccr_get_rate(struct clk *clk) +{ + int sel; + uint32_t cpccr = cpm_inl(CPM_CPCCR); + uint32_t rate; + int v; + if (CLK_CPCCR_NO(clk->flags) == SCLKA) + { + int clka_sel[4] = + { + 0, CLK_ID_EXT1, CLK_ID_APLL, 0 + }; + sel = cpm_inl(CPM_CPCCR) >> 30; + if (clka_sel[sel] == 0) + { + rate = 0; + clk->flags &= ~CLK_FLG_ENABLE; + } + else + { + clk->parent = get_clk_from_id(clka_sel[sel]); + rate = clk->parent->rate; + clk->flags |= CLK_FLG_ENABLE; + } + } + else + { + v = (cpccr >> cpccr_clks[CLK_CPCCR_NO(clk->flags)].off) & 0xf; + sel = (cpccr >> (cpccr_clks[CLK_CPCCR_NO(clk->flags)].sel)) & 0x3; + rate = get_clk_from_id(cpccr_selector[sel])->rate; + rate = rate / (v + 1); + } + return rate; +} +static struct clk_ops clk_cpccr_ops = +{ + .get_rate = cpccr_get_rate, + .set_rate = RT_NULL, +}; + +void init_cpccr_clk(struct clk *clk) +{ + int sel; //check + uint32_t cpccr = cpm_inl(CPM_CPCCR); + if (CLK_CPCCR_NO(clk->flags) != SCLKA) + { + sel = (cpccr >> cpccr_clks[CLK_CPCCR_NO(clk->flags)].sel) & 0x3; + if (cpccr_selector[sel] != 0) + { + clk->parent = get_clk_from_id(cpccr_selector[sel]); + clk->flags |= CLK_FLG_ENABLE; + } + else + { + clk->parent = RT_NULL; + clk->flags &= ~CLK_FLG_ENABLE; + } + } + clk->rate = cpccr_get_rate(clk); + clk->ops = &clk_cpccr_ops; +} + +/********************************************************************************************************* +** CGU & CGU Aduio +*********************************************************************************************************/ +struct clk_selectors +{ + uint16_t route[4]; +}; + +enum { + SELECTOR_A = 0, + SELECTOR_2, + SELECTOR_C, + SELECTOR_3, + SELECTOR_MSC_MUX, + SELECTOR_F, + SELECTOR_G, +}; + +const struct clk_selectors selector[] = { +#define CLK(X) CLK_ID_##X +/* + * bit31,bit30 + * 0 , 0 STOP + * 0 , 1 SCLKA + * 1 , 0 MPLL + * 1 , 1 INVALID + */ + [SELECTOR_A].route = {CLK(STOP),CLK(SCLKA),CLK(MPLL),CLK(INVALID)}, +/* + * bit31,bit30 + * 0 , x SCLKA + * 0 , x SCLKA + * 1 , x MPLL + * 1 , x MPLL + */ + [SELECTOR_2].route = {CLK(SCLKA),CLK(SCLKA),CLK(MPLL),CLK(MPLL)}, +/* + * bit31,bit30 + * 0 , 0 EXT1 + * 0 , 1 EXT1 + * 1 , 0 SCLKA + * 1 , 1 MPLL + */ + [SELECTOR_C].route = {CLK(EXT1) ,CLK(EXT1),CLK(SCLKA),CLK(MPLL)}, +/* + * bit31,bit30 + * 0 , 0 SCLKA + * 0 , 1 MPLL + * 1 , 0 EXT1 + * 1 , 1 INVALID + */ + [SELECTOR_3].route = {CLK(SCLKA),CLK(MPLL),CLK(EXT1),CLK(INVALID)}, + +/* + * bit31,bit30 + * 0 , 0 MSC_MUX + * 0 , 1 MSC_MUX + * 1 , 0 MSC_MUX + * 1 , 1 MSC_MUX + */ + [SELECTOR_MSC_MUX].route = {CLK(SCLKA),CLK(SCLKA),CLK(MPLL),CLK(MPLL)}, +/* + * bit31,bit30 + * 0 , 0 SCLKA + * 0 , 1 MPLL + * 1 , 0 OTGPHY + * 1 , 1 INVALID + */ + [SELECTOR_F].route = {CLK(SCLKA),CLK(MPLL),CLK(OTGPHY),CLK(INVALID)}, +/* + * bit31,bit30 + * 0 , 0 SCLKA + * 0 , 1 EXT1 + * 1 , 0 MPLL + * 1 , 1 INVALID + */ + [SELECTOR_G].route = {CLK(SCLKA),CLK(EXT1),CLK(MPLL),CLK(INVALID)}, + +#undef CLK +}; + + +struct cgu_clk +{ + /* off: reg offset. ce_busy_stop: CE offset + 1 is busy. coe : coe for div .div: div bit width */ + /* ext: extal/pll sel bit. sels: {select} */ + int off,ce_busy_stop,coe,div,sel,cache; +}; +static struct cgu_clk cgu_clks[] = { + [CGU_DDR] = { CPM_DDRCDR, 27, 1, 4, SELECTOR_A}, + [CGU_MACPHY] = { CPM_MACCDR, 27, 1, 8, SELECTOR_2}, + [CGU_LCD] = { CPM_LPCDR, 26, 1, 8, SELECTOR_2}, + [CGU_MSC_MUX]= { CPM_MSC0CDR, 27, 2, 0, SELECTOR_MSC_MUX}, + [CGU_MSC0] = { CPM_MSC0CDR, 27, 2, 8, SELECTOR_MSC_MUX}, + [CGU_MSC1] = { CPM_MSC1CDR, 27, 2, 8, SELECTOR_MSC_MUX}, + [CGU_USB] = { CPM_USBCDR, 27, 1, 8, SELECTOR_C}, + [CGU_SFC] = { CPM_SFCCDR, 27, 1, 8, SELECTOR_G}, + [CGU_CIM] = { CPM_CIMCDR, 27, 1, 8, SELECTOR_2}, +}; + + +static uint32_t cgu_get_rate(struct clk *clk) +{ + uint32_t x; + + int no = CLK_CGU_NO(clk->flags); + + if (clk->parent == get_clk_from_id(CLK_ID_EXT1)) + return clk->parent->rate; + + if (no == CGU_MSC_MUX) + return clk->parent->rate; + + if (cgu_clks[no].div == 0) + return clk_get_rate(clk->parent); + + x = cpm_inl(cgu_clks[no].off); + x &= (1 << cgu_clks[no].div) - 1; + x = (x + 1) * cgu_clks[no].coe; + + return clk->parent->rate / x; +} + +static int cgu_enable(struct clk *clk,int on) +{ + int no = CLK_CGU_NO(clk->flags); + int reg_val; + int ce, stop, busy; + int prev_on; + + uint32_t mask; + + + if (no == CGU_MSC_MUX) + return 0; + + reg_val = cpm_inl(cgu_clks[no].off); + stop = cgu_clks[no].ce_busy_stop; + busy = stop + 1; + ce = stop + 2; + prev_on = !(reg_val & (1 << stop)); + mask = (1 << cgu_clks[no].div) - 1; + + if (prev_on && on) + goto cgu_enable_finish; + + if ((!prev_on) && (!on)) + goto cgu_enable_finish; + + if (no == CGU_USB) + { + // usb phy clock enable + if (on) + reg_val &= ~(1 << 26); + else + reg_val |= (1 << 26); + } + + if (on) + { + if (cgu_clks[no].cache && ((cgu_clks[no].cache & mask) != (reg_val & mask))) + { + int x = cgu_clks[no].cache; + x = (x & ~(0x1 << stop)) | (0x1 << ce); + + cpm_outl(x, cgu_clks[no].off); + while (cpm_test_bit(busy, cgu_clks[no].off)) + { + PRINT("wait stable.[%d][%s]\n", __LINE__, clk->name); + } + + cpm_clear_bit(ce, cgu_clks[no].off); + x &= (1 << cgu_clks[no].div) - 1; + x = (x + 1) * cgu_clks[no].coe; + clk->rate = clk->parent->rate / x; + cgu_clks[no].cache = 0; + } + else + { + reg_val |= (1 << ce); + reg_val &= ~(1 << stop); + cpm_outl(reg_val, cgu_clks[no].off); + cpm_clear_bit(ce, cgu_clks[no].off); + } + } + else + { + reg_val |= (1 << ce); + reg_val |= (1 << stop); + cpm_outl(reg_val, cgu_clks[no].off); + cpm_clear_bit(ce, cgu_clks[no].off); + } + +cgu_enable_finish: + + return 0; +} + +static int cgu_set_rate(struct clk *clk, uint32_t rate) +{ + uint32_t x,tmp; + int i,no = CLK_CGU_NO(clk->flags); + int ce,stop,busy; + uint32_t reg_val,mask; + + + /* CLK_ID_CGU_I2S could be exten clk. */ + if(no == CGU_MSC_MUX) + return -1; + + mask = (1 << cgu_clks[no].div) - 1; + tmp = clk->parent->rate / cgu_clks[no].coe; + + for (i = 1; i <= mask + 1; i++) + { + if ((tmp / i) <= rate) + break; + } + i--; + if (i > mask) + i = mask; + reg_val = cpm_inl(cgu_clks[no].off); + x = reg_val & ~mask; + x |= i; + stop = cgu_clks[no].ce_busy_stop; + busy = stop + 1; + ce = stop + 2; + if (x & (1 << stop)) + { + cgu_clks[no].cache = x; + clk->rate = tmp / (i + 1); + } + else if ((mask & reg_val) != i) + { + + x = (x & ~(0x1 << stop)) | (0x1 << ce); + cpm_outl(x, cgu_clks[no].off); + while (cpm_test_bit(busy, cgu_clks[no].off)) + PRINT("wait stable.[%d][%s]\n", __LINE__, clk->name); + x &= ~(1 << ce); + cpm_outl(x, cgu_clks[no].off); + cgu_clks[no].cache = 0; + clk->rate = tmp / (i + 1); + } + + return 0; +} + +static struct clk* cgu_get_parent(struct clk *clk) +{ + uint32_t no,cgu,idx,pidx; + + no = CLK_CGU_NO(clk->flags); + cgu = cpm_inl(cgu_clks[no].off); + idx = cgu >> 30; + pidx = selector[cgu_clks[no].sel].route[idx]; + if (pidx == CLK_ID_STOP || pidx == CLK_ID_INVALID) + return RT_NULL; + + return get_clk_from_id(pidx); +} + +static int cgu_set_parent(struct clk *clk, struct clk *parent) +{ + int i,tmp; + int no = CLK_CGU_NO(clk->flags); + int ce,stop,busy; + + uint32_t reg_val,cgu,mask; + + stop = cgu_clks[no].ce_busy_stop; + busy = stop + 1; + ce = stop + 2; + mask = (1 << cgu_clks[no].div) - 1; + for(i = 0;i < 4;i++) { + if(selector[cgu_clks[no].sel].route[i] == get_clk_id(parent)){ + break; + } + } + if(i >= 4) + return -1; + cgu = cpm_inl(cgu_clks[no].off); + reg_val = cgu; + if (cgu_clks[no].sel == SELECTOR_2) + { + if (i == 0) + cgu &= ~(1 << 31); + else + cgu |= (1 << 31); + } + else + { + cgu &= ~(3 << 30); + cgu |= ~(i << 30); + } + + tmp = parent->rate / cgu_clks[no].coe; + for (i = 1; i <= mask + 1; i++) + { + if ((tmp / i) <= clk->rate) + break; + } + i--; + mask = (1 << cgu_clks[no].div) - 1; + cgu = (cgu & ~(0x1 << stop)) | (0x1 << ce); + cgu = cgu & ~mask; + cgu |= i; + + if (reg_val & (1 << stop)) + cgu_clks[no].cache = cgu; + else if ((mask & reg_val) != i) + { + cpm_outl(cgu, cgu_clks[no].off); + while (cpm_test_bit(busy, cgu_clks[no].off)) + PRINT("wait stable.[%d][%s]\n", __LINE__, clk->name); + cgu &= ~(1 << ce); + cpm_outl(cgu, cgu_clks[no].off); + cgu_clks[no].cache = 0; + } + return 0; +} + +static int cgu_is_enabled(struct clk *clk) +{ + int no = CLK_CGU_NO(clk->flags); + int stop; + stop = cgu_clks[no].ce_busy_stop; + return !(cpm_inl(cgu_clks[no].off) & (1 << stop)); +} + +static struct clk_ops clk_cgu_ops = +{ + .enable = cgu_enable, + .get_rate = cgu_get_rate, + .set_rate = cgu_set_rate, + .get_parent = cgu_get_parent, + .set_parent = cgu_set_parent, +}; + +void init_cgu_clk(struct clk *clk) +{ + int no; + int id; + + if (clk->flags & CLK_FLG_PARENT) + { + id = CLK_PARENT(clk->flags); + clk->parent = get_clk_from_id(id); + } + else + { + clk->parent = cgu_get_parent(clk); + } + no = CLK_CGU_NO(clk->flags); + cgu_clks[no].cache = 0; + clk->rate = cgu_get_rate(clk); + if (cgu_is_enabled(clk)) + { + clk->flags |= CLK_FLG_ENABLE; + } + if (no == CGU_MSC_MUX) + clk->ops = RT_NULL; + else if(no == CGU_DDR) + { +// if(ddr_readl(DDRP_PIR) & DDRP_PIR_DLLBYP) +// { +///** +// * DDR request cpm to stop clk (0x9 << 28) DDR_CLKSTP_CFG (0x13012068) +// * CPM response ddr stop clk request (1 << 26) (0x1000002c) +// */ +// cpm_set_bit(26,CPM_DDRCDR); +// REG32(0xb3012068) |= 0x9 << 28; +// } +// REG32(0xb3012088) |= 4 << 16; + } + else + clk->ops = &clk_cgu_ops; +} + +/********************************************************************************************************* +** CGU_AUDIO +*********************************************************************************************************/ +enum +{ + SELECTOR_AUDIO = 0, +}; + +const struct clk_selectors audio_selector[] = +{ +#define CLK(X) CLK_ID_##X +/* + * bit31,bit30 + * 0 , 0 EXT1 + * 0 , 1 APLL + * 1 , 0 EXT1 + * 1 , 1 MPLL + */ + [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]; + +struct cgu_audio_clk +{ + int off,en,maskm,bitm,maskn,bitn,maskd,bitd,sel,cache; +}; +static struct cgu_audio_clk cgu_audio_clks[] = +{ + [CGU_AUDIO_I2S] = { CPM_I2SCDR, 1<<29, 0x1f << 13, 13, 0x1fff, 0, SELECTOR_AUDIO}, + [CGU_AUDIO_I2S1] = { CPM_I2SCDR1, -1, -1, -1, -1, -1, -1}, + [CGU_AUDIO_PCM] = { CPM_PCMCDR, 1<<29, 0x1f << 13, 13, 0x1fff, 0, SELECTOR_AUDIO}, + [CGU_AUDIO_PCM1] = { CPM_PCMCDR1, -1, -1, -1, -1, -1, -1}, +}; + + +static uint32_t cgu_audio_get_rate(struct clk *clk) +{ + uint32_t m, n, d; + + int no = CLK_CGU_AUDIO_NO(clk->flags); + + if (clk->parent == get_clk_from_id(CLK_ID_EXT1)) + return clk->parent->rate; + + m = cpm_inl(cgu_audio_clks[no].off); + n = m & cgu_audio_clks[no].maskn; + m &= cgu_audio_clks[no].maskm; + + if (no == CGU_AUDIO_I2S) + { + d = readl(I2S_PRI_DIV); + return (clk->parent->rate * m) / (n * ((d & 0x3f) + 1) * (64)); + } + else if (no == CGU_AUDIO_PCM) + { + d = readl(PCM_PRI_DIV); + return (clk->parent->rate * m) / (n * (((d & 0x1f << 6) >> 6) + 1) * 8); + } + return 0; +} +static int cgu_audio_enable(struct clk *clk, int on) +{ + int no = CLK_CGU_AUDIO_NO(clk->flags); + int reg_val; + + + if (on) + { + reg_val = cpm_inl(cgu_audio_clks[no].off); + if (reg_val & (cgu_audio_clks[no].en)) + goto cgu_enable_finish; + + if (!cgu_audio_clks[no].cache) + PRINT("must set rate before enable\n"); + + cpm_outl(cgu_audio_clks[no].cache, cgu_audio_clks[no].off); + cpm_outl(cgu_audio_clks[no].cache | cgu_audio_clks[no].en, cgu_audio_clks[no].off); + cgu_audio_clks[no].cache = 0; + } + else + { + reg_val = cpm_inl(cgu_audio_clks[no].off); + reg_val &= ~cgu_audio_clks[no].en; + cpm_outl(reg_val, cgu_audio_clks[no].off); + } +cgu_enable_finish: + return 0; +} + +static int get_div_val(int max1,int max2,int machval, int* res1, int* res2) +{ + int tmp1 = 0, tmp2 = 0; + for (tmp1 = 1; tmp1 < max1; tmp1++) + for (tmp2 = 1; tmp2 < max2; tmp2++) + if (tmp1 * tmp2 == machval) + break; + if (tmp1 * tmp2 != machval) + { + PRINT("can't find mach wal\n"); + return -1; + } + *res1 = tmp1; + *res2 = tmp2; + return 0; +} +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; + } + else if(pid == CLK_ID_SCLKA) + audio_div = (int*)audio_div_apll; + else + return 0; + + for (i = 0; i < 50; i += 3) + { + if (audio_div[i] == rate) + break; + } + if(i >= 50) + { + PRINT("cgu aduio set rate err!\n"); + return -1; + } + else{ + m = audio_div[i+1]; + if(no == CGU_AUDIO_I2S) + { +#ifdef CONFIG_SND_ASOC_JZ_AIC_SPDIF_V13 + m*=2; +#endif + d_max = 0x1ff; + tmp_val = audio_div[i+2]/64; + if (tmp_val > n_max) + { + if (get_div_val(n_max, d_max, tmp_val, &n, &d)) + goto calculate_err; + } + else + { + n = tmp_val; + d = 1; + } + tmp_val = cpm_inl(cgu_audio_clks[no].off)&(~(cgu_audio_clks[no].maskm|cgu_audio_clks[no].maskn)); + tmp_val |= (m< n_max) + { + if (get_div_val(n_max, d_max, tmp_val, &n, &d)) + goto calculate_err; + if (d > 0x3f) + { + tmp_val = d; + d_max = 0x3f, sync_max = 0x1f; + if (get_div_val(d_max, sync_max, tmp_val, &d, &sync)) + goto calculate_err; + } + else + { + sync = 1; + } + } + else + { + n = tmp_val; + d = 1; + sync = 1; + } + tmp_val = cpm_inl(cgu_audio_clks[no].off)&(~(cgu_audio_clks[no].maskm|cgu_audio_clks[no].maskn)); + tmp_val |= (m<rate = rate; + return 0; +calculate_err: + PRINT("audio div Calculate err!\n"); + return -1; +} + +static struct clk* cgu_audio_get_parent(struct clk *clk) +{ + uint32_t no,cgu,idx,pidx; + + struct clk* pclk; + + no = CLK_CGU_AUDIO_NO(clk->flags); + cgu = cpm_inl(cgu_audio_clks[no].off); + idx = cgu >> 30; + pidx = audio_selector[cgu_audio_clks[no].sel].route[idx]; + if (pidx == CLK_ID_STOP || pidx == CLK_ID_INVALID) + { + return RT_NULL; + } + pclk = get_clk_from_id(pidx); + + return pclk; +} + +static int cgu_audio_set_parent(struct clk *clk, struct clk *parent) +{ + int tmp_val,i; + int no = CLK_CGU_AUDIO_NO(clk->flags); + + for(i = 0;i < 4;i++) { + if(audio_selector[cgu_audio_clks[no].sel].route[i] == get_clk_id(parent)){ + break; + } + } + + if(i >= 4) + return -1; + + if (get_clk_id(parent) != CLK_ID_EXT1) + { + tmp_val = cpm_inl(cgu_audio_clks[no].off) & (~(3 << 30)); + tmp_val |= i << 30; + cpm_outl(tmp_val, cgu_audio_clks[no].off); + } + else + { + tmp_val = cpm_inl(cgu_audio_clks[no].off) & (~(3 << 30 | 0x3fffff)); + tmp_val |= i << 30 | 1 << 13 | 1; + cpm_outl(tmp_val, cgu_audio_clks[no].off); + } + + return 0; +} + +static int cgu_audio_set_rate(struct clk *clk, uint32_t rate) +{ + int tmp_val; + + int no = CLK_CGU_AUDIO_NO(clk->flags); + if (rate == 24000000) + { + cgu_audio_set_parent(clk, get_clk_from_id(CLK_ID_EXT1)); + clk->parent = get_clk_from_id(CLK_ID_EXT1); + clk->rate = rate; + tmp_val = cpm_inl(cgu_audio_clks[no].off); + tmp_val &= ~0x3fffff; + tmp_val |= 1<<13|1; + if(tmp_val&cgu_audio_clks[no].en) + cpm_outl(tmp_val,cgu_audio_clks[no].off); + else + cgu_audio_clks[no].cache = tmp_val; + return 0; + } + else + { + 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); + } + return 0; +} + + +static int cgu_audio_is_enabled(struct clk *clk) { + int no,state; + + no = CLK_CGU_AUDIO_NO(clk->flags); + state = (cpm_inl(cgu_audio_clks[no].off) & cgu_audio_clks[no].en); + return state; +} + +static struct clk_ops clk_cgu_audio_ops = +{ + .enable = cgu_audio_enable, + .get_rate = cgu_audio_get_rate, + .set_rate = cgu_audio_set_rate, + .get_parent = cgu_audio_get_parent, + .set_parent = cgu_audio_set_parent, +}; + +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); + clk->parent = get_clk_from_id(id); + } + else + { + clk->parent = cgu_audio_get_parent(clk); + } + no = CLK_CGU_AUDIO_NO(clk->flags); + cgu_audio_clks[no].cache = 0; + if (cgu_audio_is_enabled(clk)) + { + clk->flags |= CLK_FLG_ENABLE; + } + clk->rate = cgu_audio_get_rate(clk); + tmp_val = cpm_inl(cgu_audio_clks[no].off); + tmp_val &= ~0x3fffff; + tmp_val |= 1<<13|1; + if((tmp_val&cgu_audio_clks[no].en)&&(clk->rate == 24000000)) + cpm_outl(tmp_val,cgu_audio_clks[no].off); + else + cgu_audio_clks[no].cache = tmp_val; + + clk->ops = &clk_cgu_audio_ops; +} + +/********************************************************************************************************* +** GATE +*********************************************************************************************************/ +static int cpm_gate_enable(struct clk *clk,int on) +{ + int bit = CLK_GATE_BIT(clk->flags); + uint32_t clkgr[2] = {CPM_CLKGR}; + + if (on) + { + cpm_clear_bit(bit % 32, clkgr[bit / 32]); + } + else + { + cpm_set_bit(bit % 32, clkgr[bit / 32]); + } + + return 0; +} +static struct clk_ops clk_gate_ops = +{ + .enable = cpm_gate_enable, +}; + +void init_gate_clk(struct clk *clk) +{ + int id = 0; + static uint32_t clkgr[2]={0}; + static int clkgr_init = 0; + int bit = CLK_GATE_BIT(clk->flags); + + if (clkgr_init == 0) + { + clkgr[0] = cpm_inl(CPM_CLKGR); + clkgr_init = 1; + } + if (clk->flags & CLK_FLG_PARENT) + { + id = CLK_PARENT(clk->flags); + clk->parent = get_clk_from_id(id); + } + else + clk->parent = get_clk_from_id(CLK_ID_EXT1); + + clk->rate = clk_get_rate(clk->parent); + if (clkgr[bit / 32] & (1 << (bit % 32))) + { + clk->flags &= ~(CLK_FLG_ENABLE); + //cpm_gate_enable(clk,0); + } + else + { + clk->flags |= CLK_FLG_ENABLE; + //cpm_gate_enable(clk,1); + } + clk->ops = &clk_gate_ops; +} + +/********************************************************************************************************* +** CLK function +*********************************************************************************************************/ +static void init_clk_parent(struct clk *p) +{ + int init = 0; + if (!p) + return; + if (p->init_state) + { + p->count = 1; + p->init_state = 0; + init = 1; + } + if (p->count == 0) + { + PRINT("%s clk should be opened!\n", p->name); + p->count = 1; + } + if (!init) + p->count ++; +} + + +struct clk *clk_get(const char *id) +{ + int i; + struct clk *retval = RT_NULL; + struct clk *clk_srcs = get_clk_from_id(0); + struct clk *parent_clk = RT_NULL; + + for (i = 0; i < get_clk_sources_size(); i++) + { + if (id && clk_srcs[i].name && !rt_strcmp(id, clk_srcs[i].name)) + { + if (clk_srcs[i].flags & CLK_FLG_NOALLOC) + return &clk_srcs[i]; + retval = rt_malloc(sizeof(struct clk)); + if (!retval) + return (RT_NULL); + + rt_memcpy(retval, &clk_srcs[i], sizeof(struct clk)); + retval->flags = 0; + retval->source = &clk_srcs[i]; + if (CLK_FLG_RELATIVE & clk_srcs[i].flags) + { + parent_clk = get_clk_from_id(CLK_RELATIVE(clk_srcs[i].flags)); + parent_clk->child = RT_NULL; + } + retval->count = 0; + return retval; + } + } + return RT_NULL; +} + +int clk_enable(struct clk *clk) +{ + int count; + if (!clk) + return -RT_EIO; + /** + * if it has parent clk,first it will control itself,then it will control parent. + * if it hasn't parent clk,it will control itself. + */ + if(clk->source) + { + count = ++clk->count; + if (count != 1) + return 0; + + clk->flags |= CLK_FLG_ENABLE; + clk = clk->source; + if (clk->init_state) + { + clk->count = 1; + clk->init_state = 0; + return 0; + } + } + + count = ++clk->count; + if(count == 1) + { + if(clk->parent) + { + clk_enable(clk->parent); + } + + if(clk->ops && clk->ops->enable) + { + clk->ops->enable(clk,1); + } + clk->flags |= CLK_FLG_ENABLE; + } + return 0; +} + +int clk_is_enabled(struct clk *clk) +{ + /* if(clk->source) */ + /* clk = clk->source; */ + return !!(clk->flags & CLK_FLG_ENABLE); +} + +void clk_disable(struct clk *clk) +{ + int count; + if (!clk) + return; + /** + * if it has parent clk,first it will control itself,then it will control parent. + * if it hasn't parent clk,it will control itself. + */ + if (clk->source) + { + + count = --clk->count; + if (count != 0) + { + if (count < 0) + { + clk->count = 0; + PRINT("%s isn't enabled!\n", clk->name); + return; + } + } + + clk->flags &= ~CLK_FLG_ENABLE; + clk = clk->source; + } + + count = --clk->count; + if (count < 0) + { + clk->count++; + return; + } + + if(count == 0) + { + if(clk->ops && clk->ops->enable) + clk->ops->enable(clk,0); + clk->flags &= ~CLK_FLG_ENABLE; + if(clk->parent) + clk_disable(clk->parent); + } +} + +uint32_t clk_get_rate(struct clk *clk) +{ + if (!clk) + return 0; + if (clk->source) + clk = clk->source; + return clk ? clk->rate : 0; +} + +void clk_put(struct clk *clk) +{ + struct clk *parent_clk; + if (clk && !(clk->flags & CLK_FLG_NOALLOC)) + { + if (clk->source && clk->count && clk->source->count > 0) + { + if (--(clk->source->count) == 0) + clk->source->init_state = 1; + } + if (CLK_FLG_RELATIVE & clk->source->flags) + { + parent_clk = get_clk_from_id(CLK_RELATIVE(clk->source->flags)); + parent_clk->child = clk->source; + } + rt_free(clk); + } +} + +int clk_set_rate(struct clk *clk, uint32_t rate) +{ + int ret = 0; + if (!clk) + return -1; + if (clk->source) + clk = clk->source; + if (!clk->ops || !clk->ops->set_rate) + return -1; + if (clk->rate != rate) + ret = clk->ops->set_rate(clk, rate); + return ret; +} + +int init_all_clk(void) +{ + int i; + struct clk *clk_srcs = get_clk_from_id(0); + int clk_srcs_size = get_clk_sources_size(); + + PRINT("Init all clock ...\n"); + + for (i = 0; i < clk_srcs_size; i++) + { + clk_srcs[i].CLK_ID = i; + + if (clk_srcs[i].flags & CLK_FLG_CPCCR) + { + init_cpccr_clk(&clk_srcs[i]); + } + if (clk_srcs[i].flags & CLK_FLG_CGU) + { + init_cgu_clk(&clk_srcs[i]); + } + + if (clk_srcs[i].flags & CLK_FLG_CGU_AUDIO) + { + init_cgu_audio_clk(&clk_srcs[i]); + } + + if (clk_srcs[i].flags & CLK_FLG_PLL) + { + init_ext_pll(&clk_srcs[i]); + } + if (clk_srcs[i].flags & CLK_FLG_NOALLOC) + { + init_ext_pll(&clk_srcs[i]); + } + if (clk_srcs[i].flags & CLK_FLG_GATE) + { + init_gate_clk(&clk_srcs[i]); + } + if (clk_srcs[i].flags & CLK_FLG_ENABLE) + clk_srcs[i].init_state = 1; + } + + for (i = 0; i < clk_srcs_size; i++) + { + if (clk_srcs[i].parent && clk_srcs[i].init_state) + init_clk_parent(clk_srcs[i].parent); + } + + PRINT("CCLK:%luMHz L2CLK:%luMhz H0CLK:%luMHz H2CLK:%luMhz PCLK:%luMhz\n", + clk_srcs[CLK_ID_CCLK].rate/1000/1000, + clk_srcs[CLK_ID_L2CLK].rate/1000/1000, + clk_srcs[CLK_ID_H0CLK].rate/1000/1000, + clk_srcs[CLK_ID_H2CLK].rate/1000/1000, + clk_srcs[CLK_ID_PCLK].rate/1000/1000); + + return 0; +} +INIT_BOARD_EXPORT(init_all_clk); diff --git a/bsp/x1000/driver/drv_clock.h b/bsp/x1000/driver/drv_clock.h new file mode 100644 index 0000000000000000000000000000000000000000..90514c50df94527f21da5a02dd5e8f23464cb8c3 --- /dev/null +++ b/bsp/x1000/driver/drv_clock.h @@ -0,0 +1,143 @@ +/* + * File : drv_clock.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ + +#ifndef DRV_CLOCK_H_ +#define DRV_CLOCK_H_ + +#include "board.h" + +#define CPM_CPCCR (0x00) +#define CPM_CPCSR (0xd4) + +#define CPM_DDRCDR (0x2c) +#define CPM_I2SCDR (0x60) +#define CPM_I2SCDR1 (0x70) +#define CPM_LPCDR (0x64) +#define CPM_MSC0CDR (0x68) +#define CPM_MSC1CDR (0xa4) +#define CPM_USBCDR (0x50) +#define CPM_MACCDR (0x54) +#define CPM_UHCCDR (0x6c) +#define CPM_SFCCDR (0x74) +#define CPM_CIMCDR (0x7c) +#define CPM_PCMCDR (0x84) +#define CPM_PCMCDR1 (0xe0) +#define CPM_MPHYC (0xe8) + +#define CPM_INTR (0xb0) +#define CPM_INTRE (0xb4) +#define CPM_DRCG (0xd0) +#define CPM_CPSPPR (0x38) +#define CPM_CPPSR (0x34) + +#define CPM_USBPCR (0x3c) +#define CPM_USBRDT (0x40) +#define CPM_USBVBFIL (0x44) +#define CPM_USBPCR1 (0x48) + +#define CPM_CPAPCR (0x10) +#define CPM_CPMPCR (0x14) + +#define CPM_LCR (0x04) +#define CPM_PSWC0ST (0x90) +#define CPM_PSWC1ST (0x94) +#define CPM_PSWC2ST (0x98) +#define CPM_PSWC3ST (0x9c) +#define CPM_CLKGR (0x20) +#define CPM_MESTSEL (0xec) +#define CPM_SRBC (0xc4) +#define CPM_ERNG (0xd8) +#define CPM_RNG (0xdc) +#define CPM_SLBC (0xc8) +#define CPM_SLPC (0xcc) +#define CPM_OPCR (0x24) +#define CPM_RSR (0x08) + +#define LCR_LPM_MASK (0x3) +#define LCR_LPM_SLEEP (0x1) + +#define OPCR_ERCS (0x1<<2) +#define OPCR_PD (0x1<<3) +#define OPCR_IDLE (0x1<<31) + +#define cpm_inl(off) readl(CPM_BASE + (off)) +#define cpm_outl(val,off) writel(val, CPM_BASE + (off)) +#define cpm_test_bit(bit,off) (cpm_inl(off) & 0x1<<(bit)) +#define cpm_set_bit(bit,off) (cpm_outl((cpm_inl(off) | 0x1<<(bit)),off)) +#define cpm_clear_bit(bit,off) (cpm_outl(cpm_inl(off) & ~(0x1 << bit), off)) + + +#define I2S_PRI_DIV 0xb0020030 +#define PCM_PRI_DIV 0xb0030014 + +struct clk; + +struct clk_ops { + int (*enable) (struct clk *,int); + struct clk* (*get_parent) (struct clk *); + int (*set_parent) (struct clk *,struct clk *); + uint32_t (*get_rate) (struct clk *); + int (*set_rate) (struct clk *,uint32_t); + int (*set_round_rate) (struct clk *,uint32_t); +}; + +struct clk { + const char *name; + uint32_t rate; + struct clk *parent; + uint32_t flags; +#define CLK_FLG_NOALLOC BIT(0) +#define CLK_FLG_ENABLE BIT(1) +#define CLK_GATE_BIT(flg) ((flg) >> 24) +#define CLK_FLG_GATE BIT(2) +#define CLK_CPCCR_NO(flg) (((flg) >> 24) & 0xff) +#define CLK_FLG_CPCCR BIT(3) +#define CLK_CGU_NO(flg) (((flg) >> 24) & 0xff) +#define CLK_FLG_CGU BIT(4) +#define CLK_PLL_NO(flg) (((flg) >> 24) & 0xff) +#define CLK_FLG_PLL BIT(5) +#define CLK_CGU_AUDIO_NO(flg) (((flg) >> 24) & 0xff) +#define CLK_FLG_CGU_AUDIO BIT(6) +#define CLK_PARENT(flg) (((flg) >> 16) & 0xff) +#define CLK_RELATIVE(flg) (((flg) >> 16) & 0xff) +#define CLK_FLG_PARENT BIT(7) +#define CLK_FLG_RELATIVE BIT(8) + struct clk_ops *ops; + int count; + int init_state; + struct clk *source; + struct clk *child; + unsigned int CLK_ID; +}; + +int init_all_clk(void); +struct clk *clk_get(const char *id); +int clk_enable(struct clk *clk); +int clk_is_enabled(struct clk *clk); +void clk_disable(struct clk *clk); +uint32_t clk_get_rate(struct clk *clk); +void clk_put(struct clk *clk); +int clk_set_rate(struct clk *clk, uint32_t rate); + +#endif diff --git a/bsp/x1000/driver/drv_gpio.c b/bsp/x1000/driver/drv_gpio.c new file mode 100644 index 0000000000000000000000000000000000000000..1310f7dfc92465664489ee879ddc686864cc40db --- /dev/null +++ b/bsp/x1000/driver/drv_gpio.c @@ -0,0 +1,263 @@ +/* + * File : drv_gpio.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ + +#include +#include +#include + +#include "board.h" +#include "drv_gpio.h" + +#define GPIO_DEBUG 0 + +#if GPIO_DEBUG +#define GPIO_DBG(...) rt_kprintf(__VA_ARGS__) +#else +#define GPIO_DBG(...) +#endif + +struct jz_gpio_irq_def _g_gpio_irq_tbl[GPIO_NR_PORTS] = {0}; + +rt_inline int _fls(int x) +{ + __asm__("clz %0, %1" : "=r" (x) : "r" (x)); + + return 32 - x; +} + +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)); + + 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 & 0x10 ? pins : 0, GPIO_PXPENC(port)); + writel(func & 0x10 ? 0 : pins, GPIO_PXPENS(port)); +} + +void gpio_set_value(enum gpio_port port,enum gpio_pin pin,int value) +{ + RT_ASSERT(IS_GPIO_ALL_PORT(port)); + + if (value) + writel(pin, GPIO_PXPAT0S(port)); + else + writel(pin, GPIO_PXPAT0C(port)); +} + +void gpio_enable_pull(enum gpio_port port, enum gpio_pin pin) +{ + RT_ASSERT(IS_GPIO_ALL_PORT(port)); + + writel(pin, GPIO_PXPENC(port)); +} + +void gpio_disable_pull(enum gpio_port port, enum gpio_pin pin) +{ + RT_ASSERT(IS_GPIO_ALL_PORT(port)); + + writel(pin, GPIO_PXPENS(port)); +} + +void gpio_ctrl_pull(enum gpio_port port, uint32_t pins,int enable) +{ + RT_ASSERT(IS_GPIO_ALL_PORT(port)); + + if (enable) + writel(pins, GPIO_PXPENC(port)); + else + writel(pins, GPIO_PXPENS(port)); +} + +int gpio_get_value(enum gpio_port port, enum gpio_pin pin) +{ + RT_ASSERT(IS_GPIO_ALL_PORT(port)); + + return !!(readl(GPIO_PXPIN(port)) & pin); +} + +int gpio_get_flag(enum gpio_port port, enum gpio_pin pin) +{ + RT_ASSERT(IS_GPIO_ALL_PORT(port)); + + return (readl(GPIO_PXFLG(port)) & pin); +} + +void gpio_clear_flag(enum gpio_port port, enum gpio_pin pin) +{ + RT_ASSERT(IS_GPIO_ALL_PORT(port)); + + writel(pin, GPIO_PXFLGC(port)); +} + +void gpio_direction_input(enum gpio_port port, enum gpio_pin pin) +{ + RT_ASSERT(IS_GPIO_ALL_PORT(port)); + + gpio_set_func(port,pin,GPIO_INPUT); +} + +void gpio_direction_output(enum gpio_port port, enum gpio_pin pin,int value) +{ + RT_ASSERT(IS_GPIO_ALL_PORT(port)); + + gpio_set_func(port, pin, value ? GPIO_OUTPUT1 : GPIO_OUTPUT0); +} + +/********************************************************************************************************* +** IRQ +*********************************************************************************************************/ +void gpio_unmask_irq(enum gpio_port port, enum gpio_pin pin) +{ + RT_ASSERT(IS_GPIO_ALL_PORT(port)); + + writel(pin, GPIO_PXMSKC(port)); +} + +void gpio_mask_irq(enum gpio_port port, enum gpio_pin pin) +{ + RT_ASSERT(IS_GPIO_ALL_PORT(port)); + + writel(BIT(pin), GPIO_PXMSKS(port)); +} + +int gpio_set_irq_type(enum gpio_port port, enum gpio_pin pin, enum gpio_irq_type irq_type) +{ + enum gpio_function func; + + RT_ASSERT(IS_GPIO_ALL_PORT(port)); + + if (irq_type & IRQ_TYPE_PROBE) + return 0; + switch (irq_type & IRQ_TYPE_SENSE_MASK) + { + case IRQ_TYPE_LEVEL_HIGH: + func = GPIO_INT_HI; + break; + case IRQ_TYPE_LEVEL_LOW: + func = GPIO_INT_LO; + break; + case IRQ_TYPE_EDGE_RISING: + func = GPIO_INT_RE; + break; + case IRQ_TYPE_EDGE_FALLING: + func = GPIO_INT_FE; + break; + case IRQ_TYPE_EDGE_BOTH: + if (gpio_get_value(port, pin)) + func = GPIO_INT_FE; + else + func = GPIO_INT_RE; + break; + default: + return -1; + } + + gpio_set_func(port,pin, func); + + return 0; +} + +void gpio_ack_irq(enum gpio_port port, enum gpio_pin pin) +{ + RT_ASSERT(IS_GPIO_ALL_PORT(port)); + + writel(pin, GPIO_PXFLGC(port)); +} + +void gpio_set_irq_callback(enum gpio_port port, enum gpio_pin pin, void (*irq_cb)(void *),void *irq_arg) +{ + uint32_t pin_id; + RT_ASSERT(IS_GPIO_ALL_PORT(port)); + pin_id = _fls(pin) - 1; + + GPIO_DBG("port = %d,pin = %d \n",port,pin_id); + + _g_gpio_irq_tbl[port].irq_cb[pin_id] = irq_cb; + _g_gpio_irq_tbl[port].irq_arg[pin_id] = irq_arg; + + GPIO_DBG("set irq callback end... \n"); +} + +void gpio_irq_handler(int irq, void *param) +{ + struct jz_gpio_irq_def *irq_def = (struct jz_gpio_irq_def *)param; + uint32_t pend,mask; + uint32_t pin_id; + enum gpio_port port = (IRQ_GPIO0 - irq); + enum gpio_pin pin; + + RT_ASSERT(param != RT_NULL); + GPIO_DBG("GPIO irq handler,irq=%d\n",irq); + + pend = readl(GPIO_PXFLG(port)); + mask = readl(GPIO_PXMSK(port)); + + GPIO_DBG("port =%d pend =%08x mask =%08x\n",port,pend,mask); + + pend = pend & ~mask; + while(pend) + { + pin_id = _fls(pend) - 1; + pin = 0x01 << pin_id; + + GPIO_DBG("PORT%d PIN%d interrupt happened..\n",port,pin_id); + if(irq_def->irq_cb[pin_id] != RT_NULL) + { + GPIO_DBG("do irq callback...\n",port,pin); + irq_def->irq_cb[pin_id](irq_def->irq_arg[pin_id]); + } + + pend &= ~(0x01 << pin_id); + gpio_ack_irq(port, pin); + } +} + +int rt_hw_gpio_init(void) +{ + GPIO_DBG("Install gpio interrupt source...\n"); + /* install ISR */ + rt_hw_interrupt_install(IRQ_GPIO0,gpio_irq_handler,&_g_gpio_irq_tbl[GPIO_PORT_A],"GPIOAINT"); + rt_hw_interrupt_umask(IRQ_GPIO0); + + rt_hw_interrupt_install(IRQ_GPIO1,gpio_irq_handler,&_g_gpio_irq_tbl[GPIO_PORT_B],"GPIOBINT"); + rt_hw_interrupt_umask(IRQ_GPIO1); + + rt_hw_interrupt_install(IRQ_GPIO2,gpio_irq_handler,&_g_gpio_irq_tbl[GPIO_PORT_C],"GPIOCINT"); + rt_hw_interrupt_umask(IRQ_GPIO2); + + rt_hw_interrupt_install(IRQ_GPIO3,gpio_irq_handler,&_g_gpio_irq_tbl[GPIO_PORT_D],"GPIODINT"); + rt_hw_interrupt_umask(IRQ_GPIO3); + + return 0; +} +INIT_BOARD_EXPORT(rt_hw_gpio_init); diff --git a/bsp/x1000/driver/drv_gpio.h b/bsp/x1000/driver/drv_gpio.h new file mode 100644 index 0000000000000000000000000000000000000000..ceef761aaadb1b8a133709f81ff7a74a473e4711 --- /dev/null +++ b/bsp/x1000/driver/drv_gpio.h @@ -0,0 +1,208 @@ +/* + * File : board_gpio.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ + +#ifndef _BOARD_GPIO_H_ +#define _BOARD_GPIO_H_ + +#include + +#define GPIO_PA(n) (0*32 + n) +#define GPIO_PB(n) (1*32 + n) +#define GPIO_PC(n) (2*32 + n) +#define GPIO_PD(n) (3*32 + n) +#define GPIO_PE(n) (4*32 + n) +#define GPIO_PF(n) (5*32 + n) +#define GPIO_PG(n) (6*32 + n) + +#define GPIO_PIN(n) (0x01 << n) + +/************************************************************************* + * GPIO (General-Purpose I/O Ports) + *************************************************************************/ +#define GPIO_PORT_OFF 0x100 +#define GPIO_SHADOW_OFF 0x700 + +#define PXPIN 0x00 /* PIN Level Register */ +#define PXINT 0x10 /* Port Interrupt Register */ +#define PXINTS 0x14 /* Port Interrupt Set Register */ +#define PXINTC 0x18 /* Port Interrupt Clear Register */ +#define PXMSK 0x20 /* Port Interrupt Mask Reg */ +#define PXMSKS 0x24 /* Port Interrupt Mask Set Reg */ +#define PXMSKC 0x28 /* Port Interrupt Mask Clear Reg */ +#define PXPAT1 0x30 /* Port Pattern 1 Set Reg. */ +#define PXPAT1S 0x34 /* Port Pattern 1 Set Reg. */ +#define PXPAT1C 0x38 /* Port Pattern 1 Clear Reg. */ +#define PXPAT0 0x40 /* Port Pattern 0 Register */ +#define PXPAT0S 0x44 /* Port Pattern 0 Set Register */ +#define PXPAT0C 0x48 /* Port Pattern 0 Clear Register */ +#define PXFLG 0x50 /* Port Flag Register */ +#define PXFLGC 0x58 /* Port Flag clear Register */ +#define PXOENS 0x64 /* Port Output Disable Set Register */ +#define PXOENC 0x68 /* Port Output Disable Clear Register */ +#define PXPEN 0x70 /* Port Pull Disable Register */ +#define PXPENS 0x74 /* Port Pull Disable Set Register */ +#define PXPENC 0x78 /* Port Pull Disable Clear Register */ +#define PXDSS 0x84 /* Port Drive Strength set Register */ +#define PXDSC 0x88 /* Port Drive Strength clear Register */ +#define PZGID2LD 0xF0 /* GPIOZ Group ID to load */ + + +#define GPIO_PXPIN(n) (GPIO_BASE + (PXPIN + (n) * GPIO_PORT_OFF)) /* PIN Level Register */ +#define GPIO_PXINT(n) (GPIO_BASE + (PXINT + (n) * GPIO_PORT_OFF)) /* Port Interrupt Register */ +#define GPIO_PXINTS(n) (GPIO_BASE + (PXINTS + (n) * GPIO_PORT_OFF)) /* Port Interrupt Set Register */ +#define GPIO_PXINTC(n) (GPIO_BASE + (PXINTC + (n) * GPIO_PORT_OFF)) /* Port Interrupt Clear Register */ +#define GPIO_PXMSK(n) (GPIO_BASE + (PXMSK + (n) * GPIO_PORT_OFF)) /* Port Interrupt Mask Register */ +#define GPIO_PXMSKS(n) (GPIO_BASE + (PXMSKS + (n) * GPIO_PORT_OFF)) /* Port Interrupt Mask Set Reg */ +#define GPIO_PXMSKC(n) (GPIO_BASE + (PXMSKC + (n) * GPIO_PORT_OFF)) /* Port Interrupt Mask Clear Reg */ +#define GPIO_PXPAT1(n) (GPIO_BASE + (PXPAT1 + (n) * GPIO_PORT_OFF)) /* Port Pattern 1 Register */ +#define GPIO_PXPAT1S(n) (GPIO_BASE + (PXPAT1S + (n) * GPIO_PORT_OFF)) /* Port Pattern 1 Set Reg. */ +#define GPIO_PXPAT1C(n) (GPIO_BASE + (PXPAT1C + (n) * GPIO_PORT_OFF)) /* Port Pattern 1 Clear Reg. */ +#define GPIO_PXPAT0(n) (GPIO_BASE + (PXPAT0 + (n) * GPIO_PORT_OFF)) /* Port Pattern 0 Register */ +#define GPIO_PXPAT0S(n) (GPIO_BASE + (PXPAT0S + (n) * GPIO_PORT_OFF)) /* Port Pattern 0 Set Register */ +#define GPIO_PXPAT0C(n) (GPIO_BASE + (PXPAT0C + (n) * GPIO_PORT_OFF)) /* Port Pattern 0 Clear Register */ +#define GPIO_PXFLG(n) (GPIO_BASE + (PXFLG + (n) * GPIO_PORT_OFF)) /* Port Flag Register */ +#define GPIO_PXFLGC(n) (GPIO_BASE + (PXFLGC + (n) * GPIO_PORT_OFF)) /* Port Flag clear Register */ +#define GPIO_PXOENS(n) (GPIO_BASE + (PXOENS + (n) * GPIO_PORT_OFF)) /* Port Output Disable Set Register */ +#define GPIO_PXOENC(n) (GPIO_BASE + (PXOENC + (n) * GPIO_PORT_OFF)) /* Port Output Disable Clear Register */ +#define GPIO_PXPEN(n) (GPIO_BASE + (PXPEN + (n) * GPIO_PORT_OFF)) /* Port Pull Disable Register */ +#define GPIO_PXPENS(n) (GPIO_BASE + (PXPENS + (n) * GPIO_PORT_OFF)) /* Port Pull Disable Set Register */ +#define GPIO_PXPENC(n) (GPIO_BASE + (PXPENC + (n) * GPIO_PORT_OFF)) /* Port Pull Disable Clear Register */ +#define GPIO_PXDSS(n) (GPIO_BASE + (PXDSS + (n) * GPIO_PORT_OFF)) /* Port Drive Strength set Register */ +#define GPIO_PXDSC(n) (GPIO_BASE + (PXDSC + (n) * GPIO_PORT_OFF)) /* Port Drive Strength clear Register */ +#define GPIO_PZGID2LD(n) (GPIO_BASE + (PZGID2LD + (n) * GPIO_PORT_OFF)) /* GPIOZ Group ID to load */ + + +struct jzgpio_state { + uint32_t pxint; + uint32_t pxmsk; + uint32_t pxpat1; + uint32_t pxpat0; + uint32_t pxpen; + uint32_t pxignore; +}; + +enum gpio_function +{ + GPIO_FUNC_0 = 0x00, //0000, GPIO as function 0 / device 0 + GPIO_FUNC_1 = 0x01, //0001, GPIO as function 1 / device 1 + GPIO_FUNC_2 = 0x02, //0010, GPIO as function 2 / device 2 + GPIO_FUNC_3 = 0x03, //0011, GPIO as function 3 / device 3 + GPIO_OUTPUT0 = 0x04, //0100, GPIO output low level + GPIO_OUTPUT1 = 0x05, //0101, GPIO output high level + GPIO_INPUT = 0x06, //0110, GPIO as input + GPIO_INT_LO = 0x08, //1000, Low Level trigger interrupt + GPIO_INT_HI = 0x09, //1001, High Level trigger interrupt + GPIO_INT_FE = 0x0a, //1010, Fall Edge trigger interrupt + GPIO_INT_RE = 0x0b, //1011, Rise Edge trigger interrupt + GPIO_INPUT_PULL = 0x16, //0001 0110, GPIO as input and enable pull +}; + +enum gpio_irq_type +{ + IRQ_TYPE_NONE = 0x00000000, + IRQ_TYPE_EDGE_RISING = 0x00000001, + IRQ_TYPE_EDGE_FALLING = 0x00000002, + IRQ_TYPE_EDGE_BOTH = (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING), + IRQ_TYPE_LEVEL_HIGH = 0x00000004, + IRQ_TYPE_LEVEL_LOW = 0x00000008, + IRQ_TYPE_LEVEL_MASK = (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH), + IRQ_TYPE_SENSE_MASK = 0x0000000f, + IRQ_TYPE_DEFAULT = IRQ_TYPE_SENSE_MASK, + + IRQ_TYPE_PROBE = 0x00000010, + + IRQ_LEVEL = (1 << 8), +}; + +enum gpio_port { + GPIO_PORT_A = 0, + GPIO_PORT_B, + GPIO_PORT_C, + GPIO_PORT_D, + /* this must be last */ + GPIO_NR_PORTS, +}; + +#define IS_GPIO_ALL_PORT(PORT) ( (PORT) < GPIO_NR_PORTS ) + +enum gpio_pin { + GPIO_Pin_0 = ((uint32_t)0x00000001), /* Pin 0 selected */ + GPIO_Pin_1 = ((uint32_t)0x00000002), /* Pin 1 selected */ + GPIO_Pin_2 = ((uint32_t)0x00000004), /* Pin 2 selected */ + GPIO_Pin_3 = ((uint32_t)0x00000008), /* Pin 3 selected */ + GPIO_Pin_4 = ((uint32_t)0x00000010), /* Pin 4 selected */ + GPIO_Pin_5 = ((uint32_t)0x00000020), /* Pin 5 selected */ + GPIO_Pin_6 = ((uint32_t)0x00000040), /* Pin 6 selected */ + GPIO_Pin_7 = ((uint32_t)0x00000080), /* Pin 7 selected */ + GPIO_Pin_8 = ((uint32_t)0x00000100), /* Pin 8 selected */ + GPIO_Pin_9 = ((uint32_t)0x00000200), /* Pin 9 selected */ + GPIO_Pin_10 = ((uint32_t)0x00000400), /* Pin 10 selected */ + GPIO_Pin_11 = ((uint32_t)0x00000800), /* Pin 11 selected */ + GPIO_Pin_12 = ((uint32_t)0x00001000), /* Pin 12 selected */ + GPIO_Pin_13 = ((uint32_t)0x00002000), /* Pin 13 selected */ + GPIO_Pin_14 = ((uint32_t)0x00004000), /* Pin 14 selected */ + GPIO_Pin_15 = ((uint32_t)0x00008000), /* Pin 15 selected */ + GPIO_Pin_16 = ((uint32_t)0x00010000), /* Pin 16 selected */ + GPIO_Pin_17 = ((uint32_t)0x00020000), /* Pin 17 selected */ + GPIO_Pin_18 = ((uint32_t)0x00040000), /* Pin 18 selected */ + GPIO_Pin_19 = ((uint32_t)0x00080000), /* Pin 19 selected */ + GPIO_Pin_20 = ((uint32_t)0x00100000), /* Pin 20 selected */ + GPIO_Pin_21 = ((uint32_t)0x00200000), /* Pin 21 selected */ + GPIO_Pin_22 = ((uint32_t)0x00400000), /* Pin 22 selected */ + GPIO_Pin_23 = ((uint32_t)0x00800000), /* Pin 23 selected */ + GPIO_Pin_24 = ((uint32_t)0x01000000), /* Pin 24 selected */ + GPIO_Pin_25 = ((uint32_t)0x02000000), /* Pin 25 selected */ + GPIO_Pin_26 = ((uint32_t)0x04000000), /* Pin 26 selected */ + GPIO_Pin_27 = ((uint32_t)0x08000000), /* Pin 27 selected */ + GPIO_Pin_28 = ((uint32_t)0x10000000), /* Pin 28 selected */ + GPIO_Pin_29 = ((uint32_t)0x20000000), /* Pin 29 selected */ + GPIO_Pin_30 = ((uint32_t)0x40000000), /* Pin 30 selected */ + GPIO_Pin_31 = ((uint32_t)0x80000000), /* Pin 31 selected */ + + GPIO_Pin_All = ((uint32_t)0xFFFFFFFF), /* All pins selected */ +}; + +struct jz_gpio_irq_def +{ + void *irq_arg[32]; + void (*irq_cb[32]) (void *param); +}; + +void gpio_set_func (enum gpio_port port, uint32_t pins, enum gpio_function func); + +void gpio_set_value (enum gpio_port port, enum gpio_pin pin,int value); +int gpio_get_value (enum gpio_port port, enum gpio_pin pin); +int gpio_get_flag (enum gpio_port port, enum gpio_pin pin); +void gpio_clear_flag (enum gpio_port port, enum gpio_pin pin); +void gpio_direction_input (enum gpio_port port, enum gpio_pin pin); +void gpio_direction_output (enum gpio_port port, enum gpio_pin pin,int value); +void gpio_enable_pull (enum gpio_port port, enum gpio_pin pin); +void gpio_disable_pull (enum gpio_port port, enum gpio_pin pin); +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); + +#endif /* _BOARD_GPIO_H_ */ diff --git a/bsp/x1000/driver/drv_mmc.c b/bsp/x1000/driver/drv_mmc.c new file mode 100644 index 0000000000000000000000000000000000000000..6d4656bd3567f10c18817747cdda3051ce62714c --- /dev/null +++ b/bsp/x1000/driver/drv_mmc.c @@ -0,0 +1,750 @@ +/* + * File : drv_mmc.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013 - 2015, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2013-03-09 aozima the first version + * 2013-03-29 aozima support Jz4770. + * 2013-04-01 aozima add interrupt support for Jz4770. + */ + +#include +#include +#include + +#include +#include + +#include "board.h" +#include "drv_gpio.h" +#include "drv_clock.h" +#include "drv_mmc.h" + +#define RT_USING_MSC0 +#define RT_USING_MSC1 + +// #define JZ47XX_SDIO_DBG + +#ifdef JZ47XX_SDIO_DBG +#define sdio_dbg(fmt, ...) rt_kprintf("[SDIO]");rt_kprintf(fmt, ##__VA_ARGS__) +#else +#define sdio_dbg(fmt, ...) +#endif + +static void msc_handler(int irqno, void* param) +{ + struct jz47xx_sdio * jz_sdio = (struct jz47xx_sdio *)param; + + /* disable interrupt */ + rt_hw_interrupt_mask(jz_sdio->irqno); + + rt_completion_done(&jz_sdio->completion); +} + +rt_inline void jz_mmc_clk_autoctrl(struct jz47xx_sdio *host, unsigned int on) +{ + if(on) + { + if(!clk_is_enabled(host->clock)) + clk_enable(host->clock); + if(!clk_is_enabled(host->clock_gate)) + clk_enable(host->clock_gate); + } + else + { + if(clk_is_enabled(host->clock_gate)) + clk_disable(host->clock_gate); + if(clk_is_enabled(host->clock)) + clk_disable(host->clock); + } +} + +/* Stop the MMC clock and wait while it happens */ +rt_inline rt_err_t jz_mmc_stop_clock(uint32_t hw_base) +{ + uint16_t value; + int timeout = 10000; + + value = readw(hw_base + MSC_CTRL_OFFSET); + value |= MSC_CTRL_CLOCK_STOP; + writew(value, hw_base + MSC_CTRL_OFFSET); + + while (timeout && (readl(hw_base + MSC_STAT_OFFSET) & MSC_STAT_CLK_EN)) + { + timeout--; + if (timeout == 0) + { + return -RT_ETIMEOUT; + } + rt_thread_delay(1); + } + + return RT_EOK; +} + +/* Start the MMC clock and operation */ +rt_inline void jz_mmc_start_clock(uint32_t hw_base) +{ + uint16_t value; + value = readw(hw_base + MSC_CTRL_OFFSET); + value |= (MSC_CTRL_CLOCK_START | MSC_CTRL_START_OP); + writew(value, hw_base + MSC_CTRL_OFFSET); +} + +static int jz_mmc_hardware_init(struct jz47xx_sdio * jz_sdio) +{ + uint32_t hw_base = jz_sdio->hw_base; + uint32_t value; + + /* reset mmc/sd controller */ + value = readl(hw_base + MSC_CTRL_OFFSET); + value |= MSC_CTRL_RESET; + writel(value, hw_base + MSC_CTRL_OFFSET); + rt_thread_delay(1); + value &= ~MSC_CTRL_RESET; + writel(value, hw_base + MSC_CTRL_OFFSET); + + while(readl(hw_base + MSC_STAT_OFFSET) & MSC_STAT_IS_RESETTING); + + /* mask all IRQs */ + writel(0xffffffff, hw_base + MSC_IMASK_OFFSET); + writel(0xffffffff, hw_base + MSC_IREG_OFFSET); + + /* set timeout */ + writel(0x100, hw_base + MSC_RESTO_OFFSET); + writel(0x1ffffff, hw_base + MSC_RDTO_OFFSET); + + /* stop MMC/SD clock */ + jz_mmc_stop_clock(hw_base); +} + +/* Set the MMC clock frequency */ +void jz_mmc_set_clock(struct jz47xx_sdio * jz_sdio, unsigned int clock) +{ + unsigned int msc_clock = jz_sdio->msc_clock; + + /* calc and set MSC_CLKRT. */ + { + unsigned int div = 0; + while (clock < msc_clock) + { + div++; + msc_clock >>= 1; + } + if(div > 7) div = 7; + + sdio_dbg("msc_clock: %u, SDIO_CLK: %u, MSC_CLKRT: %u\r\n", jz_sdio->msc_clock, clock, div); + writew(div, jz_sdio->hw_base + MSC_CLKRT_OFFSET); + } +} + +/* RT-Thread SDIO interface */ +static void jz47xx_sdio_request(struct rt_mmcsd_host *host, + struct rt_mmcsd_req *req) +{ + struct jz47xx_sdio *sdio = host->private_data; + unsigned int cmdat = 0; + unsigned int stat; + uint32_t hw_base, value; + + hw_base = sdio->hw_base; + jz_mmc_stop_clock(hw_base); + + sdio_dbg("CMD: %d ARG: %08X\n", req->cmd->cmd_code, req->cmd->arg); + + if(sdio->flag & MSC_CMDAT_BUS_WIDTH_4BIT) + { + cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT; + } + + /* auto send stop */ + if (req->stop) + { + sdio_dbg("CMD STOP: %d ARG: %08X\n", req->stop->cmd_code, + req->stop->arg); + cmdat |= MSC_CMDAT_SEND_AS_STOP; + } + + if(req->cmd->cmd_code == GO_IDLE_STATE) + { + cmdat |= MSC_CMDAT_INIT; + } + + /* clear status */ + writew(0xFFFF, hw_base + MSC_IREG_OFFSET); + + /* open interrupt */ + value = readl(hw_base + MSC_IMASK_OFFSET); + value &= ~(MSC_DATA_TRAN_DONE | MSC_PRG_DONE | MSC_END_CMD_RES); + writel(value, hw_base + MSC_IMASK_OFFSET); + + if(req->data) + { + writew(req->data->blksize, hw_base + MSC_BLKLEN_OFFSET); + writew(req->data->blks, hw_base + MSC_NOB_OFFSET); + + cmdat |= MSC_CMDAT_DATA_EN; + if (req->data->flags & DATA_DIR_WRITE) + { + cmdat |= MSC_CMDAT_WRITE; + } + else if (req->data->flags & DATA_DIR_READ) + { + cmdat |= MSC_CMDAT_READ; + } + } + else + { + writew(0, hw_base + MSC_BLKLEN_OFFSET); + writew(0, hw_base + MSC_NOB_OFFSET); + } + + /* set command */ + writeb(req->cmd->cmd_code, hw_base + MSC_CMD_OFFSET); + + /* set argument */ + writel(req->cmd->arg, hw_base + MSC_ARG_OFFSET); + + /* Set response type */ +#ifdef JZ47XX_SDIO_DBG + { + int res_type = req->cmd->flags & RESP_MASK; + sdio_dbg("resp type:%u\r\n", res_type); + } +#endif + + cmdat &= ~(MSC_CMDAT_RESP_FORMAT_MASK); + switch (req->cmd->flags & RESP_MASK) + { + case RESP_NONE: + break; + + case RESP_R1B: + cmdat |= MSC_CMDAT_BUSY; + /*FALLTHRU*/ + case RESP_R1: + cmdat |= MSC_CMDAT_RESPONSE_R1; + break; + case RESP_R2: + cmdat |= MSC_CMDAT_RESPONSE_R2; + break; + case RESP_R3: + cmdat |= MSC_CMDAT_RESPONSE_R3; + break; + case RESP_R4: + cmdat |= MSC_CMDAT_RESPONSE_R4; + break; + case RESP_R5: + cmdat |= MSC_CMDAT_RESPONSE_R5; + break; + case RESP_R6: + cmdat |= MSC_CMDAT_RESPONSE_R6; + case RESP_R7: + cmdat |= MSC_CMDAT_RESPONSE_R7; + break; + default: + break; + } + + /* Set command */ + sdio_dbg("cmdat: %08X\r\n", cmdat); + writel(cmdat, sdio->hw_base + MSC_CMDAT_OFFSET); + writel(MSC_CTRL_START_OP, sdio->hw_base + MSC_CTRL_OFFSET); + + writel(0xFF, sdio->hw_base + MSC_RESTO_OFFSET); + writel(0xFFFFFFFF, sdio->hw_base + MSC_RDTO_OFFSET); + + jz_mmc_start_clock(sdio->hw_base); + req->cmd->err = RT_EOK; + + if(!(readl(sdio->hw_base + MSC_IREG_OFFSET) & MSC_END_CMD_RES)) + { + rt_err_t ret; + + rt_completion_init(&sdio->completion); + rt_hw_interrupt_umask(sdio->irqno); + ret = rt_completion_wait(&sdio->completion, RT_TICK_PER_SECOND); + if(ret == RT_EOK) + { + sdio_dbg("wait END_CMD_RES OK!\r\n"); + } + else + { + uint32_t value; + + value = readl(hw_base + MSC_STAT_OFFSET); + sdio_dbg("stat=0x%08x\n", value); + value = readl(hw_base + MSC_IREG_OFFSET); + sdio_dbg("iflag=0x%08x\n", value); + + req->cmd->err = ret; + sdio_dbg("wait END_CMD_RES timeout[uncompletion]\r\n"); + } + } + else + { + sdio_dbg("no need wait MSC_END_CMD_RES!\r\n"); + } + + stat = readl(hw_base + MSC_STAT_OFFSET); + writew(MSC_END_CMD_RES, hw_base + MSC_IREG_OFFSET); + + /* get response. */ + { + uint8_t buf[16]; + uint32_t data; + + if(req->cmd->err == RT_EOK) + { + if(stat & MSC_STAT_TIME_OUT_RES) + { + sdio_dbg("ERR: MSC_STAT_TIME_OUT_RES\r\n"); + req->cmd->err = -RT_ETIMEOUT; + } + else if(stat & MSC_STAT_CRC_READ_ERR) + { + sdio_dbg("ERR: MSC_STAT_CRC_READ_ERR\r\n"); + req->cmd->err = -1; + } + } + + switch (req->cmd->flags & RESP_MASK) + { + case RESP_R1: + case RESP_R1B: + case RESP_R6: + case RESP_R3: + case RESP_R4: + case RESP_R5: + case RESP_R7: + data = readw(sdio->hw_base + MSC_RES_OFFSET); + buf[1] = data & 0xFF; + + data = readw(sdio->hw_base + MSC_RES_OFFSET); + buf[2] = (data >> 8) & 0xFF; + buf[3] = data & 0xFF; + + data = readw(sdio->hw_base + MSC_RES_OFFSET); + buf[4] = data & 0xFF; + + req->cmd->resp[0] = buf[1] << 24 | buf[2] << 16 + | buf[3] << 8 | buf[4]; + break; + case RESP_R2: + { + uint32_t i, v, w1, w2; + + data = readw(sdio->hw_base + MSC_RES_OFFSET); + v = data & 0xFFFF; + + for(i=0; i<4; i++) + { + data = readw(sdio->hw_base + MSC_RES_OFFSET); + w1 = data & 0xFFFF; + + data = readw(sdio->hw_base + MSC_RES_OFFSET); + w2 = data & 0xFFFF; + + req->cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8; + v = w2; + } + } + break; + default: + break; + } + + sdio_dbg("error:%d cmd->resp [%08X, %08X, %08X, %08X]\r\n\r\n", + req->cmd->err, + req->cmd->resp[0], + req->cmd->resp[1], + req->cmd->resp[2], + req->cmd->resp[3] + ); + } + + if(req->data) + { + unsigned int waligned; + uint32_t len = req->data->blksize * req->data->blks; + + /* word aligned ? */ + waligned = (((unsigned int)req->data->buf & 0x3) == 0); + + if (req->data->flags & DATA_DIR_WRITE) + { + if(waligned) + { + uint32_t i; + uint32_t *src = (uint32_t *)req->data->buf; + + for(i=0; ihw_base + MSC_STAT_OFFSET) & MSC_STAT_DATA_FIFO_FULL); + + writel(*src++, hw_base + MSC_TXFIFO_OFFSET); + } + } + else + { + uint32_t i, data; + uint8_t * src = (uint8_t *)req->data->buf; + + for(i=0; ihw_base + MSC_STAT_OFFSET) & MSC_STAT_DATA_FIFO_FULL); + + data = (*src++ << 0); + data |= (*src++ << 8); + data |= (*src++ << 16); + data |= (*src++ << 24); + + writel(data, hw_base + MSC_TXFIFO_OFFSET); + } + } + + writel(IFLG_PRG_DONE, hw_base + MSC_IREG_OFFSET); + } + else if (req->data->flags & DATA_DIR_READ) + { + if(waligned) + { + uint32_t i; + uint32_t * dst = (uint32_t *)req->data->buf; + + for(i=0; ihw_base + MSC_STAT_OFFSET) & MSC_STAT_DATA_FIFO_EMPTY); + + *dst ++ = readl(sdio->hw_base + MSC_RXFIFO_OFFSET); + } + } + else + { + uint32_t data, i; + uint8_t * dst = (uint8_t *)req->data->buf; + + for(i=0; ihw_base + MSC_STAT_OFFSET) & MSC_STAT_DATA_FIFO_EMPTY); + + data = readl(sdio->hw_base + MSC_RXFIFO_OFFSET); + *dst++ = (uint8_t)(data >> 0); + *dst++ = (uint8_t)(data >> 8); + *dst++ = (uint8_t)(data >> 16); + *dst++ = (uint8_t)(data >> 24); + } + } + + writel(IFLG_DATA_TRAN_DONE, hw_base + MSC_IREG_OFFSET); + } + +#if 0 + value = readl(hw_base + MSC_IMASK_OFFSET); + value &= ~MSC_DATA_TRAN_DONE; + writel(value, hw_base + MSC_IMASK_OFFSET); + + if(!(readl(sdio->hw_base + MSC_IREG_OFFSET) & MSC_DATA_TRAN_DONE)) + { + rt_err_t ret; + + rt_completion_init(&sdio->completion); + sdio_dbg("TRAN_DONE umask\r\n"); + rt_hw_interrupt_umask(sdio->irqno); + + ret = rt_completion_wait(&sdio->completion, RT_TICK_PER_SECOND); + if(ret == RT_EOK) + { + sdio_dbg("wait END_CMD_RES OK!\r\n"); + } + else + { + rt_kprintf("SD DATA: int status 0x%08x\n", readl(sdio->hw_base + MSC_IREG_OFFSET)); + sdio_dbg("wait END_CMD_RES timeout!\r\n"); + } + } + else + { + sdio_dbg("no need wait MSC_DATA_TRAN_DONE!\r\n"); + } +#endif + + /* clear status */ + writew(MSC_DATA_TRAN_DONE, hw_base + MSC_IREG_OFFSET); + } /* if req->data */ + + mmcsd_req_complete(host); +} + + +static void jz47xx_sdio_set_iocfg(struct rt_mmcsd_host *host, + struct rt_mmcsd_io_cfg *io_cfg) +{ + struct jz47xx_sdio * jz_sdio = host->private_data; + rt_uint32_t clkdiv; + + sdio_dbg("set_iocfg clock: %d\n", io_cfg->clock); + + if (io_cfg->bus_width == MMCSD_BUS_WIDTH_4) + { + sdio_dbg("MMC: Setting controller bus width to 4\n"); + jz_sdio->flag |= MSC_CMDAT_BUS_WIDTH_4BIT; + } + else + { + jz_sdio->flag &= ~(MSC_CMDAT_BUS_WIDTH_4BIT); + sdio_dbg("MMC: Setting controller bus width to 1\n"); + } + + if (io_cfg->clock) + { + unsigned int clk_set = 0, clkrt = 0; + unsigned int clk_want = io_cfg->clock; + unsigned int lpm = 0; + + if (io_cfg->clock > 1 * 1000 * 1000) + { + io_cfg->clock = 1000 * 1000; + } + + jz_mmc_clk_autoctrl(jz_sdio, 1); + if (clk_want > 3000000) + { + clk_set_rate(jz_sdio->clock, io_cfg->clock); + } + else + { + clk_set_rate(jz_sdio->clock, 24000000); + } + clk_set = clk_get_rate(jz_sdio->clock); + + while (clk_want < clk_set) + { + clkrt++; + clk_set >>= 1; + } + + if (clkrt > 7) + { + sdio_dbg("invalid value of CLKRT: " + "ios->clock=%d clk_want=%d " + "clk_set=%d clkrt=%X,\n", + io_cfg->clock, clk_want, clk_set, clkrt); + return; + } + + if (!clkrt) + { + sdio_dbg("clk_want: %u, clk_set: %luHz\n", io_cfg->clock, clk_get_rate(jz_sdio->clock)); + } + + writel(clkrt, jz_sdio->hw_base + MSC_CLKRT_OFFSET); + + if (clk_set > 25000000) + { + lpm = (0x2 << LPM_DRV_SEL_SHF) | LPM_SMP_SEL; + } + + if(jz_sdio->sdio_clk) + { + writel(lpm, jz_sdio->hw_base + MSC_LPM_OFFSET); + writel(MSC_CTRL_CLOCK_START, jz_sdio->hw_base + MSC_CTRL_OFFSET); + } + else + { + lpm |= LPM_LPM; + writel(lpm, jz_sdio->hw_base + MSC_LPM_OFFSET); + } + } + else + { + jz_mmc_clk_autoctrl(jz_sdio, 0); + } + + /* maybe switch power to the card */ + switch (io_cfg->power_mode) + { + case MMCSD_POWER_OFF: + sdio_dbg("MMCSD_POWER_OFF\r\n"); + break; + case MMCSD_POWER_UP: + sdio_dbg("MMCSD_POWER_UP\r\n"); + break; + case MMCSD_POWER_ON: + sdio_dbg("MMCSD_POWER_ON\r\n"); + jz_mmc_hardware_init(jz_sdio); + // jz_mmc_set_clock(jz_sdio, io_cfg->clock); + break; + default: + sdio_dbg("unknown power_mode %d\n", io_cfg->power_mode); + break; + } +} + +static rt_int32_t jz47xx_SD_Detect(struct rt_mmcsd_host *host) +{ + sdio_dbg("jz47xx_SD_Detect\n"); +} + +static void jz47xx_sdio_enable_sdio_irq(struct rt_mmcsd_host *host, + rt_int32_t enable) +{ + sdio_dbg("jz47xx_sdio_enable_sdio_irq, enable:%d\n", enable); +} + +static const struct rt_mmcsd_host_ops ops = +{ + jz47xx_sdio_request, + jz47xx_sdio_set_iocfg, + jz47xx_SD_Detect, + jz47xx_sdio_enable_sdio_irq, +}; + +int jz47xx_sdio_init(void) +{ + struct rt_mmcsd_host *host = RT_NULL; + struct jz47xx_sdio * jz_sdio = RT_NULL; + +#ifdef RT_USING_MSC0 + host = mmcsd_alloc_host(); + jz_sdio = rt_malloc(sizeof(struct jz47xx_sdio)); + if(!(host && jz_sdio)) + { + goto err; + } + + rt_memset(jz_sdio, 0, sizeof(struct jz47xx_sdio)); + /* set hardware base firstly */ + jz_sdio->hw_base = MSC0_BASE; + jz_sdio->clock = clk_get("cgu_msc0"); + jz_sdio->clock_gate = clk_get("msc0"); + + /* init GPIO (msc0 boot) + * name pin fun + * X1000 MSC0_D0: PA23 1 + * X1000 MSC0_D1: PA22 1 + * X1000 MSC0_D2: PA21 1 + * X1000 MSC0_D3: PA20 1 + * X1000 MSC0_CMD: PA25 1 + * X1000 MSC0_CLK: PA24 1 + */ + { + gpio_set_func(GPIO_PORT_A, GPIO_Pin_20, GPIO_FUNC_1); + gpio_set_func(GPIO_PORT_A, GPIO_Pin_21, GPIO_FUNC_1); + gpio_set_func(GPIO_PORT_A, GPIO_Pin_22, GPIO_FUNC_1); + gpio_set_func(GPIO_PORT_A, GPIO_Pin_23, GPIO_FUNC_1); + gpio_set_func(GPIO_PORT_A, GPIO_Pin_24, GPIO_FUNC_1); + gpio_set_func(GPIO_PORT_A, GPIO_Pin_25, GPIO_FUNC_1); + } + + /* enable MSC0 clock gate. */ + clk_enable(jz_sdio->clock_gate); + + jz_sdio->msc_clock = 24UL * 1000 * 1000; /* 50Mhz */ + host->freq_min = 400 * 1000; /* min 400Khz. */ + host->freq_max = 24 * 1000 * 1000; /* max 50Mhz. */ + + /* set clock */ + clk_set_rate(jz_sdio->clock, BOARD_EXTAL_CLK); + + host->ops = &ops; + host->valid_ocr = VDD_27_28 | VDD_28_29 | VDD_29_30 | VDD_30_31 | VDD_31_32 | + VDD_32_33 | VDD_33_34 | VDD_34_35 | VDD_35_36; + host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE | MMCSD_SUP_HIGHSPEED; + host->max_seg_size = 65535; + host->max_dma_segs = 2; + host->max_blk_size = 512; + host->max_blk_count = 4096; + host->private_data = jz_sdio; + + jz_sdio->host = host; + jz_sdio->irqno = IRQ_MSC0; + + rt_hw_interrupt_install(jz_sdio->irqno, msc_handler, jz_sdio, "msc0"); + rt_hw_interrupt_mask(jz_sdio->irqno); + + mmcsd_change(host); +#endif // RT_USING_MSC0 + +#ifdef RT_USING_MSC1 + host = mmcsd_alloc_host(); + jz_sdio = rt_malloc(sizeof(struct jz47xx_sdio)); + if(!(host && jz_sdio)) + { + goto err; + } + + rt_memset(jz_sdio, 0, sizeof(struct jz47xx_sdio)); + jz_sdio->hw_base = MSC1_BASE; + jz_sdio->clock = clk_get("cgu_msc1"); + jz_sdio->clock_gate = clk_get("msc1"); + + /* init GPIO (paladin msc1 SDIO wifi) + * name pin fun + * X1000 MSC1_D0: PC02 0 + * X1000 MSC1_D1: PC03 0 + * X1000 MSC1_D2: PC04 0 + * X1000 MSC1_D3: PC05 0 + * X1000 MSC1_CMD: PC01 0 + * X1000 MSC1_CLK: PC00 0 + * + */ + { + gpio_set_func(GPIO_PORT_C, GPIO_Pin_0, GPIO_FUNC_0); + gpio_set_func(GPIO_PORT_C, GPIO_Pin_1, GPIO_FUNC_0); + gpio_set_func(GPIO_PORT_C, GPIO_Pin_2, GPIO_FUNC_0); + gpio_set_func(GPIO_PORT_C, GPIO_Pin_3, GPIO_FUNC_0); + gpio_set_func(GPIO_PORT_C, GPIO_Pin_4, GPIO_FUNC_0); + gpio_set_func(GPIO_PORT_C, GPIO_Pin_5, GPIO_FUNC_0); + } + + /* enable MSC1 clock gate. */ + clk_enable(jz_sdio->clock_gate); + + jz_sdio->msc_clock = 50UL * 1000 * 1000; /* 50Mhz */ + host->freq_min = 400 * 1000; /* min 400Khz. */ + host->freq_max = 50 * 1000 * 1000; /* max 50Mhz. */ + + /* set clock */ + clk_set_rate(jz_sdio->clock, BOARD_EXTAL_CLK); + + host->ops = &ops; + host->valid_ocr = VDD_27_28 | VDD_28_29 | VDD_29_30 | VDD_30_31 | VDD_31_32 | + VDD_32_33 | VDD_33_34 | VDD_34_35 | VDD_35_36; + host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE; + host->max_seg_size = 65535; + host->max_dma_segs = 2; + host->max_blk_size = 512; + host->max_blk_count = 4096; + host->private_data = jz_sdio; + + jz_sdio->host = host; + jz_sdio->irqno = IRQ_MSC1; + + rt_hw_interrupt_install(jz_sdio->irqno, msc_handler, jz_sdio, "msc1"); + rt_hw_interrupt_mask(jz_sdio->irqno); + + mmcsd_change(host); +#endif // RT_USING_MSC1 + + return RT_EOK; + +err: + if(host) + { + mmcsd_free_host(host); + } + if(jz_sdio) + { + rt_free(host); + } + + return -RT_ENOMEM; +} + diff --git a/bsp/x1000/driver/drv_mmc.h b/bsp/x1000/driver/drv_mmc.h new file mode 100644 index 0000000000000000000000000000000000000000..06f414344ccf8ff1461ed3e40c756c9d16e3be8e --- /dev/null +++ b/bsp/x1000/driver/drv_mmc.h @@ -0,0 +1,263 @@ +#ifndef DRV_MMC_H__ +#define DRV_MMC_H__ + +#include + +/* MSC configure */ +#define MMC_MSC_INTERRUPT_ENABLE 1 /* 0: disable, 1: enable. */ + +//-------------------------------------------------------------------------- +// MSC Registers Offset Definition +//-------------------------------------------------------------------------- +#define MSC_CTRL_OFFSET ( 0x00 ) // W, 16, 0x000, MSC Control register +#define MSC_STAT_OFFSET ( 0x04 ) // R, 32, 0x00000040, MSC Status register +#define MSC_CLKRT_OFFSET ( 0x08 ) // RW, 16, 0x0000, MSC Clock Rate register +#define MSC_CMDAT_OFFSET ( 0x0C ) // RW, 32, 0x00000000, MSC Command and Data Control register +#define MSC_RESTO_OFFSET ( 0x10 ) // RW, 16, 0x0040, MSC Response Time Out register +#define MSC_RDTO_OFFSET ( 0x14 ) // RW, 16, 0xFFFF, MSC Read Time Out register +#define MSC_BLKLEN_OFFSET ( 0x18 ) // RW, 16, 0x0000, MSC Block Length register +#define MSC_NOB_OFFSET ( 0x1C ) // RW, 16, 0x0000, MSC Number of Block register +#define MSC_SNOB_OFFSET ( 0x20 ) // R, 16, 0x????, MSC Number of Successfully-transferred Blocks register +#define MSC_IMASK_OFFSET ( 0x24 ) // RW, 32, 0x000000FF, MSC Interrupt Mask register +#define MSC_IREG_OFFSET ( 0x28 ) // RW, 16, 0x2000, MSC Interrupt register +#define MSC_CMD_OFFSET ( 0x2C ) // RW, 8, 0x00, MSC Command Index register +#define MSC_ARG_OFFSET ( 0x30 ) // RW, 32, 0x00000000, MSC Command Argument register +#define MSC_RES_OFFSET ( 0x34 ) // R, 16, 0x????, MSC Response FIFO register +#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 ) + +//-------------------------------------------------------------------------- +// MMC/SD Control Register field descriptions (MSC_CTRL) +//-------------------------------------------------------------------------- +#define MSC_CTRL_CLOCK_CONTROL_MASK ( 3 << 0 ) +#define MSC_CTRL_CLOCK_DONOTHING ( 0 << 0 ) +#define MSC_CTRL_CLOCK_STOP ( 1 << 0 ) +#define MSC_CTRL_CLOCK_START ( 2 << 0 ) + +#define MSC_CTRL_START_OP ( 1 << 2 ) +#define MSC_CTRL_RESET ( 1 << 3 ) +#define MSC_CTRL_STOP_RDWAIT ( 1 << 4 ) +#define MSC_CTRL_START_RDWAIT ( 1 << 5 ) +#define MSC_CTRL_EXIT_TRANSFER ( 1 << 6 ) +#define MSC_CTRL_EXIT_MULTIPLE ( 1 << 7 ) +#define MSC_CTRL_SEND_AS_CCSD ( 1 << 14 ) +#define MSC_CTRL_SEND_CCSD ( 1 << 15 ) + +//-------------------------------------------------------------------------- +// MSC Status Register field descriptions (MSC_STAT) +//-------------------------------------------------------------------------- + +#define MSC_STAT_TIME_OUT_READ ( 1 << 0 ) +#define MSC_STAT_TIME_OUT_RES ( 1 << 1 ) + +#define MSC_STAT_CRC_WRITE_ERR_MASK ( 3 << 2 ) +#define MSC_STAT_CRC_WRITE_NO_ERR ( 0 << 2 ) +#define MSC_STAT_CRC_WRITE_ERR ( 1 << 2 ) +#define MSC_STAT_CRC_WRITE_NO_STATUS ( 2 << 2 ) + +#define MSC_STAT_CRC_READ_ERR ( 1 << 4 ) + +#define MSC_CMDAT_RESP_FORMAT_MASK ( 7 << 0 ) + +#define MSC_STAT_CRC_RES_ERR ( 1 << 5 ) +#define MSC_STAT_DATA_FIFO_EMPTY ( 1 << 6 ) +#define MSC_STAT_DATA_FIFO_FULL ( 1 << 7 ) +#define MSC_STAT_CLK_EN ( 1 << 8 ) +#define MSC_STAT_IS_READWAIT ( 1 << 9 ) +#define MSC_STAT_DATA_FIFO_AFULL ( 1 << 10 ) +#define MSC_STAT_END_CMD_RES ( 1 << 11 ) +#define MSC_STAT_DATA_TRAN_DONE ( 1 << 12 ) +#define MSC_STAT_PRG_DONE ( 1 << 13 ) +#define MSC_STAT_SDIO_INT_ACTIVE ( 1 << 14 ) +#define MSC_STAT_IS_RESETTING ( 1 << 15 ) +#define MSC_STAT_AUTO_CMD_DONE ( 1 << 31 ) + +//-------------------------------------------------------------------------- +//MMC/SD Command and Data Control Register field descriptions (MSC_CMDAT) +//-------------------------------------------------------------------------- +#define MSC_CMDAT_RESP_FORMAT_MASK ( 7 << 0 ) +#define MSC_CMDAT_RESPONSE_NONE ( 0 << 0 )/* No response */ +#define MSC_CMDAT_RESPONSE_R1 ( 1 << 0 )/* Format R1 and R1b */ +#define MSC_CMDAT_RESPONSE_R2 ( 2 << 0 )/* Format R2 */ +#define MSC_CMDAT_RESPONSE_R3 ( 3 << 0 )/* Format R3 */ +#define MSC_CMDAT_RESPONSE_R4 ( 4 << 0 )/* Format R4 */ +#define MSC_CMDAT_RESPONSE_R5 ( 5 << 0 )/* Format R5 */ +#define MSC_CMDAT_RESPONSE_R6 ( 6 << 0 )/* Format R6 */ +#define MSC_CMDAT_RESPONSE_R7 ( 7 << 0 )/* Format R7 */ + +#define MSC_CMDAT_DATA_EN ( 1 << 3 ) +#define MSC_CMDAT_WRRD_MASK ( 1 << 4 ) +#define MSC_CMDAT_WRITE ( 1 << 4 ) +#define MSC_CMDAT_READ ( 0 << 4 ) +#define MSC_CMDAT_STREAM_BLOCK ( 1 << 5 ) +#define MSC_CMDAT_BUSY ( 1 << 6 ) +#define MSC_CMDAT_INIT ( 1 << 7 ) +#define MSC_CMDAT_DMA_EN ( 1 << 8 ) + +#define MSC_CMDAT_BUS_WIDTH_MASK ( 3 << 9 ) +#define MSC_CMDAT_BUS_WIDTH_1BIT ( 0 << 9 ) +#define MSC_CMDAT_BUS_WIDTH_4BIT ( 2 << 9 ) +#define MSC_CMDAT_BUS_WIDTH_8BIT ( 3 << 9 ) + +#define MSC_CMDAT_STOP_ABORT ( 1 << 11 ) + +#define MSC_CMDAT_TTRG_MASK ( 3 << 12 ) +#define MSC_CMDAT_TTRG_08 ( 0 << 12 ) +#define MSC_CMDAT_TTRG_16 ( 1 << 12 ) +#define MSC_CMDAT_TTRG_24 ( 2 << 12 ) + +#define MSC_CMDAT_RTRG_MASK ( 3 << 14 ) +#define MSC_CMDAT_RTRG_08 ( 0 << 14 ) +#define MSC_CMDAT_RTRG_16 ( 1 << 14 ) +#define MSC_CMDAT_RTRG_24 ( 2 << 14 ) + +#define MSC_CMDAT_SEND_AS_STOP ( 1 << 16 ) +#define MSC_CMDAT_SDIO_PRDT ( 1 << 17 ) +#define MSC_CMDAT_READ_CEATA ( 1 << 30 ) +#define MSC_CMDAT_CCS_EXPECTED ( 1 << 31 ) + +//-------------------------------------------------------------------------- +// IRQ Number descriptions +//-------------------------------------------------------------------------- +#define MSC_DATA_TRAN_DONE ( 1 << 0 ) +#define MSC_PRG_DONE ( 1 << 1 ) +#define MSC_END_CMD_RES ( 1 << 2 ) +#define MSC_RXFIFO_RD_REQ ( 1 << 5 ) +#define MSC_TXFIFO_WR_REQ ( 1 << 6 ) +#define MSC_SDIO ( 1 << 7 ) +#define MSC_TIME_OUT_READ ( 1 << 8 ) +#define MSC_TIME_OUT_RES ( 1 << 9 ) +#define MSC_CRC_WRITE_ERR ( 1 << 10 ) +#define MSC_CRC_READ_ERR ( 1 << 11 ) +#define MSC_CRC_RES_ERR ( 1 << 12 ) +#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 ) + +/* 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) + +/* 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) + +/* 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) + +/* 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) + +/* Error codes */ +enum mmc_result_t { + MMC_NO_RESPONSE = -1, + MMC_NO_ERROR = 0, + MMC_ERROR_OUT_OF_RANGE, + MMC_ERROR_ADDRESS, + MMC_ERROR_BLOCK_LEN, + MMC_ERROR_ERASE_SEQ, + MMC_ERROR_ERASE_PARAM, + MMC_ERROR_WP_VIOLATION, + MMC_ERROR_CARD_IS_LOCKED, + MMC_ERROR_LOCK_UNLOCK_FAILED, + MMC_ERROR_COM_CRC, + MMC_ERROR_ILLEGAL_COMMAND, + MMC_ERROR_CARD_ECC_FAILED, + MMC_ERROR_CC, + MMC_ERROR_GENERAL, + MMC_ERROR_UNDERRUN, + MMC_ERROR_OVERRUN, + MMC_ERROR_CID_CSD_OVERWRITE, + MMC_ERROR_STATE_MISMATCH, + MMC_ERROR_HEADER_MISMATCH, + MMC_ERROR_TIMEOUT, + MMC_ERROR_CRC, + MMC_ERROR_DRIVER_FAILURE, +}; + +struct jz47xx_sdio +{ + struct rt_mmcsd_host *host; + struct rt_mmcsd_req *req; + struct rt_mmcsd_cmd *cmd; + + uint32_t hw_base; + uint32_t msc_clock; + uint32_t irqno; + uint32_t flag; + + struct rt_completion completion; + + struct clk *clock; + struct clk *clock_gate; + + int sdio_clk; /* clock for sdio */ + rt_uint32_t current_status; +}; + + +#endif /* DRV_MMC_H__ */ + diff --git a/bsp/x1000/driver/drv_ost.c b/bsp/x1000/driver/drv_ost.c new file mode 100644 index 0000000000000000000000000000000000000000..181f72d6e1a6fe2bf37e829511b67e071591fb8f --- /dev/null +++ b/bsp/x1000/driver/drv_ost.c @@ -0,0 +1,79 @@ +/* + * File : board_timer.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ + +#include +#include +#include + +#include + +#include "board.h" +#include "drv_clock.h" +#include "drv_ost.h" + +/** + * This is the OST timer interrupt service routine. + */ +void rt_hw_ost_handler(void) +{ + /* increase a OS tick */ + rt_tick_increase(); + + /* clear flag */ + REG_OSTFR = 0; +} + +void rt_hw_ost_init(void) +{ + rt_uint32_t cnt, div; + struct clk *clk; + + div = OST_DIV16; + cnt = BOARD_EXTAL_CLK / 16; + + /* enable OST clock */ + clk = clk_get("sys_ost"); + clk_enable(clk); + + /* Disable OST (channel 1/2) */ + REG_OSTECR = 0x3; + + /* clear counter */ + REG_OSTCR = 0x01; + REG_OST1CNT = 0; + + /* set timer data (channel 1) */ + REG_OST1DFR = (cnt / RT_TICK_PER_SECOND - 1); + + /* set prescale ext clk */ + REG_OSTCCR = div; + + /* unmask interrupt */ + REG_OSTMR = 0; + + /* enable OST (channel 1) */ + REG_OSTESR = 0x01; + + clk_put(clk); +} diff --git a/bsp/x1000/driver/drv_ost.h b/bsp/x1000/driver/drv_ost.h new file mode 100644 index 0000000000000000000000000000000000000000..418ddae34ffdc68004c5d004f195350bde3ff4c4 --- /dev/null +++ b/bsp/x1000/driver/drv_ost.h @@ -0,0 +1,142 @@ +/* + * File : board_timer.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ + +#ifndef DRV_OST_H__ +#define DRV_OST_H__ + +#define TCU_TSTR (0xF0) /* Timer Status Register,Only Used In Tcu2 Mode */ +#define TCU_TSTSR (0xF4) /* Timer Status Set Register */ +#define TCU_TSTCR (0xF8) /* Timer Status Clear Register */ +#define TCU_TSR (0x1C) /* Timer Stop Register */ +#define TCU_TSSR (0x2C) /* Timer Stop Set Register */ +#define TCU_TSCR (0x3C) /* Timer Stop Clear Register */ +#define TCU_TER (0x10) /* Timer Counter Enable Register */ +#define TCU_TESR (0x14) /* Timer Counter Enable Set Register */ +#define TCU_TECR (0x18) /* Timer Counter Enable Clear Register */ +#define TCU_TFR (0x20) /* Timer Flag Register */ +#define TCU_TFSR (0x24) /* Timer Flag Set Register */ +#define TCU_TFCR (0x28) /* Timer Flag Clear Register */ +#define TCU_TMR (0x30) /* Timer Mask Register */ +#define TCU_TMSR (0x34) /* Timer Mask Set Register */ +#define TCU_TMCR (0x38) /* Timer Mask Clear Register */ + +#define CH_TDFR(n) (0x40 + (n)*0x10) /* Timer Data Full Reg */ +#define CH_TDHR(n) (0x44 + (n)*0x10) /* Timer Data Half Reg */ +#define CH_TCNT(n) (0x48 + (n)*0x10) /* Timer Counter Reg */ +#define CH_TCSR(n) (0x4C + (n)*0x10) /* Timer Control Reg */ + +#define REG_TCU_TSTR REG32(TCU_BASE + (0xF0)) +#define REG_TCU_TSTSR REG32(TCU_BASE + (0xF4)) +#define REG_TCU_TSTCR REG32(TCU_BASE + (0xF8)) +#define REG_TCU_TSR REG32(TCU_BASE + (0x1C)) +#define REG_TCU_TSSR REG32(TCU_BASE + (0x2C)) +#define REG_TCU_TSCR REG32(TCU_BASE + (0x3C)) +#define REG_TCU_TER REG32(TCU_BASE + (0x10)) +#define REG_TCU_TESR REG32(TCU_BASE + (0x14)) +#define REG_TCU_TECR REG16(TCU_BASE + (0x18)) +#define REG_TCU_TFR REG32(TCU_BASE + (0x20)) +#define REG_TCU_TFSR REG32(TCU_BASE + (0x24)) +#define REG_TCU_TFCR REG32(TCU_BASE + (0x28)) +#define REG_TCU_TMR REG32(TCU_BASE + (0x30)) +#define REG_TCU_TMSR REG32(TCU_BASE + (0x34)) +#define REG_TCU_TMCR REG32(TCU_BASE + (0x38)) + +#define REG_CH_TDFR(n) REG32(TCU_BASE + (0x40 + (n)*0x10)) +#define REG_CH_TDHR(n) REG32(TCU_BASE + (0x44 + (n)*0x10)) +#define REG_CH_TCNT(n) REG32(TCU_BASE + (0x48 + (n)*0x10)) +#define REG_CH_TCSR(n) REG32(TCU_BASE + (0x4C + (n)*0x10)) + +#define TER_OSTEN (1 << 15) /* enable the counter in ost */ +#define TMR_OSTM (1 << 15) /* ost comparison match interrupt mask */ +#define TFR_OSTF (1 << 15) /* ost interrupt flag */ +#define TSR_OSTS (1 << 15) /*the clock supplies to osts is stopped */ + +#define TSR_WDTS (1 << 16) /*the clock supplies to wdt is stopped */ + +// Register bits definitions +#define TSTR_REAL2 (1 << 18) /* only used in TCU2 mode */ +#define TSTR_REAL1 (1 << 17) /* only used in TCU2 mode */ +#define TSTR_BUSY2 (1 << 2) /* only used in TCU2 mode */ +#define TSTR_BUSY1 (1 << 1) /* only used in TCU2 mode */ + +#define TCSR_CNT_CLRZ (1 << 10) /* clear counter to 0, only used in TCU2 mode */ +#define TCSR_PWM_SD (1 << 9) /* shut down the pwm output only used in TCU1 mode */ +#define TCSR_PWM_HIGH (1 << 8) /* selects an initial output level for pwm output */ +#define TCSR_PWM_EN (1 << 7) /* pwm pin output enable */ + +/********************************************************************************************************* +** OST +*********************************************************************************************************/ + +#define REG_OSTCCR REG32(OST_BASE + 0x00) +#define REG_OSTER REG32(OST_BASE + 0x04) +#define REG_OSTCR REG32(OST_BASE + 0x08) +#define REG_OSTFR REG32(OST_BASE + 0x0C) +#define REG_OSTMR REG32(OST_BASE + 0x10) +#define REG_OST1DFR REG32(OST_BASE + 0x14) +#define REG_OST1CNT REG32(OST_BASE + 0x18) +#define REG_OST2CNTL REG32(OST_BASE + 0x20) +#define REG_OSTCNT2HBUF REG32(OST_BASE + 0x24) +#define REG_OSTESR REG32(OST_BASE + 0x34) +#define REG_OSTECR REG32(OST_BASE + 0x38) + +/* + * Operating system timer module(OST) address definition + */ + +#define OST_DR (0xE0) +#define OST_CNTL (0xE4) +#define OST_CNTH (0xE8) +#define OST_CSR (0xEC) +#define OST_CNTH_BUF (0xFC) + +#define REG_OST_DR REG32(OST_BASE + (0xE0)) +#define REG_OST_CNTL REG32(OST_BASE + (0xE4)) +#define REG_OST_CNTH REG32(OST_BASE + (0xE8)) +#define REG_OST_CSR REG16(OST_BASE + (0xEC)) +#define REG_OST_CNTH_BUF REG32(OST_BASE + (0xFC)) + +/* Operating system control register(OSTCSR) */ +#define OST_CSR_CNT_MD (1 << 15) + +#define CSR_EXT_EN (1 << 2) /* select extal as the timer clock input */ +#define CSR_RTC_EN (1 << 1) /* select rtcclk as the timer clock input */ +#define CSR_PCK_EN (1 << 0) /* select pclk as the timer clock input */ +#define CSR_CLK_MSK (0x7) + +#define CSR_DIV1 (0x0 << 3) +#define CSR_DIV4 (0x1 << 3) +#define CSR_DIV16 (0x2 << 3) +#define CSR_DIV64 (0x3 << 3) +#define CSR_DIV256 (0x4 << 3) +#define CSR_DIV1024 (0x5 << 3) +#define CSR_DIV_MSK (0x7 << 3) + +#define OST_DIV1 (0x0) +#define OST_DIV4 (0x1) +#define OST_DIV16 (0x2) + +void rt_hw_ost_init(void); + +#endif diff --git a/bsp/x1000/driver/drv_uart.c b/bsp/x1000/driver/drv_uart.c new file mode 100644 index 0000000000000000000000000000000000000000..ebe144e4b5837b3c7bbcbc1a7f782116af8c1a17 --- /dev/null +++ b/bsp/x1000/driver/drv_uart.c @@ -0,0 +1,264 @@ +/* + * File : drv_uart.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ +#include +#include +#include + +#include "board.h" +#include "drv_uart.h" + +struct jz_uart_s +{ + rt_uint32_t hw_base; + + rt_uint32_t irqno; + char name[RT_NAME_MAX]; +}; + +static rt_err_t uart_configure (struct rt_serial_device *serial, struct serial_configure *cfg); +static rt_err_t uart_control (struct rt_serial_device *serial, int cmd, void *arg); +static int uart_putc (struct rt_serial_device *serial, char c); +static int uart_getc (struct rt_serial_device *serial); +static rt_size_t uart_dma_transmit (struct rt_serial_device *serial, const rt_uint8_t *buf, rt_size_t size, int direction); + +static void uart_irq_handler (int irqno, void *param); + +const struct rt_uart_ops _uart_ops = +{ + uart_configure, + uart_control, + uart_putc, + uart_getc, + uart_dma_transmit +}; + +/* + * UART Initiation + */ +void rt_hw_uart_init(void) +{ + struct rt_serial_device *serial; + struct jz_uart_s *uart; + struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; + +#ifdef RT_USING_UART1 + { + static struct rt_serial_device serial1; + static struct jz_uart_s uart1; + + serial = &serial1; + uart = &uart1; + + serial->ops = &_uart_ops; + serial->config = config; + serial->config.baud_rate = 115200; + + uart->hw_base = UART0_BASE; + uart->irqno = IRQ_UART0; + + rt_hw_serial_register(serial, + "uart1", + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, + uart); + } +#endif + +#ifdef RT_USING_UART2 + { + static struct rt_serial_device serial2; + static struct jz_uart_s uart2; + + serial = &serial2; + uart = &uart2; + + serial->ops = &_uart_ops; + serial->config = config; + serial->config.baud_rate = 115200; + + uart->hw_base = UART2_BASE; + uart->irqno = IRQ_UART2; + + rt_hw_serial_register(serial, + "uart2", + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, + uart); + } +#endif + +#ifdef RT_USING_UART3 + { + static struct rt_serial_device serial3; + static struct jz_uart_s uart3; + + serial = &serial3; + uart = &uart3; + + serial->ops = &_uart_ops; + serial->config = config; + serial->config.baud_rate = 115200; + + uart->hw_base = UART3_BASE; + uart->irqno = IRQ_UART3; + + rt_hw_serial_register(serial, + "uart3", + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, + uart); + } +#endif +} + +/* + * UART interface + */ +static rt_err_t uart_configure (struct rt_serial_device *serial, struct serial_configure *cfg) +{ + rt_uint32_t baud_div; + struct jz_uart_s * uart; + + RT_ASSERT(serial != RT_NULL); + serial->config = *cfg; + + uart = serial->parent.user_data; + RT_ASSERT(uart != RT_NULL); + + /* Init UART Hardware */ + UART_IER(uart->hw_base) = 0; /* clear interrupt */ + UART_FCR(uart->hw_base) = ~UARTFCR_UUE; /* disable UART unite */ + + /* Enable UART clock */ + + /* Set both receiver and transmitter in UART mode (not SIR) */ + UART_SIRCR(uart->hw_base) = ~(SIRCR_RSIRE | SIRCR_TSIRE); + + /* Set databits, stopbits and parity. (8-bit data, 1 stopbit, no parity) */ + UART_LCR(uart->hw_base) = UARTLCR_WLEN_8; + + /* set baudrate */ + #if defined(RT_USING_JZ4750) || defined(RT_USING_JZ4755) || defined(RT_USING_JZ4760) + if(REG_CPM_CPCCR & (1UL << 30)) + { + /* CPCCR.ECS = 1: clock source is EXCLK/2 */ + baud_div = BOARD_EXTAL_CLK / 2 / 16 / cfg->baud_rate; + } + else + #endif + { + /* CPCCR.ECS = 0: clock source is EXCLK */ + baud_div = BOARD_EXTAL_CLK / 16 / cfg->baud_rate; + } + + UART_LCR(uart->hw_base) |= UARTLCR_DLAB; + UART_DLHR(uart->hw_base) = (baud_div >> 8) & 0xff; + UART_DLLR(uart->hw_base) = baud_div & 0xff; + + UART_LCR(uart->hw_base) &= ~UARTLCR_DLAB; + + /* Enable UART unit, enable and clear FIFO */ + UART_FCR(uart->hw_base) = UARTFCR_UUE | UARTFCR_FE | UARTFCR_TFLS | UARTFCR_RFLS; + + return (RT_EOK); +} + +static rt_err_t uart_control (struct rt_serial_device *serial, int cmd, void *arg) +{ + struct jz_uart_s * uart; + + uart = serial->parent.user_data; + + RT_ASSERT(uart != RT_NULL); + + switch (cmd) + { + case RT_DEVICE_CTRL_CLR_INT: + /* Disable the UART Interrupt */ + UART_IER(uart->hw_base) &= ~(UARTIER_RIE | UARTIER_RTIE); + rt_hw_interrupt_mask(uart->irqno); + break; + + case RT_DEVICE_CTRL_SET_INT: + /* install interrupt */ + rt_hw_interrupt_install(uart->irqno, uart_irq_handler, + serial, uart->name); + rt_hw_interrupt_umask(uart->irqno); + + /* Enable the UART Interrupt */ + UART_IER(uart->hw_base) |= (UARTIER_RIE | UARTIER_RTIE); + break; + } + + return (RT_EOK); +} + +static int uart_putc (struct rt_serial_device *serial, char c) +{ + struct jz_uart_s* uart; + + uart = serial->parent.user_data; + + /* FIFO status, contain valid data */ + while (!((UART_LSR(uart->hw_base) & (UARTLSR_TDRQ | UARTLSR_TEMT)) == 0x60)); + /* write data */ + UART_TDR(uart->hw_base) = c; + + return (1); +} + +static int uart_getc (struct rt_serial_device *serial) +{ + struct jz_uart_s* uart = serial->parent.user_data; + + /* Receive Data Available */ + if (UART_LSR(uart->hw_base) & UARTLSR_DR) + { + return UART_RDR(uart->hw_base); + } + + return (-1); +} + +static rt_size_t uart_dma_transmit (struct rt_serial_device *serial, const rt_uint8_t *buf, rt_size_t size, int direction) +{ + return (0); +} + +/* UART ISR */ +static void uart_irq_handler(int irqno, void *param) +{ + rt_ubase_t isr; + struct rt_serial_device *serial = (struct rt_serial_device*)param; + struct jz_uart_s* uart = serial->parent.user_data; + + /* read interrupt status and clear it */ + isr = UART_ISR(uart->hw_base); + if (isr & UARTISR_IID_RDI) /* Receive Data Available */ + { + rt_hw_serial_isr(serial,RT_SERIAL_EVENT_RX_IND); + } + + if(isr & UARTISR_IID_THRI) + { + rt_hw_serial_isr(serial,RT_SERIAL_EVENT_TX_DONE); + } +} diff --git a/bsp/x1000/driver/drv_uart.h b/bsp/x1000/driver/drv_uart.h new file mode 100644 index 0000000000000000000000000000000000000000..d03f93002050aef86e27478cde87cba6b5960799 --- /dev/null +++ b/bsp/x1000/driver/drv_uart.h @@ -0,0 +1,152 @@ +/* + * File : board_uart.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ + + +#ifndef _BOARD_UART_H_ +#define _BOARD_UART_H_ + +/* Uart Register */ +#define UART_RDR(base) REG8((base) + 0x00) /* R 8b H'xx */ +#define UART_TDR(base) REG8((base) + 0x00) /* W 8b H'xx */ +#define UART_DLLR(base) REG8((base) + 0x00) /* RW 8b H'00 */ +#define UART_DLHR(base) REG8((base) + 0x04) /* RW 8b H'00 */ +#define UART_IER(base) REG8((base) + 0x04) /* RW 8b H'00 */ +#define UART_ISR(base) REG8((base) + 0x08) /* R 8b H'01 */ +#define UART_FCR(base) REG8((base) + 0x08) /* W 8b H'00 */ +#define UART_LCR(base) REG8((base) + 0x0C) /* RW 8b H'00 */ +#define UART_MCR(base) REG8((base) + 0x10) /* RW 8b H'00 */ +#define UART_LSR(base) REG8((base) + 0x14) /* R 8b H'00 */ +#define UART_MSR(base) REG8((base) + 0x18) /* R 8b H'00 */ +#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 macros for UARTIER + * UART Interrupt Enable Register + */ +#define UARTIER_RIE (1 << 0) /* 0: receive fifo "full" interrupt disable */ +#define UARTIER_TIE (1 << 1) /* 0: transmit fifo "empty" interrupt disable */ +#define UARTIER_RLIE (1 << 2) /* 0: receive line status interrupt disable */ +#define UARTIER_MIE (1 << 3) /* 0: modem status interrupt disable */ +#define UARTIER_RTIE (1 << 4) /* 0: receive timeout interrupt disable */ + +/* + * Define macros for UARTISR + * UART Interrupt Status Register + */ +#define UARTISR_IP (1 << 0) /* 0: interrupt is pending 1: no interrupt */ +#define UARTISR_IID (7 << 1) /* Source of Interrupt */ +#define UARTISR_IID_MSI (0 << 1) /* Modem status interrupt */ +#define UARTISR_IID_THRI (1 << 1) /* Transmitter holding register empty */ +#define UARTISR_IID_RDI (2 << 1) /* Receiver data interrupt */ +#define UARTISR_IID_RLSI (3 << 1) /* Receiver line status interrupt */ +#define UARTISR_FFMS (3 << 6) /* FIFO mode select, set when UARTFCR.FE is set to 1 */ +#define UARTISR_FFMS_NO_FIFO (0 << 6) +#define UARTISR_FFMS_FIFO_MODE (3 << 6) + +/* + * Define macros for UARTFCR + * UART FIFO Control Register + */ +#define UARTFCR_FE (1 << 0) /* 0: non-FIFO mode 1: FIFO mode */ +#define UARTFCR_RFLS (1 << 1) /* write 1 to flush receive FIFO */ +#define UARTFCR_TFLS (1 << 2) /* write 1 to flush transmit FIFO */ +#define UARTFCR_DMS (1 << 3) /* 0: disable DMA mode */ +#define UARTFCR_UUE (1 << 4) /* 0: disable UART */ +#define UARTFCR_RTRG (3 << 6) /* Receive FIFO Data Trigger */ +#define UARTFCR_RTRG_1 (0 << 6) +#define UARTFCR_RTRG_4 (1 << 6) +#define UARTFCR_RTRG_8 (2 << 6) +#define UARTFCR_RTRG_15 (3 << 6) + +/* + * Define macros for UARTLCR + * UART Line Control Register + */ +#define UARTLCR_WLEN (3 << 0) /* word length */ +#define UARTLCR_WLEN_5 (0 << 0) +#define UARTLCR_WLEN_6 (1 << 0) +#define UARTLCR_WLEN_7 (2 << 0) +#define UARTLCR_WLEN_8 (3 << 0) +#define UARTLCR_STOP (1 << 2) /* 0: 1 stop bit when word length is 5,6,7,8 + 1: 1.5 stop bits when 5; 2 stop bits when 6,7,8 */ +#define UARTLCR_PE (1 << 3) /* 0: parity disable */ +#define UARTLCR_PROE (1 << 4) /* 0: even parity 1: odd parity */ +#define UARTLCR_SPAR (1 << 5) /* 0: sticky parity disable */ +#define UARTLCR_SBRK (1 << 6) /* write 0 normal, write 1 send break */ +#define UARTLCR_DLAB (1 << 7) /* 0: access UARTRDR/TDR/IER 1: access UARTDLLR/DLHR */ + +/* + * Define macros for UARTLSR + * UART Line Status Register + */ +#define UARTLSR_DR (1 << 0) /* 0: receive FIFO is empty 1: receive data is ready */ +#define UARTLSR_ORER (1 << 1) /* 0: no overrun error */ +#define UARTLSR_PER (1 << 2) /* 0: no parity error */ +#define UARTLSR_FER (1 << 3) /* 0; no framing error */ +#define UARTLSR_BRK (1 << 4) /* 0: no break detected 1: receive a break signal */ +#define UARTLSR_TDRQ (1 << 5) /* 1: transmit FIFO half "empty" */ +#define UARTLSR_TEMT (1 << 6) /* 1: transmit FIFO and shift registers empty */ +#define UARTLSR_RFER (1 << 7) /* 0: no receive error 1: receive error in FIFO mode */ + +/* + * Define macros for UARTMCR + * UART Modem Control Register + */ +#define UARTMCR_DTR (1 << 0) /* 0: DTR_ ouput high */ +#define UARTMCR_RTS (1 << 1) /* 0: RTS_ output high */ +#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_MCE (1 << 7) /* 0: modem function is disable */ + +/* + * Define macros for UARTMSR + * UART Modem Status Register + */ +#define UARTMSR_DCTS (1 << 0) /* 0: no change on CTS_ pin since last read of UARTMSR */ +#define UARTMSR_DDSR (1 << 1) /* 0: no change on DSR_ pin since last read of UARTMSR */ +#define UARTMSR_DRI (1 << 2) /* 0: no change on RI_ pin since last read of UARTMSR */ +#define UARTMSR_DDCD (1 << 3) /* 0: no change on DCD_ pin since last read of UARTMSR */ +#define UARTMSR_CTS (1 << 4) /* 0: CTS_ pin is high */ +#define UARTMSR_DSR (1 << 5) /* 0: DSR_ pin is high */ +#define UARTMSR_RI (1 << 6) /* 0: RI_ pin is high */ +#define UARTMSR_DCD (1 << 7) /* 0: DCD_ pin is high */ + +/* + * Define macros for SIRCR + * Slow IrDA Control Register + */ +#define SIRCR_TSIRE (1 << 0) /* 0: transmitter is in UART mode 1: IrDA mode */ +#define SIRCR_RSIRE (1 << 1) /* 0: receiver is in UART mode 1: IrDA mode */ +#define SIRCR_TPWS (1 << 2) /* 0: transmit 0 pulse width is 3/16 of bit length + 1: 0 pulse width is 1.6us for 115.2Kbps */ +#define SIRCR_TXPL (1 << 3) /* 0: encoder generates a positive pulse for 0 */ +#define SIRCR_RXPL (1 << 4) /* 0: decoder interprets positive pulse as 0 */ + +void rt_hw_uart_init(void); + +#endif /* _BOARD_UART_H_ */ diff --git a/bsp/x1000/rtconfig.h b/bsp/x1000/rtconfig.h new file mode 100644 index 0000000000000000000000000000000000000000..455cfcb11e3923c8d5cf71cc2d890b5fbfc5c434 --- /dev/null +++ b/bsp/x1000/rtconfig.h @@ -0,0 +1,217 @@ +#ifndef __RTTHREAD_CFG_H__ +#define __RTTHREAD_CFG_H__ + +// + +// +#define RT_NAME_MAX 8 +// +#define RT_ALIGN_SIZE 4 +// +// 8 +// 32 +// 256 +// +#define RT_THREAD_PRIORITY_MAX 32 +// +#define RT_TICK_PER_SECOND 100 +// +#define IDLE_THREAD_STACK_SIZE 1024 + +//
+#define RT_DEBUG +// +#define RT_DEBUG_SCHEDULER 0 +// +#define RT_USING_OVERFLOW_CHECK +//
+ +// +#define RT_USING_HOOK + +//
+// #define RT_USING_TIMER_SOFT +// +#define RT_TIMER_THREAD_PRIO 4 +// +#define RT_TIMER_THREAD_STACK_SIZE 512 +//
+ +//
+// +#define RT_USING_SEMAPHORE +// +#define RT_USING_MUTEX +// +#define RT_USING_EVENT +// +#define RT_USING_MAILBOX +// +#define RT_USING_MESSAGEQUEUE +//
+ +//
+// +#define RT_USING_MEMPOOL +// +// #define RT_USING_MEMHEAP +// +#define RT_USING_HEAP +// +#define RT_USING_SMALL_MEM +// +// #define RT_USING_SLAB +//
+ +//
+#define RT_USING_DEVICE +// +#define RT_USING_SERIAL +// +// #define RT_USING_SPI +// +#define RT_USING_DEVICE_IPC +// +#define RT_USING_SDIO +// +//#define RT_USING_USB_DEVICE +// +//#define RT_USB_DEVICE_CDC +//#define USB_VENDOR_ID 0x0483 +//#define USB_PRODUCT_ID 0x5740 +//
+ +//
+#define RT_USING_CONSOLE +// +#define RT_CONSOLEBUF_SIZE 128 +// +#define RT_CONSOLE_DEVICE_NAME "uart2" +//
+ +//
+#define RT_USING_FINSH +// +#define FINSH_USING_SYMTAB +// +#define FINSH_USING_DESCRIPTION +// +#define FINSH_THREAD_STACK_SIZE 4096 +// +#define FINSH_USING_MSH +// +#define FINSH_USING_MSH_DEFAULT +// +// #define FINSH_USING_MSH_ONLY +//
+ +//
+// +#define RT_USING_LIBC +// +#define RT_USING_PTHREADS +// +#define RT_USING_COMPONENTS_INIT +// +#define RT_USING_USER_MAIN +//
+ +//
+#define RT_USING_DFS +// +#define DFS_USING_WORKDIR +// +#define DFS_FILESYSTEMS_MAX 4 +// +#define DFS_FD_MAX 8 +// +#define RT_USING_DFS_ELMFAT +// +#define RT_DFS_ELM_DRIVES 4 +// +#define RT_DFS_ELM_REENTRANT +// +// 0 +// 1 +// 2 +// 3 +// +#define RT_DFS_ELM_USE_LFN 3 +// +#define RT_DFS_ELM_CODE_PAGE 437 +// +#define RT_DFS_ELM_MAX_LFN 256 +// +// #define RT_USING_DFS_YAFFS2 +// +// #define RT_USING_DFS_UFFS +// +#define RT_USING_DFS_DEVFS +// +// #define RT_USING_DFS_NFS +// +#define RT_NFS_HOST_EXPORT "192.168.1.5:/" +// +// #define RT_USING_DFS_LWIP +//
+ +//
+// #define RT_USING_LWIP +// +#define RT_LWIP_PBUF_POOL_BUFSIZE (1536) +// +#define RT_LWIP_ICMP +// +// #define RT_LWIP_IGMP +// +#define RT_LWIP_UDP +// +#define RT_LWIP_TCP +// +#define RT_LWIP_DNS +// +#define RT_LWIP_TCP_PCB_NUM 8 +// +#define RT_LWIP_TCP_SND_BUF 8192 +// +#define RT_LWIP_TCP_WND 8192 +// +// #define RT_LWIP_SNMP +// +#define RT_LWIP_DHCP +// +#define RT_LWIP_TCPTHREAD_PRIORITY 12 +// +#define RT_LWIP_TCPTHREAD_MBOX_SIZE 8 +// +#define RT_LWIP_TCPTHREAD_STACKSIZE 4096 +// +#define RT_LWIP_ETHTHREAD_PRIORITY 14 +// +#define RT_LWIP_ETHTHREAD_MBOX_SIZE 8 +// +#define RT_LWIP_ETHTHREAD_STACKSIZE 512 +// +#define RT_LWIP_IPADDR0 192 +#define RT_LWIP_IPADDR1 168 +#define RT_LWIP_IPADDR2 10 +#define RT_LWIP_IPADDR3 222 +// +#define RT_LWIP_GWADDR0 192 +#define RT_LWIP_GWADDR1 168 +#define RT_LWIP_GWADDR2 10 +#define RT_LWIP_GWADDR3 1 +// +#define RT_LWIP_MSKADDR0 255 +#define RT_LWIP_MSKADDR1 255 +#define RT_LWIP_MSKADDR2 255 +#define RT_LWIP_MSKADDR3 0 +//
+ +//
+ +#define RT_USING_CPU_FFS +#define RT_CFG_MAX_DMA_CHANNELS 8 + +#endif + diff --git a/bsp/x1000/rtconfig.py b/bsp/x1000/rtconfig.py new file mode 100644 index 0000000000000000000000000000000000000000..628fa71db4b14087cb885b448c739493d8f6145f --- /dev/null +++ b/bsp/x1000/rtconfig.py @@ -0,0 +1,57 @@ +import os + +# toolchains options +ARCH ='mips' +CPU ='xburst' +CROSS_TOOL ='gcc' + +if os.getenv('RTT_ROOT'): + RTT_ROOT = os.getenv('RTT_ROOT') +else: + RTT_ROOT = r'../..' + +if os.getenv('RTT_CC'): + CROSS_TOOL = os.getenv('RTT_CC') + +if CROSS_TOOL == 'gcc': + PLATFORM = 'gcc' + EXEC_PATH = r'c:/embStudio/tools/mips-2015.11/bin' +else: + print 'Please make sure your toolchains is GNU GCC!' + exit(0) + +if os.getenv('RTT_EXEC_PATH'): + EXEC_PATH = os.getenv('RTT_EXEC_PATH') + +BUILD = 'debug' + +if PLATFORM == 'gcc': + # toolchains + PREFIX = 'mips-sde-elf-' + CC = PREFIX + 'gcc' + CXX = PREFIX + 'g++' + AS = PREFIX + 'gcc' + AR = PREFIX + 'ar' + LINK = PREFIX + 'gcc' + TARGET_EXT = 'elf' + SIZE = PREFIX + 'size' + OBJDUMP = PREFIX + 'objdump' + OBJCPY = PREFIX + 'objcopy' + + DEVICE = ' -mips32 -msoft-float' + CFLAGS = DEVICE + ' -EL -G0 -mno-abicalls -fno-pic -fno-builtin -fno-exceptions -ffunction-sections -fomit-frame-pointer' + AFLAGS = ' -c' + DEVICE + ' -EL -x assembler-with-cpp' + LFLAGS = DEVICE + ' -EL -Wl,--gc-sections,-Map=rtthread_x1000.map,-cref,-u,Reset_Handler -T x1000_ram.lds' + CPATH = '' + LPATH = '' + + if BUILD == 'debug': + CFLAGS += ' -O0 -gdwarf-2' + AFLAGS += ' -gdwarf-2' + else: + CFLAGS += ' -O2' + + CXXFLAGS = CFLAGS + +DUMP_ACTION = OBJDUMP + ' -D -S $TARGET > rtt.asm\n' +POST_ACTION = OBJCPY + ' -O binary $TARGET rtthread.bin\n' + SIZE + ' $TARGET \n' diff --git a/bsp/x1000/x1000_ram.lds b/bsp/x1000/x1000_ram.lds new file mode 100644 index 0000000000000000000000000000000000000000..9c575903ecfcf6abc6b03703f6d1f5f2981f9e1a --- /dev/null +++ b/bsp/x1000/x1000_ram.lds @@ -0,0 +1,178 @@ +/* + * File : x1000_ram.lds + * COPYRIGHT (C) 2015, 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: + * 2015-12-12 bernard first version + */ + +OUTPUT_FORMAT("elf32-tradlittlemips", "elf32-tradlittlemips", "elf32-tradlittlemips") +OUTPUT_ARCH(mips) + +MEMORY +{ + /* 16M SDRAM */ + DRAM : ORIGIN = 0x80800000, LENGTH = 0x01800000 + /* 16K SRAM */ + IRAM : ORIGIN = 0x80000000, LENGTH = 0x00004000 +} + +ENTRY(_start) +SECTIONS +{ + . = 0x80800000 ; + + .start : + { + *(.start); + } > DRAM + + . = ALIGN(4); + + .text : + { + *(.text) /* remaining code */ + *(.text.*) /* remaining code */ + *(.rodata) /* read-only data (constants) */ + *(.rodata*) + *(.glue_7) + *(.glue_7t) + *(.gnu.linkonce.t*) + + /* section information for finsh shell */ + . = ALIGN(4); + __fsymtab_start = .; + KEEP(*(FSymTab)) + __fsymtab_end = .; + . = ALIGN(4); + __vsymtab_start = .; + KEEP(*(VSymTab)) + __vsymtab_end = .; + . = ALIGN(4); + + /* section information for initial. */ + . = ALIGN(4); + __rt_init_start = .; + KEEP(*(SORT(.rti_fn*))) + __rt_init_end = .; + . = ALIGN(4); + + . = ALIGN(4); + _etext = .; + } > DRAM + + .eh_frame_hdr : + { + *(.eh_frame_hdr) + *(.eh_frame_entry) + } > DRAM + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } > DRAM + + . = ALIGN(4); + + .data : + { + *(.data) + *(.data.*) + + *(.data1) + *(.data1.*) + + . = ALIGN(8); + _gp = ABSOLUTE(.); /* Base of small data */ + + *(.sdata) + *(.sdata.*) + } > DRAM + + . = ALIGN(4); + _iramat = .; + + .iram : AT(_iramat) + { + _iramstart = .; + *(.vectors.1); + . = 0x100; + *(.vectors.2); + . = 0x180; + *(.vectors.3); + . = 0x200; + *(.vectors.4); + *(.vectors); + + *(.icode); + *(.irodata); + *(.idata); + KEEP(*(.vectors*)) + _iramend = .; + } > IRAM + _iramcopy = LOADADDR(.iram); + + .sbss : + { + __bss_start = .; + *(.sbss) + *(.sbss.*) + *(.dynsbss) + *(.scommon) + } > DRAM + + .bss : + { + *(.bss) + *(.bss.*) + *(.dynbss) + *(COMMON) + __bss_end = .; + } > DRAM + + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + * Symbols in the DWARF debugging sections are relative to the beginning + * of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/libcpu/mips/xburst/SConscript b/libcpu/mips/xburst/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..0f06c299bbfa2cd38544869657c7b3e51149261a --- /dev/null +++ b/libcpu/mips/xburst/SConscript @@ -0,0 +1,11 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') + Glob('*.S') +CPPPATH = [cwd] + +group = DefineGroup('CPU', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/libcpu/mips/xburst/cache.c b/libcpu/mips/xburst/cache.c new file mode 100644 index 0000000000000000000000000000000000000000..cd37f69993db071ab9b4f64e73b5b58bb6b4736b --- /dev/null +++ b/libcpu/mips/xburst/cache.c @@ -0,0 +1,118 @@ +/* + * File : cache.c + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes +*/ + +#include "../xburst/cache.h" + +#include + +#define CACHE_SIZE 16*1024 +#define CACHE_LINE_SIZE 32 +#define KSEG0 0x80000000 + +#define K0_TO_K1() \ +do { \ + unsigned long __k0_addr; \ + \ + __asm__ __volatile__( \ + "la %0, 1f\n\t" \ + "or %0, %0, %1\n\t" \ + "jr %0\n\t" \ + "nop\n\t" \ + "1: nop\n" \ + : "=&r"(__k0_addr) \ + : "r" (0x20000000) ); \ +} while(0) + +#define K1_TO_K0() \ +do { \ + unsigned long __k0_addr; \ + __asm__ __volatile__( \ + "nop;nop;nop;nop;nop;nop;nop\n\t" \ + "la %0, 1f\n\t" \ + "jr %0\n\t" \ + "nop\n\t" \ + "1: nop\n" \ + : "=&r" (__k0_addr)); \ +} while (0) + +#define INVALIDATE_BTB() \ +do { \ + unsigned long tmp; \ + __asm__ __volatile__( \ + ".set mips32\n\t" \ + "mfc0 %0, $16, 7\n\t" \ + "nop\n\t" \ + "ori %0, 2\n\t" \ + "mtc0 %0, $16, 7\n\t" \ + "nop\n\t" \ + ".set mips2\n\t" \ + : "=&r" (tmp)); \ +} while (0) + +#define SYNC_WB() __asm__ __volatile__ ("sync") + +#define cache_op(op,addr) \ + __asm__ __volatile__( \ + " .set noreorder \n" \ + " .set mips32\n\t \n" \ + " cache %0, %1 \n" \ + " .set mips0 \n" \ + " .set reorder" \ + : \ + : "i" (op), "m" (*(unsigned char *)(addr))) + +void __icache_invalidate_all(void) +{ + unsigned int i; + + K0_TO_K1(); + + asm volatile (".set noreorder\n" + ".set mips32\n\t" + "mtc0\t$0,$28\n\t" + "mtc0\t$0,$29\n" + ".set mips0\n" + ".set reorder\n"); + for (i=KSEG0;i from + * a1 --> to + */ + .globl rt_hw_context_switch +rt_hw_context_switch: + mtc0 ra, CP0_EPC + SAVE_ALL + + sw sp, 0(a0) /* store sp in preempted tasks TCB */ + lw sp, 0(a1) /* get new task stack pointer */ + + RESTORE_ALL_AND_RET + +/* + * void rt_hw_context_switch_to(rt_uint32 to)/* + * a0 --> to + */ + .globl rt_hw_context_switch_to +rt_hw_context_switch_to: + lw sp, 0(a0) /* get new task stack pointer */ + + RESTORE_ALL_AND_RET + +/* + * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to)/* + */ + .globl rt_thread_switch_interrupt_flag + .globl rt_interrupt_from_thread + .globl rt_interrupt_to_thread + .globl rt_hw_context_switch_interrupt +rt_hw_context_switch_interrupt: + la t0, rt_thread_switch_interrupt_flag + lw t1, 0(t0) + nop + bnez t1, _reswitch + nop + li t1, 0x01 /* set rt_thread_switch_interrupt_flag to 1 */ + sw t1, 0(t0) + la t0, rt_interrupt_from_thread /* set rt_interrupt_from_thread */ + sw a0, 0(t0) +_reswitch: + la t0, rt_interrupt_to_thread /* set rt_interrupt_to_thread */ + sw a1, 0(t0) + jr ra + nop + + .globl system_dump + +/* + * void rt_hw_context_switch_interrupt_do(rt_base_t flag) + */ + .globl rt_interrupt_enter + .globl rt_interrupt_leave + .globl mips_irq_handle +mips_irq_handle: + SAVE_ALL + + mfc0 t0, CP0_CAUSE + mfc0 t1, CP0_STATUS + and t0, t1 + + andi t0, 0xff00 + beqz t0, spurious_interrupt + nop + + /* let k0 keep the current context sp */ + move k0, sp + /* switch to kernel stack */ + li sp, SYSTEM_STACK + + jal rt_interrupt_enter + nop + jal rt_interrupt_dispatch + nop + jal rt_interrupt_leave + nop + + /* switch sp back to thread's context */ + move sp, k0 + + /* + * if rt_thread_switch_interrupt_flag set, jump to + * rt_hw_context_switch_interrupt_do and don't return + */ + la k0, rt_thread_switch_interrupt_flag + lw k1, 0(k0) + beqz k1, spurious_interrupt + nop + sw zero, 0(k0) /* clear flag */ + nop + + /* + * switch to the new thread + */ + la k0, rt_interrupt_from_thread + lw k1, 0(k0) + nop + sw sp, 0(k1) /* store sp in preempted tasks's TCB */ + + la k0, rt_interrupt_to_thread + lw k1, 0(k0) + nop + lw sp, 0(k1) /* get new task's stack pointer */ + j spurious_interrupt + nop + +spurious_interrupt: + RESTORE_ALL_AND_RET + + .set reorder diff --git a/libcpu/mips/xburst/cpu.c b/libcpu/mips/xburst/cpu.c new file mode 100644 index 0000000000000000000000000000000000000000..88137535d95a6dbb102f1e1085a384703c9ddb91 --- /dev/null +++ b/libcpu/mips/xburst/cpu.c @@ -0,0 +1,75 @@ +/* + * File : cpu.c + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2010-07-09 Bernard first version + * 2010-09-11 Bernard add CPU reset implementation + */ +#include +#include + +/** + * @addtogroup Ingenic + */ +/*@{*/ + +/** + * this function will reset CPU + * + */ +void rt_hw_cpu_reset() +{ + /* open the watch-dog */ + REG_WDT_TCSR = WDT_TCSR_EXT_EN; + REG_WDT_TCSR |= WDT_TCSR_PRESCALE_1024; + REG_WDT_TDR = 0x03; + REG_WDT_TCNT = 0x00; + REG_WDT_TCER |= WDT_TCER_TCEN; + + rt_kprintf("reboot system...\n"); + while (1); +} + +/** + * this function will shutdown CPU + * + */ +void rt_hw_cpu_shutdown() +{ + rt_kprintf("shutdown...\n"); + + while (1); +} + +/** + * This function finds the first bit set (beginning with the least significant bit) + * in value and return the index of that bit. + * + * Bits are numbered starting at 1 (the least significant bit). A return value of + * zero from any of these functions means that the argument was zero. + * + * @return return the index of the first bit set. If value is 0, then this function + * shall return 0. + */ +int __rt_ffs(int value) +{ + return __builtin_ffs(value); +} + +/*@}*/ diff --git a/libcpu/mips/xburst/exception.c b/libcpu/mips/xburst/exception.c new file mode 100644 index 0000000000000000000000000000000000000000..aebdf704ea18658429bb00f0bdd91320ea5448c9 --- /dev/null +++ b/libcpu/mips/xburst/exception.c @@ -0,0 +1,81 @@ +/* + * File : exception.c + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2010-05-17 swkyer first version + */ +#include +#include +#include "../common/exception.h" +#include "../common/mipsregs.h" + +/** + * @addtogroup Ingenic + */ +/*@{*/ + +/** + * exception handle table + */ +exception_func_t sys_exception_handlers[33]; + +/** + * setup the exception handle + */ +exception_func_t rt_set_except_vector(int n, exception_func_t func) +{ + exception_func_t old_handler = sys_exception_handlers[n]; + + if ((n == 0) || (n > 32) || (!func)) + { + return 0; + } + + sys_exception_handlers[n] = func; + + return old_handler; +} + +void tlb_refill_handler(void) +{ + rt_kprintf("tlb-miss happens, epc: 0x%08x\n", read_c0_epc()); + rt_hw_cpu_shutdown(); +} + +void cache_error_handler(void) +{ + rt_kprintf("cache exception happens, epc: 0x%08x\n", read_c0_epc()); + rt_hw_cpu_shutdown(); +} + +static void unhandled_exception_handle(pt_regs_t *regs) +{ + rt_kprintf("exception happens, epc: 0x%08x\n", regs->cp0_epc); +} + +void install_default_execpt_handle(void) +{ + rt_int32_t i; + + for (i=0; i<33; i++) + sys_exception_handlers[i] = (exception_func_t)unhandled_exception_handle; +} + +/*@}*/ + diff --git a/libcpu/mips/xburst/interrupt.c b/libcpu/mips/xburst/interrupt.c new file mode 100644 index 0000000000000000000000000000000000000000..4d39c8f62151dc4e127209eaac244f83d6852dd5 --- /dev/null +++ b/libcpu/mips/xburst/interrupt.c @@ -0,0 +1,249 @@ +/* + * File : interrupt.c + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * 2010-07-09 Bernard first version + * 2013-03-29 aozima Modify the interrupt interface implementations. + */ + +#include +#include +#include + +#if defined(RT_USING_JZ4770) || defined(RT_USING_JZ4775) || defined(RT_USING_JZ_M150) || defined(RT_USING_JZ_X1000) +#define INTERRUPTS_MAX 64 +#else +#define INTERRUPTS_MAX 32 +#endif + +extern rt_uint32_t rt_interrupt_nest; +rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread; +rt_uint32_t rt_thread_switch_interrupt_flag; + +static struct rt_irq_desc isr_table[INTERRUPTS_MAX]; + +/** + * @addtogroup Ingenic + */ +/*@{*/ + +static void rt_hw_interrupt_handler(int vector, void *param) +{ + rt_kprintf("Unhandled interrupt %d occured!!!\n", vector); +} + +/** + * This function will initialize hardware interrupt + */ +void rt_hw_interrupt_init(void) +{ + rt_int32_t idx; + + rt_memset(isr_table, 0x00, sizeof(isr_table)); + for (idx = 0; idx < INTERRUPTS_MAX; idx ++) + { + isr_table[idx].handler = rt_hw_interrupt_handler; + } + + /* init interrupt nest, and context in thread sp */ + rt_interrupt_nest = 0; + rt_interrupt_from_thread = 0; + rt_interrupt_to_thread = 0; + rt_thread_switch_interrupt_flag = 0; +} + +/** + * This function will mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_mask(int vector) +{ + /* mask interrupt */ + __intc_mask_irq(vector); +} + +/** + * This function will un-mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_umask(int vector) +{ + __intc_unmask_irq(vector); +} + +/** + * This function will install a interrupt service routine to a interrupt. + * @param vector the interrupt number + * @param handler the interrupt service routine to be installed + * @param param the interrupt service function parameter + * @param name the interrupt name + * @return old handler + */ +rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, + void *param, char *name) +{ + rt_isr_handler_t old_handler = RT_NULL; + + if(vector < INTERRUPTS_MAX) + { + old_handler = isr_table[vector].handler; + +#ifdef RT_USING_INTERRUPT_INFO + rt_strncpy(isr_table[vector].name, name, RT_NAME_MAX); +#endif /* RT_USING_INTERRUPT_INFO */ + isr_table[vector].handler = handler; + isr_table[vector].param = param; + } + + return old_handler; +} + +#if defined(RT_USING_JZ4770) || defined(RT_USING_JZ4775) || defined(RT_USING_JZ_M150) || defined(RT_USING_JZ_X1000) +/* + * fls - find last bit set. + * @word: The word to search + * + * This is defined the same way as ffs. + * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. + */ +rt_inline int fls(int x) +{ + __asm__("clz %0, %1" : "=r" (x) : "r" (x)); + + return 32 - x; +} +#endif + +#include + +void rt_interrupt_dispatch(void *ptreg) +{ + int i; + void *param; + rt_isr_handler_t irq_func; + +#if defined(RT_USING_JZ4770) || defined(RT_USING_JZ4775) || defined(RT_USING_JZ_M150) || defined(RT_USING_JZ_X1000) + int irq = 0, group; + rt_uint32_t intc_ipr0 = 0, intc_ipr1 = 0, vpu_pending = 0; + + rt_uint32_t c0_status, c0_cause; + rt_uint32_t pending_im; + + /* check os timer */ + c0_status = read_c0_status(); + c0_cause = read_c0_cause(); + + pending_im = (c0_cause & ST0_IM) & (c0_status & ST0_IM); + + if (pending_im & CAUSEF_IP3) + { + extern void rt_hw_ost_handler(void); + rt_hw_ost_handler(); + return; + } + + if (pending_im & CAUSEF_IP2) + { + intc_ipr0 = REG_INTC_IPR(0); + intc_ipr1 = REG_INTC_IPR(1); + + if (intc_ipr0) + { + irq = fls(intc_ipr0) - 1; + intc_ipr0 &= ~(1<= INTERRUPTS_MAX) + rt_kprintf("max interrupt, irq=%d\n", irq); + + /* do interrupt */ + irq_func = isr_table[irq].handler; + param = isr_table[irq].param; + (*irq_func)(irq, param); + +#ifdef RT_USING_INTERRUPT_INFO + isr_table[i].counter++; +#endif /* RT_USING_INTERRUPT_INFO */ + + /* ack interrupt */ + __intc_ack_irq(irq); + } + + if (pending_im & CAUSEF_IP0) + rt_kprintf("CAUSEF_IP0\n"); + if (pending_im & CAUSEF_IP1) + rt_kprintf("CAUSEF_IP1\n"); + if (pending_im & CAUSEF_IP4) + rt_kprintf("CAUSEF_IP4\n"); + if (pending_im & CAUSEF_IP5) + rt_kprintf("CAUSEF_IP5\n"); + if (pending_im & CAUSEF_IP6) + rt_kprintf("CAUSEF_IP6\n"); + if (pending_im & CAUSEF_IP7) + rt_kprintf("CAUSEF_IP7\n"); +#else + static rt_uint32_t pending = 0; + + /* the hardware interrupt */ + pending |= REG_INTC_IPR; + if (!pending) return; + + for (i = INTERRUPTS_MAX; i > 0; --i) + { + if ((pending & (1< +#include "../common/mipsregs.h" +#include "../common/mipscfg.h" + +mips32_core_cfg_t g_mips_core = +{ + 16, /* icache_line_size */ + 256, /* icache_lines_per_way */ + 4, /* icache_ways */ + 16, /* dcache_line_size */ + 256, /* dcache_lines_per_way */ + 4, /* dcache_ways */ + 16, /* max_tlb_entries */ +}; + +static rt_uint16_t m_pow(rt_uint16_t b, rt_uint16_t n) +{ + rt_uint16_t rets = 1; + + while (n--) + rets *= b; + + return rets; +} + +/** + * read core attribute + */ +void mips32_cfg_init(void) +{ + rt_uint16_t val; + rt_uint32_t cp0_config1; + + cp0_config1 = read_c0_config(); + if (cp0_config1 & 0x80000000) + { + cp0_config1 = read_c0_config1(); + + val = (cp0_config1 & (7<<22))>>22; + g_mips_core.icache_lines_per_way = 64 * m_pow(2, val); + val = (cp0_config1 & (7<<19))>>19; + g_mips_core.icache_line_size = 2 * m_pow(2, val); + val = (cp0_config1 & (7<<16))>>16; + g_mips_core.icache_ways = val + 1; + + val = (cp0_config1 & (7<<13))>>13; + g_mips_core.dcache_lines_per_way = 64 * m_pow(2, val); + val = (cp0_config1 & (7<<10))>>10; + g_mips_core.dcache_line_size = 2 * m_pow(2, val); + val = (cp0_config1 & (7<<7))>>7; + g_mips_core.dcache_ways = val + 1; + + val = (cp0_config1 & (0x3F<<25))>>25; + g_mips_core.max_tlb_entries = val + 1; + } +} + +#ifdef RT_USING_FINSH +#include +static void CP0_status_analyze(unsigned long value) +{ + if(value & (1<<26)) + rt_kprintf(" FR"); + if(value & (1<<23)) + rt_kprintf(" PX"); + if(value & (1<<22)) + rt_kprintf(" BEV"); + if(value & (1<<20)) + rt_kprintf(" SR"); + if(value & (1<<19)) + rt_kprintf(" NMI"); + if(value & (1<<20)) + rt_kprintf(" SR"); + if(value & (0xFF<<8)) + rt_kprintf(" IM:0x%02X", (value >> 8) & 0xFF); + if(value & (1<<7)) + rt_kprintf(" KX"); + if(value & (1<<6)) + rt_kprintf(" SX"); + if(value & (1<<5)) + rt_kprintf(" UX"); + if(value & (0x03<<3)) + rt_kprintf(" KSU:0x%02X", (value >> 3) & 0x03); + if(value & (1<<2)) + rt_kprintf(" ERL"); + if(value & (1<<1)) + rt_kprintf(" EXL"); + if(value & (1<<0)) + rt_kprintf(" IE"); +} + +static void CP0_config0_analyze(unsigned long value) +{ + /* [31] M */ + if(value & (1UL<<31)) + rt_kprintf(" M"); + + /* [15] BE */ + if(value & (1<<15)) + rt_kprintf(" big-endian"); + else + rt_kprintf(" little-endian"); + + /* [14:13] AT */ + { + int AT = (value >> 13) & 0x03; + + if(AT == 0) + { + rt_kprintf(" MIPS32"); + } + else if(AT == 1) + { + rt_kprintf(" MIPS64/A32"); + } + else if(AT == 2) + { + rt_kprintf(" MIPS64/A64"); + } + else + { + rt_kprintf(" unkown"); + } + } + + /* [12:10] AR */ + { + int AR = (value >> 10) & 0x07; + + if(AR == 0) + { + rt_kprintf(" R1"); + } + else if(AR == 1) + { + rt_kprintf(" R2"); + } + else + { + rt_kprintf(" reserve"); + } + } + + /* [3] VI */ + if(value & (1UL<<31)) + rt_kprintf(" VI"); + + /* [2:0] K0 */ + { + int K0 = value & 0x07; + + if(K0 == 2) + { + rt_kprintf(" uncached"); + } + else if(K0 == 3) + { + rt_kprintf(" cacheable"); + } + else + { + rt_kprintf(" K0:reserve"); + } + } +} + +static void CP0_config1_analyze(unsigned long value) +{ + /* [31] M */ + if(value & (1UL<<31)) + rt_kprintf(" M"); + + /* [30:25] MMU size */ + { + int MMU_size = (value >> 25) & 0x3F; + rt_kprintf(" TLB:%d", MMU_size + 1); + } + + /* [24:22] IS, [21:19] IL, [18:16] IA */ + { + int IS = (value >> 22) & 0x07; + int IL = (value >> 19) & 0x07; + int IA = (value >> 16) & 0x07; + + IA = IA + 1; + IS = 64 << IS; + IL = 2 << IL; + rt_kprintf(" Icache-%dKB:%dway*%dset*%dbyte", + (IA*IS*IL) >> 10, IA, IS, IL); + } + + /* [15:13] DS, [12:10] DL, [9:7] DA */ + { + int DS = (value >> 13) & 0x07; + int DL = (value >> 10) & 0x07; + int DA = (value >> 7) & 0x07; + + DA = DA + 1; + DS = 64 << DS; + DL = 2 << DL; + rt_kprintf(" Dcache-%dKB:%dway*%dset*%dbyte", + (DA*DS*DL) >> 10, DA, DS, DL); + } + + /* [6] C2 */ + if(value & (1UL<<6)) + rt_kprintf(" CP2"); + + /* [5] MD */ + if(value & (1UL<<5)) + rt_kprintf(" MDMX-ASE"); + + /* [4] PC */ + if(value & (1UL<<4)) + rt_kprintf(" performa-count"); + + /* [3] WR */ + if(value & (1UL<<3)) + rt_kprintf(" Watch"); + + /* [2] CA */ + if(value & (1UL<<2)) + rt_kprintf(" MIPS16e"); + + /* [1] EP */ + if(value & (1UL<<1)) + rt_kprintf(" EJTAG"); + + /* [0] FP */ + if(value & (1UL<<0)) + rt_kprintf(" FPU"); +} + +static void CP0_config2_analyze(unsigned long value) +{ + /* [31] M */ + if(value & (1UL<<31)) + rt_kprintf(" M"); +} + +static void CP0_config3_analyze(unsigned long value) +{ + /* [31] M */ + if(value & (1UL<<31)) + rt_kprintf(" M"); +} + +static void list_mips(void) +{ + unsigned long value; + unsigned long num = 0; + + rt_kprintf("MIPS coprocessor register:\r\n"); + + rt_kprintf("( 0,0) INDEX : 0x%08X\r\n", read_c0_index()); + rt_kprintf("( 1,0) RANDOM : 0x%08X\r\n", read_c0_random()); + rt_kprintf("( 2,0) ENTRYLO0 : 0x%08X\r\n", read_c0_entrylo0()); + rt_kprintf("( 3,0) ENTRYLO1 : 0x%08X\r\n", read_c0_entrylo1()); + rt_kprintf("( 4,0) CONTEXT : 0x%08X\r\n", read_c0_context()); + rt_kprintf("( 5,0) PAGEMASK : 0x%08X\r\n", read_c0_pagemask()); + rt_kprintf("( 6,0) WIRED : 0x%08X\r\n", read_c0_wired()); + rt_kprintf("( 7,0) INFO : 0x%08X\r\n", read_c0_info()); + rt_kprintf("( 8,0) BADVADDR : 0x%08X\r\n", read_c0_badvaddr()); + rt_kprintf("( 9,0) COUNT : 0x%08X\r\n", read_c0_count()); + rt_kprintf("(10,0) ENTRYHI : 0x%08X\r\n", read_c0_entryhi()); + rt_kprintf("(11,0) COMPARE : 0x%08X\r\n", read_c0_compare()); + + value = read_c0_status(); + rt_kprintf("(12,0) STATUS : 0x%08X", value); + CP0_status_analyze(value); + rt_kprintf("\r\n"); + + /* + rt_kprintf("(12,1) INTCTL : 0x%08X\r\n", __read_32bit_c0_register(12, 1)); + rt_kprintf("(12,2) SRSCTL : 0x%08X\r\n", __read_32bit_c0_register(12, 2)); + */ + + rt_kprintf("(13,0) CAUSE : 0x%08X\r\n", read_c0_cause()); + rt_kprintf("(14,0) EPC : 0x%08X\r\n", read_c0_epc()); + rt_kprintf("(15,0) PRID : 0x%08X\r\n", read_c0_prid()); + rt_kprintf("(15,1) EBASE : 0x%08X\r\n", read_c0_ebase()); + + value = read_c0_config(); + rt_kprintf("(16,0) CONFIG : 0x%08X", value); + CP0_config0_analyze(value); + rt_kprintf("\r\n"); + if(value & (1UL << 31)) + { + value = read_c0_config1(); + rt_kprintf("(16,1) CONFIG1 : 0x%08X", value); + CP0_config1_analyze(value); + rt_kprintf("\r\n"); + + if(value & (1UL << 31)) + { + value = read_c0_config2(); + rt_kprintf("(16,2) CONFIG2 : 0x%08X\r\n", value); + CP0_config2_analyze(value); + rt_kprintf("\r\n"); + + if(value & (1UL << 31)) + { + value = read_c0_config3(); + rt_kprintf("(16,3) CONFIG3 : 0x%08X\r\n", value); + CP0_config3_analyze(value); + rt_kprintf("\r\n"); + } + } + } + + rt_kprintf("(17,0) LLADDR : 0x%08X\r\n", __read_32bit_c0_register($17, 0)); + rt_kprintf("(18,0) WATCHLO : 0x%08X\r\n", __read_32bit_c0_register($18, 0)); + rt_kprintf("(19,0) WATCHHI : 0x%08X\r\n", __read_32bit_c0_register($19, 0)); + rt_kprintf("(20,0) XCONTEXT : 0x%08X\r\n", __read_32bit_c0_register($20, 0)); + rt_kprintf("(21,0) FRAMEMASK : 0x%08X\r\n", __read_32bit_c0_register($21, 0)); + rt_kprintf("(22,0) DIAGNOSTIC: 0x%08X\r\n", __read_32bit_c0_register($22, 0)); + rt_kprintf("(23,0) DEBUG : 0x%08X\r\n", __read_32bit_c0_register($23, 0)); + rt_kprintf("(24,0) DEPC : 0x%08X\r\n", __read_32bit_c0_register($24, 0)); + + rt_kprintf("(25,0) PERFCTL0 : 0x%08X\r\n", __read_32bit_c0_register($25, 0)); + rt_kprintf("(26,0) ECC : 0x%08X\r\n", __read_32bit_c0_register($26, 0)); + rt_kprintf("(27,0) CACHEERR : 0x%08X\r\n", __read_32bit_c0_register($27, 0)); + rt_kprintf("(28,0) TAGLO : 0x%08X\r\n", __read_32bit_c0_register($28, 0)); + rt_kprintf("(29,0) TAGHI : 0x%08X\r\n", __read_32bit_c0_register($29, 0)); + + /* + rt_kprintf("(30,0) ERROREPC : 0x%08X\r\n", __read_32bit_c0_register($30, 0)); + rt_kprintf("(31,0) DESAVE : 0x%08X\r\n", __read_32bit_c0_register($31, 0)); + */ + + + rt_kprintf("\r\n"); +} +FINSH_FUNCTION_EXPORT(list_mips, list CPU info) +#endif /* RT_USING_FINSH */ + diff --git a/libcpu/mips/xburst/stack.c b/libcpu/mips/xburst/stack.c new file mode 100644 index 0000000000000000000000000000000000000000..ceba8b9d9d5a8e603c55e0e856f1fa0672570d8b --- /dev/null +++ b/libcpu/mips/xburst/stack.c @@ -0,0 +1,103 @@ +/* + * File : stack.c + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2010-05-17 swkyer first version + * 2010-07-07 Bernard porting to Ingenic CPU + */ +#include + +/** + * @addtogroup Ingenic + */ +/*@{*/ + +extern rt_uint32_t cp0_get_cause(void); +extern rt_uint32_t cp0_get_status(void); +extern rt_uint32_t cp0_get_hi(void); +extern rt_uint32_t cp0_get_lo(void); + +/** + * This function will initialize thread stack + * + * @param tentry the entry of thread + * @param parameter the parameter of entry + * @param stack_addr the beginning stack address + * @param texit the function will be called when thread exit + * + * @return stack address + */ +rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, rt_uint8_t *stack_addr, void *texit) +{ + rt_uint32_t *stk; + static rt_uint32_t g_sr = 0; + + if (g_sr == 0) + { + g_sr = cp0_get_status(); + g_sr &= 0xfffffffe; + g_sr |= 0x0403; + } + + /** Start at stack top */ + stk = (rt_uint32_t *)stack_addr; + *(stk) = (rt_uint32_t) tentry; /* pc: Entry Point */ + *(--stk) = (rt_uint32_t) 0xeeee; /* c0_cause */ + *(--stk) = (rt_uint32_t) 0xffff; /* c0_badvaddr */ + *(--stk) = (rt_uint32_t) cp0_get_lo(); /* lo */ + *(--stk) = (rt_uint32_t) cp0_get_hi(); /* hi */ + *(--stk) = (rt_uint32_t) g_sr; /* C0_SR: HW2 = En, IE = En */ + *(--stk) = (rt_uint32_t) texit; /* ra */ + *(--stk) = (rt_uint32_t) 0x0000001e; /* s8 */ + *(--stk) = (rt_uint32_t) stack_addr; /* sp */ + *(--stk) = (rt_uint32_t) 0x0000001c; /* gp */ + *(--stk) = (rt_uint32_t) 0x0000001b; /* k1 */ + *(--stk) = (rt_uint32_t) 0x0000001a; /* k0 */ + *(--stk) = (rt_uint32_t) 0x00000019; /* t9 */ + *(--stk) = (rt_uint32_t) 0x00000018; /* t8 */ + *(--stk) = (rt_uint32_t) 0x00000017; /* s7 */ + *(--stk) = (rt_uint32_t) 0x00000016; /* s6 */ + *(--stk) = (rt_uint32_t) 0x00000015; /* s5 */ + *(--stk) = (rt_uint32_t) 0x00000014; /* s4 */ + *(--stk) = (rt_uint32_t) 0x00000013; /* s3 */ + *(--stk) = (rt_uint32_t) 0x00000012; /* s2 */ + *(--stk) = (rt_uint32_t) 0x00000011; /* s1 */ + *(--stk) = (rt_uint32_t) 0x00000010; /* s0 */ + *(--stk) = (rt_uint32_t) 0x0000000f; /* t7 */ + *(--stk) = (rt_uint32_t) 0x0000000e; /* t6 */ + *(--stk) = (rt_uint32_t) 0x0000000d; /* t5 */ + *(--stk) = (rt_uint32_t) 0x0000000c; /* t4 */ + *(--stk) = (rt_uint32_t) 0x0000000b; /* t3 */ + *(--stk) = (rt_uint32_t) 0x0000000a; /* t2 */ + *(--stk) = (rt_uint32_t) 0x00000009; /* t1 */ + *(--stk) = (rt_uint32_t) 0x00000008; /* t0 */ + *(--stk) = (rt_uint32_t) 0x00000007; /* a3 */ + *(--stk) = (rt_uint32_t) 0x00000006; /* a2 */ + *(--stk) = (rt_uint32_t) 0x00000005; /* a1 */ + *(--stk) = (rt_uint32_t) parameter; /* a0 */ + *(--stk) = (rt_uint32_t) 0x00000003; /* v1 */ + *(--stk) = (rt_uint32_t) 0x00000002; /* v0 */ + *(--stk) = (rt_uint32_t) 0x00000001; /* at */ + *(--stk) = (rt_uint32_t) 0x00000000; /* zero */ + + /* return task's current stack address */ + return (rt_uint8_t *)stk; +} + +/*@}*/ diff --git a/libcpu/mips/xburst/stack.h b/libcpu/mips/xburst/stack.h new file mode 100644 index 0000000000000000000000000000000000000000..5bb7206c11a4da4ed3819497741d1def8d46cf23 --- /dev/null +++ b/libcpu/mips/xburst/stack.h @@ -0,0 +1,28 @@ +/* + * File : stack.h + * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes +*/ + +#ifndef __STACK_H__ +#define __STACK_H__ + +#define SYSTEM_STACK 0x80003fe8 /* the kernel system stack address */ + +#endif diff --git a/libcpu/mips/xburst/start_gcc.S b/libcpu/mips/xburst/start_gcc.S new file mode 100644 index 0000000000000000000000000000000000000000..322c2beae8973cc72f4ef37c43cef85b48ebbe7f --- /dev/null +++ b/libcpu/mips/xburst/start_gcc.S @@ -0,0 +1,150 @@ +/* + * File : start_gcc.S + * Change Logs: + * Date Author Notes + * 2010-05-17 swkyer first version + * 2010-09-04 bernard porting to Jz47xx + */ + +#include "../common/mips.inc" +#include "../common/stackframe.h" +#include "stack.h" + + .section ".start", "ax" + .set noreorder + + /* the program entry */ + .globl _start +_start: + .set noreorder + la ra, _start + + li t1, 0x00800000 + mtc0 t1, CP0_CAUSE + + /* init cp0 registers. */ + li t0, 0x0000FC00 /* BEV = 0 and mask all interrupt */ + mtc0 t0, CP0_STATUS + + /* setup stack pointer */ + li sp, SYSTEM_STACK + la gp, _gp + + /* init caches, assumes a 4way * 128set * 32byte I/D cache */ + mtc0 zero, CP0_TAGLO /* TAGLO reg */ + mtc0 zero, CP0_TAGHI /* TAGHI reg */ + li t0, 3 /* enable cache for kseg0 accesses */ + mtc0 t0, CP0_CONFIG /* CONFIG reg */ + la t0, 0x80000000 /* an idx op should use an unmappable address */ + ori t1, t0, 0x4000 /* 16kB cache */ + +_cache_loop: + cache 0x8, 0(t0) /* index store icache tag */ + cache 0x9, 0(t0) /* index store dcache tag */ + bne t0, t1, _cache_loop + addiu t0, t0, 0x20 /* 32 bytes per cache line */ + nop + + /* invalidate BTB */ + mfc0 t0, CP0_CONFIG + nop + ori t0, 2 + mtc0 t0, CP0_CONFIG + nop + + /* copy IRAM section */ + la t0, _iramcopy + la t1, _iramstart + la t2, _iramend +_iram_loop: + lw t3, 0(t0) + sw t3, 0(t1) + addiu t1, 4 + bne t1, t2, _iram_loop + addiu t0, 4 + /* clear bss */ + la t0, __bss_start + la t1, __bss_end +_clr_bss_loop: + sw zero, 0(t0) + bne t0, t1, _clr_bss_loop + addiu t0, t0, 4 + + /* jump to RT-Thread RTOS */ + jal rtthread_startup + nop + + /* restart, never die */ + j _start + nop + .set reorder + + .globl cp0_get_cause +cp0_get_cause: + mfc0 v0, CP0_CAUSE + jr ra + nop + + .globl cp0_get_status +cp0_get_status: + mfc0 v0, CP0_STATUS + jr ra + nop + + .globl cp0_get_hi +cp0_get_hi: + mfhi v0 + jr ra + nop + + .globl cp0_get_lo +cp0_get_lo: + mflo v0 + jr ra + nop + + .extern tlb_refill_handler + .extern cache_error_handler + + /* Exception Handler */ + /* 0x0 - TLB refill handler */ + .section .vectors.1, "ax", %progbits + j tlb_refill_handler + nop + + /* 0x100 - Cache error handler */ + .section .vectors.2, "ax", %progbits + j cache_error_handler + nop + + /* 0x180 - Exception/Interrupt handler */ + .section .vectors.3, "ax", %progbits + j _general_exception_handler + nop + + /* 0x200 - Special Exception Interrupt handler (when IV is set in CP0_CAUSE) */ + .section .vectors.4, "ax", %progbits + j _irq_handler + nop + + .section .vectors, "ax", %progbits + .extern mips_irq_handle + + /* general exception handler */ +_general_exception_handler: + .set noreorder + mfc0 k1, CP0_CAUSE + andi k1, k1, 0x7c + srl k1, k1, 2 + lw k0, sys_exception_handlers(k1) + jr k0 + nop + .set reorder + + /* interrupt handler */ +_irq_handler: + .set noreorder + la k0, mips_irq_handle + jr k0 + nop + .set reorder diff --git a/libcpu/mips/xburst/x1000.h b/libcpu/mips/xburst/x1000.h new file mode 100644 index 0000000000000000000000000000000000000000..71d11783a343510b7e5b86a776a47181bfc2c8f9 --- /dev/null +++ b/libcpu/mips/xburst/x1000.h @@ -0,0 +1,329 @@ +/* + * File : x1000.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-11-19 Urey the first version + */ + +#ifndef X1000_H__ +#define X1000_H__ + +#ifndef __ASSEMBLY__ + +// typedef unsigned int size_t; +#define u64 unsigned long long +#define u32 unsigned int +#define u16 unsigned short +#define u8 unsigned char + +#define U64 unsigned long long +#define U32 unsigned int +#define U16 unsigned short +#define U8 unsigned char + +#define S64 signed long long +#define S32 int +#define S16 short int +#define S8 signed char + +#define cache_unroll(base,op) \ + __asm__ __volatile__(" \ + .set noreorder; \ + .set mips3; \ + cache %1, (%0); \ + .set mips0; \ + .set reorder" \ + : \ + : "r" (base), \ + "i" (op)); + +/* cpu pipeline flush */ +static inline void jz_sync(void) +{ + __asm__ volatile ("sync"); +} + +static inline void writeb(u8 value, u32 address) +{ + *((volatile u8 *) address) = value; +} +static inline void writew( u16 value, u32 address) +{ + *((volatile u16 *) address) = value; +} +static inline void writel(u32 value, u32 address) +{ + *((volatile u32 *) address) = value; +} + +static inline u8 readb(u32 address) +{ + return *((volatile u8 *)address); +} + +static inline u16 readw(u32 address) +{ + return *((volatile u16 *)address); +} + +static inline u32 readl(u32 address) +{ + return *((volatile u32 *)address); +} + +static inline void jz_writeb(u32 address, u8 value) +{ + *((volatile u8 *)address) = value; +} + +static inline void jz_writew(u32 address, u16 value) +{ + *((volatile u16 *)address) = value; +} + +static inline void jz_writel(u32 address, u32 value) +{ + *((volatile u32 *)address) = value; +} + +static inline u8 jz_readb(u32 address) +{ + return *((volatile u8 *)address); +} + +static inline u16 jz_readw(u32 address) +{ + return *((volatile u16 *)address); +} + +static inline u32 jz_readl(u32 address) +{ + return *((volatile u32 *)address); +} + +#define REG8(addr) *((volatile u8 *)(addr)) +#define REG16(addr) *((volatile u16 *)(addr)) +#define REG32(addr) *((volatile u32 *)(addr)) + +#define BIT(n) (0x01u << (n)) + +#else + +#define REG8(addr) (addr) +#define REG16(addr) (addr) +#define REG32(addr) (addr) + +#endif /* !ASSEMBLY */ + + +//---------------------------------------------------------------------- +// Register Definitions +// +/* AHB0 BUS Devices Base */ +#define HARB0_BASE 0xB3000000 +#define EMC_BASE 0xB3010000 +#define DDRC_BASE 0xB3020000 +#define MDMAC_BASE 0xB3030000 +#define LCD_BASE 0xB3050000 +#define TVE_BASE 0xB3050000 +#define SLCD_BASE 0xB3050000 +#define CIM_BASE 0xB3060000 +#define IPU_BASE 0xB3080000 +/* AHB1 BUS Devices Base */ +#define HARB1_BASE 0xB3200000 +#define DMAGP0_BASE 0xB3210000 +#define DMAGP1_BASE 0xB3220000 +#define DMAGP2_BASE 0xB3230000 +#define MC_BASE 0xB3250000 +#define ME_BASE 0xB3260000 +#define DEBLK_BASE 0xB3270000 +#define IDCT_BASE 0xB3280000 +#define CABAC_BASE 0xB3290000 +#define TCSM0_BASE 0xB32B0000 +#define TCSM1_BASE 0xB32C0000 +#define SRAM_BASE 0xB32D0000 +/* AHB2 BUS Devices Base */ +#define HARB2_BASE 0xB3400000 +#define NEMC_BASE 0xB3410000 +#define DMAC_BASE 0xB3420000 +#define UHC_BASE 0xB3430000 +#define UDC_BASE 0xB3440000 +#define GPS_BASE 0xB3480000 +#define ETHC_BASE 0xB34B0000 +#define BCH_BASE 0xB34D0000 +#define MSC0_BASE 0xB3450000 +#define MSC1_BASE 0xB3460000 +#define MSC2_BASE 0xB3470000 + +/* APB BUS Devices Base */ +#define CPM_BASE 0xB0000000 +#define INTC_BASE 0xB0001000 +#define TCU_BASE 0xB0002000 +#define WDT_BASE 0xB0002000 +#define OST_BASE 0xB2000000 /* OS Timer */ +#define RTC_BASE 0xB0003000 +#define GPIO_BASE 0xB0010000 +#define AIC_BASE 0xB0020000 +#define DMIC_BASE 0xB0021000 +#define ICDC_BASE 0xB0020000 +#define UART0_BASE 0xB0030000 +#define UART1_BASE 0xB0031000 +#define UART2_BASE 0xB0032000 +#define UART3_BASE 0xB0033000 +#define SCC_BASE 0xB0040000 +#define SSI0_BASE 0xB0043000 +#define SSI1_BASE 0xB0044000 +#define SSI2_BASE 0xB0045000 +#define I2C0_BASE 0xB0050000 +#define I2C1_BASE 0xB0051000 +#define PS2_BASE 0xB0060000 +#define SADC_BASE 0xB0070000 +#define OWI_BASE 0xB0072000 +#define TSSI_BASE 0xB0073000 + +/* NAND CHIP Base Address*/ +#define NEMC_CS1_IOBASE 0Xbb000000 +#define NEMC_CS2_IOBASE 0Xba000000 +#define NEMC_CS3_IOBASE 0Xb9000000 +#define NEMC_CS4_IOBASE 0Xb8000000 +#define NEMC_CS5_IOBASE 0Xb7000000 +#define NEMC_CS6_IOBASE 0Xb6000000 + +/********************************************************************************************************* +** WDT +*********************************************************************************************************/ +#define WDT_TDR (WDT_BASE + 0x00) +#define WDT_TCER (WDT_BASE + 0x04) +#define WDT_TCNT (WDT_BASE + 0x08) +#define WDT_TCSR (WDT_BASE + 0x0C) + +#define REG_WDT_TDR REG16(WDT_TDR) +#define REG_WDT_TCER REG8(WDT_TCER) +#define REG_WDT_TCNT REG16(WDT_TCNT) +#define REG_WDT_TCSR REG16(WDT_TCSR) + +#define WDT_TSCR_WDTSC (1 << 16) + +#define WDT_TCSR_PRESCALE_1 (0 << 3) +#define WDT_TCSR_PRESCALE_4 (1 << 3) +#define WDT_TCSR_PRESCALE_16 (2 << 3) +#define WDT_TCSR_PRESCALE_64 (3 << 3) +#define WDT_TCSR_PRESCALE_256 (4 << 3) +#define WDT_TCSR_PRESCALE_1024 (5 << 3) + +#define WDT_TCSR_EXT_EN (1 << 2) +#define WDT_TCSR_RTC_EN (1 << 1) +#define WDT_TCSR_PCK_EN (1 << 0) + +#define WDT_TCER_TCEN (1 << 0) + +/********************************************************************************************************* +** ÖжÏÔ´ +*********************************************************************************************************/ +/* INTC (Interrupt Controller) */ +#define INTC_ISR(n) (INTC_BASE + 0x00 + (n) * 0x20) +#define INTC_IMR(n) (INTC_BASE + 0x04 + (n) * 0x20) +#define INTC_IMSR(n) (INTC_BASE + 0x08 + (n) * 0x20) +#define INTC_IMCR(n) (INTC_BASE + 0x0c + (n) * 0x20) +#define INTC_IPR(n) (INTC_BASE + 0x10 + (n) * 0x20) + +#define REG_INTC_ISR(n) REG32(INTC_ISR((n))) +#define REG_INTC_IMR(n) REG32(INTC_IMR((n))) +#define REG_INTC_IMSR(n) REG32(INTC_IMSR((n))) +#define REG_INTC_IMCR(n) REG32(INTC_IMCR((n))) +#define REG_INTC_IPR(n) REG32(INTC_IPR((n))) + +// interrupt controller interrupts +#define IRQ_DMIC 0 +#define IRQ_AIC0 1 +#define IRQ_RESERVED2 2 +#define IRQ_RESERVED3 3 +#define IRQ_RESERVED4 4 +#define IRQ_RESERVED5 5 +#define IRQ_RESERVED6 6 +#define IRQ_SFC 7 +#define IRQ_SSI0 8 +#define IRQ_RESERVED9 9 +#define IRQ_PDMA 10 +#define IRQ_PDMAD 11 +#define IRQ_RESERVED12 12 +#define IRQ_RESERVED13 13 +#define IRQ_GPIO3 14 +#define IRQ_GPIO2 15 +#define IRQ_GPIO1 16 +#define IRQ_GPIO0 17 +#define IRQ_RESERVED18 18 +#define IRQ_RESERVED19 19 +#define IRQ_RESERVED20 20 +#define IRQ_OTG 21 +#define IRQ_RESERVED22 22 +#define IRQ_AES 23 +#define IRQ_RESERVED24 24 +#define IRQ_TCU2 25 +#define IRQ_TCU1 26 +#define IRQ_TCU0 27 +#define IRQ_RESERVED28 28 +#define IRQ_RESERVED29 29 +#define IRQ_CIM 30 +#define IRQ_LCD 31 +#define IRQ_RTC 32 +#define IRQ_RESERVED33 33 +#define IRQ_RESERVED34 34 +#define IRQ_RESERVED35 35 +#define IRQ_MSC1 36 +#define IRQ_MSC0 37 +#define IRQ_SCC 38 +#define IRQ_RESERVED39 39 +#define IRQ_PCM0 40 +#define IRQ_RESERVED41 41 +#define IRQ_RESERVED42 42 +#define IRQ_RESERVED43 43 +#define IRQ_HARB2 44 +#define IRQ_RESERVED45 45 +#define IRQ_HARB0 46 +#define IRQ_CPM 47 +#define IRQ_RESERVED48 48 +#define IRQ_UART2 49 +#define IRQ_UART1 50 +#define IRQ_UART0 51 +#define IRQ_DDR 52 +#define IRQ_RESERVED53 53 +#define IRQ_EFUSE 54 +#define IRQ_MAC 55 +#define IRQ_RESERVED56 56 +#define IRQ_RESERVED57 57 +#define IRQ_I2C2 58 +#define IRQ_I2C1 59 +#define IRQ_I2C0 60 +#define IRQ_PDMAM 61 +#define IRQ_JPEG 62 +#define IRQ_RESERVED63 63 + +#define IRQ_INTC_MAX 63 + +#ifndef __ASSEMBLY__ + +#define __intc_unmask_irq(n) (REG_INTC_IMCR((n)/32) = (1 << ((n)%32))) +#define __intc_mask_irq(n) (REG_INTC_IMSR((n)/32) = (1 << ((n)%32))) +#define __intc_ack_irq(n) (REG_INTC_IPR((n)/32) = (1 << ((n)%32))) /* A dummy ack, as the Pending Register is Read Only. Should we remove __intc_ack_irq() */ + +#endif /* !__ASSEMBLY__ */ + +#endif /* _JZ_M150_H_ */