未验证 提交 8e8fba79 编写于 作者: B Bernard Xiong 提交者: GitHub

Merge pull request #1217 from uestczyh222/master

[BSP][tina] New bsp for allwinner tina
......@@ -27,6 +27,7 @@ env:
# - RTT_BSP='apollo2' RTT_TOOL_CHAIN='sourcery-arm'
- RTT_BSP='asm9260t' RTT_TOOL_CHAIN='sourcery-arm'
- RTT_BSP='at91sam9260' RTT_TOOL_CHAIN='sourcery-arm'
- RTT_BSP='allwinner_tina' RTT_TOOL_CHAIN='sourcery-arm'
# - RTT_BSP='avr32uc3b0' RTT_TOOL_CHAIN='atmel-avr32'
# - RTT_BSP='bf533' # no scons
- RTT_BSP='efm32' RTT_TOOL_CHAIN='sourcery-arm'
......
#
# Automatically generated file; DO NOT EDIT.
# RT-Thread Configuration
#
#
# RT-Thread Kernel
#
CONFIG_RT_NAME_MAX=8
CONFIG_RT_ALIGN_SIZE=4
# CONFIG_RT_THREAD_PRIORITY_8 is not set
CONFIG_RT_THREAD_PRIORITY_32=y
# CONFIG_RT_THREAD_PRIORITY_256 is not set
CONFIG_RT_THREAD_PRIORITY_MAX=32
CONFIG_RT_TICK_PER_SECOND=100
CONFIG_RT_DEBUG=y
CONFIG_RT_USING_OVERFLOW_CHECK=y
CONFIG_RT_DEBUG_INIT=0
CONFIG_RT_DEBUG_THREAD=0
CONFIG_RT_USING_HOOK=y
CONFIG_IDLE_THREAD_STACK_SIZE=256
# CONFIG_RT_USING_TIMER_SOFT is not set
#
# Inter-Thread communication
#
CONFIG_RT_USING_SEMAPHORE=y
CONFIG_RT_USING_MUTEX=y
CONFIG_RT_USING_EVENT=y
CONFIG_RT_USING_MAILBOX=y
CONFIG_RT_USING_MESSAGEQUEUE=y
# CONFIG_RT_USING_SIGNALS is not set
#
# Memory Management
#
CONFIG_RT_USING_MEMPOOL=y
# CONFIG_RT_USING_MEMHEAP is not set
# CONFIG_RT_USING_NOHEAP is not set
CONFIG_RT_USING_SMALL_MEM=y
# CONFIG_RT_USING_SLAB is not set
# CONFIG_RT_USING_MEMTRACE is not set
CONFIG_RT_USING_HEAP=y
#
# Kernel Device Object
#
CONFIG_RT_USING_DEVICE=y
# CONFIG_RT_USING_INTERRUPT_INFO is not set
CONFIG_RT_USING_CONSOLE=y
CONFIG_RT_CONSOLEBUF_SIZE=128
CONFIG_RT_CONSOLE_DEVICE_NAME="uart0"
# CONFIG_RT_USING_MODULE is not set
CONFIG_ARCH_ARM=y
CONFIG_ARCH_ARM_ARM9=y
#
# RT-Thread Components
#
CONFIG_RT_USING_COMPONENTS_INIT=y
CONFIG_RT_USING_USER_MAIN=y
#
# C++ features
#
# CONFIG_RT_USING_CPLUSPLUS is not set
#
# Command shell
#
CONFIG_RT_USING_FINSH=y
CONFIG_FINSH_THREAD_NAME="tshell"
CONFIG_FINSH_USING_HISTORY=y
CONFIG_FINSH_HISTORY_LINES=5
CONFIG_FINSH_USING_SYMTAB=y
CONFIG_FINSH_USING_DESCRIPTION=y
CONFIG_FINSH_THREAD_PRIORITY=20
CONFIG_FINSH_THREAD_STACK_SIZE=4096
CONFIG_FINSH_CMD_SIZE=80
# CONFIG_FINSH_USING_AUTH is not set
CONFIG_FINSH_USING_MSH=y
CONFIG_FINSH_USING_MSH_DEFAULT=y
# CONFIG_FINSH_USING_MSH_ONLY is not set
#
# Device virtual file system
#
CONFIG_RT_USING_DFS=y
CONFIG_DFS_USING_WORKDIR=y
CONFIG_DFS_FILESYSTEMS_MAX=2
CONFIG_DFS_FILESYSTEM_TYPES_MAX=2
CONFIG_DFS_FD_MAX=4
CONFIG_RT_USING_DFS_ELMFAT=y
#
# elm-chan's FatFs, Generic FAT Filesystem Module
#
CONFIG_RT_DFS_ELM_CODE_PAGE=437
CONFIG_RT_DFS_ELM_WORD_ACCESS=y
CONFIG_RT_DFS_ELM_USE_LFN_0=y
# CONFIG_RT_DFS_ELM_USE_LFN_1 is not set
# CONFIG_RT_DFS_ELM_USE_LFN_2 is not set
# CONFIG_RT_DFS_ELM_USE_LFN_3 is not set
CONFIG_RT_DFS_ELM_USE_LFN=0
CONFIG_RT_DFS_ELM_MAX_LFN=255
CONFIG_RT_DFS_ELM_DRIVES=2
CONFIG_RT_DFS_ELM_MAX_SECTOR_SIZE=512
# CONFIG_RT_DFS_ELM_USE_ERASE is not set
CONFIG_RT_DFS_ELM_REENTRANT=y
CONFIG_RT_USING_DFS_DEVFS=y
# CONFIG_RT_USING_DFS_NET is not set
# CONFIG_RT_USING_DFS_ROMFS is not set
# CONFIG_RT_USING_DFS_RAMFS is not set
# CONFIG_RT_USING_DFS_UFFS is not set
# CONFIG_RT_USING_DFS_JFFS2 is not set
# CONFIG_RT_USING_DFS_NFS is not set
#
# Device Drivers
#
CONFIG_RT_USING_DEVICE_IPC=y
CONFIG_RT_USING_SERIAL=y
# CONFIG_RT_USING_CAN is not set
# CONFIG_RT_USING_HWTIMER is not set
# CONFIG_RT_USING_CPUTIME is not set
# CONFIG_RT_USING_I2C is not set
CONFIG_RT_USING_PIN=y
# CONFIG_RT_USING_MTD_NOR is not set
# CONFIG_RT_USING_MTD_NAND is not set
# CONFIG_RT_USING_RTC is not set
# CONFIG_RT_USING_SDIO is not set
# CONFIG_RT_USING_SPI is not set
# CONFIG_RT_USING_WDT is not set
# CONFIG_RT_USING_WIFI is not set
#
# Using USB
#
# CONFIG_RT_USING_USB_HOST is not set
# CONFIG_RT_USING_USB_DEVICE is not set
#
# POSIX layer and C standard library
#
CONFIG_RT_USING_LIBC=y
# CONFIG_RT_USING_PTHREADS is not set
CONFIG_RT_USING_POSIX=y
# CONFIG_RT_USING_POSIX_MMAP is not set
# CONFIG_RT_USING_POSIX_TERMIOS is not set
# CONFIG_RT_USING_POSIX_AIO is not set
#
# Network stack
#
#
# light weight TCP/IP stack
#
# CONFIG_RT_USING_LWIP is not set
#
# Modbus master and slave stack
#
# CONFIG_RT_USING_MODBUS is not set
#
# RT-Thread UI Engine
#
# CONFIG_RT_USING_GUIENGINE is not set
#
# VBUS(Virtual Software BUS)
#
# CONFIG_RT_USING_VBUS is not set
#
# Utilities
#
# CONFIG_RT_USING_LOGTRACE is not set
# CONFIG_RT_USING_RYM is not set
#
# RT-Thread online packages
#
#
# system packages
#
# CONFIG_PKG_USING_LWEXT4 is not set
# CONFIG_PKG_USING_PARTITION is not set
# CONFIG_PKG_USING_PERSIMMON is not set
# CONFIG_PKG_USING_SQLITE is not set
# CONFIG_PKG_USING_RTI is not set
#
# IoT - internet of things
#
# CONFIG_PKG_USING_PAHOMQTT is not set
# CONFIG_PKG_USING_WEBCLIENT is not set
# CONFIG_PKG_USING_MONGOOSE is not set
# CONFIG_PKG_USING_WEBTERMINAL is not set
# CONFIG_PKG_USING_CJSON is not set
# CONFIG_PKG_USING_LJSON is not set
# CONFIG_PKG_USING_EZXML is not set
# CONFIG_PKG_USING_NANOPB is not set
# CONFIG_PKG_USING_GAGENT_CLOUD is not set
#
# Wi-Fi
#
#
# Marvell WiFi
#
# CONFIG_PKG_USING_WLANMARVELL is not set
#
# Wiced WiFi
#
# CONFIG_PKG_USING_WLAN_WICED is not set
# CONFIG_PKG_USING_COAP is not set
# CONFIG_PKG_USING_NOPOLL is not set
#
# security packages
#
# CONFIG_PKG_USING_MBEDTLS is not set
# CONFIG_PKG_USING_libsodium is not set
# CONFIG_PKG_USING_TINYCRYPT is not set
#
# language packages
#
# CONFIG_PKG_USING_JERRYSCRIPT is not set
# CONFIG_PKG_USING_MICROPYTHON is not set
#
# multimedia packages
#
# CONFIG_PKG_USING_OPENMV is not set
#
# tools packages
#
# CONFIG_PKG_USING_CMBACKTRACE is not set
# CONFIG_PKG_USING_EASYLOGGER is not set
# CONFIG_PKG_USING_SYSTEMVIEW is not set
# CONFIG_PKG_USING_IPERF is not set
#
# miscellaneous packages
#
# CONFIG_PKG_USING_FASTLZ is not set
# CONFIG_PKG_USING_MINILZO is not set
#
# example package: hello
#
# CONFIG_PKG_USING_HELLO is not set
# CONFIG_PKG_USING_MULTIBUTTON is not set
CONFIG_TINA_USING_UART0=y
# CONFIG_TINA_USING_UART1 is not set
CONFIG_TINA_USING_UART2=y
CONFIG_RT_USING_CPU_FFS=y
CONFIG_RT_MAIN_THREAD_STACK_SIZE=2048
mainmenu "RT-Thread Configuration"
config $BSP_DIR
string
option env="BSP_ROOT"
default "."
config $RTT_DIR
string
option env="RTT_ROOT"
default "../.."
# you can change the RTT_ROOT default "../.." to your rtthread_root,
# example : default "F:/git_repositories/rt-thread"
config $PKGS_DIR
string
option env="PKGS_ROOT"
default "packages"
source "$RTT_DIR/KConfig"
source "$PKGS_DIR/KConfig"
config SOC_TINA
bool
select ARCH_ARM_ARM9
default y
source "$BSP_DIR/drivers/Kconfig"
# Allwinner tina板级支持包
## 1. 简介
Allwinner tina 是由全志公司推出的ARM9内核的SOC
包括如下硬件特性:
| 硬件 | 描述 |
| -- | -- |
|芯片型号| tina系列 |
|CPU| ARM9 |
|主频| 408MHz |
|片内DDR | 32MB |
|板载SPI Nor Flash | 8/16MB|
## 2. 编译说明
| 环境 | 说明 |
| --- | --- |
|PC操作系统|Linux/MacOS|
|编译器|arm-none-eabi-gcc version 6.3.1 20170620 (release)|
|构建工具|scons|
1) 下载源码
```
git clone https://github.com/RT-Thread/rt-thread.git
```
2) 配置工程并准备env
```
cd rt-thread/bsp/allwinner_tina
scons --menuconfig
source ~/.env/env.sh
pkgs --upgrade
```
3) 编译安装下载工具
```
pushd /tmp
git clone https://github.com/Icenowy/sunxi-tools.git
pushd sunxi-tools
git checkout -b f1c100s
git checkout -b f1c100s origin/f1c100s
make
sudo make install
popd
popd
```
4) 编译
```
scons
```
如果编译正确无误,会产生rtthread.elf、rtthread.bin文件。其中rtthread.bin需要烧写到设备中进行运行。
## 3. 烧写及执行
**烧写工具目前仅支持Linux/MacOS环境,请在Linux/MaxOS环境下进行烧写操作**
当正确编译产生出rtthread.bin映像文件后可以使用下面的方式来烧写到设备中。
1)编译初始化引导文件
编译依赖 arm-eabi-gcc
```
pushd ../../..
git clone https://github.com/uestczyh222/tina-spl.git
pushd tina-spl
make
cp output/f1c100s.bin ../rt-thread/bsp/tina/tina-spl.bin
popd
popd
```
2)下载并运行
```
1.短接flash 1、4脚(当flash中无可引导代码时无需此步骤)
2.连接USB
3.松开短接的引脚
4.输入下列指令
```
```
sudo sunxi-fel -p write 0x00000000 tina-spl.bin
sudo sunxi-fel exec 0x00000000
sudo sunxi-fel -p write 0x80000000 rtthread.bin
sudo sunxi-fel exec 0x80000000
```
### 3.1 运行结果
如果编译 & 烧写无误,会在串口0上看到RT-Thread的启动logo信息:
```
\ | /
- RT - Thread Operating System
/ | \ 3.0.2 build Feb 8 2018
2006 - 2017 Copyright by rt-thread team
periph_get_pll_clk:600000000
cpu_get_clk:408000000
ahb_get_clk:200000000
apb_get_clk:100000000
msh />
```
## 4. 驱动支持情况及计划
| 驱动 | 支持情况 | 备注 |
| ------ | :----: | :------: |
| UART | 支持 | UART0/1/2 |
| GPIO | 支持 | / |
| clock | 支持 | / |
| mmu | 支持 | / |
### 4.1 IO在板级支持包中的映射情况
| IO号 | 板级包中的定义 |
| -- | -- |
| PE8 | USART2 RX |
| PE7 | USART2 TX |
| PA3 | USART1 RX |
| PA2 | USART1 TX |
| PE1 | USART0 TX |
| PE0 | USART0 RX |
## 5. 联系人信息
维护人:
[uestczyh222][4] < [lymz@foxmail.com][5] >
[1]: https://www.rt-thread.org/page/download.html
[4]: https://github.com/uestczyh222
[5]: mailto:lymz@foxmail.com
# 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')
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.' + 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, has_libcpu=True)
# make a building
DoBuilding(TARGET, objs)
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
CPPPATH = [cwd, str(Dir('#'))]
group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH)
Return('group')
/*
* File : main.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2017, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2017-5-30 Bernard the first version
*/
#include "rtthread.h"
#include "drv_clock.h"
int main(int argc, char **argv)
{
rt_kprintf("periph_get_pll_clk:%d\n", periph_get_pll_clk());
rt_kprintf("cpu_get_clk:%d\n", cpu_get_clk());
rt_kprintf("ahb_get_clk:%d\n", ahb_get_clk());
rt_kprintf("apb_get_clk:%d\n", apb_get_clk());
return 0;
}
config TINA_USING_UART0
bool "Using UART0"
select RT_USING_SERIAL
default n
config TINA_USING_UART1
bool "Using UART1"
select RT_USING_SERIAL
default y
config TINA_USING_UART2
bool "Using UART2"
select RT_USING_SERIAL
default y
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
list = os.listdir(cwd)
CPPPATH = [cwd]
objs = []
group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH)
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'))
objs = objs + group
Return('objs')
/*
* File : board.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2017, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2017-5-30 Bernard the first version
*/
#include <rthw.h>
#include <rtthread.h>
#include "board.h"
#include "drv_uart.h"
#include "interrupt.h"
#include "mmu.h"
static void os_clock_irq_handle(int irqno, void *param)
{
volatile rt_uint32_t *temp_addr = (rt_uint32_t *)(0x01C20C00 + 0x04);
/* clear timer */
*temp_addr |= 0x01;
rt_tick_increase();
}
static void mmu_init(void)
{
struct mem_desc r6_mem_desc[] =
{
{ 0x00000000, 0xFFFFFFFF, 0x00000000, RW_NCNB }, /* None cached for 4G memory */
{ 0x80000000, 0x82000000 - 1, 0x80000000, RW_CB }, /* 32M cached SDRAM memory */
//{ 0x00000000, 0x00001000-1, 0x80000000, RW_CB }, /* isr vector table */
//here not set mmu
//start_gcc.S Copy vector to the correct address
};
rt_hw_mmu_init(r6_mem_desc, sizeof(r6_mem_desc) / sizeof(r6_mem_desc[0]));
}
static void os_clock_init(void)
{
rt_uint32_t temp;
volatile rt_uint32_t *temp_addr;
/* reload value */
temp = 0xB71B00 / RT_TICK_PER_SECOND;
temp_addr = (rt_uint32_t *)(0x01C20C00 + 0x14);
*temp_addr = temp;
/* continuous | /2 | 24Mhz | reload*/
temp = (0x00 << 7) | (0x01 << 4) | (0x01 << 2) | (0x00 << 1);
temp_addr = (rt_uint32_t *)(0x01C20C00 + 0x10);
*temp_addr &= 0xffffff00;
*temp_addr |= temp;
/* open timer irq */
temp = 0x01 << 0;
temp_addr = (rt_uint32_t *)(0x01C20C00);
*temp_addr |= temp;
/* set init value */
temp_addr = (rt_uint32_t *)(0x01C20C00 + 0x18);
*temp_addr = 0;
/* begin run timer */
temp = 0x01 << 0;
temp_addr = (rt_uint32_t *)(0x01C20C00 + 0x10);
*temp_addr |= temp;
temp_addr = (rt_uint32_t *)(0x01C20C00);
/* set irq handle */
rt_hw_interrupt_install(TIMER0_INTERRUPT, os_clock_irq_handle, (void *)temp_addr, "timer");
rt_hw_interrupt_umask(TIMER0_INTERRUPT);
}
void rt_hw_board_init(void)
{
mmu_init();
rt_hw_interrupt_init();
#ifdef RT_USING_HEAP
/* init memory system */
rt_system_heap_init(RT_HW_HEAP_BEGIN, RT_HW_HEAP_END);
#endif
/* init hardware interrupt */
rt_hw_uart_init();
#ifdef RT_USING_CONSOLE
/* set console device */
rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif /* RT_USING_CONSOLE */
os_clock_init();
#ifdef RT_USING_COMPONENTS_INIT
rt_components_board_init();
#endif
}
/*
* File : board.h
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2017, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2017-5-30 Bernard the first version
*/
#ifndef _BOARD_H_
#define _BOARD_H_
#include <stdint.h>
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)
void rt_hw_board_init(void);
#endif
/*
* File : drv_clock.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2017, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2018-02-08 RT-Thread the first version
*/
#include <rtthread.h>
#include <rthw.h>
#include "drv_clock.h"
int cpu_get_pll_clk(void)
{
rt_uint32_t reg;
int n, k, m, p;
reg = CCU->pll_cpu_ctrl;
if (!(reg & (0x01 << 31)))
return 0;
p = PLL_CPU_DIV_P(reg) + 1;
n = PLL_CPU_FACTOR_N(reg) + 1;
k = PLL_CPU_FACTOR_K(reg) + 1;
m = PLL_CPU_FACTOR_M(reg) + 1;
//(24MHz*n*k)/(m*p)
return (_24MHZ_ * n * k) / (m * p);
}
int audio_get_pll_clk(void)
{
rt_uint32_t reg;
unsigned char n, m;
reg = CCU->pll_audio_ctrl;
if (!(reg & (0x01 << 31)))
return 0;
n = PLL_AUDIO_FACTOR_N(reg) + 1;
m = PLL_AUDIO_PREDIV_M(reg) + 1;
//24MHz*n*2/m
return _24MHZ_ * 2 * n / m;
}
int video_get_pll_clk(void)
{
rt_uint32_t reg;
int n, m;
reg = CCU->pll_video_ctrl;
if (!(reg & (0x01 << 31)))
return 0;
if (reg & PLL_VIDEO_MODE_SEL)
{
//(24MHz*n)/m
n = PLL_VIDEO_FACTOR_N(reg) + 1;
m = PLL_VIDEO_PREDIV_M(reg) + 1;
return (_24MHZ_ * n) / m;
}
if (reg & PLL_VIDEO_FRAC_CLK_OUT)
return 270000000;
else
return 297000000;
return 0;
}
int ve_get_pll_clk(void)
{
rt_uint32_t reg;
int n, m;
reg = CCU->pll_ve_ctrl;
if (!(reg & (0x01 << 31)))
return 0;
if (reg & PLL_VE_MODE_SEL)
{
//(24MHz*n)/m
n = PLL_VE_FACTOR_N(reg) + 1;
m = PLL_VE_PREDIV_M(reg) + 1;
return (_24MHZ_ * n) / m;
}
if (reg & PLL_VE_FRAC_CLK_OUT)
return 297000000;
else
return 270000000;
return 0;
}
int ddr_get_pll_clk(void)
{
rt_uint32_t reg;
int n, k, m;
reg = CCU->pll_ddr_ctrl;
if (!(reg & (0x01 << 31)))
return 0;
n = PLL_DDR_FACTOR_N(reg) + 1;
k = PLL_DDR_FACTOR_K(reg) + 1;
m = PLL_DDR_FACTOR_M(reg) + 1;
//(24MHz*n*k)/m
return (_24MHZ_ * n * k) / m;
}
int periph_get_pll_clk(void)
{
rt_uint32_t reg;
int n, k;
reg = CCU->pll_periph_ctrl;
if (!(reg & (0x01 << 31)))
return 0;
n = PLL_PERIPH_FACTOR_N(reg) + 1;
k = PLL_PERIPH_FACTOR_K(reg) + 1;
return _24MHZ_ * n * k;
}
static int cpu_get_clk_src(void)
{
return (CCU->cpu_clk_src >> 16) & 0x3;
}
int cpu_get_clk(void)
{
rt_uint32_t reg;
int cpusrc;
reg = CCU->ahb_apb_hclkc_cfg;
cpusrc = cpu_get_clk_src();
if (cpusrc == CLK_PLL_SRC)
return (cpu_get_pll_clk() / (HCLKC_DIV(reg) + 1));
else if (cpusrc == CLK_OSC24M_SRC)
return _24MHZ_ / (HCLKC_DIV(reg) + 1);
else
return _32KHZ_ / (HCLKC_DIV(reg) + 1); //猜测 内部32KHz时钟
return 0;
}
int ahb_get_clk(void)
{
rt_uint32_t reg;
int sel, spd;
reg = CCU->ahb_apb_hclkc_cfg;
sel = AHB_SRC_SEL(reg);
if (sel == CLK_PLL_SRC)
{
spd = cpu_get_clk();
return spd / (1 << AHB_CLK_DIV(reg));
}
else if (sel == PRE_DIV_SRC)
{
spd = periph_get_pll_clk();
return spd / (AHB_PRE_DIV(reg) + 1) / (1 << AHB_CLK_DIV(reg));
}
else if (sel == CLK_OSC24M_SRC)
return _24MHZ_ / (1 << AHB_CLK_DIV(reg));
else
return _32KHZ_ / (1 << AHB_CLK_DIV(reg));
}
int apb_get_clk(void)
{
rt_uint32_t reg;
int spd;
reg = CCU->ahb_apb_hclkc_cfg;
spd = ahb_get_clk();
// 0x:/2 10:/4 11:/8
if (!(APH_CLK_PATIO(reg) & 0x1))
return spd / 2;
else
return spd / (1 << APH_CLK_PATIO(reg));
}
static rt_err_t wait_pll_stable(rt_uint32_t base)
{
rt_uint32_t rval = 0;
volatile int time = 0xfff;
do
{
rval = *((volatile rt_uint32_t *)base);
time--;
}
while (time && !(rval & (1 << 28)));
return !time;
}
rt_err_t cpu_set_pll_clk(int clk)
{
rt_uint32_t cpu_src;
int p = 0, k = 1, m = 1, n = 0;
if (clk == 0)
return RT_EINVAL;
if (clk > 1152000000)
{
k = 2;
}
else if (clk > 768000000)
{
k = 3;
m = 2;
}
n = clk / (_24MHZ_ * k / m) - 1;
cpu_src = (CCU->cpu_clk_src >> 16) & 0x3;
CCU->cpu_clk_src = CLK_OSC24M_SRC << 16;
CCU->pll_cpu_ctrl &= ~(0x1 << 31);
//PLL1 rate = ((24000000 * n * k) >> 0) / m (p is ignored)
CCU->pll_cpu_ctrl = (0x1 << 31) | (m << 0) | (k << 4) | (n << 8) | (p << 16);
if (wait_pll_stable((rt_uint32_t)(&CCU->pll_cpu_ctrl)))
return RT_ERROR;
CCU->cpu_clk_src = cpu_src << 16;
return RT_EOK;
}
rt_err_t audio_set_pll_clk(int clk)
{
int n = 0, m = 0;
int n_temp = clk;
int m_temp = _24MHZ_ * 2;
if ((clk > 200000000) || (clk < 20000000))
return RT_EINVAL;
if (clk == 0)
{
CCU->pll_audio_ctrl &= ~(0x1 << 31);
return RT_EOK;
}
while (n_temp != m_temp)
{
if (n_temp > m_temp)
{
n_temp = n_temp - m_temp;
}
else if (m_temp > n_temp)
{
m_temp = m_temp - n_temp;
}
}
n = clk / n_temp;
m = _24MHZ_ * 2 / m_temp;
if ((n > 128) || (m > 32) || (clk != (_24MHZ_ * n * 2) / m))
return RT_ERROR;
CCU->pll_audio_ctrl &= ~(0x1 << 31);
n = (n - 1) & 0x7f;
m = (m - 1) & 0x1f;
//clk = (24 * n * 2) / m
CCU->pll_audio_ctrl = (0x1 << 31) | (0x0 << 24) | (n << 8) | m;
if (wait_pll_stable((rt_uint32_t)(&CCU->pll_audio_ctrl)))
return RT_ERROR;
else
return RT_EOK;
}
rt_err_t video_set_pll_clk(int clk)
{
int n = 0, m = 0;
int n_temp = clk;
int m_temp = _24MHZ_;
if ((clk > 600000000) || (clk < 30000000))
return RT_EINVAL;
if (clk == 0)
{
CCU->pll_video_ctrl &= ~(0x1 << 31);
return RT_EOK;
}
while (n_temp != m_temp)
{
if (n_temp > m_temp)
{
n_temp = n_temp - m_temp;
}
else if (m_temp > n_temp)
{
m_temp = m_temp - n_temp;
}
}
n = clk / n_temp;
m = _24MHZ_ / m_temp;
if ((n > 128) || (m > 16) || (clk != (_24MHZ_ * n) / m))
return RT_ERROR;
CCU->pll_video_ctrl &= ~(0x1 << 31);
n = (n - 1) & 0x7f;
m = (m - 1) & 0xf;
//speed = (24*n)/m
CCU->pll_video_ctrl = (0x1 << 31) | (0x0 << 30) | (0x1 << 24) | (n << 8) | m;
if (wait_pll_stable((rt_uint32_t)(&CCU->pll_video_ctrl)))
return RT_ERROR;
else
return RT_EOK;
}
rt_err_t ve_set_pll_clk(int clk)
{
int n = 0, m = 0;
int n_temp = clk;
int m_temp = _24MHZ_;
if ((clk > 600000000) || (clk < 30000000))
return RT_EINVAL;
if (clk == 0)
{
CCU->pll_ve_ctrl &= ~(0x1 << 31);
return RT_EOK;
}
while (n_temp != m_temp)
{
if (n_temp > m_temp)
{
n_temp = n_temp - m_temp;
}
else if (m_temp > n_temp)
{
m_temp = m_temp - n_temp;
}
}
n = clk / n_temp;
m = _24MHZ_ / m_temp;
if ((n > 128) || (m > 16) || (clk != (_24MHZ_ * n) / m))
return RT_ERROR;
CCU->pll_ve_ctrl &= ~(0x1 << 31);
n = (n - 1) & 0x7f;
m = (m - 1) & 0xf;
//clk = (24 * n) / m
CCU->pll_ve_ctrl = (0x1 << 31) | (0x1 << 24) | (n << 8) | m;
if (wait_pll_stable((rt_uint32_t)(&CCU->pll_ve_ctrl)))
return RT_ERROR;
else
return RT_EOK;
}
rt_err_t periph_set_pll_clk(int clk)
{
rt_uint32_t clk_src;
rt_uint32_t temp_data;
int n = 0, k = 0;
if ((clk > 1800000000) || (clk < 200000000) || (clk == 0) || (clk % _24MHZ_ != 0))
return RT_EINVAL;
n = clk / _24MHZ_;
for (k = 2; ((n > 32) || (k < 5)); k++)
{
if ((n % k) != 0)
n /= k;
}
if ((n > 32) || (k > 4) || (clk != (_24MHZ_ * n * k)))
return RT_ERROR;
temp_data = CCU->ahb_apb_hclkc_cfg;
clk_src = (temp_data >> 12) & 0x3;
temp_data &= ~(0x3 << 12);
temp_data |= (CLK_PLL_SRC << 12);
CCU->ahb_apb_hclkc_cfg = temp_data;
CCU->pll_periph_ctrl &= ~(0x1 << 31);
n = (n - 1) & 0x1f;
k = (k - 1) & 0x3;
//clk = 24 * n *k
CCU->pll_periph_ctrl = (0x1 << 31) | (0x1 << 18) | (n << 8) | (k << 4) || (0x1);
if (wait_pll_stable((rt_uint32_t)(&CCU->pll_periph_ctrl)))
return RT_ERROR;
temp_data = CCU->ahb_apb_hclkc_cfg;
temp_data &= ~(0x3 << 12);
temp_data |= (clk_src << 12);
CCU->ahb_apb_hclkc_cfg = temp_data;
return RT_EOK;
}
rt_err_t cpu_set_clk(int clk)
{
if (clk < _24MHZ_)
return RT_EINVAL;
if (clk == cpu_get_clk())
return RT_EOK;
CCU->cpu_clk_src = CLK_OSC24M_SRC << 16;
if (clk == _24MHZ_)
return RT_EOK;
if (cpu_set_pll_clk(clk))
return RT_ERROR;
CCU->ahb_apb_hclkc_cfg &= ~(0x3 << 16);
CCU->cpu_clk_src = CLK_PLL_SRC << 16;
return RT_EOK;
}
rt_err_t bus_gate_clk_enalbe(enum bus_gate bus)
{
rt_uint32_t offset;
rt_uint32_t gate_reg;
offset = bus & 0xfff;
gate_reg = bus >> BUS_GATE_OFFSET_BIT;
if (gate_reg == 0x00)
CCU->bus_clk_gating0 |= (0x1 << offset);
else if (gate_reg == 0x01)
CCU->bus_clk_gating1 |= (0x1 << offset);
else if (gate_reg == 0x02)
CCU->bus_clk_gating2 |= (0x1 << offset);
else
return RT_EINVAL;
return RT_EOK;
}
rt_err_t bus_gate_clk_disalbe(enum bus_gate bus)
{
rt_uint32_t offset;
rt_uint32_t gate_reg;
offset = bus & 0xfff;
gate_reg = bus >> BUS_GATE_OFFSET_BIT;
if (gate_reg == 0x00)
CCU->bus_clk_gating0 &= ~(0x1 << offset);
else if (gate_reg == 0x01)
CCU->bus_clk_gating1 &= ~(0x1 << offset);
else if (gate_reg == 0x02)
CCU->bus_clk_gating2 &= ~(0x1 << offset);
else
return RT_EINVAL;
return RT_EOK;
}
rt_err_t bus_software_reset_enalbe(enum bus_gate bus)
{
rt_uint32_t offset;
rt_uint32_t gate_reg;
offset = bus & 0xfff;
gate_reg = bus >> BUS_GATE_OFFSET_BIT;
if (gate_reg == 0x00)
CCU->bus_soft_rst0 |= (0x1 << offset);
else if (gate_reg == 0x01)
CCU->bus_soft_rst1 |= (0x1 << offset);
else if (gate_reg == 0x02)
CCU->bus_soft_rst2 |= (0x1 << offset);
else
return RT_EINVAL;
return RT_EOK;
}
rt_err_t bus_software_reset_disalbe(enum bus_gate bus)
{
rt_uint32_t offset;
rt_uint32_t gate_reg;
offset = bus & 0xfff;
gate_reg = bus >> BUS_GATE_OFFSET_BIT;
if (gate_reg == 0x00)
CCU->bus_soft_rst0 &= ~(0x1 << offset);
else if (gate_reg == 0x01)
CCU->bus_soft_rst1 &= ~(0x1 << offset);
else if (gate_reg == 0x02)
CCU->bus_soft_rst2 &= ~(0x1 << offset);
else
return RT_EINVAL;
return RT_EOK;
}
/*
* File : drv_clock.h
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2017, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2018-02-08 RT-Thread the first version
*/
#ifndef __DRV_CLOCK_H__
#define __DRV_CLOCK_H__
/* PLL state */
#define PLL_ENBALE (0x1)
#define PLL_STABLE (0x2)
/* Clock source selection */
#define CLK_LOSC_SRC (0x00)
#define CLK_OSC24M_SRC (0x01)
#define CLK_PLL_SRC (0x02)
#define PRE_DIV_SRC (0x03)
/* */
#define BE_GATING_DRAM (0x1<<26)
#define FE_GATING_DRAM (0x1<<24)
#define TVD_GATING_DRAM (0x1<<3)
#define DEINTERLACE_GATING_DRAM (0x1<<2)
#define CSI_GATING_DRAM (0x1<<1)
#define VE_GATING_DRAM (0x1<<0)
/* */
#define TCON_PLL_VIDEO_X1 (0x000)
#define TCON_PLL_VIDEO_X2 (0x002)
#define PLL_CPU_ENABLE_STATE (0x1<<31)
#define PLL_CPU_HAS_BEEN_STABLE (0x1<<28)
#define PLL_CPU_DIV_P(reg) ((reg>>16)&0x3)
#define PLL_CPU_FACTOR_N(reg) ((reg>>8)&0x1f)
#define PLL_CPU_FACTOR_K(reg) ((reg>>4)&0x3)
#define PLL_CPU_FACTOR_M(reg) ((reg)&0x3)
#define PLL_AUDIO_ENABLE_STATE (0x1<<31)
#define PLL_AUDIO_HAS_BEEN_STABLE (0x1<<28)
#define PLL_AUDIO_FACTOR_N(reg) ((reg>>8)&0x7f)
#define PLL_AUDIO_PREDIV_M(reg) ((reg)&0x1f)
#define PLL_VIDEO_ENABLE_STATE (0x1<<31)
#define PLL_VIDEO_MODE (0x1<<30)
#define PLL_VIDEO_HAS_BEEN_STABLE (0x1<<28)
#define PLL_VIDEO_FRAC_CLK_OUT (0x1<<25)
#define PLL_VIDEO_MODE_SEL (0x1<<24)
#define PLL_VIDEO_SDM_EN (0x1<<20)
#define PLL_VIDEO_FACTOR_N(reg) ((reg>>8)&0x7f)
#define PLL_VIDEO_PREDIV_M(reg) (reg&0xf)
#define PLL_VE_ENABLE_STATE (0x1<<31)
#define PLL_VE_HAS_BEEN_STABLE (0x1<<28)
#define PLL_VE_FRAC_CLK_OUT (0x1<<25)
#define PLL_VE_MODE_SEL (0x1<<24)
#define PLL_VE_FACTOR_N(reg) ((reg>>8)&0x7f)
#define PLL_VE_PREDIV_M(reg) (reg&0xf)
#define PLL_DDR_ENABLE_STATE (0x1<<31)
#define PLL_DDR_HAS_BEEN_STABLE (0x1<<28)
#define SDRAM_SIGMA_DELTA_EN (0x1<<24)
#define PLL_DDR_CFG_UPDATE (0x1<<20)
#define PLL_DDR_FACTOR_N(reg) ((reg>>8)&0x1f)
#define PLL_DDR_FACTOR_K(reg) ((reg>>4)&0x3)
#define PLL_DDR_FACTOR_M(reg) ((reg)&0x3)
#define PLL_PERIPH_ENABLE_STATE (0x1<<31)
#define PLL_PERIPH_HAS_BEEN_STABLE (0x1<<28)
#define PLL_PERIPH_24M_OUT_EN (0x1<<18)
#define PLL_PERIPH_24M_POST_DIV(reg) ((reg>>16)&0x3)
#define PLL_PERIPH_FACTOR_N(reg) ((reg>>8)&0x1f)
#define PLL_PERIPH_FACTOR_K(reg) ((reg>>4)&0x3)
#define PLL_PERIPH_FACTOR_M(reg) (reg&0x3)
#define HCLKC_DIV(reg) ((reg>>16)&0x3)
#define AHB_SRC_SEL(reg) ((reg>>12)&0x3)
#define AHB_CLK_DIV(reg) ((reg>>4)&0x3)
#define AHB_PRE_DIV(reg) ((reg>>6)&0x3)
#define APH_CLK_PATIO(reg) ((reg>>8)&0x3)
#define CCM_MMC_CTRL_OSCM24 (0x00)
#define CCM_MMC_CTRL_PLL_PERIPH (0x01)
#define CCU_BASE_ADDR (0x01C20000)
#define _24MHZ_ (24000000U)
#define _32KHZ_ (32000U)
/* GATE */
#define BUS_GATE_OFFSET_BIT (12)
enum bus_gate
{
USB_OTG_GATING = (0x18 | (0x0 << BUS_GATE_OFFSET_BIT)),
SPI1_GATING = (0x15 | (0x0 << BUS_GATE_OFFSET_BIT)),
SPI0_GATING = (0x14 | (0x0 << BUS_GATE_OFFSET_BIT)),
SDRAM_GATING = (0x0E | (0x0 << BUS_GATE_OFFSET_BIT)),
SD1_GATING = (0x09 | (0x0 << BUS_GATE_OFFSET_BIT)),
SD0_GATING = (0x08 | (0x0 << BUS_GATE_OFFSET_BIT)),
DMA_GATING = (0x06 | (0x0 << BUS_GATE_OFFSET_BIT)),
DEFE_GATING = (0x0E | (0x1 << BUS_GATE_OFFSET_BIT)),
DEBE_GATING = (0x0C | (0x1 << BUS_GATE_OFFSET_BIT)),
TVE_GATING = (0x0A | (0x1 << BUS_GATE_OFFSET_BIT)),
TVD_GATING = (0x09 | (0x1 << BUS_GATE_OFFSET_BIT)),
CSI_GATING = (0x08 | (0x1 << BUS_GATE_OFFSET_BIT)),
DEINTERLACE_GATING = (0x05 | (0x1 << BUS_GATE_OFFSET_BIT)),
LCD_GATING = (0x04 | (0x1 << BUS_GATE_OFFSET_BIT)),
VE_GATING = (0x00 | (0x1 << BUS_GATE_OFFSET_BIT)),
UART2_GATING = (0x16 | (0x2 << BUS_GATE_OFFSET_BIT)),
UART1_GATING = (0x15 | (0x2 << BUS_GATE_OFFSET_BIT)),
UART0_GATING = (0x14 | (0x2 << BUS_GATE_OFFSET_BIT)),
TWI2_GATING = (0x12 | (0x2 << BUS_GATE_OFFSET_BIT)),
TWI1_GATING = (0x11 | (0x2 << BUS_GATE_OFFSET_BIT)),
TWI0_GATING = (0x10 | (0x2 << BUS_GATE_OFFSET_BIT)),
DAUDIO_GATING = (0x0C | (0x2 << BUS_GATE_OFFSET_BIT)),
RSB_GATING = (0x03 | (0x2 << BUS_GATE_OFFSET_BIT)),
CIR_GATING = (0x02 | (0x2 << BUS_GATE_OFFSET_BIT)),
OWA_GATING = (0x01 | (0x2 << BUS_GATE_OFFSET_BIT)),
AUDIO_CODEC_GATING = (0x00 | (0x2 << BUS_GATE_OFFSET_BIT)),
};
struct tina_ccu
{
volatile rt_uint32_t pll_cpu_ctrl; /* 0x000 */
volatile rt_uint32_t reserved0;
volatile rt_uint32_t pll_audio_ctrl; /* 0x008 */
volatile rt_uint32_t reserved1;
volatile rt_uint32_t pll_video_ctrl; /* 0x010 */
volatile rt_uint32_t reserved2;
volatile rt_uint32_t pll_ve_ctrl; /* 0x018 */
volatile rt_uint32_t reserved3;
volatile rt_uint32_t pll_ddr_ctrl; /* 0x020 */
volatile rt_uint32_t reserved4;
volatile rt_uint32_t pll_periph_ctrl; /* 0x028 */
volatile rt_uint32_t reserved5[9];
volatile rt_uint32_t cpu_clk_src; /* 0x050 */
volatile rt_uint32_t ahb_apb_hclkc_cfg; /* 0x054 */
volatile rt_uint32_t reserved6[2];
volatile rt_uint32_t bus_clk_gating0; /* 0x060 */
volatile rt_uint32_t bus_clk_gating1; /* 0x064 */
volatile rt_uint32_t bus_clk_gating2; /* 0x068 */
volatile rt_uint32_t reserved7[7];
volatile rt_uint32_t sdmmc0_clk; /* 0x088 */
volatile rt_uint32_t sdmmc1_clk; /* 0x08C */
volatile rt_uint32_t reserved8[8];
volatile rt_uint32_t daudio_clk; /* 0x0B0 */
volatile rt_uint32_t owa_clk; /* 0x0B4 */
volatile rt_uint32_t cir_clk; /* 0x0B8 */
volatile rt_uint32_t reserved9[4];
volatile rt_uint32_t usbphy_clk; /* 0x0CC */
volatile rt_uint32_t reserved10[12];
volatile rt_uint32_t dram_gating; /* 0x100 */
volatile rt_uint32_t be_clk; /* 0x104 */
volatile rt_uint32_t reserved11;
volatile rt_uint32_t fe_clk; /* 0x10C */
volatile rt_uint32_t reserved12[2];
volatile rt_uint32_t tcon_clk; /* 0x118*/
volatile rt_uint32_t di_clk; /* 0x11C */
volatile rt_uint32_t tve_clk; /* 0x120 */
volatile rt_uint32_t tvd_clk; /* 0x124 */
volatile rt_uint32_t reserved13[3];
volatile rt_uint32_t csi_clk; /* 0x134 */
volatile rt_uint32_t reserved14;
volatile rt_uint32_t ve_clk; /* 0x13C */
volatile rt_uint32_t audio_codec_clk; /* 0x140 */
volatile rt_uint32_t avs_clk; /* 0x144 */
volatile rt_uint32_t reserved15[46];
volatile rt_uint32_t pll_stable_time0; /* 0x200 */
volatile rt_uint32_t pll_stable_time1; /* 0x204 */
volatile rt_uint32_t reserved16[6];
volatile rt_uint32_t pll_cpu_bias; /* 0x220 */
volatile rt_uint32_t pll_audio_bias; /* 0x224 */
volatile rt_uint32_t pll_video_bias; /* 0x228 */
volatile rt_uint32_t pll_ve_bias; /* 0x22C */
volatile rt_uint32_t pll_ddr_bias; /* 0x230 */
volatile rt_uint32_t pll_periph_bias; /* 0x234 */
volatile rt_uint32_t reserved17[6];
volatile rt_uint32_t pll_cpu_tun; /* 0x250 */
volatile rt_uint32_t reserved18[3];
volatile rt_uint32_t pll_ddr_tun; /* 0x260 */
volatile rt_uint32_t reserved19[8];
volatile rt_uint32_t pll_audio_pat_ctrl; /* 0x284 */
volatile rt_uint32_t pll_video_pat_ctrl; /* 0x288 */
volatile rt_uint32_t reserved20;
volatile rt_uint32_t pll_ddr_pat_ctrl; /* 0x290 */
volatile rt_uint32_t reserved21[11];
volatile rt_uint32_t bus_soft_rst0; /* 0x2C0 */
volatile rt_uint32_t bus_soft_rst1; /* 0x2C4 */
volatile rt_uint32_t reserved22[2];
volatile rt_uint32_t bus_soft_rst2; /* 0x2D0 */
};
typedef struct tina_ccu *tina_ccu_t;
#define CCU ((tina_ccu_t) CCU_BASE_ADDR)
int cpu_get_pll_clk(void);
int audio_get_pll_clk(void);
int video_get_pll_clk(void);
int ve_get_pll_clk(void);
int ddr_get_pll_clk(void);
int periph_get_pll_clk(void);
int cpu_get_clk(void);
int ahb_get_clk(void);
int apb_get_clk(void);
rt_err_t cpu_set_pll_clk(int clk);
rt_err_t audio_set_pll_clk(int clk);
rt_err_t video_set_pll_clk(int clk);
rt_err_t ve_set_pll_clk(int clk);
rt_err_t periph_set_pll_clk(int clk);
rt_err_t cpu_set_clk(int clk);
rt_err_t bus_gate_clk_enalbe(enum bus_gate bus);
rt_err_t bus_gate_clk_disalbe(enum bus_gate bus);
rt_err_t bus_software_reset_enalbe(enum bus_gate bus);
rt_err_t bus_software_reset_disalbe(enum bus_gate bus);
#endif
\ No newline at end of file
/*
* File : drv_gpio.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2017, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2018-02-08 RT-Thread the first version
*/
#include <rtthread.h>
#include <rthw.h>
#include "drv_gpio.h"
#include "interrupt.h"
#define DBG_ENABLE
#define DBG_SECTION_NAME "[GPIO]"
#define DBG_LEVEL DBG_WARNING
#define DBG_COLOR
#include <rtdbg.h>
#define readl(addr) (*(volatile unsigned int *)(addr))
#define writel(value,addr) (*(volatile unsigned int *)(addr) = (value))
// Todo: add RT_ASSERT.
/*********************************************************
** IO
*********************************************************/
int gpio_set_func(enum gpio_port port, enum gpio_pin pin, rt_uint8_t func)
{
rt_uint32_t addr;
rt_uint32_t offset;
rt_uint32_t data;
RT_ASSERT((GPIO_PORT_A <= port) && (port < GPIO_PORT_NUM));
RT_ASSERT((GPIO_PIN_0 <= pin) && (pin < GPIO_PIN_NUM));
if (func & 0x8)
{
dbg_log(DBG_WARNING, "[line]:%d There is a warning with parameter input\n", __LINE__);
return RT_EINVAL;
}
addr = GPIOn_CFG_ADDR(port) + (pin / 8) * 4;
offset = (pin % 8) * 4;
data = readl(addr);
data &= ~(0x7 << offset);
data |= func << offset;
writel(data, addr);
dbg_log(DBG_LOG, "[line]:%d offset:%d addr:%08x data:%08x\n", __LINE__, offset, addr, *((rt_uint32_t *)addr));
return RT_EOK;
}
int gpio_set_value(enum gpio_port port, enum gpio_pin pin, rt_uint8_t value)
{
rt_uint32_t addr;
rt_uint32_t offset;
rt_uint32_t data;
RT_ASSERT((GPIO_PORT_A <= port) && (port < GPIO_PORT_NUM));
RT_ASSERT((GPIO_PIN_0 <= pin) && (pin < GPIO_PIN_NUM));
if (value & 0xE)
{
dbg_log(DBG_WARNING, "[line]:%d There is a warning with parameter input\n", __LINE__);
return RT_EINVAL;
}
addr = GPIOn_DATA_ADDR(port);
offset = pin;
data = readl(addr);
data &= ~(0x1 << offset);
data |= value << offset;
writel(data, addr);
dbg_log(DBG_LOG, "[line]:%d offset:%d addr:%08x data:%08x\n", __LINE__, offset, addr, *((rt_uint32_t *)addr));
return RT_EOK;
}
int gpio_get_value(enum gpio_port port, enum gpio_pin pin)
{
rt_uint32_t addr;
rt_uint32_t offset;
rt_uint32_t data;
RT_ASSERT((GPIO_PORT_A <= port) && (port < GPIO_PORT_NUM));
RT_ASSERT((GPIO_PIN_0 <= pin) && (pin < GPIO_PIN_NUM));
addr = GPIOn_DATA_ADDR(port);
offset = pin;
data = readl(addr);
dbg_log(DBG_LOG, "[line]:%d offset:%d addr:%08x data:%08x\n", __LINE__, offset, addr, *((rt_uint32_t *)addr));
return (data >> offset) & 0x01;
}
int gpio_set_pull_mode(enum gpio_port port, enum gpio_pin pin, enum gpio_pull pull)
{
rt_uint32_t addr;
rt_uint32_t offset;
rt_uint32_t data;
RT_ASSERT((GPIO_PORT_A <= port) && (port < GPIO_PORT_NUM));
RT_ASSERT((GPIO_PIN_0 <= pin) && (pin < GPIO_PIN_NUM));
if (pull & 0xC)
{
dbg_log(DBG_WARNING, "[line]:%d There is a warning with parameter input\n", __LINE__);
return RT_EINVAL;
}
addr = GPIOn_PUL_ADDR(port);
addr += pin > GPIO_PIN_15 ? 0x4 : 0x0;
offset = (pin & 0xf) << 1;
data = readl(addr);
data &= ~(0x3 << offset);
data |= pull << offset;
writel(data, addr);
dbg_log(DBG_LOG, "[line]:%d offset:%d addr:%08x data:%08x\n", __LINE__, offset, addr, *((rt_uint32_t *)addr));
return RT_EOK;
}
int gpio_set_drive_level(enum gpio_port port, enum gpio_pin pin, enum gpio_drv_level level)
{
volatile rt_uint32_t addr;
rt_uint32_t offset;
rt_uint32_t data;
RT_ASSERT((GPIO_PORT_A <= port) && (port < GPIO_PORT_NUM));
RT_ASSERT((GPIO_PIN_0 <= pin) && (pin < GPIO_PIN_NUM));
if (level & 0xC)
{
dbg_log(DBG_WARNING, "[line]:%d There is a warning with parameter input\n", __LINE__);
return RT_EINVAL;
}
addr = GPIOn_DRV_ADDR(port);
addr += pin > GPIO_PIN_15 ? 0x4 : 0x0;
offset = (pin & 0xf) << 1;
data = readl(addr);
data &= ~(0x3 << offset);
data |= level << offset;
writel(data, addr);
dbg_log(DBG_LOG, "[line]:%d offset:%d addr:%08x data:%08x\n", __LINE__, offset, addr, *((rt_uint32_t *)addr));
return RT_EOK;
}
void gpio_direction_input(enum gpio_port port, enum gpio_pin pin)
{
volatile rt_uint32_t addr;
rt_uint32_t offset;
rt_uint32_t data;
RT_ASSERT((GPIO_PORT_A <= port) && (port < GPIO_PORT_NUM));
RT_ASSERT((GPIO_PIN_0 <= pin) && (pin < GPIO_PIN_NUM));
addr = GPIOn_CFG_ADDR(port) + (pin / 8) * 4;
offset = (pin % 8) * 4;
data = readl(addr);
data &= ~(0x7 << offset);
data |= IO_INPUT << offset;
writel(data, addr);
dbg_log(DBG_LOG, "[line]:%d offset:%d addr:%08x data:%08x\n", __LINE__, offset, addr, *((rt_uint32_t *)addr));
}
void gpio_direction_output(enum gpio_port port, enum gpio_pin pin, int value)
{
volatile rt_uint32_t addr;
rt_uint32_t offset;
rt_uint32_t data;
RT_ASSERT((GPIO_PORT_A <= port) && (port < GPIO_PORT_NUM));
RT_ASSERT((GPIO_PIN_0 <= pin) && (pin < GPIO_PIN_NUM));
gpio_set_value(port, pin, value);
addr = GPIOn_CFG_ADDR(port) + (pin / 8) * 4;
offset = (pin % 8) * 4;
data = readl(addr);
data &= ~(0x7 << offset);
data |= IO_OUTPUT << offset;
writel(data, addr);
dbg_log(DBG_LOG, "[line]:%d offset:%d addr:%08x data:%08x\n", __LINE__, offset, addr, *((rt_uint32_t *)addr));
}
/*********************************************************
** IRQ
*********************************************************/
static void gpio_ack_irq(enum gpio_port port, enum gpio_pin pin)
{
rt_uint32_t addr;
rt_uint32_t data;
addr = GPIOn_INT_STA_ADDR(port);
data = readl(addr);
data |= 0x1 << pin;
writel(data, addr);
}
void gpio_select_irq_clock(enum gpio_port port, enum gpio_irq_clock clock)
{
rt_uint32_t addr;
rt_uint32_t data;
RT_ASSERT((GPIO_PORT_C < port) && (port < GPIO_PORT_NUM));
addr = GPIOn_INT_DEB_ADDR(port - GPIO_PORT_D);
data = readl(addr);
data &= ~0x01;
data |= clock;
writel(data, addr);
dbg_log(DBG_LOG, "[line]:%d addr:%08x data:%08x\n", __LINE__, addr, *((rt_uint32_t *)addr));
}
void gpio_set_debounce(enum gpio_port port, enum gpio_direction_type prescaler)
{
rt_uint32_t addr;
rt_uint32_t data;
RT_ASSERT((GPIO_PORT_C < port) && (port < GPIO_PORT_NUM));
addr = GPIOn_INT_DEB_ADDR(port - GPIO_PORT_D);
data = readl(addr);
data &= ~(0x07 << 4);
data |= prescaler << 4;
writel(data, addr);
dbg_log(DBG_LOG, "[line]:%d addr:%08x data:%08x\n", __LINE__, addr, *((rt_uint32_t *)addr));
}
void gpio_irq_enable(enum gpio_port port, enum gpio_pin pin)
{
rt_uint32_t addr;
rt_uint32_t offset;
rt_uint32_t data;
RT_ASSERT((GPIO_PORT_C < port) && (port < GPIO_PORT_NUM));
RT_ASSERT((GPIO_PIN_0 <= pin) && (pin < GPIO_PIN_NUM));
addr = GPIOn_INT_CTRL_ADDR(port - GPIO_PORT_D);
offset = pin;
data = readl(addr);
data |= 0x1 << offset;
writel(data, addr);
gpio_select_irq_clock(port, GPIO_IRQ_HOSC_24MHZ);
dbg_log(DBG_LOG, "[line]:%d offset:%d addr:%08x data:%08x\n", __LINE__, offset, addr, *((rt_uint32_t *)addr));
}
void gpio_irq_disable(enum gpio_port port, enum gpio_pin pin)
{
rt_uint32_t addr;
rt_uint32_t offset;
rt_uint32_t data;
RT_ASSERT((GPIO_PORT_C < port) && (port < GPIO_PORT_NUM));
RT_ASSERT((GPIO_PIN_0 <= pin) && (pin < GPIO_PIN_NUM));
gpio_ack_irq(port - GPIO_PORT_D, pin);
addr = GPIOn_INT_CTRL_ADDR(port - GPIO_PORT_D);
offset = pin;
data = readl(addr);
data &= ~(0x1 << offset);
writel(data, addr);
dbg_log(DBG_LOG, "[line]:%d offset:%d addr:%08x data:%08x\n", __LINE__, offset, addr, *((rt_uint32_t *)addr));
}
void gpio_set_irq_type(enum gpio_port port, enum gpio_pin pin, enum gpio_irq_type irq_type)
{
rt_uint32_t addr;
rt_uint32_t offset;
rt_uint32_t data;
RT_ASSERT((GPIO_PORT_C < port) && (port < GPIO_PORT_NUM));
RT_ASSERT((GPIO_PIN_0 <= pin) && (pin < GPIO_PIN_NUM));
addr = GPIOn_INT_CFG_ADDR(port - GPIO_PORT_D) + (pin / 8) * 4;
offset = (pin % 8) * 4;
data = readl(addr);
data &= ~(0x7 << offset);
data |= irq_type << offset;
writel(data, addr);
dbg_log(DBG_LOG, "[line]:%d offset:%d addr:%08x data:%08x\n", __LINE__, offset, addr, *((rt_uint32_t *)addr));
}
static struct gpio_irq_def _g_gpio_irq_tbl[GPIO_PORT_NUM];
void gpio_set_irq_callback(enum gpio_port port, enum gpio_pin pin, void (*irq_cb)(void *), void *irq_arg)
{
RT_ASSERT((GPIO_PORT_C < port) && (port < GPIO_PORT_NUM));
RT_ASSERT((GPIO_PIN_0 <= pin) && (pin < GPIO_PIN_NUM));
_g_gpio_irq_tbl[port].irq_cb[pin] = irq_cb;
_g_gpio_irq_tbl[port].irq_arg[pin] = irq_arg;
}
void gpio_clear_irq_callback(enum gpio_port port, enum gpio_pin pin)
{
gpio_irq_disable(port, pin);
_g_gpio_irq_tbl[port].irq_cb[pin] = RT_NULL;
_g_gpio_irq_tbl[port].irq_arg[pin] = RT_NULL;
}
static void gpio_irq_handler(int irq, void *param)
{
struct gpio_irq_def *irq_def = (struct gpio_irq_def *)param;
rt_uint32_t pend, enable;
int port, pin;
rt_uint32_t addr;
pin = 0;
port = irq - PIOD_INTERRUPT;
addr = GPIOn_INT_STA_ADDR(port);
pend = readl(addr);
addr = GPIOn_INT_CTRL_ADDR(port);
enable = readl(addr);
pend &= enable;
while (pend)
{
if ((pend & 0x1) && (irq_def->irq_cb[pin] != RT_NULL))
{
dbg_log(DBG_LOG, "do irq callback...\n", port, pin);
irq_def->irq_cb[pin](irq_def->irq_arg[pin]);
}
pin++;
pend = pend >> 1;
gpio_ack_irq(port, pin);
}
}
#ifdef RT_USING_PIN
#include <rtdevice.h>
#define PIN_MAGIC (0x5A)
#define PIN_NUM(_N) (sizeof(_N) / sizeof(_N[0]))
struct _pin_index
{
rt_uint8_t id;
rt_uint8_t pin_port;
rt_uint8_t pin;
rt_uint8_t magic;
};
static struct _pin_index pin_index[] =
{
{0, 0, 0, 0},
{1, 0, 0, 0},
{2, 0, 0, 0},
{3, 0, 0, 0},
{4, 0, 0, 0},
{5, 0, 0, 0},
{6, GPIO_PORT_D, GPIO_PIN_0, PIN_MAGIC},
{7, GPIO_PORT_D, GPIO_PIN_1, PIN_MAGIC},
{8, GPIO_PORT_D, GPIO_PIN_2, PIN_MAGIC},
{9, GPIO_PORT_D, GPIO_PIN_3, PIN_MAGIC},
{10, GPIO_PORT_D, GPIO_PIN_4, PIN_MAGIC},
{11, GPIO_PORT_D, GPIO_PIN_5, PIN_MAGIC},
{12, GPIO_PORT_D, GPIO_PIN_6, PIN_MAGIC},
{13, GPIO_PORT_D, GPIO_PIN_7, PIN_MAGIC},
{14, GPIO_PORT_D, GPIO_PIN_8, PIN_MAGIC},
{15, GPIO_PORT_D, GPIO_PIN_9, PIN_MAGIC},
{16, GPIO_PORT_D, GPIO_PIN_10, PIN_MAGIC},
{17, GPIO_PORT_D, GPIO_PIN_11, PIN_MAGIC},
{18, GPIO_PORT_D, GPIO_PIN_12, PIN_MAGIC},
{19, GPIO_PORT_D, GPIO_PIN_13, PIN_MAGIC},
{20, 0, 0, 0},
{21, GPIO_PORT_D, GPIO_PIN_14, PIN_MAGIC},
{22, 0, 0, 0},
{23, GPIO_PORT_D, GPIO_PIN_15, PIN_MAGIC},
{24, GPIO_PORT_D, GPIO_PIN_16, PIN_MAGIC},
{25, GPIO_PORT_D, GPIO_PIN_17, PIN_MAGIC},
{26, GPIO_PORT_D, GPIO_PIN_18, PIN_MAGIC},
{27, GPIO_PORT_D, GPIO_PIN_19, PIN_MAGIC},
{28, GPIO_PORT_D, GPIO_PIN_20, PIN_MAGIC},
{29, GPIO_PORT_D, GPIO_PIN_21, PIN_MAGIC},
{30, 0, 0, 0},
{31, 0, 0, 0},
{32, 0, 0, 0},
{33, 0, 0, 0},
{34, 0, 0, 0},
{35, 0, 0, 0},
{36, 0, 0, 0},
{37, GPIO_PORT_E, GPIO_PIN_12, PIN_MAGIC},
{38, GPIO_PORT_E, GPIO_PIN_11, PIN_MAGIC},
{39, GPIO_PORT_E, GPIO_PIN_10, PIN_MAGIC},
{40, GPIO_PORT_E, GPIO_PIN_9, PIN_MAGIC},
{41, GPIO_PORT_E, GPIO_PIN_8, PIN_MAGIC},
{42, GPIO_PORT_E, GPIO_PIN_7, PIN_MAGIC},
{43, GPIO_PORT_E, GPIO_PIN_6, PIN_MAGIC},
{44, GPIO_PORT_E, GPIO_PIN_5, PIN_MAGIC},
{45, GPIO_PORT_E, GPIO_PIN_4, PIN_MAGIC},
{46, GPIO_PORT_E, GPIO_PIN_3, PIN_MAGIC},
{47, GPIO_PORT_E, GPIO_PIN_2, PIN_MAGIC},
{48, GPIO_PORT_E, GPIO_PIN_1, PIN_MAGIC},
{49, GPIO_PORT_E, GPIO_PIN_0, PIN_MAGIC},
{50, 0, 0, 0},
{51, 0, 0, 0},
{52, 0, 0, 0},
{53, GPIO_PORT_F, GPIO_PIN_5, PIN_MAGIC},
{54, GPIO_PORT_F, GPIO_PIN_4, PIN_MAGIC},
{55, GPIO_PORT_F, GPIO_PIN_3, PIN_MAGIC},
{56, GPIO_PORT_F, GPIO_PIN_2, PIN_MAGIC},
{57, GPIO_PORT_F, GPIO_PIN_1, PIN_MAGIC},
{58, GPIO_PORT_F, GPIO_PIN_0, PIN_MAGIC},
{59, GPIO_PORT_C, GPIO_PIN_0, PIN_MAGIC},
{60, GPIO_PORT_C, GPIO_PIN_1, PIN_MAGIC},
{61, GPIO_PORT_C, GPIO_PIN_2, PIN_MAGIC},
{62, GPIO_PORT_C, GPIO_PIN_3, PIN_MAGIC},
{63, GPIO_PORT_A, GPIO_PIN_3, PIN_MAGIC},
{64, GPIO_PORT_A, GPIO_PIN_2, PIN_MAGIC},
{65, GPIO_PORT_A, GPIO_PIN_1, PIN_MAGIC},
{66, GPIO_PORT_A, GPIO_PIN_0, PIN_MAGIC},
};
static void pin_mode(struct rt_device *dev, rt_base_t pin, rt_base_t mode)
{
if ((pin > PIN_NUM(pin_index)) || (pin_index[pin].magic != PIN_MAGIC))
{
dbg_log(DBG_ERROR, "pin:%d value wrongful\n", pin);
return;
}
gpio_set_func(pin_index[pin].pin_port, pin_index[pin].pin, mode);
}
static void pin_write(struct rt_device *dev, rt_base_t pin, rt_base_t value)
{
if ((pin > PIN_NUM(pin_index)) || (pin_index[pin].magic != PIN_MAGIC))
{
dbg_log(DBG_ERROR, "pin:%d value wrongful\n", pin);
return;
}
gpio_set_value(pin_index[pin].pin_port, pin_index[pin].pin, value);
}
static int pin_read(struct rt_device *device, rt_base_t pin)
{
if ((pin > PIN_NUM(pin_index)) || (pin_index[pin].magic != PIN_MAGIC))
{
dbg_log(DBG_ERROR, "pin:%d value wrongful\n", pin);
return 0;
}
return gpio_get_value(pin_index[pin].pin_port, pin_index[pin].pin);
}
static rt_err_t pin_attach_irq(struct rt_device *device, rt_int32_t pin, rt_uint32_t mode, void (*hdr)(void *args), void *args)
{
if ((pin > PIN_NUM(pin_index)) || (pin_index[pin].magic != PIN_MAGIC))
{
dbg_log(DBG_ERROR, "pin:%d value wrongful\n", pin);
return RT_ERROR;
}
gpio_set_irq_callback(pin_index[pin].pin_port, pin_index[pin].pin, hdr, args);
gpio_set_irq_type(pin_index[pin].pin_port, pin_index[pin].pin, mode);
return RT_EOK;
}
static rt_err_t pin_dettach_irq(struct rt_device *device, rt_int32_t pin)
{
if ((pin > PIN_NUM(pin_index)) || (pin_index[pin].magic != PIN_MAGIC))
{
dbg_log(DBG_ERROR, "pin:%d value wrongful\n", pin);
return RT_ERROR;
}
gpio_clear_irq_callback(pin_index[pin].pin_port, pin_index[pin].pin);
return RT_EOK;
}
rt_err_t pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint32_t enabled)
{
if ((pin > PIN_NUM(pin_index)) || (pin_index[pin].magic != PIN_MAGIC))
{
dbg_log(DBG_ERROR, "pin:%d value wrongful\n", pin);
return RT_ERROR;
}
if (enabled)
gpio_irq_enable(pin_index[pin].pin_port, pin_index[pin].pin);
else
gpio_irq_disable(pin_index[pin].pin_port, pin_index[pin].pin);
return RT_EOK;
}
/*
ID GPIO ID GPIO ID GPIO ID GPIO ID GPIO ID GPIO ID GPIO
6 PD0 13 PD7 21 PD14 29 PD21 43 PE6 53 PF5 60 PC1
7 PD1 14 PD8 23 PD15 37 PE12 44 PE5 54 PF4 61 PC2
8 PD2 15 PD9 24 PD16 38 PE11 45 PE4 55 PF3 62 PC3
9 PD3 16 PD10 25 PD17 39 PE10 46 PE3 56 PF2 63 PA3
10 PD4 17 PD11 26 PD18 40 PE9 47 PE2 57 PF1 64 PA2
11 PD5 18 PD12 27 PD19 41 PE8 48 PE1 58 PF0 65 PA1
12 PD6 19 PD13 28 PD20 42 PE7 49 PE0 59 PC0 66 PA0
*/
static const struct rt_pin_ops ops =
{
pin_mode,
pin_write,
pin_read,
pin_attach_irq,
pin_dettach_irq,
pin_irq_enable,
};
#endif
int rt_hw_gpio_init(void)
{
#ifdef RT_USING_PIN
rt_device_pin_register("gpio", &ops, RT_NULL);
#endif
/* install ISR */
rt_hw_interrupt_install(PIOD_INTERRUPT, gpio_irq_handler, &_g_gpio_irq_tbl[GPIO_PORT_D], "gpiod_irq");
rt_hw_interrupt_umask(PIOD_INTERRUPT);
rt_hw_interrupt_install(PIOE_INTERRUPT, gpio_irq_handler, &_g_gpio_irq_tbl[GPIO_PORT_E], "gpioe_irq");
rt_hw_interrupt_umask(PIOE_INTERRUPT);
rt_hw_interrupt_install(PIOF_INTERRUPT, gpio_irq_handler, &_g_gpio_irq_tbl[GPIO_PORT_F], "gpiof_irq");
rt_hw_interrupt_umask(PIOF_INTERRUPT);
return 0;
}
INIT_DEVICE_EXPORT(rt_hw_gpio_init);
/*
* File : drv_gpio.h
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2017, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2018-02-08 RT-Thread the first version
*/
#ifndef __DRV_GPIO_H__
#define __DRV_GPIO_H__
/* IO default function */
#define IO_INPUT (0x00)
#define IO_OUTPUT (0x01)
#define IO_DISABLE (0x07)
#define IO_FUN_1 (0x02)
#define IO_FUN_2 (0x03)
#define IO_FUN_3 (0x04)
#define IO_FUN_4 (0x05)
#define IO_FUN_5 (0x06)
/* IO port */
enum gpio_port
{
GPIO_PORT_A = 0,
GPIO_PORT_B,
GPIO_PORT_C,
GPIO_PORT_D,
GPIO_PORT_E,
GPIO_PORT_F,
GPIO_PORT_NUM,
};
/* IO pin */
enum gpio_pin
{
GPIO_PIN_0 = 0,
GPIO_PIN_1,
GPIO_PIN_2,
GPIO_PIN_3,
GPIO_PIN_4,
GPIO_PIN_5,
GPIO_PIN_6,
GPIO_PIN_7,
GPIO_PIN_8,
GPIO_PIN_9,
GPIO_PIN_10,
GPIO_PIN_11,
GPIO_PIN_12,
GPIO_PIN_13,
GPIO_PIN_14,
GPIO_PIN_15,
GPIO_PIN_16,
GPIO_PIN_17,
GPIO_PIN_18,
GPIO_PIN_19,
GPIO_PIN_20,
GPIO_PIN_21,
GPIO_PIN_22,
GPIO_PIN_23,
GPIO_PIN_NUM,
};
/* Drive level */
enum gpio_drv_level
{
DRV_LEVEL_0 = 0,
DRV_LEVEL_1,
DRV_LEVEL_2,
DRV_LEVEL_3,
};
/* Pull mode */
enum gpio_pull
{
PULL_DISABLE = 0,
PULL_UP,
PULL_DOWN,
};
/* interrupt type */
enum gpio_irq_type
{
POSITIVE = 0,
NEGATIVE,
HIGH,
LOW,
DOUBLE,
};
enum gpio_irq_clock
{
GPIO_IRQ_LOSC_32KHZ = 0,
GPIO_IRQ_HOSC_24MHZ
};
enum gpio_direction_type
{
DEBOUNCE_PRE_SCALE_1 = 0,
DEBOUNCE_PRE_SCALE_2,
DEBOUNCE_PRE_SCALE_4,
DEBOUNCE_PRE_SCALE_8,
DEBOUNCE_PRE_SCALE_16,
DEBOUNCE_PRE_SCALE_32,
DEBOUNCE_PRE_SCALE_64,
DEBOUNCE_PRE_SCALE_128,
};
struct gpio_irq_def
{
void *irq_arg[32];
void (*irq_cb[32])(void *param);
};
#define GPIO_BASE_ADDR (0x01C20800)
#define GPIOn_CFG_ADDR(n) (GPIO_BASE_ADDR + (n) * 0x24 + 0x00)
#define GPIOn_DATA_ADDR(n) (GPIO_BASE_ADDR + (n) * 0x24 + 0x10)
#define GPIOn_DRV_ADDR(n) (GPIO_BASE_ADDR + (n) * 0x24 + 0x14)
#define GPIOn_PUL_ADDR(n) (GPIO_BASE_ADDR + (n) * 0x24 + 0x1C)
#define GPIOn_INT_CFG_ADDR(n) (GPIO_BASE_ADDR + 0x200 + (n) * 0x20 + 0x00)
#define GPIOn_INT_CTRL_ADDR(n) (GPIO_BASE_ADDR + 0x200 + (n) * 0x20 + 0x10)
#define GPIOn_INT_STA_ADDR(n) (GPIO_BASE_ADDR + 0x200 + (n) * 0x20 + 0x14)
#define GPIOn_INT_DEB_ADDR(n) (GPIO_BASE_ADDR + 0x200 + (n) * 0x20 + 0x18)
struct tina_gpio
{
volatile rt_uint32_t pa_cfg0; /* 0x00 */
volatile rt_uint32_t pa_cfg1; /* 0x04 */
volatile rt_uint32_t pa_cfg2; /* 0x08 */
volatile rt_uint32_t pa_cfg3; /* 0x0C */
volatile rt_uint32_t pa_data; /* 0x10 */
volatile rt_uint32_t pa_drv0; /* 0x14 */
volatile rt_uint32_t pa_drv1; /* 0x18 */
volatile rt_uint32_t pa_pul0; /* 0x1C */
volatile rt_uint32_t pa_pul1; /* 0x20 */
volatile rt_uint32_t pb_cfg0; /* 0x24 */
volatile rt_uint32_t pb_cfg1; /* 0x28 */
volatile rt_uint32_t pb_cfg2; /* 0x2C */
volatile rt_uint32_t pb_cfg3; /* 0x30 */
volatile rt_uint32_t pb_data; /* 0x34 */
volatile rt_uint32_t pb_drv0; /* 0x38 */
volatile rt_uint32_t pb_drv1; /* 0x3C */
volatile rt_uint32_t pb_pul0; /* 0x40 */
volatile rt_uint32_t pb_pul1; /* 0x44 */
volatile rt_uint32_t pc_cfg0; /* 0x48 */
volatile rt_uint32_t pc_cfg1; /* 0x4C */
volatile rt_uint32_t pc_cfg2; /* 0x50 */
volatile rt_uint32_t pc_cfg3; /* 0x54 */
volatile rt_uint32_t pc_data; /* 0x58 */
volatile rt_uint32_t pc_drv0; /* 0x5C */
volatile rt_uint32_t pc_drv1; /* 0x60 */
volatile rt_uint32_t pc_pul0; /* 0x64 */
volatile rt_uint32_t pc_pul1; /* 0x68 */
volatile rt_uint32_t pd_cfg0; /* 0x6C */
volatile rt_uint32_t pd_cfg1; /* 0x70 */
volatile rt_uint32_t pd_cfg2; /* 0x74 */
volatile rt_uint32_t pd_cfg3; /* 0x78 */
volatile rt_uint32_t pd_data; /* 0x7C */
volatile rt_uint32_t pd_drv0; /* 0x80 */
volatile rt_uint32_t pd_drv1; /* 0x84 */
volatile rt_uint32_t pd_pul0; /* 0x88 */
volatile rt_uint32_t pd_pul1; /* 0x8C */
volatile rt_uint32_t pe_cfg0; /* 0x90 */
volatile rt_uint32_t pe_cfg1; /* 0x94 */
volatile rt_uint32_t pe_cfg2; /* 0x98 */
volatile rt_uint32_t pe_cfg3; /* 0x9C */
volatile rt_uint32_t pe_data; /* 0xA0 */
volatile rt_uint32_t pe_drv0; /* 0xA4 */
volatile rt_uint32_t pe_drv1; /* 0xA8 */
volatile rt_uint32_t pe_pul0; /* 0xAC */
volatile rt_uint32_t pe_pul1; /* 0xB0 */
volatile rt_uint32_t pf_cfg0; /* 0xB4 */
volatile rt_uint32_t pf_cfg1; /* 0xB8 */
volatile rt_uint32_t pf_cfg2; /* 0xBC */
volatile rt_uint32_t pf_cfg3; /* 0xC0 */
volatile rt_uint32_t pf_data; /* 0xC4 */
volatile rt_uint32_t pf_drv0; /* 0xC8 */
volatile rt_uint32_t pf_drv1; /* 0xCC */
volatile rt_uint32_t pf_pul0; /* 0xD0 */
volatile rt_uint32_t reserved0[76];
volatile rt_uint32_t pd_int_cfg0; /* 0x200 */
volatile rt_uint32_t pd_int_cfg1; /* 0x204 */
volatile rt_uint32_t pd_int_cfg2; /* 0x208 */
volatile rt_uint32_t pd_int_cfg3; /* 0x20C */
volatile rt_uint32_t pd_int_ctrl; /* 0x210 */
volatile rt_uint32_t pd_int_sta; /* 0x214 */
volatile rt_uint32_t pd_int_deb; /* 0x218 */
volatile rt_uint32_t reserved1;
volatile rt_uint32_t pe_int_cfg0; /* 0x220 */
volatile rt_uint32_t pe_int_cfg1; /* 0x224 */
volatile rt_uint32_t pe_int_cfg2; /* 0x228 */
volatile rt_uint32_t pe_int_cfg3; /* 0x22C */
volatile rt_uint32_t pe_int_ctrl; /* 0x230 */
volatile rt_uint32_t pe_int_sta; /* 0x234 */
volatile rt_uint32_t pe_int_deb; /* 0x238 */
volatile rt_uint32_t reserved2;
volatile rt_uint32_t pf_int_cfg0; /* 0x240 */
volatile rt_uint32_t pf_int_cfg1; /* 0x244 */
volatile rt_uint32_t pf_int_cfg2; /* 0x248 */
volatile rt_uint32_t pf_int_cfg3; /* 0x24C */
volatile rt_uint32_t pf_int_ctrl; /* 0x250 */
volatile rt_uint32_t pf_int_sta; /* 0x254 */
volatile rt_uint32_t pf_int_deb; /* 0x258 */
volatile rt_uint32_t reserved3[26];
volatile rt_uint32_t sdr_pad_drv; /* 0x2C0*/
volatile rt_uint32_t sdr_pad_pul; /* 0x2C4 */
};
typedef struct tina_gpio *tina_gpio_t;
#define GPIO ((tina_gpio_t)GPIO_BASE_ADDR)
int gpio_set_func(enum gpio_port port, enum gpio_pin pin, rt_uint8_t func);
int gpio_set_value(enum gpio_port port, enum gpio_pin pin, rt_uint8_t value);
int gpio_get_value(enum gpio_port port, enum gpio_pin pin);
int gpio_set_pull_mode(enum gpio_port port, enum gpio_pin pin, enum gpio_pull pull);
int gpio_set_drive_level(enum gpio_port port, enum gpio_pin pin, enum gpio_drv_level level);
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_irq_enable(enum gpio_port port, enum gpio_pin pin);
void gpio_irq_disable(enum gpio_port port, enum gpio_pin pin);
void gpio_set_irq_type(enum gpio_port port, enum gpio_pin pin, enum gpio_irq_type irq_type);
void gpio_select_irq_clock(enum gpio_port port, enum gpio_irq_clock clock);
void gpio_set_debounce(enum gpio_port port, rt_uint8_t prescaler);
void gpio_set_irq_callback(enum gpio_port port, enum gpio_pin pin, void (*irq_cb)(void *), void *irq_arg);
int rt_hw_gpio_init(void);
#endif /* __DRV_GPIO_H__ */
\ No newline at end of file
/*
* File : drv_uart.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2017, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2018-02-08 RT-Thread the first version
*/
#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>
#include "drv_uart.h"
#include "interrupt.h"
#include "drv_gpio.h"
#include "drv_clock.h"
#define readl(addr) (*(volatile unsigned int *)(addr))
#define writel(value,addr) (*(volatile unsigned int *)(addr) = (value))
#ifdef RT_USING_SERIAL
struct device_uart
{
rt_uint32_t hw_base;
rt_uint32_t irqno;
char name[RT_NAME_MAX];
rt_uint32_t gpio_rx_port;
rt_uint32_t gpio_tx_port;
rt_uint32_t gpio_rx_pin;
rt_uint32_t gpio_tx_pin;
rt_uint32_t gpio_rx_fun;
rt_uint32_t gpio_tx_fun;
};
static rt_err_t uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg);
static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *arg);
static int uart_putc(struct rt_serial_device *serial, char c);
static int uart_getc(struct rt_serial_device *serial);
static rt_size_t uart_dma_transmit(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction);
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
*/
int rt_hw_uart_init(void)
{
struct rt_serial_device *serial;
struct device_uart *uart;
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
#ifdef TINA_USING_UART0
{
static struct rt_serial_device serial0;
static struct device_uart uart0;
serial = &serial0;
uart = &uart0;
serial->ops = &_uart_ops;
serial->config = config;
serial->config.baud_rate = 115200;
uart->hw_base = UART0_BASE_ADDR; // UART0_BASE;
uart->irqno = UART0_INTERRUPT; // IRQ_UART0;
uart->gpio_rx_port = GPIO_PORT_E;
uart->gpio_tx_port = GPIO_PORT_E;
uart->gpio_rx_pin = GPIO_PIN_0;
uart->gpio_tx_pin = GPIO_PIN_1;
uart->gpio_rx_fun = IO_FUN_4;
uart->gpio_tx_fun = IO_FUN_4;
rt_hw_serial_register(serial,
"uart0",
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
uart);
}
#endif
#ifdef TINA_USING_UART1
{
static struct rt_serial_device serial1;
static struct device_uart uart1;
serial = &serial1;
uart = &uart1;
serial->ops = &_uart_ops;
serial->config = config;
serial->config.baud_rate = 115200;
uart->hw_base = UART1_BASE_ADDR; // UART1_BASE;
uart->irqno = UART1_INTERRUPT; // IRQ_UART1;
uart->gpio_rx_port = GPIO_PORT_A;
uart->gpio_tx_port = GPIO_PORT_A;
uart->gpio_rx_pin = GPIO_PIN_3;
uart->gpio_tx_pin = GPIO_PIN_2;
uart->gpio_rx_fun = IO_FUN_4;
uart->gpio_tx_fun = IO_FUN_4;
rt_hw_serial_register(serial,
"uart1",
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
uart);
}
#endif
#ifdef TINA_USING_UART2
{
static struct rt_serial_device serial2;
static struct device_uart uart2;
serial = &serial2;
uart = &uart2;
serial->ops = &_uart_ops;
serial->config = config;
serial->config.baud_rate = 115200;
uart->hw_base = UART2_BASE_ADDR; // UART1_BASE;
uart->irqno = UART2_INTERRUPT; // IRQ_UART1;
uart->gpio_rx_port = GPIO_PORT_E;
uart->gpio_tx_port = GPIO_PORT_E;
uart->gpio_rx_pin = GPIO_PIN_8;
uart->gpio_tx_pin = GPIO_PIN_7;
uart->gpio_rx_fun = IO_FUN_2;
uart->gpio_tx_fun = IO_FUN_2;
rt_hw_serial_register(serial,
"uart2",
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
uart);
}
#endif
return 0;
}
/*
* UART interface
*/
static rt_err_t uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
{
rt_uint32_t addr, val;
struct device_uart *uart;
RT_ASSERT(serial != RT_NULL);
serial->config = *cfg;
uart = serial->parent.user_data;
RT_ASSERT(uart != RT_NULL);
/* config gpio port */
gpio_set_func(uart->gpio_rx_port, uart->gpio_rx_pin, uart->gpio_rx_fun);
gpio_set_func(uart->gpio_tx_port, uart->gpio_tx_pin, uart->gpio_tx_fun);
/* Enable UART clock */
/* Open the clock gate for uart */
if ((rt_uint32_t)(uart->hw_base) == UART0_BASE_ADDR)
{
bus_gate_clk_enalbe(UART0_GATING);
bus_software_reset_enalbe(UART0_GATING);
}
else if ((rt_uint32_t)(uart->hw_base) == UART1_BASE_ADDR)
{
bus_gate_clk_enalbe(UART1_GATING);
bus_software_reset_enalbe(UART1_GATING);
}
else if ((rt_uint32_t)(uart->hw_base) == UART2_BASE_ADDR)
{
bus_gate_clk_enalbe(UART2_GATING);
bus_software_reset_enalbe(UART2_GATING);
}
else
RT_ASSERT(0);
/* Config uart0 to 115200-8-1-0 */
addr = uart->hw_base;
/* close uart irq */
writel(0x0, addr + UART_IER);
/* config fifo */
writel(0x37, addr + UART_FCR);
/* config modem */
writel(0x0, addr + UART_MCR);
/* config baud */
val = readl(addr + UART_LCR);
val |= (1 << 7);
writel(val, addr + UART_LCR);
val = apb_get_clk() / 16 / serial->config.baud_rate;
writel(val & 0xff, addr + UART_DLL);
writel((val >> 8) & 0xff, addr + UART_DLH);
val = readl(addr + UART_LCR);
val &= ~(1 << 7);
writel(val, addr + UART_LCR);
val = readl(addr + UART_LCR);
val &= ~0x1f;
val |= ((serial->config.data_bits - DATA_BITS_5) << 0) | (0 << 2) | (0x0 << 3);
writel(val, addr + UART_LCR);
writel(0xf, addr + UART_TFL);
writel(0x3F, addr + UART_RFL);
writel(0x1, addr + UART_IER);
return RT_EOK;
}
static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *arg)
{
struct device_uart *uart;
uart = serial->parent.user_data;
RT_ASSERT(uart != RT_NULL);
switch (cmd)
{
case RT_DEVICE_CTRL_CLR_INT:
/* Disable the UART Interrupt */
rt_hw_interrupt_mask(uart->irqno);
writel(0x00, uart->hw_base + UART_IER);
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);
writel(0x01, uart->hw_base + UART_IER);
/* Enable the UART Interrupt */
break;
}
return (RT_EOK);
}
static int uart_putc(struct rt_serial_device *serial, char c)
{
struct device_uart *uart;
volatile rt_uint32_t *sed_buf;
volatile rt_uint32_t *sta;
uart = serial->parent.user_data;
sed_buf = (rt_uint32_t *)(uart->hw_base + UART_THR);
sta = (rt_uint32_t *)(uart->hw_base + UART_USR);
/* FIFO status, contain valid data */
while (!(*sta & 0x02));
*sed_buf = c;
return (1);
}
static int uart_getc(struct rt_serial_device *serial)
{
int ch = -1;
volatile rt_uint32_t *rec_buf;
volatile rt_uint32_t *sta;
struct device_uart *uart = serial->parent.user_data;
RT_ASSERT(serial != RT_NULL);
rec_buf = (rt_uint32_t *)(uart->hw_base + UART_RHB);
sta = (rt_uint32_t *)(uart->hw_base + UART_USR);
/* Receive Data Available */
if (*sta & 0x08)
{
ch = *rec_buf & 0xff;
}
return ch;
}
static rt_size_t uart_dma_transmit(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction)
{
return (0);
}
/* UART ISR */
void uart_irq_handler(int irqno, void *param)
{
rt_uint32_t val;
struct rt_serial_device *serial = (struct rt_serial_device *)param;
struct device_uart *uart = serial->parent.user_data;
val = readl(uart->hw_base + 0x08) & 0x0F;
/* read interrupt status and clear it */
if (val & 0x4) /* rx ind */
{
rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
}
if (0) /* tx done */
{
rt_hw_serial_isr(serial, RT_SERIAL_EVENT_TX_DONE);
}
}
#endif
\ No newline at end of file
/*
* File : drv_uart.h
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2017, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2018-02-08 RT-Thread the first version
*/
#ifndef __DRV_UART_H__
#define __DRV_UART_H__
#define UART0_BASE_ADDR (0x01C25000)
#define UART1_BASE_ADDR (0x01C25400)
#define UART2_BASE_ADDR (0x01C25800)
#define UART_THR (0X00)
#define UART_RHB (0X00)
#define UART_DLL (0X00)
#define UART_DLH (0X04)
#define UART_IER (0X04)
#define UART_IIR (0X08)
#define UART_FCR (0X08)
#define UART_LCR (0X0C)
#define UART_MCR (0X10)
#define UART_LSR (0X14)
#define UART_MSR (0X18)
#define UART_SCH (0X1C)
#define UART_USR (0X7C)
#define UART_TFL (0X80)
#define UART_RFL (0X84)
#define UART_HSK (0X88)
#define UART_HALT (0XA4)
#define UART_DBG_DLL (0XB0)
#define UART_DBG_DLH (0XB4)
struct tina_uart
{
volatile rt_uint32_t rx_tx_dll; /* 0x00 */
volatile rt_uint32_t dlh_ier; /* 0x04 */
volatile rt_uint32_t iir_fcr; /* 0x08 */
volatile rt_uint32_t lcr; /* 0x0C */
volatile rt_uint32_t mcr; /* 0x10 */
volatile rt_uint32_t lsr; /* 0x14 */
volatile rt_uint32_t msr; /* 0x18 */
volatile rt_uint32_t sch; /* 0x1C */
volatile rt_uint32_t reserved0[23];
volatile rt_uint32_t usr; /* 0x7c */
volatile rt_uint32_t tfl; /* 0x80 */
volatile rt_uint32_t rfl; /* 0x84 */
volatile rt_uint32_t hsk; /* 0x88 */
volatile rt_uint32_t reserved1[6];
volatile rt_uint32_t halt; /* 0xa4 */
volatile rt_uint32_t reserved2[2];
volatile rt_uint32_t dbg_dll; /* 0xb0 */
volatile rt_uint32_t dbg_dlh; /* 0xb4 */
};
typedef struct tina_uart *tina_uart_t;
#define UART0 ((tina_gpio_t)UART0_BASE_ADDR)
#define UART1 ((tina_gpio_t)UART1_BASE_ADDR)
#define UART2 ((tina_gpio_t)UART2_BASE_ADDR)
int rt_hw_uart_init(void);
#endif /* __DRV_UART_H__ */
Import('rtconfig')
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
CPPPATH = [cwd]
if rtconfig.PLATFORM == 'gcc':
src += Glob('*_gcc.S')
group = DefineGroup('CPU', src, depend = [''], CPPPATH = CPPPATH)
Return('group')
;/*
; * File : context_iar.S
; * This file is part of RT-Thread RTOS
; * COPYRIGHT (C) 2006, 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
; * 2011-08-14 weety copy from mini2440
; */
#define NOINT 0xC0
;/*
; * rt_base_t rt_hw_interrupt_disable();
; */
.globl rt_hw_interrupt_disable
rt_hw_interrupt_disable:
MRS R0, CPSR
ORR R1, R0, #NOINT
MSR CPSR_c, R1
BX LR
/*
* void rt_hw_interrupt_enable(rt_base_t level);
*/
.globl rt_hw_interrupt_enable
rt_hw_interrupt_enable:
MSR CPSR, R0
BX LR
/*
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
* r0 --> from
* r1 --> to
*/
.globl rt_hw_context_switch
rt_hw_context_switch:
STMFD SP!, {LR} @; push pc (lr should be pushed in place of pc)
STMFD SP!, {R0-R12, LR} @; push lr & register file
MRS R4, CPSR
STMFD SP!, {R4} @; push cpsr
STR SP, [R0] @; store sp in preempted tasks tcb
LDR SP, [R1] @; get new task stack pointer
LDMFD SP!, {R4} @; pop new task spsr
MSR SPSR_cxsf, R4
LDMFD SP!, {R0-R12, LR, PC}^ @; pop new task r0-r12, lr & pc
/*
* void rt_hw_context_switch_to(rt_uint32 to);
* r0 --> to
*/
.globl rt_hw_context_switch_to
rt_hw_context_switch_to:
LDR SP, [R0] @; get new task stack pointer
LDMFD SP!, {R4} @; pop new task cpsr
MSR SPSR_cxsf, R4
LDMFD SP!, {R0-R12, LR, PC}^ @; pop new task r0-r12, lr & pc
/*
* 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:
LDR R2, =rt_thread_switch_interrupt_flag
LDR R3, [R2]
CMP R3, #1
BEQ _reswitch
MOV R3, #1 @; set flag to 1
STR R3, [R2]
LDR R2, =rt_interrupt_from_thread @; set rt_interrupt_from_thread
STR R0, [R2]
_reswitch:
LDR R2, =rt_interrupt_to_thread @; set rt_interrupt_to_thread
STR R1, [R2]
BX LR
/*
* File : cpu.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2017, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2018-02-08 RT-Thread the first version
*/
#include <rthw.h>
#include <rtthread.h>
RT_WEAK void machine_reset(void)
{
rt_kprintf("reboot system...\n");
rt_hw_interrupt_disable();
while (1);
}
RT_WEAK void machine_shutdown(void)
{
rt_kprintf("shutdown...\n");
rt_hw_interrupt_disable();
while (1);
}
/*
* File : cpuport.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2017, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2018-02-08 RT-Thread the first version
*/
#include <rthw.h>
#include <rtthread.h>
#define ICACHE_MASK (rt_uint32_t)(1 << 12)
#define DCACHE_MASK (rt_uint32_t)(1 << 2)
extern void machine_reset(void);
extern void machine_shutdown(void);
#if defined(__GNUC__) || defined(__ICCARM__)
rt_inline rt_uint32_t cp15_rd(void)
{
rt_uint32_t i;
__asm volatile("mrc p15, 0, %0, c1, c0, 0":"=r"(i));
return i;
}
rt_inline void cache_enable(rt_uint32_t bit)
{
__asm volatile(\
"mrc p15,0,r0,c1,c0,0\n\t" \
"orr r0,r0,%0\n\t" \
"mcr p15,0,r0,c1,c0,0" \
: \
: "r"(bit) \
: "memory");
}
rt_inline void cache_disable(rt_uint32_t bit)
{
__asm volatile(\
"mrc p15,0,r0,c1,c0,0\n\t" \
"bic r0,r0,%0\n\t" \
"mcr p15,0,r0,c1,c0,0" \
: \
: "r"(bit) \
: "memory");
}
#endif
#if defined(__CC_ARM)
rt_inline rt_uint32_t cp15_rd(void)
{
rt_uint32_t i;
__asm volatile
{
mrc p15, 0, i, c1, c0, 0
}
return i;
}
rt_inline void cache_enable(rt_uint32_t bit)
{
rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
orr value, value, bit
mcr p15, 0, value, c1, c0, 0
}
}
rt_inline void cache_disable(rt_uint32_t bit)
{
rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
bic value, value, bit
mcr p15, 0, value, c1, c0, 0
}
}
#endif
/**
* enable I-Cache
*
*/
void rt_hw_cpu_icache_enable()
{
cache_enable(ICACHE_MASK);
}
/**
* disable I-Cache
*
*/
void rt_hw_cpu_icache_disable()
{
cache_disable(ICACHE_MASK);
}
/**
* return the status of I-Cache
*
*/
rt_base_t rt_hw_cpu_icache_status()
{
return (cp15_rd() & ICACHE_MASK);
}
/**
* enable D-Cache
*
*/
void rt_hw_cpu_dcache_enable()
{
cache_enable(DCACHE_MASK);
}
/**
* disable D-Cache
*
*/
void rt_hw_cpu_dcache_disable()
{
cache_disable(DCACHE_MASK);
}
/**
* return the status of D-Cache
*
*/
rt_base_t rt_hw_cpu_dcache_status()
{
return (cp15_rd() & DCACHE_MASK);
}
/**
* reset cpu by dog's time-out
*
*/
void rt_hw_cpu_reset()
{
rt_kprintf("Restarting system...\n");
machine_reset();
while (1); /* loop forever and wait for reset to happen */
/* NEVER REACHED */
}
/**
* shutdown CPU
*
*/
void rt_hw_cpu_shutdown()
{
rt_uint32_t level;
rt_kprintf("shutdown...\n");
level = rt_hw_interrupt_disable();
machine_shutdown();
while (level)
{
RT_ASSERT(0);
}
}
#ifdef RT_USING_CPU_FFS
/**
* 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.
*/
#if defined(__CC_ARM)
int __rt_ffs(int value)
{
register rt_uint32_t x;
if (value == 0)
return value;
__asm
{
rsb x, value, #0
and x, x, value
clz x, x
rsb x, x, #32
}
return x;
}
#elif defined(__GNUC__) || defined(__ICCARM__)
int __rt_ffs(int value)
{
return __builtin_ffs(value);
}
#endif
#endif
/*@}*/
/*
* File : interrupt.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2017, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2018-02-08 RT-Thread the first version
*/
#include <rthw.h>
#include <rtthread.h>
#include "interrupt.h"
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];
static void rt_hw_interrupt_handler(int vector, void *param)
{
rt_kprintf("Unhandled interrupt %d occured!!!\n", vector);
}
#define readl(addr) (*(volatile unsigned int *)(addr))
#define writel(value,addr) (*(volatile unsigned int *)(addr) = (value))
/**
* 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;
/* set base_addr reg */
INTC->base_addr_reg = 0x00000000;
/* clear enable */
INTC->en_reg0 = 0x00000000;
INTC->en_reg1 = 0x00000000;
/* mask interrupt */
INTC->mask_reg0 = 0xFFFFFFFF;
INTC->mask_reg1 = 0xFFFFFFFF;
/* clear pending */
INTC->pend_reg0 = 0x00000000;
INTC->pend_reg1 = 0x00000000;
/* set priority */
INTC->resp_reg0 = 0x00000000;
INTC->resp_reg1 = 0x00000000;
/* close fiq interrupt */
INTC->ff_reg0 = 0x00000000;
INTC->ff_reg1 = 0x00000000;
}
/**
* This function will mask a interrupt.
* @param vector the interrupt number
*/
void rt_hw_interrupt_mask(int vector)
{
rt_uint32_t mask_addr, data;
if ((vector < 0) || (vector > INTERRUPTS_MAX))
{
return;
}
mask_addr = (rt_uint32_t)(&INTC->mask_reg0);
mask_addr += vector & 0xE0 ? sizeof(rt_uint32_t *) : 0;
vector &= 0x1F;
data = readl(mask_addr);
data |= 0x1 << vector;
writel(data, mask_addr);
}
/**
* This function will un-mask a interrupt.
* @param vector the interrupt number
*/
void rt_hw_interrupt_umask(int vector)
{
rt_uint32_t mask_addr, data;
if ((vector < 0) || (vector > INTERRUPTS_MAX))
{
return;
}
mask_addr = (rt_uint32_t)(&INTC->mask_reg0);
mask_addr += vector & 0xE0 ? sizeof(rt_uint32_t *) : 0;
vector &= 0x1F;
data = readl(mask_addr);
data &= ~(0x1 << vector);
writel(data, mask_addr);
}
/**
* 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;
rt_uint32_t pend_addr, en_addr, data;
if ((vector < 0) || (vector > INTERRUPTS_MAX))
{
return old_handler;
}
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;
pend_addr = (rt_uint32_t)(&INTC->pend_reg0);
en_addr = (rt_uint32_t)(&INTC->en_reg0);
pend_addr += vector & 0xE0 ? sizeof(rt_uint32_t *) : 0;
en_addr += vector & 0xE0 ? sizeof(rt_uint32_t *) : 0;
vector &= 0x1F;
data = readl(pend_addr);
data &= ~(0x1 << vector);
writel(data, pend_addr);
data = readl(en_addr);
data |= 0x1 << vector;
writel(data, en_addr);
return old_handler;
}
void rt_interrupt_dispatch(void)
{
void *param;
int vector;
rt_isr_handler_t isr_func;
rt_uint32_t pend_addr, data;
vector = INTC->vector_reg - INTC->base_addr_reg;
vector = vector >> 2;
isr_func = isr_table[vector].handler;
param = isr_table[vector].param;
/* jump to fun */
isr_func(vector, param);
/* clear pend bit */
pend_addr = (rt_uint32_t)(&INTC->pend_reg0);
pend_addr += vector & 0xE0 ? sizeof(rt_uint32_t *) : 0;
vector &= 0x1F;
data = readl(pend_addr);
data &= ~(0x1 << vector);
writel(data, pend_addr);
#ifdef RT_USING_INTERRUPT_INFO
isr_table[vector].counter ++;
#endif
}
/*
* File : interrupt.h
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2017, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2018-02-08 RT-Thread the first version
*/
#ifndef __INTERRUPT_H__
#define __INTERRUPT_H__
/* Max number of interruptions */
#define INTERRUPTS_MAX (64)
/* a group num */
#define GROUP_NUM (32)
/* Interrupt Source */
#define NMI_INTERRUPT (0)
#define UART0_INTERRUPT (1)
#define UART1_INTERRUPT (2)
#define UART2_INTERRUPT (3)
#define OWA_INTERRUPT (5)
#define CIR_INTERRUPT (6)
#define TWI0_INTERRUPT (7)
#define TWI1_INTERRUPT (8)
#define TWI2_INTERRUPT (9)
#define SPI0_INTERRUPT (10)
#define SPI1_INTERRUPT (11)
#define TIMER0_INTERRUPT (13)
#define TIMER1_INTERRUPT (14)
#define TIMER2_INTERRUPT (15)
#define WATCHDOG_INTERRUPT (16)
#define RSB_INTERRUPT (17)
#define DMA_INTERRUPT (18)
#define TOUCHPANEL_INTERRUPT (20)
#define AUDIOCODEC_INTERRUPT (21)
#define KEYADC_INTERRUPT (22)
#define SDC0_INTERRUPT (23)
#define SDC1_INTERRUPT (24)
#define USB_OTG_INTERRUPT (26)
#define TVD_INTERRUPT (27)
#define TVE_INTERRUPT (28)
#define TCON_INTERRUPT (29)
#define DE_FE_INTERRUPT (30)
#define DE_BE_INTERRUPT (31)
#define CSI_INTERRUPT (32)
#define DE_INTERLACER_INTERRUPT (33)
#define VE_INTERRUPT (34)
#define DAUDIO_INTERRUPT (35)
#define PIOD_INTERRUPT (38)
#define PIOE_INTERRUPT (39)
#define PIOF_INTERRUPT (40)
/* intc register address */
#define INTC_BASE_ADDR (0x01C20400)
struct tina_intc
{
volatile rt_uint32_t vector_reg; /* 0x00 */
volatile rt_uint32_t base_addr_reg; /* 0x04 */
volatile rt_uint32_t reserved0;
volatile rt_uint32_t nmi_ctrl_reg; /* 0x0C */
volatile rt_uint32_t pend_reg0; /* 0x10 */
volatile rt_uint32_t pend_reg1; /* 0x14 */
volatile rt_uint32_t reserved1[2];
volatile rt_uint32_t en_reg0; /* 0x20 */
volatile rt_uint32_t en_reg1; /* 0x24 */
volatile rt_uint32_t reserved2[2];
volatile rt_uint32_t mask_reg0; /* 0x30 */
volatile rt_uint32_t mask_reg1; /* 0x34 */
volatile rt_uint32_t reserved3[2];
volatile rt_uint32_t resp_reg0; /* 0x40 */
volatile rt_uint32_t resp_reg1; /* 0x44 */
volatile rt_uint32_t reserved4[2];
volatile rt_uint32_t ff_reg0; /* 0x50 */
volatile rt_uint32_t ff_reg1; /* 0x54 */
volatile rt_uint32_t reserved5[2];
volatile rt_uint32_t prio_reg0; /* 0x60 */
volatile rt_uint32_t prio_reg1; /* 0x64 */
volatile rt_uint32_t prio_reg2; /* 0x68 */
volatile rt_uint32_t prio_reg3; /* 0x6C */
} ;
typedef struct tina_intc *tina_intc_t;
#define INTC ((tina_intc_t)INTC_BASE_ADDR)
void rt_hw_interrupt_init(void);
void rt_hw_interrupt_mask(int vector);
void rt_hw_interrupt_umask(int vector);
rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, void *param, char *name);
#endif /* __INTERRUPT_H__ */
/*
* File : mmu.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2017, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2018-02-08 RT-Thread the first version
*/
#include "mmu.h"
/*----- Keil -----------------------------------------------------------------*/
#ifdef __CC_ARM
void mmu_setttbase(rt_uint32_t i)
{
register rt_uint32_t value;
/* Invalidates all TLBs.Domain access is selected as
* client by configuring domain access register,
* in that case access controlled by permission value
* set by page table entry
*/
value = 0;
__asm volatile{ mcr p15, 0, value, c8, c7, 0 }
value = 0x55555555;
__asm volatile { mcr p15, 0, value, c3, c0, 0 }
__asm volatile { mcr p15, 0, i, c2, c0, 0 }
}
void mmu_set_domain(rt_uint32_t i)
{
__asm volatile { mcr p15, 0, i, c3, c0, 0 }
}
void mmu_enable()
{
register rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
orr value, value, #0x01
mcr p15, 0, value, c1, c0, 0
}
}
void mmu_disable()
{
register rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
bic value, value, #0x01
mcr p15, 0, value, c1, c0, 0
}
}
void mmu_enable_icache()
{
register rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
orr value, value, #0x1000
mcr p15, 0, value, c1, c0, 0
}
}
void mmu_enable_dcache()
{
register rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
orr value, value, #0x04
mcr p15, 0, value, c1, c0, 0
}
}
void mmu_disable_icache()
{
register rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
bic value, value, #0x1000
mcr p15, 0, value, c1, c0, 0
}
}
void mmu_disable_dcache()
{
register rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
bic value, value, #0x04
mcr p15, 0, value, c1, c0, 0
}
}
void mmu_enable_alignfault()
{
register rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
orr value, value, #0x02
mcr p15, 0, value, c1, c0, 0
}
}
void mmu_disable_alignfault()
{
register rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
bic value, value, #0x02
mcr p15, 0, value, c1, c0, 0
}
}
void mmu_clean_invalidated_cache_index(int index)
{
__asm volatile { mcr p15, 0, index, c7, c14, 2 }
}
void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size)
{
unsigned int ptr;
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
while (ptr < buffer + size)
{
__asm volatile { MCR p15, 0, ptr, c7, c14, 1 }
ptr += CACHE_LINE_SIZE;
}
}
void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size)
{
unsigned int ptr;
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
while (ptr < buffer + size)
{
__asm volatile { MCR p15, 0, ptr, c7, c10, 1 }
ptr += CACHE_LINE_SIZE;
}
}
void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size)
{
unsigned int ptr;
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
while (ptr < buffer + size)
{
__asm volatile { MCR p15, 0, ptr, c7, c6, 1 }
ptr += CACHE_LINE_SIZE;
}
}
void mmu_invalidate_tlb()
{
register rt_uint32_t value;
value = 0;
__asm volatile { mcr p15, 0, value, c8, c7, 0 }
}
void mmu_invalidate_icache()
{
register rt_uint32_t value;
value = 0;
__asm volatile { mcr p15, 0, value, c7, c5, 0 }
}
void mmu_invalidate_dcache_all()
{
register rt_uint32_t value;
value = 0;
__asm volatile { mcr p15, 0, value, c7, c6, 0 }
}
/*----- GNU ------------------------------------------------------------------*/
#elif defined(__GNUC__) || defined(__ICCARM__)
void mmu_setttbase(register rt_uint32_t i)
{
register rt_uint32_t value;
/* Invalidates all TLBs.Domain access is selected as
* client by configuring domain access register,
* in that case access controlled by permission value
* set by page table entry
*/
value = 0;
asm volatile("mcr p15, 0, %0, c8, c7, 0"::"r"(value));
value = 0x55555555;
asm volatile("mcr p15, 0, %0, c3, c0, 0"::"r"(value));
asm volatile("mcr p15, 0, %0, c2, c0, 0"::"r"(i));
}
void mmu_set_domain(register rt_uint32_t i)
{
asm volatile("mcr p15,0, %0, c3, c0, 0": :"r"(i));
}
void mmu_enable()
{
asm volatile
(
"mrc p15, 0, r0, c1, c0, 0 \n"
"orr r0, r0, #0x1 \n"
"mcr p15, 0, r0, c1, c0, 0 \n"
:::"r0"
);
}
void mmu_disable()
{
asm volatile
(
"mrc p15, 0, r0, c1, c0, 0 \n"
"bic r0, r0, #0x1 \n"
"mcr p15, 0, r0, c1, c0, 0 \n"
:::"r0"
);
}
void mmu_enable_icache()
{
asm volatile
(
"mrc p15, 0, r0, c1, c0, 0 \n"
"orr r0, r0, #(1<<12) \n"
"mcr p15, 0, r0, c1, c0, 0 \n"
:::"r0"
);
}
void mmu_enable_dcache()
{
asm volatile
(
"mrc p15, 0, r0, c1, c0, 0 \n"
"orr r0, r0, #(1<<2) \n"
"mcr p15, 0, r0, c1, c0, 0 \n"
:::"r0"
);
}
void mmu_disable_icache()
{
asm volatile
(
"mrc p15, 0, r0, c1, c0, 0 \n"
"bic r0, r0, #(1<<12) \n"
"mcr p15, 0, r0, c1, c0, 0 \n"
:::"r0"
);
}
void mmu_disable_dcache()
{
asm volatile
(
"mrc p15, 0, r0, c1, c0, 0 \n"
"bic r0, r0, #(1<<2) \n"
"mcr p15, 0, r0, c1, c0, 0 \n"
:::"r0"
);
}
void mmu_enable_alignfault()
{
asm volatile
(
"mrc p15, 0, r0, c1, c0, 0 \n"
"orr r0, r0, #1 \n"
"mcr p15, 0, r0, c1, c0, 0 \n"
:::"r0"
);
}
void mmu_disable_alignfault()
{
asm volatile
(
"mrc p15, 0, r0, c1, c0, 0 \n"
"bic r0, r0, #1 \n"
"mcr p15, 0, r0, c1, c0, 0 \n"
:::"r0"
);
}
void mmu_clean_invalidated_cache_index(int index)
{
asm volatile("mcr p15, 0, %0, c7, c14, 2": :"r"(index));
}
void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size)
{
unsigned int ptr;
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
while (ptr < buffer + size)
{
asm volatile("mcr p15, 0, %0, c7, c14, 1": :"r"(ptr));
ptr += CACHE_LINE_SIZE;
}
}
void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size)
{
unsigned int ptr;
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
while (ptr < buffer + size)
{
asm volatile("mcr p15, 0, %0, c7, c10, 1": :"r"(ptr));
ptr += CACHE_LINE_SIZE;
}
}
void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size)
{
unsigned int ptr;
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
while (ptr < buffer + size)
{
asm volatile("mcr p15, 0, %0, c7, c6, 1": :"r"(ptr));
ptr += CACHE_LINE_SIZE;
}
}
void mmu_invalidate_tlb()
{
asm volatile("mcr p15, 0, %0, c8, c7, 0": :"r"(0));
}
void mmu_invalidate_icache()
{
asm volatile("mcr p15, 0, %0, c7, c5, 0": :"r"(0));
}
void mmu_invalidate_dcache_all()
{
asm volatile("mcr p15, 0, %0, c7, c6, 0": :"r"(0));
}
#endif
/* level1 page table */
#if defined(__ICCARM__)
#pragma data_alignment=(16*1024)
static volatile rt_uint32_t _page_table[4 * 1024];
#else
static volatile rt_uint32_t _page_table[4 * 1024] \
__attribute__((aligned(16 * 1024)));
#endif
void mmu_setmtt(rt_uint32_t vaddrStart, rt_uint32_t vaddrEnd,
rt_uint32_t paddrStart, rt_uint32_t attr)
{
volatile rt_uint32_t *pTT;
volatile int nSec;
int i = 0;
pTT = (rt_uint32_t *)_page_table + (vaddrStart >> 20);
nSec = (vaddrEnd >> 20) - (vaddrStart >> 20);
for (i = 0; i <= nSec; i++)
{
*pTT = attr | (((paddrStart >> 20) + i) << 20);
pTT++;
}
}
void rt_hw_mmu_init(struct mem_desc *mdesc, rt_uint32_t size)
{
/* disable I/D cache */
mmu_disable_dcache();
mmu_disable_icache();
mmu_disable();
mmu_invalidate_tlb();
/* set page table */
for (; size > 0; size--)
{
mmu_setmtt(mdesc->vaddr_start, mdesc->vaddr_end,
mdesc->paddr_start, mdesc->attr);
mdesc++;
}
/* set MMU table address */
mmu_setttbase((rt_uint32_t)_page_table);
/* enables MMU */
mmu_enable();
/* enable Instruction Cache */
mmu_enable_icache();
/* enable Data Cache */
mmu_enable_dcache();
mmu_invalidate_icache();
mmu_invalidate_dcache_all();
}
/*
* File : mmu.h
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2017, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2018-02-08 RT-Thread the first version
*/
#ifndef __MMU_H__
#define __MMU_H__
#include <rtthread.h>
#define CACHE_LINE_SIZE 32
#define DESC_SEC (0x2|(1<<4))
#define CB (3<<2) //cache_on, write_back
#define CNB (2<<2) //cache_on, write_through
#define NCB (1<<2) //cache_off,WR_BUF on
#define NCNB (0<<2) //cache_off,WR_BUF off
#define AP_RW (3<<10) //supervisor=RW, user=RW
#define AP_RO (2<<10) //supervisor=RW, user=RO
#define DOMAIN_FAULT (0x0)
#define DOMAIN_CHK (0x1)
#define DOMAIN_NOTCHK (0x3)
#define DOMAIN0 (0x0<<5)
#define DOMAIN1 (0x1<<5)
#define DOMAIN0_ATTR (DOMAIN_CHK<<0)
#define DOMAIN1_ATTR (DOMAIN_FAULT<<2)
#define RW_CB (AP_RW|DOMAIN0|CB|DESC_SEC) /* Read/Write, cache, write back */
#define RW_CNB (AP_RW|DOMAIN0|CNB|DESC_SEC) /* Read/Write, cache, write through */
#define RW_NCNB (AP_RW|DOMAIN0|NCNB|DESC_SEC) /* Read/Write without cache and write buffer */
#define RW_FAULT (AP_RW|DOMAIN1|NCNB|DESC_SEC) /* Read/Write without cache and write buffer */
struct mem_desc
{
rt_uint32_t vaddr_start;
rt_uint32_t vaddr_end;
rt_uint32_t paddr_start;
rt_uint32_t attr;
};
void rt_hw_mmu_init(struct mem_desc *mdesc, rt_uint32_t size);
void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size);
void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size);
void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size);
#endif
/*
* File : rt_low_level_init.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2017, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2018-02-08 RT-Thread the first version
*/
void rt_low_level_init(void)
{
volatile unsigned int *addr;
volatile unsigned int time;
int i;
//change cpu clk source to 24M
addr = (unsigned int *)(0x01c20000 + 0x050);
*addr = 0x10000;
//init cpu pll clk 408M
addr = (unsigned int *)(0x01c20000 + 0x000);
*addr = 0x80001000;
time = 0xffff;
while ((!(*addr & (0x1 << 28))) && (time--));
//change cpu clk source to pll
if (time > 0)
{
addr = (unsigned int *)(0x01c20000 + 0x050);
*addr = 0x20000;
}
//init periph pll clk:600M
//init ahb pll clk:200M
//init apb pll clk:100M
addr = (unsigned int *)(0x01c20000 + 0x028);
if (*addr & (0x1 << 31))
return;
addr = (unsigned int *)(0x01c20000 + 0x200);
*addr = 0x1ff;
addr = (unsigned int *)(0x01c20000 + 0x204);
*addr = 0x1ff;
addr = (unsigned int *)(0x01c20000 + 0x028);
*addr |= (0x1 << 31);
while (!(*addr & (0x1 << 28)));
addr = (unsigned int *)(0x01c20000 + 0x054);
*addr = (0x0 << 16) | (0x3 << 12) | (0x0 << 8) | (0x2 << 6) | (0x0 << 4);
//init gpio config
for (i = 0; i < 6; i++)
{
if (i == 1)
continue;// not config gpio B
addr = (unsigned int *)(0x01c20800 + i * 0x24 + 0x00);
*addr = 0x77777777;
addr = (unsigned int *)(0x01c20800 + i * 0x24 + 0x04);
*addr = 0x77777777;
addr = (unsigned int *)(0x01c20800 + i * 0x24 + 0x08);
*addr = 0x77777777;
addr = (unsigned int *)(0x01c20800 + i * 0x24 + 0x0C);
*addr = 0x77777777;
}
}
/*
* File : stack.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2017, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2018-02-08 RT-Thread the first version
*/
#include <rtthread.h>
/*****************************/
/* CPU Mode */
/*****************************/
#define USERMODE 0x10
#define FIQMODE 0x11
#define IRQMODE 0x12
#define SVCMODE 0x13
#define ABORTMODE 0x17
#define UNDEFMODE 0x1b
#define MODEMASK 0x1f
#define NOINT 0xc0
/**
* 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;
//stk = (rt_uint32_t*)stack_addr;
stack_addr += sizeof(rt_uint32_t);
stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8);
stk = (rt_uint32_t *)stack_addr;
*(--stk) = (rt_uint32_t)tentry; /* entry point */
*(--stk) = (rt_uint32_t)texit; /* lr */
*(--stk) = 0xdeadbeef; /* r12 */
*(--stk) = 0xdeadbeef; /* r11 */
*(--stk) = 0xdeadbeef; /* r10 */
*(--stk) = 0xdeadbeef; /* r9 */
*(--stk) = 0xdeadbeef; /* r8 */
*(--stk) = 0xdeadbeef; /* r7 */
*(--stk) = 0xdeadbeef; /* r6 */
*(--stk) = 0xdeadbeef; /* r5 */
*(--stk) = 0xdeadbeef; /* r4 */
*(--stk) = 0xdeadbeef; /* r3 */
*(--stk) = 0xdeadbeef; /* r2 */
*(--stk) = 0xdeadbeef; /* r1 */
*(--stk) = (rt_uint32_t)parameter; /* r0 : argument */
/* cpsr */
if ((rt_uint32_t)tentry & 0x01)
*(--stk) = SVCMODE | 0x20; /* thumb mode */
else
*(--stk) = SVCMODE; /* arm mode */
/* return task's current stack address */
return (rt_uint8_t *)stk;
}
/*
* File : start_gcc.S
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2013-2018, RT-Thread Development Team
*/
.equ MODE_USR, 0x10
.equ MODE_FIQ, 0x11
.equ MODE_IRQ, 0x12
.equ MODE_SVC, 0x13
.equ MODE_ABT, 0x17
.equ MODE_UND, 0x1B
.equ MODE_SYS, 0x1F
.equ MODEMASK, 0x1F
.equ NOINT, 0xC0
.equ I_BIT, 0x80
.equ F_BIT, 0x40
.equ UND_STACK_SIZE, 0x00000100
.equ SVC_STACK_SIZE, 0x00000100
.equ ABT_STACK_SIZE, 0x00000100
.equ FIQ_STACK_SIZE, 0x00000100
.equ IRQ_STACK_SIZE, 0x00000100
.equ SYS_STACK_SIZE, 0x00000100
/*
***************************************
* Interrupt vector table
***************************************
*/
.section .vectors
.code 32
.global system_vectors
system_vectors:
ldr pc, _vector_reset
ldr pc, _vector_undef
ldr pc, _vector_swi
ldr pc, _vector_pabt
ldr pc, _vector_dabt
ldr pc, _vector_resv
ldr pc, _vector_irq
ldr pc, _vector_fiq
_vector_reset:
.word reset
_vector_undef:
.word vector_undef
_vector_swi:
.word vector_swi
_vector_pabt:
.word vector_pabt
_vector_dabt:
.word vector_dabt
_vector_resv:
.word vector_resv
_vector_irq:
.word vector_irq
_vector_fiq:
.word vector_fiq
.balignl 16,0xdeadbeef
/*
***************************************
* Stack and Heap Definitions
***************************************
*/
.section .data
.space UND_STACK_SIZE
.align 3
.global und_stack_start
und_stack_start:
.space ABT_STACK_SIZE
.align 3
.global abt_stack_start
abt_stack_start:
.space FIQ_STACK_SIZE
.align 3
.global fiq_stack_start
fiq_stack_start:
.space IRQ_STACK_SIZE
.align 3
.global irq_stack_start
irq_stack_start:
.skip SYS_STACK_SIZE
.align 3
.global sys_stack_start
sys_stack_start:
.space SVC_STACK_SIZE
.align 3
.global svc_stack_start
svc_stack_start:
/*
***************************************
* Startup Code
***************************************
*/
.section .text
.global reset
reset:
/* Enter svc mode and mask interrupts */
mrs r0, cpsr
bic r0, r0, #MODEMASK
orr r0, r0, #MODE_SVC|NOINT
msr cpsr_cxsf, r0
/* init cpu */
bl cpu_init_crit
/* todo:copyself to link address */
/* Copy vector to the correct address */
ldr r0, =system_vectors
mrc p15, 0, r2, c1, c0, 0
ands r2, r2, #(1 << 13)
ldreq r1, =0x00000000
ldrne r1, =0xffff0000
ldmia r0!, {r2-r8, r10}
stmia r1!, {r2-r8, r10}
ldmia r0!, {r2-r8, r10}
stmia r1!, {r2-r8, r10}
/* turn off the watchdog */
ldr r0, =0x01C20CB8
mov r1, #0x0
str r1, [r0]
/* mask all IRQs source */
ldr r1, =0xffffffff
ldr r0, =0x01C20430
str r1, [r0], #0x04
str r1, [r0]
/* Call low level init function */
ldr sp, =svc_stack_start
ldr r0, =rt_low_level_init
blx r0
/* init stack */
bl stack_setup
/* clear bss */
mov r0, #0
ldr r1, =__bss_start
ldr r2, =__bss_end
bss_clear_loop:
cmp r1, r2
strlo r0, [r1], #4
blo bss_clear_loop
/* call c++ constructors of global objects */
/*
ldr r0, =__ctors_start__
ldr r1, =__ctors_end__
ctor_loop:
cmp r0, r1
beq ctor_end
ldr r2, [r0], #4
stmfd sp!, {r0-r1}
mov lr, pc
bx r2
ldmfd sp!, {r0-r1}
b ctor_loop
ctor_end:
*/
/* start RT-Thread Kernel */
ldr pc, _rtthread_startup
_rtthread_startup:
.word rtthread_startup
cpu_init_crit:
/* invalidate I/D caches */
mov r0, #0
mcr p15, 0, r0, c7, c7, 0
mcr p15, 0, r0, c8, c7, 0
/* disable MMU stuff and caches */
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002300
bic r0, r0, #0x00000087
orr r0, r0, #0x00000002
orr r0, r0, #0x00001000
mcr p15, 0, r0, c1, c0, 0
bx lr
stack_setup:
/* Setup Stack for each mode */
mrs r0, cpsr
bic r0, r0, #MODEMASK
orr r1, r0, #MODE_UND|NOINT
msr cpsr_cxsf, r1
ldr sp, =und_stack_start
orr r1, r0, #MODE_ABT|NOINT
msr cpsr_cxsf, r1
ldr sp, =abt_stack_start
orr r1, r0, #MODE_IRQ|NOINT
msr cpsr_cxsf, r1
ldr sp, =irq_stack_start
orr r1, r0, #MODE_FIQ|NOINT
msr cpsr_cxsf, r1
ldr sp, =fiq_stack_start
orr r1, r0, #MODE_SYS|NOINT
msr cpsr_cxsf,r1
ldr sp, =sys_stack_start
orr r1, r0, #MODE_SVC|NOINT
msr cpsr_cxsf, r1
ldr sp, =svc_stack_start
bx lr
/*
***************************************
* exception handlers
***************************************
*/
.global rt_hw_trap_udef
.global rt_hw_trap_swi
.global rt_hw_trap_pabt
.global rt_hw_trap_dabt
.global rt_hw_trap_resv
.global rt_hw_trap_irq
.global rt_hw_trap_fiq
.global rt_interrupt_enter
.global rt_interrupt_leave
.global rt_thread_switch_interrupt_flag
.global rt_interrupt_from_thread
.global rt_interrupt_to_thread
/* Interrupt */
.align 5
vector_fiq:
stmfd sp!,{r0-r7,lr}
bl rt_hw_trap_fiq
ldmfd sp!,{r0-r7,lr}
subs pc, lr, #4
.align 5
vector_irq:
stmfd sp!, {r0-r12,lr}
bl rt_interrupt_enter
bl rt_hw_trap_irq
bl rt_interrupt_leave
ldr r0, =rt_thread_switch_interrupt_flag
ldr r1, [r0]
cmp r1, #1
beq rt_hw_context_switch_interrupt_do
ldmfd sp!, {r0-r12,lr}
subs pc, lr, #4
rt_hw_context_switch_interrupt_do:
mov r1, #0
str r1, [r0]
mov r1, sp
add sp, sp, #4*4
ldmfd sp!, {r4-r12,lr}
mrs r0, spsr
sub r2, lr, #4
msr cpsr_c, #I_BIT|F_BIT|MODE_SVC
stmfd sp!, {r2}
stmfd sp!, {r4-r12,lr}
ldmfd r1, {r1-r4}
stmfd sp!, {r1-r4}
stmfd sp!, {r0}
ldr r4, =rt_interrupt_from_thread
ldr r5, [r4]
str sp, [r5]
ldr r6, =rt_interrupt_to_thread
ldr r6, [r6]
ldr sp, [r6]
ldmfd sp!, {r4}
msr spsr_cxsf, r4
ldmfd sp!, {r0-r12,lr,pc}^
/* Exception */
.macro push_svc_reg
sub sp, sp, #17 * 4
stmia sp, {r0 - r12}
mov r0, sp
mrs r6, spsr
str lr, [r0, #15*4]
str r6, [r0, #16*4]
str sp, [r0, #13*4]
str lr, [r0, #14*4]
.endm
.align 5
vector_swi:
push_svc_reg
bl rt_hw_trap_swi
b .
.align 5
vector_undef:
push_svc_reg
bl rt_hw_trap_udef
b .
.align 5
vector_pabt:
push_svc_reg
bl rt_hw_trap_pabt
b .
.align 5
vector_dabt:
push_svc_reg
bl rt_hw_trap_dabt
b .
.align 5
vector_resv:
push_svc_reg
bl rt_hw_trap_resv
b .
/*
* File : trap.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2017, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2018-02-08 RT-Thread the first version
*/
#include <rtthread.h>
#include <rthw.h>
#define INT_IRQ 0x00
#define INT_FIQ 0x01
extern struct rt_thread *rt_current_thread;
#ifdef RT_USING_FINSH
extern long list_thread(void);
#endif
struct rt_hw_register
{
rt_uint32_t r0;
rt_uint32_t r1;
rt_uint32_t r2;
rt_uint32_t r3;
rt_uint32_t r4;
rt_uint32_t r5;
rt_uint32_t r6;
rt_uint32_t r7;
rt_uint32_t r8;
rt_uint32_t r9;
rt_uint32_t r10;
rt_uint32_t fp;
rt_uint32_t ip;
rt_uint32_t sp;
rt_uint32_t lr;
rt_uint32_t pc;
rt_uint32_t cpsr;
rt_uint32_t ORIG_r0;
};
static rt_err_t (*rt_exception_hook)(void *context) = RT_NULL;
void rt_hw_exception_install(rt_err_t (*exception_handle)(void *context))
{
rt_exception_hook = exception_handle;
}
/**
* this function will show registers of CPU
*
* @param regs the registers point
*/
void rt_hw_show_register(struct rt_hw_register *regs)
{
rt_kprintf("Execption:\n");
rt_kprintf("r00:0x%08x r01:0x%08x r02:0x%08x r03:0x%08x\n",
regs->r0, regs->r1, regs->r2, regs->r3);
rt_kprintf("r04:0x%08x r05:0x%08x r06:0x%08x r07:0x%08x\n",
regs->r4, regs->r5, regs->r6, regs->r7);
rt_kprintf("r08:0x%08x r09:0x%08x r10:0x%08x\n",
regs->r8, regs->r9, regs->r10);
rt_kprintf("fp :0x%08x ip :0x%08x\n",
regs->fp, regs->ip);
rt_kprintf("sp :0x%08x lr :0x%08x pc :0x%08x\n",
regs->sp, regs->lr, regs->pc);
rt_kprintf("cpsr:0x%08x\n", regs->cpsr);
}
/**
* When ARM7TDMI comes across an instruction which it cannot handle,
* it takes the undefined instruction trap.
*
* @param regs system registers
*
* @note never invoke this function in application
*/
void rt_hw_trap_udef(struct rt_hw_register *regs)
{
if (rt_exception_hook != RT_NULL)
{
rt_err_t result;
result = rt_exception_hook(regs);
if (result == RT_EOK) return;
}
rt_hw_show_register(regs);
rt_kprintf("undefined instruction\n");
rt_kprintf("thread - %s stack:\n", rt_current_thread->name);
#ifdef RT_USING_FINSH
list_thread();
#endif
rt_hw_cpu_shutdown();
}
/**
* The software interrupt instruction (SWI) is used for entering
* Supervisor mode, usually to request a particular supervisor
* function.
*
* @param regs system registers
*
* @note never invoke this function in application
*/
void rt_hw_trap_swi(struct rt_hw_register *regs)
{
if (rt_exception_hook != RT_NULL)
{
rt_err_t result;
result = rt_exception_hook(regs);
if (result == RT_EOK) return;
}
rt_hw_show_register(regs);
rt_kprintf("software interrupt\n");
rt_hw_cpu_shutdown();
}
/**
* An abort indicates that the current memory access cannot be completed,
* which occurs during an instruction prefetch.
*
* @param regs system registers
*
* @note never invoke this function in application
*/
void rt_hw_trap_pabt(struct rt_hw_register *regs)
{
if (rt_exception_hook != RT_NULL)
{
rt_err_t result;
result = rt_exception_hook(regs);
if (result == RT_EOK) return;
}
rt_hw_show_register(regs);
rt_kprintf("prefetch abort\n");
rt_kprintf("thread - %s stack:\n", RT_NAME_MAX, rt_current_thread->name);
#ifdef RT_USING_FINSH
list_thread();
#endif
rt_hw_cpu_shutdown();
}
/**
* An abort indicates that the current memory access cannot be completed,
* which occurs during a data access.
*
* @param regs system registers
*
* @note never invoke this function in application
*/
void rt_hw_trap_dabt(struct rt_hw_register *regs)
{
if (rt_exception_hook != RT_NULL)
{
rt_err_t result;
result = rt_exception_hook(regs);
if (result == RT_EOK) return;
}
rt_hw_show_register(regs);
rt_kprintf("data abort\n");
rt_kprintf("thread - %s stack:\n", RT_NAME_MAX, rt_current_thread->name);
#ifdef RT_USING_FINSH
list_thread();
#endif
rt_hw_cpu_shutdown();
}
/**
* Normally, system will never reach here
*
* @param regs system registers
*
* @note never invoke this function in application
*/
void rt_hw_trap_resv(struct rt_hw_register *regs)
{
if (rt_exception_hook != RT_NULL)
{
rt_err_t result;
result = rt_exception_hook(regs);
if (result == RT_EOK) return;
}
rt_kprintf("not used\n");
rt_hw_show_register(regs);
rt_hw_cpu_shutdown();
}
extern void rt_interrupt_dispatch(void);
void rt_hw_trap_irq(void)
{
rt_interrupt_dispatch();
}
void rt_hw_trap_fiq(void)
{
rt_interrupt_dispatch();
}
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SECTIONS
{
. = 0x80000000;
. = ALIGN(4);
__text_start = .;
.text :
{
*(.vectors)
*(.text)
*(.text.*)
KEEP(*(.fini))
/* 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 modules */
. = ALIGN(4);
__rtmsymtab_start = .;
KEEP(*(RTMSymTab))
__rtmsymtab_end = .;
/* section information for initialization */
. = ALIGN(4);
__rt_init_start = .;
KEEP(*(SORT(.rti_fn*)))
__rt_init_end = .;
} =0
__text_end = .;
__rodata_start = .;
.rodata : { *(.rodata) *(.rodata.*) *(.eh_frame) }
__rodata_end = .;
. = ALIGN(4);
.ctors :
{
PROVIDE(__ctors_start__ = .);
*crtbegin.o(.ctors)
*crtbegin?.o(.ctors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
*(SORT(.ctors.*))
*(.ctors)
PROVIDE(__ctors_end__ = .);
}
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
}
/* The .ARM.exidx section is used for C++ exception handling. */
/* .ARM.exidx is sorted, so has to go in its own output section. */
__exidx_start = .;
ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
/* This is used by the startup in order to initialize the .data secion */
_sidata = .;
}
__exidx_end = .;
.dtors :
{
PROVIDE(__dtors_start__ = .);
*crtbegin.o(.dtors)
*crtbegin?.o(.dtors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
*(SORT(.dtors.*))
*(.dtors)
PROVIDE(__dtors_end__ = .);
}
__data_start = .;
. = ALIGN(4);
.data :
{
*(.data)
*(.data.*)
. = ALIGN(4);
/* preinit data */
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP(*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
/* init data */
PROVIDE_HIDDEN (__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
/* finit data */
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP(*(SORT(.fini_array.*)))
KEEP(*(.fini_array))
PROVIDE_HIDDEN (__fini_array_end = .);
KEEP(*(.jcr*))
. = ALIGN(4);
/* All data end */
*(.gnu.linkonce.d*)
}
__data_end = .;
. = ALIGN(4);
__bss_start = .;
.bss :
{
*(.bss)
*(.bss.*)
*(COMMON)
. = ALIGN(4);
}
. = ALIGN(4);
__bss_end = .;
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_info 0 : { *(.debug_info) }
.debug_line 0 : { *(.debug_line) }
.debug_pubnames 0 : { *(.debug_pubnames) }
.debug_aranges 0 : { *(.debug_aranges) }
_end = .;
}
此差异已折叠。
import os
# toolchains options
ARCH ='arm'
CPU ='R6'
CROSS_TOOL ='gcc'
if os.getenv('RTT_ROOT'):
RTT_ROOT = os.getenv('RTT_ROOT')
else:
RTT_ROOT = '../..'
if os.getenv('RTT_CC'):
CROSS_TOOL = os.getenv('RTT_CC')
if CROSS_TOOL == 'gcc':
PLATFORM = 'gcc'
EXEC_PATH = r'E:\work\env\tools\gnu_gcc\arm_gcc\mingw\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 = 'release'
# BUILD = 'debug'
if PLATFORM == 'gcc':
# toolchains
PREFIX = 'arm-none-eabi-'
CC = PREFIX + 'gcc'
CXX = PREFIX + 'g++'
AS = PREFIX + 'gcc'
AR = PREFIX + 'ar'
LINK = PREFIX + 'g++'
TARGET_EXT = 'elf'
SIZE = PREFIX + 'size'
OBJDUMP = PREFIX + 'objdump'
OBJCPY = PREFIX + 'objcopy'
DEVICE = ' -mcpu=arm926ej-s -ffunction-sections -fdata-sections'
CFLAGS = DEVICE + ' -Wall'
AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp'
LFLAGS = DEVICE + ' -nostartfiles -Wl,--gc-sections,-Map=rtthread.map,-cref,-u,system_vectors -T link.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'
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册