A59项目初版工程 1.电压+光感adc采样优化 2.串口逻辑优化

This commit is contained in:
2024-08-27 10:54:23 +08:00
commit 16b6433a98
14081 changed files with 6865556 additions and 0 deletions

View File

@ -0,0 +1,25 @@
#ifndef _ANIMATION_H
#define _ANIMATION_H
typedef struct {
unsigned int magic;
int hasBootlogo;
int bootlogoDisplayTime;
int aniCount;
int aniWidth;
int aniHeight;
int aniFps;
int aniDelayHideTime;
unsigned int aniSize;
unsigned int checksum;
unsigned int reserved[2];
}BANIHEADER;
int animation_init(void);
void animation_start(void);
/* replay animation even if animation is already playing */
void animation_restart(void);
void animation_stop(void);
int get_animation_status(void);
#endif

View File

@ -0,0 +1,149 @@
#ifndef _ARK7116_DRV_H_
#define _ARK7116_DRV_H_
#if __cplusplus
extern "C"
{
#endif
typedef enum _ConfigDisplayMode
{
DISP_16_9= 0 ,
DISP_4_3,
}ConfigDisplayMode;
typedef enum _ColorSysType
{
PAL = 0,
PAL_N,
PAL_M,
NTSC,
SECAM,
PAL60,
AUTO,
NULL_SYS = -1,
}ColorSysType;
//MCU CFG Addr
#define MCU_CFG_ADDR 0xC6
/************************Global ***********************/
#define RSTN 0XFD00
#define ENH_PLL 0XFD0E
/***********************Decoder ************************/
#define DECODER_RST 0XFEA0
//BUS Addr
#define BUS_STATUS_ADDR 0xAF
typedef struct _PanlstaticPara
{
unsigned int addr;
unsigned char dat;
}PanlstaticPara;
typedef enum _VdeOutputType
{
VDE_CLOSE = 0,
VDE_RED,
VDE_GREEN,
VDE_BLUE ,
VDE_GRAY,
VDE_WHITE,
VDE_BLACK,
MAX_VDECOLOR = VDE_BLACK,
} VdeOutputTyp;
/*************************************VP CONTROL REG*********************************/
#define BRIGHT_REG 0XFFD4
#define CONTRAST_REG 0XFFD3
#define SATURATION_REG 0XFFD6
#define TINT_REG 0XFFD5
#define VDE_REG 0XFFD2
/*==============start===============*/
/*AV1
[VideoChannel]
AV1
[VideoType]
CVBS
[VideoPI]
VIDEO_P
[VideoPicSys]
PAL
[VideoData]
13500000
690
280
864
312
Update date:Monday, November 24, 2014
Update time:11:05:45
*/
/*屏参参数相关的结构体*/
typedef struct _PannelPara
{
PanlstaticPara *pVideoStaicPara;
}PannelPara;
typedef struct _VideoChannel
{
unsigned char INPUT_ID;
PannelPara VideoPara;
}VideoChannel;
#define STATIC_NUM 280
#define POS_DYN_NUM 0
#define SYS_DYN_NUM 0
#define PAD_MUX_NUM 36
#define VCOM_AC_Def 0X00
#define VCOM_DC_Def 0X00
#define PWMA_VAL 0X0000
#define PWMB_VAL 0X0000
#define PAL_PLL_CLK 0X0048
#define NTSC_PLL_CLK 0X0048
#define PWM0_CYCLE_VAL 0X00FF
#define PWM1_CYCLE_VAL 0X00FF
#define PWM2_CYCLE_VAL 0X00FF
#define PWM3_CYCLE_VAL 0X00FF
#define PWM0_DUTY_VAL 0X0080
#define PWM1_DUTY_VAL 0X0080
#define PWM2_DUTY_VAL 0X0080
#define PWM3_DUTY_VAL 0X0080
#define I2C_ACCESS_LOOP_TIME 20
typedef struct
{
unsigned char regAddr;
unsigned char regValue;
}ARK7116REG;
typedef struct
{
unsigned char regAddr;
unsigned char regPalValue;
unsigned char regNtscValue;
}ARK7116DYREG;
#if __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,520 @@
#ifndef _BOARD_H
#define _BOARD_H
/********** display configuration **********/
#define LCD_INTERFACE_TTL 0
#define LCD_INTERFACE_LVDS 1
#define LCD_INTERFACE_CPU 2
#define LCD_INTERFACE_MIPI 3
#define LCD_WIRING_MODE_RGB 0
#define LCD_WIRING_MODE_RBG 1
#define LCD_WIRING_MODE_GRB 2
#define LCD_WIRING_MODE_GBR 3
#define LCD_WIRING_MODE_BRG 4
#define LCD_WIRING_MODE_BGR 5
#define LCD_WIRING_BIT_ORDER_MSB 0
#define LCD_WIRING_BIT_ORDER_LSB 1
#define LVDS_PANEL_FORMAT_TI 0
#define LVDS_PANEL_FORMAT_NS 1
#define LVDS_PANEL_DATA_8BIT 0
#define LVDS_PANEL_DATA_6BIT 1
#define CPU_PANEL_18BIT_MODE 0
#define CPU_PANEL_16BIT_MODE 1
#define CPU_PANEL_9BIT_MODE 2
#define CPU_PANEL_8BIT_MODE 3
#define LCD_ROTATE_ANGLE_0 0
#define LCD_ROTATE_ANGLE_90 1
#define LCD_ROTATE_ANGLE_180 2
#define LCD_ROTATE_ANGLE_270 3
#define LCD_H_FLIP 0 //水平镜像
#define LCD_V_FLIP 0 //垂直镜像
//#define LCD_CLK_INVERSE //LCD时钟极性反向
#define LCD_ROTATE_ANGLE LCD_ROTATE_ANGLE_0
#if defined(LVGL_VG_GPU) || defined(VG_ONLY) || defined(REVERSE_TRACK)
#ifndef VG_DRIVER
#error "Error! Must define VG_DRIVER."
#endif
#endif
#if defined(DOUBLE_POINTER_HALO) || defined(SINGLE_POINTER_HALO)
#ifndef VG_ONLY
#error "Error! Must define VG_ONLY."
#endif
#endif
#ifdef VG_ONLY
#if defined(DOUBLE_POINTER_HALO)
#define LCD_WIDTH 1280
#define LCD_HEIGHT 480
#define LCD_BPP 16
#define LCD_INTERFACE_TYPE LCD_INTERFACE_LVDS
#elif defined(SINGLE_POINTER_HALO)
#define LCD_WIDTH 1024
#define LCD_HEIGHT 600
#define LCD_BPP 16
#define LCD_INTERFACE_TYPE LCD_INTERFACE_TTL
#endif
#elif defined(AWTK)
//240719 lj
// #define LCD_WIDTH 1024
// #define LCD_HEIGHT 600
// #define LCD_BPP 16
#define LCD_WIDTH 800
#define LCD_HEIGHT 480
#define LCD_BPP 32
#define LCD_INTERFACE_TYPE LCD_INTERFACE_TTL
#else
#define LCD_WIDTH 1024
#define LCD_HEIGHT 600
#ifdef REVERSE_UI
#define LCD_BPP 32
#else
#define LCD_BPP 16
#endif
#define LCD_INTERFACE_TYPE LCD_INTERFACE_TTL
#endif
#if LCD_INTERFACE_TYPE == LCD_INTERFACE_TTL
#define LCD_WIRING_MODE LCD_WIRING_MODE_RGB
#define LCD_WIRING_BIT_ORDER LCD_WIRING_BIT_ORDER_LSB
#elif LCD_INTERFACE_TYPE == LCD_INTERFACE_LVDS
#define LCD_WIRING_MODE LCD_WIRING_MODE_BGR
#define LCD_WIRING_BIT_ORDER LCD_WIRING_BIT_ORDER_MSB
#define LVDS_SCREEN_RST_GPIO 74
#define LVDS_PANEL_FORMAT LVDS_PANEL_FORMAT_TI
#define LVDS_PANEL_DATA LVDS_PANEL_DATA_8BIT
#elif LCD_INTERFACE_TYPE == LCD_INTERFACE_CPU
#define CPU_PANEL_DATA CPU_PANEL_8BIT_MODE
#elif LCD_INTERFACE_TYPE == LCD_INTERFACE_MIPI
#define LCD_WIRING_MODE LCD_WIRING_MODE_RGB
#define LCD_WIRING_BIT_ORDER LCD_WIRING_BIT_ORDER_MSB
#endif
#define FB_SIZE (LCD_WIDTH * LCD_HEIGHT * LCD_BPP / 8)
#define VIDEO_DISPLAY_WIDTH LCD_WIDTH
#define VIDEO_DISPLAY_HEIGHT LCD_HEIGHT
#define VIDEO_DISPLAY_BUF_NUM 2
#if (LCD_WIDTH == 1024 && LCD_HEIGHT == 600)
#define LCD_TIMING_VBP 1
#define LCD_TIMING_VFP 1
#define LCD_TIMING_VSW 30
#define LCD_TIMING_HBP 100
#define LCD_TIMING_HFP 100
#define LCD_TIMING_HSW 370
#define LCD_CLK_FREQ 50000000
#elif (LCD_WIDTH == 800 && LCD_HEIGHT == 480)
#define LCD_TIMING_VBP 1
#define LCD_TIMING_VFP 1
#define LCD_TIMING_VSW 30
#define LCD_TIMING_HBP 50
#define LCD_TIMING_HFP 50
#define LCD_TIMING_HSW 180
#define LCD_CLK_FREQ 35000000
#elif (LCD_WIDTH == 1280 && LCD_HEIGHT == 720)
#define LCD_TIMING_VBP 5
#define LCD_TIMING_VFP 65
#define LCD_TIMING_VSW 2
#define LCD_TIMING_HBP 16
#define LCD_TIMING_HFP 42
#define LCD_TIMING_HSW 2
#define LCD_CLK_FREQ 60000000
#elif (LCD_WIDTH == 1280 && LCD_HEIGHT == 480)
#define LCD_TIMING_VBP 5
#define LCD_TIMING_VFP 8
#define LCD_TIMING_VSW 3
#define LCD_TIMING_HBP 16
#define LCD_TIMING_HFP 26
#define LCD_TIMING_HSW 12
#define LCD_CLK_FREQ 40000000
#elif (LCD_WIDTH == 480 && LCD_HEIGHT == 1280)
#define LCD_TIMING_VBP 6// 14
#define LCD_TIMING_VFP 6// 16
#define LCD_TIMING_VSW 16// 2
#define LCD_TIMING_HBP 16
#define LCD_TIMING_HFP 36
#define LCD_TIMING_HSW 26
#define LCD_CLK_FREQ 50000000
#elif (LCD_WIDTH == 480 && LCD_HEIGHT == 960)
#define LCD_TIMING_VBP 20//10
#define LCD_TIMING_VFP 20//30
#define LCD_TIMING_VSW 10
#define LCD_TIMING_HBP 30//5
#define LCD_TIMING_HFP 40//10
#define LCD_TIMING_HSW 10
#define LCD_CLK_FREQ 33330000
#else
#error "no lcd timing configuraion."
#endif
/*******************************************/
/************ adc configuration ************/
//#define ADC_TOUCH
#define ADC_KEY
/*******************************************/
/******* video in configuration *******/
#define VIDEO_DECODER_RN6752
//#define VIDEO_DECODER_ARK7116
#define VIN_CVBS_PAL 0
#define VIN_CVBS_NTSC 1
#define VIN_AHD_720P_25 2
#define VIN_AHD_720P_30 3
#define VIDEO_IN_FORMAT VIN_CVBS_NTSC
#if VIDEO_IN_FORMAT == VIN_CVBS_PAL
#define VIN_WIDTH 720
#define VIN_HEIGHT 288
#elif VIDEO_IN_FORMAT == VIN_CVBS_NTSC
#define VIN_WIDTH 720
#define VIN_HEIGHT 240
#elif VIDEO_IN_FORMAT == VIN_AHD_720P_25 || VIDEO_IN_FORMAT == VIN_AHD_720P_30
#define VIN_WIDTH 1280
#define VIN_HEIGHT 720
#endif
#if VIN_WIDTH * VIN_HEIGHT > 0x96000
#define VIN_SMALL_MEM
#endif
/*******************************************/
/************ carback configuration ********/
//#define CARBACK_DETECT
/*******************************************/
/********* touchscreen configuration *******/
//#define TP_SUPPORT
#ifdef TP_SUPPORT
/* Select one tp IC */
//#define TP_USE_GT9XX
//#define TP_USE_GA657X
//#define TP_USE_FT6336U
/* Config tp parameters */
#define TP_GPIO_INT 4
#define TP_GPIO_RST 5
#define TP_INV_X 0
#define TP_INV_Y 0
#define TP_INV_XY_AXIS 0 //翻转XY轴
#define TP_MT_TOUCH 0 //支持多点触摸
#endif
/*******************************************/
/*********** sdmmc configuration ***********/
#define SDMMC_SUPPORT
/*******************************************/
/*********** uart configuration ************/
//240719 lj
#define UART_BT_PORT 3//蓝牙通讯串口3
#define UART_MCU_PORT 2//通话蓝牙与cat1通讯串口2
/*******************************************/
/************ rtc configuration ************/
#define RTC_SUPPORT
/*******************************************/
/************ remote configuration ************/
//#define REMOTE_SUPPORT
/*******************************************/
/************ pwm capture configuration ************/
//#define PWM_CAP_SUPPORT
/*******************************************/
/************ dma configuration ************/
/* the smaller channel has higher priority */
#define I2S_DMA_RXCH 0
#define I2S_DMA_TXCH 1
#define SPI0_RX_DMA_CH 2
#define SDMMC_DMA_CH 3
/*******************************************/
/************ usb configuration ************/
#define USB_SUPPORT
#define USB_MODE_ID -1
//#define USB_DMA
//#define USB_UVC_SUPPORT
#define CONFIG_USB_DWC2_HOST 1
#define CONFIG_USB_NEW_DWC2_HOST 1
#define CONFIG_USB_DWC2_PERIPHERAL 1
#define CONFIG_USB_NEW_DWC2_GADGET 1
#if USB_MODE_ID && USB_MODE_ID != -1
#define CONFIG_USB_DEVICE_CDC_NCM 1
#endif
/*******************************************/
/************ carlink configuration ************/
#ifdef CARLINK_ENABLE /* define in iar options */
#define WIFI_SUPPORT
#endif
#ifdef WIFI_SUPPORT
#define CARLINK_EY 0
#define CARLINK_EC 0
#define CARLINK_CP 1
#define CARLINK_AA 0
#define WIFI_RESET_IO 12
#else
#define CARLINK_EY 0
#define CARLINK_EC 0
#define CARLINK_CP 0
#define CARLINK_AA 0
#endif
//蓝牙供电io口
#define BT_RESET_POWER_IO 46
#if CARLINK_EY && CARLINK_EC
#error "Do not choose two car links"
#elif (CARLINK_EY && CARLINK_CP)
#error "Do not choose two car links"
#elif (CARLINK_EY && CARLINK_AA)
#error "Do not choose two car links"
#elif (CARLINK_EC && CARLINK_CP)
#error "Do not choose two car links"
#elif (CARLINK_EC && CARLINK_AA)
#error "Do not choose two car links"
#elif (CARLINK_CP && CARLINK_AA)
#error "Do not choose two car links"
#endif
#define USE_LWIP 1
#if CARLINK_CP && !USE_LWIP
#error "carplay need lwip"
#endif
#define BT_RESET_IO 13
#define BT_UART_PORT 1
//#define RELTECK_WIFI_AP_MODE
/*******************************************/
/************ i2c configuration ************/
#define HW_I2C0_SUPPORT //Hardware i2c0 support
//#define HW_I2C1_SUPPORT //Hardware i2c1 support
//#define ANALOG_I2C_SUPPORT //Analog i2c support
#ifdef ANALOG_I2C_SUPPORT
#define I2C_GPIO0_SDA_PIN 102
#define I2C_GPIO0_SCL_PIN 101
#endif
/*******************************************/
/************ audio configuration ************/
#define I2S_ID0 0
#define I2S_ID1 1
#define I2S_NUMS 2
#define AUDIO_FLAG_REPLAY 1
#define AUDIO_FLAG_RECORD 2
#define AUDIO_FLAG_REPLAY_RECORD (AUDIO_FLAG_REPLAY | AUDIO_FLAG_RECORD)
/* add your adc type */
#define AUDIO_CODEC_ADC_NONE 0 //Not use codec adc ic or no need driver.
#define AUDIO_CODEC_ADC_ES7243E 1 //Use codec adc ic es7243e.
/* add your dac type */
#define AUDIO_CODEC_DAC_NONE 0 //Not use codec adc ic or no need driver.
#define AUDIO_CODEC_DAC_ES8156 1 //Use codec dac ic es8156.
/* choose your audio use type */
#define AUDIO_REPLAY
#define AUDIO_RECORD
#ifdef AUDIO_REPLAY
#define AUDIO_REPLAY_I2S I2S_ID0 /* Select i2s id */
#define AUDIO_CODEC_DAC_IC AUDIO_CODEC_DAC_NONE /* Select your codec dac type */
#endif
#ifdef AUDIO_RECORD
#define AUDIO_RECORD_I2S I2S_ID1 /* Select i2s id */
#define AUDIO_CODEC_ADC_IC AUDIO_CODEC_ADC_ES7243E /* Select your codec adc type */
#endif
#ifndef AUDIO_CODEC_DAC_IC
#define AUDIO_CODEC_DAC_IC AUDIO_CODEC_DAC_NONE /* Do not use codec dac by default */
#endif
#ifndef AUDIO_CODEC_ADC_IC
#define AUDIO_CODEC_ADC_IC AUDIO_CODEC_ADC_NONE /* Do not use codec adc by default */
#endif
/*******************************************/
/********** romfile configuration **********/
/* 没有定义ROMFILE_USE_SMALL_MEMromfile内容会全部加载到ddr
* 内存不足时可以定义ROMFILE_USE_SMALL_MEM节省内存使用 */
#if !defined(VG_ONLY)
#define ROMFILE_USE_SMALL_MEM
#endif
#ifndef ROMFILE_USE_SMALL_MEM
/* 定义READ_ROMFILE_ONCEromfile内容会整个一次加载到ddr如果
* 文件过大会导致启动时间慢 */
//#define READ_ROMFILE_ONCE
#else
/* 缓存在DDR里的文件数未缓存的文件需要重新从flash里读取 */
#define ROMFILE_CACHE_DEF_SIZE 0
#endif
/*******************************************/
/********** animation configuration **********/
#define ANIMATION_NONE 0
#define ANIMATION_USE_SMALL_MEM 1
#define ANIMATION_NORMAL 2
#define ANIMATION_POLICY ANIMATION_NORMAL
/*********************************************/
/************ flash type configuration ************/
#define SPI_NOR_FLASH 0
#define SPI_NAND_FLASH 1
#define EMMC_FLASH 2
#define DEVICE_TYPE_SELECT SPI_NOR_FLASH
/*******************************************/
/********** update address configuration **********/
#if DEVICE_TYPE_SELECT == SPI_NAND_FLASH
#define LOADER_OFFSET 0x0
#define STEPLDRA_OFFSET 0x20000
#define STEPLDRB_OFFSET 0x40000
#define STEPLDR_MAX_SIZE 0x14000
#define SYSINFOA_MEDIA_OFFSET 0x60000
#define SYSINFOB_MEDIA_OFFSET 0x80000
#define UPDATEFILE_MEDIA_OFFSET 0xa0000
#define UPDATEFILE_MEDIA_B_OFFSET 0xc00000
#define UPDATEFILE_MAX_SIZE 0xb00000
#define OTA_MEDIA_OFFSET 0x500000
#define OTA_MEDIA_SIZE 0xa00000
#define SPI0_QSPI_MODE
#elif DEVICE_TYPE_SELECT == SPI_NOR_FLASH
#define LOADER_OFFSET 0x0
#define STEPLDRA_OFFSET 0x4000
#define STEPLDRB_OFFSET 0x20000
#define STEPLDR_MAX_SIZE 0x14000
#define SYSINFOA_MEDIA_OFFSET 0x3c000
#define SYSINFOB_MEDIA_OFFSET 0x3e000
#define UPDATEFILE_MEDIA_OFFSET 0x40000
#define UPDATEFILE_MEDIA_B_OFFSET 0xc00000
#define UPDATEFILE_MAX_SIZE 0xb00000
#define OTA_MEDIA_OFFSET 0xa00000
#define OTA_MEDIA_SIZE 0x500000
//#define SPI0_QSPI_MODE
#elif DEVICE_TYPE_SELECT == EMMC_FLASH
#define LOADER_OFFSET 0x0
#define LOADERB_OFFSET 0x100000
#define STEPLDRA_OFFSET 0x200000
#define STEPLDRB_OFFSET 0x300000
#define STEPLDR_MAX_SIZE 0x14000
#define SYSINFOA_MEDIA_OFFSET 0x400000
#define SYSINFOB_MEDIA_OFFSET 0x500000
#define UPDATEFILE_MEDIA_OFFSET 0xA00000
#define UPDATEFILE_MEDIA_B_OFFSET 0x40000000
#define UPDATEFILE_MAX_SIZE 0x1000000
#define OTA_MEDIA_OFFSET 0x80000000
#define OTA_MEDIA_SIZE 0x10000000
//#define SPI0_QSPI_MODE
#endif
/*********************************************/
/********** ulog configuration **********/
//#define USE_ULOG
#define ULOG_NAME_MAX 8
#define ULOG_LINE_BUF_SIZE 1024
#define ULOG_OUTPUT_LEVEL
#define ULOG_OUTPUT_TIME
//#define ULOG_TIME_USING_TIMESTAMP
//#define ULOG_OUTPUT_TAG
//#define ULOG_USING_COLOR
#define ULOG_USING_ISR_LOG
#define ULOG_BACKEND_USING_CONSOLE
#define ULOG_EASYFLASH_BACKEND_ENABLE
#ifdef ULOG_EASYFLASH_BACKEND_ENABLE
#define EASYFLASH_LOG
#if DEVICE_TYPE_SELECT != EMMC_FLASH
#define EASYFLASH_LOG_AREA_SIZE 0x100000
#define EASYFLASH_ERASE_GRAN 0x1000
#define EASYFLASH_WRITE_GRAN 0x100
#define EASYFLASH_START_ADDR 0x1700000
#else
#define EASYFLASH_LOG_AREA_SIZE 0x100000
#define EASYFLASH_ERASE_GRAN 0x10000
#define EASYFLASH_WRITE_GRAN 0x200
#define EASYFLASH_START_ADDR 0x60000000
#endif
#endif
//#define ULOG_FILE_BACKEND_ENABLE
#ifdef ULOG_FILE_BACKEND_ENABLE
#if DEVICE_TYPE_SELECT != EMMC_FLASH
#define ULOG_FILE_ROOT_PATH "/sf/logs"
#else
#define ULOG_FILE_ROOT_PATH "/sd/logs"
#endif
#define ULOG_FILE_NAME_BASE "ulog.log"
#define ULOG_FILE_MAX_NUM 10
#define ULOG_FILE_MAX_SIZE (1024 * 32)
#endif
//#define ULOG_USING_ASYNC_OUTPUT
#define ULOG_ASYNC_OUTPUT_BUF_SIZE 1024
#define ULOG_ASYNC_OUTPUT_THREAD_STACK 2048
#define ULOG_ASYNC_OUTPUT_THREAD_PRIORITY 10
/*********************************************/
/********** update address configuration **********/
//#define OTA_UPDATE_SUPPORT
#ifdef OTA_UPDATE_SUPPORT
//#define WIFI_UPDATE_SUPPORT
#if defined(WIFI_UPDATE_SUPPORT) && !defined(USB_SUPPORT)
#error "Error! Should define USB_SUPPORT to support wifi simu update"
#endif
//#define NCM_UPDATE_SUPPORT
#if defined(NCM_UPDATE_SUPPORT) && !CONFIG_USB_DEVICE_CDC_NCM
#error "Error! Should define CONFIG_USB_DEVICE_CDC_NCM=1 to support ncm update"
#endif
//#define NCM_LOG_SUPPORT
#if defined(NCM_LOG_SUPPORT) && !CONFIG_USB_DEVICE_CDC_NCM
#error "Error! Should define CONFIG_USB_DEVICE_CDC_NCM=1 to support ncm log"
#endif
#endif
/*********************************************/
void VideoDisplayBufInit(void);
int xVideoDisplayBufTake(uint32_t xTicksToWait);
void vVideoDisplayBufGive(void);
uint32_t ulVideoDisplayBufGet(void);
uint32_t ulVideoDisplayBufGetSize(void);
void vVideoDisplayBufRender(uint32_t buf_addr);
void vVideoDisplayBufFree(uint32_t buf_addr);
unsigned int ulVideoDisplayGetBufferAddr(int index);
#ifdef VIDEO_DECODER_RN6752
int rn6752_init(void);
#endif
#ifdef VIDEO_DECODER_ARK7116
int ark7116_init();
#endif
#ifdef SDMMC_SUPPORT
int mmcsd_core_init(void);
int mmc_init(void);
#endif
int carback_init(void);
void notify_enter_carback(void);
void notify_exit_carback(void);
int get_carback_status(void);
#endif

View File

@ -0,0 +1,20 @@
#ifndef _KEYPAD_H
#define _KEYPAD_H
#ifdef __cplusplus
extern "C" {
#endif
#define KEY_START_EVENT 1
#define KEY_STOP_EVENT 2
#define KEY_SAMPLE_EVENT 3
void KeypadInit(void);
void KeyEventHandler(UINT32 ulEvent, UINT32 lpParam, UINT32 wParam);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,44 @@
#ifndef _OTA_UPDATE_H
#define _OTA_UPDATE_H
#include "board.h"
typedef enum {
UPFILE_TYPE_WHOLE,
UPFILE_TYPE_RESOURCE,
UPFILE_TYPE_ANIMATION,
UPFILE_TYPE_APP,
UPFILE_TYPE_FIRSTLDR,
UPFILE_TYPE_STEPLDR,
UPFILE_TYPE_LNCHEMMC,
UPFILE_TYPE_NUM,
} eUpfileType;
static const char *g_upfilename[UPFILE_TYPE_NUM] = {
"update.bin",
"rom.bin",
"bootanim.bin",
"amt630hv100.bin",
#if DEVICE_TYPE_SELECT == EMMC_FLASH
"emmcldr.bin",
#else
"spildr.bin",
#endif
"stepldr.bin",
"lnchemmc.bin",
};
#define SF_MOUNT_PATH "/sf"
#define SDMMC_MOUNT_PATH "/sd"
#if DEVICE_TYPE_SELECT == EMMC_FLASH
#define OTA_MOUNT_PATH SDMMC_MOUNT_PATH
#else
#define OTA_MOUNT_PATH SF_MOUNT_PATH
#endif
#define UPFILE_APP_MAGIC 0xe59ff030
#define APPLDR_CHECKSUM_OFFSET 20
#define IMAGE_RW_SIZE 0x10000
int update_from_media(char *mpath, int filetype);
#endif

View File

@ -0,0 +1,93 @@
#ifndef _RINGBLK_BUF_H_
#define _RINGBLK_BUF_H_
/*
* Introduction:
* The rbb is the ring buffer which is composed with many blocks. It is different from the ring buffer.
* The ring buffer is only composed with chars. The rbb put and get supported zero copies. So the rbb
* is very suitable for put block and get block by a certain order. Such as DMA block transmit,
* communicate frame send/recv, and so on.
*/
#ifdef __cplusplus
extern "C" {
#endif
enum rbb_status
{
/* unused status when first initialize or after blk_free() */
RBB_BLK_UNUSED,
/* initialized status after blk_alloc() */
RBB_BLK_INITED,
/* put status after blk_put() */
RBB_BLK_PUT,
/* get status after blk_get() */
RBB_BLK_GET,
};
typedef enum rbb_status rbb_status_t;
/**
* the block of rbb
*/
struct rbb_blk
{
rbb_status_t status :8;
/* less then 2^24 */
size_t size :24;
uint8_t *buf;
ListItem_t list;
};
typedef struct rbb_blk *rbb_blk_t;
/**
* Rbb block queue: the blocks (from block1->buf to blockn->buf) memory which on this queue is continuous.
*/
struct rbb_blk_queue
{
rbb_blk_t blocks;
size_t blk_num;
};
typedef struct rbb_blk_queue *rbb_blk_queue_t;
/**
* ring block buffer
*/
struct rbb
{
uint8_t *buf;
size_t buf_size;
/* all of blocks */
rbb_blk_t blk_set;
size_t blk_max_num;
/* saved the initialized and put status blocks */
List_t blk_list;
};
typedef struct rbb *rbb_t;
/* rbb (ring block buffer) API */
void rbb_init(rbb_t rbb, uint8_t *buf, size_t buf_size, rbb_blk_t block_set, size_t blk_max_num);
rbb_t rbb_create(size_t buf_size, size_t blk_max_num);
void rbb_destroy(rbb_t rbb);
size_t rbb_get_buf_size(rbb_t rbb);
/* rbb block API */
rbb_blk_t rbb_blk_alloc(rbb_t rbb, size_t blk_size);
void rbb_blk_put(rbb_blk_t block);
rbb_blk_t rbb_blk_get(rbb_t rbb);
size_t rbb_blk_size(rbb_blk_t block);
uint8_t *rbb_blk_buf(rbb_blk_t block);
void rbb_blk_free(rbb_t rbb, rbb_blk_t block);
/* rbb block queue API */
size_t rbb_blk_queue_get(rbb_t rbb, size_t queue_data_len, rbb_blk_queue_t blk_queue);
size_t rbb_blk_queue_len(rbb_blk_queue_t blk_queue);
uint8_t *rbb_blk_queue_buf(rbb_blk_queue_t blk_queue);
void rbb_blk_queue_free(rbb_t rbb, rbb_blk_queue_t blk_queue);
size_t rbb_next_blk_queue_len(rbb_t rbb);
#ifdef __cplusplus
}
#endif
#endif /* _RINGBLK_BUF_H_ */

View File

@ -0,0 +1,46 @@
#ifndef _ROMFILE_H
#define _ROMFILE_H
#define ROMFILE_NAME_MAX_LEN 64
typedef struct {
char name[ROMFILE_NAME_MAX_LEN];
unsigned int offset;
unsigned int size;
} RomFileInfo;
typedef struct {
unsigned int magic;
unsigned int filenum;
unsigned int romsize;
unsigned int checksum;
RomFileInfo files[];
} RomHeader;
typedef struct {
char name[ROMFILE_NAME_MAX_LEN];
void *buf;
int cached_filenum;
int life;
} RomFileCache;
typedef struct {
void *buf;
int index;
int size;
int pos;
RomFileCache *cache;
} RomFile;
int ReadRomFile(void);
RomFile *RomFileOpen(const char *name);
size_t RomFileRead(RomFile *file, void *buf, size_t size);
int RomFileSeek(RomFile *file, int offset, int whence);
void RomFileClose(RomFile *file);
const char * RomFileGetExt(const char * path);
int RomFileTell(RomFile *file);
int RomFileGetSize(RomFile *file);
int RomFileExist(const char *name);
int RomFileDirExist(const char *name);
#endif

View File

@ -0,0 +1,58 @@
#ifndef _SOC_DAI_H
#define _SOC_DAI_H
#ifdef __cplusplus
extern "C" {
#endif
#define SND_SOC_DAIFMT_FORMAT_MASK 0x000f
#define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0
#define SND_SOC_DAIFMT_INV_MASK 0x0f00
#define SND_SOC_DAIFMT_MASTER_MASK 0xf000
#define SND_SOC_DAIFMT_CBM_CFM (1 << 12) /* codec clk & FRM master */
#define SND_SOC_DAIFMT_CBS_CFM (2 << 12) /* codec clk slave & FRM master */
#define SND_SOC_DAIFMT_CBM_CFS (3 << 12) /* codec clk master & frame slave */
#define SND_SOC_DAIFMT_CBS_CFS (4 << 12) /* codec clk & FRM slave */
#define SND_SOC_DAIFMT_I2S 1 /* I2S mode */
#define SND_SOC_DAIFMT_RIGHT_J 2 /* Right Justified mode */
#define SND_SOC_DAIFMT_LEFT_J 3 /* Left Justified mode */
#define SND_SOC_DAIFMT_DSP_A 4 /* L data MSB after FRM LRC */
#define SND_SOC_DAIFMT_DSP_B 5 /* L data MSB during FRM LRC */
#define SND_SOC_DAIFMT_AC97 6 /* AC97 */
#define SND_SOC_DAIFMT_PDM 7 /* Pulse density modulation */
#define SND_SOC_DAIFMT_NB_NF (1 << 8) /* normal bit clock + frame */
#define SND_SOC_DAIFMT_NB_IF (2 << 8) /* normal BCLK + inv FRM */
#define SND_SOC_DAIFMT_IB_NF (3 << 8) /* invert BCLK + nor FRM */
#define SND_SOC_DAIFMT_IB_IF (4 << 8) /* invert BCLK + FRM */
enum snd_soc_bias_level {
SND_SOC_BIAS_OFF = 0,
SND_SOC_BIAS_STANDBY = 1,
SND_SOC_BIAS_PREPARE = 2,
SND_SOC_BIAS_ON = 3,
};
struct snd_soc_hw_params {
int rates;
int channels;
int bits;
};
struct snd_soc_dai_ops {
int (*init)(int master);
int (*hw_params)(struct snd_soc_hw_params *params);
int (*startup)(int start);
int (*set_mclk)(int freq, int dir); //reserved.
int (*set_fmt)(unsigned int fmt); //reserved.
int (*set_mute)(int mute); //reserved.
};
#ifdef __cplusplus
}
#endif
#endif /* _TOUCH_H */

View File

@ -0,0 +1,32 @@
#ifndef _SYSINFO_H
#define _SYSINFO_H
#define UPDATE_MEDIA_SD 0
#define UPDATE_MEDIA_USB 1
#define UPDATE_MEDIA_UART 2
#define UPDATE_STATUS_START 0
#define UPDATE_STATUS_END 1
typedef struct {
unsigned int app_checksum;
unsigned int stepldr_offset;
unsigned int stepldr_size;
unsigned int update_media_type;
unsigned int update_status;
unsigned int app_size;
unsigned int image_offset;
unsigned int loader_offset;
unsigned int loader_size;
unsigned int reserved[12];
unsigned int checksum;
} SysInfo;
SysInfo *GetSysInfo(void);
int ReadSysInfo(void);
void SaveSysInfo(void);
#endif

View File

@ -0,0 +1,34 @@
#ifndef _TOUCH_H
#define _TOUCH_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
int x[5], xfb[5];
int y[5], yfb[5];
int a[7];
} calibration;
#define TOUCH_START_EVENT 1
#define TOUCH_STOP_EVENT 2
#define TOUCH_SAMPLE_EVENT 3
UINT32 AdjustTouch(void);
void InitializeCalibration(int a0, int a1, int a2, int a3, int a4, int a5, int a6);
int LoadTouchConfigure(void);
void TouchInit(void);
void TouchEventHandler(UINT32 ulEvent, UINT32 lpParam, UINT32 wParam);
#ifdef __cplusplus
}
#endif
#endif /* _TOUCH_H */

View File

@ -0,0 +1,26 @@
#ifndef _UPDATEFILE_H
#define _UPDATEFILE_H
#define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24))
typedef struct {
unsigned int magic;
unsigned int offset;
unsigned int size;
} UpFileInfo;
typedef struct {
unsigned int magic;
unsigned int filenum;
unsigned int size;
unsigned int checksum;
unsigned int reserved1;
unsigned int reserved2;
UpFileInfo files[];
} UpFileHeader;
int GetUpFileInfo(void);
uint32_t GetUpFileOffset(uint32_t magic);
uint32_t GetUpFileSize(uint32_t magic);
#endif

View File

@ -0,0 +1,653 @@
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "board.h"
#include "chip.h"
#include "sfud.h"
#include "updatefile.h"
#include "mfcapi.h"
#include "dwl.h"
#include "animation.h"
#if DEVICE_TYPE_SELECT == EMMC_FLASH
#include "mmcsd_core.h"
#endif
static TaskHandle_t animation_task = NULL;
static SemaphoreHandle_t animation_mutex;
#if ANIMATION_POLICY == ANIMATION_USE_SMALL_MEM
static BANIHEADER ani_header;
static BANIHEADER *aniheader = &ani_header;
#else
static BANIHEADER *aniheader;
#endif
static unsigned int anioffset;
static unsigned int anisize;
static int ani_playing = 0;
static int ani_replay = 0;
static int ani_stop = 0;
static int ani_frames = 0;
static int ani_display_index = 0;
static int ani_take_vdisbuf = 0;
static unsigned int ani_frame_addr;
static uint32_t first_show_done = 0;
#if 0
#include "ff_stdio.h"
static int get_h264_single_file_from_sd(void *buf, int *len)
{
#define READ_SIZE (LCD_WIDTH*LCD_HEIGHT*2)
char path_name[64] = "/sd/000.h264";
static int count = 0;
FF_FILE *fp;
int ret = -1;
sprintf(path_name, "/sd/%.3d.h264", count++);
*len = 0;
fp = ff_fopen(path_name, "rb");
if (fp) {
ret = ff_fread(buf, 1, READ_SIZE, fp);
if (ret <= 0) {
printf("read sdmmc file:%s failed, maybe read done\n", path_name);
return -1;
}
*len = ret;
} else {
printf("### open %s fail.\n", path_name);
count = 0;
return -1;
}
if(fp)
ff_fclose(fp);
//printf("###read %s len:%d.\n", path_name, *len);
return 0;
}
static void h264_decode_test_thread(void *param)
{
#define H264DEC_SEMIPLANAR_YUV420 0x020001
#define H264DEC_INBUF_SIZE (LCD_WIDTH*LCD_HEIGHT*2)
#define H264DEC_DISP_COUNTS 2
DWLLinearMem_t inBuf;
OutFrameBuffer outBuf = {0};
uint32_t h264SrcSize = 0;
MFCHandle *handle = NULL;
uint32_t display_addr[H264DEC_DISP_COUNTS] = {0};
uint32_t display_addr_index = 0;
uint32_t first_show_done = 0;
int ret;
int i;
void *h264SrcBuf = pvPortMalloc(H264DEC_INBUF_SIZE);
if(!h264SrcBuf) {
printf("%s, h264SrcBuf pvPortMalloc failed.\n", __func__);
return ;
}
for(i=0; i<H264DEC_DISP_COUNTS; i++) {
display_addr[i] = (uint32_t)pvPortMalloc(H264DEC_INBUF_SIZE);
if(!display_addr[i] ) {
printf("%s, display_addr[%d] pvPortMalloc failed.\n", __func__, i);
return ;
}
}
mmcsd_wait_cd_changed(portMAX_DELAY);
handle = mfc_init(RAW_STRM_TYPE_H264);
if(!handle) {
printf("%s, mfc_init failed.\n", __func__);
return ;
}
while(1) {
//memset(&outBuf, 0, sizeof(OutFrameBuffer));
//memset(h264SrcBuf, 0, H264DEC_INBUF_SIZE);
mdelay(30);
#if 1 //get h264 info form sdcard.
ret = get_h264_single_file_from_sd(h264SrcBuf, &h264SrcSize);
if(ret != 0) {
printf("%s, get_h264_single_file_from_sd failed.\n", __func__);
continue;
}
inBuf.busAddress = (u32)h264SrcBuf;
inBuf.virtualAddress = (u32 *)inBuf.busAddress;
inBuf.size = h264SrcSize;
CP15_clean_dcache_for_dma(inBuf.busAddress, inBuf.busAddress + inBuf.size);
#else
//1. copy your h264 data to h264SrcBuf;
//2. set your h264 data size to h264SrcSize;
inBuf.busAddress = (u32)h264SrcBuf;
inBuf.virtualAddress = (u32 *)inBuf.busAddress;
inBuf.size = h264SrcSize;
#endif
ret = mfc_decode(handle, &inBuf, &outBuf);
if (ret < 0) {
printf("animation decode fail.\n");
} else {
uint32_t align_width, align_height;
uint32_t yaddr, uaddr, vaddr;
for(i=0; i<outBuf.num; i++) {
align_width = outBuf.frameWidth;
align_height = outBuf.frameHeight;
if(1/*outBuf.outputFormat == H264DEC_SEMIPLANAR_YUV420*/ && align_width && align_height)
{
memcpy((void *)display_addr[display_addr_index], outBuf.buffer[i].pyVirAddress, align_width * align_height * 3 / 2);
// ret = dma_m2mcpy(display_addr[display_addr_index], (uint32_t)outBuf.buffer[i].yBusAddress, align_width * align_height * 3 / 2);
// if(ret) {
// printf("%s() dma_m2m_memcpy failed.\n", __func__);
// continue;
// }
yaddr = display_addr[display_addr_index];
uaddr = yaddr + align_width * align_height;
vaddr = yaddr + align_width * align_height * 5/4;
display_addr_index++;
if(display_addr_index >= H264DEC_DISP_COUNTS) {
display_addr_index = 0;
}
if(!first_show_done) {
ark_lcd_set_osd_size(LCD_VIDEO_LAYER, /*outBuf.codedWidth, outBuf.codedHeight*/LCD_WIDTH, LCD_HEIGHT);
ark_lcd_set_osd_format(LCD_VIDEO_LAYER, LCD_OSD_FORAMT_YUV420);
ark_lcd_set_osd_yuv420_mode(LCD_VIDEO_LAYER, LCD_OSD_Y_UV420);
ark_lcd_osd_enable(LCD_VIDEO_LAYER, 1);
ark_lcd_osd_enable(LCD_UI_LAYER, 0);
first_show_done = 1;
}
ark_lcd_set_osd_yaddr(LCD_VIDEO_LAYER, yaddr);
ark_lcd_set_osd_uaddr(LCD_VIDEO_LAYER, uaddr);
ark_lcd_set_osd_vaddr(LCD_VIDEO_LAYER, vaddr);
ark_lcd_set_osd_sync(LCD_VIDEO_LAYER);
ark_lcd_set_osd_sync(LCD_UI_LAYER);
ark_lcd_wait_for_vsync();
} else {
continue;
}
}
}
}
if(handle)
mfc_uninit(handle);
if(h264SrcBuf)
vPortFree(h264SrcBuf);
for(i=0; i<H264DEC_DISP_COUNTS; i++) {
if(!display_addr[i]) {
vPortFree((void *)display_addr[i]);
}
}
}
static int save_nv12_file_to_sd(void *buf, int len)
{
char path_name[64] = "/sd/000.bin";
static int count = 0;
FF_FILE *fp;
int ret = -1;
sprintf(path_name, "/sd/%.3d.bin", count++);
fp = ff_fopen(path_name, "w+");
if (fp) {
ret = ff_fwrite(buf, 1, len, fp);
if (ret != len) {
printf("read sdmmc file:%s failed.\n", path_name);
ff_fclose(fp);
return -1;
}
} else {
printf("### open %s fail.\n", path_name);
return -1;
}
ff_fclose(fp);
return 0;
}
static int get_file_from_sd(void *buf, int *len)
{
#define READ_SIZE (LCD_WIDTH*LCD_HEIGHT*2)
#if LCD_BPP == 32
char path_name[64] = "/sd/480x1280_rgb888.rgb";
#else
char path_name[64] = "/sd/480x1280_rgb565.rgb";
#endif
FF_FILE *fp;
int ret = -1;
*len = 0;
fp = ff_fopen(path_name, "rb");
if (fp) {
ret = ff_fread(buf, 1, READ_SIZE, fp);
if (ret <= 0) {
printf("read sdmmc file:%s failed.\n", path_name);
return -1;
}
*len = ret;
} else {
printf("### open %s fail.\n", path_name);
return -1;
}
if(fp)
ff_fclose(fp);
return 0;
}
void mipi_disp_test(void)
{
u32 len;
int ret;
u32 *disp_addr = (u32 *)pvPortMalloc(LCD_WIDTH*LCD_HEIGHT*2);
if(!disp_addr) {
printf("disp_addr pvPortMalloc failed.\n");
return ;
}
mmcsd_wait_cd_changed(portMAX_DELAY);
get_file_from_sd(disp_addr, &len);
if(!len) {
printf("get_file_from_sd failed.\n");
return ;
}
CP15_clean_dcache_for_dma((uint32_t)disp_addr, (uint32_t)disp_addr + LCD_WIDTH*LCD_HEIGHT*2);
u32 layer = LCD_OSD0;
u32 width = VIDEO_DISPLAY_WIDTH;
u32 height = VIDEO_DISPLAY_HEIGHT;
u32 format;
#if LCD_BPP == 32
format = LCD_OSD_FORAMT_ARGB888;
#else
format = LCD_OSD_FORAMT_RGB565;
#endif
while(1) {
ark_lcd_osd_enable(LCD_OSD0, 0);
ark_lcd_osd_enable(LCD_OSD1, 0);
ark_lcd_set_osd_sync(LCD_OSD0);
ark_lcd_set_osd_sync(LCD_OSD1);
ark_lcd_set_osd_size(layer, width, height);
ark_lcd_set_osd_format(layer, format);
ark_lcd_osd_enable(layer, 1);
ark_lcd_set_osd_yaddr(layer, (u32)disp_addr);
ark_lcd_set_osd_sync(layer);
ark_lcd_wait_for_vsync();
}
}
#endif
//#define PLAY_SHUTDOWN_ANIMATION
#ifdef PLAY_SHUTDOWN_ANIMATION
static int shutdown_anim = 0;
#endif
static void animation_thread(void *param)
{
MFCHandle *mfc_handle = NULL;
#if DEVICE_TYPE_SELECT != EMMC_FLASH
sfud_flash *sflash;
#endif
uint32_t size;
uint32_t stick, etick, delaytick;
uint32_t display_addr;
uint32_t *tmp_addr = NULL;
uint8_t power=1;
anioffset = GetUpFileOffset(MKTAG('B', 'A', 'N', 'I'));
anisize = GetUpFileSize(MKTAG('B', 'A', 'N', 'I'));
#ifdef PLAY_SHUTDOWN_ANIMATION
if(shutdown_anim){
anioffset = GetUpFileOffset(MKTAG('S', 'A', 'N', 'I'));
anisize = GetUpFileSize(MKTAG('S', 'A', 'N', 'I'));
}
#endif
if (anisize > 0) {
void *anibuf = pvPortMalloc(anisize);
if (anibuf) {
#if DEVICE_TYPE_SELECT != EMMC_FLASH
sflash = sfud_get_device(0);
sfud_read(sflash, anioffset, anisize, anibuf);
#else
emmc_read(anioffset, anisize, anibuf);
#endif
aniheader = (BANIHEADER*)anibuf;
if (aniheader->magic != MKTAG('B', 'A', 'N', 'I')
#ifdef PLAY_SHUTDOWN_ANIMATION
&& aniheader->magic != MKTAG('S', 'A', 'N', 'I')
#endif
) {
printf("Read animation file error!\n");
vPortFree(anibuf);
vTaskDelete(NULL);
return;
}
CP15_clean_dcache_for_dma((uint32_t)anibuf, (uint32_t)anibuf + anisize);
} else {
printf("Error! No enough memory for animation file.\n");
vTaskDelete(NULL);
return;
}
} else {
printf("Warning! Not found animation in update file.\n");
vTaskDelete(NULL);
return;
}
ani_frame_addr = (uint32_t)aniheader + sizeof(BANIHEADER);
for (;;) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
xSemaphoreTake(animation_mutex, portMAX_DELAY);
if (ani_replay) {
ani_frame_addr = (uint32_t)aniheader + sizeof(BANIHEADER);
ani_frames = 0;
ani_replay = 0;
}
stick = xTaskGetTickCount();
ani_playing = 1;
size = *(uint32_t*)ani_frame_addr;
if (xVideoDisplayBufTake(pdMS_TO_TICKS(10)) == pdTRUE) {
if(!mfc_handle)
mfc_handle = mfc_init(RAW_STRM_TYPE_JPEG);
if(!mfc_handle) {
printf("%s, mfc_init failed.\n", __func__);
continue ;
}
display_addr = ulVideoDisplayBufGet();
JpegHeaderInfo jpegInfo = {0};
jpegInfo.handle = mfc_handle;
jpegInfo.jpg_addr = ani_frame_addr + 8;
jpegInfo.jpg_size = size;
jpegInfo.dec_addry = display_addr;
#if LCD_ROTATE_ANGLE != LCD_ROTATE_ANGLE_0
if(!tmp_addr) {
uint32_t tmp_size = ulVideoDisplayBufGetSize();
tmp_addr = (u32 *)pvPortMalloc(tmp_size);
if(!tmp_addr) {
printf("tmp_addr pvPortMalloc failed.\n");
}
}
if(tmp_addr) {
jpegInfo.dec_addry = VIRT_TO_PHY((u32)tmp_addr);
}
#endif
if (mfc_jpegdec(&jpegInfo) != 0) {
printf("animation decode %d frame fail.\n", ani_frames);
vVideoDisplayBufFree(display_addr);
} else {
if(!first_show_done) {
#if LCD_ROTATE_ANGLE == LCD_ROTATE_ANGLE_0
int align_width = (LCD_WIDTH + 0xF) & (~0xF);
int align_height = (LCD_HEIGHT + 0xF) & (~0xF);
if((align_width == jpegInfo.dec_width) && (align_height == jpegInfo.dec_height)) {
ark_lcd_set_osd_size(LCD_VIDEO_LAYER, LCD_WIDTH, LCD_HEIGHT);
} else {
ark_lcd_set_osd_size(LCD_VIDEO_LAYER, jpegInfo.dec_width, jpegInfo.dec_height);
}
ark_lcd_set_osd_format(LCD_VIDEO_LAYER, LCD_OSD_FORAMT_YUV420);
ark_lcd_set_osd_yuv420_mode(LCD_VIDEO_LAYER, LCD_OSD_Y_UV420);
#else
ark_lcd_set_osd_size(LCD_VIDEO_LAYER, LCD_WIDTH, LCD_HEIGHT);
ark_lcd_set_osd_format(LCD_VIDEO_LAYER, LCD_OSD_FORAMT_RGB565);
#endif
if(power){
BrightnessPowerOnSetting();
pwm_enable(2);//?<3F><>?<3F><>?-??<3F><>?<3F><>?<3F>̨<EFBFBD><CCA8><EFBFBD>???<3F><><EFBFBD><EFBFBD>?a??<3F><>31a
pwm_enable(3);//?<3F><>?<3F><>?-??<3F><>?<3F><>?<3F>̨<EFBFBD><CCA8><EFBFBD>???<3F><><EFBFBD><EFBFBD>?a??<3F><>?1a
}
ark_lcd_osd_enable(LCD_VIDEO_LAYER, 1);
ark_lcd_osd_enable(LCD_UI_LAYER, 0);
first_show_done = 1;
}
#if LCD_ROTATE_ANGLE == LCD_ROTATE_ANGLE_0
ark_lcd_set_osd_yaddr(LCD_VIDEO_LAYER, jpegInfo.dec_addry);
ark_lcd_set_osd_uaddr(LCD_VIDEO_LAYER, jpegInfo.dec_addru);
ark_lcd_set_osd_vaddr(LCD_VIDEO_LAYER, jpegInfo.dec_addrv);
#else
pxp_scaler_rotate(jpegInfo.dec_addry, jpegInfo.dec_addru, jpegInfo.dec_addrv,
PXP_SRC_FMT_YUV2P420, jpegInfo.dec_width, jpegInfo.dec_height,
display_addr, 0, PXP_OUT_FMT_RGB565, LCD_WIDTH, LCD_HEIGHT, LCD_ROTATE_ANGLE);
ark_lcd_set_osd_yaddr(LCD_VIDEO_LAYER, display_addr);
#endif
ark_lcd_set_osd_sync(LCD_VIDEO_LAYER);
ark_lcd_set_osd_sync(LCD_UI_LAYER);
ark_lcd_wait_for_vsync();
vVideoDisplayBufRender(display_addr);
ani_take_vdisbuf = 1;
}
}
ani_frame_addr += size;
ani_display_index = !ani_display_index;
if (ani_stop || (++ani_frames >= aniheader->aniCount + aniheader->hasBootlogo ? 1 : 0)
#if ANIMATION_POLICY == ANIMATION_USE_SMALL_MEM
|| (ani_frame_addr > anioffset + anisize))
#else
|| (ani_frame_addr > (uint32_t)aniheader + anisize))
#endif
{
printf("animation end.\n");
extern void Set_sys_power_on_self_test(uint8_t value);
Set_sys_power_on_self_test(50);
ani_stop = 0;
if (aniheader->aniCount > 0)
vTaskDelay(aniheader->aniDelayHideTime);
else if (aniheader->hasBootlogo)
vTaskDelay(aniheader->bootlogoDisplayTime);
#ifdef PLAY_SHUTDOWN_ANIMATION
if(shutdown_anim)
ani_take_vdisbuf = 0;
#endif
if (ani_take_vdisbuf) {
ark_lcd_osd_enable(LCD_VIDEO_LAYER, 0);
ark_lcd_osd_enable(LCD_UI_LAYER, 1);
ark_lcd_set_osd_sync(LCD_UI_LAYER);
ark_lcd_set_osd_sync(LCD_VIDEO_LAYER);
}
vVideoDisplayBufFree(display_addr);
vVideoDisplayBufGive();
ani_playing = 0;
if (ani_replay)
xTaskNotifyGive(animation_task);
xSemaphoreGive(animation_mutex);
if(mfc_handle) {
mfc_uninit(mfc_handle);
mfc_handle = NULL;
}
if(tmp_addr) {
vPortFree(tmp_addr);
tmp_addr = NULL;
}
#ifdef PLAY_SHUTDOWN_ANIMATION
break;
#endif
continue;
}
vVideoDisplayBufGive();
xSemaphoreGive(animation_mutex);
etick = xTaskGetTickCount();
if (aniheader->hasBootlogo && ani_frames == 1)
delaytick = pdMS_TO_TICKS(aniheader->bootlogoDisplayTime) > (etick - stick) ?
pdMS_TO_TICKS(aniheader->bootlogoDisplayTime) - (etick - stick) : 0;
else
delaytick = pdMS_TO_TICKS(1000 / aniheader->aniFps) > (etick - stick) ?
pdMS_TO_TICKS(1000 / aniheader->aniFps) - (etick - stick) : 0;
if (delaytick)
vTaskDelay(delaytick);
xTaskNotifyGive(animation_task);
}
#ifdef PLAY_SHUTDOWN_ANIMATION
if(aniheader) {
vPortFree(aniheader);
aniheader = NULL;
}
animation_task = NULL;
vTaskDelete(NULL);
#endif
}
int animation_init(void)
{
if (animation_task) {
printf("animation is already inited.\n");
return 0;
}
animation_mutex = xSemaphoreCreateMutex();
/* Create a task to play animation */
//if (xTaskCreate(h264_decode_test_thread, "h264_decode_test", configMINIMAL_STACK_SIZE*2, NULL,
if (xTaskCreate(animation_thread, "animation", configMINIMAL_STACK_SIZE, NULL,
configMAX_PRIORITIES - 2, &animation_task) != pdPASS) {
printf("create animation task fail.\n");
animation_task = NULL;
return -1;
}
return 0;
}
void animation_start(void)
{
xSemaphoreTake(animation_mutex, portMAX_DELAY);
first_show_done=0;
if (ani_playing) {
printf("animation is already playing.\n");
xSemaphoreGive(animation_mutex);
return;
}
#if ANIMATION_POLICY == ANIMATION_USE_SMALL_MEM
ani_frame_addr = anioffset + sizeof(BANIHEADER);
#else
ani_frame_addr = (uint32_t)aniheader + sizeof(BANIHEADER);
#endif
ani_frames = 0;
if (animation_task)
xTaskNotifyGive(animation_task);
xSemaphoreGive(animation_mutex);
}
/* replay animation even if animation is already playing */
void animation_restart(void)
{
xSemaphoreTake(animation_mutex, portMAX_DELAY);
first_show_done=0;
ani_stop=0;
if (ani_playing) {
ani_replay = 1;
xSemaphoreGive(animation_mutex);
return;
}
#if ANIMATION_POLICY == ANIMATION_USE_SMALL_MEM
ani_frame_addr = anioffset + sizeof(BANIHEADER);
#else
ani_frame_addr = (uint32_t)aniheader + sizeof(BANIHEADER);
#endif
ani_frames = 0;
if (animation_task)
xTaskNotifyGive(animation_task);
xSemaphoreGive(animation_mutex);
}
#ifdef PLAY_SHUTDOWN_ANIMATION
int play_shutdown_animation(void)
{
#define TIMEOUT_SEC 10
uint32_t wait_tick;
if (animation_task) {
printf("%s, animation is already inited.\n", __func__);
return -1;
}
xSemaphoreTake(animation_mutex, portMAX_DELAY);
shutdown_anim = 1;
ani_frames = 0;
first_show_done = 0;
ani_stop = 0;
ani_take_vdisbuf = 0;
xSemaphoreGive(animation_mutex);
if (xTaskCreate(animation_thread, "animation", configMINIMAL_STACK_SIZE, NULL,
configMAX_PRIORITIES - 2, &animation_task) != pdPASS) {
printf("%s, create animation task fail.\n", __func__);
animation_task = NULL;
return -1;
}
xSemaphoreTake(animation_mutex, portMAX_DELAY);
if (ani_playing) {
printf("%s, animation is already playing.\n", __func__);
xSemaphoreGive(animation_mutex);
return -1;
}
if (animation_task)
xTaskNotifyGive(animation_task);
xSemaphoreGive(animation_mutex);
//wait for animation_thread exit.
wait_tick = xTaskGetTickCount();
while(xTaskGetTickCount() - wait_tick < configTICK_RATE_HZ * TIMEOUT_SEC) {
if(ani_stop)
break;
vTaskDelay(pdMS_TO_TICKS(100));
}
return 0;
}
#endif
void animation_stop(void)
{
xSemaphoreTake(animation_mutex, portMAX_DELAY);
ani_stop = 1;
xSemaphoreGive(animation_mutex);
}
int get_animation_status(void)
{
return ani_playing;
}

View File

@ -0,0 +1,603 @@
#include "FreeRTOS.h"
#include "board.h"
#include "chip.h"
#include "ark7116.h"
#ifdef VIDEO_DECODER_ARK7116
#define ARK7116_RST_GPIO 7
PanlstaticPara AV1_staticPara[]=
{
//GLOBAL
{0XFD02,0X00},
{0XFD0A,0X48},
{0XFD0B,0X1D},
{0XFD0C,0X33},
{0XFD0D,0X20},
{0XFD0E,0X2C},
{0XFD0F,0X09},
{0XFD10,0X01},
{0XFD11,0XFF},
{0XFD12,0XFF},
{0XFD13,0XFF},
{0XFD14,0X02},
{0XFD15,0X02},
{0XFD16,0X02},
{0XFD1A,0X45},
{0XFD19,0X0A},
//PWM
//DECODER
{0XFE01,0X06},
{0XFE02,0X00},
{0XFE06,0X07},
{0XFE07,0X80},
{0XFE08,0X0E},
{0XFE0C,0X10},
{0XFE0F,0X07},
{0XFE13,0X16},
{0XFE14,0X22},
{0XFE15,0X05},
{0XFE26,0X0E},
{0XFE27,0X00},
{0XFE48,0X87},
{0XFE54,0X00},
{0XFE55,0X01},
{0XFE63,0XC0},
{0XFE83,0XFF},
{0XFED5,0X81},
{0XFED7,0XF7},
{0XFEDC,0X00},
{0XFE44,0X20},
{0XFE45,0X80},
{0XFE43,0X80},
{0XFECB,0X00},
{0XFE56,0X07},
{0XFEC9,0X01},
{0XFE46,0X00},
{0XFE42,0X00},
{0XFE19,0X82},
{0XFE1A,0X50},
{0XFE1B,0X22},
{0XFE1C,0X61},
{0XFE1D,0X70},
//VP
{0XFFB0,0X67},
{0XFFB1,0X0F},
{0XFFB2,0X10},
{0XFFB3,0X10},
{0XFFB4,0X10},
{0XFFB7,0X10},
{0XFFB8,0X10},
{0XFFB9,0X22},
{0XFFBA,0X20},
{0XFFBB,0XFF},
{0XFFBC,0X10},
{0XFFC7,0X31},
{0XFFC8,0X03},
{0XFFC9,0X10},
{0XFFCB,0X80},
{0XFFCC,0X80},
{0XFFCD,0X00},
{0XFFCE,0X10},
{0XFFCF,0X80},
{0XFFD0,0X80},
{0XFFD2,0X4F},
{0XFFD3,0X80},
{0XFFD4,0X80},
{0XFFD7,0X05},
{0XFFD8,0X80},
{0XFFE7,0X50},
{0XFFE8,0X10},
{0XFFE9,0X22},
{0XFFEA,0X20},
{0XFFF0,0X2F},
{0XFFF1,0XE1},
{0XFFF2,0XEE},
{0XFFF3,0XDC},
{0XFFF4,0XFD},
{0XFFF5,0X29},
{0XFFF6,0XF7},
{0XFFF7,0X9E},
{0XFFF8,0X10},
{0XFFF9,0X3D},
{0XFFFA,0X4E},
{0XFFFB,0X81},
{0XFFD5,0X00},
{0XFFD6,0X35},
//TCON
{0XFC00,0X48},
{0XFC01,0X00},
{0XFC02,0X00},
{0XFC09,0X06},
{0XFC0A,0X33},
//SCALE
{0XFC90,0X42},
{0XFC91,0X00},
{0XFC92,0X00},
{0XFC93,0X0C},
{0XFC94,0X00},
{0XFC95,0X00},
{0XFC96,0XE0},
{0XFC97,0X03},
{0XFC98,0X00},
{0XFC99,0X04},
{0XFC9A,0X57},
{0XFC9B,0X03},
{0XFC9C,0X02},
{0XFC9D,0X00},
{0XFC9E,0X06},
{0XFC9F,0X00},
{0XFCA0,0X23},
{0XFCA1,0X00},
{0XFCA2,0X1D},
{0XFCA3,0X04},
{0XFCA4,0X06},
{0XFCA5,0X00},
{0XFCA6,0X08},
{0XFCA7,0X00},
{0XFCA8,0X0A},
{0XFCA9,0X00},
{0XFCAA,0X09},
{0XFCAB,0X01},
{0XFCAC,0X12},
{0XFCAD,0X00},
{0XFCAE,0X00},
{0XFCAF,0X00},
{0XFCB0,0X00},
{0XFCB1,0X00},
{0XFCB2,0X00},
{0XFCB3,0X00},
{0XFCB4,0X00},
{0XFCB5,0X00},
{0XFCB7,0X0E},
{0XFCB8,0X02},
{0XFCBB,0X3B},
{0XFCBC,0X01},
{0XFCBD,0X00},
{0XFCBE,0X00},
{0XFCBF,0X0C},
{0XFCC0,0X00},
{0XFCC1,0X00},
{0XFCC2,0X00},
{0XFCC3,0X04},
{0XFCC4,0X00},
{0XFCC5,0X04},
{0XFCC6,0X60},
{0XFCC7,0X03},
{0XFCC8,0X02},
{0XFCC9,0X00},
{0XFCCA,0X06},
{0XFCCB,0X00},
{0XFCCC,0X28},
{0XFCCD,0X00},
{0XFCCE,0XF8},
{0XFCCF,0X02},
{0XFCD1,0X00},
{0XFCD2,0X15},
{0XFCD3,0X00},
{0XFCD4,0X0A},
{0XFCD5,0X00},
{0XFCD6,0X2F},
{0XFCD7,0X01},
{0XFCD8,0X00},
{0XFCD9,0X07},
{0XFCDA,0X00},
{0XFCDB,0X00},
{0XFCDC,0X00},
{0XFCDD,0X14},
{0XFCDE,0X00},
{0XFCDF,0X00},
{0XFCE0,0X00},
{0XFCE1,0X02},
{0XFCE3,0X01},
{0XFCE4,0X02},
{0XFCE7,0X03},
{0XFCD0,0X0A},
{0XFCE2,0X00},
{0XFCB6,0X00},
{0XFB35,0X00},
{0XFB89,0X00},
//GAMMA
{0XFF00,0X03},
{0XFF01,0X0F},
{0XFF02,0X1E},
{0XFF03,0X2B},
{0XFF04,0X36},
{0XFF05,0X40},
{0XFF06,0X4B},
{0XFF07,0X55},
{0XFF08,0X5F},
{0XFF09,0X69},
{0XFF0A,0X73},
{0XFF0B,0X7D},
{0XFF0C,0X85},
{0XFF0D,0X8E},
{0XFF0E,0X96},
{0XFF0F,0X9F},
{0XFF10,0XA7},
{0XFF11,0XAE},
{0XFF12,0XB6},
{0XFF13,0XBD},
{0XFF14,0XC4},
{0XFF15,0XCA},
{0XFF16,0XD1},
{0XFF17,0XD7},
{0XFF18,0XDD},
{0XFF19,0XE3},
{0XFF1A,0XE8},
{0XFF1B,0XED},
{0XFF1C,0XF1},
{0XFF1D,0XF5},
{0XFF1E,0XF8},
{0XFF1F,0XFC},
{0XFF20,0X0F},
{0XFF21,0X1E},
{0XFF22,0X2B},
{0XFF23,0X36},
{0XFF24,0X40},
{0XFF25,0X4B},
{0XFF26,0X55},
{0XFF27,0X5F},
{0XFF28,0X69},
{0XFF29,0X73},
{0XFF2A,0X7D},
{0XFF2B,0X85},
{0XFF2C,0X8E},
{0XFF2D,0X96},
{0XFF2E,0X9F},
{0XFF2F,0XA7},
{0XFF30,0XAE},
{0XFF31,0XB6},
{0XFF32,0XBD},
{0XFF33,0XC4},
{0XFF34,0XCA},
{0XFF35,0XD1},
{0XFF36,0XD7},
{0XFF37,0XDD},
{0XFF38,0XE3},
{0XFF39,0XE8},
{0XFF3A,0XED},
{0XFF3B,0XF1},
{0XFF3C,0XF5},
{0XFF3D,0XF8},
{0XFF3E,0XFC},
{0XFF3F,0X0F},
{0XFF40,0X1E},
{0XFF41,0X2B},
{0XFF42,0X36},
{0XFF43,0X40},
{0XFF44,0X4B},
{0XFF45,0X55},
{0XFF46,0X5F},
{0XFF47,0X69},
{0XFF48,0X73},
{0XFF49,0X7D},
{0XFF4A,0X85},
{0XFF4B,0X8E},
{0XFF4C,0X96},
{0XFF4D,0X9F},
{0XFF4E,0XA7},
{0XFF4F,0XAE},
{0XFF50,0XB6},
{0XFF51,0XBD},
{0XFF52,0XC4},
{0XFF53,0XCA},
{0XFF54,0XD1},
{0XFF55,0XD7},
{0XFF56,0XDD},
{0XFF57,0XE3},
{0XFF58,0XE8},
{0XFF59,0XED},
{0XFF5A,0XF1},
{0XFF5B,0XF5},
{0XFF5C,0XF8},
{0XFF5D,0XFC},
{0XFF5E,0XFF},
{0XFF5F,0XFF},
{0XFF60,0XFF},
};
/*点屏 PAD MUX 参数*/
PanlstaticPara AMT_PadMuxStaticPara[]=
{
//PAD MUX
{0XFD30,0X22},
{0XFD32,0X11},
{0XFD33,0X11},
{0XFD34,0X55},
{0XFD35,0X55},
{0XFD36,0X55},
{0XFD37,0X55},
{0XFD38,0X55},
{0XFD39,0X55},
{0XFD3A,0X11},
{0XFD3B,0X11},
{0XFD3C,0X44},
{0XFD3D,0X44},
{0XFD3E,0X44},
{0XFD3F,0X44},
{0XFD40,0X44},
{0XFD41,0X44},
{0XFD44,0X01},
{0XFD45,0X00},
{0XFD46,0X00},
{0XFD47,0X00},
{0XFD48,0X00},
{0XFD49,0X00},
{0XFD4A,0X00},
{0XFD4B,0X00},
{0XFD50,0X0B},
{0XFD51,0X55},
{0XFD52,0X55},
{0XFD53,0X57},
{0XFD54,0X57},
{0XFD55,0X55},
{0XFD56,0X55},
{0XFD57,0X55},
{0XFD58,0X55},
{0XFD59,0X5D},
{0XFD5A,0X55},
};
/*-----------------------------------------------------------*/
static int ark7116_i2c_write (struct i2c_adapter *adap, UINT16 RegAddr, unsigned int data)
{
struct i2c_msg msg;
int ret = -1;
u8 retries = 0;
u8 buf[2];
UINT8 ucDeviceAddr;
UINT8 uctmpDeviceAddr;
UINT8 ucSubAddr;
uctmpDeviceAddr = (unsigned char)((RegAddr>>8)&0XFF);
ucSubAddr = (UINT8)(RegAddr&0XFF);
switch(uctmpDeviceAddr)
{
case 0XF9:
case 0XFD:
ucDeviceAddr= 0XB0;
break;
case 0XFA:
ucDeviceAddr= 0XBE;
break;
case 0XFB:
ucDeviceAddr= 0XB6;
break;
case 0XFC:
ucDeviceAddr= 0XB8;
break;
case 0XFE:
ucDeviceAddr= 0XB2;
break;
case 0XFF:
ucDeviceAddr= 0XB4;
break;
case 0X00:
ucDeviceAddr = 0XBE;
break;
default:
ucDeviceAddr= 0XB0;
break;
}
buf[0] = (ucSubAddr);
buf[1] = (data & 0xFF);
msg.flags = !I2C_M_RD;
msg.addr = (ucDeviceAddr>>1);
msg.len = sizeof(buf);
msg.buf = buf;
//printf("msg.addr is %x\n", msg.addr);
//printf("msg.ucSubAddr is %x\n",buf[0]);
//printf("msg.data is %x\n", buf[1]);
while(retries < 10)
{
//printf("retries is %x\n", retries);
ret = i2c_transfer(adap, &msg, 1);
//printf("ret is %x\n", ret);
if (ret == 1)
break;
retries++;
vTaskDelay (20);
}
if (retries >= 10)
{
printf("%s timeout11\n", __FUNCTION__);
return -1;
}
return 0;
}
static void ARK7116_reset(void)
{
gpio_direction_output(ARK7116_RST_GPIO, 0);
vTaskDelay(10);
gpio_direction_output(ARK7116_RST_GPIO, 1);
vTaskDelay(10);
gpio_direction_output(ARK7116_RST_GPIO, 0);
vTaskDelay(10);
}
int ConfigSlaveMode(struct i2c_adapter *adap)
{
unsigned char AddrBuff[6] = {0xa1,0xa2,0xa3,0xa4,0xa5,0xa6};
unsigned char DataBuff[6] = {0x00,0x00,0x00,0x00,0x00,0x00};
unsigned char i;
DataBuff[0] = 0X55;
DataBuff[1] = 0xAA;
DataBuff[2] = 0X03;
DataBuff[3] = 0X50; //slave mode
DataBuff[4] = 0; // crc val
DataBuff[5] = DataBuff[2]^DataBuff[3]^DataBuff[4];
printf("ConfigSlaveMode\n");
ark7116_i2c_write(adap,MCU_CFG_ADDR,0X40);
ark7116_i2c_write(adap,RSTN,0X00);
ark7116_i2c_write(adap,RSTN,0X5A);
if(ark7116_i2c_write(adap,BUS_STATUS_ADDR, 0x00) < 0) //I2c Write Start
return -1;
for(i =0;i < 6;i++)
{
if(ark7116_i2c_write(adap,AddrBuff[i], DataBuff[i]) < 0)
return -1;
}
if(ark7116_i2c_write(adap,BUS_STATUS_ADDR, 0x11) < 0) //I2c Write End
return -1;
vTaskDelay (200);
return 0;
}
int AMT_WriteStaticPara(struct i2c_adapter *adap,PanlstaticPara * dataPt,UINT16 num)
{
struct i2c_msg msg;
int ret = -1;
u8 retries = 0;
u8 buf[2];
u8 ucDeviceAddr;
u8 uctmpDeviceAddr;
u8 ucSubAddr;
u8 ucRegVal;
while(num--)
{
uctmpDeviceAddr = (unsigned char)(((*dataPt).addr>>8)&0XFF);
ucSubAddr = (unsigned char)(((*dataPt).addr)&0XFF);
ucRegVal = (*dataPt).dat;
switch(uctmpDeviceAddr)
{
case 0XF9:
case 0XFD:
ucDeviceAddr= 0XB0;
break;
case 0XFA:
ucDeviceAddr= 0XBE;
break;
case 0XFB:
ucDeviceAddr= 0XB6;
break;
case 0XFC:
ucDeviceAddr= 0XB8;
break;
case 0XFE:
ucDeviceAddr= 0XB2;
break;
case 0XFF:
ucDeviceAddr= 0XB4;
break;
case 0X00:
ucDeviceAddr = 0XBE;
break;
default:
ucDeviceAddr= 0XB0;
break;
}
buf[0] = (ucSubAddr);
buf[1] = (ucRegVal & 0xFF);
msg.flags = !I2C_M_RD;
msg.addr = (ucDeviceAddr>>1);
msg.len = sizeof(buf);
msg.buf = buf;
while(retries < 10)
{
ret = i2c_transfer(adap, &msg, 1);
if (ret == 1)
break;
retries++;
vTaskDelay (20);
}
if (retries >= 10)
{
return -1;
}
dataPt++;
}
return 0;
}
void ConfigStaticPara(struct i2c_adapter *adap)
{
//CurretSource = CurretSource;
AMT_WriteStaticPara(adap,AV1_staticPara,sizeof(AV1_staticPara)/sizeof(AV1_staticPara[0]));
}
void ConfigPadMuxPara(struct i2c_adapter *adap)
{
AMT_WriteStaticPara(adap,AMT_PadMuxStaticPara,
sizeof(AMT_PadMuxStaticPara)/sizeof(AMT_PadMuxStaticPara[0]));
}
void InitGlobalPara(struct i2c_adapter *adap) //165
{
printf("InitGlobalPara\n");
ark7116_i2c_write(adap,ENH_PLL,0X20);
ConfigStaticPara(adap);
ConfigPadMuxPara(adap);
ark7116_i2c_write(adap,0xFD0C,0X33);
ark7116_i2c_write(adap,0xFD14,0X02);
//黑屏
ark7116_i2c_write(adap,0xFFCE,0X00);
ark7116_i2c_write(adap,0xFFCF,0X80);
ark7116_i2c_write(adap,0xFFD0,0X80);
ark7116_i2c_write(adap,ENH_PLL,0X2C);
#if 1 //20190117 增加每次上电初始化完之后复位decoder
//复位Decoder
vTaskDelay (200);
ark7116_i2c_write(adap,DECODER_RST,0X03);
vTaskDelay (10);
ark7116_i2c_write(adap,DECODER_RST,0X02);
#endif
}
int ark7116_init(void)
{
struct i2c_adapter *adap = NULL;
if (!(adap = i2c_open("i2c1"))) {
printf("open i2c1 fail.\n");
return -1;
}
ARK7116_reset();
if(ConfigSlaveMode(adap) < 0)
return -1;
InitGlobalPara(adap);
return 0;
}
#endif

View File

@ -0,0 +1,190 @@
#include "FreeRTOS.h"
#include "board.h"
#include "sysinfo.h"
#include "chip.h"
static const char* abort_status[][2]=
{
// IFSR status , DFSR status
{"Unknown(reserved status)", "Unknown(reserved status)" },//0
{"Unknown(reserved status)", "Alignment Fault" },//1
{"Debug Event", "Debug Event" },//2
{"Access flag - section", "Access flag - section" },//3
{"Unknown(reserved status)", "Instruction cache maintenance" },//4
{"Translation fault - section", "Translation fault - section" },//5
{"Access flag - Page", "Access flag - Page" },//6
{"Translation fault -Page", "Translation fault -Page" },//7
{"Synchronous external abort", "Synchronous external abort, nontranslation" },//8
{"Domain fault - Section", "Domain fault - Section" },//9
{"Unknown(reserved status)", "Unknown(reserved status)" },//10
{"Domain fault - Page", "Domain fault - Page" },//11
{"Synchronous external abort - L1 Translation", "Synchronous external abort - L1 Translation" },//12
{"Permission fault - Section", "Permission fault - Section" },//13
{"Synchronous external abort - L2 Translation", "Synchronous external abort - L2 Translation" },//14
{"Permission fault - Page", "Permission fault - Page" },//15
{"Unknown(reserved status)", "Unknown(reserved status)" },//16
{"Unknown(reserved status)", "Unknown(reserved status)" },//17
{"Unknown(reserved status)", "Unknown(reserved status)" },//18
{"Unknown(reserved status)", "Unknown(reserved status)" },//19
{"Unknown(reserved status)", "Unknown(reserved status)" },//20
{"Unknown(reserved status)", "Unknown(reserved status)" },//21
{"Unknown(reserved status)", "Asynchronous external abort"}
};
void LowLevelInit( void )
{
}
void Abort_C_Handler( void)
{
uint32_t v1,v2, dfsr;
v1= 0;
v2= 0;
asm("mrc p15, 0, %0, c5, c0, 0" : : "r"(v1));
asm("mrc p15, 0, %0, c6, c0, 0" : : "r"(v2));
dfsr = ((v1 >> 4) & 0x0F);
printf("\n\r######################################################################\n\r");
printf("Data Abort occured in %x domain\n\r", (unsigned int)dfsr);
dfsr = (((v1 & 0x400) >> 6) | (v1 & 0x0F));
printf("Data abort fault reason is: %s\n\r", (char*)abort_status[dfsr][1]);
printf("Data fault occured at Address = 0x%08x\n\n\r",(unsigned int)v2);
printf("-[Info]-Data fault status register value = 0x%x\n\r",(unsigned int)v1);
while(1);
}
void Prefetch_C_Handler( void)
{
uint32_t v1,v2, ifsr;
v1= 0;
v2= 0;
asm("mrc p15, 0, %0, c5, c0, 1" : : "r"(v1));
asm("mrc p15, 0, %0, c6, c0, 2" : : "r"(v2));
ifsr = (((v1 & 0x400) >> 6) | (v1 & 0x0F));
printf("\n\r######################################################################\n\r");
printf("Instruction prefetch abort reason is: %s\n\r", (char*)abort_status[ifsr][0]);
printf("Instruction prefetch Fault occured at Address = 0x%08x\n\n\r",(unsigned int)v2);
printf("-[INFO]- Prefetch Fault status register value by = 0x%x\n\r",(unsigned int)v1);
while(1);
}
void Undefined_C_Handler( void)
{
printf("Undefined abort \n\r");
while(1);
}
typedef enum {
VBUF_STATUS_FREE = 0,
VBUF_STATUS_USED,
VBUF_STATUS_RENDERED,
} VIDEO_BUFFER_STATUS;
typedef struct {
uint32_t addr;
int status;
}VideoBufInfo;
static SemaphoreHandle_t vdisbuf_mutex = NULL;
static VideoBufInfo vdisbufs[VIDEO_DISPLAY_BUF_NUM] = {0};
void VideoDisplayBufInit(void)
{
int i;
vdisbuf_mutex = xSemaphoreCreateRecursiveMutex();
for (i = 0; i < VIDEO_DISPLAY_BUF_NUM; i++) {
vdisbufs[i].addr = (uint32_t)pvPortMalloc(VIDEO_DISPLAY_WIDTH * VIDEO_DISPLAY_HEIGHT * 2);
vdisbufs[i].status = VBUF_STATUS_FREE;
}
}
int xVideoDisplayBufTake(uint32_t xTicksToWait)
{
return xSemaphoreTakeRecursive(vdisbuf_mutex, xTicksToWait);
}
void vVideoDisplayBufGive(void)
{
xSemaphoreGiveRecursive(vdisbuf_mutex);
}
uint32_t ulVideoDisplayBufGet(void)
{
uint32_t bufaddr = 0;
int i;
xSemaphoreTakeRecursive(vdisbuf_mutex, portMAX_DELAY);
for (i = 0; i < VIDEO_DISPLAY_BUF_NUM; i++) {
if (vdisbufs[i].status == VBUF_STATUS_FREE) {
bufaddr = vdisbufs[i].addr;
vdisbufs[i].status = VBUF_STATUS_USED;
break;
}
}
xSemaphoreGiveRecursive(vdisbuf_mutex);
configASSERT(bufaddr != 0);
return bufaddr;
}
uint32_t ulVideoDisplayBufGetSize(void)
{
return VIDEO_DISPLAY_WIDTH * VIDEO_DISPLAY_HEIGHT * 2;
}
void vVideoDisplayBufRender(uint32_t buf_addr)
{
int i, j;
xSemaphoreTakeRecursive(vdisbuf_mutex, portMAX_DELAY);
for (i = 0; i < VIDEO_DISPLAY_BUF_NUM; i++) {
if (vdisbufs[i].addr == buf_addr) {
for (j = 0; j < VIDEO_DISPLAY_BUF_NUM; j++) {
if (vdisbufs[j].status == VBUF_STATUS_RENDERED)
vdisbufs[j].status = VBUF_STATUS_FREE;
}
vdisbufs[i].status = VBUF_STATUS_RENDERED;
break;
}
}
xSemaphoreGiveRecursive(vdisbuf_mutex);
}
void vVideoDisplayBufFree(uint32_t buf_addr)
{
int i;
xSemaphoreTakeRecursive(vdisbuf_mutex, portMAX_DELAY);
for (i = 0; i < VIDEO_DISPLAY_BUF_NUM; i++) {
if (vdisbufs[i].addr == buf_addr) {
vdisbufs[i].status = VBUF_STATUS_FREE;
break;
}
}
xSemaphoreGiveRecursive(vdisbuf_mutex);
}
unsigned int ulVideoDisplayGetBufferAddr(int index)
{
configASSERT(index < VIDEO_DISPLAY_BUF_NUM);
return vdisbufs[index].addr;
}

View File

@ -0,0 +1,106 @@
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "chip.h"
#include "board.h"
static TaskHandle_t carback_task = NULL;
//static SemaphoreHandle_t carback_mutex;
static int carback_status = 0;
void notify_enter_carback(void)
{
if (carback_task)
xTaskNotify(carback_task, 1, eSetValueWithOverwrite);
}
void notify_exit_carback(void)
{
if (carback_task)
xTaskNotify(carback_task, 0, eSetValueWithOverwrite);
}
int get_carback_status(void)
{
int status;
portENTER_CRITICAL();
status = carback_status;
portEXIT_CRITICAL();
return status;
}
static void carback_thread(void *param)
{
uint32_t ulNotifiedValue;
//carback_mutex = xSemaphoreCreateMutex();
#if defined(VIDEO_DECODER_RN6752)
rn6752_init();
#elif defined(VIDEO_DECODER_ARK7116)
ark7116_init();
#endif
for (;;) {
xTaskNotifyWait( 0x00, /* Don't clear any notification bits on entry. */
0xffffffff, /* Reset the notification value to 0 on exit. */
&ulNotifiedValue, /* Notified value pass out in ulNotifiedValue. */
portMAX_DELAY);
if (ulNotifiedValue && !carback_status) {
printf("enter carback.\n");
ItuConfigPara para = {0};
para.itu601 = 1;
para.out_format = ITU_YUV420;
para.yuv_type = ITU_Y_UV;
para.in_width = VIN_WIDTH;
para.in_height = VIN_HEIGHT;
para.in_height = VIN_HEIGHT - 2;
#ifdef REVERSE_TRACK
para.out_width = 704;
para.out_height = 440;
#else
para.out_width = LCD_WIDTH;
para.out_height = LCD_HEIGHT;
#endif
itu_config(&para);
itu_start();
carback_status = 1;
} else if (!ulNotifiedValue && carback_status) {
printf("exit carback.\n");
itu_stop();
carback_status = 0;
}
}
}
static void carback_test_thread(void *param)
{
for (;;) {
vTaskDelay(pdMS_TO_TICKS(30000));
notify_enter_carback();
vTaskDelay(pdMS_TO_TICKS(10000));
notify_exit_carback();
}
}
int carback_init(void)
{
/* Create a task to play animation */
if (xTaskCreate(carback_thread, "carback", configMINIMAL_STACK_SIZE, NULL,
configMAX_PRIORITIES - 3, &carback_task) != pdPASS) {
printf("create carback task fail.\n");
carback_task = NULL;
return -1;
}
xTaskCreate(carback_test_thread, "ctest", configMINIMAL_STACK_SIZE, NULL,
configMAX_PRIORITIES / 2, NULL);
return 0;
}

View File

@ -0,0 +1,82 @@
#include <stdio.h>
#include <stdlib.h>
static const unsigned int crc32_table[] =
{
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
};
unsigned int
xcrc32(const unsigned char *buf, int len, unsigned int init)
{
unsigned int crc = init;
while (len--)
{
crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *buf) & 255];
buf++;
}
return crc;
}

View File

@ -0,0 +1,7 @@
#ifndef _CRC32_H
#define _CRC32_H
unsigned int
xcrc32(const unsigned char *buf, int len, unsigned int init);
#endif

View File

@ -0,0 +1,723 @@
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include "FreeRTOS.h"
#include "chip.h"
#include "board.h"
#include "soc-dai.h"
#if AUDIO_CODEC_ADC_IC == AUDIO_CODEC_ADC_ES7243E
/* Slave device address */
#define ES7243E_SLAVE_ADDR 0x10
typedef enum adc_data_select {
ADC_OUTPUT_L_R,
ADC_OUTPUT_L_L,
ADC_OUTPUT_R_R,
ADC_OUTPUT_R_L
} adc_data_sel;
typedef enum adc_polarity_invert {
ADC_INV_NORMAL,
ADC_R_INV,
ADC_L_INV,
ADC_LR_INV
} adc_pol_inv;
struct _coeff_div {
u32 mclk; //mclk frequency
u32 sr_rate; //sample rate
u8 osr; //adc over sample rate
u8 prediv_premulti; //adcclk and dacclk divider
u8 cf_dsp_div; //adclrck divider and daclrck divider
u8 scale;
u8 lrckdiv_h;
u8 lrckdiv_l;
u8 bclkdiv; //sclk divider
};
typedef struct _adc_private {
adc_data_sel adc_data_sel;
adc_pol_inv adc_inv;
} adc_private;
typedef struct es7243e_private_data {
struct i2c_adapter *adap;
unsigned short slave_addr;
int rates;
int channels;
int bits;
int master;
int mclk;
int fmt;
int mute;
adc_private adc_priv;
} es7243e_client;
static int es7243e_mute(int mute);
static es7243e_client *g_es7243e_client = NULL;
/**
* es7243e_i2c_read - read data from a register of the i2c slave device.
*
* @adap: i2c device.
* @reg: the register to read from.
* @buf: raw write data buffer.
* @len: length of the buffer to write
*/
static int es7243e_i2c_read(es7243e_client *client, uint8_t reg)
{
struct i2c_msg msgs[2];
uint8_t wbuf[2];
uint8_t rbuf = 0;
int ret;
int i;
wbuf[0] = reg;
msgs[0].flags = 0;
msgs[0].addr = client->slave_addr;
msgs[0].len = 1;
msgs[0].buf = wbuf;
msgs[1].flags = I2C_M_RD;
msgs[1].addr = client->slave_addr;
msgs[1].len = 1;
msgs[1].buf = &rbuf;
for(i=0; i<5; i++)
{
ret = i2c_transfer(client->adap, msgs, 2);
if(ret == 2)
break;
}
return (ret==ARRAY_SIZE(msgs)) ? rbuf : -EIO;
}
/**
* es7243e_i2c_write - write data to a register of the i2c slave device.
*
* @adap: i2c device.
* @reg: the register to write to.
* @buf: raw data buffer to write.
* @len: length of the buffer to write
*/
static int es7243e_i2c_write(es7243e_client *client, uint8_t reg, uint8_t val)
{
struct i2c_msg msg;
uint8_t addr_buf[2];
int ret;
int i;
addr_buf[0] = reg;
addr_buf[1] = val;
msg.flags = 0;
msg.addr = client->slave_addr;
msg.buf = addr_buf;
msg.len = 2;
for(i=0; i<5; i++)
{
ret = i2c_transfer(client->adap, &msg, 1);
if(ret == 1)
break;
}
//printf("reg[0x%x], val:0x%x, read:0x%x\n", reg, val, es7243e_i2c_read(client, reg));
return (ret != 1 ? -EIO : 0);
}
int es7243e_i2c_write_bits(es7243e_client *client, u8 reg, u8 mask, u8 offset, u8 val)
{
int value = es7243e_i2c_read(client, reg);
if(value < 0)
{
printf("%s read failed, reg:0x%x, val:0x%x\n", __func__, reg, value);
return -1;
}
value &= ~(mask << offset);
value |= (val << offset);
if(es7243e_i2c_write(client, reg, value&0xFF))
{
printf("%s write failed, reg:0x%x, val:0x%x\n", __func__, reg, value);
return -1;
}
return 0;
}
/* codec mclk clock divider coefficients */
static const struct _coeff_div coeff_div[] = {
//mclk lrck, osr, pre, div ,scale, lrckdiv_h, lrckdiv_l, bclkdiv
/* 24.576MHZ */
{24576000, 8000 , 0x20, 0x50, 0x00, 0x00, 0x0b, 0xff, 0x2f},
{24576000, 12000, 0x20, 0x30, 0x00, 0x00, 0x07, 0xff, 0x1f},
{24576000, 16000, 0x20, 0x20, 0x00, 0x00, 0x05, 0xff, 0x17},
{24576000, 24000, 0x20, 0x10, 0x00, 0x00, 0x03, 0xff, 0x0f},
{24576000, 32000, 0x20, 0x21, 0x00, 0x00, 0x02, 0xff, 0x0b},
{24576000, 48000, 0x20, 0x00, 0x00, 0x00, 0x01, 0xff, 0x07},
/* 12.288MHZ */
{12288000, 8000 , 0x20, 0x20, 0x00, 0x00, 0x05, 0xff, 0x17},
{12288000, 12000, 0x20, 0x10, 0x00, 0x00, 0x03, 0xff, 0x0f},
{12288000, 16000, 0x20, 0x21, 0x00, 0x00, 0x02, 0xff, 0x0b},
{12288000, 24000, 0x20, 0x00, 0x00, 0x00, 0x01, 0xff, 0x07},
{12288000, 32000, 0x20, 0x22, 0x00, 0x00, 0x01, 0x7f, 0x05},
{12288000, 48000, 0x20, 0x01, 0x00, 0x00, 0x00, 0xff, 0x03},
/* 6.144MHZ */
{6144000 , 8000 , 0x20, 0x21, 0x00, 0x00, 0x02, 0xff, 0x0b},
{6144000 , 12000, 0x20, 0x00, 0x00, 0x00, 0x01, 0xff, 0x07},
{6144000 , 16000, 0x20, 0x22, 0x00, 0x00, 0x01, 0x7f, 0x05},
{6144000 , 24000, 0x20, 0x01, 0x00, 0x00, 0x00, 0xff, 0x03},
{6144000 , 32000, 0x20, 0x23, 0x00, 0x00, 0x00, 0xbf, 0x02},
{6144000 , 48000, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x01},
/* 3.072MHZ */
{3072000 , 8000 , 0x20, 0x22, 0x00, 0x00, 0x01, 0x7f, 0x05},
{3072000 , 12000, 0x20, 0x01, 0x00, 0x00, 0x00, 0xff, 0x03},
{3072000 , 16000, 0x20, 0x23, 0x00, 0x00, 0x00, 0xbf, 0x02},
{3072000 , 24000, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x01},
{3072000 , 32000, 0x10, 0x03, 0x20, 0x04, 0x00, 0x5f, 0x02},
{3072000 , 48000, 0x20, 0x03, 0x00, 0x00, 0x00, 0x3f, 0x00},
/* 1.536MHZ */
{1536000 , 8000 , 0x20, 0x23, 0x00, 0x00, 0x00, 0xbf, 0x02},
{1536000 , 12000, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x01},
{1536000 , 16000, 0x10, 0x03, 0x20, 0x04, 0x00, 0x5f, 0x00},
{1536000 , 24000, 0x20, 0x03, 0x00, 0x00, 0x00, 0x3f, 0x00},
/* 32.768MHZ */
{32768000, 8000 , 0x20, 0x70, 0x00, 0x00, 0x0f, 0xff, 0x3f},
{32768000, 16000, 0x20, 0x30, 0x00, 0x00, 0x07, 0xff, 0x1f},
{32768000, 32000, 0x20, 0x10, 0x00, 0x00, 0x03, 0xff, 0x0f},
/* 16.384MHZ */
{16384000, 8000 , 0x20, 0x30, 0x00, 0x00, 0x07, 0xff, 0x1f},
{16384000, 16000, 0x20, 0x10, 0x00, 0x00, 0x03, 0xff, 0x0f},
{16384000, 32000, 0x20, 0x00, 0x00, 0x00, 0x01, 0xff, 0x07},
/* 8.192MHZ */
{8192000 , 8000 , 0x20, 0x10, 0x00, 0x00, 0x03, 0xff, 0x0f},
{8192000 , 16000, 0x20, 0x00, 0x00, 0x00, 0x01, 0xff, 0x07},
{8192000 , 32000, 0x20, 0x01, 0x00, 0x00, 0x00, 0xff, 0x03},
/* 4.096MHZ */
{4096000 , 8000 , 0x20, 0x00, 0x00, 0x00, 0x01, 0xff, 0x07},
{4096000 , 16000, 0x20, 0x01, 0x00, 0x00, 0x00, 0xff, 0x03},
{4096000 , 32000, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x01},
/* 2.048MHZ */
{2048000 , 8000 , 0x20, 0x01, 0x00, 0x00, 0x00, 0xff, 0x03},
{2048000 , 16000, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x01},
{2048000 , 32000, 0x20, 0x03, 0x00, 0x00, 0x00, 0x3f, 0x00},
/* 1.024MHZ */
{1024000 , 8000 , 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x01},
{1024000 , 16000, 0x20, 0x03, 0x00, 0x00, 0x00, 0x3f, 0x00},
/* 22.5792MHz */
{22579200, 11025, 0x20, 0x30, 0x00, 0x00, 0x07, 0xff, 0x1f},
{22579200, 22050, 0x20, 0x10, 0x00, 0x00, 0x03, 0xff, 0x0f},
{22579200, 44100, 0x20, 0x00, 0x00, 0x00, 0x01, 0xff, 0x07},
/* 11.2896MHz */
{11289600, 11025, 0x20, 0x10, 0x00, 0x00, 0x03, 0xff, 0x0f},
{11289600, 22050, 0x20, 0x00, 0x00, 0x00, 0x01, 0xff, 0x07},
{11289600, 44100, 0x20, 0x01, 0x00, 0x00, 0x00, 0xff, 0x03},
/* 5.6448MHz */
{56448000, 11025, 0x20, 0x00, 0x00, 0x00, 0x01, 0xff, 0x07},
{56448000, 22050, 0x20, 0x01, 0x00, 0x00, 0x00, 0xff, 0x03},
{56448000, 44100, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x01},
/* 2.8224MHz */
{28224000, 11025, 0x20, 0x01, 0x00, 0x00, 0x00, 0xff, 0x03},
{28224000, 22050, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x01},
{28224000, 44100, 0x20, 0x03, 0x00, 0x00, 0x00, 0x3f, 0x00},
/* 1.4112MHz */
{14112000, 11025, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x01},
{14112000, 22050, 0x20, 0x03, 0x00, 0x00, 0x00, 0x3f, 0x00},
};
static inline int get_coeff(int mclk, int rate)
{
int i;
for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
if (coeff_div[i].sr_rate == rate && coeff_div[i].mclk == mclk) {
printf("%s() get_coeff find index:%d\n", __func__, i);
return i;
}
}
printf("%s() get_coeff not find\n", __func__);
return -EINVAL;
}
static int es7243e_pcm_hw_params(es7243e_client *client)
{
u8 regv;
int coeff;
#if 1
coeff = get_coeff(client->mclk, client->rates);
if(coeff < 0)
{
printf("Unable to configure sample rate %dHz with %dHz MCLK", client->rates, client->mclk);
return coeff;
}
/*
* set clock parameters
*/
//printf("%s():coeff = %d\n",__func__, coeff);
if(coeff >= 0)
{
es7243e_i2c_write(client, 0x03, coeff_div[coeff].osr);
es7243e_i2c_write(client, 0x04, coeff_div[coeff].prediv_premulti);
es7243e_i2c_write(client, 0x05, coeff_div[coeff].cf_dsp_div);
es7243e_i2c_write_bits(client, 0x0D, 0x07, 0, coeff_div[coeff].scale);
es7243e_i2c_write(client, 0x03, coeff_div[coeff].osr);
es7243e_i2c_write_bits(client, 0x07, 0x0F, 0, coeff_div[coeff].lrckdiv_h & 0x0f);
es7243e_i2c_write(client, 0x06, coeff_div[coeff].bclkdiv);
//es7243e_i2c_write(client, 0x06, 0x07);//BCLK:1.536
}
#endif
#if 1//add-
regv = es7243e_i2c_read(client, 0x0B);
regv &= 0xe3;
switch (client->bits)
{
case 16:
regv |= 0x0c;
break;
case 20:
regv |= 0x04;
break;
case 24:
break;
case 32:
regv |= 0x10;
break;
default:
regv |= 0x0c;
break;
}
es7243e_i2c_write(client, 0x0B, regv);
/*
* unmute SDP for MT8516 and MT8167 platform
*/
msleep(500);
es7243e_mute(1);
#endif
return 0;
}
static int es7243e_set_bias_level(es7243e_client *client, enum snd_soc_bias_level level)
{
u8 regv;
switch (level) {
case SND_SOC_BIAS_ON:
printf("%s on\n", __func__);
break;
case SND_SOC_BIAS_PREPARE:
printf("%s prepare\n", __func__);
break;
case SND_SOC_BIAS_STANDBY:
printf("%s standby\n", __func__);
/*
* enable clock
*/
regv = es7243e_i2c_read(client, 0x01);
regv |= 0x0A;
es7243e_i2c_write(client, 0x01, regv);
es7243e_i2c_write(client, 0x16, 0x00); //power up analog
/*
* enable mic input 1
*/
regv = es7243e_i2c_read(client, 0x20);
regv |= 0x10;
es7243e_i2c_write(client, 0x20, regv);
/*
* enable mic input 2
*/
regv = es7243e_i2c_read(client, 0x21);
regv |= 0x10;
es7243e_i2c_write(client, 0x21, regv);
msleep(100);
es7243e_mute(0);
break;
case SND_SOC_BIAS_OFF:
printf("%s off\n", __func__);
es7243e_mute(1);
/*
* disable mic input 1
*/
regv = es7243e_i2c_read(client, 0x20);
regv &= 0xef;
es7243e_i2c_write(client, 0x20, regv);
/*
* disable mic input 2
*/
regv = es7243e_i2c_read(client, 0x21);
regv &= 0xef;
es7243e_i2c_write(client, 0x21, regv);
es7243e_i2c_write(client, 0x16, 0xff); //power down analog
/*
* disable clock
*/
regv = es7243e_i2c_read(client, 0x01);
regv &= 0xf5;
es7243e_i2c_write(client, 0x01, regv);
break;
}
return 0;
}
static int es7243e_init_regs(es7243e_client *client)
{
if(client->master)
{
//ES7243e master mode
es7243e_i2c_write(client, 0x01, 0x3A);
es7243e_i2c_write(client, 0x00, 0x80);
es7243e_i2c_write(client, 0x04, 0x02);
es7243e_i2c_write(client, 0x04, 0x01);
es7243e_i2c_write(client, 0xF9, 0x01);
es7243e_i2c_write(client, 0x00, 0x1E);
es7243e_i2c_write(client, 0x01, 0x00);
es7243e_i2c_write(client, 0x02, 0x00); //default:0x00 (0x01 :BCLK invert)
es7243e_i2c_write(client, 0x03, 0x20);
//es7243e_i2c_write(client, 0x0D, 0x40);//default:0x00 (settable:0x40 0x80)
es7243e_i2c_write_bits(client, 0x0D, 0x0f, 4, (client->adc_priv.adc_data_sel<<2) | client->adc_priv.adc_inv);
es7243e_i2c_write(client, 0xF9, 0x00);
es7243e_i2c_write(client, 0x04, 0x02);
es7243e_i2c_write(client, 0x04, 0x01);
es7243e_i2c_write(client, 0x05, 0x00);
//es7243e_i2c_write(client, 0x06, 0x07);//test: set BCLK 1.536M
es7243e_i2c_write(client, 0x07, 0x00);//default:0x00 0x02
es7243e_i2c_write(client, 0x08, 0xFF);//default:0xFF
es7243e_i2c_write(client, 0x09, 0xC5);
es7243e_i2c_write(client, 0x0A, 0x81);
es7243e_i2c_write(client, 0x0B, 0x0C);//default:0x00(24bit) 0x0c(16 bit) add:0x0d 20210722
es7243e_i2c_write(client, 0x0E, 0xBF);
es7243e_i2c_write(client, 0x0F, 0x80);
es7243e_i2c_write(client, 0x14, 0x0C);
es7243e_i2c_write(client, 0x15, 0x0C);
es7243e_i2c_write(client, 0x17, 0x02);
es7243e_i2c_write(client, 0x18, 0x26);
es7243e_i2c_write(client, 0x19, 0x77);
es7243e_i2c_write(client, 0x1A, 0xF4);
es7243e_i2c_write(client, 0x1B, 0x66);
es7243e_i2c_write(client, 0x1C, 0x44);
es7243e_i2c_write(client, 0x1E, 0x00);
es7243e_i2c_write(client, 0x1F, 0x0C);
es7243e_i2c_write(client, 0x20, 0x1c);//default:0x19 Analog gain(min:0x01 max:0x1e)
es7243e_i2c_write(client, 0x21, 0x1c);//default:0x19 Analog gain(min:0x01 max:0x1e)
es7243e_i2c_write(client, 0x00, 0xC0);
es7243e_i2c_write(client, 0x01, 0x3A);
es7243e_i2c_write(client, 0x16, 0x3F);
es7243e_i2c_write(client, 0x16, 0x00);
es7243e_i2c_write(client, 0x13, 0x3f);//add
es7243e_i2c_write(client, 0x0f, 0x40);//add
}
else
{
//ES7243e slave mode
es7243e_i2c_write(client, 0x01, 0x3A);
es7243e_i2c_write(client, 0x00, 0x80);
es7243e_i2c_write(client, 0x04, 0x02);
es7243e_i2c_write(client, 0x04, 0x01);
es7243e_i2c_write(client, 0xF9, 0x01);
es7243e_i2c_write(client, 0x00, 0x1E);
es7243e_i2c_write(client, 0x01, 0x00);
es7243e_i2c_write(client, 0x02, 0x00);
es7243e_i2c_write(client, 0x03, 0x20);
//es7243e_i2c_write(client, 0x0D, 0x00);
es7243e_i2c_write_bits(client, 0x0D, 0x0f, 4, (client->adc_priv.adc_data_sel<<2) | client->adc_priv.adc_inv);
es7243e_i2c_write(client, 0xF9, 0x00);
es7243e_i2c_write(client, 0x04, 0x02);
es7243e_i2c_write(client, 0x04, 0x01);
es7243e_i2c_write(client, 0x05, 0x00);
es7243e_i2c_write(client, 0x07, 0x00);//add
es7243e_i2c_write(client, 0x09, 0xC5);
es7243e_i2c_write(client, 0x0A, 0x81);
es7243e_i2c_write(client, 0x0b, 0x00);
es7243e_i2c_write(client, 0x0E, 0xBF);
es7243e_i2c_write(client, 0x0F, 0x80);
es7243e_i2c_write(client, 0x14, 0x0C);
es7243e_i2c_write(client, 0x15, 0x0C);
es7243e_i2c_write(client, 0x17, 0x02);//add
es7243e_i2c_write(client, 0x18, 0x26);
es7243e_i2c_write(client, 0x19, 0x77);
es7243e_i2c_write(client, 0x1A, 0xF4);
es7243e_i2c_write(client, 0x1B, 0x66);
es7243e_i2c_write(client, 0x1C, 0x44);
es7243e_i2c_write(client, 0x1E, 0x00);
es7243e_i2c_write(client, 0x1F, 0x0C);
es7243e_i2c_write(client, 0x20, 0x19);
es7243e_i2c_write(client, 0x21, 0x19);
es7243e_i2c_write(client, 0x00, 0x80);
es7243e_i2c_write(client, 0x01, 0x3A);
es7243e_i2c_write(client, 0x16, 0x3F);
es7243e_i2c_write(client, 0x16, 0x00);
}
return 0;
}
static int es7243e_set_fmt(unsigned int fmt)
{
u8 iface = 0;
u8 adciface = 0;
u8 clksel = 0;
es7243e_client *client = g_es7243e_client;
if(!client)
{
printf("%s(), Invalid client\n", __func__);
return -1;
}
adciface = es7243e_i2c_read(client, 0x0B); //get interface format
iface = es7243e_i2c_read(client, 0x00); //get spd interface
clksel = es7243e_i2c_read(client, 0x02); //get spd interface
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK)
{
case SND_SOC_DAIFMT_CBM_CFM: // MASTER MODE
printf("Enter into %s(), I2S master\n", __func__);
iface |= 0x40;
break;
case SND_SOC_DAIFMT_CBS_CFS: // SLAVE MODE
printf("Enter into %s(), I2S slave\n", __func__);
iface &= 0xbf;
break;
default:
return -EINVAL;
}
/* interface format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK)
{
case SND_SOC_DAIFMT_I2S:
printf("Enter into %s(), I2S format \n", __func__);
adciface &= 0xFC;
break;
case SND_SOC_DAIFMT_RIGHT_J:
return -EINVAL;
case SND_SOC_DAIFMT_LEFT_J:
printf("Enter into %s(), LJ format \n", __func__);
adciface &= 0xFC;
adciface |= 0x01;
break;
case SND_SOC_DAIFMT_DSP_A:
printf("Enter into %s(), DSP-A format \n", __func__);
adciface &= 0xDC;
adciface |= 0x03;
break;
case SND_SOC_DAIFMT_DSP_B:
printf("Enter into %s(), DSP-B format \n", __func__);
adciface &= 0xDC;
adciface |= 0x23;
break;
default:
return -EINVAL;
}
/* clock inversion */
switch (fmt & SND_SOC_DAIFMT_INV_MASK)
{
case SND_SOC_DAIFMT_NB_NF:
printf("Enter into %s(), BCLK noinvert, MCLK noinvert \n", __func__);
adciface &= 0xdf;
clksel &= 0xfe;
break;
case SND_SOC_DAIFMT_IB_IF:
printf("Enter into %s(), BCLK invert, MCLK invert \n", __func__);
adciface |= 0x20;
clksel |= 0x01;
break;
case SND_SOC_DAIFMT_IB_NF:
printf("Enter into %s(), BCLK invert, MCLK noinvert \n", __func__);
adciface &= 0xdf;
clksel |= 0x01;
break;
case SND_SOC_DAIFMT_NB_IF:
printf("Enter into %s(), BCLK noinvert, MCLK invert \n", __func__);
adciface |= 0x20;
clksel &= 0xfe;
break;
default:
return -EINVAL;
}
es7243e_i2c_write(client, 0x00, iface);
es7243e_i2c_write(client, 0x02, clksel);
es7243e_i2c_write(client, 0x0B, adciface);
return 0;
}
static int es7243e_mute(int mute)
{
es7243e_client *client = g_es7243e_client;
if(!client)
{
printf("%s(), Invalid client\n", __func__);
return -1;
}
printf("%s %d\n", __func__, mute);
if (mute)
{
es7243e_i2c_write_bits(client, 0x0B, 0x3, 6, 0x3);
client->mute = 1;
}
else
{
es7243e_i2c_write_bits(client, 0x0B, 0x3, 6, 0x0);
client->mute = 0;
}
return 0;
}
static int es7243e_set_mclk(int freq, int dir)
{
return 0;
}
static int es7243e_hw_params(struct snd_soc_hw_params *params)
{
es7243e_client *client = g_es7243e_client;
if(!client)
{
printf("%s(), Invalid client\n", __func__);
return -1;
}
if(!params)
{
printf("%s(), Invalid params\n", __func__);
return -1;
}
client->rates = params->rates;
client->channels = params->channels;
client->bits = params->bits;
client->mclk = client->rates * 256;
es7243e_set_bias_level(client, SND_SOC_BIAS_OFF);
es7243e_pcm_hw_params(client);
return 0;
}
static int es7243e_startup(int start)
{
es7243e_client *client = g_es7243e_client;
if(!client)
{
printf("%s(), Invalid client\n", __func__);
return -1;
}
if(start)
es7243e_set_bias_level(client, SND_SOC_BIAS_STANDBY);
else
es7243e_set_bias_level(client, SND_SOC_BIAS_OFF);
return 0;
}
static int es7243e_hw_init(int master)
{
es7243e_client *client = g_es7243e_client;
if(!client)
{
printf("%s(), Invalid client\n", __func__);
return -1;
}
client->master = !!master;
client->fmt = SND_SOC_DAIFMT_I2S; //interface type.
client->fmt |= SND_SOC_DAIFMT_NB_NF; //normal bclk + normal frame.
client->fmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
if(client->master)
client->fmt |= SND_SOC_DAIFMT_CBM_CFM; //master
else
client->fmt |= SND_SOC_DAIFMT_CBS_CFS; //slave
client->adc_priv.adc_data_sel = ADC_OUTPUT_L_R;
client->adc_priv.adc_inv = ADC_INV_NORMAL;
es7243e_init_regs(client);
es7243e_set_fmt(client->fmt);
return 0;
}
static int es7243e_reset(es7243e_client *client)
{
return 0;
}
static int es7243e_probe(struct i2c_adapter *adap, struct snd_soc_dai_ops *ops)
{
es7243e_client *client;
client = pvPortMalloc(sizeof(es7243e_client));
if (!client)
{
printf("%s, pvPortMalloc fail.\n", __func__);
return -ENOMEM;
}
memset(client, 0, sizeof(es7243e_client));
g_es7243e_client = client;
client->adap = adap;
client->slave_addr = ES7243E_SLAVE_ADDR;
if(ops)
{
ops->init = es7243e_hw_init;
ops->hw_params = es7243e_hw_params;
ops->startup = es7243e_startup;
ops->set_fmt = es7243e_set_fmt;
ops->set_mute = es7243e_mute;
ops->set_mclk = es7243e_set_mclk;
}
es7243e_reset(client);
es7243e_mute(1);
return 0;
}
int audio_codec_adc_init(struct snd_soc_dai_ops *ops)
{
struct i2c_adapter *adap = NULL;
if (!(adap = i2c_open("i2c0"))) {
printf("%s, open i2c0 fail.\n", __func__);
return -1;
}
return es7243e_probe(adap, ops);
}
#endif

View File

@ -0,0 +1,229 @@
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include "FreeRTOS.h"
#include "chip.h"
#include "board.h"
#include "soc-dai.h"
#if AUDIO_CODEC_DAC_IC == AUDIO_CODEC_DAC_ES8156
/* Reset Control */
#define ES8156_RESET_REG00 0x00
/* Clock Managerment */
#define ES8156_MAINCLOCK_CTL_REG01 0x01
#define ES8156_SCLK_MODE_REG02 0x02
#define ES8156_LRCLK_DIV_H_REG03 0x03
#define ES8156_LRCLK_DIV_L_REG04 0x04
#define ES8156_SCLK_DIV_REG05 0x05
#define ES8156_NFS_CONFIG_REG06 0x06
#define ES8156_MISC_CONTROL1_REG07 0x07
#define ES8156_CLOCK_ON_OFF_REG08 0x08
#define ES8156_MISC_CONTROL2_REG09 0x09
#define ES8156_TIME_CONTROL1_REG0A 0x0a
#define ES8156_TIME_CONTROL2_REG0B 0x0b
/* System Control */
#define ES8156_CHIP_STATUS_REG0C 0x0c
#define ES8156_P2S_CONTROL_REG0D 0x0d
#define ES8156_DAC_OSR_COUNTER_REG10 0x10
/* SDP Control */
#define ES8156_DAC_SDP_REG11 0x11
#define ES8156_AUTOMUTE_SET_REG12 0x12
#define ES8156_DAC_MUTE_REG13 0x13
#define ES8156_VOLUME_CONTROL_REG14 0x14
/* ALC Control */
#define ES8156_ALC_CONFIG1_REG15 0x15
#define ES8156_ALC_CONFIG2_REG16 0x16
#define ES8156_ALC_CONFIG3_REG17 0x17
#define ES8156_MISC_CONTROL3_REG18 0x18
#define ES8156_EQ_CONTROL1_REG19 0x19
#define ES8156_EQ_CONTROL2_REG1A 0x1a
/* Analog System Control */
#define ES8156_ANALOG_SYS1_REG20 0x20
#define ES8156_ANALOG_SYS2_REG21 0x21
#define ES8156_ANALOG_SYS3_REG22 0x22
#define ES8156_ANALOG_SYS4_REG23 0x23
#define ES8156_ANALOG_LP_REG24 0x24
#define ES8156_ANALOG_SYS5_REG25 0x25
/* Chip Information */
#define ES8156_I2C_PAGESEL_REGFC 0xFC
#define ES8156_CHIPID1_REGFD 0xFD
#define ES8156_CHIPID0_REGFE 0xFE
#define ES8156_CHIP_VERSION_REGFF 0xFF
/* Slave device address */
#define ES8156_SLAVE_ADDR 0x09
typedef struct es8156_private_data {
struct i2c_adapter *adap;
unsigned short slave_addr;
int rates;
int channels;
int bits;
int master;
int mclk;
int fmt;
int mute;
} es8156_client;
#if 0
/**
* es8156_i2c_read - read data from a register of the i2c slave device.
*
* @adap: i2c device.
* @reg: the register to read from.
* @buf: raw write data buffer.
* @len: length of the buffer to write
*/
static int es8156_i2c_read(es8156_client *client, uint8_t reg)
{
struct i2c_msg msgs[2];
uint8_t wbuf[2];
uint8_t rbuf = 0;
int ret;
int i;
wbuf[0] = reg;
msgs[0].flags = 0;
msgs[0].addr = client->slave_addr;
msgs[0].len = 1;
msgs[0].buf = wbuf;
msgs[1].flags = I2C_M_RD;
msgs[1].addr = client->slave_addr;
msgs[1].len = 1;
msgs[1].buf = &rbuf;
for(i=0; i<5; i++)
{
ret = i2c_transfer(client->adap, msgs, 2);
if(ret == 2)
break;
}
return (ret==ARRAY_SIZE(msgs)) ? rbuf : -EIO;
}
/**
* es8156_i2c_write - write data to a register of the i2c slave device.
*
* @adap: i2c device.
* @reg: the register to write to.
* @buf: raw data buffer to write.
* @len: length of the buffer to write
*/
static int es8156_i2c_write(es8156_client *client, uint8_t reg, uint8_t val)
{
struct i2c_msg msg;
uint8_t addr_buf[2];
int ret;
int i;
addr_buf[0] = reg;
addr_buf[1] = val;
msg.flags = 0;
msg.addr = client->slave_addr;
msg.buf = addr_buf;
msg.len = 2;
for(i=0; i<5; i++)
{
ret = i2c_transfer(client->adap, &msg, 1);
if(ret == 1)
break;
}
printf("reg[0x%x], val:0x%x, read:0x%x\n", reg, val, es8156_i2c_read(client, reg));
return (ret != 1 ? -EIO : 0);
}
int es8156_i2c_write_bits(es8156_client *client, u8 reg, u8 mask, u8 offset, u8 value)
{
int val = es8156_i2c_read(client, reg);
if(val < 0)
{
printf("%s read failed, reg:0x%x, val:0x%x\n", __func__, reg, val);
return -1;
}
val &= ~(mask << offset);
val |= (value << offset);
if(es8156_i2c_write(client, reg, val))
{
printf("%s write failed, reg:0x%x, val:0x%x\n", __func__, reg, val);
return -1;
}
return 0;
}
static int es8156_reset(es8156_client *client)
{
es8156_i2c_write(client, ES8156_RESET_REG00, 0x1c);
mdelay(5);
es8156_i2c_write(client, ES8156_RESET_REG00, 0x03);
return 0;
}
static int es8156_probe(struct i2c_adapter *adap, struct snd_soc_dai_ops *ops)
{
es8156_client *client;
client = pvPortMalloc(sizeof(es8156_client));
if (!client)
{
printf("%s, pvPortMalloc fail.\n", __func__);
return -ENOMEM;
}
memset(client, 0, sizeof(es8156_client));
#if 0 //set default value;
client->rates = 44100;
client->channels = 2;
client->bits = 16;
client->mute = 0;
client->master = 1;
client->mclk = client->rates * 256;
client->fmt = SND_SOC_DAIFMT_I2S; //interface type.
#endif
if(ops)
{
//es8156 Free Driver(免驱).
//ops->init =;
//ops->hw_params =;
//ops->startup =;
//ops->set_fmt =;
//ops->set_mute =;
//ops->set_mclk =;
}
//es8156_reset(client);
return 0;
}
#endif
int audio_codec_dac_init(struct snd_soc_dai_ops *ops)
{
(void)ops;
#if 0 //es8156 no need driver.
struct i2c_adapter *adap = NULL;
if (!(adap = i2c_open("i2c0"))) {
printf("%s, open i2c0 fail.\n", __func__);
return -1;
}
es8156_probe(adap, ops);
#endif
return 0;
}
#endif

View File

@ -0,0 +1,102 @@
#include "FreeRTOS.h"
#include "board.h"
#include "chip.h"
#ifdef I2C_EEPROM_SLAVE_DEMO
#if !defined(I2C0_SLAVE_MODE) && !defined(I2C1_SLAVE_MODE)
#error "i2c eeprom slave demo needs a slave mode i2c dev"
#endif
#define I2C_EEPROM_24C02_ADDR 0x50
#define I2C_EEPROM_24C02_SIZE 256
struct eeprom_data {
bool first_write;
u8 buffer_idx;
u8 buffer[];
};
static struct eeprom_data *g_eeprom = NULL;
static struct i2c_adapter *g_adap = NULL;
static int i2c_slave_eeprom_slave_cb(struct i2c_adapter *adap,
enum i2c_slave_event event, u8 *val)
{
struct eeprom_data *eeprom = g_eeprom;
switch (event) {
case I2C_SLAVE_WRITE_RECEIVED:
if (eeprom->first_write) {
eeprom->buffer_idx = *val;
eeprom->first_write = false;
} else {
eeprom->buffer[eeprom->buffer_idx++] = *val;
}
break;
case I2C_SLAVE_READ_REQUESTED:
*val = eeprom->buffer[eeprom->buffer_idx++];
/*
* Do not increment buffer_idx here, because we don't know if
* this byte will be actually used. Read Linux I2C slave docs
* for details.
*/
break;
case I2C_SLAVE_STOP:
case I2C_SLAVE_WRITE_REQUESTED:
eeprom->first_write = true;
break;
default:
break;
}
return 0;
}
int i2c_slave_eeprom_init(void)
{
struct eeprom_data *eeprom;
int ret;
unsigned size = I2C_EEPROM_24C02_SIZE;
struct i2c_adapter *adap = NULL;
eeprom = pvPortMalloc(sizeof(struct eeprom_data) + size);
if (!eeprom)
return -ENOMEM;
g_eeprom = eeprom;
eeprom->first_write = true;
#ifdef I2C0_SLAVE_MODE
adap = i2c_open("i2c0");
#else
adap = i2c_open("i2c1");
#endif
if (!adap) {
printf("%s open i2c fail.\n", __func__);
vPortFree(eeprom);
return -1;
}
g_adap = adap;
ret = i2c_slave_register(adap, I2C_EEPROM_24C02_ADDR, i2c_slave_eeprom_slave_cb);
if (ret) {
return ret;
}
return 0;
};
int i2c_slave_eeprom_uninit(void)
{
if (g_adap)
i2c_slave_unregister(g_adap);
if (g_eeprom)
vPortFree(g_eeprom);
return 0;
}
#endif

View File

@ -0,0 +1,251 @@
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include "FreeRTOS.h"
#include "chip.h"
#include "board.h"
#include "keypad.h"
#if !defined(VG_ONLY) && !defined(AWTK)
#include "lvgl/lvgl.h"
#else
typedef int16_t lv_coord_t;
typedef uint8_t lv_indev_state_t;
typedef struct {
lv_coord_t x;
lv_coord_t y;
} lv_point_t;
enum { LV_INDEV_STATE_REL = 0, LV_INDEV_STATE_PR };
enum {
LV_KEY_UP = 17, /*0x11*/
LV_KEY_DOWN = 18, /*0x12*/
LV_KEY_RIGHT = 19, /*0x13*/
LV_KEY_LEFT = 20, /*0x14*/
LV_KEY_ESC = 27, /*0x1B*/
LV_KEY_DEL = 127, /*0x7F*/
LV_KEY_BACKSPACE = 8, /*0x08*/
LV_KEY_ENTER = 10, /*0x0A, '\n'*/
LV_KEY_NEXT = 9, /*0x09, '\t'*/
LV_KEY_PREV = 11, /*0x0B, '*/
LV_KEY_HOME = 2, /*0x02, STX*/
LV_KEY_END = 3, /*0x03, ETX*/
};
typedef struct {
lv_point_t point; /**< For LV_INDEV_TYPE_POINTER the currently pressed point*/
uint32_t key; /**< For LV_INDEV_TYPE_KEYPAD the currently pressed key*/
uint32_t btn_id; /**< For LV_INDEV_TYPE_BUTTON the currently pressed button*/
int16_t enc_diff; /**< For LV_INDEV_TYPE_ENCODER number of steps since the previous read*/
lv_indev_state_t state; /**< LV_INDEV_STATE_REL or LV_INDEV_STATE_PR*/
} lv_indev_data_t;
#endif
#define KEYAD_1 10
#define KEYAD_2 530
#define KEYAD_3 1150
#define KEYAD_4 1665
#define KEYAD_5 2278
#define KEYAD_6 2845
#define KEYAD_7 3372
#define KEYAD_NUM 7
#define KEYAD_RANGE 10
static int KeyAdcValue[KEYAD_NUM] =
{
KEYAD_1,
KEYAD_2,
KEYAD_3,
KEYAD_4,
KEYAD_5,
KEYAD_6,
KEYAD_7,
};
static unsigned int KeypadMap[KEYAD_NUM] =
{
LV_KEY_HOME,
LV_KEY_ENTER,
LV_KEY_ESC,
LV_KEY_UP,
LV_KEY_DOWN,
LV_KEY_LEFT,
LV_KEY_RIGHT,
};
#define NULL_KEY 0xFFFF
#define KEY_STATE_IDLE 0
#define KEY_STATE_START 1
#define KEY_STATE_PRESS 2
static UINT32 lg_ulKeyMachineState = KEY_STATE_IDLE;
static UINT32 lg_ulLastKey = NULL_KEY;
#define KEY_POOL_SIZE 8
static UINT32 lg_arrKeyAvgPool[KEY_POOL_SIZE];
static UINT32 lg_ulKeyIndex = 0;
extern void SendKeypadInputEventFromISR(lv_indev_data_t *indata);
static void PushKeyToAVGPool(UINT32 ulKeyValue)
{
if(lg_ulKeyIndex < KEY_POOL_SIZE)
{
lg_arrKeyAvgPool[lg_ulKeyIndex] = ulKeyValue;
lg_ulKeyIndex++;
}
}
static UINT32 AVGPoolIsFull(void)
{
return lg_ulKeyIndex == KEY_POOL_SIZE;
}
static UINT32 GetKeyAVGValue(void)
{
UINT32 i;
UINT32 ulSum;
ulSum = 0;
for(i=0;i<lg_ulKeyIndex;i++)
{
ulSum += lg_arrKeyAvgPool[i];
}
return ulSum/lg_ulKeyIndex;
}
static void ResetKeyAVGPool(void)
{
lg_ulKeyIndex = 0;
}
static UINT32 CheckKey(UINT32 ulSampleValue)
{
UINT32 i;
for(i = 0; i < (sizeof(KeyAdcValue) / sizeof(KeyAdcValue[0])); i++ )
{
if((ulSampleValue >= KeyAdcValue[i] - KEYAD_RANGE) && (ulSampleValue <= KeyAdcValue[i] + KEYAD_RANGE))
{
return i;
}
}
return NULL_KEY;
}
static void SendKeyPress(UINT32 key)
{
lv_indev_data_t indata = {0};
indata.key = key;
indata.state = LV_INDEV_STATE_PR;
SendKeypadInputEventFromISR(&indata);
}
static void SendKeyRelease(UINT32 key)
{
lv_indev_data_t indata = {0};
indata.key = key;
indata.state = LV_INDEV_STATE_REL;
SendKeypadInputEventFromISR(&indata);
}
extern char key_value;
void KeyEventHandler(UINT32 ulEvent, UINT32 lpParam, UINT32 wParam)
{
switch(lg_ulKeyMachineState)
{
case KEY_STATE_IDLE:
if(ulEvent == KEY_START_EVENT)
{
lg_ulKeyMachineState = KEY_STATE_START;
}
break;
case KEY_STATE_START:
key_value = !key_value;
if(ulEvent == KEY_SAMPLE_EVENT)
{
ResetKeyAVGPool();
PushKeyToAVGPool(lpParam);
lg_ulKeyMachineState = KEY_STATE_PRESS;
}
else if(ulEvent == KEY_STOP_EVENT)
{
lg_ulKeyMachineState = KEY_STATE_IDLE;
lg_ulLastKey = NULL_KEY;
}
break;
case KEY_STATE_PRESS:
if(ulEvent == KEY_SAMPLE_EVENT)
{
PushKeyToAVGPool(lpParam);
if(AVGPoolIsFull())
{
UINT32 ulKeySampleValue;
UINT32 ulNewKeyCode;
ulKeySampleValue = GetKeyAVGValue();
ulNewKeyCode = CheckKey(ulKeySampleValue);
ResetKeyAVGPool();
if(ulNewKeyCode != NULL_KEY)
{
if(lg_ulLastKey != ulNewKeyCode && lg_ulLastKey != NULL_KEY)
{
lg_ulKeyMachineState = KEY_STATE_IDLE;
//send key release event;
SendKeyRelease(KeypadMap[lg_ulLastKey]);
lg_ulLastKey = NULL_KEY;
}
else if (lg_ulLastKey == ulNewKeyCode)
{
//Send repeat key event;
SendKeyPress(KeypadMap[lg_ulLastKey]);
}
else if (lg_ulLastKey == NULL_KEY)
{
//Send key press event;
SendKeyPress(KeypadMap[ulNewKeyCode]);
}
lg_ulLastKey = ulNewKeyCode;
}
else
{
lg_ulKeyMachineState = KEY_STATE_IDLE;
if(lg_ulLastKey != NULL_KEY)
{
//send key release event
SendKeyRelease(KeypadMap[lg_ulLastKey]);
lg_ulLastKey = NULL_KEY;
}
}
}
}
else if(ulEvent == KEY_STOP_EVENT)
{
lg_ulKeyMachineState = KEY_STATE_IDLE;
if(lg_ulLastKey != NULL_KEY)
{
//send key release event
SendKeyRelease(KeypadMap[lg_ulLastKey]);
lg_ulLastKey = NULL_KEY;
}
}
break;
}
}
void KeypadInit(void)
{
adc_channel_enable(ADC_CH_AUX0);
}

View File

@ -0,0 +1,715 @@
#include <stdlib.h>
#include <unistd.h>
#include "FreeRTOS.h"
#include "board.h"
#include "chip.h"
#include "sfud.h"
#include "romfile.h"
#include "updatefile.h"
#include "animation.h"
#include "sysinfo.h"
#include "mmcsd_core.h"
#include "ff_stdio.h"
#include "source/crc32.h"
#if DEVICE_TYPE_SELECT != EMMC_FLASH
#include "ff_sfdisk.h"
#endif
#ifdef OTA_UPDATE_SUPPORT
#include "ota_update.h"
/* 获取已升级文件位置, toburn不为0时获取升级文件要烧录的位置 */
static unsigned int get_upfile_offset(int filetype, int toburn)
{
SysInfo *sysinfo = GetSysInfo();
if (filetype == UPFILE_TYPE_WHOLE) {
if (!toburn) return sysinfo->image_offset;
if (sysinfo->image_offset == UPDATEFILE_MEDIA_OFFSET)
return UPDATEFILE_MEDIA_B_OFFSET;
else
return UPDATEFILE_MEDIA_OFFSET;
} else if (filetype == UPFILE_TYPE_FIRSTLDR) {
#if DEVICE_TYPE_SELECT == EMMC_FLASH
if (!toburn) return sysinfo->loader_offset;
if (sysinfo->loader_offset == LOADER_OFFSET)
return LOADERB_OFFSET;
else
return LOADER_OFFSET;
#else
return LOADER_OFFSET;
#endif
} else if (filetype == UPFILE_TYPE_STEPLDR) {
if (!toburn) return sysinfo->stepldr_offset;
if (sysinfo->stepldr_offset == STEPLDRA_OFFSET)
return STEPLDRB_OFFSET;
else
return STEPLDRA_OFFSET;
} else if (filetype == UPFILE_TYPE_LNCHEMMC) {
return 0;
} else {
uint8_t buf[512];
UpFileHeader *header;
UpFileInfo *appfile;
unsigned int image_offset;
int i;
if (toburn) {
if (sysinfo->image_offset == UPDATEFILE_MEDIA_OFFSET)
image_offset = UPDATEFILE_MEDIA_B_OFFSET;
else
image_offset = UPDATEFILE_MEDIA_OFFSET;
} else {
image_offset = sysinfo->image_offset;
}
#if DEVICE_TYPE_SELECT == EMMC_FLASH
emmc_read(image_offset, 512, buf);
#else
sfud_flash *sflash = sfud_get_device(0);
sfud_read(sflash, image_offset, 512, buf);
#endif
header = (UpFileHeader *)buf;
if (header->magic != MKTAG('U', 'P', 'D', 'F')) {
printf("update file isn't found, can't support module update.\n");
return 0xffffffff;
}
for (i = 0; i < header->filenum; i++) {
appfile = &header->files[i];
if ((appfile->magic == UPFILE_APP_MAGIC && filetype == UPFILE_TYPE_APP) ||
(appfile->magic == MKTAG('R', 'O', 'M', 'A') && filetype == UPFILE_TYPE_RESOURCE) ||
(appfile->magic == MKTAG('B', 'A', 'N', 'I') && filetype == UPFILE_TYPE_ANIMATION)) {
if (appfile->offset & (64 - 1)) {
printf("offset isn't align to sector erase size, can't support module update.\n");
return 0xffffffff;
}
return appfile->offset + image_offset;
}
}
}
return 0xffffffff;
}
static void set_upfile_offset(SysInfo *sysinfo, int filetype, uint32_t offset)
{
if (filetype == UPFILE_TYPE_WHOLE) {
sysinfo->image_offset = offset;
} else if (filetype == UPFILE_TYPE_FIRSTLDR) {
#if DEVICE_TYPE_SELECT == EMMC_FLASH
sysinfo->loader_offset = offset;
#endif
} else if (filetype == UPFILE_TYPE_STEPLDR) {
sysinfo->stepldr_offset = offset;
}
}
static unsigned int get_upfile_size(int filetype)
{
SysInfo *sysinfo = GetSysInfo();
uint32_t offset;
uint8_t buf[512];
if (filetype <= UPFILE_TYPE_ANIMATION) {
offset = get_upfile_offset(filetype, 0);
#if DEVICE_TYPE_SELECT == EMMC_FLASH
emmc_read(offset, 512, buf);
#else
sfud_flash *sflash = sfud_get_device(0);
sfud_read(sflash, offset, 512, buf);
#endif
if (filetype == UPFILE_TYPE_WHOLE) {
UpFileHeader *header = (UpFileHeader *)buf;
return header->size;
} else if (filetype == UPFILE_TYPE_RESOURCE) {
RomHeader *header = (RomHeader *)buf;
return header->romsize;
} else if (filetype == UPFILE_TYPE_ANIMATION) {
BANIHEADER *header = (BANIHEADER *)buf;
return header->aniSize;
}
} else if (filetype >= UPFILE_TYPE_APP) {
return sysinfo->app_size;
} else if (filetype == UPFILE_TYPE_FIRSTLDR) {
return sysinfo->loader_size;
} else if (filetype == UPFILE_TYPE_STEPLDR) {
return sysinfo->stepldr_size;
}
return 0;
}
/* 获取已升级文件校验和
filesize 0:从已升级的文件中读取该文件大小
toburn 0:获取当运行文件的校验和 1:获取要烧录位置的旧升级文件的校验和
checkmode 0:不校验 1:进行校验校验错误返回0 2:进行校验,校验出错也返回校验值 */
static uint32_t get_upfile_checksum(int filetype, size_t filesize, int checkmode, int toburn)
{
uint32_t checksum, calc_checksum = 0xffffffff;
uint8_t *buf;
sfud_flash *sflash = sfud_get_device(0);
uint32_t fileoffset;
int off, size, leftsize;
buf = pvPortMalloc(IMAGE_RW_SIZE);
if (!buf) {
printf("%s %d malloc %d bytes fail.\n", __FUNCTION__, __LINE__, IMAGE_RW_SIZE);
return 0;
}
if (!filesize) {
filesize = get_upfile_size(filetype);
if (!filesize) {
if (!checkmode) {
filesize = IMAGE_RW_SIZE;
} else {
printf("Error, filesize is zero when needing chekced.\n");
return 0;
}
}
}
fileoffset = get_upfile_offset(filetype, toburn);
size = filesize > IMAGE_RW_SIZE ? IMAGE_RW_SIZE : filesize;
#if DEVICE_TYPE_SELECT == EMMC_FLASH
if (filetype == UPFILE_TYPE_LNCHEMMC) {
if (!sflash->init_ok)
sfud_init();
sfud_read(sflash, fileoffset, size, buf);
} else emmc_read(fileoffset, size, buf);
#else
sfud_read(sflash, fileoffset, size, buf);
#endif
if (filetype == UPFILE_TYPE_WHOLE) {
UpFileHeader *header = (UpFileHeader *)buf;
checksum = header->checksum;
header->checksum = 0;
if (checkmode)
calc_checksum = xcrc32(buf, size, calc_checksum);
} else if (filetype == UPFILE_TYPE_RESOURCE) {
RomHeader *header = (RomHeader *)buf;
checksum = header->checksum;
header->checksum = 0;
if (checkmode)
calc_checksum = xcrc32(buf, size, calc_checksum);
} else if (filetype == UPFILE_TYPE_ANIMATION) {
BANIHEADER *header = (BANIHEADER *)buf;
checksum = header->checksum;
header->checksum = 0;
if (checkmode)
calc_checksum = xcrc32(buf, size, calc_checksum);
} else if (filetype >= UPFILE_TYPE_APP) {
checksum = *(uint32_t*)(buf + APPLDR_CHECKSUM_OFFSET);
*(uint32_t*)(buf + APPLDR_CHECKSUM_OFFSET) = 0;
if (checkmode)
calc_checksum = xcrc32(buf, size, calc_checksum);
}
if (!checkmode) {
vPortFree(buf);
return checksum;
}
off = fileoffset + IMAGE_RW_SIZE;
leftsize = filesize - size;
while (leftsize > 0) {
size = leftsize > IMAGE_RW_SIZE ? IMAGE_RW_SIZE : leftsize;
#if DEVICE_TYPE_SELECT == EMMC_FLASH
if (filetype == UPFILE_TYPE_LNCHEMMC)
sfud_read(sflash, off, size, buf);
else
emmc_read(off, size, buf);
#else
sfud_read(sflash, off, size, buf);
#endif
calc_checksum = xcrc32(buf, size, calc_checksum);
off += size;
leftsize -= size;
}
vPortFree(buf);
if (calc_checksum == checksum || checkmode > 1)
return calc_checksum;
else
return 0;
}
/* 获取升级文件的校验和bchecked不为0时表示需要校验校验错误返回0 */
static uint32_t get_mediafile_checksum(const char *ufile, int filetype, int bchecked)
{
uint32_t checksum, calc_checksum = 0xffffffff;
FF_FILE *fp;
uint8_t *buf;
int rlen;
fp = ff_fopen(ufile, "rb");
if (!fp) {
printf("open %s fail.\n", ufile);
return 0;
}
buf = pvPortMalloc(IMAGE_RW_SIZE);
if (!buf) {
printf("%s %d malloc %d bytes fail.\n", __FUNCTION__, __LINE__, IMAGE_RW_SIZE);
ff_fclose(fp);
return 0;
}
rlen = ff_fread(buf, 1, IMAGE_RW_SIZE, fp);
if (rlen <= 0) {
printf("read %s data fail.\n", ufile);
ff_fclose(fp);
vPortFree(buf);
return 0;
}
if (filetype == UPFILE_TYPE_WHOLE) {
UpFileHeader *header = (UpFileHeader *)buf;
checksum = header->checksum;
header->checksum = 0;
if (bchecked)
calc_checksum = xcrc32(buf, rlen, calc_checksum);
} else if (filetype == UPFILE_TYPE_RESOURCE) {
RomHeader *header = (RomHeader *)buf;
checksum = header->checksum;
header->checksum = 0;
if (bchecked)
calc_checksum = xcrc32(buf, rlen, calc_checksum);
} else if (filetype == UPFILE_TYPE_ANIMATION) {
BANIHEADER *header = (BANIHEADER *)buf;
checksum = header->checksum;
header->checksum = 0;
if (bchecked)
calc_checksum = xcrc32(buf, rlen, calc_checksum);
} else if (filetype >= UPFILE_TYPE_APP) {
checksum = *(uint32_t*)(buf + APPLDR_CHECKSUM_OFFSET);
*(uint32_t*)(buf + APPLDR_CHECKSUM_OFFSET) = 0;
if (bchecked)
calc_checksum = xcrc32(buf, rlen, calc_checksum);
}
if (!bchecked) {
ff_fclose(fp);
vPortFree(buf);
return checksum;
}
while ((rlen = ff_fread(buf, 1, IMAGE_RW_SIZE, fp)) > 0)
calc_checksum = xcrc32(buf, rlen, calc_checksum);
ff_fclose(fp);
vPortFree(buf);
if (calc_checksum == checksum)
return checksum;
else
return 0;
}
static int backup_whole_image(void)
{
uint8_t *buf;
SysInfo *sysinfo = GetSysInfo();
uint32_t imagechecksum, imagesize, imageoff, roff, woff;
UpFileHeader *header = NULL;
int leftsize, rwsize;
int retimes = 3;
#if DEVICE_TYPE_SELECT != EMMC_FLASH
sfud_flash *sflash = sfud_get_device(0);
#endif
buf = pvPortMalloc(IMAGE_RW_SIZE);
if (!buf) {
printf("%s %d malloc %d bytes fail.\n", __FUNCTION__, __LINE__, IMAGE_RW_SIZE);
return -1;
}
if (sysinfo->image_offset == UPDATEFILE_MEDIA_OFFSET)
imageoff = UPDATEFILE_MEDIA_B_OFFSET;
else
imageoff = UPDATEFILE_MEDIA_OFFSET;
#if DEVICE_TYPE_SELECT == EMMC_FLASH
emmc_read(imageoff, IMAGE_RW_SIZE, buf);
#else
sfud_read(sflash, imageoff, IMAGE_RW_SIZE, buf);
#endif
header = (UpFileHeader*)buf;
if (header->checksum == sysinfo->app_checksum) {
if (get_upfile_checksum(UPFILE_TYPE_WHOLE, header->size, 1, 1) == sysinfo->app_checksum) {
printf("the whole images are same, no need to backup.\n");
vPortFree(buf);
return 0;
}
} else if (sysinfo->app_checksum == 0) {
uint32_t checksum = get_upfile_checksum(UPFILE_TYPE_WHOLE, header->size, 2, 1);
if (checksum && checksum == get_upfile_checksum(UPFILE_TYPE_WHOLE, header->size, 2, 0)) {
printf("the whole images are same, no need to backup.\n");
vPortFree(buf);
return 0;
}
}
printf("start backup the whole image...\n");
rewrite:
#if DEVICE_TYPE_SELECT == EMMC_FLASH
emmc_read(sysinfo->image_offset, IMAGE_RW_SIZE, buf);
emmc_write(imageoff, IMAGE_RW_SIZE, buf);
#else
sfud_read(sflash, sysinfo->image_offset, IMAGE_RW_SIZE, buf);
sfud_erase_write(sflash, imageoff, IMAGE_RW_SIZE, buf);
#endif
imagesize = header->size;
leftsize = imagesize - IMAGE_RW_SIZE;
woff = imageoff + IMAGE_RW_SIZE;
roff = sysinfo->image_offset + IMAGE_RW_SIZE;
/* 如果串口单独升级过update.bin内某一种文件的话可能导致header->checksum并不是真实的校验和 */
header->checksum = 0;
imagechecksum = xcrc32(buf, IMAGE_RW_SIZE, 0xffffffff);
while (leftsize > 0) {
rwsize = leftsize > IMAGE_RW_SIZE ? IMAGE_RW_SIZE : leftsize;
#if DEVICE_TYPE_SELECT == EMMC_FLASH
emmc_read(roff, rwsize, buf);
emmc_write(woff, rwsize, buf);
#else
sfud_read(sflash, roff, rwsize, buf);
sfud_erase_write(sflash, woff, rwsize, buf);
#endif
leftsize -= rwsize;
roff += rwsize;
woff += rwsize;
imagechecksum = xcrc32(buf, rwsize, imagechecksum);
}
#if DEVICE_TYPE_SELECT == EMMC_FLASH
emmc_read(sysinfo->image_offset, IMAGE_RW_SIZE, buf);
header->checksum = imagechecksum;
emmc_write(imageoff, IMAGE_RW_SIZE, buf);
#else
sfud_read(sflash, sysinfo->image_offset, IMAGE_RW_SIZE, buf);
header->checksum = imagechecksum;
sfud_erase_write(sflash, imageoff, IMAGE_RW_SIZE, buf);
#endif
printf("checksum after backup...\n");
if (get_upfile_checksum(UPFILE_TYPE_WHOLE, imagesize, 1, 1) == imagechecksum) {
printf("backup the whole image ok.\n");
vPortFree(buf);
return 0;
} else if (retimes-- > 0) {
printf("checksum fail, retry...\n");
goto rewrite;
} else {
printf("backup the whole image fail.\n");
}
vPortFree(buf);
return -1;
}
/* 获取app, resource, rom升级文件单独升级时能支持的最大文件大小 */
static unsigned int get_subfile_maxsize(int filetype)
{
uint8_t buf[512];
UpFileHeader *header;
UpFileInfo *appfile;
SysInfo *sysinfo = GetSysInfo();
int i;
if (filetype < UPFILE_TYPE_RESOURCE || filetype > UPFILE_TYPE_APP)
return 0;
#if DEVICE_TYPE_SELECT == EMMC_FLASH
emmc_read(sysinfo->image_offset, 512, buf);
#else
sfud_flash *sflash = sfud_get_device(0);
sfud_read(sflash, sysinfo->image_offset, 512, buf);
#endif
header = (UpFileHeader *)buf;
if (header->magic != MKTAG('U', 'P', 'D', 'F'))
return 0;
for (i = 0; i < header->filenum; i++) {
appfile = &header->files[i];
if ((appfile->magic == UPFILE_APP_MAGIC && filetype == UPFILE_TYPE_APP) ||
(appfile->magic == MKTAG('R', 'O', 'M', 'A') && filetype == UPFILE_TYPE_RESOURCE) ||
(appfile->magic == MKTAG('B', 'A', 'N', 'I') && filetype == UPFILE_TYPE_ANIMATION)) {
if (i < header->filenum - 1) {
UpFileInfo *nextfile = &header->files[i + 1];
return nextfile->offset - appfile->offset;
} else {
return UPDATEFILE_MAX_SIZE - appfile->offset;
}
}
}
return 0;
}
int update_from_media(char *mpath, int filetype)
{
char update_file[32];
FF_FILE *fp;
size_t filesize;
uint8_t *buf;
size_t file_offset;
SysInfo *sysinfo = GetSysInfo();
sfud_flash *sflash = sfud_get_device(0);
int leftsize, rwoffset, rwsize;
int rlen;
uint32_t checksum;
SysInfo bak_sysinfo;
memcpy(&bak_sysinfo, sysinfo, sizeof(SysInfo));
strcpy(update_file, mpath);
strcat(update_file, "/");
strcat(update_file, g_upfilename[filetype]);
printf("%s checksum...\n", update_file);
if (!(checksum = get_mediafile_checksum(update_file, filetype, 1))) {
printf("checksum fail, don't update.\n");
return 0;
}
if (checksum == get_upfile_checksum(filetype, 0, 0, 0)) {
if (!(filetype == UPFILE_TYPE_WHOLE && sysinfo->app_checksum == 0)) {
printf("checksum is the same as now, don't update.\n");
return 0;
}
}
fp = ff_fopen(update_file, "rb");
if (!fp) {
printf("open %s fail.\n", update_file);
return -1;
}
filesize = ff_filelength(fp);
buf = pvPortMalloc(IMAGE_RW_SIZE);
if (!buf) {
printf("%s %d malloc %d bytes fail.\n", __FUNCTION__, __LINE__, IMAGE_RW_SIZE);
ff_fclose(fp);
return -1;
}
rlen = ff_fread(buf, 1, IMAGE_RW_SIZE, fp);
if (rlen <= 0) {
printf("read %s data fail.\n", update_file);
goto end;
}
if (filetype == UPFILE_TYPE_WHOLE) {
UpFileHeader *header = (UpFileHeader *)buf;
bak_sysinfo.app_checksum = header->checksum;
bak_sysinfo.app_size = header->files[0].size;
} else if (filetype == UPFILE_TYPE_APP) {
bak_sysinfo.app_size = filesize;
} else if (filetype == UPFILE_TYPE_FIRSTLDR) {
bak_sysinfo.loader_size = filesize;
} else if (filetype == UPFILE_TYPE_STEPLDR) {
bak_sysinfo.stepldr_size = filesize;
} else if (filetype == UPFILE_TYPE_LNCHEMMC) {
if (!sflash->init_ok)
sfud_init();
}
/* 这三种文件没有备份需要先备份整个update.bin镜像再升级备份区域 */
if (filetype >= UPFILE_TYPE_RESOURCE && filetype <= UPFILE_TYPE_APP) {
if (filesize > get_subfile_maxsize(filetype)) {
printf("Not have enough space to update subfile %s.\n", update_file);
goto end;
}
if (backup_whole_image()) {
printf("backup_whole_image fail.\n");
goto end;
}
if (sysinfo->image_offset == UPDATEFILE_MEDIA_OFFSET)
bak_sysinfo.image_offset = UPDATEFILE_MEDIA_B_OFFSET;
else
bak_sysinfo.image_offset = UPDATEFILE_MEDIA_OFFSET;
}
file_offset = get_upfile_offset(filetype, 1);
if (file_offset == 0xffffffff) {
printf("get_upfile_offset fail.\n");
goto end;
}
leftsize = filesize;
rwoffset = file_offset;
while (leftsize > 0) {
rwsize = leftsize > rlen ? rlen : leftsize;
#if DEVICE_TYPE_SELECT == EMMC_FLASH
if (filetype == UPFILE_TYPE_LNCHEMMC) {
if (sfud_erase_write(sflash, rwoffset, rwsize, buf) != SFUD_SUCCESS)
{
printf("burn %s data fail.\n", update_file);
goto end;
}
} else {
if (emmc_write(rwoffset, rwsize, buf))
#else
if (sfud_erase_write(sflash, rwoffset, rwsize, buf) != SFUD_SUCCESS)
#endif
{
printf("burn %s data fail.\n", update_file);
goto end;
}
#if DEVICE_TYPE_SELECT == EMMC_FLASH
}
#endif
rwoffset += rwsize;
leftsize -= rwsize;
printf("burn %d/%d.\n", filesize - leftsize, filesize);
rlen = ff_fread(buf, 1, IMAGE_RW_SIZE, fp);
if (rlen < 0) {
printf("read %s data fail.\n", update_file);
goto end;
}
}
printf("checksum after burn...\n");
if (checksum == get_upfile_checksum(filetype, filesize, 1, 1)) {
/* 升级这三个文件app_checksum后不准确不能再用来判断版本 */
if (filetype >= UPFILE_TYPE_RESOURCE && filetype <= UPFILE_TYPE_APP)
bak_sysinfo.app_checksum = 0;
set_upfile_offset(&bak_sysinfo, filetype, file_offset);
memcpy(sysinfo, &bak_sysinfo, sizeof(SysInfo));
SaveSysInfo();
ff_fclose(fp);
vPortFree(buf);
printf("burn %s ok.\n", update_file);
return 0;
} else {
printf("checksum after burn fail.\n");
}
end:
ff_fclose(fp);
vPortFree(buf);
return -1;
}
int save_file_to_ota(int filetype)
{
char update_file[32];
char ota_file[32];
FF_FILE *fp, *fota;
size_t filesize;
int leftsize;
uint8_t *buf = NULL;
size_t readlen;
strcpy(update_file,"/usb/");
strcat(update_file, g_upfilename[filetype]);
strcpy(ota_file, OTA_MOUNT_PATH "/");
strcat(ota_file, g_upfilename[filetype]);
if (get_mediafile_checksum(update_file, filetype, 0) ==
get_mediafile_checksum(ota_file, filetype, 0)) {
if (get_mediafile_checksum(ota_file, filetype, 1)) {
printf("%s is same with ota, not save.\n", g_upfilename[filetype]);
return 0;
}
}
fp = ff_fopen(update_file, "rb");
if (!fp) {
printf("open %s fail.\n", update_file);
return -1;
}
filesize = ff_filelength(fp);
fota = ff_fopen(ota_file, "wb");
if (!fota) {
printf("create %s in ota partition fail.\n", ota_file);
ff_fclose(fp);
return -1;
}
buf = pvPortMalloc(IMAGE_RW_SIZE);
if (!buf) {
printf("malloc IMAGE_RW_SIZE fail.\n");
ff_fclose(fota);
ff_fclose(fp);
return -1;
}
leftsize = filesize;
while (leftsize > 0) {
if (readlen = ff_fread(buf, 1, IMAGE_RW_SIZE, fp)) {
if (ff_fwrite(buf, 1, readlen, fota) != readlen) {
printf("write ota data fail.\n");
break;
} else {
printf("write ota data %d/%d.\n", filesize - leftsize + readlen, filesize);
}
} else {
break;
}
leftsize -= readlen;
}
ff_fclose(fota);
ff_fclose(fp);
vPortFree(buf);
if (leftsize == 0) {
printf("save file ok.\n");
return 0;
}
return -1;
}
#ifdef WIFI_UPDATE_SUPPORT
#define USB_DEV_PLUGED 0
#define USB_DEV_UNPLUGED 1
extern int usb_wait_stor_dev_pluged(uint32_t timeout);
extern void hub_usb_dev_reset(void);
/* 用从usb读取数据来模拟wifi接收升级数据真实的wifi接收升级文件
需要和端app适配需要客户自己实现 */
static void wifi_update_demo_thread(void *para)
{
#if DEVICE_TYPE_SELECT != EMMC_FLASH
FF_Disk_t *sfdisk = FF_SFDiskInit(SF_MOUNT_PATH);
if (sfdisk)
#endif
{
unsigned int status;
int filetype;
for (;;) {
status = usb_wait_stor_dev_pluged(portMAX_DELAY);
if (status == USB_DEV_PLUGED) {
printf("usb dev inserted.\n");
for (filetype = UPFILE_TYPE_WHOLE; filetype <= UPFILE_TYPE_LNCHEMMC; filetype++) {
if (save_file_to_ota(filetype)) {
printf("save_file_to_ota fail.\n");
} else {
printf("start to update from ota...\n");
update_from_media(OTA_MOUNT_PATH, filetype);
}
}
} else {
printf("usb removed.\n");
}
}
}
for (;;)
vTaskDelay(portMAX_DELAY);
}
void wifi_update_demo(void)
{
if (xTaskCreate(wifi_update_demo_thread, "wifiupdate", configMINIMAL_STACK_SIZE * 16, NULL,
1, NULL) != pdPASS) {
printf("create wifi update demo task fail.\n");
}
}
#endif
#endif

View File

@ -0,0 +1,536 @@
#include <FreeRTOS.h>
#include "list.h"
#include "ringblk_buf.h"
/**
* ring block buffer object initialization
*
* @param rbb ring block buffer object
* @param buf buffer
* @param buf_size buffer size
* @param block_set block set
* @param blk_max_num max block number
*
* @note When your application need align access, please make the buffer address is aligned.
*/
void rbb_init(rbb_t rbb, uint8_t *buf, size_t buf_size, rbb_blk_t block_set, size_t blk_max_num)
{
size_t i;
configASSERT(rbb);
configASSERT(buf);
configASSERT(block_set);
rbb->buf = buf;
rbb->buf_size = buf_size;
rbb->blk_set = block_set;
rbb->blk_max_num = blk_max_num;
vListInitialise(&rbb->blk_list);
/* initialize block status */
for (i = 0; i < blk_max_num; i++)
{
block_set[i].status = RBB_BLK_UNUSED;
}
}
/**
* ring block buffer object create
*
* @param buf_size buffer size
* @param blk_max_num max block number
*
* @return != NULL: ring block buffer object
* NULL: create failed
*/
rbb_t rbb_create(size_t buf_size, size_t blk_max_num)
{
rbb_t rbb = NULL;
uint8_t *buf;
rbb_blk_t blk_set;
rbb = (rbb_t)pvPortMalloc(sizeof(struct rbb));
if (!rbb)
{
return NULL;
}
buf = (uint8_t *)pvPortMalloc(buf_size);
if (!buf)
{
vPortFree(rbb);
return NULL;
}
blk_set = (rbb_blk_t)pvPortMalloc(sizeof(struct rbb_blk) * blk_max_num);
if (!blk_set)
{
vPortFree(buf);
vPortFree(rbb);
return NULL;
}
rbb_init(rbb, buf, buf_size, blk_set, blk_max_num);
return rbb;
}
/**
* ring block buffer object destroy
*
* @param rbb ring block buffer object
*/
void rbb_destroy(rbb_t rbb)
{
configASSERT(rbb);
vPortFree(rbb->buf);
vPortFree(rbb->blk_set);
vPortFree(rbb);
}
static rbb_blk_t find_empty_blk_in_set(rbb_t rbb)
{
size_t i;
configASSERT(rbb);
for (i = 0; i < rbb->blk_max_num; i ++)
{
if (rbb->blk_set[i].status == RBB_BLK_UNUSED)
{
return &rbb->blk_set[i];
}
}
return NULL;
}
/**
* Allocate a block by given size. The block will add to blk_list when allocate success.
*
* @param rbb ring block buffer object
* @param blk_size block size
*
* @note When your application need align access, please make the blk_szie is aligned.
*
* @return != NULL: allocated block
* NULL: allocate failed
*/
rbb_blk_t rbb_blk_alloc(rbb_t rbb, size_t blk_size)
{
UBaseType_t uxSavedInterruptStatus;
size_t empty1 = 0, empty2 = 0;
rbb_blk_t head, tail, new_rbb = NULL;
configASSERT(rbb);
configASSERT(blk_size < (1L << 24));
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
new_rbb = find_empty_blk_in_set(rbb);
if (listCURRENT_LIST_LENGTH(&rbb->blk_list) < rbb->blk_max_num && new_rbb)
{
if (listCURRENT_LIST_LENGTH(&rbb->blk_list) > 0)
{
head = listGET_OWNER_OF_HEAD_ENTRY(&rbb->blk_list);
tail = listGET_LIST_ITEM_OWNER(rbb->blk_list.xListEnd.pxPrevious);
if (head->buf <= tail->buf)
{
/**
* head tail
* +--------------------------------------+-----------------+------------------+
* | empty2 | block1 | block2 | block3 | empty1 |
* +--------------------------------------+-----------------+------------------+
* rbb->buf
*/
empty1 = (rbb->buf + rbb->buf_size) - (tail->buf + tail->size);
empty2 = head->buf - rbb->buf;
if (empty1 >= blk_size)
{
listSET_LIST_ITEM_OWNER(&new_rbb->list, new_rbb);
vListInsertEnd(&rbb->blk_list, &new_rbb->list);
new_rbb->status = RBB_BLK_INITED;
new_rbb->buf = tail->buf + tail->size;
new_rbb->size = blk_size;
}
else if (empty2 >= blk_size)
{
listSET_LIST_ITEM_OWNER(&new_rbb->list, new_rbb);
vListInsertEnd(&rbb->blk_list, &new_rbb->list);
new_rbb->status = RBB_BLK_INITED;
new_rbb->buf = rbb->buf;
new_rbb->size = blk_size;
}
else
{
/* no space */
new_rbb = NULL;
}
}
else
{
/**
* tail head
* +----------------+-------------------------------------+--------+-----------+
* | block3 | empty1 | block1 | block2 |
* +----------------+-------------------------------------+--------+-----------+
* rbb->buf
*/
empty1 = head->buf - (tail->buf + tail->size);
if (empty1 >= blk_size)
{
listSET_LIST_ITEM_OWNER(&new_rbb->list, new_rbb);
vListInsertEnd(&rbb->blk_list, &new_rbb->list);
new_rbb->status = RBB_BLK_INITED;
new_rbb->buf = tail->buf + tail->size;
new_rbb->size = blk_size;
}
else
{
/* no space */
new_rbb = NULL;
}
}
}
else
{
/* the list is empty */
listSET_LIST_ITEM_OWNER(&new_rbb->list, new_rbb);
vListInsertEnd(&rbb->blk_list, &new_rbb->list);
new_rbb->status = RBB_BLK_INITED;
new_rbb->buf = rbb->buf;
new_rbb->size = blk_size;
}
}
else
{
new_rbb = NULL;
}
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);
return new_rbb;
}
/**
* put a block to ring block buffer object
*
* @param block the block
*/
void rbb_blk_put(rbb_blk_t block)
{
configASSERT(block);
configASSERT(block->status == RBB_BLK_INITED);
block->status = RBB_BLK_PUT;
}
/**
* get a block from the ring block buffer object
*
* @param rbb ring block buffer object
*
* @return != NULL: block
* NULL: get failed
*/
rbb_blk_t rbb_blk_get(rbb_t rbb)
{
UBaseType_t uxSavedInterruptStatus;
rbb_blk_t block = NULL;
ListItem_t *node;
configASSERT(rbb);
if (listLIST_IS_EMPTY(&rbb->blk_list))
return 0;
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
for (node = listGET_HEAD_ENTRY(&rbb->blk_list); node != listGET_END_MARKER(&rbb->blk_list);
node = listGET_NEXT(node))
{
block = listGET_LIST_ITEM_OWNER(node);
if (block->status == RBB_BLK_PUT)
{
block->status = RBB_BLK_GET;
goto __exit;
}
}
/* not found */
block = NULL;
__exit:
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);
return block;
}
/**
* return the block size
*
* @param block the block
*
* @return block size
*/
size_t rbb_blk_size(rbb_blk_t block)
{
configASSERT(block);
return block->size;
}
/**
* return the block buffer
*
* @param block the block
*
* @return block buffer
*/
uint8_t *rbb_blk_buf(rbb_blk_t block)
{
configASSERT(block);
return block->buf;
}
/**
* free the block
*
* @param rbb ring block buffer object
* @param block the block
*/
void rbb_blk_free(rbb_t rbb, rbb_blk_t block)
{
UBaseType_t uxSavedInterruptStatus;
configASSERT(rbb);
configASSERT(block);
configASSERT(block->status != RBB_BLK_UNUSED);
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
/* remove it on rbb block list */
uxListRemove(&block->list);
block->status = RBB_BLK_UNUSED;
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);
}
/**
* get a continuous block to queue by given size
*
* tail head
* +------------------+---------------+--------+----------+--------+
* | block3 | empty1 | block1 | block2 |fragment|
* +------------------+------------------------+----------+--------+
* |<-- return_size -->| |
* |<--- queue_data_len --->|
*
* tail head
* +------------------+---------------+--------+----------+--------+
* | block3 | empty1 | block1 | block2 |fragment|
* +------------------+------------------------+----------+--------+
* |<-- return_size -->| out of len(b1+b2+b3) |
* |<-------------------- queue_data_len -------------------->|
*
* @param rbb ring block buffer object
* @param queue_data_len The max queue data size, and the return size must less then it.
* @param queue continuous block queue
*
* @return the block queue data total size
*/
size_t rbb_blk_queue_get(rbb_t rbb, size_t queue_data_len, rbb_blk_queue_t blk_queue)
{
UBaseType_t uxSavedInterruptStatus;
size_t data_total_size = 0;
ListItem_t *node;
rbb_blk_t last_block = NULL, block;
configASSERT(rbb);
configASSERT(blk_queue);
if (listLIST_IS_EMPTY(&rbb->blk_list))
return 0;
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
for (node = listGET_HEAD_ENTRY(&rbb->blk_list); node != listGET_END_MARKER(&rbb->blk_list);
node = listGET_NEXT(node))
{
if (!last_block)
{
last_block = listGET_LIST_ITEM_OWNER(node);
if (last_block->status == RBB_BLK_PUT)
{
/* save the first put status block to queue */
blk_queue->blocks = last_block;
blk_queue->blk_num = 0;
}
else
{
/* the first block must be put status */
last_block = NULL;
continue;
}
}
else
{
block = listGET_LIST_ITEM_OWNER(node);
/*
* these following conditions will break the loop:
* 1. the current block is not put status
* 2. the last block and current block is not continuous
* 3. the data_total_size will out of range
*/
if (block->status != RBB_BLK_PUT ||
last_block->buf > block->buf ||
data_total_size + block->size > queue_data_len)
{
break;
}
/* backup last block */
last_block = block;
}
/* remove current block */
uxListRemove(&last_block->list);
data_total_size += last_block->size;
last_block->status = RBB_BLK_GET;
blk_queue->blk_num++;
}
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);
return data_total_size;
}
/**
* get all block length on block queue
*
* @param blk_queue the block queue
*
* @return total length
*/
size_t rbb_blk_queue_len(rbb_blk_queue_t blk_queue)
{
size_t i, data_total_size = 0;
configASSERT(blk_queue);
for (i = 0; i < blk_queue->blk_num; i++)
{
data_total_size += blk_queue->blocks[i].size;
}
return data_total_size;
}
/**
* return the block queue buffer
*
* @param blk_queue the block queue
*
* @return block queue buffer
*/
uint8_t *rbb_blk_queue_buf(rbb_blk_queue_t blk_queue)
{
configASSERT(blk_queue);
return blk_queue->blocks[0].buf;
}
/**
* free the block queue
*
* @param rbb ring block buffer object
* @param blk_queue the block queue
*/
void rbb_blk_queue_free(rbb_t rbb, rbb_blk_queue_t blk_queue)
{
size_t i;
configASSERT(rbb);
configASSERT(blk_queue);
for (i = 0; i < blk_queue->blk_num; i++)
{
rbb_blk_free(rbb, &blk_queue->blocks[i]);
}
}
/**
* The put status and buffer continuous blocks can be make a block queue.
* This function will return the length which from next can be make block queue.
*
* @param rbb ring block buffer object
*
* @return the next can be make block queue's length
*/
size_t rbb_next_blk_queue_len(rbb_t rbb)
{
UBaseType_t uxSavedInterruptStatus;
size_t data_len = 0;
ListItem_t *node;
rbb_blk_t last_block = NULL, block;
configASSERT(rbb);
if (listLIST_IS_EMPTY(&rbb->blk_list))
return 0;
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
for (node = listGET_HEAD_ENTRY(&rbb->blk_list); node != listGET_END_MARKER(&rbb->blk_list);
node = listGET_NEXT(node))
{
if (!last_block)
{
last_block = listGET_LIST_ITEM_OWNER(node);
if (last_block->status != RBB_BLK_PUT)
{
/* the first block must be put status */
last_block = NULL;
continue;
}
}
else
{
block = listGET_LIST_ITEM_OWNER(node);
/*
* these following conditions will break the loop:
* 1. the current block is not put status
* 2. the last block and current block is not continuous
*/
if (block->status != RBB_BLK_PUT || last_block->buf > block->buf)
{
break;
}
/* backup last block */
last_block = block;
}
data_len += last_block->size;
}
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);
return data_len;
}
/**
* get the ring block buffer object buffer size
*
* @param rbb ring block buffer object
*
* @return buffer size
*/
size_t rbb_get_buf_size(rbb_t rbb)
{
configASSERT(rbb);
return rbb->buf_size;
}

View File

@ -0,0 +1,465 @@
#include "FreeRTOS.h"
#include "board.h"
#include "chip.h"
#ifdef VIDEO_DECODER_RN6752
#define RN6752_RST_GPIO 7
#define RN6752_SLAVE_ADDR (0x58 >> 1)
/*-----------------------------------------------------------*/
static int rn6752_i2c_write (struct i2c_adapter *adap, unsigned int addr, unsigned int data)
{
struct i2c_msg msg;
int ret = -1;
u8 retries = 0;
u8 buf[2];
buf[0] = (addr & 0xFF);
buf[1] = (data & 0xFF);
msg.flags = !I2C_M_RD;
msg.addr = RN6752_SLAVE_ADDR;
msg.len = sizeof(buf);
msg.buf = buf;
while(retries < 5)
{
ret = i2c_transfer(adap, &msg, 1);
if (ret == 1)
break;
retries++;
}
if (retries >= 5)
{
printf("%s timeout\n", __FUNCTION__);
return -1;
}
return 0;
}
/* static unsigned int rn6752_i2c_read(struct i2c_adapter *adap, unsigned int addr)
{
struct i2c_msg msgs[2];
int retries = 0;
int ret = -1;
u8 buf;
buf = addr & 0xFF;
msgs[0].flags = !I2C_M_RD;
msgs[0].addr = RN6752_SLAVE_ADDR;
msgs[0].len = 1;
msgs[0].buf = &buf;
msgs[1].flags = I2C_M_RD;
msgs[1].addr = RN6752_SLAVE_ADDR;
msgs[1].len = 1;
msgs[1].buf = &buf;
while(retries < 5)
{
ret = i2c_transfer(adap, msgs, 2);
if(ret == 2)
break;
retries++;
}
if (retries >= 5)
{
printf( "%s timeout\n", __FUNCTION__);
return 0;
}
return buf;
} */
static void rn6752_reset(void)
{
gpio_direction_output(RN6752_RST_GPIO, 1);
vTaskDelay(10);
gpio_direction_output(RN6752_RST_GPIO, 0);
vTaskDelay(10);
gpio_direction_output(RN6752_RST_GPIO, 1);
vTaskDelay(100);
}
typedef struct _RXCCHIPstaticPara
{
unsigned int addr;
unsigned int dat;
} RXCHIPstaticPara;
#if VIDEO_IN_FORMAT == VIN_AHD_720P_25
const RXCHIPstaticPara rn6752m_720p_25_staticPara[]=
{
//RN6752M-601-720P(°üÀ¨Í¬Öá¿ØÖÆ)
// 720P@25 BT601
// Slave address is 0x58
// Register, data
// if clock source(Xin) of RN6752 is 26MHz, please add these procedures marked first
//0xD2, 0x85, // disable auto clock detect
//0xD6, 0x37, // 27MHz default
//0xD8, 0x18, // switch to 26MHz clock
//delay(100), // delay 100ms
{0x81, 0x01}, // turn on video decoder
{0xA3, 0x04},
{0xDF, 0xFE}, // enable HD format
{0x88, 0x40}, // disable SCLK0B out
{0xF6, 0x40}, // disable SCLK3A out
// ch0
{0xFF, 0x00}, // switch to ch0 (default; optional)
{0x2C, 0x30},
{0x2D, 0xF0},
{0x00, 0x20}, // internal use*
{0x06, 0x08}, // internal use*
{0x07, 0x63}, // HD format
{0x2A, 0x01}, // filter control
{0x3A, 0x00}, // No Insert Channel ID in SAV/EAV code
{0x3F, 0x10}, // channel ID
{0x4C, 0x37}, // equalizer
{0x4F, 0x03}, // sync control
{0x50, 0x02}, // 720p resolution
{0x56, 0x05}, // BT 72M mode and BT601 mode
{0x5F, 0x40}, // blank level
{0x63, 0xF5}, // filter control
{0x59, 0x00}, // extended register access
{0x5A, 0x42}, // data for extended register
{0x58, 0x01}, // enable extended register write
{0x59, 0x33}, // extended register access
{0x5A, 0x23}, // data for extended register
{0x58, 0x01}, // enable extended register write
{0x51, 0xE1}, // scale factor1
{0x52, 0x88}, // scale factor2
{0x53, 0x12}, // scale factor3
{0x5B, 0x07}, // H-scaling control
{0x5E, 0x08}, // enable H-scaling control
{0x6A, 0x82}, // H-scaling control
{0x28, 0x92}, // cropping
{0x01, 0x08}, // brightness
{0x02, 0x80}, // contrast
{0x03, 0x80}, // saturation
{0x04, 0x80}, // hue
{0x05, 0x03}, // sharpness
{0x09, 0xC8}, // EQ
{0x34, 0x02}, // OB
{0x57, 0x15}, // black/white stretch
{0x68, 0x32}, // coring
{0x00, 0x20}, // internal use*
{0x0D, 0x20}, // cagc initial value
//{0x2D, 0xF2}, // cagc adjust
{0x37, 0X33},
{0x61, 0X6C},
//{0x30, 0X30},// V30H_0836_NEW
//{0x0d, 0X50},
//{0x3A, 0x04},
//{0x3E, 0x32},
{0x3A, 0x02},//P-MOS
{0x3E, 0xf6},//ͬÖáÓ³Éäµ½AVID½Å
{0x40, 0x04},
{0x46, 0x23},
{0x47, 0x30},
//{0x49, 0x84},//85
{0x6d, 0x00},
{0x8E, 0x00}, // single channel output for VP
{0x8F, 0x80}, // 720p mode for VP
{0x8D, 0x31}, // enable VP out
{0x89, 0x09}, // select 72MHz for SCLK
{0x88, 0x41}, // enable SCLK out
{0x96, 0x00}, // select AVID & VBLK as status indicator
{0x97, 0x0B}, // enable status indicator out on AVID,VBLK & VSYNC
{0x98, 0x00}, // video timing pin status
{0x9A, 0x40}, // select AVID & VBLK as status indicator
{0x9B, 0xE1}, // enable status indicator out on HSYNC
{0x9C, 0x00}, // video timing pin status
//{0x00, 0xC0},//test bar color
};
#endif
#if VIDEO_IN_FORMAT == VIN_AHD_720P_30
const RXCHIPstaticPara rn6752m_720p_30_staticPara[]=
{
// 720P@30 BT601
// Slave address is 0x58
// Register, data
// if clock source(Xin) of RN6752 is 26MHz, please add these procedures marked first
//0xD2, 0x85, // disable auto clock detect
//0xD6, 0x37, // 27MHz default
//0xD8, 0x18, // switch to 26MHz clock
//delay(100), // delay 100ms
0x49,0x01,
0x19,0x07,
0x81, 0x01, // turn on video decoder
0xA3, 0x04,
0xDF, 0xFE, // enable HD format
0x88, 0x40, // disable SCLK0B out
0xF6, 0x40, // disable SCLK3A out
// ch0
0xFF, 0x00, // switch to ch0 (default; optional)
0x00, 0x20, // internal use*
0x06, 0x08, // internal use*
0x07, 0x63, // HD format
0x2A, 0x01, // filter control
0x3A, 0x00, // No Insert Channel ID in SAV/EAV code
0x3F, 0x10, // channel ID
0x4C, 0x37, // equalizer
0x4F, 0x03, // sync control
0x50, 0x02, // 720p resolution
0x56, 0x05, // BT 72M mode and BT601 mode
0x5F, 0x40, // blank level
0x63, 0xF5, // filter control
0x59, 0x00, // extended register access
0x5A, 0x44, // data for extended register
0x58, 0x01, // enable extended register write
0x59, 0x33, // extended register access
0x5A, 0x23, // data for extended register
0x58, 0x01, // enable extended register write
0x51, 0xE1, // scale factor1
0x52, 0x88, // scale factor2
0x53, 0x12, // scale factor3
0x5B, 0x07, // H-scaling control
0x5E, 0x0B, // enable H-scaling control
0x6A, 0x82, // H-scaling control
0x28, 0x92, // cropping
0x03, 0x80, // saturation
0x04, 0x80, // hue
0x05, 0x00, // sharpness
0x57, 0x23, // black/white stretch
0x68, 0x32, // coring
0x3A, 0x04,
0x3E, 0x32,
0x40, 0x04,
0x46, 0x23,
0x8E, 0x00, // single channel output for VP
0x8F, 0x80, // 720p mode for VP
0x8D, 0x31, // enable VP out
0x89, 0x09, // select 72MHz for SCLK
0x88, 0x41, // enable SCLK out
0XD3,0X00,//channel 0 0x00 channel 1 0X01
0x96, 0x00, // select AVID & VBLK as status indicator
0x97, 0x0B, // enable status indicator out on AVID,VBLK & VSYNC
0x98, 0x00, // video timing pin status
0x9A, 0x40, // select AVID & VBLK as status indicator
0x9B, 0xE1, // enable status indicator out on HSYNC
0x9C, 0x00, // video timing pin status
};
#endif
#if VIDEO_IN_FORMAT == VIN_CVBS_NTSC
const RXCHIPstaticPara rn6752m_cvbs_ntsc_staticPara[]=
{
// if clock source(Xin) of RN6752 is 26MHz, please add these procedures marked first
//0xD2, 0x85, // disable auto clock detect
//0xD6, 0x37, // 27MHz default
//0xD8, 0x18, // switch to 26MHz clock
//delay(100), // delay 100ms
0x81, 0x01, // turn on video decoder
0xA3, 0x00,
0xDF, 0xFF, // enable CVBS format
// ch0
0xFF, 0x00, // switch to ch0 (default; optional)
0x00, 0x00, // internal use*
0x06, 0x08, // internal use*
0x07, 0x63, // HD format
0x2A, 0x81, // filter control
0x3A, 0x00, // No Insert Channel ID in SAV/EAV code
0x3F, 0x10, // channel ID
0x4C, 0x37, // equalizer
0x4F, 0x00, // sync control
0x50, 0x00, // D1 resolution
0x56, 0x04, // 27M mode and BT601 mode
0x5F, 0x00, // blank level
0x63, 0x75, // filter control
0x59, 0x00, // extended register access
0x5A, 0x00, // data for extended register
0x58, 0x01, // enable extended register write
0x59, 0x33, // extended register access
0x5A, 0x02, // data for extended register
0x58, 0x01, // enable extended register write
0x5B, 0x00, // H-scaling control
0x5E, 0x01, // enable H-scaling control
0x6A, 0x00, // H-scaling control
0x28, 0xB2, // cropping
0x20, 0x24,
0x23, 0x11,
0x24, 0x05,
0x25, 0x11,
0x26, 0x00,
0x42, 0x00,
0x03, 0x80, // saturation
0x04, 0x80, // hue
0x05, 0x03, // sharpness
0x57, 0x20, // black/white stretch
0x68, 0x32, // coring
0x3A, 0x04,
0x3E, 0x32,
0x40, 0x04,
0x46, 0x23,
0x8E, 0x00, // single channel output for VP
0x8F, 0x00, // D1 mode for VP
0x8D, 0x31, // enable VP out
0x89, 0x00, // select 27MHz for SCLK
0x88, 0x41, // enable SCLK out
0x96, 0x00, // select AVID & VBLK as status indicator
0x97, 0x0B, // enable status indicator out on AVID,VBLK & VSYNC
0x98, 0x00, // video timing pin status
0x9A, 0x40, // select AVID & VBLK as status indicator
0x9B, 0xE1, // enable status indicator out on HSYNC
0x9C, 0x00, // video timing pin status
};
#endif
#if VIDEO_IN_FORMAT == VIN_CVBS_PAL
const RXCHIPstaticPara rn6752m_cvbs_pal_staticPara[]=
{
// cvbs@25 BT601
// Slave address is 0x58
// Register, data
// if clock source(Xin) of RN6752 is 26MHz, please add these procedures marked first
//0xD2, 0x85, // disable auto clock detect
//0xD6, 0x37, // 27MHz default
//0xD8, 0x18, // switch to 26MHz clock
//delay(100), // delay 100ms
0x49,0x01,
0x19,0x07,
0x81, 0x01, // turn on video decoder
0xA3, 0x04,
0xDF, 0x0F, // enable CVBS format
0x88, 0x40, // disable SCLK0B out
0xF6, 0x40, // disable SCLK3A out
// ch0
0xFF, 0x00, // switch to ch0 (default; optional)
0x00, 0x00, // internal use*
0x06, 0x08, // internal use*
0x07, 0x62, // HD format
0x2A, 0x81, // filter control
0x3A, 0x00, // No Insert Channel ID in SAV/EAV code
0x3F, 0x10, // channel ID
0x4C, 0x37, // equalizer
0x4F, 0x00, // sync control
0x50, 0x00, // 720p resolution
0x56, 0x05, // 72M mode and BT601 mode
0x5F, 0x00, // blank level
0x63, 0x75, // filter control
0x59, 0x00, // extended register access
0x5A, 0x00, // data for extended register
0x58, 0x01, // enable extended register write
0x59, 0x33, // extended register access
0x5A, 0x02, // data for extended register
0x58, 0x01, // enable extended register write
0x5B, 0x00, // H-scaling control
0x5E, 0x01, // enable H-scaling control
0x6A, 0x00, // H-scaling control
0x28, 0xB2, // cropping
0x20, 0x24,
0x23, 0x17,
0x24, 0x37,
0x25, 0x17,
0x26, 0x00,
0x42, 0x00,
0x03, 0x80, // saturation
0x04, 0x80, // hue
0x05, 0x03, // sharpness
0x57, 0x20, // black/white stretch
0x68, 0x32, // coring
0x3A, 0x04,
0x3E, 0x32,
0x40, 0x04,
0x46, 0x23,
0x8E, 0x00, // single channel output for VP
0x8F, 0x80, // 720p mode for VP
0x8D, 0x31, // enable VP out
0x89, 0x09, // select 72MHz for SCLK
0x88, 0x41, // enable SCLK out
0x96, 0x00, // select AVID & VBLK as status indicator
0x97, 0x0B, // enable status indicator out on AVID,VBLK & VSYNC
0x98, 0x00, // video timing pin status
0x9A, 0x40, // select AVID & VBLK as status indicator
0x9B, 0xE1, // enable status indicator out on HSYNC
0x9C, 0x00, // video timing pin status
};
#endif
static void rn6752_config(struct i2c_adapter *adap)
{
int i;
//int val;
#if VIDEO_IN_FORMAT == VIN_CVBS_PAL
for (i = 0; i < sizeof(rn6752m_cvbs_pal_staticPara) / sizeof(RXCHIPstaticPara); i++)
{
rn6752_i2c_write(adap, rn6752m_cvbs_pal_staticPara[i].addr,
rn6752m_cvbs_pal_staticPara[i].dat);
}
#elif VIDEO_IN_FORMAT == VIN_CVBS_NTSC
for (i = 0; i < sizeof(rn6752m_cvbs_ntsc_staticPara) / sizeof(RXCHIPstaticPara); i++)
{
rn6752_i2c_write(adap, rn6752m_cvbs_ntsc_staticPara[i].addr,
rn6752m_cvbs_ntsc_staticPara[i].dat);
}
#elif VIDEO_IN_FORMAT == VIN_AHD_720P_25
for (i = 0; i < sizeof(rn6752m_720p_25_staticPara) / sizeof(RXCHIPstaticPara); i++)
{
rn6752_i2c_write(adap, rn6752m_720p_25_staticPara[i].addr,
rn6752m_720p_25_staticPara[i].dat);
}
#elif VIDEO_IN_FORMAT == VIN_AHD_720P_30
for (i = 0; i < sizeof(rn6752m_720p_30_staticPara) / sizeof(RXCHIPstaticPara); i++)
{
rn6752_i2c_write(adap, rn6752m_720p_30_staticPara[i].addr,
rn6752m_720p_30_staticPara[i].dat);
}
#endif
}
int rn6752_init(void)
{
struct i2c_adapter *adap = NULL;
rn6752_reset();
if (!(adap = i2c_open("i2c1"))) {
printf("open i2c1 fail.\n");
return -1;
}
rn6752_config(adap);
return 0;
}
#endif

View File

@ -0,0 +1,426 @@
#include <stdio.h>
#include <string.h>
#include "FreeRTOS.h"
#include "chip.h"
#include "board.h"
#include "sfud.h"
#include "updatefile.h"
#include "romfile.h"
#if DEVICE_TYPE_SELECT == EMMC_FLASH
#include "mmcsd_core.h"
#endif
static RomHeader *romheader = NULL;
static SemaphoreHandle_t romfileMutex;
#ifndef ROMFILE_USE_SMALL_MEM
#ifndef READ_ROMFILE_ONCE
static unsigned char *filestatus;
static uint32_t romoffset;
#endif
#else
static uint32_t romoffset;
#if ROMFILE_CACHE_DEF_SIZE
#define ROMFILE_CACHE_LIFE_LIMIT 1000000
static RomFileCache *romfilecache;
#endif
#endif
int ReadRomFile(void)
{
uint32_t offset = GetUpFileOffset(MKTAG('R', 'O', 'M', 'A'));
uint32_t size = GetUpFileSize(MKTAG('R', 'O', 'M', 'A'));
romfileMutex = xSemaphoreCreateMutex();
xSemaphoreTake(romfileMutex, portMAX_DELAY);
if (size > 0) {
#if DEVICE_TYPE_SELECT != EMMC_FLASH
sfud_flash *sflash = sfud_get_device(0);
#endif
#ifndef ROMFILE_USE_SMALL_MEM
void *rombuf = pvPortMalloc(size);
if (rombuf) {
#if DEVICE_TYPE_SELECT != EMMC_FLASH
#ifdef READ_ROMFILE_ONCE
sfud_read(sflash, offset, size, rombuf);
#else
sfud_read(sflash, offset, sizeof(RomHeader), rombuf);
romoffset = offset;
#endif
#else
#ifdef READ_ROMFILE_ONCE
emmc_read(offset, size, rombuf);
#else
emmc_read(offset, sizeof(RomHeader), rombuf);
romoffset = offset;
#endif
#endif
romheader = rombuf;
if (romheader->magic != MKTAG('R', 'O', 'M', 'A')) {
printf("Read rom file error!\n");
vPortFree(rombuf);
xSemaphoreGive(romfileMutex);
return -1;
}
#ifdef READ_ROMFILE_ONCE
CP15_clean_dcache_for_dma((uint32_t)rombuf, (uint32_t)rombuf + size);
#else
int files = romheader->filenum;
#if DEVICE_TYPE_SELECT != EMMC_FLASH
sfud_read(sflash, offset + sizeof(RomHeader), sizeof(RomFileInfo) * files,
(unsigned char*)rombuf + sizeof(RomHeader));
#else
emmc_read(offset + sizeof(RomHeader), sizeof(RomFileInfo) * files,
(unsigned char*)rombuf + sizeof(RomHeader));
#endif
filestatus = pvPortMalloc(files * sizeof(*filestatus));
if (!filestatus) {
printf("filestatus malloc fail.\n");
vPortFree(rombuf);
xSemaphoreGive(romfileMutex);
return -1;
}
memset(filestatus, 0, files * sizeof(*filestatus));
CP15_clean_dcache_for_dma((uint32_t)rombuf, (uint32_t)rombuf + sizeof(RomHeader) +
sizeof(RomFileInfo) * files);
#endif
} else {
printf("Error! No enough memory for romfile.\n");
xSemaphoreGive(romfileMutex);
return -1;
}
#else
RomHeader header;
#if DEVICE_TYPE_SELECT != EMMC_FLASH
sfud_read(sflash, offset, sizeof(RomHeader), (void*)&header);
#else
emmc_read(offset, sizeof(RomHeader), (void*)&header);
#endif
romoffset = offset;
romheader = pvPortMalloc(sizeof(RomHeader) + sizeof(RomFileInfo) * header.filenum);
if (romheader == NULL) {
printf("Error! No enough memory for romheader.\n");
xSemaphoreGive(romfileMutex);
return -1;
}
memcpy(romheader, &header, sizeof(RomHeader));
#if DEVICE_TYPE_SELECT != EMMC_FLASH
sfud_read(sflash, offset + sizeof(RomHeader), sizeof(RomFileInfo) * header.filenum,
(unsigned char*)romheader + sizeof(RomHeader));
#else
emmc_read(offset + sizeof(RomHeader), sizeof(RomFileInfo) * header.filenum,
(unsigned char*)romheader + sizeof(RomHeader));
#endif
CP15_clean_dcache_for_dma((uint32_t)romheader, (uint32_t)romheader + sizeof(RomHeader) +
sizeof(RomFileInfo) * header.filenum);
#if ROMFILE_CACHE_DEF_SIZE
romfilecache = pvPortMalloc(sizeof(RomFileCache) * ROMFILE_CACHE_DEF_SIZE);
if (romfilecache == NULL) {
printf("Error! No enough memory for romfile cache.\n");
xSemaphoreGive(romfileMutex);
return -1;
}
memset(romfilecache, 0, sizeof(RomFileCache) * ROMFILE_CACHE_DEF_SIZE);
#endif
#endif
} else {
printf("Warning! Not found romfile in update file.\n");
xSemaphoreGive(romfileMutex);
return -1;
}
xSemaphoreGive(romfileMutex);
return 0;
}
RomFile *RomFileOpen(const char *name)
{
int i;
xSemaphoreTake(romfileMutex, portMAX_DELAY);
for (i = 0; i < romheader->filenum; i++) {
if (!strcmp(romheader->files[i].name, name)) {
RomFile *file = pvPortMalloc(sizeof(RomFile));
if (!file) {
xSemaphoreGive(romfileMutex);
return NULL;
}
memset(file, 0, sizeof(RomFile));
file->index = i;
#ifndef ROMFILE_USE_SMALL_MEM
file->buf = (void*)((uint32_t)romheader + romheader->files[i].offset);
#endif
file->size = romheader->files[i].size;
xSemaphoreGive(romfileMutex);
return file;
}
}
xSemaphoreGive(romfileMutex);
return NULL;
}
size_t RomFileRead(RomFile *file, void *buf, size_t size)
{
#if ROMFILE_CACHE_DEF_SIZE
int i;
#endif
if (!file) return 0;
if (size > file->size - file->pos)
size = file->size - file->pos;
if(size == 0)
return 0;
xSemaphoreTake(romfileMutex, portMAX_DELAY);
#ifndef ROMFILE_USE_SMALL_MEM
#ifndef READ_ROMFILE_ONCE
if (!filestatus[file->index]) {
#if DEVICE_TYPE_SELECT != EMMC_FLASH
sfud_flash *sflash = sfud_get_device(0);
sfud_read(sflash, romoffset + romheader->files[file->index].offset, file->size, file->buf);
#else
emmc_read(romoffset + romheader->files[file->index].offset, file->size, file->buf);
#endif
CP15_clean_dcache_for_dma((uint32_t)file->buf, (uint32_t)file->buf + file->size);
filestatus[file->index] = 1;
}
#endif
#else
#if ROMFILE_CACHE_DEF_SIZE
if (!file->cache) {
for (i = 0; i < ROMFILE_CACHE_DEF_SIZE; i++) {
if(!strcmp(romfilecache[i].name, romheader->files[file->index].name)) {
configASSERT(romfilecache[i].buf);
file->buf = romfilecache[i].buf;
file->cache = &romfilecache[i];
romfilecache[i].cached_filenum++;
romfilecache[i].life++;
if (romfilecache[i].life > ROMFILE_CACHE_LIFE_LIMIT)
romfilecache[i].life = ROMFILE_CACHE_LIFE_LIMIT;
}
}
}
for (i = 0; i < ROMFILE_CACHE_DEF_SIZE; i++) {
if(romfilecache[i].life > INT32_MIN + 1)
romfilecache[i].life -= 1;
}
#endif
if (!file->cache) {
#if DEVICE_TYPE_SELECT != EMMC_FLASH
sfud_flash *sflash = sfud_get_device(0);
#endif
#if ROMFILE_CACHE_DEF_SIZE
RomFileCache *cachefile = NULL;
uint32_t stime;
int i;
for (i = 0; i < ROMFILE_CACHE_DEF_SIZE; i++) {
if (romfilecache[i].name[0] == 0) {
cachefile = &romfilecache[i];
break;
}
}
if (!cachefile) {
for (i = 0; i < ROMFILE_CACHE_DEF_SIZE; i++) {
if (romfilecache[i].cached_filenum == 0) {
cachefile = &romfilecache[i];
break;
}
}
if (cachefile) {
for(i = i + 1; i < ROMFILE_CACHE_DEF_SIZE; i++) {
if (romfilecache[i].cached_filenum == 0 &&
romfilecache[i].life < cachefile->life)
cachefile = &romfilecache[i];
}
}
}
if (cachefile) {
int filelife;
file->buf = pvPortMalloc(romheader->files[file->index].size);
if (!file->buf) {
printf("ERROR! No enough memory for opening romfile.\n");
vPortFree(file);
xSemaphoreGive(romfileMutex);
return 0;
}
stime = get_timer(0);
#if DEVICE_TYPE_SELECT != EMMC_FLASH
sfud_read(sflash, romoffset + romheader->files[file->index].offset, file->size, file->buf);
#else
emmc_read(romoffset + romheader->files[file->index].offset, file->size, file->buf);
#endif
CP15_clean_dcache_for_dma((uint32_t)file->buf, (uint32_t)file->buf + file->size);
filelife = get_timer(stime);
if (cachefile->buf)
vPortFree(cachefile->buf);
strncpy(cachefile->name, romheader->files[file->index].name, ROMFILE_NAME_MAX_LEN);
cachefile->buf = file->buf;
cachefile->cached_filenum = 1;
cachefile->life = filelife;
if (cachefile->life > ROMFILE_CACHE_LIFE_LIMIT)
cachefile->life = ROMFILE_CACHE_LIFE_LIMIT;
file->cache = cachefile;
} else
#endif
{
file->buf = pvPortMalloc(size);
if (!file->buf) {
printf("ERROR! No enough memory for opening romfile.\n");
vPortFree(file);
xSemaphoreGive(romfileMutex);
return 0;
}
#if DEVICE_TYPE_SELECT != EMMC_FLASH
sfud_read(sflash, romoffset + romheader->files[file->index].offset + file->pos,
size, file->buf);
#else
emmc_read(romoffset + romheader->files[file->index].offset + file->pos,
size, file->buf);
#endif
CP15_clean_dcache_for_dma((uint32_t)file->buf, (uint32_t)file->buf + size);
}
}
#endif
if (buf) {
#ifdef ROMFILE_USE_SMALL_MEM
if (!file->cache) {
memcpy(buf, (char *)file->buf, size);
vPortFree(file->buf);
file->buf = NULL;
} else {
#endif
memcpy(buf, (char *)file->buf + file->pos, size);
#ifdef ROMFILE_USE_SMALL_MEM
}
#endif
}
file->pos += size;
xSemaphoreGive(romfileMutex);
return size;
}
int RomFileSeek(RomFile *file, int offset, int whence)
{
if (!file) return -1;
xSemaphoreTake(romfileMutex, portMAX_DELAY);
if (whence == SEEK_SET)
file->pos = offset;
else if (whence == SEEK_CUR)
file->pos += offset;
else if (whence == SEEK_END)
file->pos = file->size - 1 + offset;
if (file->pos >= file->size)
file->pos = file->size - 1;
else if (file->pos < 0)
file->pos = 0;
xSemaphoreGive(romfileMutex);
return file->pos;
}
void RomFileClose(RomFile *file)
{
xSemaphoreTake(romfileMutex, portMAX_DELAY);
if (file) {
#ifdef ROMFILE_USE_SMALL_MEM
#if ROMFILE_CACHE_DEF_SIZE
if (file->cache) {
file->cache->cached_filenum--;
} else {
#endif
if (file->buf)
vPortFree(file->buf);
#if ROMFILE_CACHE_DEF_SIZE
}
#endif
#endif
vPortFree(file);
}
xSemaphoreGive(romfileMutex);
}
/**
* Return with the extension of the filename
* @param fn string with a filename
* @return pointer to the beginning extension or empty string if no extension
*/
const char * RomFileGetExt(const char * path)
{
size_t i;
for(i = strlen(path); i > 0; i--) {
if(path[i] == '.') {
return &path[i + 1];
}
else if(path[i] == '/' || path[i] == '\\') {
return ""; /*No extension if a '\' or '/' found*/
}
}
return ""; /*Empty string if no '.' in the file name. */
}
int RomFileTell(RomFile *file)
{
return file->pos;
}
int RomFileGetSize(RomFile *file)
{
return file->size;
}
int RomFileExist(const char *name)
{
int i;
for (i = 0; i < romheader->filenum; i++) {
if (!strcmp(romheader->files[i].name, name)) {
return 1;
}
}
return 0;
}
int RomFileDirExist(const char *name)
{
int i;
int len = strlen(name);
for (i = 0; i < romheader->filenum; i++) {
if (!strncmp(romheader->files[i].name, name, len) &&
romheader->files[i].name[len] == '/') {
return 1;
}
}
return 0;

View File

@ -0,0 +1,376 @@
/*
* ST7701S LCD Display.
*
* LCD Type: AMT TFT
* Display Format: 320(RGB)*960
* Input Data: RGB 16bits(RGB565)
*/
#include "FreeRTOS.h"
#include "board.h"
#include "chip.h"
//3 lines mode spi.
#define ST7701S_GPIO_SPI_CS 23
#define ST7701S_GPIO_SPI_SCL 24
#define ST7701S_GPIO_SPI_SDA 25
#define ST7701S_GPIO_SPI_RST 26
#define ST7701S_DELAY udelay(5)
static void SPI_SendData(unsigned char value)
{
int i;
for(i=0; i<8; i++)
{
if(value & 0x80)
gpio_direction_output(ST7701S_GPIO_SPI_SDA, 1); //SDA=1
else
gpio_direction_output(ST7701S_GPIO_SPI_SDA, 0); //SDA=0
value<<= 1;
gpio_direction_output(ST7701S_GPIO_SPI_SCL, 0); //SCL=0
ST7701S_DELAY;
gpio_direction_output(ST7701S_GPIO_SPI_SCL, 1); //SCL=1
ST7701S_DELAY;
}
}
static void SPI_WriteComm(unsigned char value)
{
gpio_direction_output(ST7701S_GPIO_SPI_CS, 0); //CS=0
//D/CX = 0
gpio_direction_output(ST7701S_GPIO_SPI_SDA, 0); //SDA=0
gpio_direction_output(ST7701S_GPIO_SPI_SCL, 0); //SCL=0
ST7701S_DELAY;
gpio_direction_output(ST7701S_GPIO_SPI_SCL, 1); //SCL=1
ST7701S_DELAY;
//Command data.
SPI_SendData(value);
gpio_direction_output(ST7701S_GPIO_SPI_CS, 1); //CS=1
ST7701S_DELAY;
}
static void SPI_WriteData(unsigned char value)
{
gpio_direction_output(ST7701S_GPIO_SPI_CS, 0); //CS=0
//D/CX = 1
gpio_direction_output(ST7701S_GPIO_SPI_SDA, 1); //SDA=1
gpio_direction_output(ST7701S_GPIO_SPI_SCL, 0); //SCL=0
ST7701S_DELAY;
gpio_direction_output(ST7701S_GPIO_SPI_SCL, 1); //SCL=1
ST7701S_DELAY;
//Parameter data.
SPI_SendData(value);
gpio_direction_output(ST7701S_GPIO_SPI_CS, 1); //CS=1
ST7701S_DELAY;
}
static void st7701s_reg_init(void)
{
SPI_WriteComm (0xFF);
SPI_WriteData (0x77);
SPI_WriteData (0x01);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0x13);
SPI_WriteComm (0xEF);
SPI_WriteData (0x08);
SPI_WriteComm (0xFF);
SPI_WriteData (0x77);
SPI_WriteData (0x01);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0x10);
SPI_WriteComm (0xC0);
SPI_WriteData (0x77);
SPI_WriteData (0x00);
SPI_WriteComm (0xC1); //proch control.
SPI_WriteData (0x09); //vbp
SPI_WriteData (0x08); //vfp
SPI_WriteComm (0xC2); //inv
#if 0
SPI_WriteData (0x01);
#else
SPI_WriteData (0x07);
#endif
SPI_WriteData (0x02);
//default:0x00, DE mode.
SPI_WriteComm (0xC3); //RGB control.
SPI_WriteData (0x02); //82 HVmode 02 DEmode
#if 0 //default:0x00
SPI_WriteComm (0xC7); //add. Source direction control.
SPI_WriteData (0x04); //0x00:Source form 0 to 479, 0x04:from 479 to 0.
#endif
SPI_WriteComm (0xCC);
SPI_WriteData (0x10);
SPI_WriteComm (0xB0);
SPI_WriteData (0x40);
SPI_WriteData (0x14);
SPI_WriteData (0x59);
SPI_WriteData (0x10);
SPI_WriteData (0x12);
SPI_WriteData (0x08);
SPI_WriteData (0x03);
SPI_WriteData (0x09);
SPI_WriteData (0x05);
SPI_WriteData (0x1E);
SPI_WriteData (0x05);
SPI_WriteData (0x14);
SPI_WriteData (0x10);
SPI_WriteData (0x68);
SPI_WriteData (0x33);
SPI_WriteData (0x15);
SPI_WriteComm (0xB1);
SPI_WriteData (0x40);
SPI_WriteData (0x08);
SPI_WriteData (0x53);
SPI_WriteData (0x09);
SPI_WriteData (0x11);
SPI_WriteData (0x09);
SPI_WriteData (0x02);
SPI_WriteData (0x07);
SPI_WriteData (0x09);
SPI_WriteData (0x1A);
SPI_WriteData (0x04);
SPI_WriteData (0x12);
SPI_WriteData (0x12);
SPI_WriteData (0x64);
SPI_WriteData (0x29);
SPI_WriteData (0x29);
SPI_WriteComm (0xFF);
SPI_WriteData (0x77);
SPI_WriteData (0x01);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0x11);
SPI_WriteComm (0xB0);
SPI_WriteData (0x6D); //6D
SPI_WriteComm (0xB1); //vcom
SPI_WriteData (0x1D);
SPI_WriteComm (0xB2);
SPI_WriteData (0x87);
SPI_WriteComm (0xB3);
SPI_WriteData (0x80);
SPI_WriteComm (0xB5);
SPI_WriteData (0x49);
SPI_WriteComm (0xB7);
SPI_WriteData (0x85);
SPI_WriteComm (0xB8);
SPI_WriteData (0x20);
SPI_WriteComm (0xC1);
SPI_WriteData (0x78);
SPI_WriteComm (0xC2);
SPI_WriteData (0x78);
SPI_WriteComm (0xD0);
SPI_WriteData (0x88);
SPI_WriteComm (0xE0);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0x02);
SPI_WriteComm (0xE1);
SPI_WriteData (0x02);
SPI_WriteData (0x8C);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0x03);
SPI_WriteData (0x8C);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0x33);
SPI_WriteData (0x33);
SPI_WriteComm (0xE2);
SPI_WriteData (0x33);
SPI_WriteData (0x33);
SPI_WriteData (0x33);
SPI_WriteData (0x33);
SPI_WriteData (0xC9);
SPI_WriteData (0x3C);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0xCA);
SPI_WriteData (0x3C);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteComm (0xE3);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0x33);
SPI_WriteData (0x33);
SPI_WriteComm (0xE4);
SPI_WriteData (0x44);
SPI_WriteData (0x44);
SPI_WriteComm (0xE5);
SPI_WriteData (0x05);
SPI_WriteData (0xCD);
SPI_WriteData (0x82);
SPI_WriteData (0x82);
SPI_WriteData (0x01);
SPI_WriteData (0xC9);
SPI_WriteData (0x82);
SPI_WriteData (0x82);
SPI_WriteData (0x07);
SPI_WriteData (0xCF);
SPI_WriteData (0x82);
SPI_WriteData (0x82);
SPI_WriteData (0x03);
SPI_WriteData (0xCB);
SPI_WriteData (0x82);
SPI_WriteData (0x82);
SPI_WriteComm (0xE6);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0x33);
SPI_WriteData (0x33);
SPI_WriteComm (0xE7);
SPI_WriteData (0x44);
SPI_WriteData (0x44);
SPI_WriteComm (0xE8);
SPI_WriteData (0x06);
SPI_WriteData (0xCE);
SPI_WriteData (0x82);
SPI_WriteData (0x82);
SPI_WriteData (0x02);
SPI_WriteData (0xCA);
SPI_WriteData (0x82);
SPI_WriteData (0x82);
SPI_WriteData (0x08);
SPI_WriteData (0xD0);
SPI_WriteData (0x82);
SPI_WriteData (0x82);
SPI_WriteData (0x04);
SPI_WriteData (0xCC);
SPI_WriteData (0x82);
SPI_WriteData (0x82);
SPI_WriteComm (0xEB);
SPI_WriteData (0x08);
SPI_WriteData (0x01);
SPI_WriteData (0xE4);
SPI_WriteData (0xE4);
SPI_WriteData (0x88);
SPI_WriteData (0x00);
SPI_WriteData (0x40);
SPI_WriteComm (0xEC);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteComm (0xED);
SPI_WriteData (0xFF);
SPI_WriteData (0xF0);
SPI_WriteData (0x07);
SPI_WriteData (0x65);
SPI_WriteData (0x4F);
SPI_WriteData (0xFC);
SPI_WriteData (0xC2);
SPI_WriteData (0x2F);
SPI_WriteData (0xF2);
SPI_WriteData (0x2C);
SPI_WriteData (0xCF);
SPI_WriteData (0xF4);
SPI_WriteData (0x56);
SPI_WriteData (0x70);
SPI_WriteData (0x0F);
SPI_WriteData (0xFF);
SPI_WriteComm (0xEF);
SPI_WriteData (0x10);
SPI_WriteData (0x0D);
SPI_WriteData (0x04);
SPI_WriteData (0x08);
SPI_WriteData (0x3F);
SPI_WriteData (0x1F);
SPI_WriteComm (0xFF);
SPI_WriteData (0x77);
SPI_WriteData (0x01);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
mdelay(114); //Sleep out cmd cannot be send after hw-reset for 120ms.
SPI_WriteComm (0x11); //sleep out.
SPI_WriteComm (0x35);
SPI_WriteData (0x00);
#if 0
SPI_WriteComm (0x36); //
SPI_WriteData (0x10); //bit4(0:normal scan, 1:inverse scan); bit3(0:RGB, 1:BGR), default:0x00
#endif
SPI_WriteComm (0x3A); //RGB Interface pixel format.
SPI_WriteData (0x77); //bit[4-6](101:16-bit/pixel; 110:18-bit/pixel;111:24-bit/pixel), default:0x70
//SPI_WriteComm (0x11);
//Delay(120);
SPI_WriteComm (0x29); //display on.
}
static void st7701s_hw_reset(void)
{
gpio_direction_output(ST7701S_GPIO_SPI_RST, 1);
mdelay(10);
gpio_direction_output(ST7701S_GPIO_SPI_RST, 0);
mdelay(1); //>=9us
gpio_direction_output(ST7701S_GPIO_SPI_RST, 1);
mdelay(6); //>=5ms
}
int st7701s_init(void)
{
gpio_direction_output(ST7701S_GPIO_SPI_CS, 1); //CS=1
gpio_direction_output(ST7701S_GPIO_SPI_SCL, 1); //SCL=1
gpio_direction_output(ST7701S_GPIO_SPI_SDA, 0); //SDA=0
st7701s_hw_reset();
st7701s_reg_init();
return 0;
}

View File

@ -0,0 +1,62 @@
#include <stdio.h>
#include <string.h>
#include "FreeRTOS.h"
#include "board.h"
#include "sfud.h"
#include "sysinfo.h"
#include "crc32.h"
#if DEVICE_TYPE_SELECT == EMMC_FLASH
#include "mmcsd_core.h"
#endif
#pragma data_alignment=4
static SysInfo amt630h_sysinfo;
int ReadSysInfo(void)
{
unsigned int checksum;
#if DEVICE_TYPE_SELECT != EMMC_FLASH
sfud_flash *sflash = sfud_get_device(0);
sfud_read(sflash, SYSINFOA_MEDIA_OFFSET, sizeof(SysInfo), (void*)&amt630h_sysinfo);
#else
emmc_read(SYSINFOA_MEDIA_OFFSET, sizeof(SysInfo), (void*)&amt630h_sysinfo);
#endif
checksum = xcrc32((unsigned char*)&amt630h_sysinfo, sizeof(SysInfo) - 4, 0xffffffff);
if (checksum == amt630h_sysinfo.checksum)
return 0;
#if DEVICE_TYPE_SELECT != EMMC_FLASH
sfud_read(sflash, SYSINFOB_MEDIA_OFFSET, sizeof(SysInfo), (void*)&amt630h_sysinfo);
#else
emmc_read(SYSINFOB_MEDIA_OFFSET, sizeof(SysInfo), (void*)&amt630h_sysinfo);
#endif
checksum = xcrc32((unsigned char*)&amt630h_sysinfo, sizeof(SysInfo) - 4, 0xffffffff);
if (checksum == amt630h_sysinfo.checksum)
return 0;
return -1;
}
SysInfo *GetSysInfo(void)
{
return &amt630h_sysinfo;
}
void SaveSysInfo(void)
{
amt630h_sysinfo.checksum = xcrc32((unsigned char*)&amt630h_sysinfo, sizeof(SysInfo) - 4, 0xffffffff);
#if DEVICE_TYPE_SELECT != EMMC_FLASH
sfud_flash *sflash = sfud_get_device(0);
if(sflash) {
sfud_erase_write(sflash, SYSINFOB_MEDIA_OFFSET, sizeof(SysInfo), (void*)&amt630h_sysinfo);
sfud_erase_write(sflash, SYSINFOA_MEDIA_OFFSET, sizeof(SysInfo), (void*)&amt630h_sysinfo);
}
#else
emmc_write(SYSINFOB_MEDIA_OFFSET, sizeof(SysInfo), (void*)&amt630h_sysinfo);
emmc_write(SYSINFOA_MEDIA_OFFSET, sizeof(SysInfo), (void*)&amt630h_sysinfo);
#endif
}

View File

@ -0,0 +1,997 @@
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include "FreeRTOS.h"
#include "chip.h"
#include "board.h"
#include "touch.h"
#if !defined(VG_ONLY) && !defined(AWTK)
#include "lvgl/lvgl.h"
#else
typedef int16_t lv_coord_t;
typedef uint8_t lv_indev_state_t;
typedef struct {
lv_coord_t x;
lv_coord_t y;
} lv_point_t;
enum { LV_INDEV_STATE_REL = 0, LV_INDEV_STATE_PR };
enum {
LV_KEY_UP = 17, /*0x11*/
LV_KEY_DOWN = 18, /*0x12*/
LV_KEY_RIGHT = 19, /*0x13*/
LV_KEY_LEFT = 20, /*0x14*/
LV_KEY_ESC = 27, /*0x1B*/
LV_KEY_DEL = 127, /*0x7F*/
LV_KEY_BACKSPACE = 8, /*0x08*/
LV_KEY_ENTER = 10, /*0x0A, '\n'*/
LV_KEY_NEXT = 9, /*0x09, '\t'*/
LV_KEY_PREV = 11, /*0x0B, '*/
LV_KEY_HOME = 2, /*0x02, STX*/
LV_KEY_END = 3, /*0x03, ETX*/
};
typedef struct {
lv_point_t point; /**< For LV_INDEV_TYPE_POINTER the currently pressed point*/
uint32_t key; /**< For LV_INDEV_TYPE_KEYPAD the currently pressed key*/
uint32_t btn_id; /**< For LV_INDEV_TYPE_BUTTON the currently pressed button*/
int16_t enc_diff; /**< For LV_INDEV_TYPE_ENCODER number of steps since the previous read*/
lv_indev_state_t state; /**< LV_INDEV_STATE_REL or LV_INDEV_STATE_PR*/
} lv_indev_data_t;
#endif
#ifdef ADC_TOUCH
#define TOUCH_STATE_IDLE 0
#define TOUCH_STATE_START 1
#define TOUCH_STATE_SAMPLE 2
#define TOUCH_STATE_STOP 3
#define MAX_POINT_POOL_SIZE 2
#define FILTER_MAX 3
#define MAXPANADCLEN 20
typedef struct {
int x;
int y;
} POINT;
typedef struct
{
UINT16 adcX;
UINT16 adcY;
} PAN_DATA;
typedef struct
{
UINT32 *pValue;
UINT32 header;
UINT32 trail;
UINT32 quelen;
} ADCValueQueue;
static calibration cal;
static UINT32 lg_ulTouchMachineState = TOUCH_STATE_IDLE;
static POINT lg_stLastMovePoint;
ADCValueQueue panADCXQueue;
ADCValueQueue panADCYQueue;
UINT32 PANADC_X[MAXPANADCLEN];
UINT32 PANADC_Y[MAXPANADCLEN];
static INT32 Queue_ADCValue_Init(ADCValueQueue *pQueue, UINT32 *pValue, UINT32 quelen)
{
INT32 ret=0;
if((pQueue != 0) && (pValue != 0) && (quelen > 0))
{
pQueue->pValue = pValue;
pQueue->quelen = quelen;
pQueue->header = 0;
pQueue->trail = 0;
ret =1;
}
return ret;
}
static INT32 Queue_ADCValue_Length(ADCValueQueue *pQueue)
{
INT32 queuelen=0;
if(pQueue != 0)
{
if(pQueue->trail < pQueue->header)
{
queuelen = pQueue->quelen +(pQueue->trail- pQueue->header);
}
else
queuelen = pQueue->trail- pQueue->header;
}
return queuelen;
}
static INT32 Queue_ADCValue_Add(ADCValueQueue *pQueue,unsigned int value)
{
INT32 ret=0;
UINT32 *pValue=0;
if(pQueue != 0)
{
pValue = pQueue->pValue + pQueue->trail;
*pValue = value;
pQueue->trail++;
if(pQueue->trail >= pQueue->quelen)
{
pQueue->trail = 0;
}
if(pQueue->trail == pQueue->header)
{
pQueue->header++;
if(pQueue->header >= pQueue->quelen)
{
pQueue->header = 1;
pQueue->trail=0;
}
}
ret=1;
}
return ret;
}
static INT32 Queue_ADCValue_Read(ADCValueQueue *pQueue, UINT32 *pValue)
{
INT32 ret=0;
UINT32 *pHeaderValue=0;
if((pQueue != 0) && (pValue != 0))
{
if(Queue_ADCValue_Length(pQueue) > 0)
{
pHeaderValue = pQueue->pValue + pQueue->header;
*pValue = *pHeaderValue;
pQueue->header++;
if(pQueue->header >= pQueue->quelen)
{
pQueue->header = 0;
}
ret=1;
}
}
return ret;
}
//////////////////////////////////////////////////
static UINT32 GetADCTouch(PAN_DATA *pPan)
{
UINT32 panX;
UINT32 panY;
INT32 ret=0;
if(pPan != 0)
{
ret = Queue_ADCValue_Read(&panADCXQueue,&panX);
if(ret==1)
{
ret = Queue_ADCValue_Read(&panADCYQueue,&panY);
if(ret == 1)
{
pPan->adcX = panX;
pPan->adcY = panY;
}
}
}
return ret;
}
static void CalcCoord(PAN_DATA *pPan, POINT *pPT);
#define TOUCH_DOT_REGION 10
extern void SendTouchInputEventFromISR(lv_indev_data_t *indata);
/***********************************************************************************************
通过大量试验发现触摸屏存在的问题有
1: 触摸刚开始的几个点可能任意哪个点或者哪几个点会有较大偏差;
2: 释放前的采样点很大几率不准确。
为了应对各种错误情况,采取的措施有
1: 首先简单地丢弃掉最后一个采样点
2: 提高采样频率,保证最开始的几个采样点都在一个比较小的范围
内(即使快速滑动,刚开始不会有很大速度,因此也能保证起始点
比较聚集)。在这种前提下提取开始采样时的若干个点进行分析,
找出坐标值比较接近的点数最多的点,其他点则认为是错误点丢
弃掉,如果找不到的话则认为所有点都不稳定,重新再提取之后
的若干个点进行分析。
*************************************************************************************************/
#define SCOPE_ADJUST 8
#define ANALYSIS_POINT_SUCCESS 3
#define ANALYSIS_POINT_COUNT 5
#define DISCARD_POINT_COUNT 2
#define POINT_POOL_SIZE (ANALYSIS_POINT_COUNT+DISCARD_POINT_COUNT)
#define MYABS(x) (((x)>=0) ? (x) : (-(x)))
/*
*********************************************************************************************************
* Description: 分析采样最开始的若干点,丢弃错误点
*
* Arguments : point[] : 采样点坐标值数组
num : 用于分析的采样点个数
*
* Returns : 有效点的个数返回0表示所有点都无效
* Notes : 剩余的有效点重新从原数组起始位置开始依次放置
*********************************************************************************************************
*/
static int Touch_Start_Analyse(POINT point[], int num)
{
int i, j;
int key[ANALYSIS_POINT_COUNT] = {0};
int near_by_point[ANALYSIS_POINT_COUNT] = {0};
int effective_near_by_points[ANALYSIS_POINT_COUNT] = {0};
int max = -1;
int samplecnt = 0;
if(num > ANALYSIS_POINT_COUNT)
num = ANALYSIS_POINT_COUNT;
for(i=0; i<num; i++)
{
//计算每个点和其接近的点的个数并记录下距离最近的点
near_by_point[i] = 1;
for(j=0; j<num; j++)
{
if(j == i)
continue;
if(MYABS(point[i].x - point[j].x)<SCOPE_ADJUST && MYABS(point[i].y - point[j].y)<SCOPE_ADJUST)
{
key[i]++;
near_by_point[j] = 1;
}
else
near_by_point[j] = 0;
}
//筛选出相近点数最多的点并记录下与其距离最近的点位置
if(key[i] > max)
{
max = key[i];
for(j=0;j<num;j++)
{
effective_near_by_points[j] = near_by_point[j];
}
}
}
//有效点个数不够,判定所有点都不稳定全部丢弃
if(max < ANALYSIS_POINT_SUCCESS-1)
return 0;
//移除所有无效点有效点从原数组位置0开始依次放置
for(i=0; i<num; i++)
{
if(effective_near_by_points[i])
{
point[samplecnt] = point[i];
samplecnt++;
}
}
return samplecnt;
}
static void Handler_Touch_IntEvent(UINT32 ulEvent, UINT32 lpParam, UINT32 wParam)
{
static int s_SampleCnt;
static int s_PoolIndex;
static POINT s_PointPool[POINT_POOL_SIZE];
switch(lg_ulTouchMachineState)
{
case TOUCH_STATE_IDLE:
if(ulEvent == TOUCH_START_EVENT)
{
lg_ulTouchMachineState = TOUCH_STATE_START;
s_SampleCnt = 0;
s_PoolIndex = 0;
}
break;
case TOUCH_STATE_START:
if(ulEvent == TOUCH_STOP_EVENT)
{
lg_ulTouchMachineState = TOUCH_STATE_IDLE;
}
else if(ulEvent == TOUCH_SAMPLE_EVENT)
{
POINT pt;
PAN_DATA stPanData;
lv_indev_data_t indata = {0};
int i;
//get cordinate
stPanData.adcX = lpParam;
stPanData.adcY = wParam;
CalcCoord(&stPanData, &pt);
if(pt.x < 0 || pt.y < 0)
return;
if(pt.x < 0 || pt.x >= LCD_WIDTH || pt.y < 0 || pt.y >= LCD_HEIGHT)
return;
//防止ANALYSIS_POINT_START个点内包含最后要丢弃的点刚开始要暂存
//ANALYSIS_POINT_START + DISCARD_POINT_END个点
if(s_SampleCnt < ANALYSIS_POINT_COUNT + DISCARD_POINT_COUNT)
{
s_PointPool[s_SampleCnt++] = pt;
if(s_SampleCnt < ANALYSIS_POINT_COUNT + DISCARD_POINT_COUNT)
return;
}
s_SampleCnt = Touch_Start_Analyse(s_PointPool, ANALYSIS_POINT_COUNT);
if(s_SampleCnt == 0)
{
for(i=0; i<DISCARD_POINT_COUNT; i++)
s_PointPool[i] = s_PointPool[ANALYSIS_POINT_COUNT+i];
s_SampleCnt = DISCARD_POINT_COUNT;
return;
}
//send press event
indata.point.x = s_PointPool[0].x;
indata.point.y = s_PointPool[0].y;
indata.state = LV_INDEV_STATE_PR;
SendTouchInputEventFromISR(&indata);
lg_ulTouchMachineState = TOUCH_STATE_SAMPLE;
//将为满足最后丢弃任务而暂存的点复制到分析后剩余点之后
for(i=0; i<DISCARD_POINT_COUNT; i++)
s_PointPool[s_SampleCnt + i] = s_PointPool[ANALYSIS_POINT_COUNT+i];
s_PoolIndex = 1;
//计算此时剩余的未操作的有效点数
s_SampleCnt = s_SampleCnt - 1 + DISCARD_POINT_COUNT;
//send move event in the pool
while(s_SampleCnt > DISCARD_POINT_COUNT)
{
int xdiff, ydiff;
unsigned int totaldiff;
xdiff = s_PointPool[s_PoolIndex].x - lg_stLastMovePoint.x;
ydiff = s_PointPool[s_PoolIndex].y - lg_stLastMovePoint.y;
totaldiff = xdiff * xdiff + ydiff * ydiff;
if(totaldiff > 4)
{
indata.point.x = s_PointPool[s_PoolIndex].x;
indata.point.y = s_PointPool[s_PoolIndex].y;
indata.state = LV_INDEV_STATE_PR;
SendTouchInputEventFromISR(&indata);
lg_stLastMovePoint.x = s_PointPool[s_PoolIndex].x;
lg_stLastMovePoint.y = s_PointPool[s_PoolIndex].y;
}
s_PoolIndex++;
s_SampleCnt--;
}
}
break;
case TOUCH_STATE_SAMPLE:
if(ulEvent == TOUCH_SAMPLE_EVENT)
{
//caculate move center cordinate
//if move, then send move event
PAN_DATA stPanData;
POINT pt;
int xDiff = 0, yDiff = 0;
unsigned int totalDiff = 0;
//get cordinate
stPanData.adcX = lpParam;
stPanData.adcY = wParam;
CalcCoord(&stPanData, &pt);
if(pt.x < 0 || pt.y < 0)
return;
if(pt.x < 0 || pt.x >= LCD_WIDTH || pt.y < 0 || pt.y >= LCD_HEIGHT)
return;
if(s_SampleCnt < DISCARD_POINT_COUNT)
{
int index = (s_PoolIndex+s_SampleCnt++) % POINT_POOL_SIZE;
s_PointPool[index] = pt;
return;
}
xDiff = s_PointPool[s_PoolIndex].x - lg_stLastMovePoint.x;
yDiff = s_PointPool[s_PoolIndex].y - lg_stLastMovePoint.y;
totalDiff = xDiff * xDiff + yDiff * yDiff;
if(totalDiff > 4)
{
lv_indev_data_t indata = {0};
indata.point.x = s_PointPool[s_PoolIndex].x;
indata.point.y = s_PointPool[s_PoolIndex].y;
indata.state = LV_INDEV_STATE_PR;
SendTouchInputEventFromISR(&indata);
lg_stLastMovePoint.x = s_PointPool[s_PoolIndex].x;
lg_stLastMovePoint.y = s_PointPool[s_PoolIndex].y;
}
s_PointPool[(s_PoolIndex+DISCARD_POINT_COUNT)%POINT_POOL_SIZE] = pt;
s_PoolIndex = (s_PoolIndex+1)%POINT_POOL_SIZE;
}
else if(ulEvent == TOUCH_STOP_EVENT)
{
lv_indev_data_t indata = {0};
//send release event
indata.point.x = lg_stLastMovePoint.x;
indata.point.y = lg_stLastMovePoint.y;
indata.state = LV_INDEV_STATE_REL;
SendTouchInputEventFromISR(&indata);
lg_ulTouchMachineState = TOUCH_STATE_IDLE;
}
break;
case TOUCH_STATE_STOP:
break;
}
}
static volatile UINT32 lg_bTouchStart = 0;
static UINT32 CheckTouchStart()
{
return lg_bTouchStart == 1;
}
static UINT32 CheckTouchStop()
{
return lg_bTouchStart == 0;
}
static UINT32 GetTouchSampleCounter()
{
return Queue_ADCValue_Length(&panADCXQueue);
}
static UINT32 lg_bTouchAdjusted = 0;
void TouchEventHandler(UINT32 ulEvent, UINT32 lpParam, UINT32 wParam)
{
if(lg_bTouchAdjusted)
{
Handler_Touch_IntEvent(ulEvent, lpParam, wParam);
}
else
{
if(ulEvent == TOUCH_START_EVENT)
{
lg_bTouchStart = 1;
Queue_ADCValue_Init(&panADCXQueue, PANADC_X, MAXPANADCLEN);
Queue_ADCValue_Init(&panADCYQueue, PANADC_Y, MAXPANADCLEN);
}
else if(ulEvent == TOUCH_SAMPLE_EVENT)
{
Queue_ADCValue_Add(&panADCXQueue,lpParam);
Queue_ADCValue_Add(&panADCYQueue,wParam);
}
else if(ulEvent == TOUCH_STOP_EVENT)
{
lg_bTouchStart = 0;
}
}
}
/***************************************************************************************
触摸屏坐标校验代码
***************************************************************************************/
#define GRID_RANGE 12
#define HIT_RANGE 2
#define ABS_HIT ((GRID_RANGE+HIT_RANGE)*2)
#define TOUCH_HIGH_EXACTION 0
#define TOUCH_MID_EXACTION 0
#define TOUCH_LOW_EXACTION 1
#define TOUCH_REVISE_DEBUG 1
#if TOUCH_REVISE_DEBUG
#define TOUCH_DEBUG_MSG(fmt, args...) printf(fmt, ##args)
#else
#define TOUCH_DEBUG_MSG(fmt, args...)
#endif
#define SYSTEM_ERROR 100.0
#define SCALE_AERROR 2// 3 这里考虑触摸屏的差异修改20130618
#define SCALE_DERROR 5
static double abs_ax,abs_dx,abs_ly,abs_ry;
static double abs_lx,abs_rx;
static double abs_err1,abs_err2,abs_err3,abs_err4,abs_err5;
static double abs_cx,abs_cy;
static int lg_direction = 0;
#if TOUCH_HIGH_EXACTION
#define SYSTEM_ERROR1 100.0
#elif TOUCH_MID_EXACTION
#define SYSTEM_ERROR1 150.0
#elif TOUCH_LOW_EXACTION
#define SYSTEM_ERROR1 200.0
#else
#define SYSTEM_ERROR1 150.0
#endif
/* static void InitializeCalibration(int a0, int a1, int a2, int a3, int a4, int a5, int a6)
{
cal.a[0] = a0;
cal.a[1] = a1;
cal.a[2] = a2;
cal.a[3] = a3;
cal.a[4] = a4;
cal.a[5] = a5;
cal.a[6] = a6;
} */
static void SaveCalibration(calibration *pCalibration)
{
}
static int perform_calibration(calibration *cal) {
int j;
float n, x, y, x2, y2, xy, z, zx, zy;
float det, a, b, c, e, f, i;
float scaling = 65536.0;
// Get sums for matrix
n = x = y = x2 = y2 = xy = 0;
for(j=0;j<5;j++) {
n += 1.0;
x += (float)cal->x[j];
y += (float)cal->y[j];
x2 += (float)(cal->x[j]*cal->x[j]);
y2 += (float)(cal->y[j]*cal->y[j]);
xy += (float)(cal->x[j]*cal->y[j]);
}
// Get determinant of matrix -- check if determinant is too small
det = n*(x2*y2 - xy*xy) + x*(xy*y - x*y2) + y*(x*xy - y*x2);
if(det < 0.1 && det > -0.1) {
printf("ts_calibrate: determinant is too small -- %f\n",det);
return 0;
}
// Get elements of inverse matrix
a = (x2*y2 - xy*xy)/det;
b = (xy*y - x*y2)/det;
c = (x*xy - y*x2)/det;
e = (n*y2 - y*y)/det;
f = (x*y - n*xy)/det;
i = (n*x2 - x*x)/det;
// Get sums for x calibration
z = zx = zy = 0;
for(j=0;j<5;j++) {
z += (float)cal->xfb[j];
zx += (float)(cal->xfb[j]*cal->x[j]);
zy += (float)(cal->xfb[j]*cal->y[j]);
}
// Now multiply out to get the calibration for framebuffer x coord
cal->a[0] = (int)((a*z + b*zx + c*zy)*(scaling));
cal->a[1] = (int)((b*z + e*zx + f*zy)*(scaling));
cal->a[2] = (int)((c*z + f*zx + i*zy)*(scaling));
// Get sums for y calibration
z = zx = zy = 0;
for(j=0;j<5;j++) {
z += (float)cal->yfb[j];
zx += (float)(cal->yfb[j]*cal->x[j]);
zy += (float)(cal->yfb[j]*cal->y[j]);
}
// Now multiply out to get the calibration for framebuffer y coord
cal->a[3] = (int)((a*z + b*zx + c*zy)*(scaling));
cal->a[4] = (int)((b*z + e*zx + f*zy)*(scaling));
cal->a[5] = (int)((c*z + f*zx + i*zy)*(scaling));
// If we got here, we're OK, so assign scaling to a[6] and return
cal->a[6] = (int)scaling;
return 1;
}
void CleanTouchAdjustParameter(void)
{
Queue_ADCValue_Init(&panADCXQueue, PANADC_X, MAXPANADCLEN);
Queue_ADCValue_Init(&panADCYQueue, PANADC_Y, MAXPANADCLEN);
lg_bTouchAdjusted = 0;
}
void TouchInit(void)
{
CleanTouchAdjustParameter();
}
static void CalcCoord(PAN_DATA *pPan, POINT *pPT)
{
pPT->x = (pPan->adcX * cal.a[1] + pPan->adcY * cal.a[2] + cal.a[0])/cal.a[6];
pPT->y = (pPan->adcX * cal.a[4] + pPan->adcY * cal.a[5] + cal.a[3])/cal.a[6];
}
static unsigned int GetTouchHit(PAN_DATA *pPan)
{
unsigned int PanReq;
PAN_DATA Pan[50];
unsigned int i, Count;
for(i = 0; i < 50; i++)
{
Pan[i].adcX = 0xFFFF;
Pan[i].adcY = 0xFFFF;
}
ReStartCheck:
while(!CheckTouchStart());
while(!CheckTouchStop());
if(GetTouchSampleCounter() < 16)
goto ReStartCheck;
AIC_DisableIT(ADC_IRQn);
while(1)
{
PanReq = GetADCTouch(&Pan[49]);
if(PanReq==0)
{
break;
}
for(i = 0; i < 49; i++)
{
Pan[i].adcX = Pan[i+1].adcX;
Pan[i].adcY = Pan[i+1].adcY;
}
}
AIC_EnableIT(ADC_IRQn);
Count = 0;
for(i = 0; i < 49; i++)
{
if(Pan[i].adcY < 0xFFF)
{
Count++;
}
}
pPan->adcX = Pan[49-Count/2].adcX;
pPan->adcY = Pan[49-Count/2].adcY;
TOUCH_DEBUG_MSG("Hit Count = %d\n", Count);
TOUCH_DEBUG_MSG("pPan->adcX=%d\n",pPan->adcX);
TOUCH_DEBUG_MSG("pPan->adcY=%d\n",pPan->adcY);
return TRUE;
}
static void ClearBitmap(lv_color_t color, const lv_area_t * area, lv_color_t * color_p)
{
/*Truncate the area to the screen*/
int32_t act_x1 = area->x1 < 0 ? 0 : area->x1;
int32_t act_y1 = area->y1 < 0 ? 0 : area->y1;
int32_t act_x2 = area->x2 > LCD_WIDTH - 1 ? LCD_WIDTH - 1 : area->x2;
int32_t act_y2 = area->y2 > LCD_HEIGHT - 1 ? LCD_HEIGHT - 1 : area->y2;
/*32 or 24 bit per pixel*/
if(LCD_BPP == 32) {
uint32_t * fbp32 = (uint32_t *)color_p;
int32_t x, y;
for(y = act_y1; y <= act_y2; y++) {
fbp32 = (uint32_t *)color_p + y * LCD_WIDTH;
for (x = act_x1; x <= act_x2; x++)
fbp32[x] = color.full;
}
}
/*16 bit per pixel*/
else if(LCD_BPP == 16) {
uint16_t * fbp16 = (uint16_t *)color_p;
int32_t x, y;
for(y = act_y1; y <= act_y2; y++) {
fbp16 = (uint16_t *)color_p + y * LCD_WIDTH;
for (x = act_x1; x <= act_x2; x++)
fbp16[x] = color.full;
}
}
}
static void PutHitCursor(int x, int y)
{
lv_area_t area;
area.x1 = x - GRID_RANGE;
area.y1 = y;
area.x2 = x + GRID_RANGE + HIT_RANGE - 1;
area.y2 = y + HIT_RANGE - 1;
ClearBitmap(LV_COLOR_WHITE, &area, (lv_color_t*)ark_lcd_get_virt_addr());
area.x1 = x;
area.y1 = y - GRID_RANGE;
area.x2 = x + HIT_RANGE - 1;
area.y2 = y + GRID_RANGE + HIT_RANGE - 1;
ClearBitmap(LV_COLOR_WHITE, &area, (lv_color_t*)ark_lcd_get_virt_addr());
area.x1 = x;
area.y1 = y;
area.x2 = x + HIT_RANGE - 1;
area.y2 = y + HIT_RANGE - 1;
ClearBitmap(LV_COLOR_BLACK, &area, (lv_color_t*)ark_lcd_get_virt_addr());
CP15_clean_dcache_for_dma((uint32_t)(lv_color_t*)ark_lcd_get_virt_addr(),
(uint32_t)(lv_color_t*)ark_lcd_get_virt_addr() + FB_SIZE);
}
static void ClrHitCursor(int x, int y)
{
lv_area_t area;
area.x1 = x - GRID_RANGE;
area.y1 = y - GRID_RANGE;
area.x2 = x + GRID_RANGE + HIT_RANGE - 1;
area.y2 = y + GRID_RANGE + HIT_RANGE - 1;
ClearBitmap(LV_COLOR_BLACK, &area, (lv_color_t*)ark_lcd_get_virt_addr());
CP15_clean_dcache_for_dma((uint32_t)(lv_color_t*)ark_lcd_get_virt_addr(),
(uint32_t)(lv_color_t*)ark_lcd_get_virt_addr() + FB_SIZE);
}
static int compare_data(calibration *cal)
{
int ret=0;
int diff_x;
int diff_y;
diff_x = (int)fabs(cal->x[0] - cal->x[1]);
diff_y = (int)fabs(cal->y[0] - cal->y[1]);
if(diff_x > diff_y)
lg_direction = 0;
else
lg_direction = 1;
TOUCH_DEBUG_MSG("lg_direction = %d\r\n", lg_direction);
if(lg_direction == 0)
{
if((cal->x [0]<cal->x [1])&&(cal->x [3]<cal->x [2]))
ret=1;
if((cal->x [0]>cal->x [1])&&(cal->x [3]>cal->x [2]))
ret=1;
}
else
{
if((cal->y[0]<cal->y[1])&&(cal->y[3]<cal->y[2]))
ret=1;
if((cal->y[0]>cal->y[1])&&(cal->y[3]>cal->y[2]))
ret=1;
}
return ret;
}
static int square_judge(calibration *cal)
{
int ret=0;
if(lg_direction == 0)
{
abs_ax=fabs(cal->x [0] - cal->x [1]);
abs_dx=fabs(cal->x [2]-cal->x [3]);
abs_err1=fabs(abs_ax -abs_dx);
TOUCH_DEBUG_MSG("***abs_ax=%d, abs_dx=%d, abs_err1=%d, SYSTEM_ERROR1=%d*******\n", (int)abs_ax, (int)abs_dx, (int)abs_err1, (int)SYSTEM_ERROR1);
abs_lx=fabs(cal->x [0]-cal->x [4]);
abs_rx=fabs(cal->x[3]-cal->x [4]);
abs_err2=fabs(abs_lx -abs_rx);
TOUCH_DEBUG_MSG("***abs_lx=%d,abs_rx=%d,abs_err2=%d****2\n", (int)abs_lx, (int)abs_rx, (int)abs_err2);
abs_ly=fabs(cal->y [0]-cal->y [3]);
abs_ry=fabs(cal->y [1]-cal->y [2]);
abs_err3=fabs(abs_ly -abs_ry);
TOUCH_DEBUG_MSG("***abs_ly=%d, abs_ry=%d, abs_err3=%d****2\n", (int)abs_ly, (int)abs_ry, (int)abs_err3);
if(abs_err1<SYSTEM_ERROR1&&abs_err2<SYSTEM_ERROR1&&abs_err3<SYSTEM_ERROR1)
ret=1;
}
else
{
abs_ax=fabs(cal->y[0] - cal->y[1]);
abs_dx=fabs(cal->y[2]-cal->y[3]);
abs_err1=fabs(abs_ax -abs_dx);
TOUCH_DEBUG_MSG("***abs_ax=%d, abs_dx=%d, abs_err1=%d, SYSTEM_ERROR1=%d*******\n", (int)abs_ax, (int)abs_dx, (int)abs_err1, (int)SYSTEM_ERROR1);
abs_lx=fabs(cal->y[0]-cal->y[4]);
abs_rx=fabs(cal->y[3]-cal->y[4]);
abs_err2=fabs(abs_lx -abs_rx);
TOUCH_DEBUG_MSG("***abs_lx=%d, abs_rx=%d, abs_err2=%d****2\n", (int)abs_lx, (int)abs_rx, (int)abs_err2);
abs_ly=fabs(cal->x[0]-cal->x[3]);
abs_ry=fabs(cal->x[1]-cal->x[2]);
abs_err3=fabs(abs_ly -abs_ry);
TOUCH_DEBUG_MSG("***abs_ly=%d, abs_ry=%d, abs_err3=%d****2\n", (int)abs_ly, (int)abs_ry, (int)abs_err3);
if(abs_err1<SYSTEM_ERROR1&&abs_err2<SYSTEM_ERROR1&&abs_err3<SYSTEM_ERROR1)
ret=1;
}
TOUCH_DEBUG_MSG("***ret=%d****4\n",ret);
return ret;
}
static int judge_center(calibration *cal)
{
int ret=0;
if(lg_direction == 0)
{
abs_cx=fabs(cal->x [4]-cal->x [0])*2;
abs_cy=fabs(cal->y [4]-cal->y [0])*2;
abs_err4=fabs(abs_cx -abs_ax);
abs_err5=fabs(abs_cy -abs_ly);
TOUCH_DEBUG_MSG("***abs_cx=%d, abs_cy=%d, abs_err4=%d, abs_err5=%d****2\n", (int)abs_cx, (int)abs_cy, (int)abs_err4, (int)abs_err5);
if(abs_err4<SYSTEM_ERROR1&&abs_err5<SYSTEM_ERROR1)
ret=1;
}
else
{
abs_cx=fabs(cal->y[4]-cal->y[0])*2;
abs_cy=fabs(cal->x[4]-cal->x[0])*2;
abs_err4=fabs(abs_cx -abs_ax);
abs_err5=fabs(abs_cy -abs_ly);
TOUCH_DEBUG_MSG("***abs_cx=%d, abs_cy=%d, abs_err4=%d, abs_err5=%d****2\n", (int)abs_cx, (int)abs_cy, (int)abs_err4, (int)abs_err5);
if(abs_err4<SYSTEM_ERROR1&&abs_err5<SYSTEM_ERROR1)
ret=1;
}
return ret;
}
static int filter_data(calibration *cal)
{
int ret=0;
float abs_lcd;
int scale;
int i;
TOUCH_DEBUG_MSG("***filter_data****1\n");
for(i=0;i<5;i++)
{
TOUCH_DEBUG_MSG("cal->x[%d] = %d, cal->y[%d] = %d\r\n", i, (int)cal->x[i], i, (int)cal->y[i]);
}
if(compare_data( cal))
{
TOUCH_DEBUG_MSG("*** Pass compare_data ****\n");
if(square_judge(cal))
{
TOUCH_DEBUG_MSG("*** Pass square_judge ****\n");
abs_lcd=fabs(cal->xfb[1] -cal->xfb[0]);
TOUCH_DEBUG_MSG("***abs_ax=%d, abs_lcd=%d****\n", (int)abs_ax, (int)abs_lcd);
scale=(int)(abs_ax/abs_lcd);
TOUCH_DEBUG_MSG("***scale=%d****4\n",scale);
if(SCALE_AERROR<scale&&SCALE_DERROR>scale)
{
TOUCH_DEBUG_MSG("*** Scale check ok ****\n");
if(judge_center(cal))
{
ret=1;
}
else
{
TOUCH_DEBUG_MSG("*** Failed at judge_center****\n");
}
}
}
}
TOUCH_DEBUG_MSG("*** filter_data ret=%d****\n",ret);
return ret;
}
static void get_sample (calibration *cal,
int index, int x, int y, char *name)
{
PAN_DATA ts_cord;
PutHitCursor(x, y);
// getxy (ts, &cal->x [index], &cal->y [index]);
GetTouchHit(&ts_cord);
cal->x [index] = ts_cord.adcX;
cal->y [index] = ts_cord.adcY;
ClrHitCursor(x, y);
cal->xfb [index] = x;
cal->yfb [index] = y;
TOUCH_DEBUG_MSG("get_sample %s : X = %4d Y = %4d\n", name, cal->x [index], cal->y [index]);
}
unsigned int AdjustTouch(void)
{
unsigned int i;
#if 0
cal.a[0]=56822272;
cal.a[1]=-14948;
cal.a[2]=36;
cal.a[3]=38820672;
cal.a[4]=-59;
cal.a[5]=-11704;
cal.a[6]=65536;
lg_bTouchAdjusted = 1;
#else
while(1)
{
get_sample (&cal, 0, 50, 50, "Top left");
get_sample (&cal, 1, LCD_WIDTH - 50, 50, "Top right");
get_sample (&cal, 2, LCD_WIDTH - 50, LCD_HEIGHT - 50, "Bot right");
get_sample (&cal, 3, 50, LCD_HEIGHT - 50, "Bot left");
get_sample (&cal, 4, LCD_WIDTH / 2, LCD_HEIGHT / 2, "Center");
if(filter_data(&cal))
{
perform_calibration (&cal);
for(i=0;i<7;i++)
{
printf("the result cal->a[%d]=%d\n", i, cal.a[i]);
}
SaveCalibration(&cal);
break;
}
}
#endif
lg_bTouchAdjusted = 1;
return 0; // 5次均无效, 取默认值
}
int LoadTouchConfigure(void)
{
return -1;
}
#endif

View File

@ -0,0 +1,471 @@
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include "FreeRTOS.h"
#include "chip.h"
#include "board.h"
#include "timers.h"
#ifdef TP_USE_FT6336U
#define FT6336U_STAT_ADDR 0x02
#define FT6336U_TOUCH1_ADDR 0x03
#define FT6336U_TOUCH2_ADDR 0x09
#define FT6336U_TOUCH3_ADDR 0x0F
#define FT6336U_TOUCH4_ADDR 0x15
#define FT6336U_TOUCH5_ADDR 0x1B
#define FT6336U_CHIP_ID 0xA3
#define FT6336U_CONFIG_X_MAX 960
#define FT6336U_CONFIG_Y_MAX 320
#define FT6336U_SLAVE_ADDR 0x38
#define FT6336U_GPIO_INT TP_GPIO_INT
#define FT6336U_GPIO_RST TP_GPIO_RST
#define FT6336U_INVERTED_X TP_INV_X
#define FT6336U_INVERTED_Y TP_INV_Y
#if TP_MT_TOUCH
#define FT6336U_MAX_CONTACTS 5
#else
#define FT6336U_MAX_CONTACTS 1
#endif
//#define FT6336U_USE_RELEASE_TIMER
//#define FT6336U_REPEAT_FILTER
#define GPIO_IS_VALID(n) ((n >= 0) && (n < 128) ? 1 : 0)
#define FT6336U_ERR(fmt, args...) printf("###ERR:[%s]"fmt, __func__, ##args)
#define FT6336U_DBG(fmt, args...) //printf("DBG:[%s]"fmt, __func__, ##args)
enum {
FT6336U_INDEV_STATE_DOWN,
FT6336U_INDEV_STATE_UP,
FT6336U_INDEV_STATE_CONTACT
};
struct ft6336u_ts_data {
struct i2c_adapter *adap;
unsigned int max_touch_num;
unsigned int x_max;
unsigned int y_max;
int last_input_x;
int last_input_y;
int last_input_state;
int gpio_int;
int gpio_rst;
uint8_t id;
unsigned long irq_flags;
TaskHandle_t irq_task;
#ifdef FT6336U_USE_RELEASE_TIMER
TimerHandle_t release_timer;
#endif
};
typedef struct _ft6336u_point{
int16_t x;
int16_t y;
uint8_t state;
} ft6336u_point_t;
#if !defined(VG_ONLY) && !defined(AWTK)
#include "lvgl/lvgl.h"
#else
enum { LV_INDEV_STATE_REL = 0, LV_INDEV_STATE_PR };
typedef int16_t lv_coord_t;
typedef uint8_t lv_indev_state_t;
typedef struct {
lv_coord_t x;
lv_coord_t y;
} lv_point_t;
typedef struct {
lv_point_t point; /**< For LV_INDEV_TYPE_POINTER the currently pressed point*/
uint32_t key; /**< For LV_INDEV_TYPE_KEYPAD the currently pressed key*/
uint32_t btn_id; /**< For LV_INDEV_TYPE_BUTTON the currently pressed button*/
int16_t enc_diff; /**< For LV_INDEV_TYPE_ENCODER number of steps since the previous read*/
lv_indev_state_t state; /**< LV_INDEV_STATE_REL or LV_INDEV_STATE_PR*/
} lv_indev_data_t;
#endif
extern void SendTouchInputEvent(lv_indev_data_t *indata);
extern void SendTouchInputEventFromISR(lv_indev_data_t *indata);
static int ft6336u_i2c_read(struct i2c_adapter *adap, uint8_t reg, uint8_t *buf, int len)
{
struct i2c_msg msgs[2];
int ret;
msgs[0].flags = !I2C_M_RD;
msgs[0].addr = adap->addr;
msgs[0].len = 1;
msgs[0].buf = &reg;
msgs[1].flags = I2C_M_RD;
msgs[1].addr = adap->addr;
msgs[1].len = len;
msgs[1].buf = buf;
ret = i2c_transfer(adap, msgs, 2);
return ((ret != 2) ? -EIO : 0);
}
#if 0
static int ft6336u_i2c_write(struct i2c_adapter *adap, const uint8_t *buf, int len)
{
struct i2c_msg msg;
int ret;
msg.flags = !I2C_M_RD;
msg.addr = adap->addr;
msg.buf = buf;
msg.len = len + 1;
ret = i2c_transfer(adap, &msg, 1);
return ((ret != 1) ? -EIO : 0);
}
#endif
static int ft6336u_ts_read_input_report(struct ft6336u_ts_data *ts)
{
uint8_t counter = 0;
uint8_t lvalue;
uint8_t ts_num;
do {
//make sure data in buffer is valid
ft6336u_i2c_read(ts->adap, FT6336U_STAT_ADDR, &lvalue, 1);
if(counter++ == 0x30)
return 0;
} while(lvalue & 0x08);
ts_num = (uint8_t)(lvalue & 0x0F);
if(ts_num > FT6336U_MAX_CONTACTS)
ts_num = FT6336U_MAX_CONTACTS;
// FT6336U_DBG("points num:%d\n", ts_num);
return ts_num;
}
static int ft6336u_ts_report_touch(struct ft6336u_ts_data *ts, int id)
{
ft6336u_point_t point;
uint8_t values[4];
const uint8_t x_base[] = {
FT6336U_TOUCH1_ADDR,
FT6336U_TOUCH2_ADDR,
FT6336U_TOUCH3_ADDR,
FT6336U_TOUCH4_ADDR,
FT6336U_TOUCH5_ADDR
};
if(ft6336u_i2c_read(ts->adap, x_base[id], values, 4) != 0) {
FT6336U_ERR("i2c read coordinate failed\n");
return -1;
}
point.state = (values[0]>>6) & 0x3;
point.x = (((uint16_t)(values[0]&0x0f)) << 8) | values[1];
point.y = (((uint16_t)(values[2]&0x0f)) << 8) | values[3];
/*invalid point val*/
if((point.x > ts->x_max) || (point.y > ts->y_max) || (point.state > FT6336U_INDEV_STATE_CONTACT)) {
FT6336U_ERR("Coordinate out of range: x:%d, y:%d\n", point.x, point.y);
return -1;
}
#if FT6336U_INVERTED_X
point.x = ts->x_max - point.x;
#endif
#if FT6336U_INVERTED_Y
point.y = ts->y_max - point.y;
#endif
#ifdef FT6336U_REPEAT_FILTER
if(point.state == FT6336U_INDEV_STATE_CONTACT) {
if((ts->last_input_x == point.x) && (ts->last_input_y == point.y)) {
return 0;
} else {
//move event.
}
}
#endif
//send press event
#ifdef AWTK
XM_TpEventProc (XM_EVENT_TOUCHDOWN, point.x, point.y, 0);
#else
lv_indev_data_t indata = {0};
indata.point.x = point.x;
indata.point.y = point.y;
if(point.state == FT6336U_INDEV_STATE_CONTACT) {
indata.state = LV_INDEV_STATE_PR;
} else if(point.state == FT6336U_INDEV_STATE_DOWN) {
indata.state = LV_INDEV_STATE_PR;
//printf("++++++ id[%d]: x:%d, y:%d\n", id, point.x, point.y);
} else /*if(point.state == FT6336U_INDEV_STATE_UP)*/ {
indata.state = LV_INDEV_STATE_REL;
//printf("------ id[%d]: x:%d, y:%d\n", id, point.x, point.y);
}
SendTouchInputEvent(&indata);
#endif
ts->last_input_x = point.x;
ts->last_input_y = point.y;
ts->last_input_state = point.state;
// FT6336U_DBG("id[%d]:x:%d, y:%d, state:0x%x\n", id, point.x, point.y, point.state);
return 0;
}
static void ft6336u_process_events(struct ft6336u_ts_data *ts)
{
uint8_t ts_num, i;
ts_num = ft6336u_ts_read_input_report(ts);
for(i=0; i<ts_num; i++) {
ft6336u_ts_report_touch(ts, i);
}
if(ts_num == 0) { /* report the last point release event */
#ifdef AWTK
XM_TpEventProc (XM_EVENT_TOUCHUP, ts->last_input_x, ts->last_input_y, 0);
#else
lv_indev_data_t indata = {0};
indata.point.x = ts->last_input_x;
indata.point.y = ts->last_input_y;
indata.state = LV_INDEV_STATE_REL;
SendTouchInputEvent(&indata);
#endif
}
}
#ifdef FT6336U_USE_RELEASE_TIMER
static void ft6336_timeout_callback(TimerHandle_t timer)
{
struct ft6336u_ts_data *ts = (struct ft6336u_ts_data *)pvTimerGetTimerID(timer);
if(!ts) {
FT6336U_ERR("Invalid ts.\n");
return;
}
if(ts->last_input_state != FT6336U_INDEV_STATE_UP) { //drop release event.
#ifdef AWTK
XM_TpEventProc (XM_EVENT_TOUCHUP, ts->last_input_x, ts->last_input_y, 0);
#else
lv_indev_data_t indata = {0};
indata.point.x = ts->last_input_x;
indata.point.y = ts->last_input_y;
indata.state = LV_INDEV_STATE_REL;
SendTouchInputEventFromISR(&indata);
#endif
FT6336U_ERR("Force report release event\n");
}
}
#endif
static void ft6336u_ts_irq_task(void *param)
{
uint32_t ulNotifiedValue;
struct ft6336u_ts_data *ts;
for(;;) {
xTaskNotifyWait( 0x00, /* Don't clear any notification bits on entry. */
0xffffffff, /* Reset the notification value to 0 on exit. */
&ulNotifiedValue, /* Notified value pass out in ulNotifiedValue. */
portMAX_DELAY);
ts = (struct ft6336u_ts_data *)ulNotifiedValue;
if(!ts) {
FT6336U_ERR("Invalid ts.\n");
continue;
}
#ifdef FT6336U_USE_RELEASE_TIMER
if(ts->release_timer)
xTimerStop(ts->release_timer, 0);
#endif
ft6336u_process_events(ts);
#ifdef FT6336U_USE_RELEASE_TIMER
if(ts->release_timer)
{
xTimerReset(ts->release_timer, 0);
xTimerStart(ts->release_timer, 0);
}
#endif
}
}
static void ft6336u_ts_irq_handler(void *param)
{
struct ft6336u_ts_data *ts = (struct ft6336u_ts_data *)param;
if(ts)
xTaskNotifyFromISR(ts->irq_task, (uint32_t)ts, eSetValueWithOverwrite, 0);
}
static int ft6336u_request_irq(struct ft6336u_ts_data *ts)
{
int ret = -1;
if(GPIO_IS_VALID(ts->gpio_int)) {
gpio_direction_input(ts->gpio_int);
if(gpio_irq_request(ts->gpio_int, ts->irq_flags, ft6336u_ts_irq_handler, ts)) {
FT6336U_ERR("gpio irq request failed\n");
return -1;
}
ret = 0;
}
return ret;
}
static int ft6336u_configure_dev(struct ft6336u_ts_data *ts)
{
int ret;
ret = xTaskCreate(ft6336u_ts_irq_task, "ft6336u irq task", 1024, ts, 10, &ts->irq_task);
if(ret != pdPASS) {
FT6336U_ERR("create ft6336u irq task fail.\n");
return -1;
}
ret = ft6336u_request_irq(ts);
if(ret) {
FT6336U_ERR("request IRQ failed\n");
if(ts->irq_task)
vTaskDelete(ts->irq_task);
return ret;
}
return 0;
}
static int ft6336u_read_chip_id(struct ft6336u_ts_data *ts)
{
int retry = 3;
int ret;
do {
ret = ft6336u_i2c_read(ts->adap, FT6336U_CHIP_ID, &ts->id, 1);
if(ret == 0) {
FT6336U_DBG("FT6336U ID %d\n", ts->id);
return 0;
}
vTaskDelay(pdMS_TO_TICKS(10));
} while(retry--);
return -1;
}
static int ft6336u_get_chip_para(struct ft6336u_ts_data *ts)
{
int ret;
ret = ft6336u_read_chip_id(ts);
if(ret) {
FT6336U_ERR("read chip id failed\n");
return ret;
}
if(ts->id != 0x64) {
FT6336U_ERR("Invalid chip ID:0x%2x\n", ts->id);
return -1;
}
ts->irq_flags = IRQ_TYPE_EDGE_FALLING;
ts->max_touch_num = FT6336U_MAX_CONTACTS;
ts->x_max = FT6336U_CONFIG_X_MAX;
ts->y_max = FT6336U_CONFIG_Y_MAX;
return 0;
}
static int ft6336u_reset(struct ft6336u_ts_data *ts)
{
if(GPIO_IS_VALID(ts->gpio_rst)) {
gpio_direction_output(ts->gpio_rst, 0);
vTaskDelay(pdMS_TO_TICKS(10)); /* Trst: > 5ms */
gpio_direction_output(ts->gpio_rst, 1);
vTaskDelay(pdMS_TO_TICKS(200)); /* tpon: 200ms */
return 0;
}
return -1;
}
static int ft6336u_ts_probe(struct i2c_adapter *adap)
{
struct ft6336u_ts_data *ts;
int ret;
ts = pvPortMalloc(sizeof(*ts));
if(!ts) {
FT6336U_ERR("malloc failed.\n");
return -ENOMEM;
}
memset(ts, 0, sizeof(*ts));
ts->adap = adap;
ts->adap->addr = FT6336U_SLAVE_ADDR;
ts->gpio_int = FT6336U_GPIO_INT;
ts->gpio_rst = FT6336U_GPIO_RST;
ret = ft6336u_reset(ts);
if(ret) {
FT6336U_ERR("Controller reset failed.\n");
// goto exit;
}
ret = ft6336u_get_chip_para(ts);
if(ret) {
FT6336U_ERR("version id unmatches.\n");
goto exit;
}
#ifdef FT6336U_USE_RELEASE_TIMER
ts->release_timer = xTimerCreate("FT6336 Release Timer",
pdMS_TO_TICKS(200),
pdFALSE,
ts,
ft6336_timeout_callback
);
#endif
ret = ft6336u_configure_dev(ts);
if(ret) {
FT6336U_ERR("ft6336u_configure_dev failed.\n");
goto exit;
}
return 0;
exit:
vPortFree(ts);
return -1;
}
int ft6336u_init(void)
{
struct i2c_adapter *adap = NULL;
if(!(adap = i2c_open("i2c0"))) {
FT6336U_ERR("open i2c0 fail.\n");
return -1;
}
if(ft6336u_ts_probe(adap)) {
FT6336U_ERR("ft6336u probe fail\n");
i2c_close(adap);
return -1;
}
return 0;
}
#endif

View File

@ -0,0 +1,695 @@
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include "FreeRTOS.h"
#include "chip.h"
#include "board.h"
#ifdef TP_USE_GA657X
#if !defined(VG_ONLY) && !defined(AWTK)
#include "lvgl/lvgl.h"
#else
typedef int16_t lv_coord_t;
typedef uint8_t lv_indev_state_t;
typedef struct {
lv_coord_t x;
lv_coord_t y;
} lv_point_t;
enum { LV_INDEV_STATE_REL = 0, LV_INDEV_STATE_PR };
enum {
LV_KEY_UP = 17, /*0x11*/
LV_KEY_DOWN = 18, /*0x12*/
LV_KEY_RIGHT = 19, /*0x13*/
LV_KEY_LEFT = 20, /*0x14*/
LV_KEY_ESC = 27, /*0x1B*/
LV_KEY_DEL = 127, /*0x7F*/
LV_KEY_BACKSPACE = 8, /*0x08*/
LV_KEY_ENTER = 10, /*0x0A, '\n'*/
LV_KEY_NEXT = 9, /*0x09, '\t'*/
LV_KEY_PREV = 11, /*0x0B, '*/
LV_KEY_HOME = 2, /*0x02, STX*/
LV_KEY_END = 3, /*0x03, ETX*/
};
typedef struct {
lv_point_t point; /**< For LV_INDEV_TYPE_POINTER the currently pressed point*/
uint32_t key; /**< For LV_INDEV_TYPE_KEYPAD the currently pressed key*/
uint32_t btn_id; /**< For LV_INDEV_TYPE_BUTTON the currently pressed button*/
int16_t enc_diff; /**< For LV_INDEV_TYPE_ENCODER number of steps since the previous read*/
lv_indev_state_t state; /**< LV_INDEV_STATE_REL or LV_INDEV_STATE_PR*/
} lv_indev_data_t;
#endif
#define GOODIX_GPIO_INT_NAME "irq"
#define GOODIX_GPIO_RST_NAME "reset"
#define GOODIX_MAX_HEIGHT 4096
#define GOODIX_MAX_WIDTH 4096
#define GOODIX_INT_TRIGGER 1// 1//<2F>½<EFBFBD><C2BD><EFBFBD> 0 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#define GOODIX_CONTACT_SIZE 8
#define GOODIX_MAX_CONTACTS 10
#define GOODIX_CONFIG_MAX_LENGTH 240
#define GOODIX_CONFIG_911_LENGTH 186
#define GOODIX_CONFIG_967_LENGTH 228
/* Register defines */
#define GOODIX_REG_COMMAND 0x8040
#define GOODIX_CMD_SCREEN_OFF 0x05
#define GOODIX_READ_COOR_ADDR 0x814E
#define GOODIX_GT1X_REG_CONFIG_DATA 0x8050
#define GOODIX_GT9X_REG_CONFIG_DATA 0x8047
#define GOODIX_GT6571_REG_CONFIG_DATA 0x814E
#define GOODIX_REG_ID 0x8140
#define GOODIX_BUFFER_STATUS_READY BIT(7)
#define GOODIX_BUFFER_STATUS_TIMEOUT 20
#define RESOLUTION_LOC 1
#define MAX_CONTACTS_LOC 5
#define TRIGGER_LOC 6
#define GT657X_SLAVE_ADDR 0x5d
#define GT657X_GPIO_INT TP_GPIO_INT
#define GT657X_GPIO_RST TP_GPIO_RST
#define GT657X_INVERTED_X TP_INV_Y
#define GT657X_INVERTED_Y TP_INV_Y
#define GT657X_MT_TOUCH TP_MT_TOUCH
struct goodix_ts_data;
struct goodix_chip_data {
u16 config_addr;
int config_len;
};
struct goodix_ts_data {
struct i2c_adapter *adap;
const struct goodix_chip_data *chip;
unsigned int max_touch_num;
unsigned int x_max;
unsigned int y_max;
unsigned int int_trigger_type;
int gpio_int;
int gpio_rst;
u16 id;
u16 version;
const char cfg_name[32];
unsigned long irq_flags;
TaskHandle_t irq_task;
};
static const struct goodix_chip_data gt1x_chip_data = {
.config_addr = GOODIX_GT1X_REG_CONFIG_DATA,
.config_len = GOODIX_CONFIG_MAX_LENGTH,
};
static const struct goodix_chip_data gt911_chip_data = {
.config_addr = GOODIX_GT9X_REG_CONFIG_DATA,
.config_len = GOODIX_CONFIG_911_LENGTH,
};
static const struct goodix_chip_data gt967_chip_data = {
.config_addr = GOODIX_GT9X_REG_CONFIG_DATA,
.config_len = GOODIX_CONFIG_967_LENGTH,
};
static const struct goodix_chip_data gt6571_chip_data = {
.config_addr = GOODIX_GT6571_REG_CONFIG_DATA,
.config_len = GOODIX_CONFIG_967_LENGTH,
};
static const struct goodix_chip_data gt9x_chip_data = {
.config_addr = GOODIX_GT9X_REG_CONFIG_DATA,
.config_len = GOODIX_CONFIG_MAX_LENGTH,
};
static const unsigned long goodix_irq_flags[] = {
IRQ_TYPE_EDGE_RISING,
IRQ_TYPE_EDGE_FALLING,
IRQ_TYPE_LEVEL_LOW,
IRQ_TYPE_LEVEL_HIGH,
};
static int last_input_x, last_input_y;
extern void SendTouchInputEvent(lv_indev_data_t *indata);
#ifdef AWTK
#include <xm_base.h>
#include <xm_event.h>
#endif
static inline int get_unaligned_le16(void *p)
{
u8 *tmp = (u8*)p;
return (tmp[1] << 8) | tmp[0];
}
/**
* goodix_i2c_read - read data from a register of the i2c slave device.
*
* @adap: i2c device.
* @reg: the register to read from.
* @buf: raw write data buffer.
* @len: length of the buffer to write
*/
static int goodix_i2c_read(struct i2c_adapter *adap,
u16 reg, u8 *buf, int len)
{
struct i2c_msg msgs[2];
u8 wbuf[2];
int ret;
wbuf[0] = reg >> 8;
wbuf[1] = reg & 0xFF;
msgs[0].flags = 0;
msgs[0].addr = GT657X_SLAVE_ADDR;
msgs[0].len = 2;
msgs[0].buf = (u8 *)&wbuf;
msgs[1].flags = I2C_M_RD;
msgs[1].addr = GT657X_SLAVE_ADDR;
msgs[1].len = len;
msgs[1].buf = buf;
ret = i2c_transfer(adap, msgs, 2);
return ret < 0 ? ret : (ret != ARRAY_SIZE(msgs) ? -EIO : 0);
}
/**
* goodix_i2c_write - write data to a register of the i2c slave device.
*
* @adap: i2c device.
* @reg: the register to write to.
* @buf: raw data buffer to write.
* @len: length of the buffer to write
*/
static int goodix_i2c_write(struct i2c_adapter *adap, u16 reg, const u8 *buf,
unsigned len)
{
u8 *addr_buf;
struct i2c_msg msg;
int ret;
addr_buf = pvPortMalloc(len + 2);
if (!addr_buf)
return -ENOMEM;
addr_buf[0] = reg >> 8;
addr_buf[1] = reg & 0xFF;
memcpy(&addr_buf[2], buf, len);
msg.flags = 0;
msg.addr = GT657X_SLAVE_ADDR;
msg.buf = addr_buf;
msg.len = len + 2;
ret = i2c_transfer(adap, &msg, 1);
vPortFree(addr_buf);
return ret < 0 ? ret : (ret != 1 ? -EIO : 0);
}
static int goodix_i2c_write_u8(struct i2c_adapter *adap, u16 reg, u8 value)
{
return goodix_i2c_write(adap, reg, &value, sizeof(value));
}
static const struct goodix_chip_data *goodix_get_chip_data(u16 id)
{
switch (id) {
case 1151:
return &gt1x_chip_data;
case 911:
case 9271:
case 9110:
case 927:
case 928:
return &gt911_chip_data;
case 912:
case 967:
return &gt967_chip_data;
case 6571:
return &gt6571_chip_data;
default:
return &gt9x_chip_data;
}
}
static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
{
unsigned long max_timeout;
int touch_num;
int error;
/*
* The 'buffer status' bit, which indicates that the data is valid, is
* not set as soon as the interrupt is raised, but slightly after.
* This takes around 10 ms to happen, so we poll for 20 ms.
*/
max_timeout = xTaskGetTickCount() + pdMS_TO_TICKS(GOODIX_BUFFER_STATUS_TIMEOUT);
do {
error = goodix_i2c_read(ts->adap, GOODIX_READ_COOR_ADDR,
data, GOODIX_CONTACT_SIZE + 1);
if (error) {
printf("I2C transfer error: %d\n", error);
return error;
}
if (data[0] & GOODIX_BUFFER_STATUS_READY) {
touch_num = data[0] & 0x0f;
if (touch_num > ts->max_touch_num)
return -EPROTO;
#ifdef GT9XX_MT_TOUCH
if (touch_num > 1) {
data += 1 + GOODIX_CONTACT_SIZE;
error = goodix_i2c_read(ts->adap,
GOODIX_READ_COOR_ADDR +
1 + GOODIX_CONTACT_SIZE,
data,
GOODIX_CONTACT_SIZE *
(touch_num - 1));
if (error)
return error;
}
return touch_num;
#else
return touch_num > 0 ? 1 : 0;
#endif
}
vTaskDelay(pdMS_TO_TICKS(1)); /* Poll every 1 - 2 ms */
} while (xTaskGetTickCount() < max_timeout);
/*
* The Goodix panel will send spurious interrupts after a
* 'finger up' event, which will always cause a timeout.
*/
return 0;
}
static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
{
int id = coor_data[0] & 0x0F;
int input_x = get_unaligned_le16(&coor_data[1]);
int input_y = get_unaligned_le16(&coor_data[3]);
int input_w = get_unaligned_le16(&coor_data[5]);
printf("id=0x%x, input_x=%d, input_y=%d, input_w=%d.\n", id, input_x,
input_y, input_w);
#if GT657X_INVERTED_X
input_x = ts->x_max - input_x;
#endif
#if GT657X_INVERTED_Y
input_y = ts->y_max - input_y;
#endif
//send press event
#ifdef AWTK
XM_TpEventProc (XM_EVENT_TOUCHDOWN, input_x, input_y, 0);
#else
lv_indev_data_t indata = {0};
indata.point.x = input_x;
indata.point.y = input_y;
indata.state = LV_INDEV_STATE_PR;
SendTouchInputEvent(&indata);
#endif
last_input_x = input_x;
last_input_y = input_y;
}
/**
* goodix_process_events - Process incoming events
*
* @ts: our goodix_ts_data pointer
*
* Called when the IRQ is triggered. Read the current device state, and push
* the input events to the user space.
*/
static void goodix_process_events(struct goodix_ts_data *ts)
{
u8 point_data[1 + GOODIX_CONTACT_SIZE * GOODIX_MAX_CONTACTS];
int touch_num;
int i;
touch_num = goodix_ts_read_input_report(ts, point_data);
if (touch_num < 0)
return;
/*
* Bit 4 of the first byte reports the status of the capacitive
* Windows/Home button.
*/
//input_report_key(ts->input_dev, KEY_LEFTMETA, point_data[0] & BIT(4));
for (i = 0; i < touch_num; i++)
goodix_ts_report_touch(ts,
&point_data[1 + GOODIX_CONTACT_SIZE * i]);
if (touch_num == 0) {
//send release event
#ifdef AWTK
XM_TpEventProc (XM_EVENT_TOUCHUP, last_input_x, last_input_y, 0);
#else
lv_indev_data_t indata = {0};
indata.point.x = last_input_x;
indata.point.y = last_input_y;
indata.state = LV_INDEV_STATE_REL;
SendTouchInputEvent(&indata);
#endif
}
/* input_mt_sync_frame(ts->input_dev);
input_sync(ts->input_dev); */
}
static void goodix_ts_irq_task(void *param)
{
uint32_t ulNotifiedValue;
struct goodix_ts_data *ts;
for (;;) {
xTaskNotifyWait( 0x00, /* Don't clear any notification bits on entry. */
0xffffffff, /* Reset the notification value to 0 on exit. */
&ulNotifiedValue, /* Notified value pass out in ulNotifiedValue. */
portMAX_DELAY);
ts = (struct goodix_ts_data *)ulNotifiedValue;
goodix_process_events(ts);
if (goodix_i2c_write_u8(ts->adap, GOODIX_READ_COOR_ADDR, 0) < 0)
TRACE_ERROR("I2C write end_cmd error.\n");
}
}
/**
* goodix_ts_irq_handler - The IRQ handler
*
* @param: private data pointer.
*/
static void goodix_ts_irq_handler(void *param)
{
struct goodix_ts_data *ts = param;
xTaskNotifyFromISR(ts->irq_task, (uint32_t)ts, eSetValueWithOverwrite, 0);
return;
}
static int goodix_request_irq(struct goodix_ts_data *ts)
{
if (xTaskCreate(goodix_ts_irq_task, "gt9xx", 1024, ts,
10, &ts->irq_task) != pdPASS) {
printf("create gt9xx irq task fail.\n");
}
return gpio_irq_request(ts->gpio_int, ts->irq_flags, goodix_ts_irq_handler, ts);
}
static int goodix_int_sync(struct goodix_ts_data *ts)
{
gpio_direction_output(ts->gpio_int, 0);
vTaskDelay(pdMS_TO_TICKS(50)); /* T5: 50ms */
gpio_direction_input(ts->gpio_int);
return 0;
}
/**
* goodix_reset - Reset device during power on
*
* @ts: goodix_ts_data pointer
*/
static int goodix_reset(struct goodix_ts_data *ts)
{
int error;
/* begin select I2C slave addr */
gpio_direction_output(ts->gpio_rst, 0);
vTaskDelay(pdMS_TO_TICKS(50)); /* T2: > 10ms */
/* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
gpio_direction_output(ts->gpio_int, GT657X_SLAVE_ADDR == 0x14);
vTaskDelay(pdMS_TO_TICKS(1)); /* T3: > 100us */
gpio_direction_output(ts->gpio_rst, 1);
vTaskDelay(pdMS_TO_TICKS(30)); /* T4: > 5ms */
/* end select I2C slave addr */
gpio_direction_input(ts->gpio_rst);
error = goodix_int_sync(ts);
if (error)
return error;
return 0;
}
/**
* goodix_read_config - Read the embedded configuration of the panel
*
* @ts: our goodix_ts_data pointer
*
* Must be called during probe
*/
static void goodix_read_config(struct goodix_ts_data *ts)
{
u8 config[GOODIX_CONFIG_MAX_LENGTH];
int error;
error = goodix_i2c_read(ts->adap, ts->chip->config_addr,
config, ts->chip->config_len);
if (error) {
printf("Error reading config: %d\n", error);
ts->int_trigger_type = GOODIX_INT_TRIGGER;
ts->max_touch_num = GOODIX_MAX_CONTACTS;
return;
}
ts->int_trigger_type = config[TRIGGER_LOC] & 0x03;
ts->max_touch_num = GOODIX_MAX_CONTACTS;//config[MAX_CONTACTS_LOC] & 0x0f;
ts->x_max = get_unaligned_le16(&config[RESOLUTION_LOC]);
ts->y_max = get_unaligned_le16(&config[RESOLUTION_LOC + 2]);
}
/**
* goodix_read_version - Read goodix touchscreen version
*
* @ts: our goodix_ts_data pointer
*/
static int goodix_read_version(struct goodix_ts_data *ts)
{
int error;
u8 buf[6];
char id_str[5];
error = goodix_i2c_read(ts->adap, GOODIX_REG_ID, buf, sizeof(buf));
if (error) {
TRACE_INFO("read version failed: %d\n", error);
return error;
}
memcpy(id_str, buf, 4);
id_str[4] = 0;
char *ptr;
ts->id = strtoul(id_str, &ptr, 10);
if (ts->id == 0xffff)
ts->id = 0x1001;
ts->version = get_unaligned_le16(&buf[4]);
TRACE_INFO("ID %d, version: %04x\n", ts->id, ts->version);
return 0;
}
/**
* goodix_i2c_test - I2C test function to check if the device answers.
*
* @adap: the i2c adapter
*/
static int goodix_i2c_test(struct i2c_adapter *adap)
{
int retry = 0;
int error;
u8 test;
while (retry++ < 5) {
error = goodix_i2c_read(adap, GOODIX_REG_ID,
&test, 1);
if (!error)
return 0;
TRACE_ERROR("i2c test failed attempt %d: %d\n",
retry, error);
vTaskDelay(pdMS_TO_TICKS(20));
}
return error;
}
/**
* goodix_configure_dev - Finish device initialization
*
* @ts: our goodix_ts_data pointer
*
* Must be called from probe to finish initialization of the device.
* Contains the common initialization code for both devices that
* declare gpio pins and devices that do not. It is either called
* directly from probe or from request_firmware_wait callback.
*/
static int goodix_configure_dev(struct goodix_ts_data *ts)
{
int error;
ts->int_trigger_type = GOODIX_INT_TRIGGER;
ts->max_touch_num = GOODIX_MAX_CONTACTS;
/* Read configuration and apply touchscreen parameters */
goodix_read_config(ts);
ts->irq_flags = goodix_irq_flags[ts->int_trigger_type];
error = goodix_request_irq(ts);
if (error) {
TRACE_ERROR("request IRQ failed: %d\n", error);
return error;
}
return 0;
}
static const unsigned char zero[2] = {0,0};
static const unsigned char cmd[186] = {
0x43,0x61,0x1C,0x1E,0x73,0x13,0x00,0x1B,0x52,0x9C,0x85,0x00,0xFF,0x5A,0x4B,0x00,0x00,0x16,0x1A,0x20,0x14,
0x00,0x00,0xFF,0xFF,0x00,0x00,0x3F,0x01,0x94,0x50,0x05,0x42,0x00,0x00,0x00,0xF0,0x00,0x05,0xD0,0x02,0x10,0x10,0xBB,0x15,
0x14,0x13,0x12,0x11,0x10,0x0F,0x0E,0x0D,0x0C,0x0B,0x0A,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0E,0x0F,0x10,0x11,0x12,0x13,0x19,0x1B,0x1C,
0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,
0x0F,0x32,0x8C,0xE3,0x81,0x14,0x04,0x00,0xD6,0x12,0x00,0xBF,0x18,0x00,0xAE,0x20,0x00,0x9E,0x2A,0x00,0x92,0x39,0x00,0x92,
0x00,0x00,0x00,0x6A,0x00,0xAC,0x64,0x32,0x00,0xAA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x14,0x03,0x32,0x23,0xAF,0x00,0x0F,0x32,0x09,0x01,0x3C,0xC8,0x33,0x64,0x50,0x8F,0x55,0xC8,0x00,0x00,0x30,0x01
};
//static const unsigned char buff[186] = {0};
int goodix_ts_probe(struct i2c_adapter *adap)
{
struct goodix_ts_data *ts;
int error;
//u8 i=0;
TRACE_DEBUG("I2C Address: 0x%02x\n", GT657X_SLAVE_ADDR);
ts = pvPortMalloc(sizeof(*ts));
if (!ts)
return -ENOMEM;
memset(ts, 0, sizeof(*ts));
ts->adap = adap;
ts->gpio_int = GT657X_GPIO_INT;
ts->gpio_rst = GT657X_GPIO_RST;
if (ts->gpio_int && ts->gpio_rst) {
/* reset the controller */
error = goodix_reset(ts);
if (error) {
TRACE_ERROR("Controller reset failed.\n");
return error;
}
}
error = goodix_i2c_test(adap);
if (error) {
TRACE_ERROR("I2C communication failure: %d\n", error);
return error;
}
error = goodix_read_version(ts);
if (error) {
TRACE_ERROR("Read version failed.\n");
return error;
}
printf("ts->id is %x \n ",ts->id);
ts->chip = goodix_get_chip_data(ts->id);
do{
printf("goodix_i2c_write \n ");
error= goodix_i2c_write(ts->adap, GOODIX_READ_COOR_ADDR, (unsigned char *)&zero[0],2);
}while(error!=0);
error= goodix_i2c_write(ts->adap, 0x8047, (unsigned char *)&cmd[0],sizeof(cmd));
if (error)
{
printf("goodix_i2c_write error\n");
return error;
}
#if 0
error = goodix_i2c_read(ts->adap, 0x8047,
(unsigned char *)&buff[0], 186);
for(i=0;i<186;i++)
{
if(buff[i]!=cmd[i])
{
printf("i is %x \n",i);
printf("buff is %x \n",buff[i]);
printf("cmd is %x \n",cmd[i]);
}
}
#endif
error = goodix_configure_dev(ts);
if (error)
{
printf("goodix_configure_dev error \n ");
return error;
}
return 0;
}
int gt675x_init(void)
{
struct i2c_adapter *adap = NULL;
if (!(adap = i2c_open("i2c0"))) {
printf("open i2c0 fail.\n");
return -1;
}
goodix_ts_probe(adap);
return 0;
}
#endif

View File

@ -0,0 +1,635 @@
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include "FreeRTOS.h"
#include "chip.h"
#include "board.h"
#ifdef TP_USE_GT9XX
#if !defined(VG_ONLY) && !defined(AWTK)
#include "lvgl/lvgl.h"
#else
typedef int16_t lv_coord_t;
typedef uint8_t lv_indev_state_t;
typedef struct {
lv_coord_t x;
lv_coord_t y;
} lv_point_t;
enum { LV_INDEV_STATE_REL = 0, LV_INDEV_STATE_PR };
enum {
LV_KEY_UP = 17, /*0x11*/
LV_KEY_DOWN = 18, /*0x12*/
LV_KEY_RIGHT = 19, /*0x13*/
LV_KEY_LEFT = 20, /*0x14*/
LV_KEY_ESC = 27, /*0x1B*/
LV_KEY_DEL = 127, /*0x7F*/
LV_KEY_BACKSPACE = 8, /*0x08*/
LV_KEY_ENTER = 10, /*0x0A, '\n'*/
LV_KEY_NEXT = 9, /*0x09, '\t'*/
LV_KEY_PREV = 11, /*0x0B, '*/
LV_KEY_HOME = 2, /*0x02, STX*/
LV_KEY_END = 3, /*0x03, ETX*/
};
typedef struct {
lv_point_t point; /**< For LV_INDEV_TYPE_POINTER the currently pressed point*/
uint32_t key; /**< For LV_INDEV_TYPE_KEYPAD the currently pressed key*/
uint32_t btn_id; /**< For LV_INDEV_TYPE_BUTTON the currently pressed button*/
int16_t enc_diff; /**< For LV_INDEV_TYPE_ENCODER number of steps since the previous read*/
lv_indev_state_t state; /**< LV_INDEV_STATE_REL or LV_INDEV_STATE_PR*/
} lv_indev_data_t;
#endif
#define GOODIX_GPIO_INT_NAME "irq"
#define GOODIX_GPIO_RST_NAME "reset"
#define GOODIX_MAX_HEIGHT 4096
#define GOODIX_MAX_WIDTH 4096
#define GOODIX_INT_TRIGGER 1
#define GOODIX_CONTACT_SIZE 8
#define GOODIX_MAX_CONTACTS 10
#define GOODIX_CONFIG_MAX_LENGTH 240
#define GOODIX_CONFIG_911_LENGTH 186
#define GOODIX_CONFIG_967_LENGTH 228
/* Register defines */
#define GOODIX_REG_COMMAND 0x8040
#define GOODIX_CMD_SCREEN_OFF 0x05
#define GOODIX_READ_COOR_ADDR 0x814E
#define GOODIX_GT1X_REG_CONFIG_DATA 0x8050
#define GOODIX_GT9X_REG_CONFIG_DATA 0x8047
#define GOODIX_REG_ID 0x8140
#define GOODIX_BUFFER_STATUS_READY BIT(7)
#define GOODIX_BUFFER_STATUS_TIMEOUT 20
#define RESOLUTION_LOC 1
#define MAX_CONTACTS_LOC 5
#define TRIGGER_LOC 6
#define GT9XX_SLAVE_ADDR 0x5d
#define GT9XX_GPIO_INT TP_GPIO_INT
#define GT9XX_GPIO_RST TP_GPIO_RST
#define GT9XX_INVERTED_X TP_INV_X
#define GT9XX_INVERTED_Y TP_INV_Y
#define GT9XX_MT_TOUCH TP_MT_TOUCH//支持多点触摸
struct goodix_ts_data;
struct goodix_chip_data {
u16 config_addr;
int config_len;
};
struct goodix_ts_data {
struct i2c_adapter *adap;
const struct goodix_chip_data *chip;
unsigned int max_touch_num;
unsigned int x_max;
unsigned int y_max;
unsigned int int_trigger_type;
int gpio_int;
int gpio_rst;
u16 id;
u16 version;
const char cfg_name[32];
unsigned long irq_flags;
TaskHandle_t irq_task;
};
static const struct goodix_chip_data gt1x_chip_data = {
.config_addr = GOODIX_GT1X_REG_CONFIG_DATA,
.config_len = GOODIX_CONFIG_MAX_LENGTH,
};
static const struct goodix_chip_data gt911_chip_data = {
.config_addr = GOODIX_GT9X_REG_CONFIG_DATA,
.config_len = GOODIX_CONFIG_911_LENGTH,
};
static const struct goodix_chip_data gt967_chip_data = {
.config_addr = GOODIX_GT9X_REG_CONFIG_DATA,
.config_len = GOODIX_CONFIG_967_LENGTH,
};
static const struct goodix_chip_data gt9x_chip_data = {
.config_addr = GOODIX_GT9X_REG_CONFIG_DATA,
.config_len = GOODIX_CONFIG_MAX_LENGTH,
};
static const unsigned long goodix_irq_flags[] = {
IRQ_TYPE_EDGE_RISING,
IRQ_TYPE_EDGE_FALLING,
IRQ_TYPE_LEVEL_LOW,
IRQ_TYPE_LEVEL_HIGH,
};
static int last_input_x, last_input_y;
extern void SendTouchInputEvent(lv_indev_data_t *indata);
#ifdef AWTK
#include <xm_base.h>
#include <xm_event.h>
#endif
static inline int get_unaligned_le16(void *p)
{
u8 *tmp = (u8*)p;
return (tmp[1] << 8) | tmp[0];
}
/**
* goodix_i2c_read - read data from a register of the i2c slave device.
*
* @adap: i2c device.
* @reg: the register to read from.
* @buf: raw write data buffer.
* @len: length of the buffer to write
*/
static int goodix_i2c_read(struct i2c_adapter *adap,
u16 reg, u8 *buf, int len)
{
struct i2c_msg msgs[2];
u8 wbuf[2];
int ret;
wbuf[0] = reg >> 8;
wbuf[1] = reg & 0xFF;
msgs[0].flags = 0;
msgs[0].addr = GT9XX_SLAVE_ADDR;
msgs[0].len = 2;
msgs[0].buf = (u8 *)&wbuf;
msgs[1].flags = I2C_M_RD;
msgs[1].addr = GT9XX_SLAVE_ADDR;
msgs[1].len = len;
msgs[1].buf = buf;
ret = i2c_transfer(adap, msgs, 2);
return ret < 0 ? ret : (ret != ARRAY_SIZE(msgs) ? -EIO : 0);
}
/**
* goodix_i2c_write - write data to a register of the i2c slave device.
*
* @adap: i2c device.
* @reg: the register to write to.
* @buf: raw data buffer to write.
* @len: length of the buffer to write
*/
static int goodix_i2c_write(struct i2c_adapter *adap, u16 reg, const u8 *buf,
unsigned len)
{
u8 *addr_buf;
struct i2c_msg msg;
int ret;
addr_buf = pvPortMalloc(len + 2);
if (!addr_buf)
return -ENOMEM;
addr_buf[0] = reg >> 8;
addr_buf[1] = reg & 0xFF;
memcpy(&addr_buf[2], buf, len);
msg.flags = 0;
msg.addr = GT9XX_SLAVE_ADDR;
msg.buf = addr_buf;
msg.len = len + 2;
ret = i2c_transfer(adap, &msg, 1);
vPortFree(addr_buf);
return ret < 0 ? ret : (ret != 1 ? -EIO : 0);
}
static int goodix_i2c_write_u8(struct i2c_adapter *adap, u16 reg, u8 value)
{
return goodix_i2c_write(adap, reg, &value, sizeof(value));
}
static const struct goodix_chip_data *goodix_get_chip_data(u16 id)
{
switch (id) {
case 1151:
return &gt1x_chip_data;
case 911:
case 9271:
case 9110:
case 927:
case 928:
return &gt911_chip_data;
case 912:
case 967:
return &gt967_chip_data;
default:
return &gt9x_chip_data;
}
}
static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
{
unsigned long max_timeout;
int touch_num;
int error;
/*
* The 'buffer status' bit, which indicates that the data is valid, is
* not set as soon as the interrupt is raised, but slightly after.
* This takes around 10 ms to happen, so we poll for 20 ms.
*/
max_timeout = xTaskGetTickCount() + pdMS_TO_TICKS(GOODIX_BUFFER_STATUS_TIMEOUT);
do {
error = goodix_i2c_read(ts->adap, GOODIX_READ_COOR_ADDR,
data, GOODIX_CONTACT_SIZE + 1);
if (error) {
TRACE_ERROR("I2C transfer error: %d\n", error);
return error;
}
if (data[0] & GOODIX_BUFFER_STATUS_READY) {
touch_num = data[0] & 0x0f;
if (touch_num > ts->max_touch_num)
return -EPROTO;
#if GT9XX_MT_TOUCH
if (touch_num > 1) {
data += 1 + GOODIX_CONTACT_SIZE;
error = goodix_i2c_read(ts->adap,
GOODIX_READ_COOR_ADDR +
1 + GOODIX_CONTACT_SIZE,
data,
GOODIX_CONTACT_SIZE *
(touch_num - 1));
if (error)
return error;
}
return touch_num;
#else
return touch_num > 0 ? 1 : 0;
#endif
}
vTaskDelay(pdMS_TO_TICKS(1)); /* Poll every 1 - 2 ms */
} while (xTaskGetTickCount() < max_timeout);
/*
* The Goodix panel will send spurious interrupts after a
* 'finger up' event, which will always cause a timeout.
*/
return 0;
}
static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
{
//int id = coor_data[0] & 0x0F;
int input_x = get_unaligned_le16(&coor_data[1]);
int input_y = get_unaligned_le16(&coor_data[3]);
int input_w = get_unaligned_le16(&coor_data[5]);
/* printf("id=0x%x, input_x=%d, input_y=%d, input_w=%d.\n", id, input_x,
input_y, input_w); */
#if GT9XX_INVERTED_X
input_x = ts->x_max - input_x;
#endif
#if GT9XX_INVERTED_Y
input_y = ts->y_max - input_y;
#endif
//send press event
#ifdef AWTK
XM_TpEventProc (XM_EVENT_TOUCHDOWN, input_x, input_y, 0);
#else
lv_indev_data_t indata = {0};
indata.point.x = input_x;
indata.point.y = input_y;
indata.state = LV_INDEV_STATE_PR;
SendTouchInputEvent(&indata);
#endif
last_input_x = input_x;
last_input_y = input_y;
}
/**
* goodix_process_events - Process incoming events
*
* @ts: our goodix_ts_data pointer
*
* Called when the IRQ is triggered. Read the current device state, and push
* the input events to the user space.
*/
static void goodix_process_events(struct goodix_ts_data *ts)
{
u8 point_data[1 + GOODIX_CONTACT_SIZE * GOODIX_MAX_CONTACTS];
int touch_num;
int i;
touch_num = goodix_ts_read_input_report(ts, point_data);
if (touch_num < 0)
return;
/*
* Bit 4 of the first byte reports the status of the capacitive
* Windows/Home button.
*/
//input_report_key(ts->input_dev, KEY_LEFTMETA, point_data[0] & BIT(4));
for (i = 0; i < touch_num; i++)
goodix_ts_report_touch(ts,
&point_data[1 + GOODIX_CONTACT_SIZE * i]);
if (touch_num == 0) {
//send release event
#ifdef AWTK
XM_TpEventProc (XM_EVENT_TOUCHUP, last_input_x, last_input_y, 0);
#else
lv_indev_data_t indata = {0};
indata.point.x = last_input_x;
indata.point.y = last_input_y;
indata.state = LV_INDEV_STATE_REL;
SendTouchInputEvent(&indata);
#endif
}
/* input_mt_sync_frame(ts->input_dev);
input_sync(ts->input_dev); */
}
static void goodix_ts_irq_task(void *param)
{
uint32_t ulNotifiedValue;
struct goodix_ts_data *ts;
for (;;) {
xTaskNotifyWait( 0x00, /* Don't clear any notification bits on entry. */
0xffffffff, /* Reset the notification value to 0 on exit. */
&ulNotifiedValue, /* Notified value pass out in ulNotifiedValue. */
portMAX_DELAY);
ts = (struct goodix_ts_data *)ulNotifiedValue;
goodix_process_events(ts);
if (goodix_i2c_write_u8(ts->adap, GOODIX_READ_COOR_ADDR, 0) < 0)
TRACE_ERROR("I2C write end_cmd error\n");
}
}
/**
* goodix_ts_irq_handler - The IRQ handler
*
* @param: private data pointer.
*/
static void goodix_ts_irq_handler(void *param)
{
struct goodix_ts_data *ts = param;
xTaskNotifyFromISR(ts->irq_task, (uint32_t)ts, eSetValueWithOverwrite, 0);
return;
}
static int goodix_request_irq(struct goodix_ts_data *ts)
{
if (xTaskCreate(goodix_ts_irq_task, "gt9xx", 1024, ts,
10, &ts->irq_task) != pdPASS) {
printf("create gt9xx irq task fail.\n");
}
return gpio_irq_request(ts->gpio_int, ts->irq_flags, goodix_ts_irq_handler, ts);
}
static int goodix_int_sync(struct goodix_ts_data *ts)
{
gpio_direction_output(ts->gpio_int, 0);
vTaskDelay(pdMS_TO_TICKS(50)); /* T5: 50ms */
gpio_direction_input(ts->gpio_int);
return 0;
}
/**
* goodix_reset - Reset device during power on
*
* @ts: goodix_ts_data pointer
*/
static int goodix_reset(struct goodix_ts_data *ts)
{
int error;
/* begin select I2C slave addr */
gpio_direction_output(ts->gpio_rst, 0);
vTaskDelay(pdMS_TO_TICKS(20)); /* T2: > 10ms */
/* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
gpio_direction_output(ts->gpio_int, GT9XX_SLAVE_ADDR == 0x14);
vTaskDelay(pdMS_TO_TICKS(1)); /* T3: > 100us */
gpio_direction_output(ts->gpio_rst, 1);
vTaskDelay(pdMS_TO_TICKS(6)); /* T4: > 5ms */
/* end select I2C slave addr */
gpio_direction_input(ts->gpio_rst);
error = goodix_int_sync(ts);
if (error)
return error;
return 0;
}
/**
* goodix_read_config - Read the embedded configuration of the panel
*
* @ts: our goodix_ts_data pointer
*
* Must be called during probe
*/
static void goodix_read_config(struct goodix_ts_data *ts)
{
u8 config[GOODIX_CONFIG_MAX_LENGTH];
int error;
error = goodix_i2c_read(ts->adap, ts->chip->config_addr,
config, ts->chip->config_len);
if (error) {
TRACE_WARNING("Error reading config: %d\n", error);
ts->int_trigger_type = GOODIX_INT_TRIGGER;
ts->max_touch_num = GOODIX_MAX_CONTACTS;
return;
}
ts->int_trigger_type = config[TRIGGER_LOC] & 0x03;
ts->max_touch_num = config[MAX_CONTACTS_LOC] & 0x0f;
ts->x_max = get_unaligned_le16(&config[RESOLUTION_LOC]);
ts->y_max = get_unaligned_le16(&config[RESOLUTION_LOC + 2]);
}
/**
* goodix_read_version - Read goodix touchscreen version
*
* @ts: our goodix_ts_data pointer
*/
static int goodix_read_version(struct goodix_ts_data *ts)
{
int error;
u8 buf[6];
char id_str[5];
error = goodix_i2c_read(ts->adap, GOODIX_REG_ID, buf, sizeof(buf));
if (error) {
TRACE_ERROR("read version failed: %d\n", error);
return error;
}
memcpy(id_str, buf, 4);
id_str[4] = 0;
char *ptr;
ts->id = strtoul(id_str, &ptr, 10);
if (ts->id == 0xffff)
ts->id = 0x1001;
ts->version = get_unaligned_le16(&buf[4]);
TRACE_INFO("ID %d, version: %04x\n", ts->id, ts->version);
return 0;
}
/**
* goodix_i2c_test - I2C test function to check if the device answers.
*
* @adap: the i2c adapter
*/
static int goodix_i2c_test(struct i2c_adapter *adap)
{
int retry = 0;
int error;
u8 test;
while (retry++ < 2) {
error = goodix_i2c_read(adap, GOODIX_REG_ID,
&test, 1);
if (!error)
return 0;
TRACE_ERROR("i2c test failed attempt %d: %d\n",
retry, error);
vTaskDelay(pdMS_TO_TICKS(20));
}
return error;
}
/**
* goodix_configure_dev - Finish device initialization
*
* @ts: our goodix_ts_data pointer
*
* Must be called from probe to finish initialization of the device.
* Contains the common initialization code for both devices that
* declare gpio pins and devices that do not. It is either called
* directly from probe or from request_firmware_wait callback.
*/
static int goodix_configure_dev(struct goodix_ts_data *ts)
{
int error;
ts->int_trigger_type = GOODIX_INT_TRIGGER;
ts->max_touch_num = GOODIX_MAX_CONTACTS;
/* Read configuration and apply touchscreen parameters */
goodix_read_config(ts);
ts->irq_flags = goodix_irq_flags[ts->int_trigger_type];
error = goodix_request_irq(ts);
if (error) {
TRACE_ERROR("request IRQ failed: %d\n", error);
return error;
}
return 0;
}
int goodix_ts_probe(struct i2c_adapter *adap)
{
struct goodix_ts_data *ts;
int error;
TRACE_DEBUG("I2C Address: 0x%02x\n", GT9XX_SLAVE_ADDR);
ts = pvPortMalloc(sizeof(*ts));
if (!ts)
return -ENOMEM;
memset(ts, 0, sizeof(*ts));
ts->adap = adap;
ts->gpio_int = GT9XX_GPIO_INT;
ts->gpio_rst = GT9XX_GPIO_RST;
if (ts->gpio_int && ts->gpio_rst) {
/* reset the controller */
error = goodix_reset(ts);
if (error) {
TRACE_ERROR("Controller reset failed.\n");
return error;
}
}
error = goodix_i2c_test(adap);
if (error) {
TRACE_ERROR("I2C communication failure: %d\n", error);
return error;
}
error = goodix_read_version(ts);
if (error) {
TRACE_ERROR("Read version failed.\n");
return error;
}
ts->chip = goodix_get_chip_data(ts->id);
error = goodix_configure_dev(ts);
if (error)
return error;
return 0;
}
int goodix_init(void)
{
struct i2c_adapter *adap = NULL;
if (!(adap = i2c_open("i2c0"))) {
printf("open i2c0 fail.\n");
return -1;
}
goodix_ts_probe(adap);
return 0;
}
#endif

View File

@ -0,0 +1,28 @@
#include <stdio.h>
#include "chip.h"
#include "board.h"
#ifdef TP_SUPPORT
extern int goodix_init(void);
extern int gt675x_init(void);
extern int ft6336u_init(void);
int tp_init(void)
{
#if defined(TP_USE_GT9XX)
printf("TP select gt9xx.\n");
return goodix_init();
#elif defined(TP_USE_GA657X)
printf("TP select ga657x.\n");
return gt675x_init();
#elif defined(TP_USE_FT6336U)
printf("TP select ft6336u.\n");
return ft6336u_init();
#else
#error "Please select one tp IC"
#endif
return -1;
}
#endif

View File

@ -0,0 +1,85 @@
#include <stdio.h>
#include <string.h>
#include "FreeRTOS.h"
#include "board.h"
#include "sfud.h"
#include "updatefile.h"
#include "mmcsd_core.h"
#include "sysinfo.h"
static UpFileHeader *upfile = NULL;
#if DEVICE_TYPE_SELECT != EMMC_FLASH
int GetUpFileInfo(void)
{
UpFileHeader header;
uint32_t headersize;
sfud_flash *sflash;
SysInfo *sysinfo = GetSysInfo();
sflash = sfud_get_device(0);
sfud_read(sflash, sysinfo->image_offset, sizeof(header), (void*)&header);
if (header.magic != MKTAG('U', 'P', 'D', 'F')) {
printf("Error! Wrong update file.\n");
return -1;
}
headersize = sizeof(UpFileHeader) + sizeof(UpFileInfo) * header.filenum;
upfile = pvPortMalloc(headersize);
if (!upfile) return -1;
sfud_read(sflash, sysinfo->image_offset, headersize, (void*)upfile);
return 0;
}
#else
int GetUpFileInfo(void)
{
UpFileHeader header;
uint32_t headersize;
SysInfo *sysinfo = GetSysInfo();
emmc_read(sysinfo->image_offset, sizeof(header), (void*)&header);
if (header.magic != MKTAG('U', 'P', 'D', 'F')) {
printf("Error! Wrong update file.\n");
return -1;
}
headersize = sizeof(UpFileHeader) + sizeof(UpFileInfo) * header.filenum;
upfile = pvPortMalloc(headersize);
if (!upfile) return -1;
emmc_read(sysinfo->image_offset, headersize, (void*)upfile);
return 0;
}
#endif
uint32_t GetUpFileOffset(uint32_t magic)
{
int i;
SysInfo *sysinfo = GetSysInfo();
if (!upfile) return 0;
for (i = 0; i < upfile->filenum; i++) {
if (upfile->files[i].magic == magic) {
return upfile->files[i].offset + sysinfo->image_offset;
}
}
return 0;
}
uint32_t GetUpFileSize(uint32_t magic)
{
int i;
if (!upfile) return 0;
for (i = 0; i < upfile->filenum; i++) {
if (upfile->files[i].magic == magic) {
return upfile->files[i].size;
}
}
return 0;
}

View File

@ -0,0 +1,81 @@
#ifndef _LIB_CHIP_AMT630HV100_
#define _LIB_CHIP_AMT630HV100_
/*
* Peripherals registers definitions
*/
#if defined AMT630HV100
#include "include/amt630hv100.h"
#else
#warning Library does not support the specified chip, specifying AMT630HV100
#define AMT630HV100
#include "include/amt630hv100.h"
#endif
/* Define attribute */
#if defined ( __CC_ARM ) /* Keil 礦ision 4 */
#define WEAK __attribute__ ((weak))
#elif defined ( __ICCARM__ ) /* IAR Ewarm 5.41+ */
#define WEAK __weak
#elif defined ( __GNUC__ ) /* GCC CS3 2009q3-68 */
#define WEAK __attribute__ ((weak))
#endif
/* Define NO_INIT attribute and compiler specific symbols */
#if defined ( __CC_ARM )
#define NO_INIT
#define __ASM __asm /*!< asm keyword for ARM Compiler */
#define __INLINE __inline /*!< inline keyword for ARM Compiler */
#elif defined ( __ICCARM__ )
#define NO_INIT __no_init
#define __ASM __asm /*!< asm keyword for IAR Compiler */
#define __INLINE inline /*!< inline keyword for IAR Compiler. Only avaiable in High optimization mode! */
#elif defined ( __GNUC__ )
#define __ASM asm /*!< asm keyword for GNU Compiler */
#define __INLINE inline /*!< inline keyword for GNU Compiler */
#define NO_INIT
#endif
#define CP15_PRESENT
struct device {
const char *init_name;
};
#include <stdbool.h>
/*
* Peripherals
*/
#include "errno.h"
#include "include/mmu.h"
#include "cp15/cp15.h"
#include "include/trace.h"
#include "include/sysctl.h"
#include "include/aic.h"
#include "include/timer.h"
#include "include/uart.h"
#include "include/clock.h"
#include "include/pinctrl.h"
#include "include/gpio.h"
#include "include/i2c.h"
#include "include/i2c-gpio.h"
#include "include/i2c-dw.h"
#include "include/spi.h"
#include "include/wdt.h"
#include "include/rtc.h"
#include "include/dma.h"
#include "include/lcd.h"
#include "include/pwm.h"
#include "include/itu.h"
#include "include/pxp.h"
#include "include/can.h"
#include "include/adc.h"
#include "include/sdmmc.h"
#include "include/vdec.h"
#include "include/blend2d.h"
#include "include/remote.h"
#endif /* _LIB_CHIP_AMT630HV100_ */

View File

@ -0,0 +1,363 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2011, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
//-----------------------------------------------------------------------------
// Reg Reads Writes
//----------------------------------------------------------------------------
// 0 ID code Unpredictable
// 0 cache type Unpredictable
// 0 TCM status Unpredictable
// 1 Control Control
// 2 Translation table base Translation table base
// 3 Domain access control Domain access control
// 4 (Reserved)
// 5 Data fault status Data fault status
// 5 Instruction fault status Instruction fault status
// 6 Fault address Fault address
// 7 cache operations cache operations
// 8 Unpredictable TLB operations
// 9 cache lockdown cache lockdown
// 9 TCM region TCM region
// 10 TLB lockdown TLB lockdown
// 11 (Reserved)
// 12 (Reserved)
// 13 FCSE PID FCSE PID
// 13 Context ID Context ID
// 14 (Reserved)
// 15 Test configuration Test configuration
//-----------------------------------------------------------------------------
/** \page cp15_f CP15 Functions.
*
* \section CP15 function Usage
*
* Methods to manage the Coprocessor 15. Coprocessor 15, or System Control
* Coprocessor CP15, is used to configure and control all the items in the
* list below:
* <ul>
* <li> ARM core
* <li> caches (Icache, Dcache and write buffer)
* <li> TCM
* <li> MMU
* <li> Other system options
* </ul>
* \section Usage
*
* -# Enable or disable D cache with Enable_D_cache and Disable_D_cache
* -# Enable or disable I cache with Enable_I_cache and Disable_I_cache
*
* Related files:\n
* \ref cp15.h\n
* \ref cp15.c.\n
*/
/** \file */
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#if defined(__ICCARM__)
#include <intrinsics.h>
#endif
/*----------------------------------------------------------------------------
* Global functions
*----------------------------------------------------------------------------*/
/**
* \brief Check Instruction cache
* \return 0 if I_cache disable, 1 if I_cache enable
*/
unsigned int CP15_IsIcacheEnabled(void)
{
unsigned int control;
control = CP15_ReadControl();
return ((control & (1 << CP15_I_BIT)) != 0);
}
/**
* \brief Enable Instruction cache
*/
void CP15_EnableIcache(void)
{
unsigned int control;
control = CP15_ReadControl();
// Check if cache is disabled
if ((control & (1 << CP15_I_BIT)) == 0) {
control |= (1 << CP15_I_BIT);
CP15_WriteControl(control);
TRACE_INFO("I cache enabled.\n\r");
}
else {
TRACE_INFO("I cache is already enabled.\n\r");
}
}
/**
* \brief Disable Instruction cache
*/
void CP15_DisableIcache(void)
{
unsigned int control;
control = CP15_ReadControl();
// Check if cache is enabled
if ((control & (1 << CP15_I_BIT)) != 0) {
control &= ~(1ul << CP15_I_BIT);
CP15_WriteControl(control);
TRACE_INFO("I cache disabled.\n\r");
}
else {
TRACE_INFO("I cache is already disabled.\n\r");
}
}
/**
* \brief Check MMU
* \return 0 if MMU disable, 1 if MMU enable
*/
unsigned int CP15_IsMMUEnabled(void)
{
unsigned int control;
control = CP15_ReadControl();
return ((control & (1 << CP15_M_BIT)) != 0);
}
/**
* \brief Enable MMU
*/
void CP15_EnableMMU(void)
{
unsigned int control;
control = CP15_ReadControl();
// Check if MMU is disabled
if ((control & (1 << CP15_M_BIT)) == 0) {
control |= (1 << CP15_M_BIT);
CP15_WriteControl(control);
TRACE_INFO("MMU enabled.\n\r");
}
else {
TRACE_INFO("MMU is already enabled.\n\r");
}
}
/**
* \brief Disable MMU
*/
void CP15_DisableMMU(void)
{
unsigned int control;
control = CP15_ReadControl();
// Check if MMU is enabled
if ((control & (1 << CP15_M_BIT)) != 0) {
control &= ~(1ul << CP15_M_BIT);
control &= ~(1ul << CP15_C_BIT);
CP15_WriteControl(control);
TRACE_INFO("MMU disabled.\n\r");
}
else {
TRACE_INFO("MMU is already disabled.\n\r");
}
}
/**
* \brief Check D_cache
* \return 0 if D_cache disable, 1 if D_cache enable (with MMU of course)
*/
unsigned int CP15_IsDcacheEnabled(void)
{
unsigned int control;
control = CP15_ReadControl();
return ((control & ((1 << CP15_C_BIT)||(1 << CP15_M_BIT))) != 0);
}
/**
* \brief Enable Data cache
*/
void CP15_EnableDcache(void)
{
unsigned int control;
control = CP15_ReadControl();
if( !CP15_IsMMUEnabled() ) {
TRACE_ERROR("Do nothing: MMU not enabled\n\r");
}
else {
// Check if cache is disabled
if ((control & (1 << CP15_C_BIT)) == 0) {
control |= (1 << CP15_C_BIT);
CP15_WriteControl(control);
TRACE_INFO("D cache enabled.\n\r");
}
else {
TRACE_INFO("D cache is already enabled.\n\r");
}
}
}
/**
* \brief Disable Data cache
*/
void CP15_DisableDcache(void)
{
unsigned int control;
control = CP15_ReadControl();
// Check if cache is enabled
if ((control & (1 << CP15_C_BIT)) != 0) {
control &= ~(1ul << CP15_C_BIT);
CP15_WriteControl(control);
TRACE_INFO("D cache disabled.\n\r");
}
else {
TRACE_INFO("D cache is already disabled.\n\r");
}
}
/**
* \brief Invalidate TLB
*/
void CP15_InvalidateTLB(void)
{
asm("MCR p15, 0, %0, c8, c3, 0" : : "r"(1));
asm("DSB");
}
/**
* \brief Clean Data cache
*/
void CP15_CacheClean(uint8_t CacheType)
{
configASSERT(!CacheType);
CP15_SelectDCache();
CP15_CleanDCacheBySetWay();
asm("DSB");
}
/**
* \brief Invalidate D/Icache
*/
void CP15_CacheInvalidate(uint8_t CacheType)
{
if(CacheType)
{
CP15_SelectICache();
CP15_InvalidateIcacheInnerSharable();
asm("DSB");
asm("ISB");
}
else
{
CP15_SelectDCache();
CP15_InvalidateDcacheBySetWay();
asm("DSB");
asm("ISB");
}
}
/**
* \brief Flush(Clean and invalidate) Data cache
*/
void CP15_CacheFlush(uint8_t CacheType)
{
configASSERT(!CacheType);
CP15_SelectDCache();
CP15_CleanInvalidateDCacheBySetWay();
asm("DSB");
}
/**
* \brief Invalidate Data cache by address
*/
void CP15_InvalidateDCacheByVA(uint32_t S_Add, uint32_t E_Add)
{
CP15_SelectDCache();
CP15_InvalidateDcacheByMva(S_Add, E_Add);
}
/**
* \brief Clean Data cache by address
*/
void CP15_CleanDCacheByVA(uint32_t S_Add, uint32_t E_Add)
{
CP15_SelectDCache();
CP15_CleanDCacheByMva(S_Add, E_Add);
}
/**
* \brief Flush Data cache by address
*/
void CP15_FlushDCacheByVA(uint32_t S_Add, uint32_t E_Add)
{
CP15_SelectDCache();
CP15_CleanInvalidateDcacheByMva(S_Add, E_Add);
}

View File

@ -0,0 +1,164 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2011, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
#ifndef _CP15_H
#define _CP15_H
/*----------------------------------------------------------------------------
* Definition
*----------------------------------------------------------------------------*/
#define CP15_L4_BIT 15 // Determines if the T bit is set when load instructions
// change the PC:
// 0 = loads to PC set the T bit
// 1 = loads to PC do not set T bit
#define CP15_RR_BIT 14 // RR bit Replacement strategy for Icache and Dcache:
// 0 = Random replacement
// 1 = Round-robin replacement.
#define CP15_V_BIT 13 // V bit Location of exception vectors:
// 0 = Normal exception vectors selected address range = 0x0000 0000 to 0x0000 001C
// 1 = High exception vect selected, address range = 0xFFFF 0000 to 0xFFFF 001C
#define CP15_I_BIT 12 // I bit Icache enable/disable:
// 0 = Icache disabled
// 1 = Icache enabled
#define CP15_R_BIT 9 // R bit ROM protection
#define CP15_S_BIT 8 // S bit System protection
#define CP15_B_BIT 7 // B bit Endianness:
// 0 = Little-endian operation
// 1 = Big-endian operation.
#define CP15_C_BIT 2 // C bit Dcache enable/disable:
// 0 = cache disabled
// 1 = cache enabled
#define CP15_A_BIT 1 // A bit Alignment fault enable/disable:
// 0 = Data address alignment fault checking disabled
// 1 = Data address alignment fault checking enabled
#define CP15_M_BIT 0 // M bit MMU enable/disable: 0 = disabled 1 = enabled.
// 0 = disabled
// 1 = enabled
/** No access Any access generates a domain fault. */
#define CP15_DOMAIN_NO_ACCESS 0x00
/** Client Accesses are checked against the access permission bits in the section or page descriptor. */
#define CP15_DOMAIN_CLIENT_ACCESS 0x01
/** Manager Accesses are not checked against the access permission bits so a permission fault cannot be generated. */
#define CP15_DOMAIN_MANAGER_ACCESS 0x03
#define CP15_ICache 1
#define CP15_DCache 0
#define CP15_PMCNTENSET_ENABLE 31
#define CP15_PMCR_DIVIDER 3
#define CP15_PMCR_RESET 2
#define CP15_PMCR_ENABLE 0
/*------------------------------------------------------------------------------ */
/* Exported functions */
/*------------------------------------------------------------------------------ */
extern unsigned int CP15_ReadID(void);
extern unsigned int CP15_ReadControl(void);
extern void CP15_ExclusiveCache(void);
extern void CP15_NonExclusiveCache(void);
extern void CP15_ISB(void);
extern void CP15_DSB(void);
extern void CP15_DMB(void);
extern void CP15_SelectDCache(void);
extern void CP15_SelectICache(void);
extern void CP15_WriteControl(unsigned int value);
extern void CP15_WriteTTB(unsigned int value);
extern void CP15_WriteDomainAccessControl(unsigned int value);
extern void CP15_InvalidateIcacheInnerSharable(void);
extern void CP15_InvalidateBTBinnerSharable(void);
extern void CP15_InvalidateIcache(void);
extern void CP15_InvalidateIcacheByMva(void);
extern void CP15_InvalidateBTB(void);
extern void CP15_InvalidateBTBbyMva(uint32_t VA_Addr);
extern void CP15_InvalidateDcacheBySetWay(void);
extern void CP15_CleanDCacheBySetWay(void);
extern void CP15_CleanInvalidateDCacheBySetWay(void);
extern void CP15_InvalidateDcacheByMva(uint32_t startAddr, uint32_t endAddr );
extern void CP15_CleanDCacheByMva(uint32_t startAddr, uint32_t endAddr );
extern void CP15_CleanInvalidateDcacheByMva(uint32_t startAddr, uint32_t endAddr );
extern void CP15_CleanDCacheUMva(void);
extern void CP15_InvalidateTranslationTable(void);
extern void CP15_coherent_dcache_for_dma (uint32_t startAddr, uint32_t endAddr );
extern void CP15_invalidate_dcache_for_dma (uint32_t startAddr, uint32_t endAddr );
extern void CP15_clean_dcache_for_dma (uint32_t startAddr, uint32_t endAddr );
extern void CP15_flush_dcache_for_dma (uint32_t startAddr, uint32_t endAddr );
extern void CP15_flush_kern_dcache_for_dma (uint32_t startAddr, uint32_t size );
/*------------------------------------------------------------------------------ */
/* Exported functions from CP15.c */
/*------------------------------------------------------------------------------ */
/** MMU (Status/Enable/Disable) */
extern unsigned int CP15_IsMMUEnabled(void);
extern void CP15_EnableMMU(void);
extern void CP15_DisableMMU(void);
/** I cache (Status/Enable/Disable) */
extern unsigned int CP15_IsIcacheEnabled(void);
extern void CP15_EnableIcache(void);
extern void CP15_DisableIcache(void);
/** D cache (Status/Enable/Disable) */
extern unsigned int CP15_IsDcacheEnabled(void);
extern void CP15_EnableDcache(void);
extern void CP15_DisableDcache(void);
extern void CP15_InvalidateTLB(void);
extern void CP15_CacheClean(uint8_t CacheType);
extern void CP15_CacheInvalidate(uint8_t CacheType);
extern void CP15_CacheFlush(uint8_t CacheType);
extern void CP15_InvalidateDCacheByVA(uint32_t S_Add, uint32_t E_Add);
extern void CP15_CleanDCacheByVA(uint32_t S_Add, uint32_t E_Add);
extern void CP15_FlushDCacheByVA(uint32_t S_Add, uint32_t E_Add);
#endif // #ifndef _CP15_H

View File

@ -0,0 +1,728 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2012, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES// LOSS OF USE, DATA,
* OR PROFITS// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
/** \file */
/**
* \addtogroup cp15_cache Cache Operations
*
* \section Usage
*
* They are performed as MCR instructions and only operate on a level 1 cache associated with
* ATM v7 processor.
* The supported operations are:
* <ul>
* <li> Any of these operations can be applied to
* -# any data cache
* -# any unified cache.
* <li> Invalidate by MVA
* Performs an invalidate of a data or unified cache line based on the address it contains.
* <li> Invalidate by set/way
* Performs an invalidate of a data or unified cache line based on its location in the cache hierarchy.
* <li> Clean by MVA
* Performs a clean of a data or unified cache line based on the address it contains.
* <li> Clean by set/way
* Performs a clean of a data or unified cache line based on its location in the cache hierarchy.
* <li> Clean and Invalidate by MVA
* Performs a clean and invalidate of a data or unified cache line based on the address it contains.
* <li> Clean and Invalidate by set/way
* Performs a clean and invalidate of a data or unified cache line based on its location in the cache hierarchy.
* </ul>
*
* Related files:\n
* \ref cp15.h\n
* \ref cp15_arm_iar.s \n
*/
MODULE ?cp15
//// Forward declaration of sections.
SECTION IRQ_STACK:DATA:NOROOT(2)
SECTION CSTACK:DATA:NOROOT(3)
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#define __ASSEMBLY__
/*----------------------------------------------------------------------------
* Functions to access CP15 coprocessor register
*----------------------------------------------------------------------------*/
PUBLIC CP15_ReadID
PUBLIC CP15_ExclusiveCache
PUBLIC CP15_NonExclusiveCache
PUBLIC CP15_ISB
PUBLIC CP15_DSB
PUBLIC CP15_DMB
PUBLIC CP15_SelectICache
PUBLIC CP15_SelectDCache
PUBLIC CP15_ReadControl
PUBLIC CP15_WriteControl
PUBLIC CP15_WriteDomainAccessControl
PUBLIC CP15_WriteTTB
PUBLIC CP15_InvalidateIcacheInnerSharable
PUBLIC CP15_InvalidateBTBinnerSharable
PUBLIC CP15_InvalidateIcache
PUBLIC CP15_InvalidateIcacheByMva
PUBLIC CP15_InvalidateBTB
PUBLIC CP15_InvalidateBTBbyMva
PUBLIC CP15_InvalidateDcacheBySetWay
PUBLIC CP15_CleanDCacheBySetWay
PUBLIC CP15_CleanInvalidateDCacheBySetWay
PUBLIC CP15_InvalidateDcacheByMva
PUBLIC CP15_CleanDCacheByMva
PUBLIC CP15_CleanDCacheUMva
PUBLIC CP15_CleanInvalidateDcacheByMva
PUBLIC CP15_InvalidateTranslationTable
PUBLIC CP15_coherent_dcache_for_dma
PUBLIC CP15_invalidate_dcache_for_dma
PUBLIC CP15_clean_dcache_for_dma
PUBLIC CP15_flush_dcache_for_dma
PUBLIC CP15_flush_kern_dcache_for_dma
/**
* \brief Register c0 accesses the ID Register, Cache Type Register, and TCM Status Registers.
* Reading from this register returns the device ID, the cache type, or the TCM status
* depending on the value of Opcode_2 used.
*/
SECTION .CP15_ReadID:DATA:NOROOT(2)
PUBLIC CP15_ReadID
CP15_ReadID:
mov r0, #0
mrc p15, 0, r0, c0, c0, 0
bx lr
/**
* \brief Register c7 accesses the ACTLR Register, to indicate cpu that L2 is in exclusive mode
*/
SECTION .CP15_ISB:DATA:NOROOT(2)
PUBLIC CP15_ISB
CP15_ISB:
mov r0, #0
mcr p15, 0, r0, c7, c5, 4
nop
bx lr
/**
* \brief Register c7 accesses the ACTLR Register, to indicate cpu that L2 is in exclusive mode
*/
SECTION .CP15_DSB:DATA:NOROOT(2)
PUBLIC CP15_DSB
CP15_DSB:
mov r0, #0
mcr p15, 0, r0, c7, c10, 4
nop
bx lr
/**
* \brief Register c7 accesses the ACTLR Register, to indicate cpu that L2 is in exclusive mode
*/
SECTION .CP15_DMB:DATA:NOROOT(2)
PUBLIC CP15_DMB
CP15_DMB:
mov r0, #0
mcr p15, 0, r0, c7, c10, 5
nop
bx lr
/**
* \brief Register c1 accesses the ACTLR Register, to indicate cpu that L2 is in exclusive mode
*/
SECTION .CP15_ExclusiveCache:DATA:NOROOT(2)
PUBLIC CP15_ExclusiveCache
CP15_ExclusiveCache:
mov r0, #0
mrc p15, 0, r0, c1, c0, 1 ; Read ACTLR
orr r0, r0, #0x00000080
mcr p15, 0, r0, c1, c0, 1 ; Write ACTLR
nop
bx lr
/**
* \brief Register c1 accesses the ACTLR Register, to indicate cpu that L2 is in exclusive mode
*/
SECTION .CP15_NonExclusiveCache:DATA:NOROOT(2)
PUBLIC CP15_NonExclusiveCache
CP15_NonExclusiveCache:
mov r0, #0
mrc p15, 0, r0, c1, c0, 1 ; Read ACTLR
bic r0, r0, #0x00000080
mcr p15, 0, r0, c1, c0, 1 ; Write ACTLR
nop
bx lr
/**
* \brief Register c1 accesses the CSSELR Register, to select ICache
*/
SECTION .CP15_SelectICache:DATA:NOROOT(2)
PUBLIC CP15_SelectICache
CP15_SelectICache:
mrc p15, 2, r0, c0, c0, 0 ; Read CSSELR
orr r0, r0, #0x1 ; Change 0th bit to ICache
mcr p15, 2, r0, c0, c0, 0 ; Write CSSELR
nop
bx lr
/**
* \brief Register c1 accesses the CSSELR Register, to select DCache
*/
SECTION .CP15_SelectDCache:DATA:NOROOT(2)
PUBLIC CP15_SelectDCache
CP15_SelectDCache:
mrc p15, 2, r0, c0, c0, 0 ; Read CSSELR
and r0, r0, #0xFFFFFFFE ; Change 0th bit to ICache
mcr p15, 2, r0, c0, c0, 0 ; Write CSSELR
nop
bx lr
/**
* \brief Register c1 is the Control Register for the ARM926EJ-S processor.
* This register specifies the configuration used to enable and disable the
* caches and MMU. It is recommended that you access this register using a
* read-modify-write sequence
*/
SECTION .CP15_ReadControl:CODE:NOROOT(2)
PUBLIC CP15_ReadControl
CP15_ReadControl:
mov r0, #0
mrc p15, 0, r0, c1, c0, 0
bx lr
SECTION .CP15_WriteControl:CODE:NOROOT(2)
PUBLIC CP15_WriteControl
CP15_WriteControl:
mcr p15, 0, r0, c1, c0, 0
dsb
isb
bx lr
SECTION .CP15_WriteDomainAccessControl:CODE:NOROOT(2)
PUBLIC CP15_WriteDomainAccessControl
CP15_WriteDomainAccessControl:
mcr p15, 0, r0, c3, c0, 0
dsb
isb
bx lr
/**
* \brief ARMv7A architecture supports two translation tables
* Configure translation table base (TTB) control register cp15,c2
* to a value of all zeros, indicates we are using TTB register 0.
* write the address of our page table base to TTB register 0.
*/
SECTION .CP15_WriteTTB:CODE:NOROOT(2)
PUBLIC CP15_WriteTTB
CP15_WriteTTB:
mcr p15, 0, r0, c2, c0, 0
dsb
isb
bx lr
/**
* \brief Invalidate I cache predictor array inner Sharable
*/
SECTION .CP15_InvalidateIcacheInnerSharable:CODE:NOROOT(2)
PUBLIC CP15_InvalidateIcacheInnerSharable
CP15_InvalidateIcacheInnerSharable:
mov r0, #0
mcr p15, 0, r0, c7, c1, 0
bx lr
/**
* \brief Invalidate entire branch predictor array inner Sharable
*/
SECTION .CP15_InvalidateBTBinnerSharable:CODE:NOROOT(2)
PUBLIC CP15_InvalidateBTBinnerSharable
CP15_InvalidateBTBinnerSharable:
mov r0, #0
mcr p15, 0, r0, c7, c1, 6
bx lr
/**
* \brief Invalidate all instruction caches to PoU, also flushes branch target cache
*/
SECTION .CP15_InvalidateIcache:CODE:NOROOT(2)
PUBLIC CP15_InvalidateIcache
CP15_InvalidateIcache:
mov r0, #0
mcr p15, 0, r0, c7, c5, 0
isb
bx lr
/**
* \brief Invalidate instruction caches by VA to PoU
*/
SECTION .CP15_InvalidateIcacheByMva:CODE:NOROOT(2)
PUBLIC CP15_InvalidateIcacheByMva
CP15_InvalidateIcacheByMva:
mov r0, #0
mcr p15, 0, r0, c7, c5, 1
bx lr
/**
* \brief Invalidate entire branch predictor array
*/
SECTION .CP15_InvalidateBTB:CODE:NOROOT(2)
PUBLIC CP15_InvalidateBTB
CP15_InvalidateBTB:
mov r0, #0
mcr p15, 0, r0, c7, c5, 6
dsb
isb
bx lr
/**
* \brief Invalidate branch predictor array entry by MVA
*/
SECTION .CP15_InvalidateBTBbyMva:CODE:NOROOT(2)
PUBLIC CP15_InvalidateBTBbyMva
CP15_InvalidateBTBbyMva:
mcr p15, 0, r0, c7, c5, 7
bx lr
/***********************************************************
*
* ===Data Cache related maintenance functions===
*
**************************************************************/
// ===Data Cache maintenance by SetWay ===
/**
* \brief Invalidate entire data cache by set/way
*/
SECTION .CP15_InvalidateDcacheBySetWay:CODE:NOROOT(2)
PUBLIC CP15_InvalidateDcacheBySetWay
CP15_InvalidateDcacheBySetWay:
MRC p15, 1, r0, c0, c0, 1 ; Read CLIDR
ANDS r3, r0, #0x07000000 ; Extract coherency level
MOV r3, r3, LSR #23 ; Total cache levels << 1
BEQ inv_finish ; If 0, no need to clean
MOV r10, #0 ; R10 holds current cache level << 1
inv_cache_level_loop
ADD r2, r10, r10, LSR #1 ; R2 holds cache "Set" position
MOV r1, r0, LSR r2 ; Bottom 3 bits are the Cache-type for this level
AND r1, r1, #7 ; Isolate those lower 3 bits
CMP r1, #2
BLT inv_skip ; No cache or only instruction cache at this level
MCR p15, 2, r10, c0, c0, 0 ; Write the Cache Size selection register
ISB ; ISB to sync the change to the CacheSizeID reg
MRC p15, 1, r1, c0, c0, 0 ; Reads current Cache Size ID register
AND r2, r1, #7 ; Extract the line length field
ADD r2, r2, #4 ; Add 4 for the line length offset (log2 16 bytes)
LDR r4, =0x3FF
ANDS r4, r4, r1, LSR #3 ; R4 is the max number on the way size (right aligned)
CLZ r5, r4 ; R5 is the bit position of the way size increment
LDR r7, =0x7FFF
ANDS r7, r7, r1, LSR #13 ; R7 is the max number of the index size (right aligned)
inv_set_loop
MOV r9, r4 ; R9 working copy of the max way size (right aligned)
inv_way_loop
ORR r11, r10, r9, LSL r5 ; Factor in the Way number and cache number into R11
ORR r11, r11, r7, LSL r2 ; Factor in the Set number
MCR p15, 0, r11, c7, c6, 2 ; Invalidate by Set/Way
SUBS r9, r9, #1 ; Decrement the Way number
BGE inv_way_loop
SUBS r7, r7, #1 ; Decrement the Set number
BGE inv_set_loop
inv_skip
ADD r10, r10, #2 ; increment the cache number
CMP r3, r10
BGT inv_cache_level_loop
inv_finish
NOP
BX lr
/**
* \brief Clean entire data cache by set/way
*/
SECTION .CP15_CleanDCacheBySetWay:CODE:NOROOT(2)
PUBLIC CP15_CleanDCacheBySetWay
CP15_CleanDCacheBySetWay:
MRC p15, 1, r0, c0, c0, 1 ; Read CLIDR
ANDS r3, r0, #0x07000000 ; Extract coherency level
MOV r3, r3, LSR #23 ; Total cache levels << 1
BEQ clean_finish ; If 0, no need to clean
MOV r10, #0 ; R10 holds current cache level << 1
clean_cache_level_loop
ADD r2, r10, r10, LSR #1 ; R2 holds cache "Set" position
MOV r1, r0, LSR r2 ; Bottom 3 bits are the Cache-type for this level
AND r1, r1, #7 ; Isolate those lower 3 bits
CMP r1, #2
BLT clean_skip ; No cache or only instruction cache at this level
MCR p15, 2, r10, c0, c0, 0 ; Write the Cache Size selection register
ISB ; ISB to sync the change to the CacheSizeID reg
MRC p15, 1, r1, c0, c0, 0 ; Reads current Cache Size ID register
AND r2, r1, #7 ; Extract the line length field
ADD r2, r2, #4 ; Add 4 for the line length offset (log2 16 bytes)
LDR r4, =0x3FF
ANDS r4, r4, r1, LSR #3 ; R4 is the max number on the way size (right aligned)
CLZ r5, r4 ; R5 is the bit position of the way size increment
LDR r7, =0x7FFF
ANDS r7, r7, r1, LSR #13 ; R7 is the max number of the index size (right aligned)
clean_set_loop
MOV r9, r4 ; R9 working copy of the max way size (right aligned)
clean_way_loop
ORR r11, r10, r9, LSL r5 ; Factor in the Way number and cache number into R11
ORR r11, r11, r7, LSL r2 ; Factor in the Set number
MCR p15, 0, r11, c7, c10, 2 ; Clean by Set/Way
SUBS r9, r9, #1 ; Decrement the Way number
BGE clean_way_loop
SUBS r7, r7, #1 ; Decrement the Set number
BGE clean_set_loop
clean_skip
ADD r10, r10, #2 ; increment the cache number
CMP r3, r10
BGT clean_cache_level_loop
clean_finish
NOP
BX lr
/**
* \brief Clean and Invalidate entire data cache by set/way
*/
SECTION .CP15_CleanInvalidateDCacheBySetWay:CODE:NOROOT(2)
PUBLIC CP15_CleanInvalidateDCacheBySetWay
CP15_CleanInvalidateDCacheBySetWay:
MRC p15, 1, r0, c0, c0, 1 ; Read CLIDR
ANDS r3, r0, #0x07000000 ; Extract coherency level
MOV r3, r3, LSR #23 ; Total cache levels << 1
BEQ clinv_finish ; If 0, no need to clean
MOV r10, #0 ; R10 holds current cache level << 1
clinv_cache_level_loop
ADD r2, r10, r10, LSR #1 ; R2 holds cache "Set" position
MOV r1, r0, LSR r2 ; Bottom 3 bits are the Cache-type for this level
AND r1, r1, #7 ; Isolate those lower 3 bits
CMP r1, #2
BLT clean_skip ; No cache or only instruction cache at this level
MCR p15, 2, r10, c0, c0, 0 ; Write the Cache Size selection register
ISB ; ISB to sync the change to the CacheSizeID reg
MRC p15, 1, r1, c0, c0, 0 ; Reads current Cache Size ID register
AND r2, r1, #7 ; Extract the line length field
ADD r2, r2, #4 ; Add 4 for the line length offset (log2 16 bytes)
LDR r4, =0x3FF
ANDS r4, r4, r1, LSR #3 ; R4 is the max number on the way size (right aligned)
CLZ r5, r4 ; R5 is the bit position of the way size increment
LDR r7, =0x7FFF
ANDS r7, r7, r1, LSR #13 ; R7 is the max number of the index size (right aligned)
clinv_set_loop
MOV r9, r4 ; R9 working copy of the max way size (right aligned)
clinv_way_loop
ORR r11, r10, r9, LSL r5 ; Factor in the Way number and cache number into R11
ORR r11, r11, r7, LSL r2 ; Factor in the Set number
MCR p15, 0, r11, c7, c14, 2 ; Clean and Invalidate by Set/Way
SUBS r9, r9, #1 ; Decrement the Way number
BGE clean_way_loop
SUBS r7, r7, #1 ; Decrement the Set number
BGE clean_set_loop
clinv_skip
ADD r10, r10, #2 ; increment the cache number
CMP r3, r10
BGT clean_cache_level_loop
clinv_finish
NOP
BX lr
// ===Data Cache maintenance by VA ===
/**
* \brief Invalidate data cache by VA to Poc
*/
SECTION .CP15_InvalidateDcacheByMva:CODE:NOROOT(2)
PUBLIC CP15_InvalidateDcacheByMva
CP15_InvalidateDcacheByMva:
mov r2, #0x20 ;Eight words per line, Cortex-A5 L1 Line Size 32 Bytes
mov r3, r0
inv_loop
mcr p15, 0, r0, c7, c6, 1
add r3, r3, r2
cmp r3, r1
bls inv_loop
bx lr
/**
* \brief Clean data cache by MVA
*/
SECTION .CP15_CleanDCacheByMva:CODE:NOROOT(2)
PUBLIC CP15_CleanDCacheByMva
CP15_CleanDCacheByMva:
mov r2, #0x20 ;Eight words per line, Cortex-A5 L1 Line Size 32 Bytes
mov r3, r0
clean_loop
mcr p15, 0, r0, c7, c10, 1
add r3, r3, r2
cmp r3, r1
bls clean_loop
bx lr
/**
* \brief Clean unified cache by MVA
*/
SECTION .CP15_CleanDCacheUMva:CODE:NOROOT(2)
PUBLIC CP15_CleanDCacheUMva
CP15_CleanDCacheUMva:
mov r0, #0
mcr p15, 0, r0, c7, c11, 1
bx lr
/**
* \brief Clean and invalidate data cache by VA to PoC
*/
SECTION .CP15_CleanInvalidateDcacheByMva:CODE:NOROOT(2)
PUBLIC CP15_CleanInvalidateDcacheByMva
CP15_CleanInvalidateDcacheByMva:
mov r2, #0x20 ;Eight words per line, Cortex-A5 L1 Line Size 32 Bytes
mov r3, r0
clinv_loop
mcr p15, 0, r0, c7, c14, 1
add r3, r3, r2
cmp r3, r1
bls clinv_loop
bx lr
/**
* \brief Invalidate translation table
*/
SECTION .CP15_InvalidateTranslationTable:CODE:NOROOT(2)
PUBLIC CP15_InvalidateTranslationTable
CP15_InvalidateTranslationTable:
mov r0, #0
mcr p15, 0, r0, c8, c3, 0
dsb
isb
mcr p15, 0, r0, c8, c7, 0
dsb
isb
bx lr
/**
* \brief flush translation table
*/
SECTION .CP15_FlushTranslationTable:CODE:NOROOT(2)
PUBLIC CP15_FlushTranslationTable
CP15_FlushTranslationTable:
mov r0, #0
mcr p15, 0, r0, c8, c3, 0
dsb
isb
bx lr
/**
* \brief Ensure that the I and D caches are coherent within specified
* region. This is typically used when code has been written to
* a memory region, and will be executed.
* \param start virtual start address of region
* \param end virtual end address of region
*/
SECTION .CP15_coherent_dcache_for_dma:CODE:NOROOT(2)
PUBLIC CP15_coherent_dcache_for_dma
CP15_coherent_dcache_for_dma:
// dcache_line_size r2, r3
mrc p15, 0, r3, c0, c0, 1 // read ctr
lsr r3, r3, #16
and r3, r3, #0xf // cache line size encoding
mov r2, #4 // bytes per word
mov r2, r2, lsl r3 // actual cache line size
sub r3, r2, #1
bic r12, r0, r3
loop1:
mcr p15, 0, r12, c7, c11, 1 // clean D line to the point of unification
add r12, r12, r2
cmp r12, r1
blo loop1
dsb
// .macro icache_line_size, reg, tmp
mrc p15, 0, r3, c0, c0, 1 // read ctr
and r3, r3, #0xf // cache line size encoding
mov r2, #4 // bytes per word
mov r2, r2, lsl r3 // actual cache line size
sub r3, r2, #1
bic r12, r0, r3
loop2:
mcr p15, 0, r12, c7, c5, 1 // invalidate I line
add r12, r12, r2
cmp r12, r1
blo loop2
mov r0, #0
mcr p15, 0, r0, c7, c1, 6 //invalidate BTB Inner Shareable
mcr p15, 0, r0, c7, c5, 6 // invalidate BTB
dsb
isb
bx lr
/**
* \brief Invalidate the data cache within the specified region; we will
* be performing a DMA operation in this region and we want to
* purge old data in the cache.
* \param start virtual start address of region
* \param end virtual end address of region
*/
SECTION .CP15_invalidate_dcache_for_dma:CODE:NOROOT(2)
PUBLIC CP15_invalidate_dcache_for_dma
CP15_invalidate_dcache_for_dma:
// dcache_line_size r2, r3
mrc p15, 0, r3, c0, c0, 1 // read ctr
lsr r3, r3, #16
and r3, r3, #0xf // cache line size encoding
mov r2, #4 // bytes per word
mov r2, r2, lsl r3 // actual cache line size
sub r3, r2, #1
tst r0, r3
bic r0, r0, r3
mcrne p15, 0, r0, c7, c14, 1 // clean & invalidate D / U line
tst r1, r3
bic r1, r1, r3
mcrne p15, 0, r1, c7, c14, 1 // clean & invalidate D / U line
loop3:
mcr p15, 0, r0, c7, c6, 1 // invalidate D / U line
add r0, r0, r2
cmp r0, r1
blo loop3
dsb
bx lr
/**
* \brief Clean the data cache within the specified region
* \param start virtual start address of region
* \param end virtual end address of region
*/
SECTION .CP15_clean_dcache_for_dma:CODE:NOROOT(2)
PUBLIC CP15_clean_dcache_for_dma
CP15_clean_dcache_for_dma:
// dcache_line_size r2, r3
mrc p15, 0, r3, c0, c0, 1 // read ctr
lsr r3, r3, #16
and r3, r3, #0xf // cache line size encoding
mov r2, #4 // bytes per word
mov r2, r2, lsl r3 // actual cache line size
sub r3, r2, #1
bic r0, r0, r3
loop4:
mcr p15, 0, r0, c7, c10, 1 // clean D / U line
add r0, r0, r2
cmp r0, r1
blo loop4
dsb
bx lr
/**
* \brief Flush the data cache within the specified region
* \param start virtual start address of region
* \param end virtual end address of region
*/
SECTION .CP15_flush_dcache_for_dma:CODE:NOROOT(2)
PUBLIC CP15_flush_dcache_for_dma
CP15_flush_dcache_for_dma:
// dcache_line_size r2, r3
mrc p15, 0, r3, c0, c0, 1 // read ctr
lsr r3, r3, #16
and r3, r3, #0xf // cache line size encoding
mov r2, #4 // bytes per word
mov r2, r2, lsl r3 // actual cache line size
sub r3, r2, #1
bic r0, r0, r3
loop5:
mcr p15, 0, r0, c7, c14, 1 // clean & invalidate D / U line
add r0, r0, r2
cmp r0, r1
blo loop5
dsb
bx lr
/**
* \brief CP15_flush_kern_dcache_for_dma
* Ensure that the data held in the page kaddr is written back to the page in question.
* \param start virtual start address of region
* \param end virtual end address of region
*/
SECTION .CP15_flush_kern_dcache_for_dma:CODE:NOROOT(2)
PUBLIC CP15_flush_kern_dcache_for_dma
CP15_flush_kern_dcache_for_dma:
// dcache_line_size r2, r3
mrc p15, 0, r3, c0, c0, 1 // read ctr
lsr r3, r3, #16
and r3, r3, #0xf // cache line size encoding
mov r2, #4 // bytes per word
mov r2, r2, lsl r3 // actual cache line size
add r1, r0, r1
sub r3, r2, #1
bic r0, r0, r3
mcr p15, 0, r0, c7, c14, 1 // clean & invalidate D line / unified line
add r0, r0, r2
cmp r0, r1
blo 1b
dsb
bx lr
END

View File

@ -0,0 +1,60 @@
#ifndef _ADC_H
#define _ADC_H
typedef enum {
ADC_CH_BAT = 1,
ADC_CH_TP = 2,
ADC_CH_AUX0 = 3,
ADC_CH_AUX1 = 4,
ADC_CH_AUX2 = 5,
ADC_CH_AUX3 = 6,
ADC_CH_AUX4 = 7,
ADC_CH_AUX5 = 8,
ADC_CH_AUX6 = 9,
ADC_CH_AUX7 = 10,
} eAdcChannel;
#define AUX0_START_INT (1<<0)
#define AUX0_STOP_INT (1<<1)
#define AUX0_VALUE_INT (1<<2)
#define AUX1_START_INT (1<<3)
#define AUX1_STOP_INT (1<<4)
#define AUX1_VALUE_INT (1<<5)
#define AUX2_START_INT (1<<6)
#define AUX2_STOP_INT (1<<7)
#define AUX2_VALUE_INT (1<<8)
#define AUX3_START_INT (1<<9)
#define AUX3_STOP_INT (1<<10)
#define AUX3_VALUE_INT (1<<11)
#define AUX4_START_INT (1<<16)
#define AUX4_STOP_INT (1<<17)
#define AUX4_VALUE_INT (1<<18)
#define AUX5_START_INT (1<<19)
#define AUX5_STOP_INT (1<<20)
#define AUX5_VALUE_INT (1<<21)
#define AUX6_START_INT (1<<22)
#define AUX6_STOP_INT (1<<23)
#define AUX6_VALUE_INT (1<<24)
#define AUX7_START_INT (1<<25)
#define AUX7_STOP_INT (1<<26)
#define AUX7_VALUE_INT (1<<27)
#define TP_START_INT (1<<12)
#define TP_STOP_INT (1<<13)
#define TP_VALUE_INT (1<<14)
#define BAT_INT (1<<15)
void adc_init(void);
void adc_channel_enable(eAdcChannel ch);
void adc_channel_disable(eAdcChannel ch);
unsigned int adc_get_channel_value(int ch);
#endif

View File

@ -0,0 +1,56 @@
/**
* \file
*
* \section Purpose
*
* Methods and definitions for configuring interrupts.
*
* \section Usage
* -# Enable or disable interrupt generation of a particular source with
* IRQ_EnableIT and IRQ_DisableIT.
* -# Start or stop the timer clock using TC_Start() and TC_Stop().
*/
#ifndef AIC_H
#define AIC_H
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include "chip.h"
#include <stdint.h>
/*------------------------------------------------------------------------------
* Global functions
*------------------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*ISRFunction_t)( void *param );
enum {
IRQ_TYPE_EDGE_BOTH,
IRQ_TYPE_EDGE_RISING,
IRQ_TYPE_EDGE_FALLING,
IRQ_TYPE_LEVEL_HIGH,
IRQ_TYPE_LEVEL_LOW,
};
extern void AIC_Initialize(void);
extern void AIC_EnableIT( uint32_t source);
extern void AIC_DisableIT(uint32_t source);
extern int32_t request_irq(uint32_t irq_source, int32_t priority, ISRFunction_t func, void *param);
extern int32_t free_irq(uint32_t irq_source);
extern void AIC_IrqHandler(void);
extern uint8_t interrupt_get_nest(void);
#ifdef __cplusplus
}
#endif
#endif //#ifndef AIC_H

View File

@ -0,0 +1,113 @@
#ifndef __AMT630HV100__H
#define __AMT630HV100__H
#ifdef __cplusplus
extern "C" {
#endif
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
#include <stdint.h>
#ifdef __cplusplus
#define __I volatile /**< Defines 'read-only' permissions */
#else
#define __I volatile const /**< Defines 'read-only' permissions */
#endif
#define __O volatile /**< Defines 'write-only' permissions */
#define __IO volatile /**< Defines 'read/write' permissions */
#endif
#include "os_adapt.h"
typedef enum IRQn
{
LCD_IRQn = 0, /**< 0 AMT630HV100 LCD Interrupt ID */
JPG_IRQn = 1, /**< 1 AMT630HV100 Jpeg Decoder Interrupt (JPG) */
GPU_IRQn = 2, /**< 2 AMT630HV100 GPU Interrupt (GPU) */
USB_IRQn = 3, /**< 3 AMT630HV100 USB Controller Interrupt (USB) */
PXP_IRQn = 4, /**< 4 AMT630HV100 PXP Interrupt (PXP) */
DMA_IRQn = 5, /**< 5 AMT630HV100 DMA Controller Interrupt (DMAC) */
SDMMC0_IRQn = 6, /**< 6 AMT630HV100 SDMMC 0 Controller Interrupt (SDMMC0) */
SPI0_IRQn = 7, /**< 7 AMT630HV100 SPI 0 Controller Interrupt (SPI0) */
SPI1_IRQn = 8, /**< 8 AMT630HV100 SPI 1 Controller Interrupt (SPI1) */
I2C0_IRQn = 9, /**< 9 AMT630HV100 I2C0 Controller Interrupt (I2C0) */
I2C1_IRQn = 10, /**< 10 AMT630HV100 I2C1 Controller Interrupt (I2C1) */
UART0_IRQn = 11, /**< 11 AMT630HV100 UART 0 Controller Interrupt (UART0) */
UART1_IRQn = 12, /**< 12 AMT630HV100 UART 1 Controller Interrupt (UART1) */
UART2_IRQn = 13, /**< 13 AMT630HV100 UART 2 Controller Interrupt (UART2) */
UART3_IRQn = 14, /**< 14 AMT630HV100 UART 3 Controller Interrupt (UART3) */
GPIOA_IRQn = 15, /**< 15 AMT630HV100 GPIO0~31 Controller Interrupt (GPIOA) */
GPIOB_IRQn = 16, /**< 16 AMT630HV100 GPIO32~63 Controller Interrupt (GPIOB) */
GPIOC_IRQn = 17, /**< 17 AMT630HV100 GPIO64~95 Controller Interrupt (GPIOC) */
GPIOD_IRQn = 18, /**< 18 AMT630HV100 GPIO96~127 Controller Interrupt (GPIOD) */
TIMER0_IRQn = 19, /**< 19 AMT630HV100 Timer 0 Interrupt (TIMER0) */
TIMER1_IRQn = 20, /**< 20 AMT630HV100 Timer 1 Interrupt (TIMER1) */
TIMER2_IRQn = 21, /**< 21 AMT630HV100 Timer 2/3 Interrupt (TIMER2/TIMER3) */
I2S1_IRQn = 22, /**< 22 AMT630HV100 I2S1 Interrupt (I2S1) */
ITU_IRQn = 23, /**< 23 AMT630HV100 ITU Controller Interrupt (ITU) */
WDT_IRQn = 24, /**< 24 AMT630HV100 Watchdog timer Interrupt (WDT) */
I2S_IRQn = 25, /**< 25 AMT630HV100 I2S Interrupt (I2S) */
BLEND2D_IRQn = 26, /**< 26 AMT630HV100 BLEND2D Interrupt (BLEND2D) */
RTC_PRD_IRQn = 27, /**< 27 AMT630HV100 RTC Controller Period Interrupt (RTCP) */
ADC_IRQn = 28, /**< 28 AMT630HV100 ADC controller Interrupt (ADC) */
RCRT_IRQn = 29, /**< 29 */
CAN0_IRQn = 30, /**< 30 AMT630HV100 CAN0 Controller Interrupt (CAN0) */
CAN1_IRQn = 31, /**< 31 AMT630HV100 CAN1 Controller Interrupt (CAN1) */
MAX_IRQ_NUM = 32 /**< Number of peripheral IDs */
} IRQn_Type;
/*@}*/
/* ************************************************************************** */
/* BASE ADDRESS DEFINITIONS FOR AMT630HV100 */
/* ************************************************************************** */
/** \addtogroup AMT630HV100_base Peripheral Base Address Definitions */
/*@{*/
#define REGS_SYSCTL_BASE (0x60000000U)
#define REGS_SPI0_BASE (0x60100000U)
#define REGS_SPI1_BASE (0x60200000U)
#define REGS_IIC0_BASE (0x60300000U)
#define REGS_IIC1_BASE (0x60400000U)
#define REGS_UART0_BASE (0x60500000U)
#define REGS_UART1_BASE (0x60600000U)
#define REGS_UART2_BASE (0x60700000U)
#define REGS_UART3_BASE (0x60800000U)
#define REGS_GPIO_BASE (0x60900000U)
#define REGS_TIMER_BASE (0x60a00000U)
#define REGS_PWM_BASE (0x60b00000U)
#define REGS_WDT_BASE (0x60c00000U)
#define REGS_I2S_BASE (0x60d00000U)
#define REGS_I2S1_BASE (0x60f00000U)
#define REGS_MIPI_BASE (0x60e00000U)
#define REGS_RTC_BASE (0x61000000U)
#define REGS_ADC_BASE (0x61100000U)
#define REGS_RCRT_BASE (0x61200000U)
#define REGS_AES_BASE (0x61300000U)
#define REGS_AIC_BASE (0x61400000U)
#define REGS_CAN0_BASE (0x61500000U)
#define REGS_CAN1_BASE (0x61600000U)
#define REGS_DMAC_BASE (0x70100000U)
#define REGS_GPU_BASE (0x70200000U)
#define REGS_USB_BASE (0x70300000U)
#define REGS_SDMMC0_BASE (0X70400000U)
#define REGS_ITU_BASE (0X70600000U)
#define REGS_BLEND2D_BASE (0x70700000U)
#define REGS_LCD_BASE (0X71000000U)
#define REGS_PXP_BASE (0X71100000U)
#define REGS_ROTATE_BASE (0X71207000U)
#define REGS_JPG_BASE (0X71208000U)
#define REGS_DDRC_BASE (0X71300000U)
/* ************************************************************************** */
/* ELECTRICAL DEFINITIONS FOR AMT630HV100 */
/* ************************************************************************** */
#ifdef __cplusplus
}
#endif
/*@}*/
#endif /* __AMT630HV100__H */

View File

@ -0,0 +1,195 @@
#ifndef __AUDIO_H__
#define __AUDIO_H__
/* AUDIO command */
#define _AUDIO_CTL(a) (0x10 + a)
#define AUDIO_CTL_GETCAPS _AUDIO_CTL(1)
#define AUDIO_CTL_CONFIGURE _AUDIO_CTL(2)
#define AUDIO_CTL_START _AUDIO_CTL(3)
#define AUDIO_CTL_STOP _AUDIO_CTL(4)
#define AUDIO_CTL_GETBUFFERINFO _AUDIO_CTL(5)
/* Audio Device Types */
#define AUDIO_TYPE_QUERY 0x00
#define AUDIO_TYPE_INPUT 0x01
#define AUDIO_TYPE_OUTPUT 0x02
#define AUDIO_TYPE_MIXER 0x04
/* Supported Sampling Rates */
#define AUDIO_SAMP_RATE_8K 0x0001
#define AUDIO_SAMP_RATE_11K 0x0002
#define AUDIO_SAMP_RATE_16K 0x0004
#define AUDIO_SAMP_RATE_22K 0x0008
#define AUDIO_SAMP_RATE_32K 0x0010
#define AUDIO_SAMP_RATE_44K 0x0020
#define AUDIO_SAMP_RATE_48K 0x0040
#define AUDIO_SAMP_RATE_96K 0x0080
#define AUDIO_SAMP_RATE_128K 0x0100
#define AUDIO_SAMP_RATE_160K 0x0200
#define AUDIO_SAMP_RATE_172K 0x0400
#define AUDIO_SAMP_RATE_192K 0x0800
/* Supported Bit Rates */
#define AUDIO_BIT_RATE_22K 0x01
#define AUDIO_BIT_RATE_44K 0x02
#define AUDIO_BIT_RATE_48K 0x04
#define AUDIO_BIT_RATE_96K 0x08
#define AUDIO_BIT_RATE_128K 0x10
#define AUDIO_BIT_RATE_160K 0x20
#define AUDIO_BIT_RATE_172K 0x40
#define AUDIO_BIT_RATE_192K 0x80
/* Support Dsp(input/output) Units controls */
#define AUDIO_DSP_PARAM 0 /* get/set all params */
#define AUDIO_DSP_SAMPLERATE 1 /* samplerate */
#define AUDIO_DSP_CHANNELS 2 /* channels */
#define AUDIO_DSP_SAMPLEBITS 3 /* sample bits width */
/* Supported Mixer Units controls */
#define AUDIO_MIXER_QUERY 0x0000
#define AUDIO_MIXER_MUTE 0x0001
#define AUDIO_MIXER_VOLUME 0x0002
#define AUDIO_MIXER_BASS 0x0004
#define AUDIO_MIXER_MID 0x0008
#define AUDIO_MIXER_TREBLE 0x0010
#define AUDIO_MIXER_EQUALIZER 0x0020
#define AUDIO_MIXER_LINE 0x0040
#define AUDIO_MIXER_DIGITAL 0x0080
#define AUDIO_MIXER_MIC 0x0100
#define AUDIO_MIXER_VITURAL 0x0200
#define AUDIO_MIXER_EXTEND 0x8000 /* extend mixer command */
#define AUDIO_VOLUME_MAX (100)
#define AUDIO_VOLUME_MIN (0)
#define CFG_AUDIO_REPLAY_QUEUE_COUNT 8
/**
* audio flags defitions
*/
//#define AUDIO_FLAG_REPLAY 0
//#define AUDIO_FLAG_RECORD 1
#define AUDIO_REPLAY_MP_BLOCK_SIZE 4096
#define AUDIO_REPLAY_MP_BLOCK_COUNT 4
#define AUDIO_RECORD_PIPE_SIZE 2048
//typedef int (*audio_record_callback)(struct audio_device *audio, void *buffer, int size);
enum
{
AUDIO_STREAM_REPLAY = 0,
AUDIO_STREAM_RECORD = 1,
};
/* the preferred number and size of audio pipeline buffer for the audio device */
struct audio_buf_info
{
uint8_t *buffer;
uint16_t block_size;
uint16_t block_count;
uint32_t total_size;
};
struct audio_device;
struct audio_caps;
struct audio_configure;
struct audio_ops
{
int (*getcaps)(struct audio_device *audio, struct audio_caps *caps);
int (*configure)(struct audio_device *audio, struct audio_caps *caps);
int (*init)(struct audio_device *audio);
int (*start)(struct audio_device *audio, int stream);
int (*stop)(struct audio_device *audio, int stream);
size_t (*transmit)(struct audio_device *audio, const void *writeBuf, void *readBuf, size_t size);
/* get page size of codec or private buffer's info */
void (*buffer_info)(struct audio_device *audio, struct audio_buf_info *info, int flags);
};
struct audio_configure
{
uint32_t samplerate;
uint16_t channels;
uint16_t samplebits;
};
struct audio_caps
{
int main_type;
int sub_type;
union
{
uint32_t mask;
int value;
struct audio_configure config;
} udata;
};
struct audio_replay
{
QueueHandle_t queue;
SemaphoreHandle_t lock;
QueueHandle_t cmp;
struct audio_buf_info buf_info;
uint8_t *mempool;
uint8_t mpstatus[AUDIO_REPLAY_MP_BLOCK_COUNT];
uint8_t *write_data;
uint16_t write_index;
uint16_t read_index;
uint32_t pos;
uint8_t event;
bool activated;
};
struct audio_record
{
QueueHandle_t cmp;
struct audio_buf_info buf_info;
int read_index;
int remain_size;
uint8_t event;
bool activated;
int (*receive_cb)(struct audio_device *audio);
};
struct audio_device
{
struct audio_ops *ops;
struct audio_replay *replay;
struct audio_record *record;
/* device call back */
int (*rx_indicate)(struct audio_device *audio, size_t size);
int (*tx_complete)(struct audio_device *audio, void *buffer);
uint32_t flag;
uint32_t id;
void *user_data; /**< device private data */
};
int audio_register(struct audio_device *audio);
void audio_tx_complete(struct audio_device *audio);
int audio_rx_complete(struct audio_device *audio);
void audio_rx_done(struct audio_device *audio, uint8_t *pbuf, size_t len);
struct audio_device *audio_dev_open(uint32_t oflag);
int audio_dev_close(struct audio_device *audio, uint32_t oflag);
size_t audio_dev_read(struct audio_device *audio, void *buffer, size_t size);
size_t audio_dev_write(struct audio_device *audio, const void *buffer, size_t size);
int audio_dev_configure(struct audio_device *audio, struct audio_caps *caps);
int audio_dev_register_record_callback(struct audio_device *audio, int (*callback)(struct audio_device *audio));
int audio_dev_record_set_param(struct audio_device *audio, uint8_t *buf, int size);
int audio_dev_record_start(struct audio_device *audio);
int audio_dev_record_stop(struct audio_device *audio);
/* Device Control Commands */
#define CODEC_CMD_RESET 0
#define CODEC_CMD_SET_VOLUME 1
#define CODEC_CMD_GET_VOLUME 2
#define CODEC_CMD_SAMPLERATE 3
#define CODEC_CMD_EQ 4
#define CODEC_CMD_3D 5
#define CODEC_VOLUME_MAX (63)
#endif /* __AUDIO_H__ */

View File

@ -0,0 +1,67 @@
/*
* blend2d.h
*
*/
#ifndef _BLEND2D_H
#define _BLEND2D_H
typedef enum {
BLEND2D_RGBA = 0,
BLEND2D_ARGB,
} BLEND2D_BLEND_ENDIAN;
typedef enum {
BLEND2D_RGB = 0,
BLEND2D_RBG,
BLEND2D_GRB,
BLEND2D_GBR,
BLEND2D_BRG,
BLEND2D_BGR,
} BLEND2D_RGB_ORDER;
typedef enum {
BLEND2D_FORAMT_RGB565 = 5,
BLEND2D_FORAMT_ARGB888 = 6,
BLEND2D_FORAMT_BGR565 = BLEND2D_FORAMT_RGB565 | (5 << 8),
BLEND2D_FORMAT_ABGR888 = BLEND2D_FORAMT_ARGB888 | (5 << 8),
} BLEND2D_FORMAT;
typedef enum {
BLEND2D_ALPHA_DATA = 0,
BLEND2D_ALPHA_REG,
} BLEND2D_LAYER_ALPHA_MODE;
typedef enum {
BLEND2D_ALPHA_LAYER1 = 0,
BLEND2D_ALPHA_LAYER2,
BLEND2D_ALPHA_BLEND_REG,
} BLEND2D_BLEND_ALPHA_MODE;
typedef enum {
BLEND2D_MIX_BLEND = 0,
BLEND2D_MIX_LAYER1 = 1,
BLEND2D_MIX_LAYER2 = 2,
BLEND2D_MIX_LAYER1_COLORKEY_COVER_TRANSP = 3,
BLEND2D_MIX_LAYER2_COLORKEY_COVER_TRANSP = 0xc,
BLEND2D_MIX_LAYER2_COLORKEY_BLEND_COVER = 0xd,
BLEND2D_MIX_LAYER2_COLORKEY_BLEND_TRANSP = 0xe,
} BLEND2D_BLEND_MIX_MODE;
typedef enum {
BLEND2D_LAYER1 = 0,
BLEND2D_LAYER2,
BLEND2D_NUMS,
} BLEND2D_LAYER;
int blend2d_demo(void);
int blend2d_init(void);
void blend2d_fill(uint32_t address, int xpos, int ypos, int width, int height, int source_width, int source_height,
uint8_t cr, uint8_t cg, uint8_t cb, int format, uint8_t opa, int alpha_byte);
void blend2d_blit(uint32_t dst_addr, int dst_w, int dst_h, int dst_x, int dst_y, int dst_format, int width, int height,
uint32_t src_addr, int src_w, int src_h, int src_x, int src_y, int src_format, uint8_t opa, int alpha_byte);
int blend2d_run(void);
#endif

View File

@ -0,0 +1,238 @@
#ifndef _CAN_H
#define _CAN_H
#ifdef __cplusplus
extern "C" {
#endif
#define CAN0 ( (CAN_TypeDef* )REGS_CAN0_BASE)
#define CAN1 ( (CAN_TypeDef* )REGS_CAN1_BASE)
#define CAN_InitStatus_Failed ((unsigned char)0x00) /*!< CAN initialization failed */
#define CAN_InitStatus_Success ((unsigned char)0x01) /*!< CAN initialization OK */
#define CAN_SJW_1tq ((unsigned char)0x00) /*!< 1 time quantum */
#define CAN_SJW_2tq ((unsigned char)0x01) /*!< 2 time quantum */
#define CAN_SJW_3tq ((unsigned char)0x02) /*!< 3 time quantum */
#define CAN_SJW_4tq ((unsigned char)0x03) /*!< 4 time quantum */
#define CAN_BS1_1tq ((unsigned char)0x00) /*!< 1 time quantum */
#define CAN_BS1_2tq ((unsigned char)0x01) /*!< 2 time quantum */
#define CAN_BS1_3tq ((unsigned char)0x02) /*!< 3 time quantum */
#define CAN_BS1_4tq ((unsigned char)0x03) /*!< 4 time quantum */
#define CAN_BS1_5tq ((unsigned char)0x04) /*!< 5 time quantum */
#define CAN_BS1_6tq ((unsigned char)0x05) /*!< 6 time quantum */
#define CAN_BS1_7tq ((unsigned char)0x06) /*!< 7 time quantum */
#define CAN_BS1_8tq ((unsigned char)0x07) /*!< 8 time quantum */
#define CAN_BS1_9tq ((unsigned char)0x08) /*!< 9 time quantum */
#define CAN_BS1_10tq ((unsigned char)0x09) /*!< 10 time quantum */
#define CAN_BS1_11tq ((unsigned char)0x0A) /*!< 11 time quantum */
#define CAN_BS1_12tq ((unsigned char)0x0B) /*!< 12 time quantum */
#define CAN_BS1_13tq ((unsigned char)0x0C) /*!< 13 time quantum */
#define CAN_BS1_14tq ((unsigned char)0x0D) /*!< 14 time quantum */
#define CAN_BS1_15tq ((unsigned char)0x0E) /*!< 15 time quantum */
#define CAN_BS1_16tq ((unsigned char)0x0F) /*!< 16 time quantum */
#define CAN_BS2_1tq ((unsigned char)0x00) /*!< 1 time quantum */
#define CAN_BS2_2tq ((unsigned char)0x01) /*!< 2 time quantum */
#define CAN_BS2_3tq ((unsigned char)0x02) /*!< 3 time quantum */
#define CAN_BS2_4tq ((unsigned char)0x03) /*!< 4 time quantum */
#define CAN_BS2_5tq ((unsigned char)0x04) /*!< 5 time quantum */
#define CAN_BS2_6tq ((unsigned char)0x05) /*!< 6 time quantum */
#define CAN_BS2_7tq ((unsigned char)0x06) /*!< 7 time quantum */
#define CAN_BS2_8tq ((unsigned char)0x07) /*!< 8 time quantum */
#define CAN_Id_Standard 0
#define CAN_Id_Extended 1
#define CAN_RTR_DATA 0
#define CAN_RTR_Remote 1
/*!< CAN 控制状态寄存器 */
/************************** CAN_MOD 寄存器位定义*******************************/
#define CAN_Mode_RM ((unsigned char)0x01) /*!< 复位模式 */
#define CAN_Mode_LOM ((unsigned char)0x02) /*!< 只听模式 1:只听 0:正常 */
#define CAN_Mode_STM ((unsigned char)0x04) /*!< 正常工作模式1:自检测 0:正常 */
#define CAN_Mode_AFM ((unsigned char)0x08) /*!< 单/双滤波模式 1:单 0: 双*/
#define CAN_Mode_SM ((unsigned char)0x10) /*!< 睡眠模式1: 睡眠 0: 唤醒 */
/************************** CAN_CMR 寄存器位定义*******************************/
#define CAN_CMR_TR ((unsigned char)0x01) /*!< 发送请求 1: 当前信息被发送 0: 空 */
#define CAN_CMR_AT ((unsigned char)0x02) /*!< 中止发送 1: 等待发送的信息取消 0: 空缺 */
#define CAN_CMR_RRB ((unsigned char)0x04) /*!< 释放接收缓冲器 1:释放 0: 无动作 */
#define CAN_CMR_CDO ((unsigned char)0x08) /*!< 清除数据溢出 1:清除 0: 无动作 */
//#define CAN_CMR_GTS ((unsigned char)0x10) /*!< STD模式< 睡眠: 1:进入睡眠 0: 唤醒 */
#define CAN_CMR_SRR ((unsigned char)0x10) /*!< 自接收请求 1: 0: */
#define CAN_CMR_EFF ((unsigned char)0x80) /*!< 扩展模式 1:扩展帧 0: 标准帧 */
/************************** CAN_SR 寄存器位定义********************************/
#define CAN_SR_BBS ((unsigned char)0x01) /*!< 接收缓存器状态1: 满 0: 空 */
#define CAN_SR_DOS ((unsigned char)0x02) /*!< 数据溢出状态 1: 溢出 0: 空缺 */
#define CAN_SR_TBS ((unsigned char)0x04) /*!< 发送缓存器状态1: 释放 0: 锁定 */
#define CAN_SR_TCS ((unsigned char)0x08) /*!< 发送完毕状态1: 完毕 0: 未完毕 */
#define CAN_SR_RS ((unsigned char)0x10) /*!< 接收状态1: 接收 0: 空闲 */
#define CAN_SR_TS ((unsigned char)0x20) /*!< 发送状态1: 发送 0: 空闲*/
#define CAN_SR_ES ((unsigned char)0x40) /*!< 出错状态1:出错 0: 正常 */
#define CAN_SR_BS ((unsigned char)0x80) /*!< 总线状态1: 关闭 0: 开启 */
/************************** CAN_IR 中断寄存器位定义****************************/
#define CAN_IR_RI ((unsigned char)0x01) /*!< 接收中断 */
#define CAN_IR_TI ((unsigned char)0x02) /*!< 发送中断 */
#define CAN_IR_EI ((unsigned char)0x04) /*!< 错误中断 */
#define CAN_IR_DOI ((unsigned char)0x08) /*!< 数据溢出中断 */
#define CAN_IR_WUI ((unsigned char)0x10) /*!< 唤醒中断 */
#define CAN_IR_EPI ((unsigned char)0x20) /*!< 错误消极中断 */
#define CAN_IR_ALI ((unsigned char)0x40) /*!< 仲裁丢失中断 */
#define CAN_IR_BEI ((unsigned char)0x80) /*!< 总线错误中断 */
/************************* CAN_IER 中断使能寄存器位定义************************/
#define CAN_IER_RIE ((unsigned char)0x01) /*!< 接收中断使能 */
#define CAN_IER_TIE ((unsigned char)0x02) /*!< 发送中断使能 */
#define CAN_IER_EIE ((unsigned char)0x04) /*!< 错误中断使能 */
#define CAN_IER_DOIE ((unsigned char)0x08) /*!< 数据溢出中断使能 */
#define CAN_IER_WUIE ((unsigned char)0x10) /*!< 唤醒中断使能 */
#define CAN_IER_EPIE ((unsigned char)0x20) /*!< 错误消极中断使能 */
#define CAN_IER_ALIE ((unsigned char)0x40) /*!< 仲裁丢失中断使能 */
#define CAN_IER_BEIE ((unsigned char)0x80) /*!< 总线错误中断使能 */
typedef enum
{
CAN1MBaud=0, // 1 MBit/sec
CAN800kBaud, // 800 kBit/sec
CAN500kBaud, // 500 kBit/sec
CAN250kBaud, // 250 kBit/sec
CAN125kBaud, // 125 kBit/sec
CAN100kBaud, // 100 kBit/sec
CAN50kBaud, // 50 kBit/sec
CAN40kBaud, // 40 kBit/sec
} CanBPS_t;
typedef enum
{
CAN_MODE_NORMAL=0,
CAN_MODE_LISEN,
CAN_MODE_LOOPBACK,
CAN_MODE_LOOPBACKANLISEN,
} CanMode_t;
typedef struct
{
unsigned int MOD;
unsigned int CMR;
unsigned int SR;
unsigned int IR;
unsigned int IER;
unsigned int reserved0;
unsigned int BTR0;
unsigned int BTR1;
unsigned int OCR;
unsigned int reserved[2];
unsigned int ALC;
unsigned int ECC ;
unsigned int EWLR;
unsigned int RXERR;
unsigned int TXERR;
unsigned int IDE_RTR_DLC;
unsigned int ID[4];
unsigned int BUF[8];
unsigned int RMC;
unsigned int RBSA;
unsigned int CDR;
} CAN_TypeDef;
typedef struct
{
unsigned char CAN_Prescaler; /* 波特率分频系数1 to 63. */
unsigned char CAN_Mode; /*0x10:睡眠0x08:单,双滤波 0x40:正常工作0x20:只听 0x01:复位*/
unsigned char CAN_SJW; /*同步跳转宽度 */
unsigned char CAN_BS1; /*时间段1计数值*/
unsigned char CAN_BS2; /*时间段2计数值*/
} CAN_InitTypeDef;
typedef struct
{
unsigned char IDE; /*0: 使用标准标识符1: 使用扩展标识符*/
unsigned char RTR; /*0: 数据帧 1: 远程帧*/
unsigned char MODE; /* 0- 双滤波器模式;1-单滤波器模式*/
unsigned long First_Data; /*双滤波器模式下信息第一个数据字节*/
unsigned long Data_Mask; /*双滤波器模式下信息第一个数据字节屏蔽*/
unsigned long ID; /*验收代码*/
/*
双滤波器- 扩展帧: 2个滤波器的前16位,分别放在ID 的前16位和 ID的后16位.
双滤波器- 标准帧: 2个滤波器的11位,分别放在ID 的前16位和 ID的后16位,第1个滤波器同时使用First_Data和Data_Mask
单滤波器- 扩展帧: 使用29位, 放在ID 的后29位.
单滤波器- 标准帧: 使用11位, 放在ID 的后11位.
*/
unsigned long IDMASK; /*验收屏蔽*/
} CAN_FilterInitTypeDef;
typedef struct
{
unsigned long StdId; /* 11位ID*/
unsigned long ExtId; /*29位ID**/
unsigned char IDE; /*IDE: 标识符选择
该位决定发送邮箱中报文使用的标识符类型
0: 使用标准标识符
1: 使用扩展标识符*/
unsigned char RTR; /*远程发送请求
0: 数据帧
1: 远程帧*/
unsigned char DLC; /*数据帧长度*/
unsigned char Data[8]; /*8字节数据*/
} CanMsg;
unsigned char CAN_Init(CAN_TypeDef* CANx, CAN_InitTypeDef* CAN_InitStruct);
void CAN_Transmit(CAN_TypeDef* CANx, CanMsg* TxMessage);
void CAN_Receive(CAN_TypeDef* CANx, CanMsg* RxMessage);
unsigned char can_set_reset_mode(CAN_TypeDef* CANx);
unsigned char can_set_start(CAN_TypeDef* CANx);
typedef enum {
CAN_ID0 = 0,
CAN_ID1,
CAN_NUM,
} eCanID;
typedef struct {
uint32_t baud_rate;
uint32_t msgboxsz;
uint32_t sndboxnumber;
uint32_t mode : 8;
uint32_t privmode : 8;
uint32_t reserved : 16;
uint32_t ticks;
} CanConfigure_t;
typedef struct {
uint32_t id;
int irq;
CAN_TypeDef *pcan;
SemaphoreHandle_t xRxMutex;
SemaphoreHandle_t xRev;
SemaphoreHandle_t xSend;
SemaphoreHandle_t xTxMutex;
TaskHandle_t xTxThread;
QueueHandle_t tx_done;
List_t rxRevList;
List_t rxFreeList;
List_t txSendList;
List_t txFreeList;
} CanPort_t;
CanPort_t *xCanOpen(uint32_t id);
void vCanClose(CanPort_t *cap);
void vCanSetFilter(CanPort_t *cap, CAN_FilterInitTypeDef * CAN_FilterInitStruct);
int iCanWrite(CanPort_t *cap, CanMsg* messages, int nmsgs, TickType_t xBlockTime);
int iCanRead(CanPort_t *cap, CanMsg* messages, int nmsgs, TickType_t xBlockTime);
void vCanInit(CanPort_t *cap, CanBPS_t baud, CanMode_t mode);
int iCanGetReceiveErrorCount(CanPort_t *cap);
int iCanGetTransmitErrorCount(CanPort_t *cap);
int can_demo(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,46 @@
#ifndef _CIRC_BUF_H
#define _CIRC_BUF_H
#ifdef __cplusplus
extern "C" {
#endif
struct circ_buf {
char *buf;
int head;
int tail;
};
/* Return count in buffer. */
#define CIRC_CNT(head,tail,size) (((head) - (tail)) & ((size)-1))
/* Return space available, 0..size-1. We always leave one free char
as a completely full buffer has head == tail, which is the same as
empty. */
#define CIRC_SPACE(head,tail,size) CIRC_CNT((tail),((head)+1),(size))
/* Return count up to the end of the buffer. Carefully avoid
accessing head and tail more than once, so they can change
underneath us without returning inconsistent results. */
static __INLINE int CIRC_CNT_TO_END(uint32_t head, uint32_t tail, uint32_t size)
{
int end = (size) - (tail);
int n = ((head) + end) & ((size)-1);
return n < end ? n : end;
}
/* Return space available up to the end of the buffer. */
static __INLINE int CIRC_SPACE_TO_END(uint32_t head, uint32_t tail, uint32_t size)
{
int end = (size) - 1 - (head);
int n = (end + (tail)) & ((size) - 1);
return n <= end ? n : end + 1;
}
#ifdef __cplusplus
}
#endif
#endif /* _LINUX_CIRC_BUF_H */

View File

@ -0,0 +1,69 @@
#ifndef _CLOCK_H
#define _CLOCK_H
#ifdef __cplusplus
extern "C" {
#endif
#define MAX_CLK_SOURCE_NUM 4
#define MAX_CLK_ENABLE_BITS 4
typedef enum {
CLK_XTAL32K = 0,
CLK_XTAL24M,
CLK_240MHZ,
CLK_12MHZ,
CLK_6MHZ,
CLK_CPUPLL,
CLK_SYSPLL,
CLK_VPUPLL,
CLK_DDRPLL,//<2F><><EFBFBD><EFBFBD>DDR PLL
CLK_DDR,
CLK_CPU,
CLK_H2X,
CLK_AHB,
CLK_APB,
CLK_RTC,
CLK_SPI0,
CLK_SPI1,
CLK_SDMMC0,
CLK_LCD,
CLK_UART1,
CLK_UART2,
CLK_UART3,
CLK_TIMER,
CLK_MFC,
CLK_PWM,
CLK_CAN0,
CLK_CAN1,
CLK_ADC,
CLK_I2S,
CLK_I2S1,
}eClockID;
typedef enum {
FIXED_CLOCK = 0,
FIXED_FACTOR_CLOCK,
PLL_CLOCK,
SYS_CLOCK,
}eClockType;
typedef enum {
DIVMODE_NOZERO = 0, /* div = div ? div : 1 */
DIVMODE_PLUSONE, /* div = div + 1 */
DIVMODE_DOUBLE, /* div = div * 2 */
DIVMODE_EXPONENT, /* div = 1 << div */
DIVMODE_PONEDOUBLE, /* div = (div + 1) * 2 */
}eDivMode;
void vClkInit(void);
uint32_t ulClkGetRate(uint32_t clkid);
void vClkSetRate(uint32_t clkid, uint32_t freq);
void vClkEnable(uint32_t clkid);
void vClkDisable(uint32_t clkid);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,95 @@
#ifndef _DMA_H
#define _DMA_H
#ifdef __cplusplus
extern "C" {
#endif
#define DMA_INT_TC (1 << 0)
#define DMA_INT_ERR (1 << 1)
enum DMA_HW_HS_MAP{
SPI0_RX = 0,
SPI0_TX,
SPI1_RX,
SPI1_TX,
I2C0_RX,
I2C0_TX,
I2C1_RX,
I2C1_TX,
UART0_RX,
UART0_TX,
UART1_RX,
UART1_TX,
UART2_RX,
UART2_TX,
UART3_RX,
UART3_TX,
I2S_RX,
I2S_TX,
I2S1_RX,
I2S1_TX,
SDMMC0_RTX,
};
enum dma_transfer_direction {
DMA_MEM_TO_MEM,
DMA_MEM_TO_DEV,
DMA_DEV_TO_MEM,
DMA_DEV_TO_DEV,
DMA_TRANS_NONE,
};
enum dma_buswidth {
DMA_BUSWIDTH_1_BYTE = 0,
DMA_BUSWIDTH_2_BYTES = 1,
DMA_BUSWIDTH_4_BYTES = 2,
};
struct dma_config {
enum dma_transfer_direction direction;
int src_id;
int dst_id;
unsigned int src_addr;
unsigned int dst_addr;
enum dma_buswidth src_addr_width;
enum dma_buswidth dst_addr_width;
u32 src_maxburst;
u32 dst_maxburst;
u32 transfer_size;
int blkint_en;
};
struct dma_lli {
unsigned int src_addr;
unsigned int dst_addr;
unsigned int next_lli;
unsigned int control;
};
struct dma_chan {
int chan_id;
int in_use;
void (*irq_callback)(void *param, unsigned int mask);
void *callback_param;
struct dma_lli *lli;
};
struct dma_chan *dma_request_channel(int favorite_ch);
void dma_release_channel(struct dma_chan *chan);
int dma_config_channel(struct dma_chan *chan, struct dma_config *config);
int dma_register_complete_callback(struct dma_chan *chan,
void (*callback)(void *param, unsigned int mask),
void *callback_param);
int dma_start_channel(struct dma_chan *chan);
int dma_stop_channel(struct dma_chan *chan);
int dma_init(void);
int dma_m2mcpy(unsigned int dst_addr, unsigned int src_addr, int size);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,212 @@
/****************************************************************************
* include/audio/automount.h
*
* Copyright (C) 2014 Gregory Nutt. All rights reserved.
* Copyright (c) <2014-2015>, <Huawei Technologies Co., Ltd>
* All rights reserved.
*
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Notice of Export Control Law
* ===============================================
* Huawei LiteOS may be subject to applicable export control laws and regulations,
* which might include those applicable to Huawei LiteOS of U.S. and the country in
* which you are located.
* Import, export and usage of Huawei LiteOS in any manner by you shall be in
* compliance with such applicable export control laws and regulations.
****************************************************************************/
#ifndef __INCLUDE_AUDIO_AUTOMOUNT_H
#define __INCLUDE_AUDIO_AUTOMOUNT_H
/****************************************************************************
* Included Files
****************************************************************************/
#include "stdint.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Configuration ************************************************************
* Automounter configuration
* CONFIG_FS_AUTOMOUNTER - Enables automount support
*
* Prequisites:
* CONFIG_SCHED_WORKQUEUE - Work queue support is required
* And others that would only matter if you are working in a very minimal
* configuration.
*/
/* Helper macros ************************************************************/
#define AUTOMOUNT_ATTACH(s,isr,arg) ((s)->attach(s,isr,arg))
#define AUTOMOUNT_DETACH(s) ((s)->attach(s,NULL,NULL))
#define AUTOMOUNT_ENABLE(s) ((s)->enable(s,true))
#define AUTOMOUNT_DISABLE(s) ((s)->enable(s,false))
#define AUTOMOUNT_INSERTED(s) ((s)->inserted(s))
/****************************************************************************
* Public Types
****************************************************************************/
/* This is the type of the automount media change handler. The lower level
* code will intercept the interrupt and provide the upper level with the
* private data that was provided when the interrupt was attached and will
* also provide an indication if the media was inserted or removed.
*/
struct automount_lower_s; /* Forward reference. Defined below */
typedef CODE int
(*automount_handler_t)(FAR const struct automount_lower_s *lower,
FAR void *arg, bool inserted);
/* A reference to a structure of this type must be passed to the FS
* automounter. This structure provides information about the volume to be
* mounted and provides board-specific hooks.
*
* Memory for this structure is provided by the caller. It is not copied
* by the automounter and is presumed to persist while the automounter
* is active.
*/
struct automount_lower_s
{
/* Volume characterization */
FAR const char *fstype; /* Type of file system */
FAR const char *blockdev; /* Path to the block device */
FAR const char *mountpoint; /* Location to mount the volume */
/* Debounce delay in system clock ticks. Automount operation will not
* be performed until the insertion/removal state has been unchanges
* for this duration.
*/
uint32_t ddelay;
/* Unmount delay time in system clock ticks. If a volume has open
* references at the time that the media is removed, then we will be
* unable to unmount it. In that case, hopefully, the clients of the
* mount will eventually fail with file access errors and eventually close
* their references. So, at some time later, it should be possible to
* unmount the volume. This delay specifies the time between umount
* retries.
*/
uint32_t udelay;
/* Interrupt related operations all hidden behind callbacks to isolate the
* automounter from differences in interrupt handling by varying boards
* and MCUs. Board interrupts should be configured both insertion and
* removal of the media can be detected.
*
* attach - Attach or detach the media change interrupt handler to the
* board level interrupt
* enable - Enable or disable the media change interrupt
*/
CODE int (*attach)(FAR const struct automount_lower_s *lower,
automount_handler_t isr, FAR void *arg);
CODE void (*enable)(FAR const struct automount_lower_s *lower,
bool enable);
CODE bool (*inserted)(FAR const struct automount_lower_s *lower);
};
/****************************************************************************
* Public Data
****************************************************************************/
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: automount_initialize
*
* Description:
* Configure the automounter.
*
* Input Parameters:
* lower - Persistent board configuration data
*
* Returned Value:
* A void* handle. The only use for this handle is with automount_uninitialize().
* NULL is returned on any failure.
*
****************************************************************************/
FAR void *automount_initialize(FAR const struct automount_lower_s *lower);
/****************************************************************************
* Name: automount_uninitialize
*
* Description:
* Stop the automounter and free resources that it used. NOTE that the
* mount is left in its last state mounted/unmounted state.
*
* Input Parameters:
* handle - The value previously returned by automount_initialize();
*
* Returned Value:
* None
*
****************************************************************************/
void automount_uninitialize(FAR void *handle);
#undef EXTERN
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */
#endif /* __INCLUDE_AUDIO_AUTOMOUNT_H */

View File

@ -0,0 +1,145 @@
/****************************************************************************
* include/fs/dirent.h
*
* Copyright (C) 2007, 2009, 2011-2013 Gregory Nutt. All rights reserved.
* Copyright (c) <2014-2015>, <Huawei Technologies Co., Ltd>
* All rights reserved.
*
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Notice of Export Control Law
* ===============================================
* Huawei LiteOS may be subject to applicable export control laws and regulations,
* which might include those applicable to Huawei LiteOS of U.S. and the country in
* which you are located.
* Import, export and usage of Huawei LiteOS in any manner by you shall be in
* compliance with such applicable export control laws and regulations.
****************************************************************************/
#ifndef __INCLUDE_FS_DIRENT_H
#define __INCLUDE_FS_DIRENT_H
/****************************************************************************
* Included Files
****************************************************************************/
#include "vfs_config.h"
#include "sys/types.h"
#include "stdint.h"
#include "dirent.h"
#include "fs/fs.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/****************************************************************************
* Public Types
****************************************************************************/
/* The internal representation of type DIR is just a container for an inode
* reference, a position, a dirent structure, and file-system-specific
* information.
*
* For the root pseudo-file system, we need retain only the 'next' inode
* need for the next readdir() operation. We hold a reference on this
* inode so we know that it will persist until closedir is called.
*/
struct fs_pseudodir_s
{
struct inode *fd_next; /* The inode for the next call to readdir() */
};
typedef void *fs_dir_s;
#define DIRENT_MAGIC 0x11CBA828 /* Magic number to express the status of a dirent */
struct fs_dirent_s
{
/* This is the node that was opened by opendir. The type of the inode
* determines the way that the readdir() operations are performed. For the
* pseudo root pseudo-file system, it is also used to support rewind.
*
* We hold a reference on this inode so we know that it will persist until
* closedir() is called (although inodes linked to this inode may change).
*/
struct inode *fd_root;
/* At present, only mountpoints require special handling flags */
#ifndef CONFIG_DISABLE_MOUNTPOINT
unsigned int fd_flags;
#endif
/* This keeps track of the current directory position for telldir */
off_t fd_position;
/* Retained control information depends on the type of file system that
* provides is provides the mountpoint. Ideally this information should
* be hidden behind an opaque, file-system-dependent void *, but we put
* the private definitions in line here for now to reduce allocations.
*/
struct
{
/* Private data used by the built-in pseudo-file system */
struct fs_pseudodir_s pseudo;
/* Private data used by other file systems */
fs_dir_s fs_dir;
} u;
/* In any event, this the actual struct dirent that is returned by readdir */
struct dirent fd_dir; /* Populated when readdir is called */
int fd_status; /* Express the dirent is been opened or no */
};
/****************************************************************************
* Global Variables
****************************************************************************/
extern DIR *fdopendir(int);
#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */
#endif /* __INCLUDE_FS_DIRENT_H */

View File

@ -0,0 +1,412 @@
/****************************************************************************
* include/fs/file.h
*
* Copyright (C) 2007-2009, 2011-2013 Gregory Nutt. All rights reserved.
* Copyright (c) <2014-2015>, <Huawei Technologies Co., Ltd>
* All rights reserved.
*
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Notice of Export Control Law
* ===============================================
* Huawei LiteOS may be subject to applicable export control laws and regulations,
* which might include those applicable to Huawei LiteOS of U.S. and the country in
* which you are located.
* Import, export and usage of Huawei LiteOS in any manner by you shall be in
* compliance with such applicable export control laws and regulations.
****************************************************************************/
/**@defgroup fs Filesystem
*
*/
#ifndef __INCLUDE_FS_FILE_H
#define __INCLUDE_FS_FILE_H
/****************************************************************************
* Included Files
****************************************************************************/
#include "vfs_config.h"
#include "compiler.h"
#include "sys/types.h"
#include "stdarg.h"
#include "stdint.h"
#include "semaphore.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/****************************************************************************
* Global Function Prototypes
****************************************************************************/
struct filelist *sched_getfiles(void);
/* fs_inode.c ***************************************************************/
/****************************************************************************
* Name: fs_initialize
*
* Description:
* This is called from the OS initialization logic to configure the file
* system.
*
****************************************************************************/
void fs_initialize(void);
/* fs_files.c ***************************************************************/
/****************************************************************************
* Name: files_initlist
*
* Description:
* Initializes the list of files for a new task
*
****************************************************************************/
#if CONFIG_NFILE_DESCRIPTORS > 0
void files_initlist(FAR struct filelist *list);
#endif
/****************************************************************************
* Name: files_releaselist
*
* Description:
* Release a reference to the file list
*
****************************************************************************/
#if CONFIG_NFILE_DESCRIPTORS > 0
void files_releaselist(FAR struct filelist *list);
#endif
/****************************************************************************
* Name: file_dup2
*
* Description:
* Assign an inode to a specific files structure. This is the heart of
* dup2.
*
****************************************************************************/
#if CONFIG_NFILE_DESCRIPTORS > 0
int file_dup2(FAR struct file *filep1, FAR struct file *filep2);
#endif
/* fs_filedup.c *************************************************************/
/****************************************************************************
* Name: fs_dupfd OR dup
*
* Description:
* Clone a file descriptor 'fd' to an arbitray descriptor number (any value
* greater than or equal to 'minfd'). If socket descriptors are
* implemented, then this is called by dup() for the case of file
* descriptors. If socket descriptors are not implemented, then this
* function IS dup().
*
* This alternative naming is used when dup could operate on both file and
* socket descritors to avoid drawing unused socket support into the link.
*
****************************************************************************/
#if CONFIG_NFILE_DESCRIPTORS > 0
int fs_dupfd(int fd, int minfd);
#endif
/****************************************************************************
* Name: file_dup
*
* Description:
* Equivalent to the non-standard fs_dupfd() function except that it
* accepts a struct file instance instead of a file descriptor. Currently
* used only by file_vfcntl();
*
****************************************************************************/
int file_dup(FAR struct file *filep, int minfd);
/* fs_filedup2.c ************************************************************/
/****************************************************************************
* Name: fs_dupfd2 OR dup2
*
* Description:
* Clone a file descriptor to a specific descriptor number. If socket
* descriptors are implemented, then this is called by dup2() for the
* case of file descriptors. If socket descriptors are not implemented,
* then this function IS dup2().
*
* This alternative naming is used when dup2 could operate on both file and
* socket descritors to avoid drawing unused socket support into the link.
*
****************************************************************************/
#if CONFIG_NFILE_DESCRIPTORS > 0
int fs_dupfd2(int fd1, int fd2);
#endif
/* fs/vfs/fs_ioctl.c ********************************************************/
/****************************************************************************
* Name: fs_ioctl
*
* Description:
* Perform device specific operations.
*
* Parameters:
* fd File/socket descriptor of device
* req The ioctl command
* arg The argument of the ioctl cmd
*
* Return:
* >=0 on success (positive non-zero values are cmd-specific)
* -1 on failure with errno set properly:
*
* EBADF
* 'fd' is not a valid descriptor.
* EFAULT
* 'arg' references an inaccessible memory area.
* EINVAL
* 'cmd' or 'arg' is not valid.
* ENOTTY
* 'fd' is not associated with a character special device.
* ENOTTY
* The specified request does not apply to the kind of object that the
* descriptor 'fd' references.
*
****************************************************************************/
#ifdef CONFIG_LIBC_IOCTL_VARIADIC
int fs_ioctl(int fd, int req, unsigned long arg);
#endif
/* fs_fdopen.c **************************************************************/
/****************************************************************************
* Name: fs_fdopen
*
* Description:
* This function does the core operations for fopen and fdopen. It is
* used by the OS to clone stdin, stdout, stderr
*
****************************************************************************/
#if CONFIG_NFILE_STREAMS > 0
struct tcb_s; /* Forward reference */
FAR struct file_struct *fs_fdopen(int fd, int oflags);
#endif
/* libc/stdio/lib_fflush.c *************************************************/
/****************************************************************************
* Name: lib_flushall
*
* Description:
* Called either (1) by the OS when a task exits, or (2) from fflush()
* when a NULL stream argument is provided.
*
****************************************************************************/
#if CONFIG_NFILE_STREAMS > 0
int lib_flushall(FAR struct streamlist *list);
#endif
/* libc/misc/lib_sendfile.c *************************************************/
/****************************************************************************
* Name: lib_sendfile
*
* Description:
* Transfer a file
*
****************************************************************************/
#ifdef CONFIG_NET_SENDFILE
ssize_t lib_sendfile(int outfd, int infd, off_t *offset, size_t count);
#endif
/* fs/fs_getfilep.c *********************************************************/
/****************************************************************************
* Name: fs_getfilep
*
* Description:
* Given a file descriptor, return the corresponding instance of struct
* file. NOTE that this function will currently fail if it is provided
* with a socket descriptor.
*
* Parameters:
* fd - The file descriptor
*
* Return:
* A point to the corresponding struct file instance is returned on
* success. On failure, NULL is returned and the errno value is
* set appropriately (EBADF).
*
****************************************************************************/
#if CONFIG_NFILE_DESCRIPTORS > 0
FAR struct file *fs_getfilep(int fd);
#endif
/* fs/fs_read.c *************************************************************/
/****************************************************************************
* Name: file_read
*
* Description:
* Equivalent to the standard read() function except that is accepts a
* struct file instance instead of a file descriptor. Currently used
* only by net_sendfile() and aio_read();
*
****************************************************************************/
#if CONFIG_NFILE_DESCRIPTORS > 0
ssize_t file_read(FAR struct file *filep, FAR void *buf, size_t nbytes);
#endif
/* fs/fs_write.c ************************************************************/
/****************************************************************************
* Name: file_write
*
* Description:
* Equivalent to the standard write() function except that is accepts a
* struct file instance instead of a file descriptor. Currently used
* only by aio_write();
*
****************************************************************************/
#if CONFIG_NFILE_DESCRIPTORS > 0
ssize_t file_write(FAR struct file *filep, FAR const void *buf, size_t nbytes);
#endif
/* fs/fs_pread.c ************************************************************/
/****************************************************************************
* Name: file_pread
*
* Description:
* Equivalent to the standard pread function except that is accepts a
* struct file instance instead of a file descriptor. Currently used
* only by aio_read();
*
****************************************************************************/
#if CONFIG_NFILE_DESCRIPTORS > 0
ssize_t file_pread(FAR struct file *filep, FAR void *buf, size_t nbytes,
off_t offset);
#endif
/* fs/fs_pwrite.c ***********************************************************/
/****************************************************************************
* Name: file_pwrite
*
* Description:
* Equivalent to the standard pwrite function except that is accepts a
* struct file instance instead of a file descriptor. Currently used
* only by aio_write();
*
****************************************************************************/
#if CONFIG_NFILE_DESCRIPTORS > 0
ssize_t file_pwrite(FAR struct file *filep, FAR const void *buf,
size_t nbytes, off_t offset);
#endif
/* fs/fs_lseek.c ************************************************************/
/****************************************************************************
* Name: file_seek
*
* Description:
* Equivalent to the standard lseek() function except that is accepts a
* struct file instance instead of a file descriptor. Currently used
* only by net_sendfile()
*
****************************************************************************/
#if CONFIG_NFILE_DESCRIPTORS > 0
off_t file_seek(FAR struct file *filep, off_t offset, int whence);
#endif
/* fs/fs_lseek64.c ************************************************************/
/****************************************************************************
* Name: file_seek64
*
* Description:
* Equivalent to the standard lseek64() function except that is accepts a
* struct file instance instead of a file descriptor. Currently used
* only by net_sendfile()
*
****************************************************************************/
#if CONFIG_NFILE_DESCRIPTORS > 0
off64_t file_seek64(FAR struct file *filep, off64_t offset, int whence);
#endif
/* fs/fs_fsync.c ************************************************************/
/****************************************************************************
* Name: file_fsync
*
* Description:
* Equivalent to the standard fsync() function except that is accepts a
* struct file instance instead of a file descriptor. Currently used
* only by aio_fsync();
*
****************************************************************************/
#if CONFIG_NFILE_DESCRIPTORS > 0
int file_fsync(FAR struct file *filep);
#endif
/* fs/fs_fcntl.c ************************************************************/
/****************************************************************************
* Name: file_vfcntl
*
* Description:
* Similar to the standard vfcntl function except that is accepts a struct
* struct file instance instead of a file descriptor. Currently used
* only by aio_fcntl();
*
****************************************************************************/
#if CONFIG_NFILE_DESCRIPTORS > 0
int file_vfcntl(FAR struct file *filep, int cmd, va_list ap);
#endif
void clear_fd(int fd);
#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */
#endif /* __INCLUDE_FS_FILE_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,35 @@
#ifndef _GPIO_H
#define _GPIO_H
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
GPIOIRQ_TYPE_EDGE_BOTH,
GPIOIRQ_TYPE_EDGE_RISING,
GPIOIRQ_TYPE_EDGE_FALLING,
GPIOIRQ_TYPE_LEVEL_HIGH,
GPIOIRQ_TYPE_LEVEL_LOW,
} eGpioIrqType;
void gpio_request(unsigned gpio);
void gpio_direction_output(unsigned gpio, int value);
void gpio_direction_input(unsigned gpio);
void gpio_set_value(unsigned gpio, int value);
int gpio_get_value(unsigned gpio);
int gpio_irq_request(unsigned gpio, int irq_type, ISRFunction_t irq_handler, void *param);
int gpio_irq_free(unsigned gpio);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,34 @@
#ifndef _HX170DEC_H_
#define _HX170DEC_H_
struct core_desc
{
u32 id; /* id of the core */
u32 *regs; /* pointer to user registers */
u32 size; /* size of register space */
};
#define HX170DEC_IOCGHWOFFSET 3
#define HX170DEC_IOCGHWIOSIZE 4
#define HX170DEC_IOC_MC_OFFSETS 7
#define HX170DEC_IOC_MC_CORES 8
#define HX170DEC_IOCS_DEC_PUSH_REG 9
#define HX170DEC_IOCS_PP_PUSH_REG 10
#define HX170DEC_IOCH_DEC_RESERVE 11
#define HX170DEC_IOCT_DEC_RELEASE 12
#define HX170DEC_IOCQ_PP_RESERVE 13
#define HX170DEC_IOCT_PP_RELEASE 14
#define HX170DEC_IOCX_DEC_WAIT 15
#define HX170DEC_IOCX_PP_WAIT 16
#define HX170DEC_IOCS_DEC_PULL_REG 17
#define HX170DEC_IOCS_PP_PULL_REG 18
#define HX170DEC_IOX_ASIC_ID 20
#define HX170DEC_IOC_MAXNR 29
long vdec_ioctl(unsigned int cmd, void *arg);
#endif /* !_HX170DEC_H_ */

View File

@ -0,0 +1,275 @@
#ifndef _I2C_DW_H
#define _I2C_DW_H
#ifdef __cplusplus
extern "C" {
#endif
#define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \
I2C_FUNC_SMBUS_BYTE | \
I2C_FUNC_SMBUS_BYTE_DATA | \
I2C_FUNC_SMBUS_WORD_DATA | \
I2C_FUNC_SMBUS_BLOCK_DATA | \
I2C_FUNC_SMBUS_I2C_BLOCK)
#define DW_IC_CON_MASTER 0x1
#define DW_IC_CON_SPEED_STD 0x2
#define DW_IC_CON_SPEED_FAST 0x4
#define DW_IC_CON_SPEED_HIGH 0x6
#define DW_IC_CON_SPEED_MASK 0x6
#define DW_IC_CON_10BITADDR_SLAVE 0x8
#define DW_IC_CON_10BITADDR_MASTER 0x10
#define DW_IC_CON_RESTART_EN 0x20
#define DW_IC_CON_SLAVE_DISABLE 0x40
#define DW_IC_CON_STOP_DET_IFADDRESSED 0x80
#define DW_IC_CON_TX_EMPTY_CTRL 0x100
#define DW_IC_CON_RX_FIFO_FULL_HLD_CTRL 0x200
/*
* Registers offset
*/
#define DW_IC_CON 0x0
#define DW_IC_TAR 0x4
#define DW_IC_SAR 0x8
#define DW_IC_DATA_CMD 0x10
#define DW_IC_SS_SCL_HCNT 0x14
#define DW_IC_SS_SCL_LCNT 0x18
#define DW_IC_FS_SCL_HCNT 0x1c
#define DW_IC_FS_SCL_LCNT 0x20
#define DW_IC_HS_SCL_HCNT 0x24
#define DW_IC_HS_SCL_LCNT 0x28
#define DW_IC_INTR_STAT 0x2c
#define DW_IC_INTR_MASK 0x30
#define DW_IC_RAW_INTR_STAT 0x34
#define DW_IC_RX_TL 0x38
#define DW_IC_TX_TL 0x3c
#define DW_IC_CLR_INTR 0x40
#define DW_IC_CLR_RX_UNDER 0x44
#define DW_IC_CLR_RX_OVER 0x48
#define DW_IC_CLR_TX_OVER 0x4c
#define DW_IC_CLR_RD_REQ 0x50
#define DW_IC_CLR_TX_ABRT 0x54
#define DW_IC_CLR_RX_DONE 0x58
#define DW_IC_CLR_ACTIVITY 0x5c
#define DW_IC_CLR_STOP_DET 0x60
#define DW_IC_CLR_START_DET 0x64
#define DW_IC_CLR_GEN_CALL 0x68
#define DW_IC_ENABLE 0x6c
#define DW_IC_STATUS 0x70
#define DW_IC_TXFLR 0x74
#define DW_IC_RXFLR 0x78
#define DW_IC_SDA_HOLD 0x7c
#define DW_IC_TX_ABRT_SOURCE 0x80
#define DW_IC_ENABLE_STATUS 0x9c
#define DW_IC_CLR_RESTART_DET 0xa8
#define DW_IC_COMP_PARAM_1 0xf4
#define DW_IC_COMP_VERSION 0xf8
#define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A
#define DW_IC_COMP_TYPE 0xfc
#define DW_IC_COMP_TYPE_VALUE 0x44570140
#define DW_IC_INTR_RX_UNDER 0x001
#define DW_IC_INTR_RX_OVER 0x002
#define DW_IC_INTR_RX_FULL 0x004
#define DW_IC_INTR_TX_OVER 0x008
#define DW_IC_INTR_TX_EMPTY 0x010
#define DW_IC_INTR_RD_REQ 0x020
#define DW_IC_INTR_TX_ABRT 0x040
#define DW_IC_INTR_RX_DONE 0x080
#define DW_IC_INTR_ACTIVITY 0x100
#define DW_IC_INTR_STOP_DET 0x200
#define DW_IC_INTR_START_DET 0x400
#define DW_IC_INTR_GEN_CALL 0x800
#define DW_IC_INTR_RESTART_DET 0x1000
#define DW_IC_INTR_DEFAULT_MASK (DW_IC_INTR_RX_FULL | \
DW_IC_INTR_TX_ABRT | \
DW_IC_INTR_STOP_DET)
#define DW_IC_INTR_MASTER_MASK (DW_IC_INTR_DEFAULT_MASK | \
DW_IC_INTR_TX_EMPTY)
#define DW_IC_INTR_SLAVE_MASK (DW_IC_INTR_DEFAULT_MASK | \
DW_IC_INTR_RX_DONE | \
DW_IC_INTR_RX_UNDER | \
DW_IC_INTR_RD_REQ)
#define DW_IC_STATUS_ACTIVITY 0x1
#define DW_IC_STATUS_TFE BIT(2)
#define DW_IC_STATUS_MASTER_ACTIVITY BIT(5)
#define DW_IC_STATUS_SLAVE_ACTIVITY BIT(6)
#define DW_IC_SDA_HOLD_RX_SHIFT 16
#define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, DW_IC_SDA_HOLD_RX_SHIFT)
#define DW_IC_ERR_TX_ABRT 0x1
#define DW_IC_TAR_10BITADDR_MASTER BIT(12)
#define DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH (BIT(2) | BIT(3))
#define DW_IC_COMP_PARAM_1_SPEED_MODE_MASK GENMASK(3, 2)
/*
* status codes
*/
#define STATUS_IDLE 0x0
#define STATUS_WRITE_IN_PROGRESS 0x1
#define STATUS_READ_IN_PROGRESS 0x2
#define TIMEOUT 20 /* ms */
/*
* operation modes
*/
#define DW_IC_MASTER 0
#define DW_IC_SLAVE 1
/*
* Hardware abort codes from the DW_IC_TX_ABRT_SOURCE register
*
* Only expected abort codes are listed here
* refer to the datasheet for the full list
*/
#define ABRT_7B_ADDR_NOACK 0
#define ABRT_10ADDR1_NOACK 1
#define ABRT_10ADDR2_NOACK 2
#define ABRT_TXDATA_NOACK 3
#define ABRT_GCALL_NOACK 4
#define ABRT_GCALL_READ 5
#define ABRT_SBYTE_ACKDET 7
#define ABRT_SBYTE_NORSTRT 9
#define ABRT_10B_RD_NORSTRT 10
#define ABRT_MASTER_DIS 11
#define ARB_LOST 12
#define ABRT_SLAVE_FLUSH_TXFIFO 13
#define ABRT_SLAVE_ARBLOST 14
#define ABRT_SLAVE_RD_INTX 15
#define DW_IC_TX_ABRT_7B_ADDR_NOACK (1UL << ABRT_7B_ADDR_NOACK)
#define DW_IC_TX_ABRT_10ADDR1_NOACK (1UL << ABRT_10ADDR1_NOACK)
#define DW_IC_TX_ABRT_10ADDR2_NOACK (1UL << ABRT_10ADDR2_NOACK)
#define DW_IC_TX_ABRT_TXDATA_NOACK (1UL << ABRT_TXDATA_NOACK)
#define DW_IC_TX_ABRT_GCALL_NOACK (1UL << ABRT_GCALL_NOACK)
#define DW_IC_TX_ABRT_GCALL_READ (1UL << ABRT_GCALL_READ)
#define DW_IC_TX_ABRT_SBYTE_ACKDET (1UL << ABRT_SBYTE_ACKDET)
#define DW_IC_TX_ABRT_SBYTE_NORSTRT (1UL << ABRT_SBYTE_NORSTRT)
#define DW_IC_TX_ABRT_10B_RD_NORSTRT (1UL << ABRT_10B_RD_NORSTRT)
#define DW_IC_TX_ABRT_MASTER_DIS (1UL << ABRT_MASTER_DIS)
#define DW_IC_TX_ARB_LOST (1UL << ARB_LOST)
#define DW_IC_RX_ABRT_SLAVE_RD_INTX (1UL << ABRT_SLAVE_RD_INTX)
#define DW_IC_RX_ABRT_SLAVE_ARBLOST (1UL << ABRT_SLAVE_ARBLOST)
#define DW_IC_RX_ABRT_SLAVE_FLUSH_TXFIFO (1UL << ABRT_SLAVE_FLUSH_TXFIFO)
#define DW_IC_TX_ABRT_NOACK (DW_IC_TX_ABRT_7B_ADDR_NOACK | \
DW_IC_TX_ABRT_10ADDR1_NOACK | \
DW_IC_TX_ABRT_10ADDR2_NOACK | \
DW_IC_TX_ABRT_TXDATA_NOACK | \
DW_IC_TX_ABRT_GCALL_NOACK)
/**
* struct dw_i2c_dev - private i2c-designware data
* @dev: driver model device node
* @base: IO registers pointer
* @cmd_complete: tx completion indicator
* @clk: input reference clock
* @slave: represent an I2C slave device
* @cmd_err: run time hadware error code
* @msgs: points to an array of messages currently being transferred
* @msgs_num: the number of elements in msgs
* @msg_write_idx: the element index of the current tx message in the msgs
* array
* @tx_buf_len: the length of the current tx buffer
* @tx_buf: the current tx buffer
* @msg_read_idx: the element index of the current rx message in the msgs
* array
* @rx_buf_len: the length of the current rx buffer
* @rx_buf: the current rx buffer
* @msg_err: error status of the current transfer
* @status: i2c master status, one of STATUS_*
* @abort_source: copy of the TX_ABRT_SOURCE register
* @irq: interrupt number for the i2c master
* @adapter: i2c subsystem adapter node
* @slave_cfg: configuration for the slave device
* @tx_fifo_depth: depth of the hardware tx fifo
* @rx_fifo_depth: depth of the hardware rx fifo
* @rx_outstanding: current master-rx elements in tx fifo
* @clk_freq: bus clock frequency
* @ss_hcnt: standard speed HCNT value
* @ss_lcnt: standard speed LCNT value
* @fs_hcnt: fast speed HCNT value
* @fs_lcnt: fast speed LCNT value
* @fp_hcnt: fast plus HCNT value
* @fp_lcnt: fast plus LCNT value
* @hs_hcnt: high speed HCNT value
* @hs_lcnt: high speed LCNT value
* @pm_qos: pm_qos_request used while holding a hardware lock on the bus
* @acquire_lock: function to acquire a hardware lock on the bus
* @release_lock: function to release a hardware lock on the bus
* @disable: function to disable the controller
* @disable_int: function to disable all interrupts
* @init: function to initialize the I2C hardware
* @mode: operation mode - DW_IC_MASTER or DW_IC_SLAVE
*
* HCNT and LCNT parameters can be used if the platform knows more accurate
* values than the one computed based only on the input clock frequency.
* Leave them to be %0 if not used.
*/
struct dw_i2c_dev {
u32 base;
int irq;
QueueHandle_t cmd_complete;
struct i2c_adapter *slave;
u32 (*get_clk_rate_khz) (struct dw_i2c_dev *dev);
int cmd_err;
struct i2c_msg *msgs;
int msgs_num;
int msg_write_idx;
u32 tx_buf_len;
u8 *tx_buf;
int msg_read_idx;
u32 rx_buf_len;
u8 *rx_buf;
int msg_err;
unsigned int status;
u32 abort_source;
u32 flags;
struct i2c_adapter adapter;
u32 functionality;
u32 master_cfg;
u32 slave_cfg;
unsigned int tx_fifo_depth;
unsigned int rx_fifo_depth;
int rx_outstanding;
u32 clk_freq;
u32 sda_hold_time;
u32 sda_falling_time;
u32 scl_falling_time;
u16 ss_hcnt;
u16 ss_lcnt;
u16 fs_hcnt;
u16 fs_lcnt;
u16 fp_hcnt;
u16 fp_lcnt;
u16 hs_hcnt;
u16 hs_lcnt;
int (*acquire_lock)(struct dw_i2c_dev *dev);
void (*release_lock)(struct dw_i2c_dev *dev);
void (*disable)(struct dw_i2c_dev *dev);
void (*disable_int)(struct dw_i2c_dev *dev);
int (*init)(struct dw_i2c_dev *dev);
int mode;
};
#define ACCESS_SWAP 0x00000001
#define ACCESS_16BIT 0x00000002
#define ACCESS_INTR_MASK 0x00000004
#define MODEL_CHERRYTRAIL 0x00000100
int i2c_dw_init(int id);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,40 @@
#ifndef _I2C_GPIO_H
#define _I2C_GPIO_H
#ifdef __cplusplus
extern "C" {
#endif
struct i2c_gpio_platform_data {
int devid;
unsigned int sda_pin;
unsigned int scl_pin;
int udelay;
int timeout;
unsigned int sda_is_open_drain:1;
unsigned int scl_is_open_drain:1;
unsigned int scl_is_output_only:1;
};
struct i2c_algo_bit_data {
void *data; /* private data for lowlevel routines */
void (*setsda) (void *data, int state);
void (*setscl) (void *data, int state);
int (*getsda) (void *data);
int (*getscl) (void *data);
/* local settings */
int udelay; /* half clock cycle time in us,
minimum 2 us for fast-mode I2C,
minimum 5 us for standard-mode I2C and SMBus,
maximum 50 us for SMBus */
int timeout; /* in jiffies */
};
void i2c_gpio_init(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,198 @@
#ifndef _I2C_H
#define _I2C_H
#ifdef __cplusplus
extern "C" {
#endif
struct i2c_adapter;
/**
* struct i2c_msg - an I2C transaction segment beginning with START
* @addr: Slave address, either seven or ten bits. When this is a ten
* bit address, I2C_M_TEN must be set in @flags and the adapter
* must support I2C_FUNC_10BIT_ADDR.
* @flags: I2C_M_RD is handled by all adapters. No other flags may be
* provided unless the adapter exported the relevant I2C_FUNC_*
* flags through i2c_check_functionality().
* @len: Number of data bytes in @buf being read from or written to the
* I2C slave address. For read transactions where I2C_M_RECV_LEN
* is set, the caller guarantees that this buffer can hold up to
* 32 bytes in addition to the initial length byte sent by the
* slave (plus, if used, the SMBus PEC); and this value will be
* incremented by the number of block data bytes received.
* @buf: The buffer into which data is read, or from which it's written.
*
* An i2c_msg is the low level representation of one segment of an I2C
* transaction. It is visible to drivers in the @i2c_transfer() procedure,
* to userspace from i2c-dev, and to I2C adapter drivers through the
* @i2c_adapter.@master_xfer() method.
*
* Except when I2C "protocol mangling" is used, all I2C adapters implement
* the standard rules for I2C transactions. Each transaction begins with a
* START. That is followed by the slave address, and a bit encoding read
* versus write. Then follow all the data bytes, possibly including a byte
* with SMBus PEC. The transfer terminates with a NAK, or when all those
* bytes have been transferred and ACKed. If this is the last message in a
* group, it is followed by a STOP. Otherwise it is followed by the next
* @i2c_msg transaction segment, beginning with a (repeated) START.
*
* Alternatively, when the adapter supports I2C_FUNC_PROTOCOL_MANGLING then
* passing certain @flags may have changed those standard protocol behaviors.
* Those flags are only for use with broken/nonconforming slaves, and with
* adapters which are known to support the specific mangling options they
* need (one or more of IGNORE_NAK, NO_RD_ACK, NOSTART, and REV_DIR_ADDR).
*/
struct i2c_msg {
uint16_t addr; /* slave address */
uint16_t flags;
#define I2C_M_RD 0x0001 /* read data, from slave to master */
/* I2C_M_RD is guaranteed to be 0x0001! */
#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */
#define I2C_M_STOP 0x8000 /* if I2C_FUNC_PROTOCOL_MANGLING */
uint16_t len; /* msg length */
uint8_t *buf; /* pointer to msg data */
};
/* To determine what functionality is present */
#define I2C_FUNC_I2C 0x00000001
#define I2C_FUNC_10BIT_ADDR 0x00000002
#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_IGNORE_NAK etc. */
#define I2C_FUNC_SMBUS_PEC 0x00000008
#define I2C_FUNC_NOSTART 0x00000010 /* I2C_M_NOSTART */
#define I2C_FUNC_SLAVE 0x00000020
#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_QUICK 0x00010000
#define I2C_FUNC_SMBUS_READ_BYTE 0x00020000
#define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000
#define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000
#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000
#define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000
#define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000
#define I2C_FUNC_SMBUS_PROC_CALL 0x00800000
#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000
#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000
#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */
#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */
#define I2C_FUNC_SMBUS_HOST_NOTIFY 0x10000000
#define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \
I2C_FUNC_SMBUS_WRITE_BYTE)
#define I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | \
I2C_FUNC_SMBUS_WRITE_BYTE_DATA)
#define I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | \
I2C_FUNC_SMBUS_WRITE_WORD_DATA)
#define I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | \
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA)
#define I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | \
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)
#define I2C_FUNC_SMBUS_EMUL (I2C_FUNC_SMBUS_QUICK | \
I2C_FUNC_SMBUS_BYTE | \
I2C_FUNC_SMBUS_BYTE_DATA | \
I2C_FUNC_SMBUS_WORD_DATA | \
I2C_FUNC_SMBUS_PROC_CALL | \
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \
I2C_FUNC_SMBUS_I2C_BLOCK | \
I2C_FUNC_SMBUS_PEC)
/*
* Data for SMBus Messages
*/
#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */
union i2c_smbus_data {
uint8_t byte;
uint16_t word;
uint8_t block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */
/* and one more for user-space compatibility */
};
/* i2c_smbus_xfer read or write markers */
#define I2C_SMBUS_READ 1
#define I2C_SMBUS_WRITE 0
/* SMBus transaction types (size parameter in the above functions)
Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */
#define I2C_SMBUS_QUICK 0
#define I2C_SMBUS_BYTE 1
#define I2C_SMBUS_BYTE_DATA 2
#define I2C_SMBUS_WORD_DATA 3
#define I2C_SMBUS_PROC_CALL 4
#define I2C_SMBUS_BLOCK_DATA 5
#define I2C_SMBUS_I2C_BLOCK_BROKEN 6
#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */
#define I2C_SMBUS_I2C_BLOCK_DATA 8
/*flags for the client struct: */
#define I2C_CLIENT_PEC 0x04 /* Use Packet Error Checking */
#define I2C_CLIENT_TEN 0x10 /* we have a ten bit chip address */
/* Must equal I2C_M_TEN below */
#define I2C_CLIENT_SLAVE 0x20 /* we are the slave */
#define I2C_CLIENT_HOST_NOTIFY 0x40 /* We want to use I2C host notify */
#define I2C_CLIENT_WAKE 0x80 /* for board_info; true iff can wake */
#define I2C_CLIENT_SCCB 0x9000 /* Use Omnivision SCCB protocol */
/* Must match I2C_M_STOP|IGNORE_NAK */
enum i2c_slave_event {
I2C_SLAVE_READ_REQUESTED,
I2C_SLAVE_WRITE_REQUESTED,
I2C_SLAVE_READ_PROCESSED,
I2C_SLAVE_WRITE_RECEIVED,
I2C_SLAVE_STOP,
};
typedef int (*i2c_slave_cb_t)(struct i2c_adapter *, enum i2c_slave_event, u8 *);
struct i2c_algorithm {
/* master_xfer should return the number of messages successfully
processed, or a negative value on error */
int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num);
int (*reg_slave)(struct i2c_adapter *adap);
int (*unreg_slave)(struct i2c_adapter *adap);
};
/*
* i2c_adapter is the structure used to identify a physical i2c bus along
* with the access algorithms necessary to access it.
*/
struct i2c_adapter {
const struct i2c_algorithm *algo; /* the algorithm to access the bus */
void *algo_data;
void *dw_dev;
int retries;
int timeout; /* in jiffies */
SemaphoreHandle_t xMutex;
i2c_slave_cb_t slave_cb; /* callback for slave mode */
int open_count;
unsigned short flags; /* div., see below */
unsigned short addr; /* chip address - NOTE: 7bit */
char name[16];
};
static __INLINE int i2c_slave_event(struct i2c_adapter *adap,
enum i2c_slave_event event, u8 *val)
{
return adap->slave_cb(adap, event, val);
}
void i2c_init(void);
int i2c_add_adapter(struct i2c_adapter *adap);
struct i2c_adapter *i2c_open(const char *i2cdev);
void i2c_close(struct i2c_adapter *adap);
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
int i2c_slave_register(struct i2c_adapter *adap, u8 addr, i2c_slave_cb_t slave_cb);
int i2c_slave_unregister(struct i2c_adapter *adap);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,89 @@
/*
* ark_i2s.h
*
*/
#ifndef __I2S_H
#define __I2S_H
/*
* I2S Controller Register and Bit Definitions
*/
#define I2S_SACR0 0x00 /* Global Control Register */
#define I2S_SACR1 0x04 /* Serial Audio I 2 S/MSB-Justified Control Register */
#define I2S_SASR0 0x0C /* Serial Audio I 2 S/MSB-Justified Interface and FIFO Status Register */
#define I2S_SAIMR 0x14 /* Serial Audio Interrupt Mask Register */
#define I2S_SAICR 0x18 /* Serial Audio Interrupt Clear Register */
#define I2S_SADR 0x80 /* Serial Audio Data Register (TX and RX FIFO access Register). */
#define SACR0_RFIFIFIRSTBIT (1 << 26) /* rx fifo first bit */
#define SACR0_TFIFOFIRSTBIT (1 << 25) /* Tx fifo first bit */
#define SACR0_CHANLOCK (1 << 24) /* Channel lock(left first or right first) */
#define SACR0_SCBIT (1 << 23) /* */
#define SACR0_BITS (1 << 22) /* I2S Bit Select(16/32 bits) */
#define SACR0_SYNCINV (1 << 21) /* SYNC Clock Invert */
#define SACR0_RFTH_MASK (0x1F << 16)
#define SACR0_RFTH(x) ((x) << 16) /* Rx FIFO Interrupt or DMA Trigger Threshold */
#define SACR0_TFTH_MASK (0X1F << 8)
#define SACR0_TFTH(x) ((x) << 8) /* Tx FIFO Interrupt or DMA Trigger Threshold */
#define SACR0_STRF (1 << 7) /* DAC output clk edge select */
#define SACR0_RDMAEN (1 << 6) /* RX DMA Enable */
#define SACR0_ENLBF (1 << 5) /* Enable Loopback */
#define SACR0_RST (1 << 4) /* FIFO, i2s Register Reset */
#define SACR0_TDMAEN (1 << 3) /* TX DMA Enable */
#define SACR0_BCKD (1 << 2) /* Bit Clock Direction */
#define SACR0_SYNCD (1 << 1) /* Word Select(sync) Clock Direction */
#define SACR0_ENB (1 << 0) /* Enable I2S Link */
#define SACR1_DRPL (1 << 1) /* Disable Replaying Function */
#define SACR1_DREC (1 << 0) /* Disable Recording Function */
#define SASR0_RFL(x) ((x) << 16) /* Rx FIFO Level */
#define SASR0_TFL(x) ((x) << 8) /* Tx FIFO Level */
#define SASR0_ROR (1 << 6) /* Rx FIFO Overrun */
#define SASR0_TUR (1 << 5) /* Tx FIFO Underrun */
#define SASR0_RFS (1 << 4) /* Rx FIFO Service Request */
#define SASR0_TFS (1 << 3) /* Tx FIFO Service Request */
#define SASR0_BSY (1 << 2) /* I2S Busy */
#define SASR0_RNE (1 << 1) /* Rx FIFO Not Empty */
#define SASR0_TNF (1 << 0) /* Tx FIFO Not Full */
#define SAICR_ROR (1 << 6) /* Clear Rx FIFO Overrun Interrupt */
#define SAICR_TUR (1 << 5) /* Clear Tx FIFO Underrun Interrupt */
#define SAICR_RFS (1 << 4) /* Clear Rx FIFO Service Interrupt */
#define SAICR_TFS (1 << 3) /* Clear Tx FIFO Service Interrupt */
#define SAIMR_ROR (1 << 6) /* Enable Rx FIFO Overrun Condition Interrupt */
#define SAIMR_TUR (1 << 5) /* Enable Tx FIFO Underrun Condition Interrupt */
#define SAIMR_RFS (1 << 4) /* Enable Rx FIFO Service Interrupt */
#define SAIMR_TFS (1 << 3) /* Enable Tx FIFO Service Interrupt */
struct ark_i2s_cfg {
int master;
int rates;
int channels;
int bits;
int lfirst; //0: right channel first; 1:left channel first;
};
struct ark_i2s_data {
unsigned int base;
unsigned int nco_reg;
int id;
int clkid;
int full_duplex;
struct ark_i2s_cfg cfg[2];
struct dma_chan *dma_txch;
struct dma_chan *dma_rxch;
SemaphoreHandle_t mutex;
void *extdata;
};
int ark_i2s_init(struct ark_i2s_data *i2s, int flags);
void ark_i2s_set_volume(struct ark_i2s_data *i2s,int lvol, int rvol);
int ark_i2s_set_rate(struct ark_i2s_data *i2s, int stream, unsigned int rate);
int ark_i2s_set_params(struct ark_i2s_data *i2s, int stream, int rates, int channels, int bits);
int ark_i2s_startup(struct ark_i2s_data *i2s, int stream);
void ark_i2s_stop(struct ark_i2s_data *i2s, int stream);
#endif

View File

@ -0,0 +1,31 @@
#ifndef _ITU_H
#define _ITU_H
typedef enum {
ITU_Y_UV = 0,
ITU_YUYV,
} ITU_YUV_TYPE;
typedef enum {
ITU_YUV420 = 0,
ITU_YUV422,
} ITU_OUT_FMT;
typedef struct {
int in_width;
int in_height;
int out_x;
int out_y;
int out_width;
int out_height;
int out_format;
int yuv_type;
int itu601;
} ItuConfigPara;
int itu_init(void);
int itu_config(ItuConfigPara *para);
void itu_start(void);
void itu_stop(void);
#endif

View File

@ -0,0 +1,84 @@
/*
* ark_lcd.h
*
*/
#ifndef _LCD_H
#define _LCD_H
typedef enum {
LCD_OSD0 = 0,
LCD_OSD1,
LCD_OSD_NUMS,
}LCD_OSD_LAYER;
typedef enum {
LCD_OSD_FORAMT_YUV420 = 0,
LCD_OSD_FORAMT_ARGB888,
LCD_OSD_FORAMT_RGB565,
LCD_OSD_FORAMT_RGB454,
LCD_OSD_FORAMT_NUMS,
}LCD_OSD_FORMAT;
typedef enum {
LCD_OSD_Y_U_V420 = 0,
LCD_OSD_Y_UV420,
}LCD_OSD_YUV420_MODE;
typedef struct {
int x;
int y;
int width;
int height;
int format;
unsigned int yaddr;
unsigned int uaddr;
unsigned int vaddr;
} LcdOsdInfo;
#define LCD_VIDEO_LAYER LCD_OSD0
#define LCD_UI_LAYER LCD_OSD1
/* osd layer set func */
/************************************************************/
int ark_lcd_set_osd_size(LCD_OSD_LAYER osd, uint32_t width, uint32_t height);
int ark_lcd_set_osd_format(LCD_OSD_LAYER osd, LCD_OSD_FORMAT format);
int ark_lcd_set_osd_yaddr(LCD_OSD_LAYER osd, uint32_t yaddr);
int ark_lcd_set_osd_uaddr(LCD_OSD_LAYER osd, uint32_t yaddr);
int ark_lcd_set_osd_vaddr(LCD_OSD_LAYER osd, uint32_t yaddr);
int ark_lcd_osd_enable(LCD_OSD_LAYER osd, uint8_t enable);
int ark_lcd_get_osd_enable(LCD_OSD_LAYER osd);
/* Interface with default argument value, may be you need them. If you not sure, ingore them */
int ark_lcd_set_osd_possition(LCD_OSD_LAYER osd, uint32_t h, uint32_t v);
int ark_lcd_set_osd_h_offset(LCD_OSD_LAYER osd, uint32_t offset);
int ark_lcd_osd_coeff_enable(LCD_OSD_LAYER osd, uint8_t enable);
int ark_lcd_osd_set_coeff(LCD_OSD_LAYER osd, uint32_t value);
int ark_lcd_set_osd_mult_coef(LCD_OSD_LAYER osd, uint32_t value);
int ark_lcd_set_osd_yuv420_mode(LCD_OSD_LAYER osd, LCD_OSD_YUV420_MODE mode);
int ark_lcd_get_osd_yuv420_mode(LCD_OSD_LAYER osd, LCD_OSD_YUV420_MODE *mode);
/* after calling the osd layer set func, you should call */
/* this function to flush the parameters for atom option */
int ark_lcd_set_osd_sync(LCD_OSD_LAYER osd);
/************************************************************/
int ark_lcd_get_osd_size(LCD_OSD_LAYER osd, uint32_t *width, uint32_t *height);
int ark_lcd_get_osd_format(LCD_OSD_LAYER osd, LCD_OSD_FORMAT *format);
int ark_lcd_get_osd_yaddr(LCD_OSD_LAYER osd, uint32_t *yaddr);
uint32_t ark_lcd_get_virt_addr(void);
uint8_t *ark_lcd_get_fb_addr(uint8_t index);
int ark_lcd_enable(uint8_t enable);
int ark_lcd_wait_for_vsync(void);
int ark_lcd_set_osd_info_atomic(LCD_OSD_LAYER osd, LcdOsdInfo *info);
int ark_lcd_get_osd_info_atomic_isactive(LCD_OSD_LAYER osd);
int lcd_init(void);
void lcd_uninit(void);
void Cpulcd_Init(void);
#endif

View File

@ -0,0 +1,182 @@
#ifndef _MMC_H
#define _MMC_H
#include "FreeRTOS.h"
#include "mmcsd_host.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* EXT_CSD fields
*/
#define EXT_CSD_FLUSH_CACHE 32 /* W */
#define EXT_CSD_CACHE_CTRL 33 /* R/W */
#define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */
#define EXT_CSD_PACKED_FAILURE_INDEX 35 /* RO */
#define EXT_CSD_PACKED_CMD_STATUS 36 /* RO */
#define EXT_CSD_EXP_EVENTS_STATUS 54 /* RO, 2 bytes */
#define EXT_CSD_EXP_EVENTS_CTRL 56 /* R/W, 2 bytes */
#define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */
#define EXT_CSD_GP_SIZE_MULT 143 /* R/W */
#define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */
#define EXT_CSD_PARTITION_SUPPORT 160 /* RO */
#define EXT_CSD_HPI_MGMT 161 /* R/W */
#define EXT_CSD_RST_N_FUNCTION 162 /* R/W */
#define EXT_CSD_BKOPS_EN 163 /* R/W */
#define EXT_CSD_BKOPS_START 164 /* W */
#define EXT_CSD_SANITIZE_START 165 /* W */
#define EXT_CSD_WR_REL_PARAM 166 /* RO */
#define EXT_CSD_RPMB_MULT 168 /* RO */
#define EXT_CSD_BOOT_WP 173 /* R/W */
#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */
#define EXT_CSD_PART_CONFIG 179 /* R/W */
#define EXT_CSD_ERASED_MEM_CONT 181 /* RO */
#define EXT_CSD_BUS_WIDTH 183 /* R/W */
#define EXT_CSD_HS_TIMING 185 /* R/W */
#define EXT_CSD_POWER_CLASS 187 /* R/W */
#define EXT_CSD_REV 192 /* RO */
#define EXT_CSD_STRUCTURE 194 /* RO */
#define EXT_CSD_CARD_TYPE 196 /* RO */
#define EXT_CSD_OUT_OF_INTERRUPT_TIME 198 /* RO */
#define EXT_CSD_PART_SWITCH_TIME 199 /* RO */
#define EXT_CSD_PWR_CL_52_195 200 /* RO */
#define EXT_CSD_PWR_CL_26_195 201 /* RO */
#define EXT_CSD_PWR_CL_52_360 202 /* RO */
#define EXT_CSD_PWR_CL_26_360 203 /* RO */
#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
#define EXT_CSD_S_A_TIMEOUT 217 /* RO */
#define EXT_CSD_REL_WR_SEC_C 222 /* RO */
#define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */
#define EXT_CSD_ERASE_TIMEOUT_MULT 223 /* RO */
#define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */
#define EXT_CSD_BOOT_MULT 226 /* RO */
#define EXT_CSD_SEC_TRIM_MULT 229 /* RO */
#define EXT_CSD_SEC_ERASE_MULT 230 /* RO */
#define EXT_CSD_SEC_FEATURE_SUPPORT 231 /* RO */
#define EXT_CSD_TRIM_MULT 232 /* RO */
#define EXT_CSD_PWR_CL_200_195 236 /* RO */
#define EXT_CSD_PWR_CL_200_360 237 /* RO */
#define EXT_CSD_PWR_CL_DDR_52_195 238 /* RO */
#define EXT_CSD_PWR_CL_DDR_52_360 239 /* RO */
#define EXT_CSD_BKOPS_STATUS 246 /* RO */
#define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */
#define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */
#define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */
#define EXT_CSD_PWR_CL_DDR_200_360 253 /* RO */
#define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */
#define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */
#define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */
#define EXT_CSD_MAX_PACKED_READS 501 /* RO */
#define EXT_CSD_BKOPS_SUPPORT 502 /* RO */
#define EXT_CSD_HPI_FEATURES 503 /* RO */
/*
* EXT_CSD field definitions
*/
#define EXT_CSD_WR_REL_PARAM_EN (1<<2)
#define EXT_CSD_BOOT_WP_B_PWR_WP_DIS (0x40)
#define EXT_CSD_BOOT_WP_B_PERM_WP_DIS (0x10)
#define EXT_CSD_BOOT_WP_B_PERM_WP_EN (0x04)
#define EXT_CSD_BOOT_WP_B_PWR_WP_EN (0x01)
#define EXT_CSD_PART_CONFIG_ACC_MASK (0x7)
#define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1)
#define EXT_CSD_PART_CONFIG_ACC_RPMB (0x3)
#define EXT_CSD_PART_CONFIG_ACC_GP0 (0x4)
#define EXT_CSD_PART_SUPPORT_PART_EN (0x1)
#define EXT_CSD_CMD_SET_NORMAL (1<<0)
#define EXT_CSD_CMD_SET_SECURE (1<<1)
#define EXT_CSD_CMD_SET_CPSECURE (1<<2)
#define EXT_CSD_CARD_TYPE_HS_26 (1<<0) /* Card can run at 26MHz */
#define EXT_CSD_CARD_TYPE_HS_52 (1<<1) /* Card can run at 52MHz */
#define EXT_CSD_CARD_TYPE_HS (EXT_CSD_CARD_TYPE_HS_26 | \
EXT_CSD_CARD_TYPE_HS_52)
#define EXT_CSD_CARD_TYPE_DDR_1_8V (1<<2) /* Card can run at 52MHz */
/* DDR mode @1.8V or 3V I/O */
#define EXT_CSD_CARD_TYPE_DDR_1_2V (1<<3) /* Card can run at 52MHz */
/* DDR mode @1.2V I/O */
#define EXT_CSD_CARD_TYPE_DDR_52 (EXT_CSD_CARD_TYPE_DDR_1_8V \
| EXT_CSD_CARD_TYPE_DDR_1_2V)
#define EXT_CSD_CARD_TYPE_HS200_1_8V (1<<4) /* Card can run at 200MHz */
#define EXT_CSD_CARD_TYPE_HS200_1_2V (1<<5) /* Card can run at 200MHz */
/* SDR mode @1.2V I/O */
#define EXT_CSD_CARD_TYPE_HS200 (EXT_CSD_CARD_TYPE_HS200_1_8V | \
EXT_CSD_CARD_TYPE_HS200_1_2V)
#define EXT_CSD_CARD_TYPE_HS400_1_8V (1<<6) /* Card can run at 200MHz DDR, 1.8V */
#define EXT_CSD_CARD_TYPE_HS400_1_2V (1<<7) /* Card can run at 200MHz DDR, 1.2V */
#define EXT_CSD_CARD_TYPE_HS400 (EXT_CSD_CARD_TYPE_HS400_1_8V | \
EXT_CSD_CARD_TYPE_HS400_1_2V)
#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */
#define EXT_CSD_DDR_BUS_WIDTH_4 5 /* Card is in 4 bit DDR mode */
#define EXT_CSD_DDR_BUS_WIDTH_8 6 /* Card is in 8 bit DDR mode */
#define EXT_CSD_TIMING_BC 0 /* Backwards compatility */
#define EXT_CSD_TIMING_HS 1 /* High speed */
#define EXT_CSD_TIMING_HS200 2 /* HS200 */
#define EXT_CSD_TIMING_HS400 3 /* HS400 */
#define EXT_CSD_SEC_ER_EN BIT(0)
#define EXT_CSD_SEC_BD_BLK_EN BIT(2)
#define EXT_CSD_SEC_GB_CL_EN BIT(4)
#define EXT_CSD_SEC_SANITIZE BIT(6) /* v4.5 only */
#define EXT_CSD_RST_N_EN_MASK 0x3
#define EXT_CSD_RST_N_ENABLED 1 /* RST_n is enabled on card */
#define EXT_CSD_NO_POWER_NOTIFICATION 0
#define EXT_CSD_POWER_ON 1
#define EXT_CSD_POWER_OFF_SHORT 2
#define EXT_CSD_POWER_OFF_LONG 3
#define EXT_CSD_PWR_CL_8BIT_MASK 0xF0 /* 8 bit PWR CLS */
#define EXT_CSD_PWR_CL_4BIT_MASK 0x0F /* 8 bit PWR CLS */
#define EXT_CSD_PWR_CL_8BIT_SHIFT 4
#define EXT_CSD_PWR_CL_4BIT_SHIFT 0
#define EXT_CSD_PACKED_EVENT_EN BIT(3)
/*
* EXCEPTION_EVENT_STATUS field
*/
#define EXT_CSD_URGENT_BKOPS BIT(0)
#define EXT_CSD_DYNCAP_NEEDED BIT(1)
#define EXT_CSD_SYSPOOL_EXHAUSTED BIT(2)
#define EXT_CSD_PACKED_FAILURE BIT(3)
#define EXT_CSD_PACKED_GENERIC_ERROR BIT(0)
#define EXT_CSD_PACKED_INDEXED_ERROR BIT(1)
/*
* BKOPS status level
*/
#define EXT_CSD_BKOPS_LEVEL_2 0x2
/*
* MMC_SWITCH access modes
*/
#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */
#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits which are 1 in value */
#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */
#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */
/*
* extern function
*/
int mmc_send_op_cond(struct mmcsd_host *host, uint32_t ocr, uint32_t *rocr);
int32_t init_mmc(struct mmcsd_host *host, uint32_t ocr);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,186 @@
#ifndef _MMCSD_CARD_H
#define _MMCSD_CARD_H
#include "mmcsd_host.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SD_SCR_BUS_WIDTH_1 (1 << 0)
#define SD_SCR_BUS_WIDTH_4 (1 << 2)
struct mmcsd_cid {
uint8_t mid; /* ManufacturerID */
uint8_t prv; /* Product Revision */
uint16_t oid; /* OEM/Application ID */
uint32_t psn; /* Product Serial Number */
uint8_t pnm[5]; /* Product Name */
uint8_t reserved1;/* reserved */
uint16_t mdt; /* Manufacturing Date */
uint8_t crc; /* CID CRC */
uint8_t reserved2;/* not used, always 1 */
};
struct mmcsd_csd {
uint8_t csd_structure; /* CSD register version */
uint8_t taac;
uint8_t nsac;
uint8_t tran_speed; /* max data transfer rate */
uint16_t card_cmd_class; /* card command classes */
uint8_t rd_blk_len; /* max read data block length */
uint8_t rd_blk_part;
uint8_t wr_blk_misalign;
uint8_t rd_blk_misalign;
uint8_t dsr_imp; /* DSR implemented */
uint8_t c_size_mult; /* CSD 1.0 , device size multiplier */
uint32_t c_size; /* device size */
uint8_t r2w_factor;
uint8_t wr_blk_len; /* max wtire data block length */
uint8_t wr_blk_partial;
uint8_t csd_crc;
};
struct sd_scr {
uint8_t sd_version;
uint8_t sd_bus_widths;
};
struct sdio_cccr {
uint8_t sdio_version;
uint8_t sd_version;
uint8_t direct_cmd:1, /* Card Supports Direct Commands during data transfer
only SD mode, not used for SPI mode */
multi_block:1, /* Card Supports Multi-Block */
read_wait:1, /* Card Supports Read Wait
only SD mode, not used for SPI mode */
suspend_resume:1, /* Card supports Suspend/Resume
only SD mode, not used for SPI mode */
s4mi:1, /* generate interrupts during a 4-bit
multi-block data transfer */
e4mi:1, /* Enable the multi-block IRQ during
4-bit transfer for the SDIO card */
low_speed:1, /* Card is a Low-Speed card */
low_speed_4:1; /* 4-bit support for Low-Speed cards */
uint8_t bus_width:1, /* Support SDIO bus width, 1:4bit, 0:1bit */
cd_disable:1, /* Connect[0]/Disconnect[1] the 10K-90K ohm pull-up
resistor on CD/DAT[3] (pin 1) of the card */
power_ctrl:1, /* Support Master Power Control */
high_speed:1; /* Support High-Speed */
};
struct sdio_cis {
uint16_t manufacturer;
uint16_t product;
uint16_t func0_blk_size;
uint32_t max_tran_speed;
};
/*
* SDIO function CIS tuple (unknown to the core)
*/
struct sdio_function_tuple {
struct sdio_function_tuple *next;
uint8_t code;
uint8_t size;
uint8_t *data;
};
#define sdio_function sdio_func
struct sdio_function;
typedef void (sdio_irq_handler_t)(struct sdio_function *);
#if 0
/*
* SDIO function devices
*/
struct sdio_function {
struct mmcsd_card *card; /* the card this device belongs to */
sdio_irq_handler_t *irq_handler; /* IRQ callback */
uint8_t num; /* function number */
uint8_t func_code; /* Standard SDIO Function interface code */
uint16_t manufacturer; /* manufacturer id */
uint16_t product; /* product id */
uint32_t max_blk_size; /* maximum block size */
uint32_t cur_blk_size; /* current block size */
uint32_t enable_timeout_val; /* max enable timeout in msec */
struct sdio_function_tuple *tuples;
void *priv;
};
#endif
/*
* SDIO function devices
*/
struct sdio_func {
struct mmcsd_card *card; /* the card this device belongs to */
sdio_irq_handler_t *irq_handler; /* IRQ callback */
uint8_t num; /* function number */
uint8_t func_code; /* Standard SDIO Function interface code */
uint16_t manufacturer; /* manufacturer id */
uint16_t product; /* product id */
uint32_t max_blk_size; /* maximum block size */
uint32_t cur_blk_size; /* current block size */
uint32_t enable_timeout_val; /* max enable timeout in msec */
struct sdio_function_tuple *tuples;
void *priv;
};
#define SDIO_MAX_FUNCTIONS 7
struct mmcsd_card {
struct mmcsd_host *host;
uint32_t rca; /* card addr */
uint32_t resp_cid[4]; /* card CID register */
uint32_t resp_csd[4]; /* card CSD register */
uint32_t resp_scr[2]; /* card SCR register */
uint16_t tacc_clks; /* data access time by ns */
uint32_t tacc_ns; /* data access time by clk cycles */
uint32_t max_data_rate; /* max data transfer rate */
uint32_t card_capacity; /* card capacity, unit:KB */
uint32_t card_blksize; /* card block size */
uint32_t card_blknr; /* card block number */
uint32_t erase_size; /* erase size in sectors */
uint16_t card_type;
#define CARD_TYPE_MMC 0 /* MMC card */
#define CARD_TYPE_SD 1 /* SD card */
#define CARD_TYPE_SDIO 2 /* SDIO card */
#define CARD_TYPE_SDIO_COMBO 3 /* SD combo (IO+mem) card */
uint16_t flags;
#define CARD_FLAG_HIGHSPEED (1 << 0) /* SDIO bus speed 50MHz */
#define CARD_FLAG_SDHC (1 << 1) /* SDHC card */
#define CARD_FLAG_SDXC (1 << 2) /* SDXC card */
struct sd_scr scr;
struct mmcsd_csd csd;
uint32_t hs_max_data_rate; /* max data transfer rate in high speed mode */
uint8_t sdio_function_num; /* totol number of SDIO functions */
struct sdio_cccr cccr; /* common card info */
struct sdio_cis cis; /* common tuple info */
struct sdio_function *sdio_function[SDIO_MAX_FUNCTIONS + 1]; /* SDIO functions (devices) */
};
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,119 @@
#ifndef _MMSCD_CMD_H
#define _MMSCD_CMD_H
#ifdef __cplusplus
extern "C" {
#endif
/* class 1 */
#define GO_IDLE_STATE 0 /* bc */
#define SEND_OP_COND 1 /* bcr [31:0] OCR R3 */
#define ALL_SEND_CID 2 /* bcr R2 */
#define SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */
#define SET_DSR 4 /* bc [31:16] RCA */
#define SWITCH 6 /* ac [31:0] See below R1b */
#define SELECT_CARD 7 /* ac [31:16] RCA R1 */
#define SEND_EXT_CSD 8 /* adtc R1 */
#define SEND_CSD 9 /* ac [31:16] RCA R2 */
#define SEND_CID 10 /* ac [31:16] RCA R2 */
#define READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */
#define STOP_TRANSMISSION 12 /* ac R1b */
#define SEND_STATUS 13 /* ac [31:16] RCA R1 */
#define GO_INACTIVE_STATE 15 /* ac [31:16] RCA */
#define SPI_READ_OCR 58 /* spi spi_R3 */
#define SPI_CRC_ON_OFF 59 /* spi [0:0] flag spi_R1 */
/* class 2 */
#define SET_BLOCKLEN 16 /* ac [31:0] block len R1 */
#define READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */
#define READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */
/* class 3 */
#define WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */
/* class 4 */
#define SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */
#define WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */
#define WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */
#define PROGRAM_CID 26 /* adtc R1 */
#define PROGRAM_CSD 27 /* adtc R1 */
/* class 6 */
#define SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */
#define CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */
#define SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */
/* class 5 */
#define ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */
#define ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */
#define ERASE 38 /* ac R1b */
/* class 9 */
#define FAST_IO 39 /* ac <Complex> R4 */
#define GO_IRQ_STATE 40 /* bcr R5 */
/* class 7 */
#define LOCK_UNLOCK 42 /* adtc R1b */
/* class 8 */
#define APP_CMD 55 /* ac [31:16] RCA R1 */
#define GEN_CMD 56 /* adtc [0] RD/WR R1 */
/* SD commands type argument response */
/* class 0 */
/* This is basically the same command as for MMC with some quirks. */
#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */
#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */
/* class 10 */
#define SD_SWITCH 6 /* adtc [31:0] See below R1 */
/* Application commands */
#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */
#define SD_APP_SEND_NUM_WR_BLKS 22 /* adtc R1 */
#define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */
#define SD_APP_SEND_SCR 51 /* adtc R1 */
#define SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */
#define SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */
#define SCR_SPEC_VER_2 2 /* Implements system specification 2.00 */
/* SDIO commands type argument response */
#define SD_IO_SEND_OP_COND 5 /* bcr [23:0] OCR R4 */
#define SD_IO_RW_DIRECT 52 /* ac [31:0] See below R5 */
#define SD_IO_RW_EXTENDED 53 /* adtc [31:0] See below R5 */
/* CMD52 arguments */
#define SDIO_ARG_CMD52_READ (0<<31)
#define SDIO_ARG_CMD52_WRITE (1u<<31)
#define SDIO_ARG_CMD52_FUNC_SHIFT 28
#define SDIO_ARG_CMD52_FUNC_MASK 0x7
#define SDIO_ARG_CMD52_RAW_FLAG (1u<<27)
#define SDIO_ARG_CMD52_REG_SHIFT 9
#define SDIO_ARG_CMD52_REG_MASK 0x1ffff
#define SDIO_ARG_CMD52_DATA_SHIFT 0
#define SDIO_ARG_CMD52_DATA_MASK 0xff
#define SDIO_R5_DATA(resp) ((resp)[0] & 0xff)
/* CMD53 arguments */
#define SDIO_ARG_CMD53_READ (0<<31)
#define SDIO_ARG_CMD53_WRITE (1u<<31)
#define SDIO_ARG_CMD53_FUNC_SHIFT 28
#define SDIO_ARG_CMD53_FUNC_MASK 0x7
#define SDIO_ARG_CMD53_BLOCK_MODE (1u<<27)
#define SDIO_ARG_CMD53_INCREMENT (1u<<26)
#define SDIO_ARG_CMD53_REG_SHIFT 9
#define SDIO_ARG_CMD53_REG_MASK 0x1ffff
#define SDIO_ARG_CMD53_LENGTH_SHIFT 0
#define SDIO_ARG_CMD53_LENGTH_MASK 0x1ff
#define SDIO_ARG_CMD53_LENGTH_MAX 511
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,202 @@
#ifndef _MMCSD_CORE_H
#define _MMCSD_CORE_H
#include "FreeRTOS.h"
#include "mmcsd_host.h"
#include "mmcsd_card.h"
#include "mmcsd_cmd.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef MMCSD_DBG
#define mmcsd_dbg(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define mmcsd_dbg(fmt, ...)
#endif
struct mmcsd_data {
uint32_t blksize;
uint32_t blks;
uint32_t *buf;
int32_t err;
uint32_t flags;
#define DATA_DIR_WRITE (1 << 0)
#define DATA_DIR_READ (1 << 1)
#define DATA_STREAM (1 << 2)
unsigned int bytes_xfered;
struct mmcsd_cmd *stop; /* stop command */
struct mmcsd_req *mrq; /* associated request */
uint32_t timeout_ns;
uint32_t timeout_clks;
};
struct mmcsd_cmd {
uint32_t cmd_code;
uint32_t arg;
uint32_t resp[4];
uint32_t flags;
/*rsponse types
*bits:0~3
*/
#define RESP_MASK (0xF)
#define RESP_NONE (0)
#define RESP_R1 (1 << 0)
#define RESP_R1B (2 << 0)
#define RESP_R2 (3 << 0)
#define RESP_R3 (4 << 0)
#define RESP_R4 (5 << 0)
#define RESP_R6 (6 << 0)
#define RESP_R7 (7 << 0)
#define RESP_R5 (8 << 0) /*SDIO command response type*/
/*command types
*bits:4~5
*/
#define CMD_MASK (3 << 4) /* command type */
#define CMD_AC (0 << 4)
#define CMD_ADTC (1 << 4)
#define CMD_BC (2 << 4)
#define CMD_BCR (3 << 4)
#define resp_type(cmd) ((cmd)->flags & RESP_MASK)
/*spi rsponse types
*bits:6~8
*/
#define RESP_SPI_MASK (0x7 << 6)
#define RESP_SPI_R1 (1 << 6)
#define RESP_SPI_R1B (2 << 6)
#define RESP_SPI_R2 (3 << 6)
#define RESP_SPI_R3 (4 << 6)
#define RESP_SPI_R4 (5 << 6)
#define RESP_SPI_R5 (6 << 6)
#define RESP_SPI_R7 (7 << 6)
#define spi_resp_type(cmd) ((cmd)->flags & RESP_SPI_MASK)
/*
* These are the command types.
*/
#define cmd_type(cmd) ((cmd)->flags & CMD_MASK)
int32_t retries; /* max number of retries */
int32_t err;
struct mmcsd_data *data;
struct mmcsd_req *mrq; /* associated request */
};
struct mmcsd_req {
struct mmcsd_data *data;
struct mmcsd_cmd *cmd;
struct mmcsd_cmd *stop;
};
/*the following is response bit*/
#define R1_OUT_OF_RANGE (1 << 31) /* er, c */
#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */
#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */
#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */
#define R1_ERASE_PARAM (1 << 27) /* ex, c */
#define R1_WP_VIOLATION (1 << 26) /* erx, c */
#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */
#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */
#define R1_COM_CRC_ERROR (1 << 23) /* er, b */
#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */
#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */
#define R1_CC_ERROR (1 << 20) /* erx, c */
#define R1_ERROR (1 << 19) /* erx, c */
#define R1_UNDERRUN (1 << 18) /* ex, c */
#define R1_OVERRUN (1 << 17) /* ex, c */
#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */
#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */
#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */
#define R1_ERASE_RESET (1 << 13) /* sr, c */
#define R1_STATUS(x) (x & 0xFFFFE000)
#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */
#define R1_READY_FOR_DATA (1 << 8) /* sx, a */
#define R1_APP_CMD (1 << 5) /* sr, c */
#define R1_SPI_IDLE (1 << 0)
#define R1_SPI_ERASE_RESET (1 << 1)
#define R1_SPI_ILLEGAL_COMMAND (1 << 2)
#define R1_SPI_COM_CRC (1 << 3)
#define R1_SPI_ERASE_SEQ (1 << 4)
#define R1_SPI_ADDRESS (1 << 5)
#define R1_SPI_PARAMETER (1 << 6)
/* R1 bit 7 is always zero */
#define R2_SPI_CARD_LOCKED (1 << 8)
#define R2_SPI_WP_ERASE_SKIP (1 << 9) /* or lock/unlock fail */
#define R2_SPI_LOCK_UNLOCK_FAIL R2_SPI_WP_ERASE_SKIP
#define R2_SPI_ERROR (1 << 10)
#define R2_SPI_CC_ERROR (1 << 11)
#define R2_SPI_CARD_ECC_ERROR (1 << 12)
#define R2_SPI_WP_VIOLATION (1 << 13)
#define R2_SPI_ERASE_PARAM (1 << 14)
#define R2_SPI_OUT_OF_RANGE (1 << 15) /* or CSD overwrite */
#define R2_SPI_CSD_OVERWRITE R2_SPI_OUT_OF_RANGE
#define CARD_BUSY 0x80000000 /* Card Power up status bit */
/* R5 response bits */
#define R5_COM_CRC_ERROR (1 << 15)
#define R5_ILLEGAL_COMMAND (1 << 14)
#define R5_ERROR (1 << 11)
#define R5_FUNCTION_NUMBER (1 << 9)
#define R5_OUT_OF_RANGE (1 << 8)
#define R5_STATUS(x) (x & 0xCB00)
#define R5_IO_CURRENT_STATE(x) ((x & 0x3000) >> 12)
#define MMCSD_HOST_PLUGED 0
#define MMCSD_HOST_UNPLUGED 1
int mmcsd_wait_cd_changed(uint32_t timeout);
int mmcsd_wait_sdio_ready(int32_t timeout);
void mmcsd_host_lock(struct mmcsd_host *host);
void mmcsd_host_unlock(struct mmcsd_host *host);
void mmcsd_req_complete(struct mmcsd_host *host);
void mmcsd_send_request(struct mmcsd_host *host, struct mmcsd_req *req);
int32_t mmcsd_send_cmd(struct mmcsd_host *host, struct mmcsd_cmd *cmd, int retries);
int32_t mmcsd_go_idle(struct mmcsd_host *host);
int32_t mmcsd_spi_read_ocr(struct mmcsd_host *host, int32_t high_capacity, uint32_t *ocr);
int32_t mmcsd_all_get_cid(struct mmcsd_host *host, uint32_t *cid);
int32_t mmcsd_get_cid(struct mmcsd_host *host, uint32_t *cid);
int32_t mmcsd_get_csd(struct mmcsd_card *card, uint32_t *csd);
int32_t mmcsd_select_card(struct mmcsd_card *card);
int32_t mmcsd_deselect_cards(struct mmcsd_card *host);
int32_t mmcsd_spi_use_crc(struct mmcsd_host *host, int32_t use_crc);
void mmcsd_set_chip_select(struct mmcsd_host *host, int32_t mode);
void mmcsd_set_clock(struct mmcsd_host *host, uint32_t clk);
void mmcsd_set_bus_mode(struct mmcsd_host *host, uint32_t mode);
void mmcsd_set_bus_width(struct mmcsd_host *host, uint32_t width);
void mmcsd_set_data_timeout(struct mmcsd_data *data, const struct mmcsd_card *card);
uint32_t mmcsd_select_voltage(struct mmcsd_host *host, uint32_t ocr);
void mmcsd_change(struct mmcsd_host *host);
void mmcsd_change_from_isr(struct mmcsd_host *host);
void mmcsd_detect(void *param);
struct mmcsd_host *mmcsd_alloc_host(void);
void mmcsd_free_host(struct mmcsd_host *host);
int mmcsd_core_init(void);
int mmcsd_blk_init(void);
int32_t mmcsd_num_wr_blocks(struct mmcsd_card *card);
int mmcsd_req_blk(struct mmcsd_card *card, uint32_t sector, void *buf, size_t blks, uint8_t dir);
int32_t mmcsd_set_blksize(struct mmcsd_card *card);
struct mmcsd_card *mmcsd_get_sdmmc_card_info(void);
int mmcsd_wait_mmc_ready(uint32_t timeout);
#if DEVICE_TYPE_SELECT == EMMC_FLASH
int emmc_read(uint32_t offset, size_t size, uint8_t *data);
int emmc_write(uint32_t offset, size_t size, uint8_t *data);
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,119 @@
#ifndef _MMCSD_HOST_H
#define _MMCSD_HOST_H
#include "FreeRTOS.h"
#include "semphr.h"
#include "task.h"
#ifdef __cplusplus
extern "C" {
#endif
struct mmcsd_io_cfg {
uint32_t clock; /* clock rate */
uint16_t vdd;
/* vdd stores the bit number of the selected voltage range from below. */
uint8_t bus_mode; /* command output mode */
#define MMCSD_BUSMODE_OPENDRAIN 1
#define MMCSD_BUSMODE_PUSHPULL 2
uint8_t chip_select; /* SPI chip select */
#define MMCSD_CS_IGNORE 0
#define MMCSD_CS_HIGH 1
#define MMCSD_CS_LOW 2
uint8_t power_mode; /* power supply mode */
#define MMCSD_POWER_OFF 0
#define MMCSD_POWER_UP 1
#define MMCSD_POWER_ON 2
uint8_t bus_width; /* data bus width */
#define MMCSD_BUS_WIDTH_1 0
#define MMCSD_BUS_WIDTH_4 2
#define MMCSD_BUS_WIDTH_8 3
};
struct mmcsd_host;
struct mmcsd_req;
struct mmcsd_host_ops {
void (*request)(struct mmcsd_host *host, struct mmcsd_req *req);
void (*set_iocfg)(struct mmcsd_host *host, struct mmcsd_io_cfg *io_cfg);
int32_t (*get_card_status)(struct mmcsd_host *host);
void (*enable_sdio_irq)(struct mmcsd_host *host, int32_t en);
};
struct mmcsd_host {
struct mmcsd_card *card;
const struct mmcsd_host_ops *ops;
uint32_t freq_min;
uint32_t freq_max;
struct mmcsd_io_cfg io_cfg;
uint32_t valid_ocr; /* current valid OCR */
#define VDD_165_195 (1 << 7) /* VDD voltage 1.65 - 1.95 */
#define VDD_20_21 (1 << 8) /* VDD voltage 2.0 ~ 2.1 */
#define VDD_21_22 (1 << 9) /* VDD voltage 2.1 ~ 2.2 */
#define VDD_22_23 (1 << 10) /* VDD voltage 2.2 ~ 2.3 */
#define VDD_23_24 (1 << 11) /* VDD voltage 2.3 ~ 2.4 */
#define VDD_24_25 (1 << 12) /* VDD voltage 2.4 ~ 2.5 */
#define VDD_25_26 (1 << 13) /* VDD voltage 2.5 ~ 2.6 */
#define VDD_26_27 (1 << 14) /* VDD voltage 2.6 ~ 2.7 */
#define VDD_27_28 (1 << 15) /* VDD voltage 2.7 ~ 2.8 */
#define VDD_28_29 (1 << 16) /* VDD voltage 2.8 ~ 2.9 */
#define VDD_29_30 (1 << 17) /* VDD voltage 2.9 ~ 3.0 */
#define VDD_30_31 (1 << 18) /* VDD voltage 3.0 ~ 3.1 */
#define VDD_31_32 (1 << 19) /* VDD voltage 3.1 ~ 3.2 */
#define VDD_32_33 (1 << 20) /* VDD voltage 3.2 ~ 3.3 */
#define VDD_33_34 (1 << 21) /* VDD voltage 3.3 ~ 3.4 */
#define VDD_34_35 (1 << 22) /* VDD voltage 3.4 ~ 3.5 */
#define VDD_35_36 (1 << 23) /* VDD voltage 3.5 ~ 3.6 */
uint32_t flags; /* define device capabilities */
#define MMCSD_BUSWIDTH_4 (1 << 0)
#define MMCSD_BUSWIDTH_8 (1 << 1)
#define MMCSD_MUTBLKWRITE (1 << 2)
#define MMCSD_HOST_IS_SPI (1 << 3)
#define controller_is_spi(host) (host->flags & MMCSD_HOST_IS_SPI)
#define MMCSD_SUP_SDIO_IRQ (1 << 4) /* support signal pending SDIO IRQs */
#define MMCSD_SUP_HIGHSPEED (1 << 5) /* support high speed */
uint32_t max_seg_size; /* maximum size of one dma segment */
uint32_t max_dma_segs; /* maximum number of dma segments in one request */
uint32_t max_blk_size; /* maximum block size */
uint32_t max_blk_count; /* maximum block count */
uint32_t spi_use_crc;
SemaphoreHandle_t bus_lock;
SemaphoreHandle_t sem_ack;
uint32_t sdio_irq_num;
SemaphoreHandle_t sdio_irq_sem;
TaskHandle_t sdio_irq_thread;
uint8_t transfer_err;
void *private_data;
};
static inline void mmcsd_delay_ms(uint32_t ms)
{
if (ms < 1000 / configTICK_RATE_HZ)
{
vTaskDelay(1);
}
else
{
vTaskDelay(ms/(1000 / configTICK_RATE_HZ));
}
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,54 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2012, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
#ifndef _MMU_
#define _MMU_
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "../cp15/cp15.h"
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
extern void MMU_Initialize(unsigned int *pTB);
extern void dma_flush_range(unsigned int ulStart, unsigned int ulEnd);
extern void dma_inv_range (unsigned int ulStart, unsigned int ulEnd);
extern void dma_clean_range(unsigned int ulStart, unsigned int ulEnd);
#define PHY_TO_VIRT(x) ((x))
#define VIRT_TO_PHY(x) ((x))
#define PHY_TO_UNCACHED_VIRT(x) ((unsigned int)(x) + 0x10000000UL)
#define UNCACHED_VIRT_TO_PHT(x) ((unsigned int)(x) - 0x10000000UL)
#endif /* #ifndef _MMU_ */

View File

@ -0,0 +1,65 @@
#ifndef _PINCTRL_H
#define _PINCTRL_H
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
PGRP_I2C0,
PGRP_I2C1,
PGRP_LCD_TTL_CH0,
PGRP_LCD_TTL_CH1,
PGRP_LCD_LVDS,
PGRP_LCD_SRGB,
PGRP_LCD_ITU601,
PGRP_UART0,
PGRP_UART1,
PGRP_UART2,
PGRP_UART3,
PGRP_SPI0,
PGRP_SPI1,
PGRP_PWM0,
PGRP_PWM1,
PGRP_PWM2,
PGRP_PWM3,
PGRP_PWM0_IN,
PGRP_PWM1_IN,
PGRP_PWM2_IN,
PGRP_PWM3_IN,
PGRP_SDMMC0,
PGRP_ITU_CH0,
PGRP_ITU_CH0_INV,
PGRP_ITU_CH1,
PGRP_ITU_CH1_INV,
PGRP_CAN0_CH0,
PGRP_CAN0_CH1,
PGRP_CAN0_CH2,
PGRP_CAN1_CH0,
PGRP_CAN1_CH1,
PGRP_CAN1_CH2,
PGRP_I2S0_PLAY,
PGRP_I2S0_RECORD,
PGRP_I2S1_PLAY,
PGRP_I2S1_RECORD,
PGRP_RCRT,
}ePingroupID;
typedef enum {
PAD_DRIVE_DEFAULT,
PAD_DRIVE_2MA,
PAD_DRIVE_4MA,
PAD_DRIVE_8MA,
PAD_DRIVE_12MA,
}ePadDrive;
void vPinctrlSetup(void);
void pinctrl_gpio_request(int gpio);
void pinctrl_set_group(int groupid);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,16 @@
#ifndef _PWM_H
#define _PWM_H
typedef enum {
PWM_ID0 = 0,
PWM_ID1,
PWM_ID2,
PWM_ID3
} PWM_ID;
int pwm_config(int id, uint32_t duty_ns, uint32_t period_ns);
void pwm_enable(int id);
void pwm_disable(int id);
//240719 lj
void pwn_update_brightness(uint32_t duty_ns);
#endif

View File

@ -0,0 +1,52 @@
#ifndef PWM_CAP_H_
#define PWM_CAP_H_
void pwm_Initial_Cap(UINT8 id);
double pwm_getCapVal(UINT8 id);
void pwm_enableCapIRQ(UINT8 id,UINT8 en);
double pwm_getCapVal(UINT8 id);
void pwm_cap_Int_Handler(void *para);
extern double capdata[125];
#define PWM_CAP_TIMES 1
#define PWM_CAP_INTERVAL 1//64
#define PWM_CAP_GLITCH 0x7//0xF
#define PWM_CAP_ENABLE 1
typedef enum{
PWM_CAP_CH0 = 0,
PWM_CAP_CH1,
PWM_CAP_CH2,
PWM_CAP_CH3,
}PWM_CAP_CH;
typedef enum{
PWM_CAP_NUM = 0,
PWM_CAP_EXIT,
}PWM_CAP_METHOD;
typedef enum{
PWM_CAP_UINT_1MS = 0,
PWM_CAP_UINT_10MS,
PWM_CAP_UINT_100MS,
PWM_CAP_UINT_1000MS = 4,
}PWM_CAP_BASED_UINT;
typedef enum{
PWM_CAP_NO_INT = 0,
PWM_CAP_ONCE_INT,
PWM_CAP_ONCE_FINISH_INT,
PWM_CAP_FINISH_ALL,
}PWM_CAP_INT_METHOD;
#endif

View File

@ -0,0 +1,53 @@
#ifndef _PXP_H
#define _PXP_H
typedef enum {
PXP_SRC_FMT_ARGB8888 = 0x0, /* 32-bit pixels */
PXP_SRC_FMT_RGB888 = 0x1, /* 32-bit pixels (unpacked 24-bit format) */
PXP_SRC_FMT_RGB565 = 0x4, /* 16-bit pixels */
PXP_SRC_FMT_RGB555 = 0x5, /* 16-bit pixels */
PXP_SRC_FMT_YUV422 = 0x8, /* 16-bit pixels */
PXP_SRC_FMT_YUV420 = 0x9, /* 16-bit pixels */
PXP_SRC_FMT_UYVY1P422 = 0xa, /* 16-bit pixels (1-plane U0,Y0,V0,Y1 interleaved bytes) */
PXP_SRC_FMT_VYUY1P422 = 0xb, /* 16-bit pixels (1-plane V0,Y0,U0,Y1 interleaved bytes) */
PXP_SRC_FMT_YUV2P422 = 0xc, /* 16-bit pixels (2-plane UV interleaved bytes) */
PXP_SRC_FMT_YUV2P420 = 0xd, /* 16-bit pixels */
PXP_SRC_FMT_YVU2P422 = 0xe, /* 16-bit pixels (2-plane VU interleaved bytes) */
PXP_SRC_FMT_YVU2P420 = 0xf, /* 16-bit pixels */
} PXP_SRC_FMT;
typedef enum {
PXP_OUT_FMT_ARGB8888 = 0x0, /* 32-bit pixels */
PXP_OUT_FMT_RGB888 = 0x1, /* 32-bit pixels (unpacked 24-bit pixel in 32 bit DWORD.) */
PXP_OUT_FMT_RGB888P = 0x2, /* 24-bit pixels (packed 24-bit format) */
PXP_OUT_FMT_ARGB1555 = 0x3, /* 16-bit pixels */
PXP_OUT_FMT_RGB565 = 0x4, /* 16-bit pixels */
PXP_OUT_FMT_RGB555 = 0x5, /* 16-bit pixels */
PXP_OUT_FMT_YUV444 = 0x7, /* 32-bit pixels (1-plane XYUV unpacked) */
PXP_OUT_FMT_UYVY1P422 = 0xa, /* 16-bit pixels (1-plane U0,Y0,V0,Y1 interleaved bytes) */
PXP_OUT_FMT_VYUY1P422 = 0xb, /* 16-bit pixels (1-plane V0,Y0,U0,Y1 interleaved bytes) */
PXP_OUT_FMT_YUV2P422 = 0xc, /* 16-bit pixels (2-plane UV interleaved bytes) */
PXP_OUT_FMT_YUV2P420 = 0xd, /* 16-bit pixels (2-plane VU) */
PXP_OUT_FMT_YVU2P422 = 0xe, /* 16-bit pixels (2-plane VU interleaved bytes) */
PXP_OUT_FMT_YVU2P420 = 0xf, /* 16-bit pixels (2-plane VU) */
} PXP_OUT_FMT;
/* clockwise rotate */
typedef enum {
PXP_ROTATE_0 = 0,
PXP_ROTATE_90 = 1,
PXP_ROTATE_180 = 2,
PXP_ROTATE_270 = 3,
} PXP_ROTATE;
int pxp_init(void);
int pxp_scaler_rotate(uint32_t s0buf, uint32_t s0ubuf, uint32_t s0vbuf,
int s0format, uint32_t s0width, uint32_t s0height,
uint32_t outbuf, uint32_t outbuf2, int outformat,
uint32_t outwidth, uint32_t outheight, int outangle);
int pxp_rotate(uint32_t s0buf, uint32_t s0ubuf, uint32_t s0vbuf,
int s0format, uint32_t s0width, uint32_t s0height,
uint32_t outbuf, uint32_t outbuf2, int outformat,
int outangle);
#endif

View File

@ -0,0 +1,5 @@
#ifndef _REMOTE_H
#define _REMOTE_H
void RemoteKeyInit(void);
#endif

View File

@ -0,0 +1,50 @@
#ifndef _RTC_H
#define _RTC_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* The struct used to pass data via the following ioctl. Similar to the
* struct tm in <time.h>, but it needs to be here so that the kernel
* source is self contained, allowing cross-compiles, etc. etc.
*/
typedef struct rtc_time {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
} SystemTime_t;
/*
* This data structure is inspired by the EFI (v0.92) wakeup
* alarm API.
*/
struct rtc_wkalrm {
unsigned char enabled; /* 0 = alarm disabled, 1 = alarm enabled */
unsigned char pending; /* 0 = alarm not pending, 1 = alarm pending */
struct rtc_time time; /* time the alarm is set to */
};
static inline int is_leap_year(unsigned int year)
{
return (!(year % 4) && (year % 100)) || !(year % 400);
}
int rtc_init(void);
int iGetLocalTime(SystemTime_t *tm);
void vSetLocalTime(SystemTime_t *tm);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,23 @@
#ifndef _SD_H
#define _SD_H
#include "FreeRTOS.h"
#include "mmcsd_host.h"
#ifdef __cplusplus
extern "C" {
#endif
int mmcsd_send_if_cond(struct mmcsd_host *host, uint32_t ocr);
int mmcsd_send_app_op_cond(struct mmcsd_host *host, uint32_t ocr, uint32_t *rocr);
int mmcsd_get_card_addr(struct mmcsd_host *host, uint32_t *rca);
int32_t mmcsd_get_scr(struct mmcsd_card *card, uint32_t *scr);
int32_t init_sd(struct mmcsd_host *host, uint32_t ocr);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,222 @@
#ifndef _SDIO_H
#define _SDIO_H
#include "FreeRTOS.h"
#include "mmcsd_host.h"
#include "mmcsd_card.h"
#include "sdio_func_ids.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* Card Common Control Registers (CCCR)
*/
#define SDIO_REG_CCCR_CCCR_REV 0x00
#define SDIO_CCCR_REV_1_00 0 /* CCCR/FBR Version 1.00 */
#define SDIO_CCCR_REV_1_10 1 /* CCCR/FBR Version 1.10 */
#define SDIO_CCCR_REV_1_20 2 /* CCCR/FBR Version 1.20 */
#define SDIO_CCCR_REV_3_00 3 /* CCCR/FBR Version 2.00 */
#define SDIO_SDIO_REV_1_00 0 /* SDIO Spec Version 1.00 */
#define SDIO_SDIO_REV_1_10 1 /* SDIO Spec Version 1.10 */
#define SDIO_SDIO_REV_1_20 2 /* SDIO Spec Version 1.20 */
#define SDIO_SDIO_REV_2_00 3 /* SDIO Spec Version 2.00 */
#define SDIO_REG_CCCR_SD_REV 0x01
#define SDIO_SD_REV_1_01 0 /* SD Physical Spec Version 1.01 */
#define SDIO_SD_REV_1_10 1 /* SD Physical Spec Version 1.10 */
#define SDIO_SD_REV_2_00 2 /* SD Physical Spec Version 2.00 */
#define SDIO_REG_CCCR_IO_EN 0x02
#define SDIO_REG_CCCR_IO_RDY 0x03
#define SDIO_REG_CCCR_INT_EN 0x04 /* Function/Master Interrupt Enable */
#define SDIO_REG_CCCR_INT_PEND 0x05 /* Function Interrupt Pending */
#define SDIO_REG_CCCR_IO_ABORT 0x06 /* function abort/card reset */
#define SDIO_REG_CCCR_BUS_IF 0x07 /* bus interface controls */
#define SDIO_BUS_WIDTH_1BIT 0x00
#define SDIO_BUS_WIDTH_4BIT 0x02
#define SDIO_BUS_ECSI 0x20 /* Enable continuous SPI interrupt */
#define SDIO_BUS_SCSI 0x40 /* Support continuous SPI interrupt */
#define SDIO_BUS_ASYNC_INT 0x20
#define SDIO_BUS_CD_DISABLE 0x80 /* disable pull-up on DAT3 (pin 1) */
#define SDIO_REG_CCCR_CARD_CAPS 0x08
#define SDIO_CCCR_CAP_SDC 0x01 /* can do CMD52 while data transfer */
#define SDIO_CCCR_CAP_SMB 0x02 /* can do multi-block xfers (CMD53) */
#define SDIO_CCCR_CAP_SRW 0x04 /* supports read-wait protocol */
#define SDIO_CCCR_CAP_SBS 0x08 /* supports suspend/resume */
#define SDIO_CCCR_CAP_S4MI 0x10 /* interrupt during 4-bit CMD53 */
#define SDIO_CCCR_CAP_E4MI 0x20 /* enable ints during 4-bit CMD53 */
#define SDIO_CCCR_CAP_LSC 0x40 /* low speed card */
#define SDIO_CCCR_CAP_4BLS 0x80 /* 4 bit low speed card */
#define SDIO_REG_CCCR_CIS_PTR 0x09 /* common CIS pointer (3 bytes) */
/* Following 4 regs are valid only if SBS is set */
#define SDIO_REG_CCCR_BUS_SUSPEND 0x0c
#define SDIO_REG_CCCR_FUNC_SEL 0x0d
#define SDIO_REG_CCCR_EXEC_FLAG 0x0e
#define SDIO_REG_CCCR_READY_FLAG 0x0f
#define SDIO_REG_CCCR_FN0_BLKSIZE 0x10 /* 2bytes, 0x10~0x11 */
#define SDIO_REG_CCCR_POWER_CTRL 0x12
#define SDIO_POWER_SMPC 0x01 /* Supports Master Power Control */
#define SDIO_POWER_EMPC 0x02 /* Enable Master Power Control */
#define SDIO_REG_CCCR_SPEED 0x13
#define SDIO_SPEED_SHS 0x01 /* Supports High-Speed mode */
#define SDIO_SPEED_EHS 0x02 /* Enable High-Speed mode */
/*
* Function Basic Registers (FBR)
*/
#define SDIO_REG_FBR_BASE(f) ((f) * 0x100) /* base of function f's FBRs */
#define SDIO_REG_FBR_STD_FUNC_IF 0x00
#define SDIO_FBR_SUPPORTS_CSA 0x40 /* supports Code Storage Area */
#define SDIO_FBR_ENABLE_CSA 0x80 /* enable Code Storage Area */
#define SDIO_REG_FBR_STD_IF_EXT 0x01
#define SDIO_REG_FBR_POWER 0x02
#define SDIO_FBR_POWER_SPS 0x01 /* Supports Power Selection */
#define SDIO_FBR_POWER_EPS 0x02 /* Enable (low) Power Selection */
#define SDIO_REG_FBR_CIS 0x09 /* CIS pointer (3 bytes) */
#define SDIO_REG_FBR_CSA 0x0C /* CSA pointer (3 bytes) */
#define SDIO_REG_FBR_CSA_DATA 0x0F
#define SDIO_REG_FBR_BLKSIZE 0x10 /* block size (2 bytes) */
/* SDIO CIS Tuple code */
#define CISTPL_NULL 0x00
#define CISTPL_CHECKSUM 0x10
#define CISTPL_VERS_1 0x15
#define CISTPL_ALTSTR 0x16
#define CISTPL_MANFID 0x20
#define CISTPL_FUNCID 0x21
#define CISTPL_FUNCE 0x22
#define CISTPL_SDIO_STD 0x91
#define CISTPL_SDIO_EXT 0x92
#define CISTPL_END 0xff
/* SDIO device id */
#define SDIO_ANY_FUNC_ID 0xff
#define SDIO_ANY_MAN_ID 0xffff
#define SDIO_ANY_PROD_ID 0xffff
struct sdio_device_id
{
uint8_t func_code;
uint16_t manufacturer;
uint16_t product;
};
struct sdio_driver_t
{
char *name;
int32_t (*probe)(struct mmcsd_card *card);
int32_t (*remove)(struct mmcsd_card *card);
struct sdio_device_id *id;
};
int32_t sdio_io_send_op_cond(struct mmcsd_host *host,
uint32_t ocr,
uint32_t *cmd5_resp);
int32_t sdio_io_rw_direct(struct mmcsd_card *card,
int32_t rw,
uint32_t fn,
uint32_t reg_addr,
uint8_t *pdata,
uint8_t raw);
int32_t sdio_io_rw_extended(struct mmcsd_card *card,
int32_t rw,
uint32_t fn,
uint32_t addr,
int32_t op_code,
uint8_t *buf,
uint32_t blocks,
uint32_t blksize);
int32_t sdio_io_rw_extended_block(struct sdio_function *func,
int32_t rw,
uint32_t addr,
int32_t op_code,
uint8_t *buf,
uint32_t len);
uint8_t sdio_io_readb(struct sdio_function *func,
uint32_t reg,
int32_t *err);
int32_t sdio_io_writeb(struct sdio_function *func,
uint32_t reg,
uint8_t data);
uint16_t sdio_io_readw(struct sdio_function *func,
uint32_t addr,
int32_t *err);
int32_t sdio_io_writew(struct sdio_function *func,
uint16_t data,
uint32_t addr);
uint32_t sdio_io_readl(struct sdio_function *func,
uint32_t addr,
int32_t *err);
int32_t sdio_io_writel(struct sdio_function *func,
uint32_t data,
uint32_t addr);
int32_t sdio_io_read_multi_fifo_b(struct sdio_function *func,
uint32_t addr,
uint8_t *buf,
uint32_t len);
int32_t sdio_io_write_multi_fifo_b(struct sdio_function *func,
uint32_t addr,
uint8_t *buf,
uint32_t len);
int32_t sdio_io_read_multi_incr_b(struct sdio_function *func,
uint32_t addr,
uint8_t *buf,
uint32_t len);
int32_t sdio_io_write_multi_incr_b(struct sdio_function *func,
uint32_t addr,
uint8_t *buf,
uint32_t len);
int32_t init_sdio(struct mmcsd_host *host, uint32_t ocr);
int32_t sdio_attach_irq(struct sdio_function *func,
sdio_irq_handler_t *handler);
int32_t sdio_detach_irq(struct sdio_function *func);
void sdio_irq_wakeup(struct mmcsd_host *host);
void sdio_irq_wakeup_isr(struct mmcsd_host *host);
int32_t sdio_enable_func(struct sdio_function *func);
int32_t sdio_disable_func(struct sdio_function *func);
void sdio_set_drvdata(struct sdio_function *func, void *data);
void* sdio_get_drvdata(struct sdio_function *func);
int32_t sdio_set_block_size(struct sdio_function *func,
uint32_t blksize);
int32_t sdio_register_driver(struct sdio_driver_t *driver);
int32_t sdio_unregister_driver(struct sdio_driver_t *driver);
void sdio_init(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,29 @@
#ifndef _SDIO_FUNC_IDS_H
#define _SDIO_FUNC_IDS_H
#ifdef __cplusplus
extern "C" {
#endif
/* Standard SDIO Function Interfaces */
#define SDIO_FUNC_CODE_NONE 0x00 /* Not a SDIO standard interface */
#define SDIO_FUNC_CODE_UART 0x01 /* SDIO Standard UART */
#define SDIO_FUNC_CODE_BT_A 0x02 /* SDIO Type-A for Bluetooth standard interface */
#define SDIO_FUNC_CODE_BT_B 0x03 /* SDIO Type-B for Bluetooth standard interface */
#define SDIO_FUNC_CODE_GPS 0x04 /* SDIO GPS standard interface */
#define SDIO_FUNC_CODE_CAMERA 0x05 /* SDIO Camera standard interface */
#define SDIO_FUNC_CODE_PHS 0x06 /* SDIO PHS standard interface */
#define SDIO_FUNC_CODE_WLAN 0x07 /* SDIO WLAN interface */
#define SDIO_FUNC_CODE_ATA 0x08 /* Embedded SDIO-ATA standard interface */
/* manufacturer id, product io */
#define SDIO_MANUFACTURER_ID_MARVELL 0x02df
#define SDIO_PRODUCT_ID_MARVELL_88W8686 0x9103
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,231 @@
#ifndef _SDMMC_H
#define _SDMMC_H
#define MMC_FEQ_MIN 400000
#define MMC_FEQ_MAX 25000000
#define CARD_UNPLUGED 1
#define CARD_PLUGED 0
enum {
TRANS_MODE_PIO = 0,
TRANS_MODE_IDMAC,
TRANS_MODE_EDMAC
};
struct dw_mci_dma_slave {
struct dma_chan *ch;
enum dma_transfer_direction direction;
};
#define SDMMC_CTRL 0x000
#define SDMMC_PWREN 0x004
#define SDMMC_CLKDIV 0x008
#define SDMMC_CLKSRC 0x00c
#define SDMMC_CLKENA 0x010
#define SDMMC_TMOUT 0x014
#define SDMMC_CTYPE 0x018
#define SDMMC_BLKSIZ 0x01c
#define SDMMC_BYTCNT 0x020
#define SDMMC_INTMASK 0x024
#define SDMMC_CMDARG 0x028
#define SDMMC_CMD 0x02c
#define SDMMC_RESP0 0x030
#define SDMMC_RESP1 0x034
#define SDMMC_RESP2 0x038
#define SDMMC_RESP3 0x03c
#define SDMMC_MINTSTS 0x040
#define SDMMC_RINTSTS 0x044
#define SDMMC_STATUS 0x048
#define SDMMC_FIFOTH 0x04c
#define SDMMC_CDETECT 0x050
#define SDMMC_WRTPRT 0x054
#define SDMMC_GPIO 0x058
#define SDMMC_TCBCNT 0x05c
#define SDMMC_TBBCNT 0x060
#define SDMMC_DEBNCE 0x064
#define SDMMC_USRID 0x068
#define SDMMC_VERID 0x06c
#define SDMMC_HCON 0x070
#define SDMMC_UHS_REG 0x074
#define SDMMC_RST_N 0x078
#define SDMMC_BMOD 0x080
#define SDMMC_PLDMND 0x084
#define SDMMC_DBADDR 0x088
#define SDMMC_IDSTS 0x08c
#define SDMMC_IDINTEN 0x090
#define SDMMC_DSCADDR 0x094
#define SDMMC_BUFADDR 0x098
#define SDMMC_FIFO 0x100
#define SDMMC_DATA(x) (x)
#define SDMMC_FIFO_DEPTH 32
/* Control register defines */
#define SDMMC_CTRL_USE_IDMAC BIT(25)
#define SDMMC_CTRL_CEATA_INT_EN BIT(11)
#define SDMMC_CTRL_SEND_AS_CCSD BIT(10)
#define SDMMC_CTRL_SEND_CCSD BIT(9)
#define SDMMC_CTRL_ABRT_READ_DATA BIT(8)
#define SDMMC_CTRL_SEND_IRQ_RESP BIT(7)
#define SDMMC_CTRL_READ_WAIT BIT(6)
#define SDMMC_CTRL_DMA_ENABLE BIT(5)
#define SDMMC_CTRL_INT_ENABLE BIT(4)
#define SDMMC_CTRL_DMA_RESET BIT(2)
#define SDMMC_CTRL_FIFO_RESET BIT(1)
#define SDMMC_CTRL_RESET BIT(0)
/* Clock Enable register defines */
#define SDMMC_CLKEN_LOW_PWR BIT(16)
#define SDMMC_CLKEN_ENABLE BIT(0)
/* time-out register defines */
#define SDMMC_TMOUT_DATA(n) _SBF(8, (n))
#define SDMMC_TMOUT_DATA_MSK 0xFFFFFF00
#define SDMMC_TMOUT_RESP(n) ((n) & 0xFF)
#define SDMMC_TMOUT_RESP_MSK 0xFF
/* card-type register defines */
#define SDMMC_CTYPE_8BIT BIT(16)
#define SDMMC_CTYPE_4BIT BIT(0)
#define SDMMC_CTYPE_1BIT 0
/* Interrupt status & mask register defines */
#define SDMMC_INT_SDIO BIT(16)
#define SDMMC_INT_EBE BIT(15)
#define SDMMC_INT_ACD BIT(14)
#define SDMMC_INT_SBE BIT(13)
#define SDMMC_INT_HLE BIT(12)
#define SDMMC_INT_FRUN BIT(11)
#define SDMMC_INT_HTO BIT(10)
#define SDMMC_INT_VOLT_SWITCH BIT(10) /* overloads bit 10! */
#define SDMMC_INT_DRTO BIT(9)
#define SDMMC_INT_RTO BIT(8)
#define SDMMC_INT_DCRC BIT(7)
#define SDMMC_INT_RCRC BIT(6)
#define SDMMC_INT_RXDR BIT(5)
#define SDMMC_INT_TXDR BIT(4)
#define SDMMC_INT_DATA_OVER BIT(3)
#define SDMMC_INT_CMD_DONE BIT(2)
#define SDMMC_INT_RESP_ERR BIT(1)
#define SDMMC_INT_CD BIT(0)
#define SDMMC_INT_ALL (~0)
#define SDMMC_INT_DATA_ERROR (SDMMC_INT_DCRC | SDMMC_INT_SBE | SDMMC_INT_EBE)
#define SDMMC_INT_STATUS_DATA (SDMMC_INT_DATA_OVER | SDMMC_INT_DATA_ERROR \
| SDMMC_INT_TXDR | SDMMC_INT_RXDR)
/* Common flag combinations */
#define SDMMC_DATA_ERROR_FLAGS (SDMMC_INT_DRTO | SDMMC_INT_DCRC | \
SDMMC_INT_HTO | SDMMC_INT_SBE | \
SDMMC_INT_EBE | SDMMC_INT_HLE)
#define SDMMC_CMD_ERROR_FLAGS (SDMMC_INT_RTO | SDMMC_INT_RCRC | \
SDMMC_INT_RESP_ERR | SDMMC_INT_HLE)
#define SDMMC_ERROR_FLAGS (SDMMC_DATA_ERROR_FLAGS | \
SDMMC_CMD_ERROR_FLAGS)
#define SDMMC_INT_ERROR 0xbfc2
/* Command register defines */
#define SDMMC_CMD_START BIT(31)
#define SDMMC_CMD_USE_HOLD_REG BIT(29)
#define SDMMC_CMD_VOLT_SWITCH BIT(28)
#define SDMMC_CMD_CCS_EXP BIT(23)
#define SDMMC_CMD_CEATA_RD BIT(22)
#define SDMMC_CMD_UPD_CLK BIT(21)
#define SDMMC_CMD_INIT BIT(15)
#define SDMMC_CMD_STOP BIT(14)
#define SDMMC_CMD_PRV_DAT_WAIT BIT(13)
#define SDMMC_CMD_SEND_STOP BIT(12)
#define SDMMC_CMD_STRM_MODE BIT(11)
#define SDMMC_CMD_DAT_WR BIT(10)
#define SDMMC_CMD_DAT_EXP BIT(9)
#define SDMMC_CMD_RESP_CRC BIT(8)
#define SDMMC_CMD_RESP_LONG BIT(7)
#define SDMMC_CMD_RESP_EXP BIT(6)
#define SDMMC_CMD_INDX(n) ((n) & 0x1F)
/* Status register defines */
#define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF)
#define SDMMC_STATUS_DMA_REQ BIT(31)
#define SDMMC_STATUS_BUSY BIT(9)
/* FIFOTH register defines */
#define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \
((r) & 0xFFF) << 16 | \
((t) & 0xFFF))
/* HCON register defines */
#define DMA_INTERFACE_IDMA (0x0)
#define DMA_INTERFACE_DWDMA (0x1)
#define DMA_INTERFACE_GDMA (0x2)
#define DMA_INTERFACE_NODMA (0x3)
#define SDMMC_GET_TRANS_MODE(x) (((x)>>16) & 0x3)
#define SDMMC_GET_SLOT_NUM(x) ((((x)>>1) & 0x1F) + 1)
#define SDMMC_GET_HDATA_WIDTH(x) (((x)>>7) & 0x7)
#define SDMMC_GET_ADDR_CONFIG(x) (((x)>>27) & 0x1)
/* Internal DMAC interrupt defines */
#define SDMMC_IDMAC_INT_AI BIT(9)
#define SDMMC_IDMAC_INT_NI BIT(8)
#define SDMMC_IDMAC_INT_CES BIT(5)
#define SDMMC_IDMAC_INT_DU BIT(4)
#define SDMMC_IDMAC_INT_FBE BIT(2)
#define SDMMC_IDMAC_INT_RI BIT(1)
#define SDMMC_IDMAC_INT_TI BIT(0)
/* Internal DMAC bus mode bits */
#define SDMMC_IDMAC_ENABLE BIT(7)
#define SDMMC_IDMAC_FB BIT(1)
#define SDMMC_IDMAC_SWRESET BIT(0)
/* H/W reset */
#define SDMMC_RST_HWACTIVE 0x1
/* Version ID register define */
#define SDMMC_GET_VERID(x) ((x) & 0xFFFF)
/* Card read threshold */
#define SDMMC_SET_THLD(v, x) (((v) & 0xFFF) << 16 | (x))
#define SDMMC_CARD_WR_THR_EN BIT(2)
#define SDMMC_CARD_RD_THR_EN BIT(0)
/* UHS-1 register defines */
#define SDMMC_UHS_18V BIT(0)
/* All ctrl reset bits */
#define SDMMC_CTRL_ALL_RESET_FLAGS \
(SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET)
struct mmc_driver
{
uint32_t max_desc;
struct mmcsd_host *host;
struct mmcsd_req *req;
struct mmcsd_data *data;
struct mmcsd_cmd *cmd;
void* priv;
};
struct ark_mmc_obj;
/* DMA ops for Internal/External DMAC interface */
struct dw_mci_dma_ops {
/* DMA Ops */
int (*init)(struct ark_mmc_obj *mmc_obj);
int (*start)(struct ark_mmc_obj *mmc_obj, struct mmcsd_data *data);
void (*stop)(struct ark_mmc_obj *mmc_obj);
void (*cleanup)(struct ark_mmc_obj *mmc_obj);
void (*exit)(struct ark_mmc_obj *mmc_obj);
};
struct ark_mmc_obj
{
uint32_t id;
uint32_t irq;
uint32_t base;
uint32_t power_pin_gpio;
uint32_t fifoth_val;
uint32_t prev_blksz;
int result;
int use_dma;
int using_dma;
int dma_args[3];
struct dw_mci_dma_ops *dma_ops;
struct dw_mci_dma_slave *dms;
struct mmcsd_data *data;
QueueHandle_t transfer_completion;
char *tx_dummy_buffer;
char *rx_dummy_buffer;
int dummy_buffer_used;
void (*mmc_reset)(struct ark_mmc_obj *);
};
#endif /* _SDMMC_H */

View File

@ -0,0 +1,51 @@
#ifndef USER_DATA_H
#define USER_DATA_H
#include "tkc/types_def.h"
/*
typedef struct pressure_t{
char mac_address[6]; //物理地址
uint8_t state; //状态 0未匹配/未学习 1已配对/已学习
uint8_t unit; //单位
uint8_t temp; //温度
uint8_t voltage; //电压
uint8_t blow_by_state; //漏气状态
uint8_t voltage_state; //低电压状态
uint8_t temp_state; //温度状态
uint16_t psi; //压强
}pressure_t;*/
typedef struct sfuddata_t{
uint8_t factory_reset; //出厂设置
uint8_t language; //语言
uint8_t display_unit; //单位
uint8_t theme; //当前主题
uint8_t theme_state; //主题状态
uint8_t light_value; //亮度
uint8_t bt_on_off; //蓝牙
uint8_t trip_uint; //trip_uint单位
uint8_t grade; //档位
uint16_t gas; //油量
uint32_t total_mileage; //里程数
char f_mac_address[9]; //物理地址
char r_mac_address[9]; //物理地址
uint32_t maintenance_mileage; //保养里程数max
uint32_t mileage_flag; //设置时当前的总里程数
}SfudData_t;
typedef struct sfudmiledata_t{
uint32_t TRIP_mileage;//小计里程
uint32_t TOTAL_mileage;//总计里程
}SfudMileData_t;
void SaveDataToFlash(SfudData_t user_data);
void ReadDataToFlash(void);
SfudData_t* userData_getSfudSaved(void);
//extern daily_data_t custom_data;
void read_mileage(uint32_t trip_data,uint32_t total_data);
void SaveMileageData(uint32_t trip_data,uint32_t total_data);
void ReadMileageData(void);
#endif /*USER_DATA_H*/

View File

@ -0,0 +1,123 @@
#ifndef _SPI_H
#define _SPI_H
#include "FreeRTOS.h"
#include "semphr.h"
#ifdef __cplusplus
extern "C" {
#endif
/* SPI mode flags */
#define SPI_CPHA BIT(0) /* clock phase */
#define SPI_CPOL BIT(1) /* clock polarity */
#define SPI_MODE_0 (0|0) /* (original MicroWire) */
#define SPI_MODE_1 (0|SPI_CPHA)
#define SPI_MODE_2 (SPI_CPOL|0)
#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
#define SPI_CS_HIGH BIT(2) /* CS active high */
#define SPI_LSB_FIRST BIT(3) /* per-word bits-on-wire */
#define SPI_3WIRE BIT(4) /* SI/SO signals shared */
#define SPI_LOOP BIT(5) /* loopback mode */
#define SPI_SLAVE BIT(6) /* slave mode */
#define SPI_PREAMBLE BIT(7) /* Skip preamble bytes */
#define SPI_TX_BYTE BIT(8) /* transmit with 1 wire byte */
#define SPI_TX_DUAL BIT(9) /* transmit with 2 wires */
#define SPI_TX_QUAD BIT(10) /* transmit with 4 wires */
#define SPI_RX_SLOW BIT(11) /* receive with 1 wire slow */
#define SPI_RX_DUAL BIT(12) /* receive with 2 wires */
#define SPI_RX_QUAD BIT(13) /* receive with 4 wires */
#define SPI_READY BIT(14) /* Slave pulls low to pause */
#define SPI_NO_CS BIT(15) /* No chipselect */
#define SPI_DEFAULT_WORDLEN 8
/**
* SPI message structure
*/
struct spi_message
{
const void *send_buf;
void *recv_buf;
size_t length;
struct spi_message *next;
unsigned cs_take : 1;
unsigned cs_release : 1;
};
struct qspi_message
{
struct spi_message message;
/* instruction stage */
struct
{
uint8_t content;
uint8_t qspi_lines;
} instruction;
/* address and alternate_bytes stage */
struct
{
uint32_t content;
uint8_t size;
uint8_t qspi_lines;
} address, alternate_bytes;
/* dummy_cycles stage */
uint32_t dummy_cycles;
/* number of lines in qspi data stage, the other configuration items are in parent */
uint8_t qspi_data_lines;
};
/**
* SPI configuration structure
*/
struct spi_configuration
{
uint32_t mode;
uint32_t data_width;
uint32_t max_hz;
uint32_t qspi_max_hz;
uint32_t reserved;
};
/**
* struct spi_slave - Representation of a SPI slave
*/
struct spi_slave {
unsigned int bus;
unsigned int cs;
unsigned int mode;
unsigned int wordlen;
int (*xfer)(struct spi_slave *slave, struct spi_message *message);
int (*qspi_read)(struct spi_slave *slave, struct qspi_message *qspi_message);
int (*configure)(struct spi_slave *slave, struct spi_configuration *configuration);
SemaphoreHandle_t xMutex;
SemaphoreHandle_t xSfudMutex;
int open_count;
char name[16];
};
int ecspi_init(void);
int dwspi_init(void);
void spi_init(void);
int spi_add_slave(struct spi_slave *slave);
struct spi_slave *spi_open(const char *spidev);
void spi_close(struct spi_slave *slave);
int spi_send_then_recv(struct spi_slave *slave, const void *send_buf,
size_t send_length, void *recv_buf,
size_t recv_length);
int spi_transfer(struct spi_slave *slave, const void *send_buf,
void *recv_buf, size_t length);
int spi_configure(struct spi_slave *slave, struct spi_configuration *cfg);
int spi_recv(struct spi_slave *slave, void *recv_buf, size_t length);
int spi_send(struct spi_slave *slave, const void *send_buf, size_t length);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,112 @@
#ifndef _SYSCTL_H
#define _SYSCTL_H
#ifdef __cplusplus
extern "C" {
#endif
#define SYS_BOOT_SAMPLE 0x0
#define SYS_BUS_CLK_CFG 0x40
#define SYS_BUS_CLK1_CFG 0x140
#define SYS_PER_CLK_CFG 0x44
#define SYS_SDMMC_CLK_CFG 0x48
#define SYS_VOU_CLK_CFG 0x4c
#define SYS_BUS_CLK_EN 0x50
#define SYS_BUS1_CLK_EN 0x54
#define SYS_PER_CLK_EN 0x58
#define SYS_SOFT_RST 0x5c
#define SYS_SOFT1_RST 0x60
#define SYS_SSP_CLK_CFG 0x64
#define SYS_TIMER_CLK_CFG 0x68
#define SYS_I2S_NCO_CFG 0x6c
#define SYS_DDRCTL_CFG 0x70
#define SYS_PERCTL_CFG 0x78
#define SYS_TIMER1_CLK_CFG 0x7c
#define SYS_ANA_CFG 0x80
#define SYS_ANA1_CFG 0x84
#define SYS_CPUPLL_CFG 0x88
#define SYS_SYSPLL_CFG 0x8c
#define SYS_ANA2_CFG 0x98
#define SYS_ANA3_CFG 0x9c
#define SYS_ANA4_CFG 0xa0
#define SYS_ANA5_CFG 0xa4
#define SYS_ANA6_CFG 0xa8
#define SYS_PAD_CTRL00 0xc0
#define SYS_PAD_CTRL01 0xc4
#define SYS_PAD_CTRL02 0xc8
#define SYS_PAD_CTRL03 0xcc
#define SYS_PAD_CTRL04 0xd0
#define SYS_PAD_CTRL05 0xd4
#define SYS_PAD_CTRL06 0xd8
#define SYS_PAD_CTRL07 0xdc
#define SYS_PAD_CTRL08 0x120
#define SYS_IO_DRIVER00 0xe0
#define SYS_IO_DRIVER01 0xe4
#define SYS_IO_DRIVER02 0xe8
#define SYS_IO_DRIVER03 0xec
#define SYS_IO_DRIVER04 0xf0
#define SYS_IO_DRIVER05 0xf4
#define SYS_IO_DRIVER06 0xf8
#define SYS_IO_DRIVER07 0xfc
enum sys_soft_reset{
//sys_soft0_reset
softreset_lcd=0,
softreset_dma,
softreset_jpeg,
softreset_usb,
softreset_card,
softreset_itu,
softreset_gpu,
softreset_pxp,
softreset_ssp,
softreset_ssp1,
softreset_i2c,
softreset_i2c1,
softreset_uart0,
softreset_uart1,
softreset_uart2,
softreset_uart3,
softreset_gpio,
softreset_timer0,
softreset_timer1,
softreset_timer2,
softreset_timer3,
softreset_pwm,
softreset_wdt,
softreset_i2s,
softreset_rtc,
softreset_adc,
softreset_rcrt,
softreset_aes,
softreset_icu,
softreset_ddr,
softreset_usbphy,
softreset_imc, //31
//sys_soft1_reset
softreset_can0, //0,
softreset_can1, //1
softreset_h2xdma, //2
softreset_h2xusb, //3
softreset_mipi, //4
softreset_usb_utmi, //5
softreset_vpu, //6,
softreset_i2s1, //8,
};
extern void vSysctlConfigure(uint32_t regoffset, uint32_t bitoffset, uint32_t mask, uint32_t val);
extern void sys_soft_reset (int reset_dev);
extern void sys_soft_reset_from_isr (int reset_dev);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,54 @@
#ifndef _TIMER_H
#define _TIMER_H
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
TIMER_ID0 = 0,
TIMER_ID1,
TIMER_ID2,
TIMER_ID3,
} eTimerID;
#define TIMER_LOAD_COUNT(x) ((x) * 0x14 + 0x00)
#define TIMER_CURRENT_VAL(x) ((x) * 0x14 + 0x04)
#define TIMER_CTRL(x) ((x) * 0x14 + 0x08)
#define TIMER_EOI(x) ((x) * 0x14 + 0x0c)
#define TIMER_INT_STATUS(x) ((x) * 0x14 + 0x10)
#define TIMER_CTRL_INT_MASK (1ul << 2)
#define TIMER_CTRL_PERIODIC (1ul << 1)
#define TIMER_CTRL_ENABLE (1ul << 0)
void vTimerInit(uint32_t id, int32_t inten, int32_t periodic, uint32_t rate);
void vTimerEnable(uint32_t id);
void vTimerDisable(uint32_t id);
void vTimerClrInt(uint32_t id);
void vInitialiseTimerForRunTimeState(void);
uint32_t ulGetRunTimeCountValue(void);
void vInitialiseTimerForDelay(void);
void vTimerUdelay(uint32_t usec);
void vTimerMdelay(uint32_t msec);
void udelay(uint32_t usec);
void mdelay(uint32_t msec);
uint32_t get_timer(uint32_t base); /* us */
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,209 @@
/**
* \file
*
* \par Purpose
*
* Standard output methods for reporting debug information, warnings and
* errors, which can be easily be turned on/off.
*
* \par Usage
* -# Initialize the DBGU using TRACE_CONFIGURE() if you intend to eventually
* disable ALL traces; otherwise use DBGU_Configure().
* -# Uses the TRACE_DEBUG(), TRACE_INFO(), TRACE_WARNING(), TRACE_ERROR()
* TRACE_FATAL() macros to output traces throughout the program.
* -# Each type of trace has a level : Debug 5, Info 4, Warning 3, Error 2
* and Fatal 1. Disable a group of traces by changing the value of
* TRACE_LEVEL during compilation; traces with a level bigger than TRACE_LEVEL
* are not generated. To generate no trace, use the reserved value 0.
* -# Trace disabling can be static or dynamic. If dynamic disabling is selected
* the trace level can be modified in runtime. If static disabling is selected
* the disabled traces are not compiled.
*
* \par traceLevels Trace level description
* -# TRACE_DEBUG (5): Traces whose only purpose is for debugging the program,
* and which do not produce meaningful information otherwise.
* -# TRACE_INFO (4): Informational trace about the program execution. Should
* enable the user to see the execution flow.
* -# TRACE_WARNING (3): Indicates that a minor error has happened. In most case
* it can be discarded safely; it may even be expected.
* -# TRACE_ERROR (2): Indicates an error which may not stop the program execution,
* but which indicates there is a problem with the code.
* -# TRACE_FATAL (1): Indicates a major error which prevents the program from going
* any further.
*/
#ifndef _TRACE_
#define _TRACE_
/*
* Headers
*/
//#include "pio.h"
#include <stdio.h>
#include "board.h"
/*
* Global Definitions
*/
/** Softpack Version */
#define SOFTPACK_VERSION "1.1"
#if defined(USE_ULOG)
/* using ulog compatible with trace */
#include <ulog.h>
#else
#define TRACE_LEVEL_DEBUG 5
#define TRACE_LEVEL_INFO 4
#define TRACE_LEVEL_WARNING 3
#define TRACE_LEVEL_ERROR 2
#define TRACE_LEVEL_FATAL 1
#define TRACE_LEVEL_NO_TRACE 0
/* By default, all traces are output except the debug one. */
#if !defined(TRACE_LEVEL)
#define TRACE_LEVEL TRACE_LEVEL_INFO
#endif
/* By default, trace level is static (not dynamic) */
#if !defined(DYN_TRACES)
#define DYN_TRACES 0
#endif
#if defined(NOTRACE)
#error "Error: NOTRACE has to be not defined !"
#endif
#undef NOTRACE
#if (DYN_TRACES==0)
#if (TRACE_LEVEL == TRACE_LEVEL_NO_TRACE)
#define NOTRACE
#endif
#endif
/* ------------------------------------------------------------------------------
* Global Macros
* ------------------------------------------------------------------------------
*/
extern void TRACE_CONFIGURE( uint32_t dwBaudRate, uint32_t dwMCk ) ;
/**
* Initializes the DBGU for ISP project
*
* \param mode DBGU mode.
* \param baudrate DBGU baudrate.
* \param mck Master clock frequency.
*/
#ifndef DYNTRACE
#define DYNTRACE 0
#endif
#if (TRACE_LEVEL==0) && (DYNTRACE==0)
#define TRACE_CONFIGURE_ISP(mode, baudrate, mck) {}
#else
#define TRACE_CONFIGURE_ISP(mode, baudrate, mck) { \
const Pin pinsDBGU[] = {PINS_DBGU}; \
PIO_Configure(pinsDBGU, PIO_LISTSIZE(pinsDBGU)); \
DBGU_Configure( baudrate, mck ) ; \
}
#endif
/**
* Outputs a formatted string using 'printf' if the log level is high
* enough. Can be disabled by defining TRACE_LEVEL=0 during compilation.
* \param ... Additional parameters depending on formatted string.
*/
#if defined(NOTRACE)
/* Empty macro */
#define TRACE_DEBUG(...) { }
#define TRACE_INFO(...) { }
#define TRACE_WARNING(...) { }
#define TRACE_ERROR(...) { }
#define TRACE_FATAL(...) { while(1); }
#define TRACE_DEBUG_WP(...) { }
#define TRACE_INFO_WP(...) { }
#define TRACE_WARNING_WP(...) { }
#define TRACE_ERROR_WP(...) { }
#define TRACE_FATAL_WP(...) { while(1); }
#elif (DYN_TRACES == 1)
/* Trace output depends on dwTraceLevel value */
#define TRACE_DEBUG(...) { if (dwTraceLevel >= TRACE_LEVEL_DEBUG) { printf("-D- " __VA_ARGS__); } }
#define TRACE_INFO(...) { if (dwTraceLevel >= TRACE_LEVEL_INFO) { printf("-I- " __VA_ARGS__); } }
#define TRACE_WARNING(...) { if (dwTraceLevel >= TRACE_LEVEL_WARNING) { printf("-W- " __VA_ARGS__); } }
#define TRACE_ERROR(...) { if (dwTraceLevel >= TRACE_LEVEL_ERROR) { printf("-E- " __VA_ARGS__); } }
#define TRACE_FATAL(...) { if (dwTraceLevel >= TRACE_LEVEL_FATAL) { printf("-F- " __VA_ARGS__); while(1); } }
#define TRACE_DEBUG_WP(...) { if (dwTraceLevel >= TRACE_LEVEL_DEBUG) { printf(__VA_ARGS__); } }
#define TRACE_INFO_WP(...) { if (dwTraceLevel >= TRACE_LEVEL_INFO) { printf(__VA_ARGS__); } }
#define TRACE_WARNING_WP(...) { if (dwTraceLevel >= TRACE_LEVEL_WARNING) { printf(__VA_ARGS__); } }
#define TRACE_ERROR_WP(...) { if (dwTraceLevel >= TRACE_LEVEL_ERROR) { printf(__VA_ARGS__); } }
#define TRACE_FATAL_WP(...) { if (dwTraceLevel >= TRACE_LEVEL_FATAL) { printf(__VA_ARGS__); while(1); } }
#else
/* Trace compilation depends on TRACE_LEVEL value */
#if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
#define TRACE_DEBUG(...) { printf("-D- " __VA_ARGS__); }
#define TRACE_DEBUG_WP(...) { printf(__VA_ARGS__); }
#else
#define TRACE_DEBUG(...) { }
#define TRACE_DEBUG_WP(...) { }
#endif
#if (TRACE_LEVEL >= TRACE_LEVEL_INFO)
#define TRACE_INFO(...) { printf("-I- " __VA_ARGS__); }
#define TRACE_INFO_WP(...) { printf(__VA_ARGS__); }
#else
#define TRACE_INFO(...) { }
#define TRACE_INFO_WP(...) { }
#endif
#if (TRACE_LEVEL >= TRACE_LEVEL_WARNING)
#define TRACE_WARNING(...) { printf("-W- " __VA_ARGS__); }
#define TRACE_WARNING_WP(...) { printf(__VA_ARGS__); }
#else
#define TRACE_WARNING(...) { }
#define TRACE_WARNING_WP(...) { }
#endif
#if (TRACE_LEVEL >= TRACE_LEVEL_ERROR)
#define TRACE_ERROR(...) { printf("-E- " __VA_ARGS__); }
#define TRACE_ERROR_WP(...) { printf(__VA_ARGS__); }
#else
#define TRACE_ERROR(...) { }
#define TRACE_ERROR_WP(...) { }
#endif
#if (TRACE_LEVEL >= TRACE_LEVEL_FATAL)
#define TRACE_FATAL(...) { printf("-F- " __VA_ARGS__); while(1); }
#define TRACE_FATAL_WP(...) { printf(__VA_ARGS__); while(1); }
#else
#define TRACE_FATAL(...) { while(1); }
#define TRACE_FATAL_WP(...) { while(1); }
#endif
#endif
/**
* Exported variables
*/
/** Depending on DYN_TRACES, dwTraceLevel is a modifable runtime variable or a define */
#if !defined(NOTRACE) && (DYN_TRACES == 1)
extern uint32_t dwTraceLevel ;
#endif
#endif //defined(USE_ULOG)
#endif //#ifndef TRACE_H

View File

@ -0,0 +1,44 @@
#ifndef _UART_H
#define _UART_H
#ifdef __cplusplus
extern "C" {
#endif
#include "FreeRTOS.h"
#include "semphr.h"
#include "circ_buf.h"
typedef enum {
UART_ID0 = 0,
UART_ID1,
UART_ID2,
UART_ID3,
UART_NUM,
} eUartID;
typedef struct {
uint32_t id;
uint32_t regbase;
int fifosize;
struct circ_buf rxbuf;
struct circ_buf txbuf;
SemaphoreHandle_t xMutex;
SemaphoreHandle_t xRev;
SemaphoreHandle_t xSend;
}UartPort_t;
extern void vDebugConsoleInitialise(void);
extern UartPort_t *xUartOpen(uint32_t id);
extern void vUartInit(UartPort_t *uap, uint32_t baud, uint32_t flags);
extern void vUartClose(UartPort_t *uap);
extern int iUartWrite(UartPort_t *uap, uint8_t *buf, size_t len, TickType_t xBlockTime);
int iUartRead(UartPort_t *uap, uint8_t *buf, size_t len, TickType_t xBlockTime);
int uart_rx_demo(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,45 @@
/*
* Video Decoder (VDEC) - System peripherals registers.
*
* Copyright (C) 2009 Hantro Products Oy.
*
* Based on SAMA5D4 datasheet.
*
* 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.
*/
#ifndef VDEC_H
#define VDEC_H
#define VDEC_IDR 0x00 /* ID Register (read-only) */
#define VDEC_IDR_BUILD_VER 0xf /* Build Version is 0x02. */
#define VDEC_IDR_MINOR_VER (0xff << 4) /* Minor Version is 0x88. */
#define VDEC_IDR_MAJOR_VER (0xf << 12) /* Major Version is 0x08. */
#define VDEC_IDR_PROD_ID (0xffff << 16) /* Product ID is 0x6731. */
#define VDEC_DIR 0x04 /* Decoder Interrupt Register */
#define VDEC_DIR_DE 1 /* 1: Enable decoder; 0: Disable decoder. */
#define VDEC_DIR_ID 0x10 /* 1: Disable interrupts for decoder; 0: Enable interrupts. */
#define VDEC_DIR_ABORT 0x20
#define VDEC_DIR_ISET 0x100 /* Decoder Interrupt Set. 0: Clears the Decoder Interrupt. */
#define VDEC_PPIR 0xF0 /* Post Processor Interrupt Register */
#define VDEC_PPIR_PPE 1 /* 1: Enable post-processor; 0: Disable post-processor */
#define VDEC_PPIR_ID 0x10 /* 1: Disable interrupts for post-processor; 0: Enable interrupts. */
#define VDEC_PPIR_ISET 0x100 /* Post-processor Interrupt Set. 0: Clears the post-processor Interrupt. */
int vdec_init(void);
#endif

View File

@ -0,0 +1,20 @@
#ifndef _WDT_H
#define _WDT_H
#ifdef __cplusplus
extern "C" {
#endif
int wdt_set_heartbeat(unsigned int timeout);
void wdt_stop(void);
void wdt_start(void);
void ark_wdt_keepalive(void);
int wdt_init(void);
void wdt_cpu_reboot(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,363 @@
#include "FreeRTOS.h"
#include "board.h"
#include "chip.h"
#ifdef ADC_TOUCH
#include "touch.h"
#endif
#ifdef ADC_KEY
#include "keypad.h"
#endif
#define ADC_CTR 0x00
#define ADC_CFG 0x04
#define ADC_IMR 0x08
#define ADC_STA 0x0C
#define ADC_BAT 0x10
#define ADC_AUX0 0x14
#define ADC_AUX1 0x18
#define ADC_AUX2 0x1C
#define ADC_AUX3 0x20
#define ADC_AUX4 0x38
#define ADC_AUX5 0x40
#define ADC_AUX6 0x44
#define ADC_AUX7 0x4C
#define ADC_PANXZ1 0x24
#define ADC_PANXZ2 0x28
#define ADC_DBNCNT 0x2C
#define ADC_DETINTER 0x30
#define ADC_SCTR 0x34
#define ADC_CLK_FREQ 1000000
#define ADC_DEBOUNCE_CNT 0x10000
static void adc_set_deinter(uint32_t count)
{
/* dbncnt * freq_adc / (2 * freq_apb) */
int mincnt = ADC_DEBOUNCE_CNT * ulClkGetRate(CLK_ADC) / 2 / ulClkGetRate(CLK_APB);
writel(configMAX(mincnt, count), REGS_ADC_BASE + ADC_DETINTER);
}
void adc_channel_enable(eAdcChannel ch)
{
uint32_t ctr, imr;
configASSERT(ch >= ADC_CH_BAT && ch <= ADC_CH_AUX7);
ctr = readl(REGS_ADC_BASE + ADC_CTR);
imr = readl(REGS_ADC_BASE + ADC_IMR);
switch(ch) {
case ADC_CH_BAT:
ctr |= 1 << ADC_CH_BAT;
imr &= ~BAT_INT;
break;
case ADC_CH_TP:
ctr |= 1 << ADC_CH_TP;
imr &= ~(TP_START_INT | TP_STOP_INT | TP_VALUE_INT);
break;
case ADC_CH_AUX0:
ctr |= (1 << 8) | (1 << ADC_CH_AUX0);
imr &= ~(AUX0_START_INT | AUX0_STOP_INT | AUX0_VALUE_INT);
break;
case ADC_CH_AUX1:
ctr |= (1 << 9) | (1 << ADC_CH_AUX1);
imr &= ~(AUX1_START_INT | AUX1_STOP_INT | AUX1_VALUE_INT);
break;
case ADC_CH_AUX2:
ctr |= (1 << 10) | (1 << ADC_CH_AUX2);
imr &= ~(AUX2_START_INT | AUX2_STOP_INT | AUX2_VALUE_INT);
break;
case ADC_CH_AUX3:
ctr |= (1 << 11) | (1 << ADC_CH_AUX3);
imr &= ~(AUX3_START_INT | AUX3_STOP_INT | AUX3_VALUE_INT);
break;
case ADC_CH_AUX4:
ctr |= (1 << 24) | (1 << 20);
imr &= ~(AUX4_START_INT | AUX4_STOP_INT | AUX4_VALUE_INT);
break;
case ADC_CH_AUX5:
ctr |= (1 << 25) | (1 << 21);
imr &= ~(AUX5_START_INT | AUX5_STOP_INT | AUX5_VALUE_INT);
break;
case ADC_CH_AUX6:
ctr |= (1 << 26) | (1 << 22);
imr &= ~(AUX6_START_INT | AUX6_STOP_INT | AUX6_VALUE_INT);
break;
case ADC_CH_AUX7:
ctr |= (1 << 27) | (1 << 23);
imr &= ~(AUX7_START_INT | AUX7_STOP_INT | AUX7_VALUE_INT);
break;
}
writel(ctr, REGS_ADC_BASE + ADC_CTR);
writel(imr, REGS_ADC_BASE + ADC_IMR);
}
void adc_channel_disable(eAdcChannel ch)
{
uint32_t ctr, imr;
configASSERT(ch >= ADC_CH_BAT && ch <= ADC_CH_AUX7);
ctr = readl(REGS_ADC_BASE + ADC_CTR);
imr = readl(REGS_ADC_BASE + ADC_IMR);
switch(ch) {
case ADC_CH_BAT:
ctr &= ~(1 << ADC_CH_BAT);
imr |= BAT_INT;
break;
case ADC_CH_TP:
ctr &= ~(1 << ADC_CH_TP);
imr |= (TP_START_INT | TP_STOP_INT | TP_VALUE_INT);
break;
case ADC_CH_AUX0:
ctr &= ~((1 << 8) | (1 << ADC_CH_AUX0));
imr |= (AUX0_START_INT | AUX0_STOP_INT | AUX0_VALUE_INT);
break;
case ADC_CH_AUX1:
ctr &= ~((1 << 9) | (1 << ADC_CH_AUX1));
imr |= (AUX1_START_INT | AUX1_STOP_INT | AUX1_VALUE_INT);
break;
case ADC_CH_AUX2:
ctr &= ~((1 << 10) | (1 << ADC_CH_AUX2));
imr |= (AUX2_START_INT | AUX2_STOP_INT | AUX2_VALUE_INT);
break;
case ADC_CH_AUX3:
ctr &= ~((1 << 11) | (1 << ADC_CH_AUX3));
imr |= (AUX3_START_INT | AUX3_STOP_INT | AUX3_VALUE_INT);
break;
case ADC_CH_AUX4:
ctr &= ~((1 << 24) | (1 << 20));
imr |= (AUX4_START_INT | AUX4_STOP_INT | AUX4_VALUE_INT);
break;
case ADC_CH_AUX5:
ctr &= ~((1 << 25) | (1 << 21));
imr |= (AUX5_START_INT | AUX5_STOP_INT | AUX5_VALUE_INT);
break;
case ADC_CH_AUX6:
ctr &= ~((1 << 26) | (1 << 22));
imr |= (AUX6_START_INT | AUX6_STOP_INT | AUX6_VALUE_INT);
break;
case ADC_CH_AUX7:
ctr &= ~((1 << 27) | (1 << 23));
imr |= (AUX7_START_INT | AUX7_STOP_INT | AUX7_VALUE_INT);
break;
}
writel(ctr, REGS_ADC_BASE + ADC_CTR);
writel(imr, REGS_ADC_BASE + ADC_IMR);
}
static void adc_int_handler(void *para)
{
uint32_t status;
#ifdef ADC_TOUCH
uint32_t xpos, ypos;
#endif
//uint32_t value;
status = readl(REGS_ADC_BASE + ADC_STA);
writel(0, REGS_ADC_BASE + ADC_STA);
//printf("adc_int_handler status=0x%x.\n", status);
if (status & TP_START_INT) {
#ifdef ADC_TOUCH
TouchEventHandler(TOUCH_START_EVENT, 0, 0);
#endif
}
if (status & TP_STOP_INT) {
#ifdef ADC_TOUCH
TouchEventHandler(TOUCH_STOP_EVENT, 0, 0);
#endif
}
if (status & TP_VALUE_INT) {
#ifdef ADC_TOUCH
xpos = readl(REGS_ADC_BASE + ADC_PANXZ1);
ypos = readl(REGS_ADC_BASE + ADC_PANXZ2);
//printf("tp press %d, %d.\n", xpos, ypos);
TouchEventHandler(TOUCH_SAMPLE_EVENT, xpos, ypos);
#endif
}
if (status & AUX0_START_INT) {
#ifdef ADC_KEY
KeyEventHandler(KEY_START_EVENT, 0, 0);
#endif
}
if (status & AUX0_STOP_INT) {
#ifdef ADC_KEY
KeyEventHandler(KEY_STOP_EVENT, 0, 0);
#endif
}
if (status & AUX0_VALUE_INT) {
#ifdef ADC_KEY
uint32_t value = readl(REGS_ADC_BASE + ADC_AUX0);
KeyEventHandler(KEY_SAMPLE_EVENT, value, 0);
#endif
}
#if 0
if (status & AUX1_START_INT) {
}
if (status & AUX1_STOP_INT) {
}
if (status & AUX1_VALUE_INT) {
value = readl(REGS_ADC_BASE + ADC_AUX1);
}
if (status & AUX2_START_INT) {
}
if (status & AUX2_STOP_INT) {
}
if (status & AUX2_VALUE_INT) {
value = readl(REGS_ADC_BASE + ADC_AUX2);
}
if (status & AUX3_START_INT) {
}
if (status & AUX3_STOP_INT) {
}
if (status & AUX3_VALUE_INT) {
value = readl(REGS_ADC_BASE + ADC_AUX3);
}
if (status & AUX4_START_INT) {
}
if (status & AUX4_STOP_INT) {
}
if (status & AUX4_VALUE_INT) {
value = readl(REGS_ADC_BASE + ADC_AUX4);
}
if (status & AUX5_START_INT) {
}
if (status & AUX5_STOP_INT) {
}
if (status & AUX5_VALUE_INT) {
value = readl(REGS_ADC_BASE + ADC_AUX5);
}
if (status & AUX6_START_INT) {
}
if (status & AUX6_STOP_INT) {
}
if (status & AUX6_VALUE_INT) {
value = readl(REGS_ADC_BASE + ADC_AUX6);
}
if (status & AUX7_START_INT) {
}
if (status & AUX7_STOP_INT) {
}
if (status & AUX7_VALUE_INT) {
value = readl(REGS_ADC_BASE + ADC_AUX7);
}
if (status & BAT_INT) {
}
#endif
}
void adc_init(void)
{
vSysctlConfigure(SYS_ANA1_CFG, 7, 1, 0); // ref : 3.3v
vClkSetRate(CLK_ADC, ADC_CLK_FREQ);
/* reset adc modulex */
writel(readl(REGS_ADC_BASE + ADC_CTR) | 1, REGS_ADC_BASE + ADC_CTR);
/* disable all adc channel */
writel(readl(REGS_ADC_BASE + ADC_CTR) & ~0x7e, REGS_ADC_BASE + ADC_CTR);
/* disable and clear irq */
writel(0xffffffff, REGS_ADC_BASE + ADC_IMR);
writel(0, REGS_ADC_BASE + ADC_STA);
/* set debounce count */
writel(ADC_DEBOUNCE_CNT, REGS_ADC_BASE + ADC_DBNCNT);
adc_set_deinter(50);
request_irq(ADC_IRQn, 0, adc_int_handler, NULL);
}
unsigned int adc_get_channel_value(int ch)
{
int i;
configASSERT(ch >= ADC_CH_AUX0 && ch <= ADC_CH_AUX7);
adc_channel_disable(ADC_CH_TP);
for (i = ADC_CH_AUX0; i <= ADC_CH_AUX7; i++) {
if (ch == i)
adc_channel_enable(i);
else
adc_channel_disable(i);
}
vTaskDelay(pdMS_TO_TICKS(10));
if(ch<=ADC_CH_AUX3)
{
return readl(REGS_ADC_BASE + ADC_AUX0 + 4 * (ch - ADC_CH_AUX0));
}
else
{
return readl(REGS_ADC_BASE + ADC_AUX4 + 4 * (ch - ADC_CH_AUX4));
}
}

View File

@ -0,0 +1,128 @@
/**
* \file
*
* Implementation of Ark Interrupt Controller (AIC) controller.
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "chip.h"
#include <stdint.h>
#include <assert.h>
#include <string.h>
#define ICSET 0x00
#define ICPEND 0x04
#define ICMODE 0x08
#define ICMASK 0x0C
#define ICLEVEL 0x10
#define IRQPRIO 0x24
#define IRQISPR 0x3C
#define IRQISPC 0x40
#define IVEC_ADDR 0x78
typedef struct {
ISRFunction_t handler;
void *handler_param;
}IrqDesc_t;
static IrqDesc_t irq_descs[MAX_IRQ_NUM];
static volatile uint8_t interrupt_nest = 0;
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
void AIC_Initialize(void)
{
memset(irq_descs, 0, sizeof(irq_descs));
writel(0x8, REGS_AIC_BASE + ICSET);
vTimerUdelay(10);
writel(0x5, REGS_AIC_BASE + ICSET);
writel(0x0, REGS_AIC_BASE + ICMODE);
/* set irq 15-8 highest priority */
writel((1 << 12) | (0xf << 8) | (3 << 6) | (2 << 4) | (0 << 2) | 1, REGS_AIC_BASE + IRQPRIO);
/* set round-robin priority policy */
//writel(0, REGS_AIC_BASE + IRQPRIO);
writel(0xffffffff, REGS_AIC_BASE + ICMASK);
writel(0xffffffff, REGS_AIC_BASE + ICLEVEL);
writel(0xffffffff, REGS_AIC_BASE + IRQISPC);
}
/**
* \brief Enables interrupts coming from the given (unique) source (ID_xxx).
*
* \param source Interrupt source to enable.
*/
void AIC_EnableIT(uint32_t source)
{
writel(readl(REGS_AIC_BASE + ICMASK) & ~(1 << source), REGS_AIC_BASE + ICMASK);
}
/**
* \brief Disables interrupts coming from the given (unique) source (ID_xxx).
*
* \param source Interrupt source to disable.
*/
void AIC_DisableIT(uint32_t source)
{
writel(readl(REGS_AIC_BASE + ICMASK) | (1 << source), REGS_AIC_BASE + ICMASK);
}
int32_t request_irq(uint32_t irq_source, int32_t priority, ISRFunction_t func, void *param)
{
if (irq_source > MAX_IRQ_NUM - 1) {
return -1;
}
portENTER_CRITICAL();
irq_descs[irq_source].handler = func;
irq_descs[irq_source].handler_param = param;
AIC_EnableIT(irq_source);
portEXIT_CRITICAL();
return 0;
}
int32_t free_irq(uint32_t irq_source)
{
if (irq_source > MAX_IRQ_NUM - 1) {
return -1;
}
portENTER_CRITICAL();
irq_descs[irq_source].handler = NULL;
irq_descs[irq_source].handler_param = NULL;
AIC_DisableIT(irq_source);
portEXIT_CRITICAL();
return 0;
}
void AIC_IrqHandler(void)
{
int32_t source;
interrupt_nest++;
source = readl(REGS_AIC_BASE + IVEC_ADDR) >> 2;
if (irq_descs[source].handler)
irq_descs[source].handler(irq_descs[source].handler_param);
writel(1 << source, REGS_AIC_BASE + IRQISPC);
interrupt_nest--;
}
uint8_t interrupt_get_nest(void)
{
uint8_t ret;
UBaseType_t uxSavedInterruptStatus;
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
ret = interrupt_nest;
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);
return ret;
}

View File

@ -0,0 +1,650 @@
#include "FreeRTOS.h"
#include "chip.h"
#include "board.h"
#include "audio.h"
enum
{
REPLAY_EVT_NONE = 0x00,
REPLAY_EVT_START = 0x01,
REPLAY_EVT_STOP = 0x02,
};
struct audio_queue_data
{
uint8_t *data;
int size;
};
struct audio_device *audio_dev[I2S_NUMS] = {NULL, NULL};
static int audio_send_replay_frame(struct audio_device *audio)
{
int result = 0;
uint8_t *data;
size_t dst_size, src_size;
uint16_t position, remain_bytes = 0, index = 0;
struct audio_buf_info *buf_info;
struct audio_queue_data qdata;
configASSERT(audio != NULL);
buf_info = &audio->replay->buf_info;
/* save current pos */
position = audio->replay->pos;
dst_size = buf_info->block_size;
/* check replay queue is empty */
if (xQueueIsQueueEmptyFromISR(audio->replay->queue) == pdTRUE)
{
/* ack stop event */
if (audio->replay->event & REPLAY_EVT_STOP) {
xQueueSendFromISR(audio->replay->cmp, NULL, 0);
return 0;
}
/* send zero frames */
memset(&buf_info->buffer[audio->replay->pos], 0, dst_size);
audio->replay->pos += dst_size;
audio->replay->pos %= buf_info->total_size;
}
else
{
memset(&buf_info->buffer[audio->replay->pos], 0, dst_size);
/* copy data from memory pool to hardware device fifo */
while (index < dst_size)
{
result = xQueuePeekFromISR(audio->replay->queue, &qdata);
if (result != pdTRUE)
{
TRACE_DEBUG("under run %d, remain %d", audio->replay->pos, remain_bytes);
audio->replay->pos -= remain_bytes;
audio->replay->pos += dst_size;
audio->replay->pos %= buf_info->total_size;
audio->replay->read_index = 0;
result = -1;
break;
}
data = qdata.data;
src_size = qdata.size;
remain_bytes = configMIN((dst_size - index), (src_size - audio->replay->read_index));
memcpy(&buf_info->buffer[audio->replay->pos],
&data[audio->replay->read_index], remain_bytes);
index += remain_bytes;
audio->replay->read_index += remain_bytes;
audio->replay->pos += remain_bytes;
audio->replay->pos %= buf_info->total_size;
if (audio->replay->read_index == src_size)
{
audio->replay->read_index = 0;
xQueueReceiveFromISR(audio->replay->queue, &qdata, 0);
for (int i = 0; i < AUDIO_REPLAY_MP_BLOCK_COUNT; i++) {
if (qdata.data == audio->replay->mempool + AUDIO_REPLAY_MP_BLOCK_SIZE * i) {
audio->replay->mpstatus[i] = 0;
break;
}
}
}
}
}
if (audio->ops->transmit != NULL)
{
if (audio->ops->transmit(audio, &buf_info->buffer[position], NULL, dst_size) != dst_size)
result = -1;
}
return result;
}
static int audio_receive_record_frame(struct audio_device *audio)
{
struct audio_buf_info *buf_info;
size_t dst_size;
int read_pos;
int result = 0;
configASSERT(audio != NULL);
/* ack stop event */
if (audio->record->event & REPLAY_EVT_STOP) {
xQueueSendFromISR(audio->record->cmp, NULL, 0);
return 0;
}
buf_info = &audio->record->buf_info;
if(buf_info->buffer && buf_info->total_size)
{
if(audio->record->remain_size <= 0)
{
if(audio->record->read_index == buf_info->total_size)
{
if(audio->record->receive_cb)
audio->record->receive_cb(audio);
}
audio->record->remain_size = buf_info->total_size;
audio->record->read_index = 0;
}
read_pos = audio->record->read_index;
dst_size = buf_info->block_size;
if(audio->record->remain_size < buf_info->block_size)
dst_size = audio->record->remain_size;
if(audio->ops->transmit)
{
if(audio->ops->transmit(audio, NULL, &buf_info->buffer[read_pos], dst_size) != dst_size)
{
printf("%s() transmit failed.\n", __func__);
result = -1;
}
else
{
audio->record->read_index += dst_size;
audio->record->remain_size -= dst_size;
if(audio->record->remain_size < 0)
{
printf("%s() Invalid remain_size:%d.\n", __func__, audio->record->remain_size);
audio->record->remain_size = 0;
}
}
}
}
else
{
if(!buf_info->buffer)
printf("%s() record buffer is NULL.\n", __func__);
if(!buf_info->total_size)
printf("%s() record buffer size is 0.\n", __func__);
result = -1;
}
return result;
}
static int audio_flush_replay_frame(struct audio_device *audio)
{
int result = 0;
if (audio->replay->write_index)
{
struct audio_queue_data qdata = {audio->replay->write_data, audio->replay->write_index};
result = xQueueSend(audio->replay->queue, &qdata, portMAX_DELAY);
audio->replay->write_index = 0;
}
return result;
}
static int audio_replay_start(struct audio_device *audio)
{
int result = 0;
if (audio->replay->activated != true)
{
/* start playback hardware device */
if (audio->ops->start)
result = audio->ops->start(audio, AUDIO_STREAM_REPLAY);
audio->replay->activated = true;
TRACE_DEBUG("start audio replay device");
}
return result;
}
static int audio_replay_stop(struct audio_device *audio)
{
int result = 0;
if (audio->replay->activated == true)
{
/* flush replay remian frames */
audio_flush_replay_frame(audio);
/* notify irq(or thread) to stop the data transmission */
audio->replay->event |= REPLAY_EVT_STOP;
/* waiting for the remaining data transfer to complete */
xQueueReset(audio->replay->cmp);
xQueueReceive(audio->replay->cmp, NULL, pdMS_TO_TICKS(2000));
audio->replay->event &= ~REPLAY_EVT_STOP;
/* stop playback hardware device */
if (audio->ops->stop)
result = audio->ops->stop(audio, AUDIO_STREAM_REPLAY);
audio->replay->activated = false;
TRACE_DEBUG("stop audio replay device");
}
return result;
}
static int audio_record_start(struct audio_device *audio)
{
int result = 0;
if (audio->record->activated != true)
{
/* start record hardware device */
if (audio->ops->start)
result = audio->ops->start(audio, AUDIO_STREAM_RECORD);
audio->record->activated = true;
TRACE_DEBUG("start audio record device");
}
return result;
}
static int audio_record_stop(struct audio_device *audio)
{
int result = 0;
if (audio->record->activated == true)
{
/* notify irq(or thread) to stop the data transmission */
audio->record->event |= REPLAY_EVT_STOP;
/* waiting for the remaining data transfer to complete */
xQueueReset(audio->record->cmp);
xQueueReceive(audio->record->cmp, NULL, pdMS_TO_TICKS(1000));
/* stop record hardware device */
if (audio->ops->stop)
result = audio->ops->stop(audio, AUDIO_STREAM_RECORD);
audio->record->event &= ~REPLAY_EVT_STOP;
audio->record->activated = false;
TRACE_DEBUG("stop audio record device");
}
return result;
}
static int audio_dev_init(struct audio_device *audio)
{
int result = 0;
configASSERT(audio != NULL);
/* initialize replay & record */
audio->replay = NULL;
audio->record = NULL;
/* initialize replay */
if ((audio->flag & AUDIO_FLAG_REPLAY) == AUDIO_FLAG_REPLAY)
{
struct audio_replay *replay = (struct audio_replay *) pvPortMalloc(sizeof(struct audio_replay));
if (replay == NULL)
return -ENOMEM;
memset(replay, 0, sizeof(struct audio_replay));
/* alloc mempool */
replay->mempool = pvPortMalloc(AUDIO_REPLAY_MP_BLOCK_SIZE * AUDIO_REPLAY_MP_BLOCK_COUNT);
if (!replay->mempool)
return -ENOMEM;
/* init queue for audio replay */
replay->queue = xQueueCreate(CFG_AUDIO_REPLAY_QUEUE_COUNT, sizeof(struct audio_queue_data));
/* init mutex lock for audio replay */
replay->lock = xSemaphoreCreateMutex();
replay->cmp = xQueueCreate(1, 0);
replay->activated = false;
audio->replay = replay;
/* get replay buffer information */
if (audio->ops->buffer_info)
audio->ops->buffer_info(audio, &audio->replay->buf_info, AUDIO_FLAG_REPLAY);
}
/* initialize record */
if ((audio->flag & AUDIO_FLAG_RECORD) == AUDIO_FLAG_RECORD)
{
struct audio_record *record = (struct audio_record *) pvPortMalloc(sizeof(struct audio_record));
//uint8_t *buffer;
if (record == NULL)
return -ENOMEM;
memset(record, 0, sizeof(struct audio_record));
/* init pipe for record*/
/* buffer = pvPortMalloc(AUDIO_RECORD_PIPE_SIZE);
if (buffer == NULL)
{
vPortFree(record);
TRACE_ERROR("malloc memory for for record pipe failed");
return -ENOMEM;
}
audio_pipe_init(&record->pipe, "record",
(int32_t)(RT_PIPE_FLAG_FORCE_WR | RT_PIPE_FLAG_BLOCK_RD),
buffer,
RT_AUDIO_RECORD_PIPE_SIZE); */
record->cmp = xQueueCreate(1, 0);
record->activated = false;
audio->record = record;
/* get record buffer information */
if (audio->ops->buffer_info)
audio->ops->buffer_info(audio, &audio->record->buf_info, AUDIO_FLAG_RECORD);
}
/* initialize hardware configuration */
if (audio->ops->init)
audio->ops->init(audio);
return result;
}
struct audio_device *audio_dev_open(uint32_t oflag)
{
struct audio_device *audio = NULL;
#ifdef AUDIO_REPLAY_I2S
/* initialize the Rx/Tx structure according to open flag */
if ((oflag & AUDIO_FLAG_REPLAY) == AUDIO_FLAG_REPLAY)
{
audio = audio_dev[AUDIO_REPLAY_I2S];
if (audio && audio->replay->activated != true)
{
TRACE_DEBUG("open audio replay device, oflag = %x\n", oflag);
audio->replay->write_index = 0;
audio->replay->read_index = 0;
audio->replay->pos = 0;
audio->replay->event = REPLAY_EVT_NONE;
for (int i = 0; i < AUDIO_REPLAY_MP_BLOCK_COUNT; i++)
audio->replay->mpstatus[i] = 0;
}
}
#endif
#ifdef AUDIO_RECORD_I2S
if ((oflag & AUDIO_FLAG_RECORD) == AUDIO_FLAG_RECORD)
{
audio = audio_dev[AUDIO_RECORD_I2S];
if (audio && audio->record->activated != true)
{
TRACE_DEBUG("open audio record device ,oflag = %x\n", oflag);
audio->record->event = REPLAY_EVT_NONE;
audio->record->read_index = 0;
audio->record->remain_size = 0;
}
}
#endif
return audio;
}
int audio_dev_close(struct audio_device *audio, uint32_t oflag)
{
configASSERT(audio != NULL);
if ((oflag & AUDIO_FLAG_REPLAY) == AUDIO_FLAG_REPLAY)
{
/* stop replay stream */
audio_replay_stop(audio);
}
if ((oflag & AUDIO_FLAG_RECORD) == AUDIO_FLAG_RECORD)
{
/* stop record stream */
audio_record_stop(audio);
}
return 0;
}
int audio_dev_register_record_callback(struct audio_device *audio, int (*callback)(struct audio_device *audio))
{
configASSERT(audio != NULL);
if (((audio->flag & AUDIO_FLAG_RECORD) != AUDIO_FLAG_RECORD) || (audio->record == NULL))
return -EINVAL;
audio->record->receive_cb = callback;
return 0;
}
int audio_dev_record_set_param(struct audio_device *audio, uint8_t *buf, int size)
{
if(buf && ((size > 0) && (size%32 == 0))) //size should align with 32 bytes.
{
audio->record->buf_info.total_size = size;
audio->record->remain_size = audio->record->buf_info.total_size;
audio->record->buf_info.buffer = buf;
audio->record->remain_size = 0;
audio->record->read_index = 0;
return 0;
}
return -1;
}
int audio_dev_record_start(struct audio_device *audio)
{
configASSERT(audio != NULL);
if (audio->record->activated != true)
{
if(!audio->record->buf_info.buffer || !audio->record->buf_info.total_size)
{
printf("%s() Invalid buffer:%p or size:%d\n", __func__, audio->record->buf_info.buffer, audio->record->buf_info.total_size);
return -1;
}
audio->record->remain_size = 0;
audio->record->read_index = 0;
audio_record_start(audio);
audio->record->activated = true;
}
return 0;
}
int audio_dev_record_stop(struct audio_device *audio)
{
if (audio->flag == AUDIO_FLAG_RECORD)
{
/* stop record stream */
audio_record_stop(audio);
}
return 0;
}
size_t audio_dev_read(struct audio_device *audio, void *buffer, size_t size)
{
configASSERT(audio != NULL);
if ((audio->flag != AUDIO_FLAG_RECORD) || (audio->record == NULL))
return 0;
printf("%s() Invalid interface.\n", __func__);
return 0;//device_read(RT_DEVICE(&audio->record->pipe), pos, buffer, size);
}
size_t audio_dev_write(struct audio_device *audio, const void *buffer, size_t size)
{
uint8_t *ptr;
uint16_t block_size, remain_bytes, index = 0;
configASSERT(audio != NULL);
if (!((audio->flag & AUDIO_FLAG_REPLAY) == AUDIO_FLAG_REPLAY) || (audio->replay == NULL))
return 0;
/* push a new frame to replay data queue */
ptr = (uint8_t *)buffer;
block_size = AUDIO_REPLAY_MP_BLOCK_SIZE;
xSemaphoreTake(audio->replay->lock, portMAX_DELAY);
while (index < size)
{
/* request buffer from replay memory pool */
if (audio->replay->write_index % block_size == 0)
{
uint8_t *mpbuf = NULL;
uint32_t st = xTaskGetTickCount();
while(1) {
int i;
portENTER_CRITICAL();
for (i = 0; i < AUDIO_REPLAY_MP_BLOCK_COUNT; i++) {
if (!audio->replay->mpstatus[i]) {
mpbuf = audio->replay->mempool + AUDIO_REPLAY_MP_BLOCK_SIZE * i;
audio->replay->mpstatus[i] = 1;
break;
}
}
portEXIT_CRITICAL();
if (mpbuf)
break;
if (xTaskGetTickCount() - st > pdMS_TO_TICKS(1000)) {
printf("wait mempool free timeout.\n");
mpbuf = audio->replay->mempool;
for (i = 1; i < AUDIO_REPLAY_MP_BLOCK_COUNT; i++)
audio->replay->mpstatus[i] = 0;
break;
}
vTaskDelay(1);
}
audio->replay->write_data = mpbuf;
memset(audio->replay->write_data, 0, block_size);
}
/* copy data to replay memory pool */
remain_bytes = configMIN((block_size - audio->replay->write_index), (size - index));
memcpy(&audio->replay->write_data[audio->replay->write_index], &ptr[index], remain_bytes);
index += remain_bytes;
audio->replay->write_index += remain_bytes;
audio->replay->write_index %= block_size;
if (audio->replay->write_index == 0)
{
struct audio_queue_data qdata = {audio->replay->write_data, block_size};
xQueueSend(audio->replay->queue, &qdata, portMAX_DELAY);
}
}
xSemaphoreGive(audio->replay->lock);
/* check replay state */
if (audio->replay->activated != true)
{
audio_replay_start(audio);
audio->replay->activated = true;
}
return index;
}
int audio_dev_configure(struct audio_device *audio, struct audio_caps *caps)
{
int result = 0;
if (audio->ops->configure != NULL)
{
result = audio->ops->configure(audio, caps);
}
return result;
}
int audio_register(struct audio_device *audio)
{
int result = 0;
configASSERT(audio != NULL);
audio->rx_indicate = NULL;
audio->tx_complete = NULL;
/* initialize audio device */
result = audio_dev_init(audio);
audio_dev[audio->id] = audio;
return result;
}
int audio_samplerate_to_speed(uint32_t bitValue)
{
int speed = 0;
switch (bitValue)
{
case AUDIO_SAMP_RATE_8K:
speed = 8000;
break;
case AUDIO_SAMP_RATE_11K:
speed = 11052;
break;
case AUDIO_SAMP_RATE_16K:
speed = 16000;
break;
case AUDIO_SAMP_RATE_22K:
speed = 22050;
break;
case AUDIO_SAMP_RATE_32K:
speed = 32000;
break;
case AUDIO_SAMP_RATE_44K:
speed = 44100;
break;
case AUDIO_SAMP_RATE_48K:
speed = 48000;
break;
case AUDIO_SAMP_RATE_96K:
speed = 96000;
break;
case AUDIO_SAMP_RATE_128K:
speed = 128000;
break;
case AUDIO_SAMP_RATE_160K:
speed = 160000;
break;
case AUDIO_SAMP_RATE_172K:
speed = 176400;
break;
case AUDIO_SAMP_RATE_192K:
speed = 192000;
break;
default:
break;
}
return speed;
}
void audio_tx_complete(struct audio_device *audio)
{
/* try to send next frame */
audio_send_replay_frame(audio);
}
int audio_rx_complete(struct audio_device *audio)
{
/* try to receive next frame */
return audio_receive_record_frame(audio);
}
void audio_rx_done(struct audio_device *audio, uint8_t *pbuf, size_t len)
{
/* save data to record pipe */
//device_write(RT_DEVICE(&audio->record->pipe), 0, pbuf, len);
/* invoke callback */
/* if (audio->parent.rx_indicate != NULL)
audio->parent.rx_indicate(&audio->parent, len); */
}

View File

@ -0,0 +1,195 @@
#ifndef __AUDIO_H__
#define __AUDIO_H__
/* AUDIO command */
#define _AUDIO_CTL(a) (0x10 + a)
#define AUDIO_CTL_GETCAPS _AUDIO_CTL(1)
#define AUDIO_CTL_CONFIGURE _AUDIO_CTL(2)
#define AUDIO_CTL_START _AUDIO_CTL(3)
#define AUDIO_CTL_STOP _AUDIO_CTL(4)
#define AUDIO_CTL_GETBUFFERINFO _AUDIO_CTL(5)
/* Audio Device Types */
#define AUDIO_TYPE_QUERY 0x00
#define AUDIO_TYPE_INPUT 0x01
#define AUDIO_TYPE_OUTPUT 0x02
#define AUDIO_TYPE_MIXER 0x04
/* Supported Sampling Rates */
#define AUDIO_SAMP_RATE_8K 0x0001
#define AUDIO_SAMP_RATE_11K 0x0002
#define AUDIO_SAMP_RATE_16K 0x0004
#define AUDIO_SAMP_RATE_22K 0x0008
#define AUDIO_SAMP_RATE_32K 0x0010
#define AUDIO_SAMP_RATE_44K 0x0020
#define AUDIO_SAMP_RATE_48K 0x0040
#define AUDIO_SAMP_RATE_96K 0x0080
#define AUDIO_SAMP_RATE_128K 0x0100
#define AUDIO_SAMP_RATE_160K 0x0200
#define AUDIO_SAMP_RATE_172K 0x0400
#define AUDIO_SAMP_RATE_192K 0x0800
/* Supported Bit Rates */
#define AUDIO_BIT_RATE_22K 0x01
#define AUDIO_BIT_RATE_44K 0x02
#define AUDIO_BIT_RATE_48K 0x04
#define AUDIO_BIT_RATE_96K 0x08
#define AUDIO_BIT_RATE_128K 0x10
#define AUDIO_BIT_RATE_160K 0x20
#define AUDIO_BIT_RATE_172K 0x40
#define AUDIO_BIT_RATE_192K 0x80
/* Support Dsp(input/output) Units controls */
#define AUDIO_DSP_PARAM 0 /* get/set all params */
#define AUDIO_DSP_SAMPLERATE 1 /* samplerate */
#define AUDIO_DSP_CHANNELS 2 /* channels */
#define AUDIO_DSP_SAMPLEBITS 3 /* sample bits width */
/* Supported Mixer Units controls */
#define AUDIO_MIXER_QUERY 0x0000
#define AUDIO_MIXER_MUTE 0x0001
#define AUDIO_MIXER_VOLUME 0x0002
#define AUDIO_MIXER_BASS 0x0004
#define AUDIO_MIXER_MID 0x0008
#define AUDIO_MIXER_TREBLE 0x0010
#define AUDIO_MIXER_EQUALIZER 0x0020
#define AUDIO_MIXER_LINE 0x0040
#define AUDIO_MIXER_DIGITAL 0x0080
#define AUDIO_MIXER_MIC 0x0100
#define AUDIO_MIXER_VITURAL 0x0200
#define AUDIO_MIXER_EXTEND 0x8000 /* extend mixer command */
#define AUDIO_VOLUME_MAX (100)
#define AUDIO_VOLUME_MIN (0)
#define CFG_AUDIO_REPLAY_QUEUE_COUNT 8
/**
* audio flags defitions
*/
//#define AUDIO_FLAG_REPLAY 0
//#define AUDIO_FLAG_RECORD 1
#define AUDIO_REPLAY_MP_BLOCK_SIZE 4096
#define AUDIO_REPLAY_MP_BLOCK_COUNT 4
#define AUDIO_RECORD_PIPE_SIZE 2048
//typedef int (*audio_record_callback)(struct audio_device *audio, void *buffer, int size);
enum
{
AUDIO_STREAM_REPLAY = 0,
AUDIO_STREAM_RECORD = 1,
};
/* the preferred number and size of audio pipeline buffer for the audio device */
struct audio_buf_info
{
uint8_t *buffer;
uint16_t block_size;
uint16_t block_count;
uint32_t total_size;
};
struct audio_device;
struct audio_caps;
struct audio_configure;
struct audio_ops
{
int (*getcaps)(struct audio_device *audio, struct audio_caps *caps);
int (*configure)(struct audio_device *audio, struct audio_caps *caps);
int (*init)(struct audio_device *audio);
int (*start)(struct audio_device *audio, int stream);
int (*stop)(struct audio_device *audio, int stream);
size_t (*transmit)(struct audio_device *audio, const void *writeBuf, void *readBuf, size_t size);
/* get page size of codec or private buffer's info */
void (*buffer_info)(struct audio_device *audio, struct audio_buf_info *info, int flags);
};
struct audio_configure
{
uint32_t samplerate;
uint16_t channels;
uint16_t samplebits;
};
struct audio_caps
{
int main_type;
int sub_type;
union
{
uint32_t mask;
int value;
struct audio_configure config;
} udata;
};
struct audio_replay
{
QueueHandle_t queue;
SemaphoreHandle_t lock;
QueueHandle_t cmp;
struct audio_buf_info buf_info;
uint8_t *mempool;
uint8_t mpstatus[AUDIO_REPLAY_MP_BLOCK_COUNT];
uint8_t *write_data;
uint16_t write_index;
uint16_t read_index;
uint32_t pos;
uint8_t event;
bool activated;
};
struct audio_record
{
QueueHandle_t cmp;
struct audio_buf_info buf_info;
int read_index;
int remain_size;
uint8_t event;
bool activated;
int (*receive_cb)(struct audio_device *audio);
};
struct audio_device
{
struct audio_ops *ops;
struct audio_replay *replay;
struct audio_record *record;
/* device call back */
int (*rx_indicate)(struct audio_device *audio, size_t size);
int (*tx_complete)(struct audio_device *audio, void *buffer);
uint32_t flag;
uint32_t id;
void *user_data; /**< device private data */
};
int audio_register(struct audio_device *audio);
void audio_tx_complete(struct audio_device *audio);
int audio_rx_complete(struct audio_device *audio);
void audio_rx_done(struct audio_device *audio, uint8_t *pbuf, size_t len);
struct audio_device *audio_dev_open(uint32_t oflag);
int audio_dev_close(struct audio_device *audio, uint32_t oflag);
size_t audio_dev_read(struct audio_device *audio, void *buffer, size_t size);
size_t audio_dev_write(struct audio_device *audio, const void *buffer, size_t size);
int audio_dev_configure(struct audio_device *audio, struct audio_caps *caps);
int audio_dev_register_record_callback(struct audio_device *audio, int (*callback)(struct audio_device *audio));
int audio_dev_record_set_param(struct audio_device *audio, uint8_t *buf, int size);
int audio_dev_record_start(struct audio_device *audio);
int audio_dev_record_stop(struct audio_device *audio);
/* Device Control Commands */
#define CODEC_CMD_RESET 0
#define CODEC_CMD_SET_VOLUME 1
#define CODEC_CMD_GET_VOLUME 2
#define CODEC_CMD_SAMPLERATE 3
#define CODEC_CMD_EQ 4
#define CODEC_CMD_3D 5
#define CODEC_VOLUME_MAX (63)
#endif /* __AUDIO_H__ */

View File

@ -0,0 +1,591 @@
#include "FreeRTOS.h"
#include "chip.h"
#include "timers.h"
#include "board.h"
#include "i2s.h"
#include "audio.h"
#define TX_FIFO_SIZE (4096)
#define RX_FIFO_SIZE (4096)
#define I2S_DAC_NCO_REG 0x6000006C
#define I2S1_DAC_NCO_REG 0x60000148
struct ark_i2s_data amt630hv100_i2s_dac[I2S_NUMS] = {
{
.base = REGS_I2S_BASE,
.nco_reg = I2S_DAC_NCO_REG,
.id = I2S_ID0,
.clkid = CLK_I2S,
.extdata = NULL,
.dma_txch = NULL,
.dma_rxch = NULL,
},
{
.base = REGS_I2S1_BASE,
.nco_reg = I2S1_DAC_NCO_REG,
.id = I2S_ID1,
.clkid = CLK_I2S1,
.extdata = NULL,
.dma_txch = NULL,
.dma_rxch = NULL,
}
};
struct sound_device
{
struct ark_i2s_data *i2s;
struct audio_device audio;
struct audio_configure replay_config;
struct audio_configure record_config;
TimerHandle_t guard_tx_timer;
TimerHandle_t guard_rx_timer;
uint8_t volume;
uint8_t *tx_fifo;
uint8_t *rx_fifo;
};
static struct sound_device snd_dev[I2S_NUMS] = {0};
static int ark_audio_init(struct audio_device *audio)
{
struct sound_device *sdev;
configASSERT(audio != NULL);
sdev = (struct sound_device *)audio->user_data;
configASSERT(sdev != NULL);
ark_i2s_init(sdev->i2s, audio->flag);
return 0;
}
static int ark_audio_start(struct audio_device *audio, int stream)
{
struct sound_device *sdev;
configASSERT(audio != NULL);
sdev = (struct sound_device *)audio->user_data;
configASSERT(sdev != NULL);
if (stream == AUDIO_STREAM_REPLAY)
{
struct audio_caps caps;
caps.main_type = AUDIO_TYPE_OUTPUT;
caps.sub_type = AUDIO_DSP_SAMPLERATE;
audio->ops->getcaps(audio, &caps);
audio->ops->configure(audio, &caps);
audio_tx_complete(audio);
ark_i2s_startup(sdev->i2s, stream);
}
else if (stream == AUDIO_STREAM_RECORD)
{
struct audio_caps caps;
caps.main_type = AUDIO_TYPE_INPUT;
caps.sub_type = AUDIO_DSP_PARAM;
audio->ops->getcaps(audio, &caps);
audio->ops->configure(audio, &caps);
if(audio_rx_complete(audio) == 0)
{
if(sdev->guard_rx_timer)
xTimerStopFromISR(sdev->guard_rx_timer, 0);
ark_i2s_startup(sdev->i2s, stream);
if(sdev->guard_rx_timer)
{
xTimerResetFromISR(sdev->guard_rx_timer, 0);
xTimerStartFromISR(sdev->guard_rx_timer, 0);
}
}
else
printf("%s() audio_rx_complete failed.\n", __func__);
}
return 0;
}
static int ark_audio_stop(struct audio_device *audio, int stream)
{
struct sound_device *sdev;
configASSERT(audio != NULL);
sdev = (struct sound_device *)audio->user_data;
configASSERT(sdev != NULL);
configASSERT(sdev->i2s != NULL);
ark_i2s_stop(sdev->i2s, stream);
if(stream == AUDIO_STREAM_REPLAY)
dma_stop_channel(sdev->i2s->dma_txch);
else if(stream == AUDIO_STREAM_RECORD)
dma_stop_channel(sdev->i2s->dma_rxch);
return 0;
}
static int ark_audio_getcaps(struct audio_device *audio, struct audio_caps *caps)
{
struct sound_device *sdev;
int result = 0;
configASSERT(audio != NULL);
sdev = (struct sound_device *)audio->user_data;
configASSERT(sdev != NULL);
switch (caps->main_type)
{
case AUDIO_TYPE_QUERY: /* qurey the types of hw_codec device */
{
switch (caps->sub_type)
{
case AUDIO_TYPE_QUERY:
caps->udata.mask = AUDIO_TYPE_OUTPUT | AUDIO_TYPE_MIXER;
break;
default:
result = -1;
break;
}
break;
}
case AUDIO_TYPE_OUTPUT: /* Provide capabilities of OUTPUT unit */
{
switch (caps->sub_type)
{
case AUDIO_DSP_PARAM:
caps->udata.config.samplerate = sdev->replay_config.samplerate;
caps->udata.config.channels = sdev->replay_config.channels;
caps->udata.config.samplebits = sdev->replay_config.samplebits;
break;
case AUDIO_DSP_SAMPLERATE:
caps->udata.config.samplerate = sdev->replay_config.samplerate;
break;
case AUDIO_DSP_CHANNELS:
caps->udata.config.channels = sdev->replay_config.channels;
break;
case AUDIO_DSP_SAMPLEBITS:
caps->udata.config.samplebits = sdev->replay_config.samplebits;
break;
default:
result = -1;
break;
}
break;
}
case AUDIO_TYPE_INPUT:
{
switch (caps->sub_type)
{
case AUDIO_DSP_PARAM:
caps->udata.config.samplerate = sdev->record_config.samplerate;
caps->udata.config.channels = sdev->record_config.channels;
caps->udata.config.samplebits = sdev->record_config.samplebits;
break;
case AUDIO_DSP_SAMPLERATE:
caps->udata.config.samplerate = sdev->record_config.samplerate;
break;
case AUDIO_DSP_CHANNELS:
caps->udata.config.channels = sdev->record_config.channels;
break;
case AUDIO_DSP_SAMPLEBITS:
caps->udata.config.samplebits = sdev->record_config.samplebits;
break;
default:
result = -1;
break;
}
break;
}
case AUDIO_TYPE_MIXER: /* report the Mixer Units */
{
switch (caps->sub_type)
{
case AUDIO_MIXER_QUERY:
caps->udata.mask = AUDIO_MIXER_VOLUME;
break;
case AUDIO_MIXER_VOLUME:
caps->udata.value = sdev->volume;
break;
default:
result = -1;
break;
}
break;
}
default:
result = -1;
break;
}
return result;
}
static int ark_audio_configure(struct audio_device *audio, struct audio_caps *caps)
{
struct sound_device *sdev;
int result = 0;
configASSERT(audio != NULL);
sdev = (struct sound_device *)audio->user_data;
configASSERT(sdev != NULL);
switch (caps->main_type)
{
case AUDIO_TYPE_MIXER:
{
switch (caps->sub_type)
{
case AUDIO_MIXER_MUTE:
{
ark_i2s_set_volume(sdev->i2s, 0, 0);
sdev->volume = 0;
break;
}
case AUDIO_MIXER_VOLUME:
{
int volume = caps->udata.value;
ark_i2s_set_volume(sdev->i2s, volume, volume);
sdev->volume = volume;
break;
}
}
break;
}
case AUDIO_TYPE_OUTPUT:
{
switch (caps->sub_type)
{
case AUDIO_DSP_PARAM:
{
struct audio_configure config = caps->udata.config;
sdev->replay_config.channels = config.channels;
sdev->replay_config.samplebits = config.samplebits;
sdev->replay_config.samplerate = config.samplerate;
//ark_i2s_set_rate(sdev->i2s, config.samplerate);
ark_i2s_set_params(sdev->i2s, AUDIO_STREAM_REPLAY, config.samplerate, config.channels, config.samplebits);
break;
}
case AUDIO_DSP_SAMPLERATE:
{
struct audio_configure config = caps->udata.config;
sdev->replay_config.samplerate = config.samplerate;
ark_i2s_set_rate(sdev->i2s, AUDIO_STREAM_REPLAY, config.samplerate);
break;
}
default:
result = -1;
break;
}
break;
}
case AUDIO_TYPE_INPUT:
{
switch (caps->sub_type)
{
case AUDIO_DSP_PARAM:
{
struct audio_configure config = caps->udata.config;
sdev->record_config.channels = config.channels;
sdev->record_config.samplebits = config.samplebits;
sdev->record_config.samplerate = config.samplerate;
ark_i2s_set_params(sdev->i2s, AUDIO_STREAM_RECORD, config.samplerate, config.channels, config.samplebits);
break;
}
case AUDIO_DSP_SAMPLERATE:
{
struct audio_configure config = caps->udata.config;
sdev->record_config.samplerate = config.samplerate;
ark_i2s_set_rate(sdev->i2s, AUDIO_STREAM_RECORD, config.samplerate);
break;
}
default:
result = -1;
break;
}
break;
}
}
return result;
}
static void ark_i2s_dma_tx_callback(void *param, unsigned int mask)
{
struct sound_device *sdev = (struct sound_device *)param;
configASSERT(sdev != NULL);
if(sdev->guard_tx_timer)
xTimerStopFromISR(sdev->guard_tx_timer, 0);
audio_tx_complete(&sdev->audio);
}
static void ark_i2s_dma_rx_callback(void *param, unsigned int mask)
{
struct sound_device *sdev = (struct sound_device *)param;
configASSERT(sdev != NULL);
if(sdev->guard_rx_timer)
xTimerStopFromISR(sdev->guard_rx_timer, 0);
audio_rx_complete(&sdev->audio);
}
#if 1
static void ark_i2s_dma_tx_timeout_callback(TimerHandle_t timer)
{
struct sound_device *sdev = (struct sound_device *)pvTimerGetTimerID(timer);
configASSERT(sdev != NULL);
configASSERT(sdev->i2s != NULL);
if(sdev->audio.flag & AUDIO_FLAG_REPLAY == AUDIO_FLAG_REPLAY) {
printf("i2s%d dma tx timeout.\n", sdev->i2s->id);
if(sdev->guard_tx_timer)
xTimerStopFromISR(sdev->guard_tx_timer, 0);
audio_tx_complete(&sdev->audio);
}
}
static void ark_i2s_dma_rx_timeout_callback(TimerHandle_t timer)
{
struct sound_device *sdev = (struct sound_device *)pvTimerGetTimerID(timer);
configASSERT(sdev != NULL);
configASSERT(sdev->i2s != NULL);
if(sdev->audio.flag & AUDIO_FLAG_RECORD == AUDIO_FLAG_RECORD) {
printf("i2s:%d dma rx timeout.\n", sdev->i2s->id);
if(sdev->guard_rx_timer)
xTimerStopFromISR(sdev->guard_rx_timer, 0);
audio_rx_complete(&sdev->audio);
}
}
#else
static void ark_i2s_dma_timeout_callback(TimerHandle_t timer)
{
struct sound_device *sdev = (struct sound_device *)pvTimerGetTimerID(timer);
configASSERT(sdev != NULL);
if((sdev->audio.flag & AUDIO_FLAG_REPLAY) == AUDIO_FLAG_REPLAY) {
printf("i2s dma tx timeout.\n");
if(sdev->guard_tx_timer)
xTimerStopFromISR(sdev->guard_tx_timer, 0);
audio_tx_complete(&sdev->audio);
} else if((sdev->audio.flag & AUDIO_FLAG_RECORD) == AUDIO_FLAG_RECORD) {
printf("i2s dma rx timeout.\n");
if(sdev->guard_rx_timer)
xTimerStopFromISR(sdev->guard_rx_timer, 0);
ark_i2s_restart_audio(sdev->i2s);
audio_rx_complete(&sdev->audio);
}
}
#endif
static size_t ark_audio_transmit(struct audio_device *audio, const void *writeBuf, void *readBuf, size_t size)
{
struct ark_i2s_data *i2s;
struct dma_config cfg = {0};
struct sound_device *sdev = (struct sound_device *)audio->user_data;
int ret;
configASSERT(sdev != NULL);
i2s = sdev->i2s;
cfg.dst_maxburst = 16;
cfg.src_maxburst = 16;
cfg.transfer_size = size;
if(writeBuf)
{
cfg.dst_addr_width = DMA_BUSWIDTH_4_BYTES;
cfg.src_addr_width = DMA_BUSWIDTH_4_BYTES;
cfg.src_addr = (dma_addr_t)writeBuf;
cfg.dst_addr = i2s->base + I2S_SADR;
cfg.direction = DMA_MEM_TO_DEV;
if(i2s->id == I2S_ID1)
cfg.dst_id = I2S1_TX;
else /*if(i2s->id == I2S_ID0)*/
cfg.dst_id = I2S_TX;
ret = dma_config_channel(i2s->dma_txch, &cfg);
if (ret) {
printf("%s, dma_config_channel tx failed.\n", __func__);
return -1;
}
dma_register_complete_callback(i2s->dma_txch, ark_i2s_dma_tx_callback, sdev);
/* clean cache before write */
CP15_clean_dcache_for_dma((u32)writeBuf, (u32)writeBuf + size);
dma_start_channel(i2s->dma_txch);
if(sdev->guard_tx_timer)
{
xTimerResetFromISR(sdev->guard_tx_timer, 0);
xTimerStartFromISR(sdev->guard_tx_timer, 0);
}
}
else if(readBuf)
{
if(i2s->cfg[AUDIO_STREAM_RECORD].channels == 2) {
cfg.dst_addr_width = DMA_BUSWIDTH_4_BYTES;
cfg.src_addr_width = DMA_BUSWIDTH_4_BYTES;
} else {
cfg.dst_addr_width = DMA_BUSWIDTH_2_BYTES;
cfg.src_addr_width = DMA_BUSWIDTH_2_BYTES;
}
cfg.src_addr = i2s->base + I2S_SADR;
cfg.dst_addr = (dma_addr_t)readBuf;
cfg.direction = DMA_DEV_TO_MEM;
if(i2s->id == I2S_ID1)
cfg.src_id = I2S1_RX;
else /*if(i2s->id == I2S_ID0)*/
cfg.src_id = I2S_RX;
ret = dma_config_channel(i2s->dma_rxch, &cfg);
if (ret) {
printf("%s, dma_config_channel rx failed.\n", __func__);
return -1;
}
dma_register_complete_callback(i2s->dma_rxch, ark_i2s_dma_rx_callback, sdev);
/* clean cache before read */
CP15_flush_dcache_for_dma((u32)readBuf, (u32)readBuf + size);
dma_start_channel(i2s->dma_rxch);
if(sdev->guard_rx_timer)
{
xTimerResetFromISR(sdev->guard_rx_timer, 0);
xTimerStartFromISR(sdev->guard_rx_timer, 0);
}
}
return size;
}
static void ark_audio_buffer_info(struct audio_device *audio, struct audio_buf_info *info, int flags)
{
configASSERT(audio != NULL);
struct sound_device *sdev = (struct sound_device *)audio->user_data;
configASSERT(sdev != NULL);
/**
* TX_FIFO
* +----------------+----------------+
* | block1 | block2 |
* +----------------+----------------+
* \ block_size /
*/
if(flags == AUDIO_FLAG_REPLAY)
{
info->buffer = sdev->tx_fifo;
info->total_size = TX_FIFO_SIZE;
info->block_size = TX_FIFO_SIZE / 2;
info->block_count = 2;
}
else if(flags == AUDIO_FLAG_RECORD)
{
info->buffer = sdev->rx_fifo;
info->total_size = RX_FIFO_SIZE;
info->block_size = RX_FIFO_SIZE/2;
info->block_count = 2;
}
}
static struct audio_ops audio_ops =
{
.getcaps = ark_audio_getcaps,
.configure = ark_audio_configure,
.init = ark_audio_init,
.start = ark_audio_start,
.stop = ark_audio_stop,
.transmit = ark_audio_transmit,
.buffer_info = ark_audio_buffer_info,
};
int sound_init(void)
{
uint8_t *tx_fifo = NULL;
struct sound_device *sdev;
int flags;
int i;
for(i=0; i<I2S_NUMS; i++)
{
flags = 0;
#ifdef AUDIO_REPLAY_I2S
if(AUDIO_REPLAY_I2S == i) {
flags |= AUDIO_FLAG_REPLAY;
}
#endif
#ifdef AUDIO_RECORD_I2S
if(AUDIO_RECORD_I2S == i) {
flags |= AUDIO_FLAG_RECORD;
}
#endif
if(!(flags & AUDIO_FLAG_REPLAY_RECORD))
continue;
sdev = &snd_dev[i];
sdev->i2s = &amt630hv100_i2s_dac[i];
/* init default configuration */
if((flags & AUDIO_FLAG_REPLAY) == AUDIO_FLAG_REPLAY)
{
tx_fifo = pvPortMalloc(TX_FIFO_SIZE);
if (!tx_fifo)
{
printf("%s, pvPortMalloc failed\n", __func__);
return -ENOMEM;
}
sdev->tx_fifo = tx_fifo;
sdev->replay_config.samplerate = 44100; //will be reset when open() audio.
sdev->replay_config.channels = 2;
sdev->replay_config.samplebits = 16;
sdev->volume = 100;
sdev->guard_tx_timer = xTimerCreate("Replay Timer", pdMS_TO_TICKS(200), pdFALSE,
//NULL, ark_i2s_dma_timeout_callback);
sdev, ark_i2s_dma_tx_timeout_callback);
}
if((flags & AUDIO_FLAG_RECORD) == AUDIO_FLAG_RECORD)
{
sdev->rx_fifo = NULL;
sdev->record_config.samplerate = 16000; //will be reset when open() audio.
sdev->record_config.channels = 2;
sdev->record_config.samplebits = 16;
sdev->volume = 100;
sdev->guard_rx_timer = xTimerCreate("Record Timer", pdMS_TO_TICKS(200), pdFALSE,
sdev, ark_i2s_dma_rx_timeout_callback);
}
sdev->audio.ops = &audio_ops;
sdev->audio.user_data = (void *)sdev;
sdev->audio.flag = flags;
sdev->audio.id = i;
audio_register(&sdev->audio);
}
return 0;
}

View File

@ -0,0 +1,465 @@
#include <string.h>
#include "FreeRTOS.h"
#include "chip.h"
#include "board.h"
#include "lcd.h"
#include "blend2d.h"
#include "ff_stdio.h"
#define REGS_BLEND2D REGS_BLEND2D_BASE
/* BLEND2D MODULE */
#define BLEND2D_ENABLE 0x000
#define BLEND2D_START 0x004
#define BLEND2D_CTL_ENABLE 0x008
#define BLEND2D_MODE 0x00C
#define BLEND2D_WRITE_WAIT 0x010
#define BLEND2D_LAYER1_BURST_CTL 0x020
#define BLEND2D_LAYER1_CTL 0x024
#define BLEND2D_LAYER1_SIZE 0x028
#define BLEND2D_LAYER1_ADDR 0x02C
#define BLEND2D_LAYER2_BURST_CTL 0x030
#define BLEND2D_LAYER2_CTL 0x034
#define BLEND2D_LAYER2_SIZE 0x038
#define BLEND2D_LAYER2_ADDR 0x03C
#define BLEND2D_COLOR_KEY_MASK_THLD_LAYER1 0x040
#define BLEND2D_COLOR_KEY_MASK_THLD_LAYER2 0x044
#define BLEND2D_COLOR_KEY_MASK_VALUE_LAYER1 0x048
#define BLEND2D_COLOR_KEY_MASK_VALUE_LAYER2 0x04C
#define BLEND2D_LAYER1_WINDOW_POINT 0x050
#define BLEND2D_LAYER2_WINDOW_POINT 0x054
#define BLEND2D_LAYER1_SOURCE_SIZE 0x058
#define BLEND2D_LAYER2_SOURCE_SIZE 0x05C
#define BLEND2D_WRITE_BACK_SOURCE_SIZE 0x060
#define BLEND2D_BLD_SIZE 0x064
#define BLEND2D_BLD_WINDOW_POINT 0x068
#define BLEND2D_BLD_ADDR 0x06C
#define BLEND2D_BLD_CTL 0x070
#define BLEND2D_LAYER1_BACK_COLOR 0x074
#define BLEND2D_LAYER2_BACK_COLOR 0x078
#define BLEND2D_INT_CTL 0x080
#define BLEND2D_INT_CLR 0x084
#define BLEND2D_INT_STA 0x088
void blend2d_start(void)
{
writel(1, REGS_BLEND2D + BLEND2D_START);
udelay(10);
writel(0, REGS_BLEND2D + BLEND2D_START);
}
void blend2d_clear_int(void)
{
writel(0, REGS_BLEND2D + BLEND2D_INT_CLR);
}
void blend2d_read_wait_enable(int enable, unsigned int wait_time)
{
unsigned int reg;
reg = readl(REGS_BLEND2D + BLEND2D_MODE);
reg &= ~((0xffff << 16) | (1 <<5));
wait_time &= 0xffff;
if(enable)
reg |= (wait_time << 16) | (1 << 5);
writel(reg, REGS_BLEND2D + BLEND2D_MODE);
}
void blend2d_write_wait_enable(unsigned int enable, unsigned int wait_time)
{
unsigned int reg;
reg = readl(REGS_BLEND2D + BLEND2D_WRITE_WAIT);
reg &= ~((1 << 12) | 0xfff);
wait_time &= 0xfff;
if(enable)
reg |= (1 << 12) | wait_time;
writel(reg, REGS_BLEND2D + BLEND2D_WRITE_WAIT);
}
void blend2d_layer_enable(int layer, int enable)
{
unsigned int reg = readl(REGS_BLEND2D + BLEND2D_CTL_ENABLE);
if (layer == BLEND2D_LAYER1) {
if (enable)
reg |= 1;
else
reg &= ~1;
} else if (layer == BLEND2D_LAYER2) {
if (enable)
reg |= 1 << 1;
else
reg &= ~(1 << 1);
}
writel(reg, REGS_BLEND2D + BLEND2D_CTL_ENABLE);
}
void blend2d_set_layer_point(int layer, int x, int y)
{
x &= 0xfff;
y &= 0xfff;
if (layer == BLEND2D_LAYER1)
writel((y << 12) | x, REGS_BLEND2D + BLEND2D_LAYER1_WINDOW_POINT);
else if (layer == BLEND2D_LAYER2)
writel((y << 12) | x, REGS_BLEND2D + BLEND2D_LAYER2_WINDOW_POINT);
}
void blend2d_set_layer_size(int layer, int width, int height)
{
width &= 0xfff;
height &= 0xfff;
if (layer == BLEND2D_LAYER1)
writel((height << 12) | width, REGS_BLEND2D + BLEND2D_LAYER1_SIZE);
else if (layer == BLEND2D_LAYER2)
writel((height << 12) | width, REGS_BLEND2D + BLEND2D_LAYER2_SIZE);
}
void blend2d_set_layer_source_size(int layer, int width, int height)
{
width &= 0xfff;
height &= 0xfff;
if (layer == BLEND2D_LAYER1)
writel((height << 12) | width, REGS_BLEND2D + BLEND2D_LAYER1_SOURCE_SIZE);
else if (layer == BLEND2D_LAYER2)
writel((height << 12) | width, REGS_BLEND2D + BLEND2D_LAYER2_SOURCE_SIZE);
}
void blend2d_set_layer_addr(int layer, unsigned int addr)
{
if (layer == BLEND2D_LAYER1)
writel(addr, REGS_BLEND2D + BLEND2D_LAYER1_ADDR);
else if (layer == BLEND2D_LAYER2)
writel(addr, REGS_BLEND2D + BLEND2D_LAYER2_ADDR);
}
void blend2d_set_layer_format(int layer, int format, int rgb_order)
{
format &= 0xf;
rgb_order &= 0x7;
if (layer == BLEND2D_LAYER1)
writel(rgb_order << 4 | format, REGS_BLEND2D + BLEND2D_LAYER1_CTL);
else if (layer == BLEND2D_LAYER2)
writel(rgb_order << 4 | format, REGS_BLEND2D + BLEND2D_LAYER2_CTL);
}
void blend2d_set_layer_alpha_mode(int layer, int mode)
{
unsigned int reg;
if (layer == BLEND2D_LAYER1) {
reg = readl(REGS_BLEND2D + BLEND2D_LAYER1_BURST_CTL);
if (mode == BLEND2D_ALPHA_DATA)
reg &= ~(1 << 15);
else if (mode == BLEND2D_ALPHA_REG)
reg |= 1 << 15;
writel(reg, REGS_BLEND2D + BLEND2D_LAYER1_BURST_CTL);
} else if (layer == BLEND2D_LAYER2) {
reg = readl(REGS_BLEND2D + BLEND2D_LAYER2_BURST_CTL);
if (mode == BLEND2D_ALPHA_DATA)
reg &= ~(1 << 15);
else if (mode == BLEND2D_ALPHA_REG)
reg |= 1 << 15;
writel(reg, REGS_BLEND2D + BLEND2D_LAYER2_BURST_CTL);
}
}
void blend2d_set_layer_alpha(int layer, uint8_t alpha)
{
unsigned int reg;
if (layer == BLEND2D_LAYER1) {
reg = readl(REGS_BLEND2D + BLEND2D_LAYER1_BURST_CTL);
reg &= ~(0xf << 16);
reg |= alpha << 16;
writel(reg, REGS_BLEND2D + BLEND2D_LAYER1_BURST_CTL);
} else if (layer == BLEND2D_LAYER2) {
reg = readl(REGS_BLEND2D + BLEND2D_LAYER2_BURST_CTL);
reg &= ~(0xf << 16);
reg |= alpha << 16;
writel(reg, REGS_BLEND2D + BLEND2D_LAYER2_BURST_CTL);
}
}
void blend2d_set_layer_colorkey(int layer, int enable, uint8_t r, uint8_t g, uint8_t b)
{
unsigned int reg;
if (layer == BLEND2D_LAYER1) {
reg = readl(REGS_BLEND2D + BLEND2D_COLOR_KEY_MASK_VALUE_LAYER1);
reg &= ~0x1ffffff;
reg |= (r << 16) | (g << 8) | b;
if (enable)
reg |= 1 << 24;
writel(reg, REGS_BLEND2D + BLEND2D_COLOR_KEY_MASK_VALUE_LAYER1);
} else if (layer == BLEND2D_LAYER2) {
reg = readl(REGS_BLEND2D + BLEND2D_COLOR_KEY_MASK_VALUE_LAYER2);
reg &= ~0x1ffffff;
reg |= (r << 16) | (g << 8) | b;
if (enable)
reg |= 1 << 24;
writel(reg, REGS_BLEND2D + BLEND2D_COLOR_KEY_MASK_VALUE_LAYER2);
}
}
void blend2d_set_layer_colorkey_thld(int layer, uint8_t r, uint8_t g, uint8_t b)
{
if (layer == BLEND2D_LAYER1)
writel((r << 16) | (g << 8) | b, REGS_BLEND2D + BLEND2D_COLOR_KEY_MASK_THLD_LAYER1);
else if (layer == BLEND2D_LAYER2)
writel((r << 16) | (g << 8) | b, REGS_BLEND2D + BLEND2D_COLOR_KEY_MASK_THLD_LAYER2);
}
void blend2d_set_layer_colorkey_backcolor(int layer, int enable, uint8_t r, uint8_t g, uint8_t b)
{
unsigned int reg;
if (layer == BLEND2D_LAYER1) {
reg = readl(REGS_BLEND2D + BLEND2D_COLOR_KEY_MASK_VALUE_LAYER1);
if (enable)
reg |= 1 << 25;
else
reg &= ~(1 << 25);
writel(reg, REGS_BLEND2D + BLEND2D_COLOR_KEY_MASK_VALUE_LAYER1);
writel((r << 16) | (g << 8) | b, REGS_BLEND2D + BLEND2D_LAYER1_BACK_COLOR);
} else if (layer == BLEND2D_LAYER2) {
reg = readl(REGS_BLEND2D + BLEND2D_COLOR_KEY_MASK_VALUE_LAYER2);
if (enable)
reg |= 1 << 25;
else
reg &= ~(1 << 25);
writel(reg, REGS_BLEND2D + BLEND2D_COLOR_KEY_MASK_VALUE_LAYER2);
writel((r << 16) | (g << 8) | b, REGS_BLEND2D + BLEND2D_LAYER2_BACK_COLOR);
}
}
void blend2d_set_blend_point(int x, int y)
{
x &= 0xfff;
y &= 0xfff;
writel((y << 12) | x, REGS_BLEND2D + BLEND2D_BLD_WINDOW_POINT);
}
void blend2d_set_blend_source_size(int width, int height)
{
width &= 0xfff;
height &= 0xfff;
writel((height << 12) | width, REGS_BLEND2D + BLEND2D_WRITE_BACK_SOURCE_SIZE);
}
void blend2d_set_blend_size(int width, int height)
{
width &= 0xfff;
height &= 0xfff;
writel((height << 12) | width, REGS_BLEND2D + BLEND2D_BLD_SIZE);
}
void blend2d_set_blend_mode(int mode)
{
unsigned int reg = readl(REGS_BLEND2D + BLEND2D_MODE);
reg &= ~((0xf << 8) | 0x1);
reg |= (mode << 8) | (0x1 << 4);
writel(reg, REGS_BLEND2D + BLEND2D_MODE);
}
void blend2d_set_blend_addr(uint32_t addr)
{
writel(addr, REGS_BLEND2D + BLEND2D_BLD_ADDR);
}
void blend2d_set_blend_format(int format)
{
unsigned int reg = readl(REGS_BLEND2D + BLEND2D_BLD_CTL);
format &= 0xf;
reg &= ~0xf;
reg |= format;
writel(reg, REGS_BLEND2D + BLEND2D_BLD_CTL);
}
void blend2d_set_blend_endian(int endian)
{
unsigned int reg = readl(REGS_BLEND2D + BLEND2D_BLD_CTL);
if (endian == BLEND2D_ARGB)
reg |= 1 << 4;
else if (endian == BLEND2D_RGBA)
reg &= ~(1 << 4);
writel(reg, REGS_BLEND2D + BLEND2D_BLD_CTL);
}
void blend2d_set_blend_alpha(uint8_t alpha)
{
unsigned int reg = readl(REGS_BLEND2D + BLEND2D_BLD_CTL);
reg &= ~(0xff << 24);
reg |= alpha << 24;
writel(reg, REGS_BLEND2D + BLEND2D_BLD_CTL);
}
void blend2d_set_blend_alpha_mode(int mode)
{
unsigned int reg = readl(REGS_BLEND2D + BLEND2D_BLD_CTL);
mode &= 3;
reg &= ~((0x1ff << 8) | (3 << 5));
reg |= (256 << 8) | (mode << 5);
writel(reg, REGS_BLEND2D + BLEND2D_BLD_CTL);
}
void blend2d_fill(uint32_t address, int xpos, int ypos, int width, int height, int source_width, int source_height,
uint8_t cr, uint8_t cg, uint8_t cb, int format, uint8_t opa, int alpha_byte)
{
/* printf("addr 0x%x, %d,%d,%d,%d-%d,%d r=%d, g=%d, b=%d, format=%d, opa=0x%x.\n",
address, xpos, ypos, width, height, source_width, source_height, cr, cg, cb, format, opa); */
blend2d_set_layer_format(BLEND2D_LAYER2, format & 0xf, (format >> 8) & 0xf);
blend2d_set_layer_addr(BLEND2D_LAYER2, address);
blend2d_set_layer_point(BLEND2D_LAYER2, 0, 0);
blend2d_set_layer_size(BLEND2D_LAYER2, width, height);
blend2d_set_layer_source_size(BLEND2D_LAYER2, width, height);
blend2d_set_layer_colorkey(BLEND2D_LAYER2, 1, 0, 0, 0);
blend2d_set_layer_colorkey_thld(BLEND2D_LAYER2, 0xff, 0xff, 0xff);
blend2d_set_layer_colorkey_backcolor(BLEND2D_LAYER2, 1, cr, cg, cb);
blend2d_set_layer_alpha(BLEND2D_LAYER2, opa);
blend2d_set_layer_alpha_mode(BLEND2D_LAYER2, BLEND2D_ALPHA_REG);
blend2d_layer_enable(BLEND2D_LAYER2, 1);
blend2d_set_layer_format(BLEND2D_LAYER1, format & 0xf, (format >> 8) & 0xf);
blend2d_set_layer_addr(BLEND2D_LAYER1, address);
blend2d_set_layer_point(BLEND2D_LAYER1, 0, 0);
blend2d_set_layer_size(BLEND2D_LAYER1, width, height);
blend2d_set_layer_source_size(BLEND2D_LAYER1, source_width, source_height);
blend2d_layer_enable(BLEND2D_LAYER1, 1);
blend2d_set_blend_format(format & 0xf);
blend2d_set_blend_addr(address);
blend2d_set_blend_point(xpos, ypos);
blend2d_set_blend_size(width, height);
blend2d_set_blend_source_size(source_width, source_height);
blend2d_set_blend_mode(BLEND2D_MIX_BLEND);
blend2d_set_blend_endian(BLEND2D_ARGB);
blend2d_set_blend_alpha(0xff);
if (alpha_byte)
blend2d_set_blend_alpha_mode(BLEND2D_ALPHA_LAYER2);
else
blend2d_set_blend_alpha_mode(BLEND2D_ALPHA_BLEND_REG);
blend2d_read_wait_enable(1, 0x3f);
}
void blend2d_blit(uint32_t dst_addr, int dst_w, int dst_h, int dst_x, int dst_y, int dst_format, int width, int height,
uint32_t src_addr, int src_w, int src_h, int src_x, int src_y, int src_format, uint8_t opa, int alpha_byte)
{
/* printf("dst 0x%x,%dx%d-%d,%d %dx%d src 0x%x,%dx%d-%d,%d, src_format=%d, opa=0x%x, alpha_byte=%d.\n",
dst_addr, dst_w, dst_h, dst_x, dst_y, width, height,
src_addr, src_w, src_h, src_x, src_y, src_format, opa, alpha_byte); */
blend2d_set_layer_format(BLEND2D_LAYER2, src_format & 0xf, (src_format >> 8) & 0xf);
blend2d_set_layer_addr(BLEND2D_LAYER2, src_addr);
blend2d_set_layer_point(BLEND2D_LAYER2, src_x, src_y);
blend2d_set_layer_size(BLEND2D_LAYER2, width, height);
blend2d_set_layer_source_size(BLEND2D_LAYER2, src_w, src_h);
blend2d_set_layer_colorkey(BLEND2D_LAYER2, 0, 0, 0, 0);
blend2d_set_layer_alpha(BLEND2D_LAYER2, opa);
if (alpha_byte)
blend2d_set_layer_alpha_mode(BLEND2D_LAYER2, BLEND2D_ALPHA_DATA);
else
blend2d_set_layer_alpha_mode(BLEND2D_LAYER2, BLEND2D_ALPHA_REG);
blend2d_layer_enable(BLEND2D_LAYER2, 1);
blend2d_set_layer_format(BLEND2D_LAYER1, dst_format & 0xf, (dst_format >> 8) & 0xf);
blend2d_set_layer_addr(BLEND2D_LAYER1, dst_addr);
blend2d_set_layer_point(BLEND2D_LAYER1, dst_x, dst_y);
blend2d_set_layer_size(BLEND2D_LAYER1, width, height);
blend2d_set_layer_source_size(BLEND2D_LAYER1, dst_w, dst_h);
blend2d_layer_enable(BLEND2D_LAYER1, 1);
blend2d_set_blend_format(dst_format & 0xf);
blend2d_set_blend_addr(dst_addr);
blend2d_set_blend_point(dst_x, dst_y);
blend2d_set_blend_size(width, height);
blend2d_set_blend_source_size(dst_w, dst_h);
blend2d_set_blend_mode(BLEND2D_MIX_BLEND);
blend2d_set_blend_endian(BLEND2D_ARGB);
//blend2d_set_blend_alpha(0xff);
if (alpha_byte)
blend2d_set_blend_alpha_mode(BLEND2D_ALPHA_LAYER1);
else
blend2d_set_blend_alpha_mode(BLEND2D_ALPHA_LAYER2);
blend2d_read_wait_enable(1, 0x3f);
}
static void blend2d_fill_test(void)
{
unsigned char *buf = pvPortMalloc(1024*600*4);
memset(buf, 0, 1024*600*4);
CP15_clean_dcache_for_dma((uint32_t)buf, (uint32_t)buf + 1024*600*4);
ark_lcd_set_osd_yaddr(LCD_OSD1, (uint32_t)buf);
ark_lcd_set_osd_sync(LCD_OSD1);
blend2d_fill((uint32_t)buf, 0, 0, 1024, 600, 1024, 600, 0xff, 0, 0, BLEND2D_FORAMT_ARGB888, 0x20, 0);
blend2d_run();
}
static void blend2d_demo_thread(void *param)
{
blend2d_fill_test();
vTaskDelay(portMAX_DELAY);
}
int blend2d_demo(void)
{
/* Create a task to play animation */
if (xTaskCreate(blend2d_demo_thread, "axiblendemo", configMINIMAL_STACK_SIZE, NULL,
configMAX_PRIORITIES / 3, NULL) != pdPASS) {
printf("create axiblend demo task fail.\n");
return -1;
}
vTaskDelay(portMAX_DELAY);
return 0;
}
static QueueHandle_t blend2d_done;
static void blend2d_int_handler(void *para)
{
unsigned int status;
status = readl(REGS_BLEND2D + BLEND2D_INT_STA);
blend2d_clear_int();
if(status & 0x2) {
printf("blend2d err int 0x%x.\n", status);
}
xQueueSendFromISR(blend2d_done, NULL, 0);
}
int blend2d_init(void)
{
blend2d_done = xQueueCreate(1, 0);
request_irq(BLEND2D_IRQn, 0, blend2d_int_handler, NULL);
writel(0x82, REGS_BLEND2D + BLEND2D_LAYER1_BURST_CTL);
writel(0x82, REGS_BLEND2D + BLEND2D_LAYER2_BURST_CTL);
writel(0x3, REGS_BLEND2D + BLEND2D_INT_CTL);
writel(1, REGS_BLEND2D + BLEND2D_ENABLE);
return 0;
}
int blend2d_run(void)
{
xQueueReset(blend2d_done);
blend2d_start();
if (xQueueReceive(blend2d_done, NULL, pdMS_TO_TICKS(100)) != pdTRUE) {
printf("blend2d_run timeout.\n");
return -1;
}
return 0;
}

View File

@ -0,0 +1,770 @@
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include "FreeRTOS.h"
#include "chip.h"
//#define CAN_USE_TX_DEMO
#define CAN_RX_BUF_NUM 32
#define CAN_TX_BUF_NUM 32
CanMsg canRxMsg[CAN_NUM][CAN_RX_BUF_NUM] = {0};
ListItem_t canRxListItem[CAN_NUM][CAN_RX_BUF_NUM];
CanMsg canTxMsg[CAN_NUM][CAN_TX_BUF_NUM] = {0};
ListItem_t canTxListItem[CAN_NUM][CAN_TX_BUF_NUM];
static CanPort_t *pxCanPort[CAN_NUM] = {NULL};
static uint32_t ulCanBase[CAN_NUM] = {REGS_CAN0_BASE, REGS_CAN1_BASE};
static CAN_InitTypeDef CanInitValue[CAN_NUM];
static CAN_FilterInitTypeDef CanFilterInitValue[CAN_NUM];
static int nCanFilterEnable[CAN_NUM];
unsigned char can_set_reset_mode(CAN_TypeDef* CANx)
{
unsigned char status;
int i;
/*检查复位标志*/
status = CANx->MOD;
/* 关闭中断 */
CANx->IER = 0x00;
for (i = 0; i < 100; i++)
{
if((status & CAN_Mode_RM) == CAN_Mode_RM)
return CAN_InitStatus_Success;
/* 设置复位*/
CANx->MOD |= ((unsigned char)CAN_Mode_RM);
/*延时*/
udelay(10);
/*检查复位标志*/
status = CANx->MOD;
}
printf("Setting can into reset mode failed!\n");
return CAN_InitStatus_Failed;
}
static unsigned char set_normal_mode(CAN_TypeDef* CANx)
{
unsigned char status;
int i;
/*检查复位标志*/
status = CANx->MOD;
for (i = 0; i < 100; i++)
{
if((status & CAN_Mode_RM) != CAN_Mode_RM)
{
/*开所有中断 (总线错误中断不开)*/
CANx->IER |= (~(unsigned char)CAN_IR_BEI);
return CAN_InitStatus_Success;
}
/* 设置正常工作模式*/
CANx->MOD &= (~(unsigned char) CAN_Mode_RM);
/*延时*/
udelay(10);
status = CANx->MOD;
}
printf("Setting can into normal mode failed!\n");
return CAN_InitStatus_Failed;
}
unsigned char can_set_start(CAN_TypeDef* CANx)
{
/*复位TX错误计数器*/
CANx->TXERR = 0;
/*复位RX错误计数器*/
CANx->RXERR = 0;
/*时钟分频寄存器: PeliCAN模式; CBP=1,中止输入比较器, RX0激活*/
CANx->CDR = 0xC0;
return set_normal_mode(CANx);
}
unsigned char CAN_Init(CAN_TypeDef* CANx, CAN_InitTypeDef* CAN_InitStruct)
{
unsigned char InitStatus = CAN_InitStatus_Failed;
unsigned char status;
status = CANx->MOD;
if( status == 0xFF)
{
printf("Probe can failed \n");
return CAN_InitStatus_Failed;
}
/* 进入复位模式 */
InitStatus = can_set_reset_mode(CANx);
/* set acceptance filter (accept all) */
CANx->IDE_RTR_DLC = 0x0;
CANx->ID[0] = 0x0;
CANx->ID[1] = 0x0;
CANx->ID[2] = 0x0;
CANx->ID[3] = 0xFF;
CANx->BUF[0] = 0xFF;
CANx->BUF[1] = 0xFF;
CANx->BUF[2] = 0xFF;
if((CAN_InitStruct->CAN_Mode & CAN_Mode_SM) == CAN_Mode_SM)
{
/* 睡眠模式 1: 睡眠 0: 唤醒*/
CANx->MOD|= (unsigned char)CAN_Mode_SM;
}
else
{
CANx->MOD&=~ (unsigned char)CAN_Mode_SM;
}
if((CAN_InitStruct->CAN_Mode & CAN_Mode_LOM) == CAN_Mode_LOM)
{
/*只听模式 1:只听 0:正常 */
CANx->MOD|= (unsigned char)CAN_Mode_LOM;
}
else
{
CANx->MOD&=~ (unsigned char)CAN_Mode_LOM;
}
if((CAN_InitStruct->CAN_Mode & CAN_Mode_AFM) == CAN_Mode_AFM)
{
/*单滤波模式 1:单 0: 双*/
CANx->MOD |= (unsigned char)CAN_Mode_AFM;
}
else
{
CANx->MOD&=~ (unsigned char)CAN_Mode_AFM;
}
if((CAN_InitStruct->CAN_Mode & CAN_Mode_STM) == CAN_Mode_STM)
{
/*自检测模式 1:自检测 0:正常 */
CANx->MOD |= (unsigned char)CAN_Mode_STM;
}
else
{
CANx->MOD&=~ (unsigned char)CAN_Mode_STM;
}
/* 配置时钟频率 */
CANx->BTR0 = (( unsigned char )( unsigned char )CAN_InitStruct->CAN_Prescaler -1) | \
(unsigned char)CAN_InitStruct->CAN_SJW << 6;
CANx->BTR1 = ((unsigned char)CAN_InitStruct->CAN_BS1) | \
((unsigned char)CAN_InitStruct->CAN_BS2 << 4);
/* 接收发送错误阈值,错误超过该值会产生错误中断
* 默认值是96有需要可以设置不同的值 */
//CANx->EWLR = 96;
/* 进入工作模式 */
can_set_start(CANx);
/* 返回初始化结果 */
return InitStatus;
}
void CAN_Transmit(CAN_TypeDef* CANx, CanMsg* TxMessage)
{
int i;
if (TxMessage->IDE == CAN_Id_Extended)
{
CANx->ID[0]= TxMessage ->ExtId>> 21;
CANx->ID[1]= TxMessage ->ExtId>> 13;
CANx->ID[2]= TxMessage ->ExtId>> 5;
CANx->ID[3]= TxMessage ->ExtId<<3;
CANx->IDE_RTR_DLC= (TxMessage ->IDE & 0x01) << 7 |\
(TxMessage ->RTR & 0x01) << 6 |\
(TxMessage ->DLC & 0x0F);
for( i=0;i<TxMessage ->DLC; i++)
{
CANx->BUF[i]= TxMessage->Data[i];
}
}
else if (TxMessage->IDE ==CAN_Id_Standard)
{
CANx->ID[0]= TxMessage ->StdId>> 3;
CANx->ID[1]= TxMessage ->StdId<< 5;
CANx->IDE_RTR_DLC= (TxMessage ->IDE & 0x01) << 7 |\
(TxMessage ->RTR & 0x01) << 6 |\
(TxMessage ->DLC & 0x0F);
CANx->ID[2]= TxMessage ->Data[0];
CANx->ID[3]= TxMessage ->Data[1];
for( i=0;i<TxMessage ->DLC-2; i++)
{
CANx->BUF[i]= TxMessage->Data[i+2];
}
}
CANx->CMR = CAN_CMR_TR ;
}
void CAN_Receive(CAN_TypeDef* CANx, CanMsg* RxMessage)
{
/* 获取 IDE */
RxMessage->IDE = (CANx->IDE_RTR_DLC & 0x80)>>7;
/* 获取 RTR */
RxMessage->RTR = (CANx->IDE_RTR_DLC & 0x40)>>4;
/* 获取 DLC */
RxMessage->DLC= (CANx->IDE_RTR_DLC & 0x0F);
if (RxMessage->IDE == CAN_Id_Standard)
{
RxMessage->StdId = CANx->ID[0]<<3 |CANx->ID[1]>>5 ;
/* 获取数据 */
RxMessage->Data[0] = (unsigned char)CANx->ID[2];
RxMessage->Data[1] = (unsigned char)CANx->ID[3];
RxMessage->Data[2] = (unsigned char)CANx->BUF[0];
RxMessage->Data[3] = (unsigned char)CANx->BUF[1];
RxMessage->Data[4] = (unsigned char)CANx->BUF[2];
RxMessage->Data[5] = (unsigned char)CANx->BUF[3];
RxMessage->Data[6] = (unsigned char)CANx->BUF[4];
RxMessage->Data[7] = (unsigned char)CANx->BUF[5];
}
else if (RxMessage->IDE == CAN_Id_Extended)
{
RxMessage->ExtId= CANx->ID[0]<<21 |CANx->ID[1]<<13|CANx->ID[2]<<5|CANx->ID[3]>>3 ;
/* 获取数据 */
RxMessage->Data[0] = (unsigned char)CANx->BUF[0];
RxMessage->Data[1] = (unsigned char)CANx->BUF[1];
RxMessage->Data[2] = (unsigned char)CANx->BUF[2];
RxMessage->Data[3] = (unsigned char)CANx->BUF[3];
RxMessage->Data[4] = (unsigned char)CANx->BUF[4];
RxMessage->Data[5] = (unsigned char)CANx->BUF[5];
RxMessage->Data[6] = (unsigned char)CANx->BUF[6];
RxMessage->Data[7] = (unsigned char)CANx->BUF[7];
}
}
static void can_reinit(CanPort_t *cap)
{
if (cap->id == CAN_ID0)
sys_soft_reset_from_isr(softreset_can0);
else if (cap->id == CAN_ID1)
sys_soft_reset_from_isr(softreset_can1);
CAN_Init(cap->pcan, &CanInitValue[cap->id]);
if (nCanFilterEnable[cap->id]) {
vCanSetFilter(cap, &CanFilterInitValue[cap->id]);
}
}
static void vCanIntHandler(void *param)
{
CanPort_t *cap = param;
CAN_TypeDef* CANx = cap->pcan;
CanMsg RxMessage;
unsigned char status;
/*读寄存器清除中断*/
status = CANx->IR;
/*接收中断*/
if (status & CAN_IR_RI)
{
/*清除RI 中断*/
CAN_Receive(CANx, &RxMessage);
CANx->CMR |= CAN_CMR_RRB;
CANx->CMR |= CAN_CMR_CDO;
//rt_hw_can_isr(&bxcan0, RT_CAN_EVENT_RX_IND);
//printf("Can0 int RX happened!\n");
if (!listLIST_IS_EMPTY(&cap->rxFreeList)) {
ListItem_t *item = listGET_HEAD_ENTRY(&cap->rxFreeList);
memcpy((void*)listGET_LIST_ITEM_VALUE(item), &RxMessage, sizeof(CanMsg));
uxListRemove(item);
vListInsertEnd(&cap->rxRevList, item);
xSemaphoreGiveFromISR(cap->xRev, 0);
} else {
/* can数据吞吐量大的时候中断处理函数添加打印会很容易造成数据接收溢出 */
;//printf("can rx buf is full, drop a message.\n");
}
}
/*发送中断*/
if (status & CAN_IR_TI)
{
//printf("Can0 int TX happened!\n");
xQueueSendFromISR(cap->tx_done, NULL, 0);
}
/*数据溢出中断*/
if (status & CAN_IR_DOI)
{
printf("Can%d int RX OF happened!\n", cap->id);
can_reinit(cap);
}
/*错误中断*/
if (status & CAN_IR_EI)
{
printf("Can%d int ERROR happened!\n", cap->id);
if (CANx->SR & CAN_SR_ES) {
/* 接收或者发送错误超过设置的阈值 */
can_reinit(cap);
} else if (CANx->SR & CAN_SR_BS) {
/* bus off错误退出reset模式控制器会在检测到128次11个连续的隐性位
* 后恢复到bus on状态 */
set_normal_mode(CANx);
}
}
}
static void can_transmit_thread(void *param)
{
CanPort_t *cap = param;
ListItem_t *item;
CanMsg *msgs;
for (;;) {
xSemaphoreTake(cap->xSend, portMAX_DELAY);
portENTER_CRITICAL();
if(!listLIST_IS_EMPTY(&cap->txSendList)) {
item = listGET_HEAD_ENTRY(&cap->txSendList);
msgs = (CanMsg *)listGET_LIST_ITEM_VALUE(item);
uxListRemove(item);
vListInsertEnd(&cap->txFreeList, item);
portEXIT_CRITICAL();
xQueueReset(cap->tx_done);
CAN_Transmit(cap->pcan, msgs);
if (xQueueReceive(cap->tx_done, NULL, pdMS_TO_TICKS(1000)) != pdTRUE) {
/* transmit timeout, reset can */
can_reinit(cap);
}
} else {
portEXIT_CRITICAL();
}
}
}
CanPort_t *xCanOpen(uint32_t id)
{
int i;
if (id >= CAN_NUM) {
TRACE_INFO("Wrong input can id.\n");
return NULL;
}
if (pxCanPort[id] != NULL) {
TRACE_ERROR("Can %d is already in use.\n", id);
return NULL;
}
CanPort_t *cap = (CanPort_t *)pvPortMalloc(sizeof(CanPort_t));
if (cap == NULL) {
TRACE_ERROR("Out of memory for can%d.\n", id);
return NULL;
}
memset(cap, 0, sizeof(*cap));
cap->xRxMutex = xSemaphoreCreateMutex();
configASSERT(cap->xRxMutex);
cap->xRev = xSemaphoreCreateCounting(CAN_RX_BUF_NUM, 0);
configASSERT(cap->xRev);
cap->xSend = xSemaphoreCreateCounting(CAN_TX_BUF_NUM, 0);
configASSERT(cap->xSend);
cap->xTxMutex = xSemaphoreCreateMutex();
configASSERT(cap->xTxMutex);
cap->tx_done = xQueueCreate(1, 0);
configASSERT(cap->tx_done);
cap->id = id;
vListInitialise(&cap->rxRevList);
vListInitialise(&cap->rxFreeList);
for (i = 0; i < CAN_RX_BUF_NUM; i++) {
vListInitialiseItem(&canRxListItem[cap->id][i]);
listSET_LIST_ITEM_VALUE(&canRxListItem[cap->id][i], (uint32_t)&canRxMsg[cap->id][i]);
vListInsertEnd(&cap->rxFreeList, &canRxListItem[cap->id][i]);
}
vListInitialise(&cap->txSendList);
vListInitialise(&cap->txFreeList);
for (i = 0; i < CAN_TX_BUF_NUM; i++) {
vListInitialiseItem(&canTxListItem[cap->id][i]);
listSET_LIST_ITEM_VALUE(&canTxListItem[cap->id][i], (uint32_t)&canTxMsg[cap->id][i]);
vListInsertEnd(&cap->txFreeList, &canTxListItem[cap->id][i]);
}
cap->pcan = (CAN_TypeDef *)ulCanBase[id];
cap->irq = CAN0_IRQn + id;
request_irq(cap->irq, 0, vCanIntHandler, cap);
/* Create a task to transmit can msg */
if (xTaskCreate(can_transmit_thread, "cantrm", configMINIMAL_STACK_SIZE, cap,
configMAX_PRIORITIES / 3 + 2, &cap->xTxThread) != pdPASS) {
printf("create can transmit task fail.\n");
vCanClose(cap);
return NULL;
}
return pxCanPort[id] = cap;
};
void vCanInit(CanPort_t *cap, CanBPS_t baud, CanMode_t mode)
{
CAN_InitTypeDef CAN_InitStructure;
switch (mode)
{
case CAN_MODE_NORMAL:
CAN_InitStructure.CAN_Mode = 0x00;
break;
case CAN_MODE_LISEN:
CAN_InitStructure.CAN_Mode = CAN_Mode_LOM;
break;
case CAN_MODE_LOOPBACK:
CAN_InitStructure.CAN_Mode = CAN_Mode_STM;
break;
case CAN_MODE_LOOPBACKANLISEN:
CAN_InitStructure.CAN_Mode = CAN_Mode_STM|CAN_Mode_LOM;
break;
}
CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
switch (baud)
{
case CAN1MBaud:
CAN_InitStructure.CAN_Prescaler = 11;
CAN_InitStructure.CAN_BS1 = CAN_BS1_6tq;
CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq;
break;
case CAN800kBaud:
CAN_InitStructure.CAN_Prescaler = 11;
CAN_InitStructure.CAN_BS1 = CAN_BS1_8tq;
CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq;
break;
case CAN500kBaud:
CAN_InitStructure.CAN_Prescaler = 22;
CAN_InitStructure.CAN_BS1 = CAN_BS1_6tq;
CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq;
break;
case CAN250kBaud:
CAN_InitStructure.CAN_Prescaler = 44;
CAN_InitStructure.CAN_BS1 = CAN_BS1_6tq;
CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq;
break;
case CAN125kBaud:
CAN_InitStructure.CAN_Prescaler = 44;
CAN_InitStructure.CAN_BS1 = CAN_BS1_14tq;
CAN_InitStructure.CAN_BS2 = CAN_BS2_3tq;
break;
default: //250K
CAN_InitStructure.CAN_Prescaler = 40;
CAN_InitStructure.CAN_BS1 = CAN_BS1_6tq;
CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq;
break;
}
CanInitValue[cap->id] = CAN_InitStructure;
CAN_Init(cap->pcan, &CAN_InitStructure);
}
void vCanClose(CanPort_t *cap)
{
if (cap == NULL) return;
if (cap->xTxThread)
vTaskDelete(cap->xTxThread);
can_set_reset_mode(cap->pcan);
vQueueDelete(cap->tx_done);
vSemaphoreDelete(cap->xRev);
vSemaphoreDelete(cap->xSend);
vSemaphoreDelete(cap->xRxMutex);
vSemaphoreDelete(cap->xTxMutex);
free_irq(cap->irq);
vPortFree(cap);
pxCanPort[cap->id] = NULL;
}
void vCanSetFilter(CanPort_t *cap, CAN_FilterInitTypeDef * CAN_FilterInitStruct)
{
unsigned long rtr;
unsigned long fcase;
unsigned long ide;
unsigned long thisid, thisid1, thisid2;
unsigned long thismask, thismask1, thismask2;
unsigned long firstdata;
unsigned long datamask;
unsigned char CAN_FilterId0, CAN_FilterId1, CAN_FilterId2, CAN_FilterId3 ;
unsigned char CAN_FilterMaskId0, CAN_FilterMaskId1, CAN_FilterMaskId2, CAN_FilterMaskId3;
CAN_TypeDef* CANx = cap->pcan;
thisid = CAN_FilterInitStruct->ID;
thismask = CAN_FilterInitStruct->IDMASK;
thisid1 = (CAN_FilterInitStruct->ID & 0xFFFF0000 )>>16;
thismask1 = (CAN_FilterInitStruct->IDMASK & 0xFFFF0000 )>>16;
thisid2 = (CAN_FilterInitStruct->ID & 0x0000FFFF );
thismask2 = ( CAN_FilterInitStruct->IDMASK& 0x0000FFFF );
rtr = CAN_FilterInitStruct->RTR;
ide = CAN_FilterInitStruct->IDE;
firstdata = CAN_FilterInitStruct->First_Data;
datamask = CAN_FilterInitStruct->Data_Mask;
fcase = CAN_FilterInitStruct->MODE;
if(ide == 0)//标准帧
{
if(fcase == 0)// 0- 双滤波器模式
{
CAN_FilterId0 = thisid1>>3;
CAN_FilterMaskId0 = thismask1>>3;
CAN_FilterId1 = thisid1<<5 | firstdata>>4| rtr<<4;
CAN_FilterMaskId1 = thismask1<<4 | datamask>>4 ;
CAN_FilterId2 = thisid2 >> 3;
CAN_FilterMaskId2 = thismask2 >>3;
CAN_FilterId3 = firstdata & 0x0F | thisid2 <<5 | rtr<<4;
CAN_FilterMaskId3 = datamask <<4 ;
}
else if(fcase == 1)// 1-单滤波器模式
{
CAN_FilterId0 = thisid>>3;
CAN_FilterMaskId0 = thismask>>3;
CAN_FilterId1 = thisid<<5 | rtr<<4;
CAN_FilterMaskId1 = thismask<<5 ;
CAN_FilterMaskId1 |= 0x0F ;
CAN_FilterId2 = 0x00;
CAN_FilterMaskId2 = 0xFF;
CAN_FilterId3 = 0x00;
CAN_FilterMaskId3 = 0xFF ;
}
}
else if(ide == 1)//扩展帧
{
if(fcase == 0)// 0- 双滤波器模式
{
CAN_FilterId0 = thisid1>>8;
CAN_FilterMaskId0 = thismask1>>8;
CAN_FilterId1 = thisid1 ;
CAN_FilterMaskId1 = thismask1 ;
CAN_FilterId2 = thisid2>>8;
CAN_FilterMaskId2 = thismask2>>8;
CAN_FilterId3 = thisid2 ;
CAN_FilterMaskId3 = thismask2 ;
}
else if(fcase == 1)// 1-单滤波器模式
{
CAN_FilterId0 = thisid>>21;
CAN_FilterMaskId0 = thismask>>21;
CAN_FilterId1 = thisid>>13 ;
CAN_FilterMaskId1 = thismask>>13 ;
CAN_FilterId2 = thisid>>5;
CAN_FilterMaskId2 = thismask>>5;
CAN_FilterId3 = thisid<<3 | rtr<<2;
CAN_FilterMaskId3 = thismask<<3;
CAN_FilterMaskId3 |= 0x03;
}
}
/* 进入复位模式 */
can_set_reset_mode(CANx);
if(fcase == 1)// 1-单滤波器模式
{
/*单滤波模式 */
CANx->MOD |= (unsigned char)CAN_Mode_AFM;
}
else if(fcase == 0)// 0- 双滤波器模式
{
/*双滤波模式 */
CANx->MOD &=(~ (unsigned char) CAN_Mode_AFM);
}
CANx->IDE_RTR_DLC = CAN_FilterId0;
CANx->ID[0] = CAN_FilterId1;
CANx->ID[1] = CAN_FilterId2;
CANx->ID[2] = CAN_FilterId3;
CANx->ID[3] = CAN_FilterMaskId0;
CANx->BUF[0] = CAN_FilterMaskId1;
CANx->BUF[1] = CAN_FilterMaskId2;
CANx->BUF[2] = CAN_FilterMaskId3;
CanFilterInitValue[cap->id] = *CAN_FilterInitStruct;
nCanFilterEnable[cap->id] = 1;
/* 进入工作模式 */
can_set_start(CANx);
}
int iCanWrite(CanPort_t *cap, CanMsg* messages, int nmsgs, TickType_t xBlockTime)
{
TickType_t starttime = xTaskGetTickCount();
CanMsg *msgs = messages;
int count = 0;
xSemaphoreTake(cap->xTxMutex, portMAX_DELAY);
while (nmsgs) {
portENTER_CRITICAL();
if(!listLIST_IS_EMPTY(&cap->txFreeList)) {
ListItem_t *item = listGET_HEAD_ENTRY(&cap->txFreeList);
memcpy((void*)listGET_LIST_ITEM_VALUE(item), msgs, sizeof(CanMsg));
uxListRemove(item);
vListInsertEnd(&cap->txSendList, item);
portEXIT_CRITICAL();
msgs++;
count++;
nmsgs--;
xSemaphoreGive(cap->xSend);
} else {
portEXIT_CRITICAL();
if (xBlockTime && xTaskGetTickCount() - starttime > xBlockTime)
break;
vTaskDelay(1);
}
if (xBlockTime && xTaskGetTickCount() - starttime > xBlockTime)
break;
}
xSemaphoreGive(cap->xTxMutex);
return count;
}
int iCanRead(CanPort_t *cap, CanMsg* messages, int nmsgs, TickType_t xBlockTime)
{
TickType_t starttime = xTaskGetTickCount();
CanMsg *msgs = messages;
int count = 0;
xSemaphoreTake(cap->xRxMutex, portMAX_DELAY);
while (nmsgs) {
ListItem_t *item;
xSemaphoreTake(cap->xRev, pdMS_TO_TICKS(10));
portENTER_CRITICAL();
if(!listLIST_IS_EMPTY(&cap->rxRevList)) {
item = listGET_HEAD_ENTRY(&cap->rxRevList);
memcpy(msgs, (void*)listGET_LIST_ITEM_VALUE(item), sizeof(CanMsg));
uxListRemove(item);
vListInsertEnd(&cap->rxFreeList, item);
msgs++;
count++;
nmsgs--;
}
portEXIT_CRITICAL();
if (xBlockTime && xTaskGetTickCount() - starttime > xBlockTime)
break;
}
xSemaphoreGive(cap->xRxMutex);
return count;
}
int iCanGetReceiveErrorCount(CanPort_t *cap)
{
if (cap && cap->pcan)
return cap->pcan->RXERR;
return 0;
}
int iCanGetTransmitErrorCount(CanPort_t *cap)
{
if (cap && cap->pcan)
return cap->pcan->TXERR;
return 0;
}
#ifdef CAN_USE_TX_DEMO
static void can_txdemo_thread(void *param)
{
CanPort_t *cap = param;
CanMsg txmsg = {0};
txmsg.IDE = CAN_Id_Standard;
txmsg.DLC = 4;
txmsg.Data[0] = 0x11;
txmsg.Data[1] = 0x22;
txmsg.Data[2] = 0x33;
txmsg.Data[3] = 0x44;
//uint32_t last_time = get_timer(0);
for (;;) {
iCanWrite(cap, &txmsg, 1, 0);
//printf("%d us.\n", get_timer(last_time));
//last_time = get_timer(0);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
#endif
static void can_rxdemo_thread(void *param)
{
CanPort_t *cap = param;
for (;;) {
CanMsg rxmsg[8] = {0};
int revlen;
int i, j;
if ((revlen = iCanRead(cap, rxmsg, 8, pdMS_TO_TICKS(200))) > 0) {
printf("can receive %d messages:\n", revlen);
for (i = 0; i < revlen; i++) {
for (j = 0; j < rxmsg[i].DLC; j++)
printf("%.2x, ", rxmsg[i].Data[j]);
printf("\n");
}
}
}
}
int can_demo(void)
{
CanPort_t *cap = xCanOpen(CAN_ID0);
if (!cap) {
printf("open can %d fail.\n", CAN_ID0);
vTaskDelete(NULL);
return -1;
}
vCanInit(cap, CAN250kBaud, CAN_MODE_NORMAL);
#if 1
CAN_FilterInitTypeDef canfilter = {0};
/* 只接收ID的第0位为1的帧 */
canfilter.MODE = 1; /* 单滤波器模式 */
canfilter.ID = 0x1;
canfilter.IDMASK = 0x7fe;
vCanSetFilter(cap, &canfilter);
#endif
/* Create a task to test read can msg */
if (xTaskCreate(can_rxdemo_thread, "canrx", configMINIMAL_STACK_SIZE, cap,
configMAX_PRIORITIES / 3, NULL) != pdPASS) {
printf("create can rxdemo task fail.\n");
return -1;
}
#ifdef CAN_USE_TX_DEMO
/* Create a task to test write can msg */
if (xTaskCreate(can_txdemo_thread, "cantx", configMINIMAL_STACK_SIZE, cap,
configMAX_PRIORITIES / 3 + 1, NULL) != pdPASS) {
printf("create can txdemo task fail.\n");
return -1;
}
#endif
return 0;
}

View File

@ -0,0 +1,431 @@
#include "FreeRTOS.h"
#include "chip.h"
#include "board.h"
#define PLL_DIV_MASK 0xFF
#define PLL_DIV_OFFSET 0
#define PLL_NO_MASK 0x3
#define PLL_NO_OFFSET 12
#define PLL_ENA (1 << 14)
typedef struct {
uint32_t clkid;
uint32_t clktype;
uint32_t source;
int clksource[MAX_CLK_SOURCE_NUM];
int source_index;
int div;
uint32_t enable_reg[MAX_CLK_ENABLE_BITS];
int enable_offset[MAX_CLK_ENABLE_BITS];
int enable_bits;
union {
uint32_t fixed_freq;
struct {
int div;
int mult;
} fixed_fator_property;
struct {
uint32_t cfgreg;
uint32_t refclkreg;
uint32_t offset;
uint32_t mask;
} pll_property;
struct {
uint32_t cfgreg;
uint32_t analogreg;
} dds_property;
struct {
uint32_t cfgreg;
int index_offset;
int index_value;
uint32_t index_mask;
int div_offset;
int div_value;
uint32_t div_mask;
int div_mode;
uint32_t inv_reg;
int inv_offset;
uint32_t inv_mask;
int inv_value;
} sys_property;
} u;
} xClockProperty;
xClockProperty xClocks[] = {
{.clkid = CLK_XTAL32K, .clktype = FIXED_CLOCK, .u.fixed_freq = 32768},
{.clkid = CLK_XTAL24M, .clktype = FIXED_CLOCK, .u.fixed_freq = 24000000},
{.clkid = CLK_240MHZ, .clktype = FIXED_FACTOR_CLOCK, .clksource = {CLK_XTAL24M},
.u.fixed_fator_property.div = 1, .u.fixed_fator_property.mult = 10},
{.clkid = CLK_12MHZ, .clktype = FIXED_FACTOR_CLOCK, .clksource = {CLK_XTAL24M},
.u.fixed_fator_property.div = 2, .u.fixed_fator_property.mult = 1},
{.clkid = CLK_6MHZ, .clktype = FIXED_FACTOR_CLOCK, .clksource = {CLK_XTAL24M},
.u.fixed_fator_property.div = 4, .u.fixed_fator_property.mult = 1},
{.clkid = CLK_CPUPLL, .clktype = PLL_CLOCK, .clksource = {CLK_6MHZ, CLK_12MHZ},
.u.pll_property.cfgreg = 0x60000088, .u.pll_property.refclkreg = 0x60000140,
.u.pll_property.offset = 0, .u.pll_property.mask = 1},
{.clkid = CLK_SYSPLL, .clktype = PLL_CLOCK, .clksource = {CLK_6MHZ, CLK_12MHZ},
.u.pll_property.cfgreg = 0x6000008c, .u.pll_property.refclkreg = 0x60000140,
.u.pll_property.offset = 1, .u.pll_property.mask = 1},
{.clkid = CLK_DDRPLL, .clktype = PLL_CLOCK, .clksource = {CLK_6MHZ, CLK_12MHZ},
.u.pll_property.cfgreg = 0x60000090, .u.pll_property.refclkreg = 0x60000140,
.u.pll_property.offset = 2, .u.pll_property.mask = 1},
{.clkid = CLK_VPUPLL, .clktype = PLL_CLOCK, .clksource = {CLK_6MHZ, CLK_12MHZ},
.u.pll_property.cfgreg = 0x60000094, .u.pll_property.refclkreg = 0x60000140,
.u.pll_property.offset = 3, .u.pll_property.mask = 1},
{.clkid = CLK_DDR, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M,CLK_DDRPLL},
.u.sys_property.cfgreg = 0x60000040, .u.sys_property.index_offset = 24,
.u.sys_property.index_mask = 0x1, .u.sys_property.index_value = -1,
.u.sys_property.div_offset = 26, .u.sys_property.div_mask = 0x7,
.u.sys_property.div_value = -1, .u.sys_property.div_mode = DIVMODE_PLUSONE,},
{.clkid = CLK_CPU, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M,CLK_CPUPLL},
.u.sys_property.cfgreg = 0x60000040, .u.sys_property.index_offset = 0,
.u.sys_property.index_mask = 0x1, .u.sys_property.index_value = -1,
.u.sys_property.div_offset = 2, .u.sys_property.div_mask = 0x7,
.u.sys_property.div_value = -1, .u.sys_property.div_mode = DIVMODE_PLUSONE,},
{.clkid = CLK_AHB, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M,CLK_SYSPLL},
.u.sys_property.cfgreg = 0x60000040, .u.sys_property.index_offset = 8,
.u.sys_property.index_mask = 0x1, .u.sys_property.index_value = -1,
.u.sys_property.div_offset = 10, .u.sys_property.div_mask = 0x7,
.u.sys_property.div_value = -1, .u.sys_property.div_mode = DIVMODE_PLUSONE,},
{.clkid = CLK_APB, .clktype = SYS_CLOCK, .clksource = {CLK_AHB},
.u.sys_property.cfgreg = 0x60000040,
.u.sys_property.div_offset = 16, .u.sys_property.div_mask = 0x3,
.u.sys_property.div_value = -1, .u.sys_property.div_mode = DIVMODE_DOUBLE,},
{.clkid = CLK_SPI0, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M, CLK_CPUPLL},
.enable_reg = {0x60000064, 0x60000064}, .enable_offset = {30, 31}, .enable_bits = 2,
.u.sys_property.cfgreg = 0x60000064, .u.sys_property.index_offset = 4,
.u.sys_property.index_mask = 0x1, .u.sys_property.index_value = 1,
.u.sys_property.div_offset = 0, .u.sys_property.div_mask = 0xf,
.u.sys_property.div_value = 4, .u.sys_property.div_mode = DIVMODE_PLUSONE,},
{.clkid = CLK_SPI1, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M, CLK_CPUPLL},
.u.sys_property.cfgreg = 0x60000064, .u.sys_property.index_offset = 20,
.u.sys_property.index_mask = 0x1, .u.sys_property.index_value = 1,
.u.sys_property.div_offset = 16, .u.sys_property.div_mask = 0xf,
.u.sys_property.div_value = 10, .u.sys_property.div_mode = DIVMODE_PLUSONE,},
#if DEVICE_TYPE_SELECT != EMMC_FLASH
{.clkid = CLK_SDMMC0, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M, CLK_SYSPLL},
.enable_reg = {0x60000048, 0x60000050, 0x60000058}, .enable_offset = {0, 12, 15}, .enable_bits = 3,
.u.sys_property.cfgreg = 0x60000048, .u.sys_property.index_offset = 7,
.u.sys_property.index_mask = 0x1, .u.sys_property.index_value = 0,},
#else
{.clkid = CLK_SDMMC0, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M, CLK_SYSPLL},
.enable_reg = {0x60000048, 0x60000050, 0x60000058}, .enable_offset = {6, 12, 15}, .enable_bits = 3,
.u.sys_property.cfgreg = 0x60000048, .u.sys_property.index_offset = 7,
.u.sys_property.index_mask = 0x1, .u.sys_property.index_value = 1,
.u.sys_property.div_offset = 0, .u.sys_property.div_mask = 0x1f,
.u.sys_property.div_value = 10, .u.sys_property.div_mode = DIVMODE_PONEDOUBLE,},
#endif
{.clkid = CLK_LCD, .clktype = SYS_CLOCK, .clksource = {CLK_SYSPLL, CLK_VPUPLL, CLK_XTAL24M, CLK_XTAL24M},
.enable_reg = {0x60000050, 0x60000058, 0x60000058, 0x60000058}, .enable_offset = {3, 18, 17, 16}, .enable_bits = 4,
.u.sys_property.cfgreg = 0x6000004c, .u.sys_property.index_offset = 0,
.u.sys_property.index_mask = 0x3, .u.sys_property.index_value = 0,
.u.sys_property.div_offset = 3, .u.sys_property.div_mask = 0x1f,
.u.sys_property.div_value = 11, .u.sys_property.div_mode = DIVMODE_PLUSONE,
#ifdef LCD_CLK_INVERSE
.u.sys_property.inv_reg = 0x6000004c, .u.sys_property.inv_offset = 8,
.u.sys_property.inv_mask = 0x1, .u.sys_property.inv_value = 1,
#endif
},
{.clkid = CLK_TIMER, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M, CLK_CPUPLL},
.u.sys_property.cfgreg = 0x60000068, .u.sys_property.index_offset = 4,
.u.sys_property.index_mask = 0x1, .u.sys_property.index_value = 0,
.u.sys_property.div_offset = 0, .u.sys_property.div_mask = 0xf,
.u.sys_property.div_value = 1, .u.sys_property.div_mode = DIVMODE_PLUSONE,},
{.clkid = CLK_MFC, .clktype = SYS_CLOCK, .clksource = {CLK_SYSPLL, CLK_VPUPLL, CLK_XTAL24M},
.enable_reg = {0x60000050, 0x60000058}, .enable_offset = {6, 23}, .enable_bits = 2,
.u.sys_property.cfgreg = 0x60000068, .u.sys_property.index_offset = 8,
.u.sys_property.index_mask = 0x3, .u.sys_property.index_value = 1,
.u.sys_property.div_offset = 11, .u.sys_property.div_mask = 0x1f,
.u.sys_property.div_value = -1, .u.sys_property.div_mode = DIVMODE_PLUSONE,},
{.clkid = CLK_PWM, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M, CLK_240MHZ},
.enable_reg = {0x60000054, 0x60000058}, .enable_offset = {10, 10}, .enable_bits = 2,
.u.sys_property.cfgreg = 0x60000044, .u.sys_property.index_offset = 8,
.u.sys_property.index_mask = 0x1, .u.sys_property.index_value = 0,
.u.sys_property.div_offset = 4, .u.sys_property.div_mask = 0xf,
.u.sys_property.div_value = 1, .u.sys_property.div_mode = DIVMODE_PLUSONE,},
{.clkid = CLK_CAN0, .clktype = SYS_CLOCK, .clksource = {CLK_APB},
.enable_reg = {0x60000054}, .enable_offset = {19}, .enable_bits = 1,
.u.sys_property.div_value = 1,},
{.clkid = CLK_CAN1, .clktype = SYS_CLOCK, .clksource = {CLK_APB},
.enable_reg = {0x60000054}, .enable_offset = {20}, .enable_bits = 1,
.u.sys_property.div_value = 1,},
{.clkid = CLK_ADC, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M},
.enable_reg = {0x60000054, 0x60000058}, .enable_offset = {14, 13}, .enable_bits = 2,
.u.sys_property.cfgreg = 0x60000068, .u.sys_property.div_offset = 16,
.u.sys_property.div_mask = 0x7fff, .u.sys_property.div_value = 642,
.u.sys_property.div_mode = DIVMODE_PONEDOUBLE,},
{.clkid = CLK_I2S, .clktype = SYS_CLOCK, .clksource = {CLK_240MHZ, CLK_SYSPLL},
.enable_reg = {0x60000054, 0x60000058, 0x60000058}, .enable_offset = {12, 12, 11}, .enable_bits = 3,
.u.sys_property.cfgreg = 0x60000044, .u.sys_property.index_offset = 16,
.u.sys_property.index_mask = 0x1, .u.sys_property.index_value = 0,
.u.sys_property.div_value = 1,},
{.clkid = CLK_I2S1, .clktype = SYS_CLOCK, .clksource = {CLK_240MHZ, CLK_SYSPLL},
.enable_reg = {0x60000054, 0x60000144, 0x60000144}, .enable_offset = {22, 1, 0}, .enable_bits = 3,
.u.sys_property.cfgreg = 0x60000140, .u.sys_property.index_offset = 4,
.u.sys_property.index_mask = 0x1, .u.sys_property.index_value = 0,
.u.sys_property.div_value = 1,},
};
#define CLOCK_NUM (sizeof(xClocks) / sizeof(xClocks[0]))
static xClockProperty *clk_get(uint32_t clkid)
{
int i;
for (i = 0; i < CLOCK_NUM; i++) {
if (xClocks[i].clkid == clkid) {
return &xClocks[i];
}
}
return NULL;
}
static uint32_t clk_fixed_get_rate(xClockProperty *clk)
{
return clk->u.fixed_freq;
}
static uint32_t clk_fixed_factor_get_rate(xClockProperty *clk)
{
xClockProperty *parentclk = clk_get(clk->clksource[0]);
configASSERT(parentclk);
return clk_fixed_get_rate(parentclk) * clk->u.fixed_fator_property.mult
/ clk->u.fixed_fator_property.div;
}
static uint32_t clk_pll_get_rate(xClockProperty *clk)
{
uint32_t parent_rate;
uint32_t div, no, reg;
configASSERT(clk);
parent_rate = ulClkGetRate(clk->clksource[clk->source_index]);
reg = readl(clk->u.pll_property.cfgreg);
no = (reg >> PLL_NO_OFFSET) & PLL_NO_MASK;
div = (reg >> PLL_DIV_OFFSET) & PLL_DIV_MASK;
return (parent_rate * div) / (1 << no);
}
static uint32_t clk_sys_get_rate(xClockProperty *clk)
{
uint32_t parent_rate;
configASSERT(clk);
configASSERT(clk->div);
parent_rate = ulClkGetRate(clk->clksource[clk->source_index]);
return parent_rate / clk->div;
}
static void clk_pll_init(xClockProperty *clk)
{
configASSERT(clk);
clk->source_index = (readl(clk->u.pll_property.refclkreg) >> clk->u.pll_property.offset)
& clk->u.pll_property.mask;
}
static int clk_get_div(int div, int divmode)
{
switch(divmode) {
case DIVMODE_NOZERO:
div = div ? div : 1;
break;
case DIVMODE_PLUSONE:
div = div + 1;
break;
case DIVMODE_DOUBLE:
div *= 2;
break;
case DIVMODE_EXPONENT:
div = 1 << div;
break;
case DIVMODE_PONEDOUBLE:
div = (div + 1) * 2;
break;
}
return div;
}
static __INLINE int clk_set_div(int div, int divmode)
{
switch(divmode) {
case DIVMODE_PLUSONE:
div = div - 1;
break;
case DIVMODE_DOUBLE:
div /= 2;
break;
case DIVMODE_EXPONENT:
div = fls(div) - 1;
break;
case DIVMODE_PONEDOUBLE:
div = div / 2 - 1;
break;
}
return div;
}
static void clk_sys_set_rate(xClockProperty *clk, uint32_t freq)
{
int div;
uint32_t reg;
uint32_t parent_rate;
configASSERT(clk);
parent_rate = ulClkGetRate(clk->clksource[clk->source_index]);
div = DIV_ROUND_UP(parent_rate, freq);
clk->div = div;
div = clk_set_div(div, clk->u.sys_property.div_mode);
reg = readl(clk->u.sys_property.cfgreg);
reg &= ~(clk->u.sys_property.div_mask << clk->u.sys_property.div_offset);
reg |= (div & clk->u.sys_property.div_mask) << clk->u.sys_property.div_offset;
writel(reg, clk->u.sys_property.cfgreg);
}
static void clk_sys_init(xClockProperty *clk)
{
uint32_t reg;
uint32_t val;
configASSERT(clk);
if (clk->u.sys_property.index_value >= 0 && clk->u.sys_property.index_mask) {
clk->source_index = clk->u.sys_property.index_value;
val = clk->u.sys_property.index_value == 3 ? 4 : clk->u.sys_property.index_value;
reg = readl(clk->u.sys_property.cfgreg);
reg &= ~(clk->u.sys_property.index_mask << clk->u.sys_property.index_offset);
reg |= (val & clk->u.sys_property.index_mask) << clk->u.sys_property.index_offset;
writel(reg, clk->u.sys_property.cfgreg);
} else if (clk->u.sys_property.index_mask) {
reg = readl(clk->u.sys_property.cfgreg);
val = (reg >> clk->u.sys_property.index_offset) & clk->u.sys_property.index_mask;
clk->source_index = val == 4 ? 3 : val;
}
if (clk->u.sys_property.div_value >= 0 && clk->u.sys_property.div_mask) {
val = clk_set_div(clk->u.sys_property.div_value, clk->u.sys_property.div_mode);
clk->div = clk_get_div(val, clk->u.sys_property.div_mode);
reg = readl(clk->u.sys_property.cfgreg);
reg &= ~(clk->u.sys_property.div_mask << clk->u.sys_property.div_offset);
reg |= (val & clk->u.sys_property.div_mask) << clk->u.sys_property.div_offset;
writel(reg, clk->u.sys_property.cfgreg);
} else if (clk->u.sys_property.div_mask) {
reg = readl(clk->u.sys_property.cfgreg);
val = (reg >> clk->u.sys_property.div_offset) & clk->u.sys_property.div_mask;
clk->div = clk_get_div(val, clk->u.sys_property.div_mode);
} else if (clk->u.sys_property.div_value > 0) {
clk->div = clk->u.sys_property.div_value;
} else {
clk->div = 1;
}
if (clk->u.sys_property.inv_reg) {
reg = readl(clk->u.sys_property.inv_reg);
reg &= ~(clk->u.sys_property.inv_mask << clk->u.sys_property.inv_offset);
reg |= (clk->u.sys_property.inv_value & clk->u.sys_property.inv_mask)
<< clk->u.sys_property.inv_offset;
writel(reg, clk->u.sys_property.inv_reg);
}
}
static void clk_sys_enable(xClockProperty *clk)
{
int i;
configASSERT(clk);
for (i = 0; i < clk->enable_bits; i++)
writel(readl(clk->enable_reg[i]) | (1 << clk->enable_offset[i]),
clk->enable_reg[i]);
}
static void clk_sys_disable(xClockProperty *clk)
{
int i;
configASSERT(clk);
for (i = 0; i < clk->enable_bits; i++)
writel(readl(clk->enable_reg[i]) & ~(1 << clk->enable_offset[i]),
clk->enable_reg[i]);
}
void vClkInit(void)
{
int i;
xClockProperty *clk;
for (i = 0; i < CLOCK_NUM; i++) {
clk = &xClocks[i];
if (clk->clktype == PLL_CLOCK) {
clk_pll_init(clk);
} else if (clk->clktype == SYS_CLOCK) {
clk_sys_init(clk);
}
}
}
uint32_t ulClkGetRate(uint32_t clkid)
{
xClockProperty *clk = clk_get(clkid);
if (clk == NULL)
return 0;
switch (clk->clktype) {
case FIXED_CLOCK:
return clk_fixed_get_rate(clk);
case FIXED_FACTOR_CLOCK:
return clk_fixed_factor_get_rate(clk);
case PLL_CLOCK:
return clk_pll_get_rate(clk);
case SYS_CLOCK:
return clk_sys_get_rate(clk);
}
return 0;
}
void vClkSetRate(uint32_t clkid, uint32_t freq)
{
xClockProperty *clk = clk_get(clkid);
if (clk == NULL)
return;
if (clk->clktype == SYS_CLOCK)
clk_sys_set_rate(clk, freq);
}
void vClkEnable(uint32_t clkid)
{
xClockProperty *clk = clk_get(clkid);
if (clk == NULL)
return;
if (clk->clktype == SYS_CLOCK)
clk_sys_enable(clk);
}
void vClkDisable(uint32_t clkid)
{
xClockProperty *clk = clk_get(clkid);
if (clk == NULL)
return;
if (clk->clktype == SYS_CLOCK)
clk_sys_disable(clk);
}

View File

@ -0,0 +1,374 @@
#include <string.h>
#include "FreeRTOS.h"
#include "chip.h"
#include "board.h"
#if LCD_INTERFACE_TYPE == LCD_INTERFACE_CPU
/*
Cpu 屏接口模式。
*/
#define LCD_BASE REGS_LCD_BASE
#define CPU_SCR_SOFT (56 * 4)
#define CPU_SCR_CTRL (57 * 4)
#define LCD_PARAM1 4
#define SYS_BASE REGS_SYSCTL_BASE
#define WR_Com(address) WriteCpuCmd(CPU_PANEL_DATA,address);
#define WR_D(data) WriteCpuData(CPU_PANEL_DATA,data);
/*
Cpu 控制信号数据位。
*/
#define RS_1 0X200000
#define CS_1 0X100000
#define RD_1 0X080000
#define WR_1 0X040000
#define RS_0 (~0X200000)
#define CS_0 (~0X100000)
#define RD_0 (~0X080000)
#define WR_0 (~0X040000)
void ConfigCpuInit(void)
{
u32 val = 0;
val=readl(LCD_BASE + LCD_PARAM1);
val&=~(BIT(19)|BIT(18)|BIT(17)|BIT(3)|BIT(2)|BIT(1));
val|=(0x06<<1);//CPU MODE RS RD CS NORMAL
writel(val, LCD_BASE + LCD_PARAM1);
}
void ConfigCpuPadmux(u8 Interface)
{
u32 val = 0;
//cpu_screen_rst cpu_scr_cs cpu_scr_wr cpu_scr_rs cpu_scr_rd
val=readl(SYS_BASE + SYS_PAD_CTRL05);
val &= ~0x00FFC000;
// rd rs wr cs reset
val |= 1<<22|1<<20|1<<18|1<<16|1<<14;
writel(val,SYS_BASE + SYS_PAD_CTRL05);
switch(Interface) {
case CPU_PANEL_18BIT_MODE:
val = readl(SYS_BASE + SYS_PAD_CTRL04);
val &= ~0xFFFFFFFF;
//d15 d14 d13 d12 d11 d10 d19 d8 d7 d6 d5 d4 d3 d2 d1 d0
val |= 1<<30|1<<28|1<<26|1<<24|1<<22|1<<20|1<<18|1<<16|1<<14|1<<12|1<<10|1<<8|1<<6|1<<4|1<<2|1<<0;//_018BIT_MODE 接D0-D17
writel(val,SYS_BASE + SYS_PAD_CTRL04);
val = readl(SYS_BASE + SYS_PAD_CTRL05);
val &= ~0x0000000f;
// D17 D16
val |= 1<<2|1<<0;
writel(val,SYS_BASE + SYS_PAD_CTRL05);
break;
case CPU_PANEL_16BIT_MODE:
val =readl(SYS_BASE + SYS_PAD_CTRL04);
val &= ~0xFFFFFFF0;
//d15 d14 d13 d12 d11 d10 d19 d8 d7 d6 d5 d4 d3 d2
val |= 1<<30|1<<28|1<<26|1<<24|1<<22|1<<20|1<<18|1<<16|1<<14|1<<12|1<<10|1<<8|1<<6|1<<4;//_016BIT_MODE 接D2-D17
writel(val,SYS_BASE + SYS_PAD_CTRL04);
val = readl(SYS_BASE + SYS_PAD_CTRL05);
val &= ~0x0000000f;
// D17 D16
val |= 1<<2|1<<0;
writel(val,SYS_BASE + SYS_PAD_CTRL05);
break;
case CPU_PANEL_9BIT_MODE:
val = readl(SYS_BASE + SYS_PAD_CTRL04);
val &= ~0xFFFC0000;
//d15 d14 d13 d12 d11 d10 d19
val |= 1<<30|1<<28|1<<26|1<<24|1<<22|1<<20|1<<18;//_09BIT_MODE 接D9-D17
writel(val,SYS_BASE + SYS_PAD_CTRL04);
val = readl(SYS_BASE + SYS_PAD_CTRL05);
val &= ~0x0000000f;
// D17 D16
val |= 1<<2|1<<0;
writel(val,SYS_BASE + SYS_PAD_CTRL05);
break;
case CPU_PANEL_8BIT_MODE:
val = readl(SYS_BASE + SYS_PAD_CTRL04);
val &= ~0xFFF00000;
//d15 d14 d13 d12 d11 d10
val |= 1<<30|1<<28|1<<26|1<<24|1<<22|1<<20;//_08BIT_MODE 接D10-D17
writel(val,SYS_BASE + SYS_PAD_CTRL04);
val=readl(SYS_BASE + SYS_PAD_CTRL05);
val &= ~0x0000000f;
// D17 D16
val |= 1<<2|1<<0;
writel(val,SYS_BASE + SYS_PAD_CTRL05);
break;
default:
break;
}
}
void CPU_Pannel_Reset(void)
{
u32 val=0;
val=readl(LCD_BASE + CPU_SCR_CTRL);
val|= BIT(9);
writel(val,LCD_BASE + CPU_SCR_CTRL);//cpu reset 1
mdelay(20);
val &= ~(BIT(9));
writel(val,LCD_BASE + CPU_SCR_CTRL);//cpu reset 0
mdelay(20);
val|= BIT(9);
writel(val,LCD_BASE + CPU_SCR_CTRL);//cpu reset 1
mdelay(20);
}
void SetCpuSoftwareMode()
{
u32 val=0;
val=readl(LCD_BASE + CPU_SCR_CTRL);
val |=BIT(0);
writel(val,LCD_BASE + CPU_SCR_CTRL);
}
void SetCpuHardwareMode()
{
u32 val=0;
val=readl(LCD_BASE + CPU_SCR_CTRL);
val &=~(BIT(0));
writel(val,LCD_BASE + CPU_SCR_CTRL);
}
u32 transfor18BitDate(u8 Interface,u16 dat)
{
u32 tempDat = 0x00;
switch(Interface)
{
case CPU_PANEL_18BIT_MODE:
tempDat = (dat>>8)&0xff;
tempDat |= dat & 0xff;
break;
case CPU_PANEL_16BIT_MODE:
tempDat = (dat>>8)&0xff;
tempDat <<= 9;
tempDat |= dat & 0xff;
tempDat <<= 1;
break;
case CPU_PANEL_9BIT_MODE:
tempDat = dat&0xff;
tempDat <<= 10;
break;
case CPU_PANEL_8BIT_MODE:
tempDat = dat&0xff;
tempDat <<= 10;
break;
default:
break;
}
return tempDat;
}
void WriteCpuCmd(u8 Interface,u16 Val)
{
u32 tmpDat;
tmpDat=transfor18BitDate(Interface,Val);
tmpDat |=( RD_1);
tmpDat &=( CS_0);
tmpDat &=( RS_0);
writel(tmpDat,LCD_BASE + CPU_SCR_SOFT);
tmpDat&=( WR_0);
writel(tmpDat,LCD_BASE + CPU_SCR_SOFT);
tmpDat |=( WR_1);
writel(tmpDat,LCD_BASE + CPU_SCR_SOFT);
tmpDat |=( CS_1);
tmpDat &=( RS_0);
writel(tmpDat,LCD_BASE + CPU_SCR_SOFT);
}
void WriteCpuData(u8 Interface,u16 Val)
{
u32 tmpDat;
tmpDat=transfor18BitDate(Interface,Val);
tmpDat |=( RD_1);
tmpDat &=( CS_0);
tmpDat |=( RS_1);
writel(tmpDat,LCD_BASE + CPU_SCR_SOFT);
tmpDat&=( WR_0);
writel(tmpDat,LCD_BASE + CPU_SCR_SOFT);
tmpDat |=( WR_1);
writel(tmpDat,LCD_BASE + CPU_SCR_SOFT);
tmpDat |=( CS_1);
tmpDat |=( RS_1);
writel(tmpDat,LCD_BASE + CPU_SCR_SOFT);
}
void InitalCPU_TCXD035ABFON_8bit(void)
{
uint16_t i,j,k=0;
WR_Com(0x5E); // SET password
WR_D(0xA5);
mdelay(100);
WR_Com(0x49); // SET password
WR_D(0x0E);
WR_D(0x00);
WR_D(0x00);
WR_D(0xA5);
WR_Com(0x61); // Set Power Control
WR_D(0x8F); // n=2, all power on
WR_D(0x44);
WR_D(0x02);
WR_D(0xA5);
WR_Com(0x5A); // Set Power Control
WR_D(0x70); // n=2, all power on
WR_D(0x21);
WR_D(0xA5);
WR_D(0xA5);
WR_Com(0x71); //Set Electronic Volume1
WR_D(0x1E); //VCOM=-0.675V
WR_D( 0x0B); //VGH=15V
WR_D(0x0B); //VGL=-10V
WR_D(0xA5);
WR_Com( 0x72); //Set Electronic Volume2
WR_D(0x17); //GVDD=5.4V
WR_D(0x17); //GVCL=-5.4V
WR_D(0xA5);
WR_D(0xA5);
WR_Com( 0x81); //Set Gamma Positive1
WR_D(0x00);
WR_D(0x16);
WR_D(0x1B);
WR_D(0x1C);
WR_Com(0x82); //Set Gamma Positive2
WR_D(0x1E);
WR_D(0x1F);
WR_D(0x20);
WR_D(0x21);
WR_Com(0x83); //Set Gamma Positive3
WR_D(0x23);
WR_D(0x24);
WR_D(0x26);
WR_D(0x28);
WR_Com(0x84); //Set Gamma Positive4
WR_D(0x2B);
WR_D(0x2F);
WR_D(0x34);
WR_D(0x3F);
WR_Com(0x89); //Set Gamma Negative1
WR_D(0x00);
WR_D(0x16);
WR_D(0x1B);
WR_D(0x1C);
WR_Com(0x8A); //Set Gamma Negative2
WR_D(0x1E);
WR_D(0x1F);
WR_D(0x20);
WR_D(0x21);
WR_Com(0x8B); //Set Gamma Negative3
WR_D(0x23);
WR_D(0x24);
WR_D(0x26);
WR_D(0x28);
WR_Com(0x8C); //Set Gamma Negative4
WR_D(0x2B);
WR_D(0x2F);
WR_D(0x34);
WR_D(0x3F);
WR_Com(0x21); //Set Memory Address Control
WR_D(0x01);
WR_D(0xA5);
WR_D(0xA5);
WR_D(0xA5);
WR_Com(0x13); // SLEEP OUT
WR_D(0xA5); // VOFREG
mdelay(100);
WR_Com(0x25); //Set Page Address
WR_D(0x02); //from page0
WR_D(0xA5); //to page 159
WR_D(0xA5);
WR_D(0xA5);
WR_Com(0x22); //Set Page Address
WR_D(0x00); //from page0
WR_D(0x9F); //to page 159
WR_D(0x00);
WR_D(0xA5);
WR_Com(0x24);
WR_D(0x00);
WR_D(0xA5);
WR_D(0xA5);
WR_D(0xA5);
WR_Com(0x23); //Set Column Address
WR_D(0x00); //from col0
WR_D(0x00);
WR_D(0x00); //to col239
WR_D(0xEF);
WR_Com(0x12);
WR_D(0xA5);
WR_Com(0x3a);
WR_D(0xA5);
for(i=0;i<38400;i++)
WR_D(0xff);
// 16灰阶
for(k=0;k<16;k++) {
for(i=0;i<10;i++) {
for(j=0;j<240;j++)
WR_D(k<<4|k);
}
}
};
void Cpulcd_Init(void)
{
ConfigCpuInit();
ConfigCpuPadmux(CPU_PANEL_DATA);
CPU_Pannel_Reset();
SetCpuSoftwareMode();
InitalCPU_TCXD035ABFON_8bit();
SetCpuHardwareMode();
}
#endif

View File

@ -0,0 +1,349 @@
#include "FreeRTOS.h"
#include "chip.h"
#define DMA_CH_NUM 4
#define DMA_BLOCK_SIZE 0xfff
#define rDMACIntStatus *((volatile unsigned int *)(REGS_DMAC_BASE + 0x000))
#define rDMACIntTCStatus *((volatile unsigned int *)(REGS_DMAC_BASE + 0x004))
#define rDMACIntTCClear *((volatile unsigned int *)(REGS_DMAC_BASE + 0x008))
#define rDMACIntErrorStatus *((volatile unsigned int *)(REGS_DMAC_BASE + 0x00C))
#define rDMACIntErrClr *((volatile unsigned int *)(REGS_DMAC_BASE + 0x010))
#define rDMACRawIntTCStatus *((volatile unsigned int *)(REGS_DMAC_BASE + 0x014))
#define rDMACRawIntErrorStatus *((volatile unsigned int *)(REGS_DMAC_BASE + 0x018))
#define rDMACEnbldChns *((volatile unsigned int *)(REGS_DMAC_BASE + 0x01C))
#define rDMACSoftBReq *((volatile unsigned int *)(REGS_DMAC_BASE + 0x020))
#define rDMACSoftSReq *((volatile unsigned int *)(REGS_DMAC_BASE + 0x024))
#define rDMACSoftLBReq *((volatile unsigned int *)(REGS_DMAC_BASE + 0x028))
#define rDMACSoftLSReq *((volatile unsigned int *)(REGS_DMAC_BASE + 0x02C))
#define rDMACConfiguration *((volatile unsigned int *)(REGS_DMAC_BASE + 0x030))
#define rDMACSync *((volatile unsigned int *)(REGS_DMAC_BASE + 0x034))
#define rDMACCxSrcAddr(x) *((volatile unsigned int *)(REGS_DMAC_BASE + 0x100 + 0x00 + (x)*0x20))
#define rDMACCxDestAddr(x) *((volatile unsigned int *)(REGS_DMAC_BASE + 0x100 + 0x04 + (x)*0x20))
#define rDMACCxLLI(x) *((volatile unsigned int *)(REGS_DMAC_BASE + 0x100 + 0x08 + (x)*0x20))
#define rDMACCxControl(x) *((volatile unsigned int *)(REGS_DMAC_BASE + 0x100 + 0x0C + (x)*0x20))
#define rDMACCxConfiguration(x) *((volatile unsigned int *)(REGS_DMAC_BASE + 0x100 + 0x10 + (x)*0x20))
static struct dma_chan dma_ch[DMA_CH_NUM] = {0};
static SemaphoreHandle_t dma_mutex;
static QueueHandle_t dma_m2m_done = NULL;
struct dma_chan *dma_request_channel(int favorite_ch)
{
int i;
configASSERT (favorite_ch >= 0 && favorite_ch < DMA_CH_NUM)
xSemaphoreTake(dma_mutex, portMAX_DELAY);
if (!dma_ch[favorite_ch].in_use) {
dma_ch[favorite_ch].chan_id = favorite_ch;
dma_ch[favorite_ch].in_use = 1;
xSemaphoreGive(dma_mutex);
return &dma_ch[favorite_ch];
}
for (i = 0; i < DMA_CH_NUM; i++) {
if (!dma_ch[i].in_use) {
dma_ch[i].chan_id = i;
dma_ch[i].in_use = 1;
xSemaphoreGive(dma_mutex);
return &dma_ch[i];
}
}
xSemaphoreGive(dma_mutex);
return NULL;
}
void dma_release_channel(struct dma_chan *chan)
{
/* This channel is not in use, bail out */
if (!chan->in_use)
return;
dma_stop_channel(chan);
xSemaphoreTake(dma_mutex, portMAX_DELAY);
/* This channel is not in use anymore, free it */
chan->irq_callback = NULL;
chan->callback_param = NULL;
chan->in_use = 0;
xSemaphoreGive(dma_mutex);
}
/*
* Fix sconfig's burst size according to dw_dmac. We need to convert them as:
* 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
*
* NOTE: burst size 2 is not supported by controller.
*
* This can be done by finding least significant bit set: n & (n - 1)
*/
static void convert_burst(u32 *maxburst)
{
if (*maxburst > 1)
*maxburst = fls(*maxburst) - 2;
else
*maxburst = 0;
}
int dma_config_channel(struct dma_chan *chan, struct dma_config *config)
{
unsigned int ctl;
unsigned int cfg;
unsigned int src_width, dst_width;
unsigned int src_id = 0, dst_id = 0;
unsigned int di = 0, si = 0;
unsigned int data_width = (1 << DMA_BUSWIDTH_4_BYTES);
convert_burst(&config->src_maxburst);
convert_burst(&config->dst_maxburst);
if (config->direction == DMA_MEM_TO_DEV) {
src_width = __ffs(data_width | config->src_addr | config->transfer_size);
dst_width = config->dst_addr_width;
dst_id = config->dst_id;
si = 1;
} else if (config->direction == DMA_DEV_TO_MEM) {
src_width = config->src_addr_width;
dst_width = __ffs(data_width | config->dst_addr | config->transfer_size);
src_id = config->src_id;
di = 1;
} else if (config->direction == DMA_MEM_TO_MEM) {
src_width = __ffs(data_width | config->src_addr | config->transfer_size);
dst_width = __ffs(data_width | config->dst_addr | config->transfer_size);
si = 1;
di = 1;
}
ctl = (1 << 31) | /* [31] I Read/write Terminal count interrupt enable bit */
(0 << 28) | /* [30:28] Prot Read/write Protection */
(di << 27) | /* [27] DI Read/write Destination increment */
(si << 26) | /* [26] SI Read/write Source increment */
(0 << 25) | /* [25] D Read/write Destination AHB master select */
(1 << 24) | /* [24] S Read/write Source AHB master select */
(dst_width << 21) | /* [23:21] DWidth Read/write Destination transfer width */
(src_width << 18) | /* [20:18] SWidth Read/write Source transfer width */
(config->dst_maxburst << 15) | /* [17:15] DBSize Read/write Destination burst size */
(config->src_maxburst << 12) | /* [14:12] SBSize Read/write Source burst size */
0; /* [11:0] TransferSize Read/write Transfer size */
cfg = (0 << 18) | /* [18] H Read/write Halt */
(0 << 16) | /* [16] L Read/write Lock */
(1 << 15) | /* [15] ITC Read/write Terminal count interrupt mask */
(1 << 14) | /* [14] IE Read/write Interrupt error mask */
(config->direction << 11) | /* [13:11] FlowCntrl Read/write Flow control and transfer type */
(dst_id << 6) | /* [9:6] DestPeripheral Read/write Destination peripheral */
(src_id << 1) | /* [4:1] SrcPeripheral Read/write Source peripheral */
0; /* [0] Channel enable */
if ((config->transfer_size >> src_width) > DMA_BLOCK_SIZE) {
unsigned int blk_size = config->transfer_size >> src_width;
int lli_num;
int i;
lli_num = (blk_size + DMA_BLOCK_SIZE - 1) / DMA_BLOCK_SIZE - 1;
if (chan->lli) {
vPortFree(chan->lli);
chan->lli = NULL;
}
chan->lli = pvPortMalloc(sizeof(struct dma_lli) * lli_num);
if (!chan->lli)
return -ENOMEM;
for (i = 0; i < lli_num - 1; i++) {
chan->lli[i].src_addr = config->src_addr + (si ? (i + 1) : 0) * (DMA_BLOCK_SIZE << src_width);
chan->lli[i].dst_addr = config->dst_addr + (di ? (i + 1) : 0) * (DMA_BLOCK_SIZE << src_width);
chan->lli[i].next_lli = (unsigned int)&chan->lli[i + 1];
chan->lli[i].control = ctl | DMA_BLOCK_SIZE;
if (!config->blkint_en)
chan->lli[i].control &= ~(1 << 31);
}
chan->lli[i].src_addr = config->src_addr + (si ? (i + 1) : 0) * (DMA_BLOCK_SIZE << src_width);
chan->lli[i].dst_addr = config->dst_addr + (di ? (i + 1) : 0) * (DMA_BLOCK_SIZE << src_width);
chan->lli[i].next_lli = 0;
chan->lli[i].control = ctl | (blk_size - DMA_BLOCK_SIZE * lli_num);
CP15_clean_dcache_for_dma((unsigned int)chan->lli,
(unsigned int)chan->lli + sizeof(struct dma_lli) * lli_num);
rDMACCxSrcAddr(chan->chan_id) = config->src_addr;
rDMACCxDestAddr(chan->chan_id) = config->dst_addr;
rDMACCxLLI(chan->chan_id) = (unsigned int)chan->lli | 1;
rDMACCxControl(chan->chan_id) = ctl & ~(1 << 31) | DMA_BLOCK_SIZE;
rDMACCxConfiguration(chan->chan_id) = cfg;
} else {
rDMACCxSrcAddr(chan->chan_id) = config->src_addr;
rDMACCxDestAddr(chan->chan_id) = config->dst_addr;
rDMACCxLLI(chan->chan_id) = 0;
rDMACCxControl(chan->chan_id) = ctl | (config->transfer_size >> src_width);
rDMACCxConfiguration(chan->chan_id) = cfg;
}
return 0;
}
int dma_register_complete_callback(struct dma_chan *chan,
void (*callback)(void *param, unsigned int mask),
void *callback_param)
{
chan->irq_callback = callback;
chan->callback_param = callback_param;
return 0;
}
int dma_start_channel(struct dma_chan *chan)
{
configASSERT(chan && chan->chan_id < DMA_CH_NUM);
rDMACCxConfiguration(chan->chan_id) |= (1 << 0);
return 0;
}
int dma_stop_channel(struct dma_chan *chan)
{
unsigned int timeout = xTaskGetTickCount() + 1000;
configASSERT(chan && chan->chan_id < DMA_CH_NUM);
xSemaphoreTake(dma_mutex, portMAX_DELAY);
if(!(rDMACEnbldChns & (1 << chan->chan_id))) {
xSemaphoreGive(dma_mutex);
return 0;
}
// A channel can be disabled by clearing the Enable bit.
rDMACCxConfiguration(chan->chan_id) &= ~1;
// waiting
while(rDMACEnbldChns & (1 << chan->chan_id)) {
if(xTaskGetTickCount() >= timeout) {
printf ("dma_stop_channel %d timeout\n", chan->chan_id);
xSemaphoreGive(dma_mutex);
return -1;
}
vTaskDelay(pdMS_TO_TICKS(10));
}
if (chan->lli) {
vPortFree(chan->lli);
chan->lli = NULL;
}
xSemaphoreGive(dma_mutex);
return 0;
}
static void dma_m2m_callback(void *param, unsigned int mask)
{
if(dma_m2m_done)
xQueueSendFromISR(dma_m2m_done, NULL, 0);
}
int dma_m2mcpy(unsigned int dst_addr, unsigned int src_addr, int size)
{
struct dma_config cfg = {0};
int ret = -1;
struct dma_chan *dma_ch = dma_request_channel(0);
if (!dma_ch) {
printf("%s() dma_request_channel fail.\n", __func__);
return -1;
}
cfg.dst_addr_width = DMA_BUSWIDTH_4_BYTES;
cfg.dst_maxburst = 256;
cfg.src_addr_width = DMA_BUSWIDTH_4_BYTES;
cfg.src_maxburst = 256;
cfg.transfer_size = size;
cfg.src_addr = src_addr;
cfg.dst_addr = dst_addr;
cfg.direction = DMA_MEM_TO_MEM;
dma_clean_range(src_addr, src_addr + size);
dma_inv_range(dst_addr, dst_addr + size);
ret = dma_config_channel(dma_ch, &cfg);
if (ret) {
printf("%s, dma_config_channel failed.\n", __func__);
goto exit;
}
dma_register_complete_callback(dma_ch, dma_m2m_callback, NULL);
xQueueReset(dma_m2m_done);
dma_start_channel(dma_ch);
if (xQueueReceive(dma_m2m_done, NULL, pdMS_TO_TICKS(1000)) != pdTRUE) {
printf("dma_m2mcpy wait timeout.\n");
ret = -ETIMEDOUT;
goto exit;
}
dma_stop_channel(dma_ch);
ret = 0;
exit:
if(dma_ch)
dma_release_channel(dma_ch);
return ret;
}
static void dma_int_handler(void *param)
{
unsigned int err_status, tfr_status;
struct dma_chan *chan;
unsigned int irqmask = 0;
int i;
err_status = rDMACIntErrorStatus;
tfr_status = rDMACIntTCStatus;
rDMACIntTCClear = tfr_status;
rDMACIntErrClr = err_status;
for(i= 0; i< DMA_CH_NUM; i++) {
irqmask = 0;
if (err_status & (1 << i)) {
irqmask |= DMA_INT_ERR;
}
if (tfr_status & (1 << i)) {
irqmask |= DMA_INT_TC;
}
if (!irqmask)
continue;
chan = &dma_ch[i];
if (chan->irq_callback)
chan->irq_callback(chan->callback_param, irqmask);
}
}
int dma_init(void)
{
dma_mutex = xSemaphoreCreateMutex();
dma_m2m_done = xQueueCreate(1, 0);
sys_soft_reset(softreset_dma);
request_irq(DMA_IRQn, 0, dma_int_handler, NULL);
/* Clear all interrupts on all channels. */
rDMACIntTCClear = 0xff;
rDMACIntErrClr = 0xff;
rDMACConfiguration |= (1<<0); // [0] E Read/write PrimeCell DMAC enable
return 0;
}

View File

@ -0,0 +1,987 @@
#include "FreeRTOS.h"
#include "chip.h"
#include "board.h"
#include "pinctrl.h"
#include <string.h>
#define SPI0_CS0_GPIO 32
#define SPI0_IO0_GPIO 34
/* Register offsets */
#define DW_SPI_CTRL0 0x00
#define DW_SPI_CTRL1 0x04
#define DW_SPI_SSIENR 0x08
#define DW_SPI_MWCR 0x0c
#define DW_SPI_SER 0x10
#define DW_SPI_BAUDR 0x14
#define DW_SPI_TXFLTR 0x18
#define DW_SPI_RXFLTR 0x1c
#define DW_SPI_TXFLR 0x20
#define DW_SPI_RXFLR 0x24
#define DW_SPI_SR 0x28
#define DW_SPI_IMR 0x2c
#define DW_SPI_ISR 0x30
#define DW_SPI_RISR 0x34
#define DW_SPI_TXOICR 0x38
#define DW_SPI_RXOICR 0x3c
#define DW_SPI_RXUICR 0x40
#define DW_SPI_MSTICR 0x44
#define DW_SPI_ICR 0x48
#define DW_SPI_DMACR 0x4c
#define DW_SPI_DMATDLR 0x50
#define DW_SPI_DMARDLR 0x54
#define DW_SPI_IDR 0x58
#define DW_SPI_VERSION 0x5c
#define DW_SPI_DR 0x60
#define DW_SPI_QSPI_CTRL0 0xf4
/* Bit fields in CTRLR0 */
#define SPI_DFS_OFFSET 0
#define SPI_FRF_OFFSET 4
#define SPI_FRF_SPI 0x0
#define SPI_FRF_SSP 0x1
#define SPI_FRF_MICROWIRE 0x2
#define SPI_FRF_RESV 0x3
#define SPI_MODE_OFFSET 6
#define SPI_SCPH_OFFSET 6
#define SPI_SCOL_OFFSET 7
#define SPI_TMOD_OFFSET 8
#define SPI_TMOD_MASK (0x3 << SPI_TMOD_OFFSET)
#define SPI_TMOD_TR 0x0 /* xmit & recv */
#define SPI_TMOD_TO 0x1 /* xmit only */
#define SPI_TMOD_RO 0x2 /* recv only */
#define SPI_TMOD_EPROMREAD 0x3 /* eeprom read mode */
#define SPI_SLVOE_OFFSET 10
#define SPI_SRL_OFFSET 11
#define SPI_CFS_OFFSET 12
#define SPI_DFS32_OFFSET 16
#define SPI_DAF_OFFSET 21
#define SPI_DAF_STANDARD 0
#define SPI_DAF_DUAL 1
#define SPI_DAF_QUAD 2
/* Bit fields in QSPI_CTRLR0 */
#define SPI_TRANS_TYPE_OFFSET 0
#define SPI_ADDR_LENGTH_OFFSET 2
#define SPI_INST_LENGTH_OFFSET 8
#define SPI_WAIT_CYCLES_OFFSET 11
/* Bit fields in SR, 7 bits */
#define SR_MASK 0x7f /* cover 7 bits */
#define SR_BUSY (1 << 0)
#define SR_TF_NOT_FULL (1 << 1)
#define SR_TF_EMPT (1 << 2)
#define SR_RF_NOT_EMPT (1 << 3)
#define SR_RF_FULL (1 << 4)
#define SR_TX_ERR (1 << 5)
#define SR_DCOL (1 << 6)
/* Bit fields in ISR, IMR, RISR, 7 bits */
#define SPI_INT_TXEI (1 << 0)
#define SPI_INT_TXOI (1 << 1)
#define SPI_INT_RXUI (1 << 2)
#define SPI_INT_RXOI (1 << 3)
#define SPI_INT_RXFI (1 << 4)
#define SPI_INT_MSTI (1 << 5)
/* Bit fields in DMACR */
#define SPI_DMA_RDMAE (1 << 0)
#define SPI_DMA_TDMAE (1 << 1)
/* TX RX interrupt level threshold, max can be 256 */
#define SPI_INT_THRESHOLD 32
enum dw_ssi_type {
SSI_MOTO_SPI = 0,
SSI_TI_SSP,
SSI_NS_MICROWIRE,
};
struct dw_spi;
struct dw_spi_dma_ops {
int (*dma_init)(struct dw_spi *dws);
void (*dma_exit)(struct dw_spi *dws);
int (*dma_setup)(struct dw_spi *dws, struct spi_message *message);
bool (*can_dma)(struct dw_spi *dws, struct spi_message *message);
int (*dma_transfer)(struct dw_spi *dws, struct spi_message *message);
void (*dma_stop)(struct dw_spi *dws);
};
/* Slave spi_dev related */
struct chip_data {
u8 cs; /* chip select pin */
u8 tmode; /* TR/TO/RO/EEPROM */
u8 type; /* SPI/SSP/MicroWire */
u8 poll_mode; /* 1 means use poll mode */
u8 enable_dma;
u16 clk_div; /* baud rate divider */
u16 qspi_clk_div;
u32 speed_hz; /* baud rate */
void (*cs_control)(u32 command);
};
struct dw_spi {
struct spi_slave slave;
QueueHandle_t xfer_done;
enum dw_ssi_type type;
void __iomem *regs;
struct clk *clk;
unsigned long paddr;
int irq;
u32 fifo_len; /* depth of the FIFO buffer */
u32 max_freq; /* max bus freq supported */
u16 bus_num;
u16 num_cs; /* supported slave numbers */
u32 cs_gpio;
/* Current message transfer state info */
size_t len;
void *tx;
void *tx_end;
void *rx;
void *rx_end;
u32 rxlevel;
int dma_mapped;
char *rx_dummy_buffer;
u8 n_bytes; /* current is a 1/2 bytes op */
u32 dma_width;
void (*transfer_handler)(struct dw_spi *dws);
u32 current_freq; /* frequency in hz */
u32 current_qspi_freq;
/* DMA info */
int dma_inited;
struct dma_chan *txchan;
struct dma_chan *rxchan;
unsigned long dma_chan_busy;
dma_addr_t dma_addr; /* phy address of the Data register */
const struct dw_spi_dma_ops *dma_ops;
void *dma_tx;
void *dma_rx;
/* Bus interface info */
void *priv;
struct chip_data *chip;
};
/*
* Each SPI slave device to work with dw_api controller should
* has such a structure claiming its working mode (poll or PIO/DMA),
* which can be save in the "controller_data" member of the
* struct spi_device.
*/
struct dw_spi_chip {
u8 poll_mode; /* 1 for controller polling mode */
u8 type; /* SPI/SSP/MicroWire */
void (*cs_control)(u32 command);
};
static inline u32 dw_readl(struct dw_spi *dws, u32 offset)
{
return readl((u32)dws->regs + offset);
}
static inline void dw_writel(struct dw_spi *dws, u32 offset, u32 val)
{
writel(val, (u32)dws->regs + offset);
}
static inline u32 dw_read_io_reg(struct dw_spi *dws, u32 offset)
{
return dw_readl(dws, offset);
}
static inline void dw_write_io_reg(struct dw_spi *dws, u32 offset, u32 val)
{
dw_writel(dws, offset, val);
}
static inline void spi_enable_chip(struct dw_spi *dws, int enable)
{
dw_writel(dws, DW_SPI_SSIENR, (enable ? 1 : 0));
}
static inline void spi_set_clk(struct dw_spi *dws, u16 div)
{
dw_writel(dws, DW_SPI_BAUDR, div);
}
/* Disable IRQ bits */
static inline void spi_mask_intr(struct dw_spi *dws, u32 mask)
{
u32 new_mask;
new_mask = dw_readl(dws, DW_SPI_IMR) & ~mask;
dw_writel(dws, DW_SPI_IMR, new_mask);
}
/* Enable IRQ bits */
static inline void spi_umask_intr(struct dw_spi *dws, u32 mask)
{
u32 new_mask;
new_mask = dw_readl(dws, DW_SPI_IMR) | mask;
dw_writel(dws, DW_SPI_IMR, new_mask);
}
/*
* This does disable the SPI controller, interrupts, and re-enable the
* controller back. Transmit and receive FIFO buffers are cleared when the
* device is disabled.
*/
static inline void spi_reset_chip(struct dw_spi *dws)
{
spi_enable_chip(dws, 0);
spi_mask_intr(dws, 0xff);
spi_enable_chip(dws, 1);
}
/* static inline void spi_shutdown_chip(struct dw_spi *dws)
{
spi_enable_chip(dws, 0);
spi_set_clk(dws, 0);
} */
/* Return the max entries we can fill into tx fifo */
static inline u32 tx_max(struct dw_spi *dws)
{
u32 tx_left, tx_room, rxtx_gap;
tx_left = ((u32)dws->tx_end - (u32)dws->tx) / dws->n_bytes;
tx_room = dws->fifo_len - dw_readl(dws, DW_SPI_TXFLR);
/*
* Another concern is about the tx/rx mismatch, we
* though to use (dws->fifo_len - rxflr - txflr) as
* one maximum value for tx, but it doesn't cover the
* data which is out of tx/rx fifo and inside the
* shift registers. So a control from sw point of
* view is taken.
*/
rxtx_gap = (((u32)dws->rx_end - (u32)dws->rx) - ((u32)dws->tx_end - (u32)dws->tx))
/ dws->n_bytes;
return configMIN(tx_left, configMIN(tx_room, (u32) (dws->fifo_len - rxtx_gap)));
}
/* Return the max entries we should read out of rx fifo */
static inline u32 rx_max(struct dw_spi *dws)
{
u32 rx_left = ((u32)dws->rx_end - (u32)dws->rx) / dws->n_bytes;
return configMIN(rx_left, dw_readl(dws, DW_SPI_RXFLR));
}
static void dw_writer(struct dw_spi *dws)
{
u32 max = tx_max(dws);
u32 txw = 0;
while (max--) {
/* Set the tx word if the transfer's original "tx" is not null */
if ((u32)dws->tx_end - dws->len) {
if (dws->n_bytes == 1)
txw = *(u8 *)(dws->tx);
else if (dws->n_bytes == 2)
txw = *(u16 *)(dws->tx);
else
txw = *(u32 *)(dws->tx);
}
dw_write_io_reg(dws, DW_SPI_DR, txw);
dws->tx = (u8*)dws->tx + dws->n_bytes;
}
}
static void dw_reader(struct dw_spi *dws)
{
u32 max = rx_max(dws);
u32 rxw;
while (max--) {
rxw = dw_read_io_reg(dws, DW_SPI_DR);
/* Care rx only if the transfer's original "rx" is not null */
if ((u32)dws->rx_end - dws->len) {
if (dws->n_bytes == 1)
*(u8 *)(dws->rx) = rxw;
else if (dws->n_bytes == 2)
*(u16 *)(dws->rx) = rxw;
else
*(u32 *)(dws->rx) = rxw;
}
dws->rx = (u8*)dws->rx + dws->n_bytes;
}
}
static void int_error_stop(struct dw_spi *dws, const char *msg)
{
spi_reset_chip(dws);
dev_err(&dws->master->dev, "%s\n", msg);
}
static void interrupt_transfer(struct dw_spi *dws)
{
u16 irq_status = dw_readl(dws, DW_SPI_ISR);
/* Error handling */
if (irq_status & (SPI_INT_TXOI | SPI_INT_RXOI | SPI_INT_RXUI)) {
dw_readl(dws, DW_SPI_ICR);
int_error_stop(dws, "interrupt_transfer: fifo overrun/underrun");
xQueueSendFromISR(dws->xfer_done, NULL, 0);
return;
}
dw_reader(dws);
if (dws->rx_end == dws->rx) {
spi_mask_intr(dws, SPI_INT_TXEI);
xQueueSendFromISR(dws->xfer_done, NULL, 0);
return;
}
if (irq_status & SPI_INT_TXEI) {
spi_mask_intr(dws, SPI_INT_TXEI);
dw_writer(dws);
/* Enable TX irq always, it will be disabled when RX finished */
spi_umask_intr(dws, SPI_INT_TXEI);
}
return;
}
static void qspi_read_interrupt(struct dw_spi *dws)
{
u16 irq_status = dw_readl(dws, DW_SPI_ISR);
//u32 rxw;
//int i;
/* Error handling */
if (irq_status & (SPI_INT_RXOI | SPI_INT_RXUI)) {
dw_readl(dws, DW_SPI_ICR);
int_error_stop(dws, "qspi_read_interrupt: fifo overrun/underrun");
xQueueSendFromISR(dws->xfer_done, NULL, 0);
return;
}
if (irq_status & SPI_INT_RXFI) {
/*for (i = 0; i < dws->rxlevel; i++) {
rxw = dw_read_io_reg(dws, DW_SPI_DR);
if (dws->n_bytes == 1)
*(u8 *)(dws->rx) = rxw;
else if (dws->n_bytes == 2)
*(u16 *)(dws->rx) = rxw;
else
*(u32 *)(dws->rx) = rxw;
dws->rx = (u8*)dws->rx + dws->n_bytes;
}*/
dw_reader(dws);
}
if (dws->rx_end == dws->rx) {
xQueueSendFromISR(dws->xfer_done, NULL, 0);
return;
}
return;
}
static void dma_transfer(struct dw_spi *dws)
{
u16 irq_status = dw_readl(dws, DW_SPI_ISR);
printf("status=0x%x.\n", irq_status);
if (!irq_status)
return;
dw_readl(dws, DW_SPI_ICR);
int_error_stop(dws, "dma_transfer: fifo overrun/underrun");
xQueueSendFromISR(dws->xfer_done, NULL, 0);
return;
}
static void dw_spi_irq(void *param)
{
struct dw_spi *dws = param;
u16 irq_status = dw_readl(dws, DW_SPI_ISR) & 0x3f;
if (!irq_status)
return;
dws->transfer_handler(dws);
}
/* Must be called inside pump_transfers() */
static int poll_transfer(struct dw_spi *dws)
{
do {
dw_writer(dws);
dw_reader(dws);
taskYIELD();
} while (dws->rx_end > dws->rx);
return 0;
}
static void dw_spi_chipselect(struct dw_spi *dws, int is_active)
{
int dev_is_lowactive = !(dws->slave.mode & SPI_CS_HIGH);
if (dws->slave.mode & SPI_NO_CS)
return;
gpio_direction_output(dws->cs_gpio, is_active ^ dev_is_lowactive);
}
static int dw_spi_calculate_timeout(struct dw_spi *dws, int size)
{
unsigned long timeout = 0;
/* Time with actual data transfer and CS change delay related to HW */
timeout = (8 + 4) * size / dws->current_freq;
/* Add extra second for scheduler related activities */
timeout += 1;
/* Double calculated timeout */
return pdMS_TO_TICKS(2 * timeout * MSEC_PER_SEC);
}
static int dw_spi_transfer_one(struct spi_slave *slave, struct spi_message *message)
{
struct dw_spi *dws = (struct dw_spi *)slave;
struct chip_data *chip = dws->chip;
u8 imask = 0;
u16 txlevel = 0;
u32 cr0;
u32 bits_per_word = 0;
unsigned long transfer_timeout;
int ret = 0;
chip->tmode = SPI_TMOD_TR;
dws->dma_mapped = 0;
dws->tx = (void *)message->send_buf;
dws->tx_end = (u8*)dws->tx + message->length;
dws->rx = message->recv_buf;
dws->rx_end = (u8*)dws->rx + message->length;
dws->len = message->length;
spi_enable_chip(dws, 0);
spi_set_clk(dws, chip->clk_div);
if (message->cs_take)
dw_spi_chipselect(dws, 1);
if (message->length & 1 || (u32)dws->tx & 1 || (u32)dws->rx & 1)
bits_per_word = 8;
else if (message->length & 3 || (u32)dws->tx & 3 || (u32)dws->rx & 3)
bits_per_word = 16;
else
bits_per_word = 32;
//printk("len=%d, bits_per_word=%d.\n", transfer->len, bits_per_word);
if (bits_per_word == 8) {
dws->n_bytes = 1;
dws->dma_width = DMA_BUSWIDTH_1_BYTE;
} else if (bits_per_word == 16) {
dws->n_bytes = 2;
dws->dma_width = DMA_BUSWIDTH_2_BYTES;
} else if (bits_per_word == 32) {
dws->n_bytes = 4;
dws->dma_width = DMA_BUSWIDTH_4_BYTES;
} else {
ret = -EINVAL;
goto end;
}
/* Default SPI mode is SCPOL = 0, SCPH = 0 */
cr0 = ((bits_per_word - 1) << SPI_DFS32_OFFSET)
| (chip->type << SPI_FRF_OFFSET)
| ((dws->slave.mode & 3) << SPI_MODE_OFFSET)
| (chip->tmode << SPI_TMOD_OFFSET);
/*
* Adjust transfer mode if necessary. Requires platform dependent
* chipselect mechanism.
*/
if (chip->cs_control) {
if (dws->rx && dws->tx)
chip->tmode = SPI_TMOD_TR;
else if (dws->rx)
chip->tmode = SPI_TMOD_RO;
else
chip->tmode = SPI_TMOD_TO;
cr0 &= ~SPI_TMOD_MASK;
cr0 |= (chip->tmode << SPI_TMOD_OFFSET);
}
dw_writel(dws, DW_SPI_CTRL0, cr0);
/* For poll mode just disable all interrupts */
spi_mask_intr(dws, 0xff);
/*
* Interrupt mode
* we only need set the TXEI IRQ, as TX/RX always happen syncronizely
*/
if (dws->dma_mapped) {
ret = dws->dma_ops->dma_setup(dws, message);
if (ret < 0) {
spi_enable_chip(dws, 1);
goto end;
}
} else if (!chip->poll_mode) {
dw_writel(dws, DW_SPI_DMACR, 0);
txlevel = configMIN(dws->fifo_len / 2, dws->len / dws->n_bytes);
dw_writel(dws, DW_SPI_TXFLTR, txlevel);
/* Set the interrupt mask */
imask |= SPI_INT_TXEI | SPI_INT_TXOI |
SPI_INT_RXUI | SPI_INT_RXOI;
spi_umask_intr(dws, imask);
dws->transfer_handler = interrupt_transfer;
}
xQueueReset(dws->xfer_done);
dw_writel(dws, DW_SPI_SER, BIT(dws->slave.cs));
spi_enable_chip(dws, 1);
if (dws->dma_mapped) {
ret = dws->dma_ops->dma_transfer(dws, message);
if (ret < 0)
goto end;
}
if (chip->poll_mode) {
ret = poll_transfer(dws);
goto end;
}
transfer_timeout = dw_spi_calculate_timeout(dws, message->length);
if (xQueueReceive(dws->xfer_done, NULL, transfer_timeout) != pdTRUE) {
int_error_stop(dws, "transfer timeout");
ret = -ETIMEDOUT;
goto end;
}
end:
if (message->cs_release)
dw_spi_chipselect(dws, 0);
return ret;
}
static int dw_qspi_read(struct spi_slave *slave, struct qspi_message *qspi_message)
{
struct dw_spi *dws = (struct dw_spi *)slave;
struct chip_data *chip = dws->chip;
struct spi_message *message = (struct spi_message *)&qspi_message->message;
u8 imask = 0;
u16 rxlevel = 0;
u32 cr0, qspi_cr0, ndf;
u32 bits_per_word = 0;
u32 addr;
unsigned long transfer_timeout;
u32 xfer_len = 0;
int ret = 0;
chip->tmode = SPI_TMOD_RO;
if (message->length & 1)
bits_per_word = 8;
else if (message->length & 3)
bits_per_word = 16;
else
bits_per_word = 32;
if (bits_per_word == 8) {
dws->n_bytes = 1;
dws->dma_width = DMA_BUSWIDTH_1_BYTE;
} else if (bits_per_word == 16) {
dws->n_bytes = 2;
dws->dma_width = DMA_BUSWIDTH_2_BYTES;
} else if (bits_per_word == 32) {
dws->n_bytes = 4;
dws->dma_width = DMA_BUSWIDTH_4_BYTES;
} else {
ret = -EINVAL;
goto end;
}
xfer_continue:
ndf = (message->length - xfer_len) / dws->n_bytes - 1;
if (ndf > 0xffff) ndf = 0xffff;
dws->dma_mapped = 1;
dws->rx = (u8*)message->recv_buf + xfer_len;
dws->len = (ndf + 1) * dws->n_bytes;
dws->rx_end = (u8*)dws->rx + dws->len;
spi_enable_chip(dws, 0);
spi_set_clk(dws, chip->qspi_clk_div);
if (message->cs_take)
dw_spi_chipselect(dws, 1);
/* Default SPI mode is SCPOL = 0, SCPH = 0 */
cr0 = ((bits_per_word - 1) << SPI_DFS32_OFFSET)
| (chip->type << SPI_FRF_OFFSET)
| ((dws->slave.mode & 3) << SPI_MODE_OFFSET)
| (chip->tmode << SPI_TMOD_OFFSET);
if (qspi_message->qspi_data_lines == 4)
cr0 |= SPI_DAF_QUAD << SPI_DAF_OFFSET;
else if (qspi_message->qspi_data_lines == 2)
cr0 |= SPI_DAF_DUAL << SPI_DAF_OFFSET;
dw_writel(dws, DW_SPI_CTRL0, cr0);
dw_writel(dws, DW_SPI_CTRL1, ndf);
qspi_cr0 = ((qspi_message->dummy_cycles & 0xf) << SPI_WAIT_CYCLES_OFFSET) |
(2 << SPI_INST_LENGTH_OFFSET) |
((qspi_message->address.size >> 2) << SPI_ADDR_LENGTH_OFFSET);
if (qspi_message->instruction.qspi_lines == 1 && qspi_message->address.qspi_lines > 1)
qspi_cr0 |= 1;
else if (qspi_message->instruction.qspi_lines > 1 && qspi_message->address.qspi_lines > 1)
qspi_cr0 |= 2;
dw_writel(dws, DW_SPI_QSPI_CTRL0, qspi_cr0);
/* For poll mode just disable all interrupts */
spi_mask_intr(dws, 0xff);
/*
* Interrupt mode
* we only need set the TXEI IRQ, as TX/RX always happen syncronizely
*/
if (dws->dma_mapped) {
ret = dws->dma_ops->dma_setup(dws, message);
if (ret < 0) {
spi_enable_chip(dws, 1);
goto end;
}
} else if (!chip->poll_mode) {
dw_writel(dws, DW_SPI_DMACR, 0);
rxlevel = 1 << __ffs(dws->len / dws->n_bytes);
while (rxlevel > dws->fifo_len / 2)
rxlevel >>= 1;
dws->rxlevel = rxlevel;
dw_writel(dws, DW_SPI_RXFLTR, rxlevel - 1);
/* Set the interrupt mask */
imask |= SPI_INT_RXUI | SPI_INT_RXOI | SPI_INT_RXFI;
spi_umask_intr(dws, imask);
dws->transfer_handler = qspi_read_interrupt;
}
xQueueReset(dws->xfer_done);
dw_writel(dws, DW_SPI_SER, BIT(dws->slave.cs));
spi_enable_chip(dws, 1);
if (dws->dma_mapped) {
ret = dws->dma_ops->dma_transfer(dws, message);
if (ret < 0)
goto end;
}
addr = qspi_message->address.content + xfer_len;
if (qspi_message->address.size == 32) {
addr = ((addr >> 24) & 0xff) | (((addr >> 16) & 0xff) << 8) |
(((addr >> 8) & 0xff) << 16) | ((addr & 0xff) << 24);
} else {
addr = ((addr >> 16) & 0xff) | (((addr >> 8) & 0xff) << 8) | ((addr & 0xff) << 16);
}
dw_write_io_reg(dws, DW_SPI_DR, qspi_message->instruction.content);
dw_write_io_reg(dws, DW_SPI_DR, addr);
transfer_timeout = dw_spi_calculate_timeout(dws, message->length);
if (xQueueReceive(dws->xfer_done, NULL, transfer_timeout) != pdTRUE) {
int_error_stop(dws, "transfer timeout");
ret = -ETIMEDOUT;
if (dws->dma_mapped)
dma_stop_channel(dws->dma_rx);
goto end;
}
if (dws->dma_mapped && dws->rx_dummy_buffer) {
memcpy(dws->rx, dws->rx_dummy_buffer, dws->len);
vPortFree(dws->rx_dummy_buffer);
dws->rx_dummy_buffer = NULL;
}
dma_stop_channel(dws->dma_rx);
xfer_len += dws->len;
if (xfer_len < message->length) {
if (message->cs_release)
dw_spi_chipselect(dws, 0);
udelay(1);
goto xfer_continue;
}
end:
if (message->cs_release)
dw_spi_chipselect(dws, 0);
return ret;
}
/* This may be called twice for each spi dev */
int dw_spi_setup(struct spi_slave *slave, struct spi_configuration *configuration)
{
struct dw_spi *dws = (struct dw_spi *)slave;
struct chip_data *chip;
/* Only alloc on first setup */
chip = dws->chip;
if (!chip) {
chip = pvPortMalloc(sizeof(struct chip_data));
if (!chip)
return -ENOMEM;
memset(chip, 0, sizeof(struct chip_data));
dws->chip = chip;
}
dws->slave.mode = configuration->mode;
chip->clk_div = (DIV_ROUND_UP(dws->max_freq, configuration->max_hz) + 1) & 0xfffe;
chip->qspi_clk_div = (DIV_ROUND_UP(dws->max_freq, configuration->qspi_max_hz) + 1) & 0xfffe;
dws->current_freq = dws->max_freq / chip->clk_div;
dws->current_qspi_freq = dws->max_freq / chip->qspi_clk_div;
printf("spi max_freq %u, current freq %u, qspi_freq %u.\n", dws->max_freq,
dws->current_freq, dws->current_qspi_freq);
gpio_direction_output(dws->cs_gpio,
!(dws->slave.mode & SPI_CS_HIGH));
return 0;
}
/* Restart the controller, disable all interrupts, clean rx fifo */
static void spi_hw_init(struct dw_spi *dws)
{
spi_reset_chip(dws);
/*
* Try to detect the FIFO depth if not set by interface driver,
* the depth could be from 2 to 256 from HW spec
*/
if (!dws->fifo_len) {
u32 fifo;
for (fifo = 1; fifo < 256; fifo++) {
dw_writel(dws, DW_SPI_TXFLTR, fifo);
if (fifo != dw_readl(dws, DW_SPI_TXFLTR))
break;
}
dw_writel(dws, DW_SPI_TXFLTR, 0);
dws->fifo_len = (fifo == 1) ? 0 : fifo;
dev_dbg(dev, "Detected FIFO size: %u bytes\n", dws->fifo_len);
}
}
static int dw_spi_add_host(struct dw_spi *dws)
{
int ret;
BUG_ON(dws == NULL);
dws->type = SSI_MOTO_SPI;
dws->dma_inited = 0;
dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR);
ret = request_irq(dws->irq, 0, dw_spi_irq, dws);
if (ret < 0) {
dev_err(dev, "can not get IRQ\n");
goto err_exit;
}
/* Basic HW init */
spi_hw_init(dws);
if (dws->dma_ops && dws->dma_ops->dma_init) {
ret = dws->dma_ops->dma_init(dws);
if (ret) {
dev_warn(dev, "DMA init failed\n");
dws->dma_inited = 0;
dws->dma_mapped = 1;
}
}
return 0;
err_exit:
return ret;
}
/* static void dw_spi_remove_host(struct dw_spi *dws)
{
if (dws->dma_ops && dws->dma_ops->dma_exit)
dws->dma_ops->dma_exit(dws);
spi_shutdown_chip(dws);
free_irq(dws->irq);
} */
void dwspi_jedec252_reset(void)
{
int i;
int si = 0;
gpio_direction_output(SPI0_CS0_GPIO, 1);
gpio_direction_output(SPI0_IO0_GPIO, 1);
udelay(300);
for (i = 0; i < 4; i++) {
gpio_direction_output(SPI0_CS0_GPIO, 0);
gpio_direction_output(SPI0_IO0_GPIO, si);
si = !si;
udelay(300);
gpio_direction_output(SPI0_CS0_GPIO, 1);
udelay(300);
}
}
static void dw_spi_dma_complete_callback(void *param, unsigned int mask)
{
struct dw_spi *dws = param;
xQueueSendFromISR(dws->xfer_done, NULL, 0);
}
static int dw_spi_dma_init(struct dw_spi *dws)
{
dws->dma_rx = dma_request_channel(SPI0_RX_DMA_CH);
if (!dws->dma_rx) {
printf("dwspi request dma channel fail.\n");
return -1;
}
return 0;
}
static int dw_spi_dma_setup(struct dw_spi *dws, struct spi_message *message)
{
dws->rxlevel = dws->fifo_len / 4;
dw_writel(dws, DW_SPI_DMARDLR, dws->rxlevel - 1);
dw_writel(dws, DW_SPI_DMACR, SPI_DMA_RDMAE);
/* Set the interrupt mask */
spi_umask_intr(dws, SPI_INT_RXUI | SPI_INT_RXOI);
dws->transfer_handler = dma_transfer;
return 0;
}
static int dw_spi_dma_transfer(struct dw_spi *dws, struct spi_message *message)
{
struct dma_config cfg = {0};
int ret;
/* Set external dma config: burst size, burst width */
cfg.dst_addr_width = dws->dma_width;
cfg.src_addr_width = dws->dma_width;
/* Match burst msize with external dma config */
cfg.dst_maxburst = dws->rxlevel;
cfg.src_maxburst = dws->rxlevel;
cfg.transfer_size = dws->len;
cfg.direction = DMA_DEV_TO_MEM;
cfg.src_addr = REGS_SPI0_BASE + DW_SPI_DR;
//if (((u32)dws->rx/* | dws->len*/) & (ARCH_DMA_MINALIGN - 1)) {
if ((u32)dws->rx & 3) {
dws->rx_dummy_buffer = pvPortMalloc(dws->len);
if (!dws->rx_dummy_buffer)
return -ENOMEM;
cfg.dst_addr = (u32)dws->rx_dummy_buffer;
} else {
cfg.dst_addr = (u32)dws->rx;
}
/* Invalidate cache before read */
CP15_flush_dcache_for_dma(cfg.dst_addr,
cfg.dst_addr + dws->len);
cfg.src_id = SPI0_RX;
ret = dma_config_channel(dws->dma_rx, &cfg);
if (ret) {
printf("dwspi failed to config dma.\n");
return -EBUSY;
}
/* Set dw_spi_dma_complete_callback as callback */
dma_register_complete_callback(dws->dma_rx, dw_spi_dma_complete_callback, dws);
dma_start_channel(dws->dma_rx);
return 0;
}
static const struct dw_spi_dma_ops dw_dma_ops = {
.dma_init = dw_spi_dma_init,
.dma_setup = dw_spi_dma_setup,
.dma_transfer = dw_spi_dma_transfer,
};
int dwspi_init(void)
{
struct dw_spi *dws;
int ret;
dwspi_jedec252_reset();
pinctrl_set_group(PGRP_SPI0);
dws = pvPortMalloc(sizeof(struct dw_spi));
if (!dws)
return -ENOMEM;
memset(dws, 0, sizeof(struct dw_spi));
dws->xfer_done = xQueueCreate(1, 0);
dws->regs = (void __iomem *)REGS_SPI0_BASE;
dws->irq = SPI0_IRQn;
dws->bus_num = 0;
dws->max_freq = ulClkGetRate(CLK_SPI0);
vClkEnable(CLK_SPI0);
dws->num_cs = 1;
dws->cs_gpio = SPI0_CS0_GPIO;
dws->slave.mode = SPI_MODE_0;
dws->slave.cs = 0;
dws->slave.xfer = dw_spi_transfer_one;
dws->slave.qspi_read = dw_qspi_read;
dws->slave.configure = dw_spi_setup;
dws->dma_ops = &dw_dma_ops;
ret = dw_spi_add_host(dws);
if (ret)
goto out;
strncpy(dws->slave.name, "spi0", 16);
spi_add_slave(&dws->slave);
return 0;
out:
return ret;
}

View File

@ -0,0 +1,859 @@
#include "FreeRTOS.h"
#include "chip.h"
#include <string.h>
#define SPI1_CS0_GPIO 23
#define USE_DMA_THRESHOLD 32
#define MALLOC_DMA_MEM_SIZE 0x1000
#define ARK_ECSPI_RXDATA 0x50
#define ARK_ECSPI_TXDATA 0x460
/* generic defines to abstract from the different register layouts */
#define ARK_INT_RR (1 << 0) /* Receive data ready interrupt */
#define ARK_INT_TE (1 << 1) /* Transmit FIFO empty interrupt */
/* The maximum bytes that a sdma BD can transfer.*/
#define MAX_SDMA_BD_BYTES (1 << 15)
#define ARK_ECSPI_CTRL_MAX_BURST 512
struct ark_ecspi_data;
struct ark_spi_devtype_data {
void (*intctrl)(struct ark_ecspi_data *, int);
int (*config)(struct ark_ecspi_data *);
void (*trigger)(struct ark_ecspi_data *);
int (*rx_available)(struct ark_ecspi_data *);
void (*reset)(struct ark_ecspi_data *);
unsigned int fifo_size;
bool has_dmamode;
};
struct ark_ecspi_data {
struct spi_slave slave;
QueueHandle_t xfer_done;
unsigned int base;
unsigned int irq;
unsigned int spi_clk;
unsigned int spi_bus_clk;
unsigned int speed_hz;
unsigned int bits_per_word;
unsigned int spi_drctl;
unsigned int count, remainder;
void (*tx)(struct ark_ecspi_data *);
void (*rx)(struct ark_ecspi_data *);
unsigned char *rx_buf;
const unsigned char *tx_buf;
unsigned int txfifo; /* number of words pushed in tx FIFO */
unsigned int read_u32;
unsigned int word_mask;
unsigned int cs_gpio;
bool is_arke;
/* DMA */
bool usedma;
u32 wml;
QueueHandle_t dma_rx_completion;
QueueHandle_t dma_tx_completion;
struct spi_message dma_message;
struct spi_message pio_message;
struct dma_chan *dma_tx;
struct dma_chan *dma_rx;
char *rx_dummy_buffer;
char *tx_dummy_buffer;
const struct ark_spi_devtype_data *devtype_data;
};
static void ark_spi_buf_rx_u8(struct ark_ecspi_data *aspi)
{
unsigned int val = readl(aspi->base + ARK_ECSPI_RXDATA);
if (aspi->rx_buf) {
if (aspi->is_arke)
*(u8*)aspi->rx_buf = val & 0xff;
else
*(u8*)aspi->rx_buf = (val >> 24) & 0xff;
aspi->rx_buf += 1;
}
}
static void ark_spi_buf_rx_u16(struct ark_ecspi_data *aspi)
{
unsigned int val = readl(aspi->base + ARK_ECSPI_RXDATA);
if (aspi->rx_buf) {
if (aspi->is_arke)
*(u16*)aspi->rx_buf = val & 0xffff;
else
*(u16*)aspi->rx_buf = (val >> 16) & 0xffff;
aspi->rx_buf += 2;
}
}
static void ark_spi_buf_tx_u8(struct ark_ecspi_data *aspi)
{
u32 val = 0;
if (aspi->tx_buf) {
if (aspi->is_arke)
val = *(u8 *)aspi->tx_buf;
else
val = *(u8 *)aspi->tx_buf << 24;
aspi->tx_buf += 1;
}
aspi->count -= 1;
writel(val, aspi->base + ARK_ECSPI_TXDATA);
}
static void ark_spi_buf_tx_u16(struct ark_ecspi_data *aspi)
{
u32 val = 0;
if (aspi->tx_buf) {
if (aspi->is_arke)
val = *(u16 *)aspi->tx_buf;
else
val = *(u16 *)aspi->tx_buf << 16;
aspi->tx_buf += 2;
}
aspi->count -=2;
writel(val, aspi->base + ARK_ECSPI_TXDATA);
}
static int ark_spi_bytes_per_word(const int bits_per_word)
{
return DIV_ROUND_UP(bits_per_word, BITS_PER_BYTE);
}
#define ARK_ECSPI_CTRL 0x08
#define ARK_ECSPI_CTRL_ENABLE (1 << 0)
#define ARK_ECSPI_CTRL_XCH (1 << 2)
#define ARK_ECSPI_CTRL_SMC (1 << 3)
#define ARK_ECSPI_CTRL_MODE_MASK (0xf << 4)
#define ARK_ECSPI_CTRL_DRCTL(drctl) ((drctl) << 16)
#define ARK_ECSPI_CTRL_POSTDIV_OFFSET 8
#define ARK_ECSPI_CTRL_PREDIV_OFFSET 12
#define ARK_ECSPI_CTRL_CS(cs) ((cs) << 18)
#define ARK_ECSPI_CTRL_BL_OFFSET 20
#define ARK_ECSPI_CTRL_BL_MASK (0xfff << 20)
#define ARK_ECSPI_CONFIG 0x0c
#define ARK_ECSPI_CONFIG_SCLKPHA(cs) (1 << ((cs) + 0))
#define ARK_ECSPI_CONFIG_SCLKPOL(cs) (1 << ((cs) + 4))
#define ARK_ECSPI_CONFIG_SBBCTRL(cs) (1 << ((cs) + 8))
#define ARK_ECSPI_CONFIG_SSBPOL(cs) (1 << ((cs) + 12))
#define ARK_ECSPI_CONFIG_SCLKCTL(cs) (1 << ((cs) + 20))
#define ARK_ECSPI_INT 0x10
#define ARK_ECSPI_INT_TEEN (1 << 0)
#define ARK_ECSPI_INT_RREN (1 << 3)
#define ARK_ECSPI_DMA 0x14
#define ARK_ECSPI_DMA_TX_WML(wml) ((wml) & 0x3f)
#define ARK_ECSPI_DMA_RX_WML(wml) ((((wml) & 0x3f) - 1) << 16)
#define ARK_ECSPI_DMA_RXT_WML(wml) (((wml) & 0x3f) << 24)
#define ARK_ECSPI_DMA_TEDEN (1 << 7)
#define ARK_ECSPI_DMA_RXDEN (1 << 23)
#define ARK_ECSPI_DMA_RXTDEN (1UL << 31)
#define ARK_ECSPI_STAT 0x18
#define ARK_ECSPI_STAT_REN (1 << 8)
#define ARK_ECSPI_STAT_RR (1 << 3)
#define ARK_ECSPI_TESTREG 0x20
#define ARK_ECSPI_TESTREG_LBC BIT(31)
static void ark_spi_buf_rx_swap_u32(struct ark_ecspi_data *aspi)
{
unsigned int val = readl(aspi->base + ARK_ECSPI_RXDATA);
if (aspi->rx_buf) {
val &= aspi->word_mask;
*(u32 *)aspi->rx_buf = val;
aspi->rx_buf += sizeof(u32);
}
}
static void ark_spi_buf_rx_swap(struct ark_ecspi_data *aspi)
{
unsigned int bytes_per_word;
bytes_per_word = ark_spi_bytes_per_word(aspi->bits_per_word);
if (aspi->read_u32) {
ark_spi_buf_rx_swap_u32(aspi);
return;
}
if (bytes_per_word == 1)
ark_spi_buf_rx_u8(aspi);
else if (bytes_per_word == 2)
ark_spi_buf_rx_u16(aspi);
}
static void ark_spi_buf_tx_swap_u32(struct ark_ecspi_data *aspi)
{
u32 val = 0;
if (aspi->tx_buf) {
val = *(u32 *)aspi->tx_buf;
val &= aspi->word_mask;
aspi->tx_buf += sizeof(u32);
}
aspi->count -= sizeof(u32);
writel(val, aspi->base + ARK_ECSPI_TXDATA);
}
static void ark_spi_buf_tx_swap(struct ark_ecspi_data *aspi)
{
u32 ctrl, val;
unsigned int bytes_per_word;
if (aspi->count == aspi->remainder) {
ctrl = readl(aspi->base + ARK_ECSPI_CTRL);
ctrl &= ~ARK_ECSPI_CTRL_BL_MASK;
if (aspi->count > ARK_ECSPI_CTRL_MAX_BURST) {
aspi->remainder = aspi->count %
ARK_ECSPI_CTRL_MAX_BURST;
val = ARK_ECSPI_CTRL_MAX_BURST * 8 - 1;
} else if (aspi->count >= sizeof(u32)) {
aspi->remainder = aspi->count % sizeof(u32);
val = (aspi->count - aspi->remainder) * 8 - 1;
} else {
aspi->remainder = 0;
val = aspi->bits_per_word - 1;
aspi->read_u32 = 0;
}
ctrl |= (val << ARK_ECSPI_CTRL_BL_OFFSET);
writel(ctrl, aspi->base + ARK_ECSPI_CTRL);
}
if (aspi->count >= sizeof(u32)) {
ark_spi_buf_tx_swap_u32(aspi);
return;
}
bytes_per_word = ark_spi_bytes_per_word(aspi->bits_per_word);
if (bytes_per_word == 1)
ark_spi_buf_tx_u8(aspi);
else if (bytes_per_word == 2)
ark_spi_buf_tx_u16(aspi);
}
/* ARK eCSPI */
static unsigned int ark_ecspi_clkdiv(struct ark_ecspi_data *aspi,
unsigned int fspi, unsigned int *fres)
{
/*
* there are two 4-bit dividers, the pre-divider divides by
* $pre, the post-divider by 2^$post
*/
unsigned int pre, post;
unsigned int fin = aspi->spi_clk;
if (fspi > fin)
return 0;
post = fls(fin) - fls(fspi);
if (fin > fspi << post)
post++;
/* now we have: (fin <= fspi << post) with post being minimal */
post = configMAX(4U, post) - 4;
if (post > 0xf) {
TRACE_ERROR("cannot set clock freq: %u (base freq: %u)\n",
fspi, fin);
return 0xff;
}
pre = DIV_ROUND_UP(fin, fspi << post) - 1;
TRACE_DEBUG("%s: fin: %u, fspi: %u, post: %u, pre: %u\n",
__func__, fin, fspi, post, pre);
/* Resulting frequency for the SCLK line. */
*fres = (fin / (pre + 1)) >> post;
return (pre << ARK_ECSPI_CTRL_PREDIV_OFFSET) |
(post << ARK_ECSPI_CTRL_POSTDIV_OFFSET);
}
static void ark_ecspi_intctrl(struct ark_ecspi_data *aspi, int enable)
{
unsigned val = 0;
if (enable & ARK_INT_TE)
val |= ARK_ECSPI_INT_TEEN;
if (enable & ARK_INT_RR)
val |= ARK_ECSPI_INT_RREN;
writel(val, aspi->base + ARK_ECSPI_INT);
}
static void ark_ecspi_trigger(struct ark_ecspi_data *aspi)
{
u32 reg;
reg = readl(aspi->base + ARK_ECSPI_CTRL);
reg |= ARK_ECSPI_CTRL_XCH;
writel(reg, aspi->base + ARK_ECSPI_CTRL);
}
static int ark_ecspi_config(struct ark_ecspi_data *aspi)
{
unsigned int ctrl = ARK_ECSPI_CTRL_ENABLE;
unsigned int clk = aspi->speed_hz, delay, reg;
unsigned int cfg = readl(aspi->base + ARK_ECSPI_CONFIG);
unsigned int chip_select = aspi->slave.cs;
/*
* The hardware seems to have a race condition when changing modes. The
* current assumption is that the selection of the channel arrives
* earlier in the hardware than the mode bits when they are written at
* the same time.
* So set master mode for all channels as we do not support slave mode.
*/
ctrl |= ARK_ECSPI_CTRL_MODE_MASK;
/*
* Enable SPI_RDY handling (falling edge/level triggered).
*/
if (aspi->slave.mode & SPI_READY)
ctrl |= ARK_ECSPI_CTRL_DRCTL(aspi->spi_drctl);
/* set clock speed */
ctrl |= ark_ecspi_clkdiv(aspi, aspi->speed_hz, &clk);
aspi->spi_bus_clk = clk;
/* set chip select to use */
ctrl |= ARK_ECSPI_CTRL_CS(chip_select);
if (aspi->usedma)
ctrl |= (32 - 1) << ARK_ECSPI_CTRL_BL_OFFSET;
else
ctrl |= (aspi->bits_per_word - 1) << ARK_ECSPI_CTRL_BL_OFFSET;
cfg |= ARK_ECSPI_CONFIG_SBBCTRL(chip_select);
if (aspi->slave.mode & SPI_CPHA)
cfg |= ARK_ECSPI_CONFIG_SCLKPHA(chip_select);
else
cfg &= ~ARK_ECSPI_CONFIG_SCLKPHA(chip_select);
if (aspi->slave.mode & SPI_CPOL) {
cfg |= ARK_ECSPI_CONFIG_SCLKPOL(chip_select);
cfg |= ARK_ECSPI_CONFIG_SCLKCTL(chip_select);
} else {
cfg &= ~ARK_ECSPI_CONFIG_SCLKPOL(chip_select);
cfg &= ~ARK_ECSPI_CONFIG_SCLKCTL(chip_select);
}
if (aspi->slave.mode & SPI_CS_HIGH)
cfg |= ARK_ECSPI_CONFIG_SSBPOL(chip_select);
else
cfg &= ~ARK_ECSPI_CONFIG_SSBPOL(chip_select);
if (aspi->usedma) {
ctrl |= ARK_ECSPI_CTRL_SMC;
}
/* CTRL register always go first to bring out controller from reset */
writel(ctrl, aspi->base + ARK_ECSPI_CTRL);
reg = readl(aspi->base + ARK_ECSPI_TESTREG);
if (aspi->slave.mode & SPI_LOOP)
reg |= ARK_ECSPI_TESTREG_LBC;
else
reg &= ~ARK_ECSPI_TESTREG_LBC;
writel(reg, aspi->base + ARK_ECSPI_TESTREG);
writel(cfg, aspi->base + ARK_ECSPI_CONFIG);
/*
* Wait until the changes in the configuration register CONFIGREG
* propagate into the hardware. It takes exactly one tick of the
* SCLK clock, but we will wait two SCLK clock just to be sure. The
* effect of the delay it takes for the hardware to apply changes
* is noticable if the SCLK clock run very slow. In such a case, if
* the polarity of SCLK should be inverted, the GPIO ChipSelect might
* be asserted before the SCLK polarity changes, which would disrupt
* the SPI communication as the device on the other end would consider
* the change of SCLK polarity as a clock tick already.
*/
delay = (2 * 1000000) / clk;
if (delay < 10) /* SCLK is faster than 100 kHz */
udelay(delay);
else /* SCLK is _very_ slow */
udelay(delay + 10);
/* enable rx fifo */
writel(ARK_ECSPI_STAT_REN, aspi->base + ARK_ECSPI_STAT);
/*
* Configure the DMA register: setup the watermark
* and enable DMA request.
*/
if (aspi->usedma)
writel(ARK_ECSPI_DMA_RX_WML(aspi->wml) |
ARK_ECSPI_DMA_TX_WML(aspi->wml) |
ARK_ECSPI_DMA_RXT_WML(aspi->wml) |
ARK_ECSPI_DMA_TEDEN | ARK_ECSPI_DMA_RXDEN |
ARK_ECSPI_DMA_RXTDEN, aspi->base + ARK_ECSPI_DMA);
else writel(0, aspi->base + ARK_ECSPI_DMA);
return 0;
}
static int ark_ecspi_rx_available(struct ark_ecspi_data *aspi)
{
return readl(aspi->base + ARK_ECSPI_STAT) & ARK_ECSPI_STAT_RR;
}
static void ark_ecspi_reset(struct ark_ecspi_data *aspi)
{
/* drain receive buffer */
while (ark_ecspi_rx_available(aspi))
readl(aspi->base + ARK_ECSPI_RXDATA);
}
static struct ark_spi_devtype_data ark_ecspi_devtype_data = {
.intctrl = ark_ecspi_intctrl,
.config = ark_ecspi_config,
.trigger = ark_ecspi_trigger,
.rx_available = ark_ecspi_rx_available,
.reset = ark_ecspi_reset,
.fifo_size = 64,
.has_dmamode = false,
};
static void ark_spi_chipselect(struct ark_ecspi_data *aspi, int is_active)
{
int dev_is_lowactive = !(aspi->slave.mode & SPI_CS_HIGH);
if (aspi->slave.mode & SPI_NO_CS)
return;
gpio_direction_output(aspi->cs_gpio, is_active ^ dev_is_lowactive);
}
static void ark_spi_push(struct ark_ecspi_data *aspi)
{
while (aspi->txfifo < aspi->devtype_data->fifo_size) {
if (!aspi->count)
break;
if (aspi->txfifo && (aspi->count == aspi->remainder))
break;
aspi->tx(aspi);
aspi->txfifo++;
}
aspi->devtype_data->trigger(aspi);
}
static void ark_spi_isr(void *param)
{
struct ark_ecspi_data *aspi = param;
while (aspi->devtype_data->rx_available(aspi)) {
aspi->rx(aspi);
aspi->txfifo--;
}
if (aspi->count) {
ark_spi_push(aspi);
return;
}
if (aspi->txfifo) {
/* No data left to push, but still waiting for rx data,
* enable receive data available interrupt.
*/
aspi->devtype_data->intctrl(
aspi, ARK_INT_RR);
return;
}
aspi->devtype_data->intctrl(aspi, 0);
xQueueSendFromISR(aspi->xfer_done, NULL, 0);
}
static int ark_spi_setupxfer(struct ark_ecspi_data *aspi,
struct spi_configuration *configuration)
{
u32 mask;
if (!configuration)
return 0;
aspi->slave.mode = configuration->mode;
aspi->bits_per_word = configuration->data_width;
aspi->speed_hz = configuration->max_hz;
/* Initialize the functions for transfer */
aspi->remainder = 0;
aspi->read_u32 = 1;
mask = (1 << aspi->bits_per_word) - 1;
aspi->rx = ark_spi_buf_rx_swap;
aspi->tx = ark_spi_buf_tx_swap;
if (aspi->bits_per_word <= 8)
aspi->word_mask = mask << 24 | mask << 16
| mask << 8 | mask;
else if (aspi->bits_per_word <= 16)
aspi->word_mask = mask << 16 | mask;
else
aspi->word_mask = mask;
aspi->devtype_data->config(aspi);
return 0;
}
static int ark_spi_calculate_timeout(struct ark_ecspi_data *aspi, int size)
{
unsigned long timeout = 0;
/* Time with actual data transfer and CS change delay related to HW */
timeout = (8 + 4) * size / aspi->spi_bus_clk;
/* Add extra second for scheduler related activities */
timeout += 1;
/* Double calculated timeout */
return pdMS_TO_TICKS(2 * timeout * MSEC_PER_SEC);
}
static bool ark_spi_can_dma(struct ark_ecspi_data *aspi, struct spi_message *transfer)
{
const u32 mszs[] = {1, 4, 8, 16};
int idx = ARRAY_SIZE(mszs) - 1;
struct spi_message *dma_xfer = &aspi->dma_message;
struct spi_message *pio_xfer = &aspi->pio_message;
int len, remainder;
if (!aspi->dma_rx)
return false;
pio_xfer->length = 0;
memcpy(dma_xfer, transfer, sizeof(struct spi_message));
remainder = transfer->length & 3;
len = transfer->length - remainder;
if (len < USE_DMA_THRESHOLD)
return false;
if ((u32)transfer->send_buf & 3 || (u32)transfer->recv_buf & 3)
return false;
if (remainder) {
dma_xfer->length = len;
memcpy(pio_xfer, transfer, sizeof(struct spi_message));
pio_xfer->length = remainder;
if (pio_xfer->send_buf)
pio_xfer->send_buf = (u8*)pio_xfer->send_buf + len;
if (pio_xfer->recv_buf)
pio_xfer->recv_buf = (u8*)pio_xfer->recv_buf + len;
}
/* dw dma busrt should be 16,8,4,1 */
for (; idx >= 0; idx--) {
if (!(len % (mszs[idx] * 4)))
break;
}
aspi->wml = mszs[idx];
return true;
}
static void ark_spi_sdma_exit(struct ark_ecspi_data *aspi)
{
if (aspi->dma_rx) {
dma_release_channel(aspi->dma_rx);
aspi->dma_rx = NULL;
}
if (aspi->dma_tx) {
dma_release_channel(aspi->dma_tx);
aspi->dma_tx = NULL;
}
if (aspi->rx_dummy_buffer) {
vPortFree(aspi->rx_dummy_buffer);
aspi->rx_dummy_buffer = NULL;
}
if (aspi->tx_dummy_buffer) {
vPortFree(aspi->tx_dummy_buffer);
aspi->tx_dummy_buffer = NULL;
}
}
static int ark_spi_sdma_init(struct ark_ecspi_data *aspi)
{
int ret;
aspi->wml = aspi->devtype_data->fifo_size / 2;
/* Prepare for TX DMA: */
aspi->dma_tx = dma_request_channel(0);
if (IS_ERR(aspi->dma_tx)) {
ret = PTR_ERR(aspi->dma_tx);
TRACE_DEBUG("can't get the TX DMA channel, error %d!\n", ret);
aspi->dma_tx = NULL;
goto err;
}
/* Prepare for RX : */
aspi->dma_rx = dma_request_channel(0);
if (IS_ERR(aspi->dma_rx)) {
ret = PTR_ERR(aspi->dma_rx);
TRACE_DEBUG("can't get the RX DMA channel, error %d\n", ret);
aspi->dma_rx = NULL;
goto err;
}
aspi->rx_dummy_buffer = pvPortMalloc(MALLOC_DMA_MEM_SIZE);
if (!aspi->rx_dummy_buffer) {
ret = -ENOMEM;
goto err;
}
aspi->tx_dummy_buffer = pvPortMalloc(MALLOC_DMA_MEM_SIZE);
if (!aspi->tx_dummy_buffer) {
ret = -ENOMEM;
goto err;
}
aspi->dma_rx_completion = xQueueCreate(1, 0);
aspi->dma_tx_completion = xQueueCreate(1, 0);
return 0;
err:
ark_spi_sdma_exit(aspi);
return ret;
}
static void ark_spi_dma_rx_callback(void *cookie, unsigned mask)
{
struct ark_ecspi_data *aspi = (struct ark_ecspi_data *)cookie;
struct spi_message *dma_message = &aspi->dma_message;
/* Invalidate cache after read */
/* rx_dummy_buffer shoule align to CACHE_LINE_SIZE */
CP15_invalidate_dcache_for_dma((u32)aspi->rx_dummy_buffer,
(u32)aspi->rx_dummy_buffer + dma_message->length);
if (dma_message->recv_buf)
memcpy(dma_message->recv_buf, aspi->rx_dummy_buffer, dma_message->length);
xQueueSend(aspi->dma_rx_completion, NULL, 0);
}
static void ark_spi_dma_tx_callback(void *cookie, unsigned int mask)
{
struct ark_ecspi_data *aspi = (struct ark_ecspi_data *)cookie;
xQueueSend(aspi->dma_tx_completion, NULL, 0);
}
static int ark_spi_dma_transfer(struct ark_ecspi_data *aspi, struct spi_message *message)
{
struct dma_config rx = {0}, tx = {0};
unsigned long transfer_timeout;
rx.direction = DMA_DEV_TO_MEM;
rx.src_id = SPI1_RX;
rx.src_addr = aspi->base + ARK_ECSPI_RXDATA;
rx.dst_addr = (unsigned int)aspi->rx_dummy_buffer;
rx.dst_addr_width = rx.src_addr_width = DMA_BUSWIDTH_4_BYTES;
rx.src_maxburst = rx.dst_maxburst = aspi->wml;
rx.transfer_size = message->length;
dma_config_channel(aspi->dma_rx, &rx);
dma_register_complete_callback(aspi->dma_rx, ark_spi_dma_rx_callback, aspi);
tx.direction = DMA_MEM_TO_DEV;
tx.dst_id = SPI1_TX;
tx.src_addr = (unsigned int)aspi->tx_dummy_buffer;
tx.dst_addr = aspi->base + ARK_ECSPI_TXDATA;
tx.dst_addr_width = tx.src_addr_width = DMA_BUSWIDTH_4_BYTES;
tx.src_maxburst = tx.dst_maxburst = aspi->wml;
tx.transfer_size = message->length;
dma_config_channel(aspi->dma_tx, &tx);
dma_register_complete_callback(aspi->dma_tx, ark_spi_dma_tx_callback, aspi);
xQueueReset(aspi->dma_rx_completion);
dma_start_channel(aspi->dma_rx);
memset(aspi->tx_dummy_buffer, 0xff, message->length);
if (message->send_buf)
memcpy(aspi->tx_dummy_buffer, message->send_buf, message->length);
xQueueReset(aspi->dma_tx_completion);
/* Flush cache before write */
CP15_flush_dcache_for_dma((u32)aspi->tx_dummy_buffer,
(u32)aspi->tx_dummy_buffer + message->length);
dma_start_channel(aspi->dma_tx);
transfer_timeout = ark_spi_calculate_timeout(aspi, message->length);
/* Wait SDMA to finish the data transfer.*/
if (xQueueReceive(aspi->dma_tx_completion, NULL,
transfer_timeout) != pdTRUE) {
printf("I/O Error in DMA TX\n");
dma_stop_channel(aspi->dma_tx);
dma_stop_channel(aspi->dma_rx);
return -ETIMEDOUT;
}
if (xQueueReceive(aspi->dma_rx_completion, NULL,
transfer_timeout) != pdTRUE) {
printf("I/O Error in DMA RX\n");
aspi->devtype_data->reset(aspi);
dma_stop_channel(aspi->dma_rx);
return -ETIMEDOUT;
}
return message->length;
}
static int ark_spi_pio_xfer(struct ark_ecspi_data *aspi, struct spi_message *message)
{
unsigned long transfer_timeout;
int ret;
void *tx_dummy_buf = NULL;
void *rx_dummy_buf = NULL;
if ((unsigned int)message->send_buf & 3) {
tx_dummy_buf = pvPortMalloc(message->length);
if (!tx_dummy_buf) return -ENOMEM;
aspi->tx_buf = tx_dummy_buf;
memcpy(tx_dummy_buf, message->send_buf, message->length);
} else aspi->tx_buf = message->send_buf;
if ((unsigned int)message->recv_buf & 3) {
rx_dummy_buf = pvPortMalloc(message->length);
if (!rx_dummy_buf) return -ENOMEM;
aspi->rx_buf = rx_dummy_buf;
} else aspi->rx_buf = message->recv_buf;
aspi->remainder = aspi->count = message->length;
aspi->read_u32 = 1;
aspi->txfifo = 0;
xQueueReset(aspi->xfer_done);
ark_spi_push(aspi);
aspi->devtype_data->intctrl(aspi, ARK_INT_TE);
transfer_timeout = ark_spi_calculate_timeout(aspi, message->length);
if (xQueueReceive(aspi->xfer_done, NULL, transfer_timeout) != pdTRUE) {
TRACE_ERROR("I/O Error in PIO\n");
aspi->devtype_data->reset(aspi);
if (message->cs_release)
ark_spi_chipselect(aspi, 0);
ret = -ETIMEDOUT;
} else {
if (rx_dummy_buf)
memcpy(message->recv_buf, rx_dummy_buf, message->length);
ret = message->length;
}
if (rx_dummy_buf) vPortFree(rx_dummy_buf);
if (tx_dummy_buf) vPortFree(tx_dummy_buf);
return ret;
}
static int ecspi_configure(struct spi_slave *slave, struct spi_configuration *configuration)
{
struct ark_ecspi_data *aspi = (struct ark_ecspi_data *)slave;
return ark_spi_setupxfer(aspi, configuration);
}
static int ecspi_xfer(struct spi_slave *slave, struct spi_message *message)
{
struct ark_ecspi_data *aspi = (struct ark_ecspi_data *)slave;
int ret = 0;
if (message->cs_take)
ark_spi_chipselect(aspi, 1);
if (ark_spi_can_dma(aspi, message))
aspi->usedma = 1;
else
aspi->usedma = 0;
aspi->devtype_data->config(aspi);
if (aspi->usedma) {
if ((ret = ark_spi_dma_transfer(aspi, &aspi->dma_message)) < 0)
goto end;
if (aspi->pio_message.length > 0 &&
(ret = ark_spi_pio_xfer(aspi, &aspi->pio_message)) < 0)
goto end;
ret = message->length;
goto end;
}
ret = ark_spi_pio_xfer(aspi, message);
end:
if (message->cs_release)
ark_spi_chipselect(aspi, 0);
return ret;
};
static int ark_ecspi_probe(struct ark_ecspi_data *aspi, char *spi_bus_name)
{
int ret;
aspi->devtype_data = &ark_ecspi_devtype_data;
aspi->xfer_done = xQueueCreate(1, 0);
request_irq(aspi->irq, 0, ark_spi_isr, aspi);
if (aspi->devtype_data->has_dmamode) {
ret = ark_spi_sdma_init(aspi);
if (ret < 0)
TRACE_ERROR("dma setup error %d, use pio\n", ret);
}
aspi->devtype_data->reset(aspi);
aspi->devtype_data->intctrl(aspi, 0);
strncpy(aspi->slave.name, spi_bus_name, 16);
spi_add_slave(&aspi->slave);
return 0;
}
int ecspi_init(void)
{
struct ark_ecspi_data *aspi1 = pvPortMalloc(sizeof(struct ark_ecspi_data));
if (!aspi1)
return -ENOMEM;
memset(aspi1, 0, sizeof(struct ark_ecspi_data));
aspi1->base = REGS_SPI1_BASE;
aspi1->irq = SPI1_IRQn;
aspi1->spi_clk = ulClkGetRate(CLK_SPI1);
aspi1->cs_gpio = SPI1_CS0_GPIO;
aspi1->slave.mode = SPI_MODE_0;
aspi1->slave.cs = 0;
aspi1->slave.xfer = ecspi_xfer;
aspi1->slave.configure = ecspi_configure;
ark_ecspi_probe(aspi1, "spi1");
return 0;
}

View File

@ -0,0 +1,253 @@
#include "FreeRTOS.h"
#include "chip.h"
#define GPIO_SWPORTA_DR 0x00
#define GPIO_SWPORTA_DDR 0x04
#define GPIO_SWPORTA_CTL 0x08
#define GPIO_SWPORTA_INTEN 0x30
#define GPIO_SWPORTA_INTMASK 0x34
#define GPIO_SWPORTA_INTTYPE_LEVEL 0x38
#define GPIO_SWPORTA_INT_POLARITY 0x3c
#define GPIO_SWPORTA_INTSTATUS 0x40
#define GPIO_SWPORTA_RAW_INTSTATUS 0x44
#define GPIO_SWPORTA_DEBOUNCE 0x48
#define GPIO_SWPORTA_EOI 0x4c
#define GPIO_SWPORTA_EXT_PORTA 0x50
#define GPIO_SWPORTA_EXT_PORTB 0x54
#define GPIO_SWPORTA_EXT_PORTC 0x58
#define GPIO_SWPORTA_EXT_PORTD 0x5c
#define GPIO_SWPORTA_LS_SYNC 0x60
#define GPIO_SWPORTA_ID_CODE 0x64
#define GPIO_SWPORTA_INT_BOTHEDGE 0x68
#define GPIO_SWPORTA_VER_ID_CODE 0x6C
#define GPIO_SWPORTA_CONFIG_REG2 0x70
#define GPIO_SWPORTA_CONFIG_REG1 0x74
#define GPIO_BANK 4
#define GPIO_NUM 128
typedef struct {
ISRFunction_t handler;
void *handler_param;
int irq_type;
} GpioIrqDesc_t;
static GpioIrqDesc_t gpio_irq_descs[GPIO_NUM];
static __INLINE uint32_t gpio_get_regbase(int gpio)
{
int gpiox = (gpio >> 5) & 0x3;
return REGS_GPIO_BASE + 0x80 * gpiox;
}
/* static __INLINE int GPIO_BANK(unsigned gpio)
{
return gpio >> 5;
} */
static __INLINE int GPIO_OFFSET(unsigned gpio)
{
if (gpio == 96)
return 2;
else if (gpio == 97)
return 0;
else if (gpio == 98)
return 3;
else if (gpio == 99)
return 1;
else
return gpio & 0x1F;
}
static __INLINE void *GPIO_MODREG(unsigned gpio)
{
return (void*)(gpio_get_regbase(gpio) + GPIO_SWPORTA_DDR);
}
static __INLINE void *GPIO_WDATAREG(unsigned gpio)
{
return (void*)(gpio_get_regbase(gpio) + GPIO_SWPORTA_DR);
}
static __INLINE void *GPIO_RDATAREG(unsigned gpio)
{
return (void*)(gpio_get_regbase(gpio) + GPIO_SWPORTA_EXT_PORTA);
}
static __INLINE void *GPIO_INTENREG(unsigned gpio)
{
return (void*)(gpio_get_regbase(gpio) + GPIO_SWPORTA_INTEN);
}
static __INLINE void *GPIO_INTMASKREG(unsigned gpio)
{
return (void*)(gpio_get_regbase(gpio) + GPIO_SWPORTA_INTMASK);
}
static __INLINE void *GPIO_INTLVLREG(unsigned gpio)
{
return (void*)(gpio_get_regbase(gpio) + GPIO_SWPORTA_INTTYPE_LEVEL);
}
static __INLINE void *GPIO_INTPOLREG(unsigned gpio)
{
return (void*)(gpio_get_regbase(gpio) + GPIO_SWPORTA_INT_POLARITY);
}
void gpio_request(unsigned gpio)
{
pinctrl_gpio_request(gpio);
}
void gpio_direction_output(unsigned gpio, int value)
{
configASSERT(gpio < GPIO_NUM);
gpio_request(gpio);
writel(readl(GPIO_MODREG(gpio)) | (1 << GPIO_OFFSET(gpio)), GPIO_MODREG(gpio));
if (value)
writel(readl(GPIO_WDATAREG(gpio)) | (1 << GPIO_OFFSET(gpio)), GPIO_WDATAREG(gpio));
else
writel(readl(GPIO_WDATAREG(gpio)) & ~(1 << GPIO_OFFSET(gpio)), GPIO_WDATAREG(gpio));
}
void gpio_direction_input(unsigned gpio)
{
configASSERT(gpio < GPIO_NUM);
gpio_request(gpio);
writel(readl(GPIO_MODREG(gpio)) & ~(1 << GPIO_OFFSET(gpio)), GPIO_MODREG(gpio));
}
void gpio_set_value(unsigned gpio, int value)
{
configASSERT(gpio < GPIO_NUM);
if (value)
writel(readl(GPIO_WDATAREG(gpio)) | (1 << GPIO_OFFSET(gpio)), GPIO_WDATAREG(gpio));
else
writel(readl(GPIO_WDATAREG(gpio)) & ~(1 << GPIO_OFFSET(gpio)), GPIO_WDATAREG(gpio));
}
int gpio_get_value(unsigned gpio)
{
configASSERT(gpio < GPIO_NUM);
return !!(readl(GPIO_RDATAREG(gpio)) & (1 << GPIO_OFFSET(gpio)));
}
static void gpio_toggle_trigger(unsigned gpio)
{
u32 pol;
pol = readl(GPIO_INTPOLREG(gpio));
if (pol & (1 << GPIO_OFFSET(gpio)))
pol &= ~(1 << GPIO_OFFSET(gpio));
else
pol |= (1 << GPIO_OFFSET(gpio));
writel(pol, GPIO_INTPOLREG(gpio));
}
static void gpio_irq_enable(unsigned gpio)
{
writel(readl(GPIO_INTENREG(gpio)) | (1 << GPIO_OFFSET(gpio)), GPIO_INTENREG(gpio));
writel(readl(GPIO_INTMASKREG(gpio)) & ~(1 << GPIO_OFFSET(gpio)), GPIO_INTMASKREG(gpio));
}
static void gpio_irq_disable(unsigned gpio)
{
writel(readl(GPIO_INTENREG(gpio)) & ~(1 << GPIO_OFFSET(gpio)), GPIO_INTENREG(gpio));
writel(readl(GPIO_INTMASKREG(gpio)) | (1 << GPIO_OFFSET(gpio)), GPIO_INTMASKREG(gpio));
}
static int gpio_irq_set_irq_type(unsigned gpio, int type)
{
unsigned long level, polarity;
level = readl(GPIO_INTLVLREG(gpio));
polarity = readl(GPIO_INTPOLREG(gpio));
switch (type) {
case IRQ_TYPE_EDGE_BOTH:
level |= (1 << GPIO_OFFSET(gpio));
gpio_toggle_trigger(gpio);
break;
case IRQ_TYPE_EDGE_RISING:
level |= (1 << GPIO_OFFSET(gpio));
polarity |= (1 << GPIO_OFFSET(gpio));
break;
case IRQ_TYPE_EDGE_FALLING:
level |= (1 << GPIO_OFFSET(gpio));
polarity &= ~(1 << GPIO_OFFSET(gpio));
break;
case IRQ_TYPE_LEVEL_HIGH:
level &= ~(1 << GPIO_OFFSET(gpio));
polarity |= (1 << GPIO_OFFSET(gpio));
break;
case IRQ_TYPE_LEVEL_LOW:
level &= ~(1 << GPIO_OFFSET(gpio));
polarity &= ~(1 << GPIO_OFFSET(gpio));
break;
}
writel(level, GPIO_INTLVLREG(gpio));
if (type != IRQ_TYPE_EDGE_BOTH)
writel(polarity, GPIO_INTPOLREG(gpio));
return 0;
}
static void gpio_irq_handler(void *param)
{
u32 status;
int i, j;
for (i = 0; i < GPIO_BANK; i++) {
status = readl(REGS_GPIO_BASE + 0x80 * i + GPIO_SWPORTA_INTSTATUS);
for (j = 0; j < 32; j++) {
if (status & (1 << j)) {
u32 gpio = i * 32 + j;
/* clear interrupt */
writel(1 << j, REGS_GPIO_BASE + 0x80 * i + GPIO_SWPORTA_EOI);
if (gpio_irq_descs[gpio].handler != NULL) {
gpio_irq_descs[gpio].handler(gpio_irq_descs[gpio].handler_param);
if (gpio_irq_descs[gpio].irq_type == IRQ_TYPE_EDGE_BOTH)
gpio_toggle_trigger(gpio);
}
}
}
}
}
int gpio_irq_request(unsigned gpio, int irq_type, ISRFunction_t irq_handler, void *param)
{
configASSERT(gpio < GPIO_NUM);
portENTER_CRITICAL();
gpio_request(gpio);
gpio_irq_descs[gpio].handler = irq_handler;
gpio_irq_descs[gpio].handler_param = param;
gpio_irq_descs[gpio].irq_type = irq_type;
gpio_irq_set_irq_type(gpio, irq_type);
request_irq(GPIOA_IRQn + ((gpio >> 5) & 0x3), 0, gpio_irq_handler, NULL);
gpio_irq_enable(gpio);
portEXIT_CRITICAL();
return 0;
}
int gpio_irq_free(unsigned gpio)
{
configASSERT(gpio < GPIO_NUM);
portENTER_CRITICAL();
gpio_irq_disable(gpio);
gpio_irq_descs[gpio].handler = NULL;
gpio_irq_descs[gpio].handler_param = NULL;
portEXIT_CRITICAL();
return 0;
}

View File

@ -0,0 +1,236 @@
#include "FreeRTOS.h"
#include "chip.h"
#include "os_adapt.h"
#include "hx170dec.h"
#include "vdec.h"
#define REGS_VDEC_BASE 0x71200000
#define VDEC_MAX_CORES 1 /* number of cores of the hardware IP */
#define VDEC_NUM_REGS_DEC 60 /* number of registers of the Decoder part */
#define VDEC_NUM_REGS_PP 41 /* number of registers of the Post Processor part */
#define VDEC_DEC_FIRST_REG 0 /* first register (0-based) index */
#define VDEC_DEC_LAST_REG 59 /* last register (0-based) index */
#define VDEC_PP_FIRST_REG 60
#define VDEC_PP_LAST_REG 100
struct vdec_device {
unsigned int mmio_base;
struct device *dev;
int irq;
int num_cores;
unsigned long iobaseaddr;
unsigned long iosize;
QueueHandle_t dec_irq_done;
SemaphoreHandle_t dec_sem;
u32 regs[VDEC_NUM_REGS_DEC + VDEC_NUM_REGS_PP];
};
static struct vdec_device *vdec6731_global;
static inline void vdec_writel(const struct vdec_device *p, unsigned offset, u32 val)
{
writel(val, p->mmio_base + offset);
}
static inline u32 vdec_readl(const struct vdec_device *p, unsigned offset)
{
return readl(p->mmio_base + offset);
}
/**
* Write a range of registers. First register is assumed to be
* "Interrupt Register" and will be written last.
*/
static int vdec_regs_write(struct vdec_device *p, int begin, int end,
const struct core_desc *core)
{
int i;
memcpy(&p->regs[begin], core->regs, (end - begin + 1) * 4);
for (i = end; i >= begin; i--)
vdec_writel(p, 4 * i, p->regs[i]);
return 0;
}
/**
* Read a range of registers [begin..end]
*/
static int vdec_regs_read(struct vdec_device *p, int begin, int end,
const struct core_desc *core)
{
int i;
for (i = end; i >= begin; i--)
p->regs[i] = vdec_readl(p, 4 * i);
memcpy(core->regs, &p->regs[begin], (end - begin + 1) * 4);
return 0;
}
long vdec_ioctl(unsigned int cmd, void *arg)
{
int ret = 0;
void *argp = arg;
struct vdec_device *p = vdec6731_global;
struct core_desc core;
u32 reg;
switch (cmd) {
case HX170DEC_IOX_ASIC_ID:
reg = vdec_readl(p, VDEC_IDR);
memcpy(argp, &reg, sizeof(u32));
break;
case HX170DEC_IOC_MC_OFFSETS:
case HX170DEC_IOCGHWOFFSET:
memcpy(argp, &p->iobaseaddr, sizeof(p->iobaseaddr));
break;
case HX170DEC_IOCGHWIOSIZE: /* in bytes */
memcpy(argp, &p->iosize, sizeof(p->iosize));
break;
case HX170DEC_IOC_MC_CORES:
memcpy(argp, &p->num_cores, sizeof(p->num_cores));
break;
case HX170DEC_IOCS_DEC_PUSH_REG:
memcpy(&core, (void *)arg, sizeof(struct core_desc));
/* Skip VDEC_IDR (ID Register, ro) */
core.regs++; // core.size -= 4;
ret = vdec_regs_write(p, VDEC_DEC_FIRST_REG + 1, VDEC_DEC_LAST_REG, &core);
break;
case HX170DEC_IOCS_PP_PUSH_REG:
break;
case HX170DEC_IOCS_DEC_PULL_REG:
memcpy(&core, (void *)arg, sizeof(struct core_desc));
ret = vdec_regs_read(p, VDEC_DEC_FIRST_REG, VDEC_DEC_LAST_REG, &core);
break;
case HX170DEC_IOCS_PP_PULL_REG:
break;
case HX170DEC_IOCX_DEC_WAIT:
memcpy(&core, (void *)arg, sizeof(struct core_desc));
if (xQueueReceive(p->dec_irq_done, NULL, pdMS_TO_TICKS(1000)) != pdTRUE) {
dev_err(p->dev, "wait_event_interruptible dec error %d\n", ret);
ret = -ETIMEDOUT;
} else {
/* Update dec registers */
ret = vdec_regs_read(p, VDEC_DEC_FIRST_REG, VDEC_DEC_LAST_REG, &core);
}
xQueueReset(p->dec_irq_done);
break;
case HX170DEC_IOCX_PP_WAIT:
break;
case HX170DEC_IOCH_DEC_RESERVE:
if (xSemaphoreTake(p->dec_sem, pdMS_TO_TICKS(100)) == pdTRUE) {
ret = 0; /* core id */
dev_dbg(p->dev, "down dec_sem (core id %d)\n", ret);
} else {
dev_err(p->dev, "down_interruptible dec error\n");
ret = -ETIMEDOUT;
}
break;
case HX170DEC_IOCT_DEC_RELEASE:
dev_dbg(p->dev, "up dec_sem\n");
xSemaphoreGive(p->dec_sem);
break;
case HX170DEC_IOCQ_PP_RESERVE:
break;
case HX170DEC_IOCT_PP_RELEASE:
break;
default:
dev_warn(p->dev, "unknown ioctl %x\n", cmd);
ret = -EINVAL;
}
return ret;
}
/*
* Platform driver related
*/
/* Should we use spin_lock_irqsave here? */
static void vdec_isr(void *dev_id)
{
struct vdec_device *p = dev_id;
u32 irq_status_dec;
int handled = 0;
/* interrupt status register read */
irq_status_dec = vdec_readl(p, VDEC_DIR);
//printf("irq_status=0x%x.\n", irq_status_dec);
if (irq_status_dec & VDEC_DIR_ISET) {
/* Clear IRQ */
vdec_writel(p, VDEC_DIR, irq_status_dec & ~VDEC_DIR_ISET);
xQueueSendFromISR(p->dec_irq_done, NULL, 0);
handled++;
}
if (handled == 0) {
dev_warn(p->dev, "Spurious IRQ (DIR=%08x)\n", irq_status_dec);
}
}
#if 0
static void vdec_iram_mode_select(void)
{
//0 MFC ram use as iram; 1 MFCram use MFC REF buffer
u32 val = readl(REGS_SYSCTL_BASE + 0x78);
val |= (1<<0);
writel(val, REGS_SYSCTL_BASE + 0x78);
}
#endif
int vdec_init(void)
{
struct vdec_device *p;
int hwid;
/* Allocate private data */
p = pvPortMalloc(sizeof(struct vdec_device));
if (!p) {
dev_dbg(&pdev->dev, "out of memory\n");
return -ENOMEM;
}
memset(p, 0, sizeof(struct vdec_device));
p->mmio_base = REGS_VDEC_BASE;
p->irq = JPG_IRQn;
p->num_cores = VDEC_MAX_CORES;
p->iosize = 0x200;
p->iobaseaddr = REGS_VDEC_BASE;
vdec6731_global = p;
request_irq(p->irq, 0, vdec_isr, p);
p->dec_irq_done = xQueueCreate(1, 0);
p->dec_sem = xSemaphoreCreateCounting(VDEC_MAX_CORES, 1);
dev_info(&pdev->dev, "VDEC controller at 0x%u, irq = %d\n",
p->mmio_base, p->irq);
/* Reset Asic (just in case..) */
vdec_writel(p, VDEC_DIR, VDEC_DIR_ID | VDEC_DIR_ABORT);
vdec_writel(p, VDEC_PPIR, VDEC_PPIR_ID);
hwid = vdec_readl(p, VDEC_IDR);
printf("Product ID: %#x (revision %d.%d.%d)\n", \
(hwid & VDEC_IDR_PROD_ID) >> 16,
(hwid & VDEC_IDR_MAJOR_VER) >> 12,
(hwid & VDEC_IDR_MINOR_VER) >> 4,
(hwid & VDEC_IDR_BUILD_VER));
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,633 @@
#include <string.h>
#include "FreeRTOS.h"
#include "chip.h"
#include "board.h"
#include "errno.h"
#include "timer.h"
#ifdef ANALOG_I2C_SUPPORT
struct i2c_gpio_private_data {
struct i2c_adapter adap;
struct i2c_algo_bit_data bit_data;
struct i2c_gpio_platform_data pdata;
};
/* Toggle SDA by changing the direction of the pin */
static void i2c_gpio_setsda_dir(void *data, int state)
{
struct i2c_gpio_platform_data *pdata = data;
if (state)
gpio_direction_input(pdata->sda_pin);
else
gpio_direction_output(pdata->sda_pin, 0);
}
/*
* Toggle SDA by changing the output value of the pin. This is only
* valid for pins configured as open drain (i.e. setting the value
* high effectively turns off the output driver.)
*/
static void i2c_gpio_setsda_val(void *data, int state)
{
struct i2c_gpio_platform_data *pdata = data;
gpio_direction_output(pdata->sda_pin, state);
gpio_set_value(pdata->sda_pin, state);
}
/* Toggle SCL by changing the direction of the pin. */
static void i2c_gpio_setscl_dir(void *data, int state)
{
struct i2c_gpio_platform_data *pdata = data;
if (state)
gpio_direction_input(pdata->scl_pin);
else
gpio_direction_output(pdata->scl_pin, 0);
}
/*
* Toggle SCL by changing the output value of the pin. This is used
* for pins that are configured as open drain and for output-only
* pins. The latter case will break the i2c protocol, but it will
* often work in practice.
*/
static void i2c_gpio_setscl_val(void *data, int state)
{
struct i2c_gpio_platform_data *pdata = data;
gpio_direction_output(pdata->scl_pin, state);
gpio_set_value(pdata->scl_pin, state);
}
static int i2c_gpio_getsda(void *data)
{
struct i2c_gpio_platform_data *pdata = data;
gpio_direction_input(pdata->sda_pin);
return gpio_get_value(pdata->sda_pin);
}
static int i2c_gpio_getscl(void *data)
{
struct i2c_gpio_platform_data *pdata = data;
gpio_direction_input(pdata->scl_pin);
return gpio_get_value(pdata->scl_pin);
}
/* --- setting states on the bus with the right timing: --------------- */
#define setsda(adap, val) adap->setsda(adap->data, val)
#define setscl(adap, val) adap->setscl(adap->data, val)
#define getsda(adap) adap->getsda(adap->data)
#define getscl(adap) adap->getscl(adap->data)
static __INLINE void sdalo(struct i2c_algo_bit_data *adap)
{
setsda(adap, 0);
udelay((adap->udelay + 1) / 2);
}
static __INLINE void sdahi(struct i2c_algo_bit_data *adap)
{
setsda(adap, 1);
udelay((adap->udelay + 1) / 2);
}
static __INLINE void scllo(struct i2c_algo_bit_data *adap)
{
setscl(adap, 0);
udelay(adap->udelay / 2);
}
/*
* Raise scl line, and do checking for delays. This is necessary for slower
* devices.
*/
static int sclhi(struct i2c_algo_bit_data *adap)
{
unsigned long start;
setscl(adap, 1);
/* Not all adapters have scl sense line... */
if (!adap->getscl)
goto done;
start = xTaskGetTickCount();
while (!getscl(adap)) {
/* This hw knows how to read the clock line, so we wait
* until it actually gets high. This is safer as some
* chips may hold it low ("clock stretching") while they
* are processing data internally.
*/
if (xTaskGetTickCount() > start + adap->timeout) {
/* Test one last time, as we may have been preempted
* between last check and timeout test.
*/
if (getscl(adap))
break;
return -ETIMEDOUT;
}
taskYIELD();
}
done:
udelay(adap->udelay);
return 0;
}
/* --- other auxiliary functions -------------------------------------- */
static void i2c_start(struct i2c_algo_bit_data *adap)
{
/* assert: scl, sda are high */
setsda(adap, 0);
udelay(adap->udelay);
scllo(adap);
}
static void i2c_repstart(struct i2c_algo_bit_data *adap)
{
/* assert: scl is low */
sdahi(adap);
sclhi(adap);
setsda(adap, 0);
udelay(adap->udelay);
scllo(adap);
}
static void i2c_stop(struct i2c_algo_bit_data *adap)
{
/* assert: scl is low */
sdalo(adap);
sclhi(adap);
setsda(adap, 1);
udelay(adap->udelay);
}
/* send a byte without start cond., look for arbitration,
check ackn. from slave */
/* returns:
* 1 if the device acknowledged
* 0 if the device did not ack
* -ETIMEDOUT if an error occurred (while raising the scl line)
*/
static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
{
int i;
int sb;
int ack;
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
/* assert: scl is low */
for (i = 7; i >= 0; i--) {
sb = (c >> i) & 1;
setsda(adap, sb);
udelay((adap->udelay + 1) / 2);
if (sclhi(adap) < 0) { /* timed out */
TRACE_DEBUG("i2c_outb: 0x%02x, timeout at bit #%d\n", (int)c, i);
return -ETIMEDOUT;
}
/* FIXME do arbitration here:
* if (sb && !getsda(adap)) -> ouch! Get out of here.
*
* Report a unique code, so higher level code can retry
* the whole (combined) message and *NOT* issue STOP.
*/
scllo(adap);
}
sdahi(adap); //---
//sdalo(adap); //+++
if (sclhi(adap) < 0) { /* timeout */
TRACE_DEBUG("i2c_outb: 0x%02x, timeout at ack\n", (int)c);
return -ETIMEDOUT;
}
/* read ack: SDA should be pulled down by slave, or it may
* NAK (usually to report problems with the data we wrote).
*/
ack = !getsda(adap); /* ack: sda is pulled low -> success */
TRACE_DEBUG("i2c_outb: 0x%02x %s\n", (int)c, ack ? "A" : "NA");
scllo(adap);
//sdalo(adap); //+++
return ack;
/* assert: scl is low (sda undef) */
}
static int i2c_inb(struct i2c_adapter *i2c_adap)
{
/* read byte via i2c port, without start/stop sequence */
/* acknowledge is sent in i2c_read. */
int i;
unsigned char indata = 0;
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
/* assert: scl is low */
sdahi(adap); //---
for (i = 0; i < 8; i++) {
if (sclhi(adap) < 0) { /* timeout */
TRACE_DEBUG("i2c_inb: timeout at bit #%d\n", 7 - i);
return -ETIMEDOUT;
}
indata *= 2;
if (getsda(adap))
indata |= 0x01;
setscl(adap, 0);
udelay(i == 7 ? adap->udelay / 2 : adap->udelay);
}
/* assert: scl is low */
return indata;
}
/* try_address tries to contact a chip for a number of
* times before it gives up.
* return values:
* 1 chip answered
* 0 chip did not answer
* -x transmission error
*/
static int try_address(struct i2c_adapter *i2c_adap,
unsigned char addr, int retries)
{
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
int i, ret = 0;
for (i = 0; i <= retries; i++) {
ret = i2c_outb(i2c_adap, addr);
if (ret == 1 || i == retries)
break;
TRACE_DEBUG("emitting stop condition\n");
i2c_stop(adap);
udelay(adap->udelay);
taskYIELD();
TRACE_DEBUG("emitting start condition\n");
i2c_start(adap);
}
if (i && ret)
TRACE_DEBUG("Used %d tries to %s client at "
"0x%02x: %s\n", i + 1,
addr & 1 ? "read from" : "write to", addr >> 1,
ret == 1 ? "success" : "failed, timeout?");
return ret;
}
static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
{
const unsigned char *temp = msg->buf;
int count = msg->len;
unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
int retval;
int wrcount = 0;
while (count > 0) {
retval = i2c_outb(i2c_adap, *temp);
/* OK/ACK; or ignored NAK */
if ((retval > 0) || (nak_ok && (retval == 0))) {
count--;
temp++;
wrcount++;
/* A slave NAKing the master means the slave didn't like
* something about the data it saw. For example, maybe
* the SMBus PEC was wrong.
*/
} else if (retval == 0) {
TRACE_ERROR("sendbytes: NAK bailout.\n");
return -EIO;
/* Timeout; or (someday) lost arbitration
*
* FIXME Lost ARB implies retrying the transaction from
* the first message, after the "winning" master issues
* its STOP. As a rule, upper layer code has no reason
* to know or care about this ... it is *NOT* an error.
*/
} else {
TRACE_ERROR("sendbytes: error %d\n", retval);
return retval;
}
}
return wrcount;
}
static int acknak(struct i2c_adapter *i2c_adap, int is_ack)
{
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
/* assert: sda is high */
if (is_ack) /* send ack */
setsda(adap, 0);
udelay((adap->udelay + 1) / 2);
if (sclhi(adap) < 0) { /* timeout */
TRACE_ERROR("readbytes: ack/nak timeout\n");
return -ETIMEDOUT;
}
scllo(adap);
return 0;
}
static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
{
int inval;
int rdcount = 0; /* counts bytes read */
unsigned char *temp = msg->buf;
int count = msg->len;
const unsigned flags = msg->flags;
while (count > 0) {
inval = i2c_inb(i2c_adap);
if (inval >= 0) {
*temp = inval;
rdcount++;
} else { /* read timed out */
break;
}
temp++;
count--;
/* Some SMBus transactions require that we receive the
transaction length as the first read byte. */
if (rdcount == 1 && (flags & I2C_M_RECV_LEN)) {
if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) {
if (!(flags & I2C_M_NO_RD_ACK))
acknak(i2c_adap, 0);
TRACE_ERROR("readbytes: invalid block length (%d)\n", inval);
return -EPROTO;
}
/* The original count value accounts for the extra
bytes, that is, either 1 for a regular transaction,
or 2 for a PEC transaction. */
count += inval;
msg->len += inval;
}
TRACE_DEBUG( "readbytes: 0x%02x %s\n",
inval,
(flags & I2C_M_NO_RD_ACK)
? "(no ack/nak)"
: (count ? "A" : "NA"));
if (!(flags & I2C_M_NO_RD_ACK)) {
inval = acknak(i2c_adap, count);
if (inval < 0)
return inval;
}
}
return rdcount;
}
/* doAddress initiates the transfer by generating the start condition (in
* try_address) and transmits the address in the necessary format to handle
* reads, writes as well as 10bit-addresses.
* returns:
* 0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set
* -x an error occurred (like: -ENXIO if the device did not answer, or
* -ETIMEDOUT, for example if the lines are stuck...)
*/
static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
{
unsigned short flags = msg->flags;
unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
unsigned char addr;
int ret, retries;
retries = nak_ok ? 0 : i2c_adap->retries;
if (flags & I2C_M_TEN) {
/* a ten bit address */
addr = 0xf0 | ((msg->addr >> 7) & 0x06);
TRACE_DEBUG("addr0: %d\n", addr);
/* try extended address code...*/
ret = try_address(i2c_adap, addr, retries);
if ((ret != 1) && !nak_ok) {
TRACE_ERROR("died at extended address code\n");
return -ENXIO;
}
/* the remaining 8 bit address */
ret = i2c_outb(i2c_adap, msg->addr & 0xff);
if ((ret != 1) && !nak_ok) {
/* the chip did not ack / xmission error occurred */
TRACE_ERROR("died at 2nd address code\n");
return -ENXIO;
}
if (flags & I2C_M_RD) {
TRACE_DEBUG("emitting repeated start condition\n");
i2c_repstart(adap);
/* okay, now switch into reading mode */
addr |= 0x01;
ret = try_address(i2c_adap, addr, retries);
if ((ret != 1) && !nak_ok) {
TRACE_ERROR("died at repeated address code\n");
return -EIO;
}
}
} else { /* normal 7bit address */
addr = msg->addr << 1;
if (flags & I2C_M_RD)
addr |= 1;
if (flags & I2C_M_REV_DIR_ADDR)
addr ^= 1;
ret = try_address(i2c_adap, addr, retries);
if ((ret != 1) && !nak_ok)
return -ENXIO;
}
return 0;
}
static int bit_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg msgs[], int num)
{
struct i2c_msg *pmsg;
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
int i, ret;
unsigned short nak_ok;
TRACE_DEBUG("emitting start condition\n");
i2c_start(adap);
for (i = 0; i < num; i++) {
pmsg = &msgs[i];
nak_ok = pmsg->flags & I2C_M_IGNORE_NAK;
if (!(pmsg->flags & I2C_M_NOSTART)) {
if (i) {
if (msgs[i - 1].flags & I2C_M_STOP) {
TRACE_DEBUG("emitting enforced stop/start condition\n");
i2c_stop(adap);
i2c_start(adap);
} else {
TRACE_DEBUG("emitting repeated start condition\n");
i2c_repstart(adap);
}
}
ret = bit_doAddress(i2c_adap, pmsg);
if ((ret != 0) && !nak_ok) {
TRACE_DEBUG("NAK from device addr 0x%02x msg #%d\n", msgs[i].addr, i);
goto bailout;
}
}
if (pmsg->flags & I2C_M_RD) {
/* read bytes into buffer*/
ret = readbytes(i2c_adap, pmsg);
if (ret >= 1)
TRACE_DEBUG("read %d byte%s\n", ret, ret == 1 ? "" : "s");
if (ret < pmsg->len) {
if (ret >= 0)
ret = -EIO;
goto bailout;
}
} else {
/* write bytes from buffer */
ret = sendbytes(i2c_adap, pmsg);
if (ret >= 1)
TRACE_DEBUG("wrote %d byte%s\n", ret, ret == 1 ? "" : "s");
if (ret < pmsg->len) {
if (ret >= 0)
ret = -EIO;
goto bailout;
}
}
}
ret = i;
bailout:
TRACE_DEBUG("emitting stop condition\n");
i2c_stop(adap);
return ret;
}
struct i2c_gpio_platform_data i2c_gpio[] = {
{
.devid = 0,
.sda_pin = I2C_GPIO0_SDA_PIN,
.scl_pin = I2C_GPIO0_SCL_PIN,
.udelay = 5, /* clk freq 500/udelay kHz */
.timeout = configTICK_RATE_HZ / 10, /* 100ms */
.sda_is_open_drain = 0,
.scl_is_open_drain = 0,
.scl_is_output_only = 1,
}
};
const struct i2c_algorithm i2c_bit_algo = {
.master_xfer = bit_xfer,
};
int i2c_bit_add_bus(struct i2c_adapter *adap)
{
int ret;
/* register new adapter to i2c module... */
adap->algo = &i2c_bit_algo;
adap->retries = 3;
ret = i2c_add_adapter(adap);
if (ret < 0)
return ret;
return 0;
}
static int i2c_gpio_add_device(struct i2c_gpio_platform_data *pdevdata)
{
struct i2c_gpio_private_data *priv;
struct i2c_gpio_platform_data *pdata;
struct i2c_algo_bit_data *bit_data;
struct i2c_adapter *adap;
int ret;
priv = pvPortMalloc(sizeof(*priv));
if (!priv) {
TRACE_ERROR("[%s] pvPortMalloc failed, devid:%d\n", __func__, pdevdata->devid);
return -ENOMEM;
}
memset(priv, 0, sizeof(*priv));
adap = &priv->adap;
bit_data = &priv->bit_data;
pdata = &priv->pdata;
memcpy(pdata, pdevdata, sizeof(*pdata));
gpio_request(pdata->sda_pin);
gpio_request(pdata->scl_pin);
if (pdata->sda_is_open_drain) {
gpio_direction_output(pdata->sda_pin, 1);
bit_data->setsda = i2c_gpio_setsda_val;
} else {
gpio_direction_input(pdata->sda_pin);
bit_data->setsda = i2c_gpio_setsda_dir;
}
if (pdata->scl_is_open_drain || pdata->scl_is_output_only) {
gpio_direction_output(pdata->scl_pin, 1);
bit_data->setscl = i2c_gpio_setscl_val;
} else {
gpio_direction_input(pdata->scl_pin);
bit_data->setscl = i2c_gpio_setscl_dir;
}
if (!pdata->scl_is_output_only)
bit_data->getscl = i2c_gpio_getscl;
bit_data->getsda = i2c_gpio_getsda;
if (pdata->udelay)
bit_data->udelay = pdata->udelay;
else if (pdata->scl_is_output_only)
bit_data->udelay = 50; /* 10 kHz */
else
bit_data->udelay = 5; /* 100 kHz */
if (pdata->timeout)
bit_data->timeout = pdata->timeout;
else
bit_data->timeout = configTICK_RATE_HZ / 10; /* 100 ms */
bit_data->data = pdata;
snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdata->devid);
adap->algo_data = bit_data;
ret = i2c_bit_add_bus(adap);
if (ret) {
TRACE_ERROR("[%s] i2c_bit_add_bus failed, devid:%d\n", __func__, pdata->devid);
return ret;
}
TRACE_INFO("using pins %u (SDA) and %u (SCL%s)\n",
pdata->sda_pin, pdata->scl_pin,
pdata->scl_is_output_only
? ", no clock stretching" : "");
return 0;
}
void i2c_gpio_init(void)
{
int i;
for(i=0; i<sizeof(i2c_gpio)/sizeof(i2c_gpio[0]); i++) {
i2c_gpio_add_device(&i2c_gpio[i]);
}
}
#endif

View File

@ -0,0 +1,135 @@
#include <string.h>
#include "FreeRTOS.h"
#include "chip.h"
#include "errno.h"
#define MAX_I2C_DEVICE_NUM 4
static struct i2c_adapter *i2c_devs[MAX_I2C_DEVICE_NUM] = {NULL};
static int i2c_devices_count = 0;
int i2c_add_adapter(struct i2c_adapter *adap)
{
if (i2c_devices_count >= MAX_I2C_DEVICE_NUM)
return -1;
/* Set default timeout to 1 second if not already set */
if (adap->timeout == 0)
adap->timeout = configTICK_RATE_HZ;
i2c_devs[i2c_devices_count++] = adap;
return 0;
}
struct i2c_adapter *i2c_open(const char *i2cdev)
{
struct i2c_adapter *adap;
int i;
for (i = 0; i < i2c_devices_count; i++) {
adap = i2c_devs[i];
if (!strcmp(adap->name, i2cdev)) {
adap->open_count++;
if (adap->open_count == 1)
adap->xMutex = xSemaphoreCreateMutex();
return adap;
}
}
return NULL;
}
void i2c_close(struct i2c_adapter *adap)
{
if (adap && --adap->open_count == 0)
vSemaphoreDelete(adap->xMutex);
}
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
unsigned long orig_jiffies;
int ret, try;
configASSERT(adap && msgs);
xSemaphoreTake(adap->xMutex, portMAX_DELAY);
/* Retry automatically on arbitration loss */
orig_jiffies = xTaskGetTickCount();
for (ret = 0, try = 0; try <= adap->retries; try++) {
ret = adap->algo->master_xfer(adap, msgs, num);
if (ret != -EAGAIN)
break;
if (xTaskGetTickCount() > orig_jiffies + adap->timeout)
break;
}
xSemaphoreGive(adap->xMutex);
return ret;
}
int i2c_slave_register(struct i2c_adapter *adap, u8 addr, i2c_slave_cb_t slave_cb)
{
int ret;
if (!adap || !slave_cb)
return -EINVAL;
if (!(adap->flags & I2C_CLIENT_SLAVE))
TRACE_WARNING("%s: client slave flag not set.\n", __func__);
if (!adap->algo->reg_slave) {
printf("%s: not supported by adapter\n", __func__);
return -ENOTSUP;
}
adap->slave_cb = slave_cb;
adap->addr = addr;
ret = adap->algo->reg_slave(adap);
if (ret) {
adap->slave_cb = NULL;
printf("%s: adapter returned error %d\n", __func__, ret);
}
return ret;
}
int i2c_slave_unregister(struct i2c_adapter *adap)
{
int ret;
if (!adap)
return -EINVAL;
if (!adap->algo->unreg_slave) {
printf("%s: not supported by adapter\n", __func__);
return -ENOTSUP;
}
ret = adap->algo->unreg_slave(adap);
if (ret == 0)
adap->slave_cb = NULL;
else
printf("%s: adapter returned error %d\n", __func__, ret);
return ret;
}
void i2c_init(void)
{
#ifdef HW_I2C0_SUPPORT
i2c_dw_init(0);
#endif
#ifdef HW_I2C1_SUPPORT
i2c_dw_init(1);
#endif
#ifdef ANALOG_I2C_SUPPORT
i2c_gpio_init();
#endif
}

View File

@ -0,0 +1,473 @@
#include "FreeRTOS.h"
#include "chip.h"
#include "board.h"
#include "audio/audio.h"
#include "i2s.h"
#include "soc-dai.h"
#define I2S_SLAVE 0
#define I2S_MASTER 1
typedef struct ark_i2s_private_data {
struct snd_soc_dai_ops adc_ops;
struct snd_soc_dai_ops dac_ops;
} ark_i2s_pd;
extern int audio_codec_adc_init(struct snd_soc_dai_ops *ops);
extern int audio_codec_dac_init(struct snd_soc_dai_ops *ops);
#if 0
static void ark_i2s_start_play(struct ark_i2s_data *i2s)
{
u32 val = readl(i2s->base + I2S_SACR1);
val &= ~SACR1_DRPL;
writel(val, i2s->base + I2S_SACR1);
}
static void ark_i2s_start_record(struct ark_i2s_data *i2s)
{
u32 val = readl(i2s->base + I2S_SACR1);
val &= ~SACR1_DREC;
writel(val, i2s->base + I2S_SACR1);
}
#endif
static void ark_i2s_stop_play(struct ark_i2s_data *i2s)
{
u32 val = readl(i2s->base + I2S_SACR1);
val |= SACR1_DRPL;
writel(val, i2s->base + I2S_SACR1);
}
static void ark_i2s_stop_record(struct ark_i2s_data *i2s)
{
u32 val = readl(i2s->base + I2S_SACR1);
val |= SACR1_DREC;
writel(val, i2s->base + I2S_SACR1);
}
static void ark_i2s_restart(struct ark_i2s_data *i2s, int stream)
{
u32 val = readl(i2s->base + I2S_SACR1);
/* close record and replay */
writel(val | SACR1_DREC | SACR1_DRPL, i2s->base + I2S_SACR1);
mdelay(1);
if(stream == AUDIO_STREAM_REPLAY)
val &= ~SACR1_DRPL;
else
val &= ~SACR1_DREC;
writel(val, i2s->base + I2S_SACR1);
}
int ark_i2s_startup(struct ark_i2s_data *i2s, int stream)
{
unsigned int val;
xSemaphoreTake(i2s->mutex, portMAX_DELAY);
if (stream == AUDIO_STREAM_REPLAY)
{
/* close play */
ark_i2s_stop_play(i2s);
val = readl(i2s->base + I2S_SACR0);
val |= SACR0_CHANLOCK | SACR0_RFTH(0x10) | SACR0_TFTH(0xF) | SACR0_ENB;
if(i2s->cfg[stream].lfirst)
val |= SACR0_TFIFOFIRSTBIT;
else
val &= ~SACR0_TFIFOFIRSTBIT;
if(i2s->cfg[stream].channels == 1)
val |= SACR0_SCBIT; /* single channel */
else
val &= ~SACR0_SCBIT;
if(i2s->cfg[stream].bits > 16)
val |= SACR0_BITS; /* 32 Bits */
else
val &= ~SACR0_BITS;
if(i2s->cfg[stream].master)
val |= SACR0_BCKD | SACR0_SYNCD;
else
val &= ~(SACR0_BCKD | SACR0_SYNCD);
if(i2s->dma_txch)
val |= SACR0_TDMAEN;
else
val &= ~SACR0_TDMAEN;
writel(val, i2s->base + I2S_SACR0);
/* interrupt clear */
val = readl(i2s->base + I2S_SAICR);
val |= (SAICR_TFS | SAICR_TUR);
writel(val, i2s->base + I2S_SAICR);
val &= ~(SAICR_TFS | SAICR_TUR);
writel(val, i2s->base + I2S_SAICR);
/* interrupt enable */
val = readl(i2s->base + I2S_SAIMR);
val |= (SAIMR_TFS | SAIMR_TUR);
writel(val, i2s->base + I2S_SAIMR);
/* start replay */
ark_i2s_restart(i2s, stream);
}
else if(stream == AUDIO_STREAM_RECORD)
{
ark_i2s_pd *pdata = i2s->extdata;
/* close record */
ark_i2s_stop_record(i2s);
if(pdata && pdata->adc_ops.hw_params)
{
struct snd_soc_hw_params params;
params.rates = i2s->cfg[stream].rates;
params.channels = i2s->cfg[stream].channels;
params.bits = i2s->cfg[stream].bits;
pdata->adc_ops.hw_params(&params);
}
val = readl(i2s->base + I2S_SACR0);
val |= SACR0_CHANLOCK| SACR0_RFTH(0x10) | SACR0_TFTH(0xF) | SACR0_ENB;
if(i2s->cfg[stream].lfirst)
val |= SACR0_RFIFIFIRSTBIT;
else
val &= ~SACR0_RFIFIFIRSTBIT;
if(i2s->cfg[stream].channels == 1)
val |= SACR0_SCBIT;
else
val &= ~SACR0_SCBIT;
if(i2s->cfg[stream].bits > 16)
val |= SACR0_BITS; //32 Bits.
else
val &= ~SACR0_BITS;
if(i2s->dma_rxch)
val |= SACR0_RDMAEN;
else
val &= ~SACR0_RDMAEN;
if(i2s->cfg[stream].master)
{
val |= SACR0_BCKD | SACR0_SYNCD;
writel(val, i2s->base + I2S_SACR0);
}
else
{
writel(val, i2s->base + I2S_SACR0);
#if 0
/* 630hv100 record work in slave mode, bclk need inverse */
if(i2s->id == 0) {
val = readl(REGS_SYSCTL_BASE + SYS_PER_CLK_CFG);
val |= (1<<18);
writel(val, REGS_SYSCTL_BASE + SYS_PER_CLK_CFG);
} else if(i2s->id == 1) {
val = readl(REGS_SYSCTL_BASE + SYS_BUS_CLK1_CFG);
val |= (1<<6); //1:bclk inverse; 0:normal.
writel(val, REGS_SYSCTL_BASE + SYS_BUS_CLK1_CFG);
}
#endif
}
/* interrupt clear */
val = readl(i2s->base + I2S_SAICR);
val |= (SAICR_ROR | SAICR_RFS);
writel(val, i2s->base + I2S_SAICR);
val &= ~(SAICR_ROR | SAICR_RFS);
writel(val, i2s->base + I2S_SAICR);
/* interrupt enable */
val = readl(i2s->base + I2S_SAIMR);
val |= (SAIMR_ROR | SAIMR_RFS);
writel(val, i2s->base + I2S_SAIMR);
if(pdata && pdata->adc_ops.startup)
{
pdata->adc_ops.startup(1);
}
/* start record */
ark_i2s_restart(i2s, stream);
}
xSemaphoreGive(i2s->mutex);
return 0;
}
void ark_i2s_set_volume(struct ark_i2s_data *i2s, int lvol, int rvol)
{
//writel(DACR0_LVOL(lvol) | DACR0_RVOL(rvol), i2s->base + I2S_DACR0);
}
int ark_i2s_set_rate(struct ark_i2s_data *i2s, int stream, unsigned int rate)
{
u32 step = 256 * 2, modulo;
u32 val, freq;
if (!i2s->nco_reg)
return 0;
xSemaphoreTake(i2s->mutex, portMAX_DELAY);
if(stream == AUDIO_STREAM_REPLAY)
{
if(i2s->cfg[stream].rates != rate)
i2s->cfg[stream].rates = rate;
}
else if(stream == AUDIO_STREAM_RECORD)
{
if(i2s->cfg[stream].rates != rate)
i2s->cfg[stream].rates = rate;
}
else
{
printf("%s, Invalid i2s stream:%d.\n", __func__, stream);
return -EINVAL;
}
/* mclk = rate * 256, mclk = freq * step / (2 * modulo) */
freq = ulClkGetRate(i2s->clkid);
modulo = freq / rate;
val = (step << 16) | modulo;
writel(val, i2s->nco_reg);
#if 0
writel(val, 0x6000006C); //set i2s0 rate.
#endif
xSemaphoreGive(i2s->mutex);
return 0;
}
int ark_i2s_set_params(struct ark_i2s_data *i2s, int stream, int rates, int channels, int bits)
{
int ret = 0;
xSemaphoreTake(i2s->mutex, portMAX_DELAY);
if(stream == AUDIO_STREAM_REPLAY)
{
i2s->cfg[stream].rates = rates;
i2s->cfg[stream].channels = channels;
i2s->cfg[stream].bits = bits;
}
else if(stream == AUDIO_STREAM_RECORD)
{
i2s->cfg[stream].rates = rates;
i2s->cfg[stream].channels = channels;
i2s->cfg[stream].bits = bits;
}
else
{
printf("%s, Invalid i2s stream:%d.\n", __func__, stream);
ret = -EINVAL;
}
xSemaphoreGive(i2s->mutex);
ark_i2s_set_rate(i2s, stream, rates);
return ret;
}
void ark_i2s_stop(struct ark_i2s_data *i2s, int stream)
{
ark_i2s_pd *pdata = i2s->extdata;
u32 val;
xSemaphoreTake(i2s->mutex, portMAX_DELAY);
if(stream == AUDIO_STREAM_REPLAY)
{
ark_i2s_stop_play(i2s);
if(i2s->dma_txch)
{
val = readl(i2s->base + I2S_SACR0);
val &= ~SACR0_TDMAEN;
writel(val, i2s->base + I2S_SACR0);
}
/* interrupt disable */
val = readl(i2s->base + I2S_SAIMR);
val &= ~(SAIMR_TFS | SAIMR_TUR);
writel(val, i2s->base + I2S_SAIMR);
}
else if(stream == AUDIO_STREAM_RECORD)
{
ark_i2s_stop_record(i2s);
if(i2s->dma_rxch)
{
val = readl(i2s->base + I2S_SACR0);
val &= ~SACR0_RDMAEN;
writel(val, i2s->base + I2S_SACR0);
}
/* interrupt disable */
val = readl(i2s->base + I2S_SAIMR);
val &= ~(SAIMR_ROR | SAIMR_RFS);
writel(val, i2s->base + I2S_SAIMR);
if(pdata && pdata->adc_ops.startup)
pdata->adc_ops.startup(0);
}
val = readl(i2s->base + I2S_SACR1);
if((val & (SACR1_DRPL | SACR1_DREC)) == (SACR1_DRPL | SACR1_DREC))
{
writel(readl(i2s->base + I2S_SACR0) & ~SACR0_ENB, i2s->base + I2S_SACR0);
}
xSemaphoreGive(i2s->mutex);
}
void i2s_interrupt_handler(void *param)
{
struct ark_i2s_data *i2s = (struct ark_i2s_data *)param;
unsigned int status;
//unsigned int val;
if(!i2s)
return;
status = readl(i2s->base + I2S_SASR0);
#if 1
writel(0xFF, i2s->base + I2S_SAICR);
if (status & SASR0_TUR) {
//printf("i2s txfifo underrun.\n");
}
#else
val = readl(i2s->base + I2S_SAICR);
if(status & SASR0_TFS)
val |= SAICR_TFS;
if(status & SASR0_TUR)
val |= SAICR_TUR;
if(status & SASR0_RFS)
val |= SAICR_RFS;
if(status & SASR0_ROR)
val |= SAICR_ROR;
writel(val, i2s->base + I2S_SAICR);
#endif
writel(0x0, i2s->base + I2S_SAICR);
}
static void i2s_sw_reset(struct ark_i2s_data *i2s)
{
writel(SACR0_RST, i2s->base + I2S_SACR0);
udelay(1);
writel(0, i2s->base + I2S_SACR0);
}
static int codec_init(struct ark_i2s_data *i2s, int flags)
{
ark_i2s_pd *pdata = NULL;
int ret = -1;
if(!i2s->extdata)
{
pdata = (ark_i2s_pd *)pvPortMalloc(sizeof(struct ark_i2s_private_data));
memset(&pdata->adc_ops, 0, sizeof(ark_i2s_pd));
i2s->extdata = (void *)pdata;
}
else
{
pdata = i2s->extdata;
}
if(pdata)
{
if((flags & AUDIO_FLAG_RECORD) == AUDIO_FLAG_RECORD)
{
#if AUDIO_CODEC_ADC_IC != AUDIO_CODEC_ADC_NONE
ret = audio_codec_adc_init(&pdata->adc_ops);
if(ret == 0)
{
if(pdata->adc_ops.init)
pdata->adc_ops.init(!i2s->cfg[AUDIO_STREAM_RECORD].master);
}
#endif
}
if((flags & AUDIO_FLAG_REPLAY) == AUDIO_FLAG_REPLAY)
{
#if AUDIO_CODEC_DAC_IC != AUDIO_CODEC_DAC_NONE
ret = audio_codec_dac_init(&pdata->dac_ops);
if(ret == 0)
{
if(pdata->dac_ops.init)
pdata->dac_ops.init(!i2s->cfg[AUDIO_STREAM_REPLAY].master);
}
#endif
}
}
return ret;
}
int ark_i2s_init(struct ark_i2s_data *i2s, int flags)
{
struct ark_i2s_cfg *cfg = NULL;
int softreset;
int irqn;
if(i2s->id == I2S_ID0)
{
softreset = softreset_i2s;
irqn = I2S_IRQn;
}
else if(i2s->id == I2S_ID1)
{
softreset = softreset_i2s1;
irqn = I2S1_IRQn;
}
else
{
printf("%s, Invalid i2s id:%d.\n", __func__, i2s->id);
return -EINVAL;
}
if(!(flags & AUDIO_FLAG_REPLAY_RECORD))
{
printf("%s, Invalid flags:0x%x.\n", __func__, flags);
return -EINVAL;
}
if((flags & AUDIO_FLAG_REPLAY_RECORD) == AUDIO_FLAG_REPLAY_RECORD)
i2s->full_duplex = 1;
else
i2s->full_duplex = 0;
if((flags & AUDIO_FLAG_REPLAY) == AUDIO_FLAG_REPLAY)
{
i2s->dma_txch = dma_request_channel(I2S_DMA_TXCH);
if (!i2s->dma_txch)
{
printf("%s() i2s replay dma_request_channel fail.\n", __func__);
return -ENODEV;
}
cfg = &i2s->cfg[AUDIO_STREAM_REPLAY];
memset(cfg, 0, sizeof(struct ark_i2s_cfg));
cfg->master = I2S_MASTER;
cfg->lfirst = 0;
}
if((flags & AUDIO_FLAG_RECORD) == AUDIO_FLAG_RECORD)
{
i2s->dma_rxch = dma_request_channel(I2S_DMA_RXCH);
if (!i2s->dma_rxch)
{
printf("%s() i2s record dma_request_channel fail.\n", __func__);
return -ENODEV;
}
cfg = &i2s->cfg[AUDIO_STREAM_RECORD];
memset(cfg, 0, sizeof(struct ark_i2s_cfg));
cfg->master = I2S_MASTER;
cfg->lfirst = 0;
}
i2s->mutex = xSemaphoreCreateMutex();
sys_soft_reset(softreset);
i2s_sw_reset(i2s);
request_irq(irqn, 0, i2s_interrupt_handler, i2s);
codec_init(i2s, flags);
return 0;
}

Some files were not shown because too many files have changed in this diff Show More