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,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;
}

View File

@ -0,0 +1,342 @@
#include "FreeRTOS.h"
#include "board.h"
#include "chip.h"
#ifdef REVERSE_TRACK
#include "vg_driver.h"
#endif
#define ITU656IN_MODULE_EN 0x00
#define ITU656IN_IMR 0x04
#define ITU656IN_ICR 0x08
#define ITU656IN_ISR 0x0C
#define ITU656IN_LINE_NUM_PER_FIELD 0x10
#define ITU656IN_PIX_NUM_PER_LINE 0x14
#define ITU656IN_PIX_LINE_NUM_DELTA 0x18
#define ITU656IN_INPUT_SEL 0x1c
#define ITU656IN_SEP_MODE_SEL 0x20
#define ITU656IN_H_STRAT 0x24
#define ITU656IN_H_END 0x28
#define ITU656IN_H_WIDTH 0x2c
#define ITU656IN_V_START_0 0x30
#define ITU656IN_V_END_0 0x34
#define ITU656IN_V_START_1 0x38
#define ITU656IN_V_END_1 0x3C
#define ITU656IN_V_FIELD_0 0x40
#define ITU656IN_V_FIELD_1 0x44
#define ITU656IN_P_N_DETECT 0x48
#define ITU656IN_ENABLE_REG 0x4c
#define ITU656IN_HFZ 0x50
#define ITU656IN_SIZE 0x54
#define ITU656IN_TOTAL_PIX 0x58
#define ITU656IN_DRAM_DEST1 0x5c
#define ITU656IN_DRAM_DEST2 0x60
#define ITU656IN_TOTAL_PIX_OUT 0x64
#define ITU656IN_OUTLINE_NUM_PER_FIELD 0x68
#define ITU656IN_H_cut_num 0x6c
#define ITU656IN_V_cut_num 0x70
#define ITU656IN_DATA_ERROR_MODE 0x74
#define ITU656IN_MIRR_SET 0x78
#define ITU656IN_RESET 0x7c
#define ITU656IN_OUTPUT_TYPE 0x80
#define ITU656IN_PN_DETCET 0x84
#define ITU656IN_YUV_TYPESEL 0x88
#define ITU656IN_POP_ERR_INT (1 << 10)
#define ITU656IN_SLICE_INT (1 << 9)
#ifndef VIN_SMALL_MEM
#define ITU656IN_BUF_NUM 3
#else
#define ITU656IN_BUF_NUM 2
#endif
#define ITUFRAME_MAX_WIDTH VIN_WIDTH
#define ITUFRAME_MAX_HEIGHT VIN_HEIGHT
typedef struct {
uint32_t yaddr;
uint32_t uvaddr;
int status;
} ItuBufInfo;
static uint32_t itubase = REGS_ITU_BASE;
static ItuBufInfo itubuf_info[ITU656IN_BUF_NUM] = {0};
static ItuConfigPara itu_para;
static TaskHandle_t itu_task;
static SemaphoreHandle_t itu_mutex = NULL;
static void *itu_buf = NULL;
static int itu_enable = 0;
static int itu_take_video = 0;
static void itu_push_addr(void)
{
int i;
for (i = 0; i < ITU656IN_BUF_NUM; i++) {
if (!itubuf_info[i].status) {
writel(itubuf_info[i].yaddr, itubase + ITU656IN_DRAM_DEST1);
writel(itubuf_info[i].uvaddr, itubase + ITU656IN_DRAM_DEST1);
itubuf_info[i].status = 1;
break;
}
}
}
static void itu_free_addr(uint32_t yaddr)
{
int i;
for (i = 0; i < ITU656IN_BUF_NUM; i++) {
if (itubuf_info[i].yaddr == yaddr) {
itubuf_info[i].status = 0;
break;
}
}
}
static void itu_interupt_handler(void *param)
{
unsigned int status = readl(itubase + ITU656IN_ISR);
unsigned int yaddr;
//printf("itu int status = 0x%x.\n", status);
writel(status, itubase + ITU656IN_ICR);
if (status & ITU656IN_POP_ERR_INT) {
printf("itu pop err.\n");
itu_push_addr();
}
if (status & ITU656IN_SLICE_INT) {
yaddr = readl(itubase + ITU656IN_DRAM_DEST1);
//printf("yaddr 0x%x.\n", yaddr);
itu_free_addr(yaddr);
itu_push_addr();
xTaskNotifyFromISR(itu_task, yaddr, eSetValueWithOverwrite, 0);
}
}
int itu_config(ItuConfigPara *para)
{
uint32_t val;
int ret = 0;
int i;
configASSERT(para->in_width <= ITUFRAME_MAX_WIDTH &&
para->in_height <= ITUFRAME_MAX_HEIGHT);
xSemaphoreTake(itu_mutex, portMAX_DELAY);
writel(0xffffffff, itubase + ITU656IN_ICR);
writel(1 << 2, itubase + ITU656IN_MODULE_EN);
val = readl(itubase + ITU656IN_SEP_MODE_SEL);
writel(val | (1 << 3), itubase + ITU656IN_SEP_MODE_SEL); //控制YUV顺序
writel(0, itubase + ITU656IN_IMR);
if (para->itu601) {
val = readl(itubase + ITU656IN_SEP_MODE_SEL);
val &= ~(1 << 2);
writel(val, itubase + ITU656IN_SEP_MODE_SEL);
writel(0, itubase + ITU656IN_INPUT_SEL);
val = readl(itubase + ITU656IN_MODULE_EN);
writel(val | 1, itubase + ITU656IN_MODULE_EN);
} else {
writel(1, itubase + ITU656IN_INPUT_SEL);
}
writel((5 << 1), itubase + ITU656IN_ENABLE_REG);
writel(0, itubase + ITU656IN_MIRR_SET); //镜像
writel(para->yuv_type & 1, itubase + ITU656IN_YUV_TYPESEL); //0:y_uv 1:yuyv
#ifndef VIN_SMALL_MEM
writel(para->out_format & 1, itubase + ITU656IN_OUTPUT_TYPE); //0:420 1:422
#else
writel(ITU_YUV420, itubase + ITU656IN_OUTPUT_TYPE); //0:420 1:422
#endif
writel(para->in_width << 16, itubase + ITU656IN_SIZE);
//奇偶场中断(P:720*288,N:720*240)
writel(para->in_width * para->in_height, itubase + ITU656IN_TOTAL_PIX_OUT);
//slice 中断(P:720*288,N:720*240)
writel(para->in_width * para->in_height, itubase + ITU656IN_TOTAL_PIX);
writel(para->in_height, itubase + ITU656IN_OUTLINE_NUM_PER_FIELD);
//reset fifo
val = readl(itubase + ITU656IN_RESET);
val |= 1 << 1;
writel(val, itubase + ITU656IN_RESET);
udelay(10);
val &= ~(1 << 1);
writel(val, itubase + ITU656IN_RESET);
//push addr
for(i = 0; i < ITU656IN_BUF_NUM; i++) {
#ifndef VIN_SMALL_MEM
if (para->out_format == ITU_YUV422)
itubuf_info[i].yaddr = (uint32_t)itu_buf + para->in_width * para->in_height * 2 * i;
else
#endif
itubuf_info[i].yaddr = (uint32_t)itu_buf + para->in_width * para->in_height * 3 / 2 * i;
if (itubuf_info[i].yaddr == 0) {
printf("no enough memory for itu frames.\n");
ret = -ENOMEM;
goto end;
}
itubuf_info[i].uvaddr = itubuf_info[i].yaddr + para->in_width * para->in_height;
writel(itubuf_info[i].yaddr, itubase + ITU656IN_DRAM_DEST1);
writel(itubuf_info[i].uvaddr, itubase + ITU656IN_DRAM_DEST1);
itubuf_info[i].status = 1;
}
/* enable slice int */
writel(ITU656IN_POP_ERR_INT | ITU656IN_SLICE_INT, itubase + ITU656IN_IMR);
memcpy(&itu_para, para, sizeof(itu_para));
end:
xSemaphoreGive(itu_mutex);
return ret;
}
void itu_start(void)
{
uint32_t val;
//enable write data
xSemaphoreTake(itu_mutex, portMAX_DELAY);
val = readl(itubase + ITU656IN_MODULE_EN);
val &= ~(1 << 2);
writel(val, itubase + ITU656IN_MODULE_EN);
val = readl(itubase + ITU656IN_ENABLE_REG);
writel(val | 1, itubase + ITU656IN_ENABLE_REG);
itu_enable = 1;
xSemaphoreGive(itu_mutex);
}
void itu_stop(void)
{
uint32_t val;
//disable write data
xSemaphoreTake(itu_mutex, portMAX_DELAY);
val = readl(itubase + ITU656IN_MODULE_EN);
val |= (1 << 2);
writel(val, itubase + ITU656IN_MODULE_EN);
val = readl(itubase + ITU656IN_ENABLE_REG);
writel(val & ~1, itubase + ITU656IN_ENABLE_REG);
itu_enable = 0;
#ifndef REVERSE_UI
ark_lcd_osd_enable(LCD_VIDEO_LAYER, 0);
ark_lcd_set_osd_sync(LCD_VIDEO_LAYER);
ark_lcd_osd_enable(LCD_OSD1, 1);
ark_lcd_set_osd_sync(LCD_OSD1);
#endif
xTaskNotify(itu_task, 0, eSetValueWithOverwrite);
xSemaphoreGive(itu_mutex);
}
void itu_display_thread(void *param)
{
uint32_t ulNotifiedValue;
uint32_t yaddr, uvaddr, dstaddr;
int format;
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);
//printf("received address 0x%x.\n", ulNotifiedValue);
xSemaphoreTake(itu_mutex, portMAX_DELAY);
if (!itu_enable) {
xSemaphoreGive(itu_mutex);
vVideoDisplayBufFree(dstaddr);
/* 倒车显示优先级高,等倒车结束之后才释放视频显示资源 */
if (itu_take_video) {
vVideoDisplayBufGive();
itu_take_video = 0;
}
continue;
}
/* 获取视频显示资源 */
if (!itu_take_video) {
xVideoDisplayBufTake(portMAX_DELAY);
itu_take_video = 1;
}
if (!ark_lcd_get_osd_info_atomic_isactive(LCD_VIDEO_LAYER)) {
ark_lcd_wait_for_vsync();
}
/* 通过该接口获取视频显示共用的缓存可以避免切换过程中的黑屏、
花屏等问题 */
dstaddr = ulVideoDisplayBufGet();
yaddr = ulNotifiedValue;
uvaddr = yaddr + itu_para.in_width * itu_para.in_height;
#ifndef VIN_SMALL_MEM
if (itu_para.out_format == ITU_YUV422)
format = PXP_SRC_FMT_YUV2P422;
else
#endif
format = PXP_SRC_FMT_YUV2P420;
pxp_scaler_rotate(yaddr, uvaddr, 0, format, itu_para.in_width, itu_para.in_height,
dstaddr, 0, PXP_OUT_FMT_RGB565, itu_para.out_width, itu_para.out_height, LCD_ROTATE_ANGLE);
#ifdef REVERSE_TRACK
extern int get_reverse_track_index(void);
static int index = 58;
index = get_reverse_track_index();
xm_vg_set_gpu_fb_addr(dstaddr);
xm_vg_draw_prepare(&index);
xm_vg_draw_start();
#endif
LcdOsdInfo info = {0};
info.x = itu_para.out_x;
info.y = itu_para.out_y;
info.width = itu_para.out_width;
info.height = itu_para.out_height;
info.format = LCD_OSD_FORAMT_RGB565;
info.yaddr = dstaddr;
ark_lcd_set_osd_info_atomic(LCD_VIDEO_LAYER, &info);
ark_lcd_osd_enable(LCD_VIDEO_LAYER, 1);
ark_lcd_set_osd_sync(LCD_VIDEO_LAYER);
#ifndef REVERSE_UI
ark_lcd_osd_enable(LCD_OSD1, 0);
ark_lcd_set_osd_sync(LCD_OSD1);
#endif
vVideoDisplayBufRender(dstaddr);
xSemaphoreGive(itu_mutex);
vTaskDelay(pdMS_TO_TICKS(1));
}
}
int itu_init(void)
{
sys_soft_reset(softreset_itu);
itu_mutex = xSemaphoreCreateMutex();
#ifndef VIN_SMALL_MEM
itu_buf = pvPortMalloc(ITUFRAME_MAX_WIDTH * ITUFRAME_MAX_HEIGHT * 2 * ITU656IN_BUF_NUM);
#else
itu_buf = pvPortMalloc(ITUFRAME_MAX_WIDTH * ITUFRAME_MAX_HEIGHT * 3 / 2 * ITU656IN_BUF_NUM);
#endif
if (!itu_buf) {
printf("Itu malloc memory fail.\n");
return -ENOMEM;
}
if (xTaskCreate(itu_display_thread, "itudis", configMINIMAL_STACK_SIZE, NULL,
configMAX_PRIORITIES - 2, &itu_task) != pdPASS) {
printf("create itu display task fail.\n");
return -1;
}
request_irq(ITU_IRQn, 0, itu_interupt_handler, NULL);
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,222 @@
#include <string.h>
#include "FreeRTOS.h"
#include "chip.h"
#include "board.h"
#if LCD_INTERFACE_TYPE == LCD_INTERFACE_MIPI
#define ARK_MIPI_WRITEL(reg, val) writel(val, REGS_MIPI_BASE+reg)
#define ARK_MIPI_READL(reg) readl(REGS_MIPI_BASE+reg)
void mipi_init(void)
{
unsigned int val;
udelay(10000);
val = readl(REGS_SYSCTL_BASE + SYS_ANA1_CFG);
val |= (0x3 <<30)|(0x7 <<22);
writel(val, REGS_SYSCTL_BASE + SYS_ANA1_CFG);
val = readl(REGS_SYSCTL_BASE + SYS_PERCTL_CFG);
val |= (0x1<<8);
writel(val, REGS_SYSCTL_BASE + SYS_PERCTL_CFG);
ARK_MIPI_WRITEL(0x04, 0x0);
ARK_MIPI_WRITEL(0xa0, 0x0);
ARK_MIPI_WRITEL(0x08, 0x17);
ARK_MIPI_WRITEL(0x2c, 0x1c);
ARK_MIPI_WRITEL(0x9c, 0x09000c);
ARK_MIPI_WRITEL(0x94, 0x0);
ARK_MIPI_WRITEL(0x98, 0x180014);
ARK_MIPI_WRITEL(0xa4, 0x2803);
//ARK_MIPI_WRITEL(0x38, 0x1bf02);
ARK_MIPI_WRITEL(0x38, 0xbf02);
ARK_MIPI_WRITEL(0x0c, 0x0);
ARK_MIPI_WRITEL(0x68,0x000b4700);
// <20><>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD><CABD><EFBFBD><EFBFBD>
ARK_MIPI_WRITEL(0x10, 0x5);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ARK_MIPI_WRITEL(0x14, 0x0);// active high
// <20><>Ч<EFBFBD><D0A7><EFBFBD><EFBFBD>720
ARK_MIPI_WRITEL(0x3c, 0x1e0);
// HSAΪ12
ARK_MIPI_WRITEL(0x48, 29);
// Thbp = (Pixel clk period/Clklane byte period)*HBP
ARK_MIPI_WRITEL(0x4c, 18);
// Thline = (Pixel clk period/Clklane byte period)*HLINE
// HLINE = HSA+HBP+HACT+HFP
ARK_MIPI_WRITEL(0x50, 0x237);
ARK_MIPI_WRITEL(0x54, 0x10);// VSA <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ARK_MIPI_WRITEL(0x58, 0x6);// VBP <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ARK_MIPI_WRITEL(0x5c, 0x6);// VFP <20><>ǰ<EFBFBD><C7B0>
ARK_MIPI_WRITEL(0x60, 0x500);// VACT <20><><EFBFBD><EFBFBD>Ч
ARK_MIPI_WRITEL(0x34, 0x1);
ARK_MIPI_WRITEL(0x18, 0xa000a);
ARK_MIPI_WRITEL(0xc4, 0xffffffff);
ARK_MIPI_WRITEL(0xc8, 0xffffffff);
ARK_MIPI_WRITEL(0x04, 0x1);
ARK_MIPI_WRITEL(0xa0, 0xf);
ARK_MIPI_WRITEL(0xb8, 0x44);
ARK_MIPI_WRITEL(0xb8, 0x10044);
ARK_MIPI_WRITEL(0xb4, 0x2);
ARK_MIPI_WRITEL(0xb4, 0x0);
ARK_MIPI_WRITEL(0xb8, 0x2c);
ARK_MIPI_WRITEL(0xb4, 0x2);
ARK_MIPI_WRITEL(0xb4, 0x0);
while(!(ARK_MIPI_READL(0xb0) & 0x5));
// <20><><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E0BBB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>PHY<48><59><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɺ<EFBFBD>
ARK_MIPI_WRITEL(0x94, 0x1);
//udelay(200000);
//ARK_MIPI_WRITEL(0x180, 0x4);
ARK_MIPI_WRITEL(0x100, 0x1000000);
udelay(200000);
//panel init
ARK_MIPI_WRITEL(0x70, 0x9483ffb9);
ARK_MIPI_WRITEL(0x6c, 0x439);
ARK_MIPI_WRITEL(0x70, 0x721248b1);
ARK_MIPI_WRITEL(0x70, 0x71243209);
ARK_MIPI_WRITEL(0x70, 0x432f51);
ARK_MIPI_WRITEL(0x6c, 0xb39);
udelay(10000);
ARK_MIPI_WRITEL(0x70, 0x680363ba);
ARK_MIPI_WRITEL(0x70, 0xc0b26b);
ARK_MIPI_WRITEL(0x6c, 0x739);
ARK_MIPI_WRITEL(0x70, 0x64a040b2);
ARK_MIPI_WRITEL(0x70, 0x2f0a0e);
ARK_MIPI_WRITEL(0x6c, 0x739);
udelay(10000);
ARK_MIPI_WRITEL(0x70, 0x1c781cb4);
ARK_MIPI_WRITEL(0x70, 0x01781c78);
ARK_MIPI_WRITEL(0x70, 0x0055860c);
ARK_MIPI_WRITEL(0x70, 0x1c781c3f);
ARK_MIPI_WRITEL(0x70, 0x01781c78);
ARK_MIPI_WRITEL(0x70, 0x860c);
ARK_MIPI_WRITEL(0x6c, 0x1639);
ARK_MIPI_WRITEL(0x70, 0x000000d3);
ARK_MIPI_WRITEL(0x70, 0x08076400);
ARK_MIPI_WRITEL(0x70, 0x07103208);
ARK_MIPI_WRITEL(0x70, 0x15320700);
ARK_MIPI_WRITEL(0x70, 0x00150515);
ARK_MIPI_WRITEL(0x70, 0x00081032);
ARK_MIPI_WRITEL(0x70, 0x09093335);
ARK_MIPI_WRITEL(0x70, 0x37070d37);
ARK_MIPI_WRITEL(0x70, 0x080e);
ARK_MIPI_WRITEL(0x6c, 0x2239);
udelay(10000);
ARK_MIPI_WRITEL(0x70, 0x241818d5);
ARK_MIPI_WRITEL(0x70, 0x1b1a1a24);
ARK_MIPI_WRITEL(0x70, 0x0605041b);
ARK_MIPI_WRITEL(0x70, 0x02010007);
ARK_MIPI_WRITEL(0x70, 0x19181803);
ARK_MIPI_WRITEL(0x70, 0x22212019);
ARK_MIPI_WRITEL(0x70, 0x18181823);
ARK_MIPI_WRITEL(0x70, 0x18181818);
ARK_MIPI_WRITEL(0x70, 0x18181818);
ARK_MIPI_WRITEL(0x70, 0x18181818);
ARK_MIPI_WRITEL(0x70, 0x18181818);
ARK_MIPI_WRITEL(0x070, 0x18);
ARK_MIPI_WRITEL(0x6c, 0x2d39);
udelay(10000);
ARK_MIPI_WRITEL(0x70, 0x241919d6);
ARK_MIPI_WRITEL(0x70, 0x1b1a1a24);
ARK_MIPI_WRITEL(0x70, 0x0102031b);
ARK_MIPI_WRITEL(0x70, 0x05060700);
ARK_MIPI_WRITEL(0x70, 0x18181804);
ARK_MIPI_WRITEL(0x70, 0x21222318);
ARK_MIPI_WRITEL(0x70, 0x18181820);
ARK_MIPI_WRITEL(0x70, 0x18181818);
ARK_MIPI_WRITEL(0x70, 0x18181818);
ARK_MIPI_WRITEL(0x70, 0x18181818);
ARK_MIPI_WRITEL(0x70, 0x18181818);
ARK_MIPI_WRITEL(0x70, 0x18);
ARK_MIPI_WRITEL(0x6c, 0x2d39);
udelay(10000);
ARK_MIPI_WRITEL(0x70, 0x4848b6);
ARK_MIPI_WRITEL(0x6c, 0x339);
ARK_MIPI_WRITEL(0x70, 0x281e00e0);
ARK_MIPI_WRITEL(0x70, 0x3733302f);
ARK_MIPI_WRITEL(0x70, 0x887a6b34);
ARK_MIPI_WRITEL(0x70, 0x9e9b8b84);
ARK_MIPI_WRITEL(0x70, 0xa4aaaa9f);
ARK_MIPI_WRITEL(0x70, 0x5d5fc0b1);
ARK_MIPI_WRITEL(0x70, 0x70686561);
ARK_MIPI_WRITEL(0x70, 0x1e007f7e);
ARK_MIPI_WRITEL(0x70, 0x33302f28);
ARK_MIPI_WRITEL(0x70, 0x7a6b3437);
ARK_MIPI_WRITEL(0x70, 0x9b8b8488);
ARK_MIPI_WRITEL(0x70, 0xaaaa9f9e);
ARK_MIPI_WRITEL(0x70, 0x5fc0b1a4);
ARK_MIPI_WRITEL(0x70, 0x6865615d);
ARK_MIPI_WRITEL(0x70, 0x7f7e70);
ARK_MIPI_WRITEL(0x6c, 0x3b39);
udelay(10000);
ARK_MIPI_WRITEL(0x70, 0x3cc);
ARK_MIPI_WRITEL(0x6c, 0x239);
ARK_MIPI_WRITEL(0x70, 0x311fc0);
ARK_MIPI_WRITEL(0x6c, 0x339);
ARK_MIPI_WRITEL(0x070, 0x2d4);
ARK_MIPI_WRITEL(0x6c, 0x239);
udelay(10000);
ARK_MIPI_WRITEL(0x70, 0x1bd);
ARK_MIPI_WRITEL(0x6c, 0x239);
ARK_MIPI_WRITEL(0x70, 0xb1);
ARK_MIPI_WRITEL(0x6c, 0x239);
ARK_MIPI_WRITEL(0x70, 0xbd);
ARK_MIPI_WRITEL(0x6c, 0x239);
ARK_MIPI_WRITEL(0x70, 0xedc6);
ARK_MIPI_WRITEL(0x6c, 0x239);
ARK_MIPI_WRITEL(0x6c, 0x1105);
udelay(250000);
ARK_MIPI_WRITEL(0x6c, 0x2905);
udelay(120000);
ARK_MIPI_WRITEL(0x38, 0x3f02);
ARK_MIPI_WRITEL(0x34, 0x0);
}
#endif

View File

@ -0,0 +1,154 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2013, 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 mmu MMU Initialization
*
* \section Usage
*
* Translation Lookaside Buffers (TLBs) are an implementation technique that caches translations or
* translation table entries. TLBs avoid the requirement for every memory access to perform a translation table
* lookup. The ARM architecture does not specify the exact form of the TLB structures for any design. In a
* similar way to the requirements for caches, the architecture only defines certain principles for TLBs:
*
* The MMU supports memory accesses based on memory sections or pages:
* Supersections Consist of 16MB blocks of memory. Support for Supersections is optional.
* -# Sections Consist of 1MB blocks of memory.
* -# Large pages Consist of 64KB blocks of memory.
* -# Small pages Consist of 4KB blocks of memory.
*
* Access to a memory region is controlled by the access permission bits and the domain field in the TLB entry.
* Memory region attributes
* Each TLB entry has an associated set of memory region attributes. These control accesses to the caches,
* how the write buffer is used, and if the memory region is Shareable and therefore must be kept coherent.
*
* Related files:\n
* \ref mmu.c\n
* \ref mmu.h \n
*/
/*------------------------------------------------------------------------------ */
/* Headers */
/*------------------------------------------------------------------------------ */
#include <chip.h>
/*------------------------------------------------------------------------------ */
/* Exported functions */
/*------------------------------------------------------------------------------ */
/**
* \brief Initializes MMU.
* \param pTB Address of the translation table.
*/
void MMU_Initialize(uint32_t *pTB)
{
unsigned int index;
unsigned int addr;
/* Reset table entries */
for (index = 0; index < 4096; index++)
pTB[index] = 0;
/* interrupt vector address (after remap) 0x0000_0000 */
pTB[0x000] = (0x200 << 20)| // Physical Address
// ( 1 << 12)| // TEX[0]
( 3 << 10)| // Access in supervisor mode (AP)
( 0xF << 5)| // Domain 0xF
( 1 << 4)| // (XN)
( 0 << 3)| // C bit : cachable => YES
( 0 << 2)| // B bit : write-back => YES
( 2 << 0); // Set as 1 Mbyte section
/* SRAM address (after remap) 0x0030_0000 */
pTB[0x003] = (0x003 << 20)| // Physical Address
// ( 1 << 12)| // TEX[0]
( 3 << 10)| // Access in supervisor mode (AP)
( 0xF << 5)| // Domain 0xF
( 1 << 4)| // (XN)
( 0 << 3)| // C bit : cachable => YES
( 0 << 2)| // B bit : write-back => YES
( 2 << 0); // Set as 1 Mbyte section
/* DDRAM address (after remap) 0x2000_0000 */
for(addr = 0x200; addr < 0x240; addr++)
pTB[addr] = (addr << 20)| // Physical Address
( 1 << 18)| // 16MB Supersection
( 3 << 10)| // Access in supervisor mode (AP)
( 1 << 12)| // TEX[0]
( 0 << 5)| // Domain 0x0, Supersection only support domain 0
( 0 << 4)| // (XN)
( 1 << 3)| // C bit : cachable => YES
( 1 << 2)| // B bit : write-back => YES
( 2 << 0); // Set as 1 Mbyte section
/* DDRAM non-cache address (after remap) 0x3000_0000 */
for(addr = 0x300; addr < 0x340; addr++)
pTB[addr] = ((addr - 0x100) << 20)| // Physical Address
( 1 << 18)| // 16MB Supersection
( 3 << 10)| // Access in supervisor mode (AP)
( 1 << 12)| // TEX[0]
( 0 << 5)| // Domain 0x0, Supersection only support domain 0
( 0 << 4)| // (XN)
( 0 << 3)| // C bit : cachable => YES
( 0 << 2)| // B bit : write-back => YES
( 2 << 0); // Set as 1 Mbyte section
// periph address 0x60000000 ~ 0x80000000
for(addr = 0x600; addr < 0x800; addr++)
pTB[addr] = (addr << 20)| // Physical Address
( 3 << 10)| // Access in supervisor mode (AP)
( 0xF << 5)| // Domain 0xF
( 1 << 4)| // (XN)
( 0 << 3)| // C bit : cachable => NO
( 0 << 2)| // B bit : write-back => NO
( 2 << 0); // Set as 1 Mbyte section
CP15_WriteTTB((unsigned int)pTB);
/* Program the domain access register */
CP15_WriteDomainAccessControl(0xC0000003); // only domain 0 & 15: access are not checked
}
void dma_inv_range(UINT32 ulStart, UINT32 ulEnd)
{
CP15_invalidate_dcache_for_dma (ulStart, ulEnd);
}
void dma_clean_range(UINT32 ulStart, UINT32 ulEnd)
{
CP15_clean_dcache_for_dma (ulStart, ulEnd);
}
// flush<73><68>clean and invalidate
void dma_flush_range(UINT32 ulStart, UINT32 ulEnd)
{
CP15_flush_dcache_for_dma (ulStart, ulEnd);
}

View File

@ -0,0 +1,337 @@
#include "FreeRTOS.h"
#include "board.h"
#include "chip.h"
#define PINCTL_REG_BASE REGS_SYSCTL_BASE
#define MAX_PINS_PER_GROUP 32
typedef struct {
short muxio;
short pinval;
int drive;
} xPin_t;
typedef struct {
int groupid;
uint32_t mux_reg;
uint32_t mux_offset;
uint32_t mux_mask;
uint32_t mux_val;
short pins_num;
xPin_t pins[MAX_PINS_PER_GROUP];
} xPinGroup_t;
/* typedef struct {
} xPinFunction_t; */
typedef struct {
int reg;
int offset;
int mask;
} xPinmap_t;
static xPinmap_t amt630h_pin_map[] = {
{0xc0, 0, 0x3},
{0xc0, 2, 0x3},
{0xc0, 4, 0x3},
{0xc0, 6, 0x3},
{0xc0, 8, 0x3},
{0xc0, 10, 0x3},
{0xc0, 12, 0x3},
{0xc0, 14, 0x3},
{0xc0, 16, 0x3},
{0xc0, 18, 0x3},
{0xc0, 20, 0x3},
{0xc0, 22, 0x3},
{0xc0, 24, 0x3},
{0xc0, 26, 0x3},
{0xc0, 28, 0x3},
{0xc0, 30, 0x3},
{0xc4, 0, 0x3},
{0xc4, 2, 0x3},
{0xc4, 4, 0x3},
{0xc4, 6, 0x3},
{0xc4, 8, 0x3},
{0xc4, 10, 0x3},
{0xc4, 12, 0x3},
{0xc4, 14, 0x3},
{0xc4, 16, 0x3},
{0xc4, 18, 0x3},
{0xc4, 20, 0x3},
{0xc4, 22, 0x3},
{0xc4, 24, 0x3},
{0xc4, 26, 0x3},
{0xc4, 28, 0x3},
{0xc4, 30, 0x3},
{0xc8, 0, 0x3},
{0xc8, 2, 0x3},
{0xc8, 4, 0x3},
{0xc8, 6, 0x3},
{0xc8, 8, 0x3},
{0xc8, 10, 0x3},
{0xc8, 12, 0x3},
{0xc8, 14, 0x3},
{0xc8, 16, 0x3},
{0xc8, 18, 0x3},
{0xc8, 20, 0x3},
{0xc8, 22, 0x3},
{0xc8, 24, 0x3},
{0xc8, 26, 0x3},
{0xc8, 28, 0x3},
{0xc8, 30, 0x3},
{0xcc, 0, 0x3},
{0xcc, 2, 0x3},
{0xcc, 4, 0x3},
{0xcc, 6, 0x3},
{0xcc, 8, 0x3},
{0xcc, 10, 0x3},
{0xcc, 12, 0x3},
{0xcc, 14, 0x3},
{0xcc, 16, 0x3},
{0xcc, 18, 0x3},
{0xcc, 20, 0x3},
{0xcc, 22, 0x3},
{0xcc, 24, 0x3},
{0xcc, 26, 0x3},
{0xcc, 28, 0x3},
{0xcc, 30, 0x3},
{0xd0, 0, 0x3},
{0xd0, 2, 0x3},
{0xd0, 4, 0x3},
{0xd0, 6, 0x3},
{0xd0, 8, 0x3},
{0xd0, 10, 0x3},
{0xd0, 12, 0x3},
{0xd0, 14, 0x3},
{0xd0, 16, 0x3},
{0xd0, 18, 0x3},
{0xd0, 20, 0x3},
{0xd0, 22, 0x3},
{0xd0, 24, 0x3},
{0xd0, 26, 0x3},
{0xd0, 28, 0x3},
{0xd0, 30, 0x3},
{0xd4, 0, 0x3},
{0xd4, 2, 0x3},
{0xd4, 4, 0x3},
{0xd4, 6, 0x3},
{0xd4, 8, 0x3},
{0xd4, 10, 0x3},
{0xd4, 12, 0x3},
{0xd4, 14, 0x3},
{0xd4, 16, 0x3},
{0xd4, 18, 0x3},
{0xd4, 20, 0x3},
{0xd4, 22, 0x3},
{0xd4, 24, 0x3},
{0xd4, 26, 0x3},
{0xd4, 28, 0x3},
{0xd4, 30, 0x3},
{0xd8, 4, 0x3},
{0xd8, 0, 0x3},
{0xd8, 6, 0x3},
{0xd8, 2, 0x3},
{0xd8, 8, 0x3},
{0xd8, 10, 0x3},
/* pad not mux with gpio */
};
#define PIN_NUM ARRAY_SIZE(amt630h_pin_map)
static xPinGroup_t pin_groups[] = {
/* scl sda */
{.groupid = PGRP_I2C0, .pins_num = 2, .pins = {{48, 1}, {49, 1}}},
/* scl sda */
{.groupid = PGRP_I2C1, .pins_num = 2, .pins = {{50, 1}, {51, 1}}},
{.groupid = PGRP_LCD_TTL_CH0, .pins_num = 28,
/* de clk vynsc hsync */
.pins = {{88, 1}, {89, 1, PAD_DRIVE_2MA}, {90, 1}, {91, 1},
{64, 1}, {65, 1}, {66, 1}, {67, 1}, {68, 1}, {69, 1}, {70, 1}, {71, 1}, /* B0-B7 */
{72, 1}, {73, 1}, {74, 1}, {75, 1}, {76, 1}, {77, 1}, {78, 1}, {79, 1}, /* G0-G7 */
{80, 1}, {81, 1}, {82, 1}, {83, 1}, {84, 1}, {85, 1}, {86, 1}, {87, 1},}}, /* R0-R7 */
{.groupid = PGRP_LCD_TTL_CH1, .pins_num = 28,
/* de clk vynsc hsync */
.pins = {{12, 1}, {13, 1}, {14, 1}, {15, 1},
{64, 1}, {65, 1}, {66, 1}, {67, 1}, {68, 1}, {69, 1}, {70, 1}, {71, 1}, /* r0-r7 */
{72, 1}, {73, 1}, {74, 1}, {75, 1}, {84, 3}, {85, 3}, {86, 3}, {87, 3}, /* g0-g7 */
{88, 3}, {89, 3}, {90, 3}, {91, 3}, {8, 1}, {9, 1}, {10, 1}, {11, 1},}}, /* b0-b7 */
{.groupid = PGRP_LCD_LVDS, .pins_num = 10,
/* dp dn clkp clkn cp cn bp bn */
.pins = {{64, 2}, {65, 2}, {66, 2}, {67, 2}, {68, 2}, {69, 2}, {70, 2}, {71, 2},
/* ap an */
{72, 2}, {73, 2}, }},
{.groupid = PGRP_LCD_SRGB, .pins_num = 8,
.pins = {{74, 1}, {75, 1}, {76, 1}, {77, 1}, {78, 1}, {79, 1}, {80, 1}, {81, 1},}}, /* d0-d7 */
/* 由于uart0有些平台rx没有接上拉电阻需要将rx脚配置成gpio防止收到随机数据导致异常 */
{.groupid = PGRP_UART0, .pins_num = 2, .pins = {{38, 1}, {39, 1}}},
/* rx tx */
{.groupid = PGRP_UART1, .pins_num = 2, .pins = {{40, 1}, {41, 1}}},
/* rx tx */
{.groupid = PGRP_UART2, .pins_num = 2, .pins = {{42, 1}, {43, 1}}},
/* rx tx */
{.groupid = PGRP_UART3, .pins_num = 2, .pins = {{44, 1}, {45, 1}}},
/* cs clk d0 d1 d2 d3 */
{.groupid = PGRP_SPI0, .pins_num = 5, .pins = {/*{32, 1},*/ {33, 1}, {34, 1}, {35, 1}, {36, 1}, {37, 1}}},
/* cs clk txd rxd */
{.groupid = PGRP_SPI1, .pins_num = 3, .pins = {/*{23, 1},*/ {24, 1}, {25, 1}, {26, 1}}},
{.groupid = PGRP_SDMMC0, .pins_num = 7, .pins = {{16, 1}, {17, 1}, {18, 1}, {19, 1},
{20, 1}, {21, 1}, {22, 1}}},
{.groupid = PGRP_PWM0, .pins_num = 1, .pins = {{0, 1}}},
{.groupid = PGRP_PWM1, .pins_num = 1, .pins = {{1, 1}}},
{.groupid = PGRP_PWM2, .pins_num = 1, .pins = {{60, 1}}},
{.groupid = PGRP_PWM3, .pins_num = 1, .pins = {{47, 1}}},//47
{.groupid = PGRP_PWM0_IN, .pins_num = 1, .pins = {{4, 0}},//pin18 GPIO4
.mux_reg = 0x60000120, .mux_offset = 12, .mux_mask = 0x3, .mux_val = 0},
{.groupid = PGRP_PWM1_IN, .pins_num = 1, .pins = {{5, 0}},//pin19 GPIO5
.mux_reg = 0x60000120, .mux_offset = 14, .mux_mask = 0x3, .mux_val = 0},
{.groupid = PGRP_PWM2_IN, .pins_num = 1, .pins = {{6, 0}},//pin47 GPIO6
.mux_reg = 0x60000120, .mux_offset = 28, .mux_mask = 0x3, .mux_val = 0},
{.groupid = PGRP_PWM3_IN, .pins_num = 1, .pins = {{7, 0}},//pin48 GPIO7
.mux_reg = 0x60000120, .mux_offset = 30, .mux_mask = 0x3, .mux_val = 0},
{.groupid = PGRP_ITU_CH0, .pins_num = 11,
.pins = {{1, 0}, {2, 0}, {3, 0}, {4, 0}, {96, 0}, {97, 0}, {98, 0}, {99, 0}, /* d0-d7 */
{100, 0}, {101, 0}, {0, 0}}, /* hs, vs, clk */
.mux_reg = 0x600000dc, .mux_offset = 16, .mux_mask = 0x7, .mux_val = 2},
{.groupid = PGRP_ITU_CH0_INV, .pins_num = 11,
.pins = {{1, 0}, {2, 0}, {3, 0}, {4, 0}, {96, 0}, {97, 0}, {98, 0}, {99, 0}, /* d0-d7 */
{100, 0}, {101, 0}, {0, 0}}, /* hs, vs, clk */
.mux_reg = 0x600000dc, .mux_offset = 16, .mux_mask = 0x7, .mux_val = 6},
{.groupid = PGRP_ITU_CH1, .pins_num = 11,
.pins = {{8, 0}, {9, 0}, {10, 0}, {11, 0}, {12, 0}, {13, 0}, {14, 0}, {15, 0}, /* d0-d7 */
{59, 0}, {60, 0}, {61, 0}}, /* hs, vs, clk */
.mux_reg = 0x600000dc, .mux_offset = 16, .mux_mask = 0x7, .mux_val = 3},
{.groupid = PGRP_ITU_CH1_INV, .pins_num = 11,
.pins = {{8, 0}, {9, 0}, {10, 0}, {11, 0}, {12, 0}, {13, 0}, {14, 0}, {15, 0}, /* d0-d7 */
{59, 0}, {60, 0}, {61, 0}}, /* hs, vs, clk */
.mux_reg = 0x600000dc, .mux_offset = 16, .mux_mask = 0x7, .mux_val = 7},
/* tx rx */
{.groupid = PGRP_CAN0_CH0, .pins_num = 2, .pins = {{0, 2}, {1, 2}},
.mux_reg = 0x600000dc, .mux_offset = 19, .mux_mask = 0x3, .mux_val = 1},
{.groupid = PGRP_CAN0_CH1, .pins_num = 2, .pins = {{12, 2}, {13, 2}},
.mux_reg = 0x600000dc, .mux_offset = 19, .mux_mask = 0x3, .mux_val = 2},
{.groupid = PGRP_CAN0_CH2, .pins_num = 2, .pins = {{96, 2}, {97, 2}},
.mux_reg = 0x600000dc, .mux_offset = 19, .mux_mask = 0x3, .mux_val = 3},
{.groupid = PGRP_CAN1_CH0, .pins_num = 2, .pins = {{2, 2}, {3, 2}},
.mux_reg = 0x600000dc, .mux_offset = 21, .mux_mask = 0x3, .mux_val = 1},
{.groupid = PGRP_CAN1_CH1, .pins_num = 2, .pins = {{14, 2}, {15, 2}},
.mux_reg = 0x600000dc, .mux_offset = 21, .mux_mask = 0x3, .mux_val = 2},
{.groupid = PGRP_CAN1_CH2, .pins_num = 2, .pins = {{98, 2}, {99, 2}},
.mux_reg = 0x600000dc, .mux_offset = 21, .mux_mask = 0x3, .mux_val = 3},
{.groupid = PGRP_I2S0_PLAY, .pins_num = 4, .pins = {{52, 1, PAD_DRIVE_2MA}, {54, 1, PAD_DRIVE_2MA}, {55, 1, PAD_DRIVE_2MA}, {56, 1, PAD_DRIVE_2MA}}},
{.groupid = PGRP_I2S0_RECORD, .pins_num = 4, .pins = {{52, 1, PAD_DRIVE_2MA}, {53, 1, PAD_DRIVE_2MA}, {55, 1, PAD_DRIVE_2MA}, {56, 1, PAD_DRIVE_2MA}}},
{.groupid = PGRP_I2S1_PLAY, .pins_num = 4, .pins = {{23, 1, PAD_DRIVE_2MA}, {24, 1, PAD_DRIVE_2MA}, {25, 1, PAD_DRIVE_2MA}, {26, 1, PAD_DRIVE_2MA}},
//bit2: select i2s1 function(bit[2] 0:ssp1_interface; 1:i2s1_interface).
//bit3: i2s1 data pin output(bit[3] 0:input, 1:output).
.mux_reg = REGS_SYSCTL_BASE + SYS_PAD_CTRL08, .mux_offset = 2, .mux_mask = 0x3, .mux_val = 3},
{.groupid = PGRP_I2S1_RECORD, .pins_num = 4, .pins = {{23, 1, PAD_DRIVE_2MA}, {24, 1, PAD_DRIVE_2MA}, {25, 1, PAD_DRIVE_2MA}, {26, 1, PAD_DRIVE_2MA}},
//bit2: select i2s1 function(bit[2] 0:ssp1_interface; 1:i2s1_interface).
//bit3: i2s1 data pin input(bit[3] 0:input, 1:output).
.mux_reg = REGS_SYSCTL_BASE + SYS_PAD_CTRL08, .mux_offset = 2, .mux_mask = 0x3, .mux_val = 1},
{.groupid = PGRP_RCRT, .pins_num = 1, .pins = {{57, 1}}},
};
#define GROUP_NUM ARRAY_SIZE(pin_groups)
static __INLINE void pinctrl_set_pin(int npin, int val, int drive)
{
xPinmap_t *pctrl;
uint32_t reg;
if (npin >= PIN_NUM)
return;
pctrl = &amt630h_pin_map[npin];
reg = readl(PINCTL_REG_BASE + pctrl->reg);
reg &= ~(pctrl->mask << pctrl->offset);
reg |= val << pctrl->offset;
writel(reg, PINCTL_REG_BASE + pctrl->reg);
if (drive != PAD_DRIVE_DEFAULT) {
uint32_t drv_reg = SYS_IO_DRIVER00 + npin / 16 * 4;
uint32_t offset = (npin % 16) * 2;
uint32_t drv_val = drive - 1;
vSysctlConfigure(drv_reg, offset, 3, drv_val);
}
}
void pinctrl_gpio_request(int gpio)
{
pinctrl_set_pin(gpio, 0, PAD_DRIVE_DEFAULT);
}
void pinctrl_set_group(int groupid)
{
int i, j;
xPinGroup_t *pgrp;
uint32_t reg;
for (i = 0; i < GROUP_NUM; i++) {
pgrp = &pin_groups[i];
if (pgrp->groupid == groupid) {
configASSERT(pgrp->pins_num <= MAX_PINS_PER_GROUP);
for (j = 0; j < pgrp->pins_num; j++)
pinctrl_set_pin(pgrp->pins[j].muxio, pgrp->pins[j].pinval,
pgrp->pins[j].drive);
if (pgrp->mux_reg) {
reg = readl(pgrp->mux_reg);
reg &= ~(pgrp->mux_mask << pgrp->mux_offset);
reg |= pgrp->mux_val << pgrp->mux_offset;
writel(reg, pgrp->mux_reg);
}
break;
}
}
}
void vPinctrlSetup(void)
{
#ifdef HW_I2C0_SUPPORT
pinctrl_set_group(PGRP_I2C0);
#endif
#ifdef HW_I2C1_SUPPORT
pinctrl_set_group(PGRP_I2C1);
#endif
pinctrl_set_group(PGRP_UART0);
pinctrl_set_group(PGRP_UART2);
#ifdef PWM_CAP_SUPPORT
pinctrl_set_group(PGRP_PWM2_IN);
#endif
#if 0
/* 高速串口先初始化再配置pad脚(放在vUartInit()函数中初始化),否则在初始化过程中收到数据会导致串口出错 */
pinctrl_set_group(PGRP_UART1);
pinctrl_set_group(PGRP_UART3);
#endif
pinctrl_set_group(PGRP_SPI0);
pinctrl_set_group(PGRP_SPI1);
pinctrl_set_group(PGRP_SDMMC0);
#ifdef REMOTE_SUPPORT
pinctrl_set_group(PGRP_RCRT);
#endif
#if LCD_INTERFACE_TYPE == LCD_INTERFACE_TTL
pinctrl_set_group(PGRP_LCD_TTL_CH0);
#elif LCD_INTERFACE_TYPE == LCD_INTERFACE_LVDS
pinctrl_set_group(PGRP_LCD_LVDS);
#endif
pinctrl_set_group(PGRP_ITU_CH1_INV);
pinctrl_set_group(PGRP_CAN0_CH0);
#ifdef AUDIO_REPLAY
#if (AUDIO_REPLAY_I2S == I2S_ID1)
pinctrl_set_group(PGRP_I2S1_PLAY);
#else
pinctrl_set_group(PGRP_I2S0_PLAY);
#endif
#endif
#ifdef AUDIO_RECORD
#if (AUDIO_RECORD_I2S == I2S_ID1)
pinctrl_set_group(PGRP_I2S1_RECORD);
#else
pinctrl_set_group(PGRP_I2S0_RECORD);
#endif
#endif
pinctrl_set_group(PGRP_PWM2);
pinctrl_set_group(PGRP_PWM3);
}

View File

@ -0,0 +1,42 @@
#include "FreeRTOS.h"
#include "chip.h"
#define PWM_EN 0x0
#define PWM_DUTY 0x4
#define PWM_CNTR 0x8
#define PWM_REG(x) (REGS_PWM_BASE + 0x10 * (x))
int pwm_config(int id, uint32_t duty_ns, uint32_t period_ns)
{
uint32_t clk_mhz = ulClkGetRate(CLK_PWM) / 1000000;
uint32_t duty = (unsigned long long)duty_ns * clk_mhz / 1000;
uint32_t period = (unsigned long long)period_ns * clk_mhz / 1000;
//writel(0, PWM_REG(id) + PWM_EN);
writel(duty, PWM_REG(id) + PWM_DUTY);
writel(period, PWM_REG(id) + PWM_CNTR);
return 0;
}
void pwm_enable(int id)
{
writel(1, PWM_REG(id) + PWM_EN);
}
void pwm_disable(int id)
{
writel(0, PWM_REG(id) + PWM_EN);
}
//240719 lj
void pwn_update_brightness(uint32_t duty_ns)
{
int id=2;
int led_id=3;
uint32_t clk_mhz = ulClkGetRate(CLK_PWM) / 1000000;
uint32_t duty = (unsigned long long)duty_ns * clk_mhz / 1000;
writel(duty, PWM_REG(id) + PWM_DUTY);
writel(duty, PWM_REG(led_id) + PWM_DUTY);
}

View File

@ -0,0 +1,206 @@
#include "FreeRTOS.h"
#include "board.h"
#ifdef PWM_CAP_SUPPORT
#include "chip.h"
#include "pwm_cap.h"
#define PWM_CAP_INT_CLEAR (0x10*4)
#define PWM_CAP_INT_EN (0x20*4)
#define PWM_CAP_INT_STA (0x21*4)
#define PWM_CAP_SYS_FRQ (0x00)
#define PWM_CAP_SETTING (0x04)
#define PWM_CAP_CYCLE_CAP (0x08)
#define PWM_FRE_CAP (0x0c)
#define PWM_CAP_CLK 198000000
#define PWM_CAP_REG(x) (REGS_PWM_BASE + 0x100 + 0x10 * (x))
void pwm_cap_Int_Handler(void *para);
static void pwm_cap_clk_config(UINT8 id,UINT32 clk)
{
writel(clk,PWM_CAP_REG(id) + PWM_CAP_SYS_FRQ);
}
static void pwm_cap_en(UINT8 id,UINT8 enable)
{
unsigned int reg;
reg = readl(PWM_CAP_REG(id) + PWM_CAP_SETTING);
if(enable)
reg |= (1UL<<31);
else
reg &= ~(1UL<<31);
writel(reg, PWM_CAP_REG(id) + PWM_CAP_SETTING);
}
static void pwm_cap_int_method(UINT8 id,UINT8 int_method)
{
unsigned int reg;
reg = readl(PWM_CAP_REG(id) + PWM_CAP_SETTING);
reg &= ~(0x3<<28);
reg |= (int_method<<28);
writel(reg,PWM_CAP_REG(id) + PWM_CAP_SETTING);
}
static void pwm_cap_set_glitch(UINT8 id,UINT8 glitch)
{
unsigned int reg;
reg = readl(PWM_CAP_REG(id) + PWM_CAP_SETTING);
reg &= ~(0xF<<24);
reg |= (glitch<<24);
writel(reg,PWM_CAP_REG(id) + PWM_CAP_SETTING);
}
static void pwm_cap_method(UINT8 id,UINT8 cap_method)
{
unsigned int reg;
reg = readl(PWM_CAP_REG(id) + PWM_CAP_SETTING);
reg &= ~(0x1<<30);
reg |= (cap_method<<30);
writel(reg,PWM_CAP_REG(id) + PWM_CAP_SETTING);
}
static void pwm_cap_times(UINT8 id,UINT8 cat_times)
{
unsigned int reg;
reg = readl(PWM_CAP_REG(id) + PWM_CAP_SETTING);
reg &= ~(0xFF<<16);
reg |= (cat_times<<16);
writel(reg,PWM_CAP_REG(id) + PWM_CAP_SETTING);
}
static void pwm_cap_based_unit(UINT8 id,UINT8 cap_based_unit)
{
unsigned int reg;
reg = readl(PWM_CAP_REG(id) + PWM_CAP_SETTING);
reg &= ~(0x7<<12);
reg |= (cap_based_unit<<12);
writel(reg,PWM_CAP_REG(id) + PWM_CAP_SETTING);
}
static void pwm_cap_interval(UINT8 id,UINT8 cap_interval)
{
unsigned int reg;
reg = readl(PWM_CAP_REG(id) + PWM_CAP_SETTING);
reg &= ~(0xFF<<0);
reg |= (cap_interval<<0);
writel(reg,PWM_CAP_REG(id) + PWM_CAP_SETTING);
}
void pwm_Initial_Cap(UINT8 id)
{
pwm_cap_clk_config(id,PWM_CAP_CLK);
pwm_cap_int_method(id,PWM_CAP_ONCE_FINISH_INT);
pwm_cap_set_glitch(id,PWM_CAP_GLITCH);
pwm_cap_method(id,PWM_CAP_NUM);
pwm_cap_times(id,PWM_CAP_TIMES);
pwm_cap_based_unit(id,PWM_CAP_UINT_100MS);
pwm_cap_interval(id,PWM_CAP_INTERVAL);
request_irq(RCRT_IRQn, 0, pwm_cap_Int_Handler, NULL);
}
void pwm_cap_Int_Handler(void *para)
{
unsigned int val;
unsigned int Regval;
val = readl(PWM_CAP_REG(0) + PWM_CAP_INT_STA);
printf( "capture interrupt is valid\r\n") ;
if(val&1)
{
Regval = readl(PWM_CAP_REG(0) +PWM_CAP_INT_CLEAR);
Regval |= (1<<0);
writel(Regval,PWM_CAP_REG(0) +PWM_CAP_INT_CLEAR);
printf("capture 0 interrupt is valid\r\n");
pwm_getCapVal(PWM_CAP_CH0);
Regval &=~(1<<0);
writel(Regval,PWM_CAP_REG(0) +PWM_CAP_INT_CLEAR);
writel(readl(PWM_CAP_REG(PWM_CAP_CH0) + PWM_CAP_SETTING)|(1UL<<31),PWM_CAP_REG(PWM_CAP_CH0) +PWM_CAP_SETTING);
}
if(val&(1<<1))
{
Regval = readl(PWM_CAP_REG(0) +PWM_CAP_INT_CLEAR);
Regval |= (1<<1);
writel(Regval,PWM_CAP_REG(0) +PWM_CAP_INT_CLEAR);
printf( " capture 1 interrupt is valid\r\n");
pwm_getCapVal(1);
Regval &= ~(1<<1);
writel(Regval,PWM_CAP_REG(0) +PWM_CAP_INT_CLEAR);
}
if(val&(1<<2))
{
Regval = readl(PWM_CAP_REG(0) +PWM_CAP_INT_CLEAR);
Regval |= (1<<2);
writel(Regval,PWM_CAP_REG(0) +PWM_CAP_INT_CLEAR);
printf( " capture 2 interrupt is valid\r\n");
pwm_getCapVal(2);
Regval &= ~(1<<2);
writel(Regval,PWM_CAP_REG(0) +PWM_CAP_INT_CLEAR);
}
if(val&(1<<3))
{
printf( " capture 3 interrupt is valid\r\n");
Regval = readl(PWM_CAP_REG(0) +PWM_CAP_INT_CLEAR);
Regval |= (1<<3);
writel(Regval,PWM_CAP_REG(0) +PWM_CAP_INT_CLEAR);
pwm_getCapVal(3);
Regval &=~ (1<<3);
writel(Regval,PWM_CAP_REG(0) +PWM_CAP_INT_CLEAR);
}
}
double pwm_getCapVal(UINT8 id)
{
UINT32 reg,num;
double fre;
reg=readl(PWM_CAP_REG(id)+PWM_CAP_CYCLE_CAP);
writel(readl(PWM_CAP_REG(id)+PWM_CAP_SETTING)|(1UL<<31),PWM_CAP_REG(id)+PWM_CAP_SETTING);
num = reg>>8;
fre = ((reg&0xf0)>>4)/16.0+(reg&0xf)/256.0;
fre += num;
reg = readl(PWM_CAP_REG(id)+PWM_CAP_SETTING);
if(((reg >>12)&0x7)==4)
fre*=1;
else if(((reg >>12)&0x7)==2)
fre*=10;
else if(((reg >>12)&0x7)==1)
fre*=100;
else
fre*=1000;
printf("pwm cap value %lf\n",(fre+0.9));
return (fre + 0.9);
}
void pwm_enableCapIRQ(UINT8 id,unsigned char en)
{
unsigned int reg = 0;
reg = readl(PWM_CAP_REG(0)+ PWM_CAP_INT_EN);
reg &=~(1<<id);
if(en)
{
reg |=(1<<id);
writel(reg,PWM_CAP_REG(0)+ PWM_CAP_INT_EN);
}
else
writel(reg,PWM_CAP_REG(0)+ PWM_CAP_INT_EN);
}
void pwm_cap_init(UINT8 id)
{
// unsigned int irq_enable = 1;
pwm_Initial_Cap(id);
pwm_enableCapIRQ(id,1);
pwm_cap_en(id,PWM_CAP_ENABLE);
}
#endif

View File

@ -0,0 +1,267 @@
#include "FreeRTOS.h"
#include "board.h"
#include "chip.h"
#define PXP_CTRL 0x000
#define PXP_CTRL_SET 0x004
#define PXP_CTRL_CLR 0x008
#define PXP_CTRL_TOG 0x00C
#define PXP_STAT 0x010
#define PXP_STAT_SET 0x014
#define PXP_STAT_CLR 0x018
#define PXP_STAT_TOG 0x01c
#define PXP_OUTBUF 0x020
#define PXP_OUTBUF2 0x030
#define PXP_OUTSIZE 0x040
#define PXP_S0BUF 0x050
#define PXP_S0UBUF 0x060
#define PXP_S0VBUF 0x070
#define PXP_S0PARAM 0x080
#define PXP_S0BACKGROUND 0x090
#define PXP_S0CLIP 0x0A0
#define PXP_S0SCALE 0x0B0
#define PXP_S0OFFSET 0x0C0
#define PXP_CSCCOEFF0 0x0D0
#define PXP_CSCCOEFF1 0x0E0
#define PXP_CSCCOEFF2 0x0F0
#define PXP_NEXT 0x100
#define PXP_PAGETABLE 0x170
#define PXP_S0CKEYL 0x180
#define PXP_S0CKEYH 0x190
#define PXP_OLCKEYL 0x1A0
#define PXP_OLCKEYH 0x1B0
#define PXP_OL0BUF 0x200
#define PXP_OL0SIZE 0x210
#define PXP_OL0PARAM 0x220
#define PXP_OL1BUF 0x240
#define PXP_OL1SIZE 0x250
#define PXP_OL1PARAM 0x260
#define PXP_OL2BUF 0x280
#define PXP_OL2SIZE 0x290
#define PXP_OL2PARAM 0x2A0
#define PXP_OL3BUF 0x2C0
#define PXP_OL3SIZE 0x2D0
#define PXP_OL3PARAM 0x2E0
#define PXP_OL4BUF 0x300
#define PXP_OL4SIZE 0x310
#define PXP_OL4PARAM 0x320
#define PXP_OL5BUF 0x340
#define PXP_OL5SIZE 0x350
#define PXP_OL5PARAM 0x360
#define PXP_OL6BUF 0x380
#define PXP_OL6SIZE 0x390
#define PXP_OL6PARAM 0x3A0
#define PXP_OL7BUF 0x3C0
#define PXP_OL7SIZE 0x3D0
#define PXP_OL7PARAM 0x3E0
// offss for "NEXT" pointers
#define PXP_NEXTCTRL 0x000
#define PXP_NEXTRGBBUF 0x004
#define PXP_NEXTRGBBUF2 0x008
#define PXP_NEXTRGBSIZE 0x00C
#define PXP_NEXTS0BUF 0x010
#define PXP_NEXTS0UBUF 0x014
#define PXP_NEXTS0VBUF 0x018
#define PXP_NEXTS0PARAM 0x01C
#define PXP_NEXTS0BACKGROUND 0x020
#define PXP_NEXTS0CLIP 0x024
#define PXP_NEXTS0SCALE 0x028
#define PXP_NEXTS0OFFSET 0x02C
#define PXP_NEXTS0CKEYL 0x030
#define PXP_NEXTS0CKEYH 0x034
#define PXP_NEXTOLCKEYL 0x038
#define PXP_NEXTOLCKEYH 0x03C
#define PXP_NEXTOL0BUF 0x040
#define PXP_NEXTOL0SIZE 0x044
#define PXP_NEXTOL0PARAM 0x048
#define PXP_NEXTOL1BUF 0x050
#define PXP_NEXTOL1SIZE 0x054
#define PXP_NEXTOL1PARAM 0x058
#define PXP_NEXTOL2BUF 0x060
#define PXP_NEXTOL2SIZE 0x064
#define PXP_NEXTOL2PARAM 0x068
#define PXP_NEXTOL3BUF 0x070
#define PXP_NEXTOL3SIZE 0x074
#define PXP_NEXTOL3PARAM 0x078
#define PXP_NEXTOL4BUF 0x080
#define PXP_NEXTOL4SIZE 0x084
#define PXP_NEXTOL4PARAM 0x088
#define PXP_NEXTOL5BUF 0x090
#define PXP_NEXTOL5SIZE 0x094
#define PXP_NEXTOL5PARAM 0x098
#define PXP_NEXTOL6BUF 0x0A0
#define PXP_NEXTOL6SIZE 0x0A4
#define PXP_NEXTOL6PARAM 0x0A8
#define PXP_NEXTOL7BUF 0x0B0
#define PXP_NEXTOL7SIZE 0x0B4
#define PXP_NEXTOL7PARAM 0x0B8
#define abs(a, b) ((a > b) ? (a - b) : (b - a))
#define PXP_H_FILP 0
#define PXP_V_FILP 0
static uint32_t pxpbase = REGS_PXP_BASE;
static SemaphoreHandle_t pxp_mutex = NULL;
static QueueHandle_t pxp_done;
/* this function can not used in isr */
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)
{
uint32_t ctrl;
int ret = 0;
int cutx = 2;
int cuty = 2;
int mirror = 0;
#if PXP_H_FILP
mirror = 1;
#endif
#if PXP_V_FILP
mirror |= 2;
#endif
configASSERT(outangle >= PXP_ROTATE_0 && outangle <= PXP_ROTATE_270);
if (outangle == PXP_ROTATE_90 || outangle == PXP_ROTATE_270) {
uint32_t tmp = outheight;
outheight = outwidth;
outwidth = tmp;
}
if(abs(s0width, outwidth) < 16)
cutx = 0;
if(abs(s0height, outheight) < 16)
cuty = 0;
xSemaphoreTake(pxp_mutex, portMAX_DELAY);
writel(1UL << 31, pxpbase + PXP_CTRL);
udelay(10);
writel(0, pxpbase + PXP_CTRL);
writel(outbuf, pxpbase + PXP_OUTBUF);
writel(outbuf2, pxpbase + PXP_OUTBUF2);
writel((0xffUL << 24) | (outwidth << 12) | outheight, pxpbase + PXP_OUTSIZE);
writel(s0buf, pxpbase + PXP_S0BUF);
writel(s0ubuf, pxpbase + PXP_S0UBUF);
writel(s0vbuf, pxpbase + PXP_S0VBUF);
writel((((s0width >> 3) & 0xff) << 8) | ((s0height >> 3) & 0xff), pxpbase + PXP_S0PARAM);
writel(0, pxpbase + PXP_S0BACKGROUND);
writel((((outwidth >> 3) & 0xff) << 8) | ((outheight >> 3) & 0xff), pxpbase + PXP_S0CLIP);
writel(((s0height * 0x1000 / (outheight + cuty)) << 16) | (s0width * 0x1000 / (outwidth + cutx)),
pxpbase + PXP_S0SCALE);
//YCbCr->RGB Coefficient Values bit31 ycbcr_mode
writel((1 << 31) | 0x1f0 | (0x180 << 9) | (0x12a << 18), pxpbase + PXP_CSCCOEFF0);
writel(0x204 | (0x198 <<16), pxpbase + PXP_CSCCOEFF1);
writel(0x79c | (0x730 <<16), pxpbase + PXP_CSCCOEFF2);
ctrl = (1 << 19) | (1 << 18) | ((s0format & 0xf) << 12) | (outangle << 8) |
(mirror << 10) | ((outformat & 0xf) << 4) | 3;
if(outformat == PXP_OUT_FMT_ARGB8888)
ctrl |=(1<<22);
xQueueReset(pxp_done);
writel(ctrl, pxpbase + PXP_CTRL);
if (xQueueReceive(pxp_done, NULL, pdMS_TO_TICKS(1000)) != pdTRUE) {
printf("pxp timeout.\n");
ret = -ETIMEDOUT;
}
xSemaphoreGive(pxp_mutex);
return ret;
}
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)
{
uint32_t ctrl = 0;
int ret = 0;
int mirror = 0;
#if PXP_H_FILP
mirror = 1;
#endif
#if PXP_V_FILP
mirror |= 2;
#endif
configASSERT(outangle >= PXP_ROTATE_0 && outangle <= PXP_ROTATE_270);
xSemaphoreTake(pxp_mutex, portMAX_DELAY);
writel(1UL << 31, pxpbase + PXP_CTRL);
udelay(10);
writel(0, pxpbase + PXP_CTRL);
writel(outbuf, pxpbase + PXP_OUTBUF);
writel(outbuf2, pxpbase + PXP_OUTBUF2);
writel((0xffUL << 24) | (s0width << 12) | s0height, pxpbase + PXP_OUTSIZE);
writel(s0buf, pxpbase + PXP_S0BUF);
writel(s0ubuf, pxpbase + PXP_S0UBUF);
writel(s0vbuf, pxpbase + PXP_S0VBUF);
writel((((s0width >> 3) & 0xff) << 8) | ((s0height >> 3) & 0xff), pxpbase + PXP_S0PARAM);
writel(0, pxpbase + PXP_S0BACKGROUND);
//YCbCr->RGB Coefficient Values bit31 ycbcr_mode
writel((1 << 31) | 0x1f0 | (0x180 << 9) | (0x12a << 18), pxpbase + PXP_CSCCOEFF0);
writel(0x204 | (0x198 << 16), pxpbase + PXP_CSCCOEFF1);
writel(0x79c | (0x730 << 16), pxpbase + PXP_CSCCOEFF2);
if(outformat == PXP_OUT_FMT_ARGB8888) {
if(s0format == PXP_SRC_FMT_ARGB8888) {
writel(0, pxpbase + PXP_OLCKEYL);
writel(0, pxpbase + PXP_OLCKEYH);
writel(s0buf, pxpbase + PXP_OL0BUF);
writel((((s0width >> 3) & 0xff) << 8) | ((s0height >> 3) & 0xff), pxpbase + PXP_OL0SIZE);
writel((0x1<<0) | (0x3<<1) | (0x1<<3) | (s0format<<4) | (0x2<<16), pxpbase + PXP_OL0PARAM);
ctrl |= (1<<19);
s0format = PXP_SRC_FMT_RGB888;
} else {
ctrl |= (1<<22);
}
}
ctrl |= ((s0format & 0xf) << 12) | (outangle << 8) | (mirror<< 10) | ((outformat & 0xf) << 4) | 3;
xQueueReset(pxp_done);
writel(ctrl, pxpbase + PXP_CTRL);
if (xQueueReceive(pxp_done, NULL, pdMS_TO_TICKS(1000)) != pdTRUE) {
printf("pxp timeout.\n");
ret = -ETIMEDOUT;
}
xSemaphoreGive(pxp_mutex);
return ret;
}
static void pxp_interupt_handler(void *param)
{
uint32_t status = readl(pxpbase + PXP_STAT);
writel(status, pxpbase + PXP_STAT_CLR);
if (status & 0x01) {
xQueueSendFromISR(pxp_done, NULL, 0);
}
}
int pxp_init(void)
{
pxp_mutex = xSemaphoreCreateMutex();
pxp_done = xQueueCreate(1, 0);
request_irq(PXP_IRQn, 0, pxp_interupt_handler, NULL);
return 0;
}

View File

@ -0,0 +1,220 @@
#include "FreeRTOS.h"
#include "chip.h"
#include "board.h"
#ifdef REMOTE_SUPPORT
/* Remote */
#define rRC_DATA0 0x00
#define rRC_DATA1 0x04
#define rRC_DATA2 0x08
#define rRC_DATA3 0x0C
#define rRC_DATA4 0x10
#define rRC_DATA5 0x14
#define rRC_DATA6 0x18
#define rRC_DATA7 0x1C
#define rRC_CODEBUF 0x20
#define rRC_CODEVAL 0x24
#define rRC_KEYVAL 0x28
#define rRC_STATUS 0x2C
#define rRC_RT_USER_CODE_3_4 0x30
#define rRC_RT_INTER_REQ_CLR 0x34
#define NORMAL_KEY 0
#define RELEASE_KEY 1
#define REPEAT_KEY 2
#define REMOTE_NULL 0
#define REMOTE_SCAN 1 // scan state
#define REMOTE_CHECK 2 // check state
#define REMOTE_DELAY 3 // repeat delay state
#define REMOTE_REPEAT 4 // repeat state
#define REMOTE_STATE_IDLE 0
#define REMOTE_STATE_PRESS 1
#define REMOTE_STATE_REPEATE 2
#define REMOTE_PRESS_EVENT 0
#define REMOTE_RELEASE_EVENT 1
#define REMOTE_REPEATE_EVENT 2
//static UINT32 lg_ulRemoteStateMachine = REMOTE_STATE_IDLE;
//static unsigned short Remotekey_delay_time;
//static int Remotekey_state;
//static UINT32 lg_ulLastRepeatMs = 0;
static UINT32 lg_ulMaxRepeatMs = 0;
volatile UINT32 cRemoteKey; // <20><>ǰ<EFBFBD><C7B0>ֵ
volatile UINT32 cRemoteStatus; // <20><>ǰ<EFBFBD><C7B0>״̬
static void remote_config(void) //<2F><><EFBFBD><EFBFBD>ң<EFBFBD>ؽ<EFBFBD><D8BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD><C4B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
printf("remote_config\n");
#if 1
// nec
INT8 pulse_data_polarity = 0x01;//[3 :0 ]
INT8 valid_bitrange = 0x04;//[6 :4 ]
INT8 dispersion = 0x5;//[15:8 ]
INT8 prediv = 0x3f;//[23:16] 24M: 0x1f 48M: 0x3f
INT8 filtertime = 0x10;//[31:24]
INT8 start_valueh = 0x69;//[23:16]
INT8 start_valuel = 0x34;//[31:24]
INT8 one_valueh = 0x6; //0x6;//[7 : 0]
INT8 one_valuel = 0x13;//[15: 8]
INT8 zero_valueh = 0x6;//[23:16]
INT8 zero_valuel = 0x6;//[31:24]
INT8 rp0_valueh = 0x0f;//[7 : 0]
INT8 rp0_valuel = 0x0f;//[15: 8]
INT8 rp1_valueh = 0x0f;//[23:16]
INT8 rp1_valuel = 0x0f;//[31:24]
INT8 rp2_3_valueh = 0x69;//[7 : 0]
INT8 rp2_3_valuel = 0x1c;//[15: 8]
INT8 rp4_5_valueh =0x6;//[23:16]
INT8 rp4_5_valuel = 0xf5;//[31:24]
INT8 keyrelease_timeh = 0x00;//[7 : 0]
INT8 keyrelease_timel = 0x59;//[15: 8]
INT8 RP_5L_delta=0XF0;
INT8 int_num = 0x01;//[23:16]
INT8 mode_sel_reg = 0x03;//[25:24]
INT8 nec_release_int_en = 0x01;//[26]
UINT8 user_code1_l = 0x00;//[7 : 0]
UINT8 user_code1_h = 0xFF;//[15: 8]
UINT8 user_code2_l = 0x00;//[23:16]
UINT8 user_code2_h =0xFF;//[31:24]
INT32 NEC_bit_2_pulse = 0x2ff;//[15: 0]
// INT8 user_code_sel_reg = 0x01;//[23:16]
// INT8 user_code3_l = 0x02;//[7 : 0]
// INT8 user_code3_h = 0x00;//[15: 8]
// INT8 user_code4_l = 0xff;//[23:16]
// INT8 user_code4_h =0x00;//[31:24]
INT8 user_code_sel =0;
INT8 custom_jud_sel=1;
INT8 custom_not_jud_sel=1;
INT8 data_not_jud_sel=1;
uint32_t val;
uint32_t remote_param0, remote_param1, remote_param2, remote_param3 ;
uint32_t remote_param4, remote_param5, remote_param6, remote_param7 ;
#endif
remote_param0 = (pulse_data_polarity<<0)
+ (valid_bitrange<<4)
+ (dispersion<<7)
+ (prediv<<15)
+ (filtertime<<24);
remote_param1 = (RP_5L_delta<< 0)
+ (start_valueh<<16)
+ (start_valuel<<24);
remote_param2 = (one_valueh<<0)
+ (one_valuel<<8)
+ (zero_valueh<<16)
+ (zero_valuel<<24);
remote_param3 = (rp0_valueh<<0)
+ (rp0_valuel<<8)
+ (rp1_valueh<<16)
+ (rp1_valuel<<24);
remote_param4 = (rp2_3_valueh<<0)
+ (rp2_3_valuel<<8)
+ (rp4_5_valueh<<16)
+ (rp4_5_valuel<<24);
remote_param5 = (keyrelease_timel<<0)
+ (keyrelease_timeh<<8)
+ (int_num<<16)
+ (mode_sel_reg<<24)
+ (nec_release_int_en << 26);
remote_param6 = ((user_code1_l<<0)
+ (user_code1_h<<8)
+ (user_code2_l<<16)
+ (user_code2_h<<24));
/* rRC_RT_USER_CODE_3_4 = (user_code3_l<<0)
+ (user_code3_h<<8)
+ (user_code4_l<<16)
+ (user_code4_h<<24);
*/
remote_param7 =(NEC_bit_2_pulse<<0)
+ (user_code_sel<<16)
+(custom_jud_sel<<24)
+(custom_not_jud_sel<<25)
+(data_not_jud_sel<<26);
val = readl(REGS_SYSCTL_BASE + SYS_PER_CLK_CFG);
val &= ~0x0f;
writel(val, REGS_SYSCTL_BASE + SYS_PER_CLK_CFG);
writel(remote_param0, REGS_RCRT_BASE+rRC_DATA0);
writel(remote_param1, REGS_RCRT_BASE+rRC_DATA1);
writel(remote_param2, REGS_RCRT_BASE+rRC_DATA2);
writel(remote_param3, REGS_RCRT_BASE+rRC_DATA3);
writel(remote_param4, REGS_RCRT_BASE+rRC_DATA4);
writel(remote_param5, REGS_RCRT_BASE+rRC_DATA5);
writel(remote_param6, REGS_RCRT_BASE+rRC_DATA6);
writel(remote_param7, REGS_RCRT_BASE+rRC_DATA7);
}
/*********************************************************************
Set the report interval for remote repeating event
Parameter:
ulMillisecond: interval, unit as millisecond, this parameter should be the multiply of
10 millsecond.
*********************************************************************/
void SetRemoteKeyRepeateInterval(UINT32 ulMillisecond)
{
lg_ulMaxRepeatMs = ulMillisecond/10;
}
/*********************************************************************
Get the report interval for remote repeating event
Return:
millisendonds for interval
*********************************************************************/
UINT32 GetRemoteKeyRepeatInterval(void)
{
return lg_ulMaxRepeatMs * 10;
}
static void remote_int_handler(void *param)
{
// printf("Enter remote interrupt!\n");
cRemoteStatus=(readl(REGS_RCRT_BASE + rRC_STATUS))&0x0F;// ȡң<C8A1><D2A3><EFBFBD><EFBFBD>״̬
cRemoteKey=readl(REGS_RCRT_BASE + rRC_KEYVAL);
printf(" cRemoteKey is%x.\n",cRemoteKey);
writel(0xff, REGS_RCRT_BASE+rRC_RT_INTER_REQ_CLR);
if(cRemoteStatus & 0x01)
printf(" release detect\n");
else
printf(" cRemoteStatus: %x cRemoteKey: %x\n",cRemoteStatus,cRemoteKey);
}
void RemoteKeyInit(void)
{
cRemoteKey = REMOTE_NULL;
cRemoteStatus = NORMAL_KEY;
sys_soft_reset(softreset_rcrt);
remote_config();
request_irq(RCRT_IRQn,0,remote_int_handler,NULL);
printf("RemoteKeyInit\n");
}
#endif

View File

@ -0,0 +1,484 @@
#include <stdio.h>
#include "FreeRTOS.h"
#include "chip.h"
#include "errno.h"
/* RTC registers */
#define RTC_CTL 0x00 /*control register*/
#define RTC_ANAWEN 0x04 /*analog block write enable register*/
#define RTC_ANACTL 0x08 /*analog block control register*/
#define RTC_IM 0x0c /*interrupt mode register*/
#define RTC_STA 0x10 /*rtc status register*/
#define RTC_ALMDAT 0x14 /*alarm data register*/
#define RTC_DONT 0x18 /*delay on timer register*/
#define RTC_RAM 0x1c /*ram bit register*/
#define RTC_CNTL 0x20 /*rtc counter register*/
#define RTC_CNTH 0x24 /*rtc sec counter register*/
//RTC_CTL register fields defination
#define CTL_CTL3_VALUE(x) (x<<23)
#define CTL_CTL2_VALUE(x) (x<<22)
#define CTL_BIAS_TRM_VALUE(x) (x<<21)
#define CTL_SOFT_SEL_VALUE(x) (x<<20)
#define CTL_CTL1_VALUE(x) (x<<19)
#define CTL_CTL0_VALUE(x) (x<<18)
#define CTL_SOFT_STR_VALUE(x) (x<<17)
#define CTL_OSC_EN_VALUE(x) (x<<16)
#define CTL_CTL3_SET (1<<15)
#define CTL_CTL2_SET (1<<14)
#define CTL_BIAS_TRM_SET (1<<13)
#define CTL_SOFT_SEL_SET (1<<12)
#define CTL_CTL1_SET (1<<11)
#define CTL_CTL0_SET (1<<10)
#define CTL_SOFT_STR_SET (1<<9)
#define CTL_OSC_EN_SET (1<<8)
#define CTL_ALM_DATA_WEN (1<<3)
#define CTL_PERIOD_INT_EN (1<<2)
#define CTL_ALARM_INT_EN (1<<1)
#define CTL_RESET (1<<0)
//RTC_ANAWEN register fields defination
#define ANA_CNT_WEN (1<<7)
#define ANA_RAM_WEN (1<<6)
#define ANA_DELAY_TIMER_WEN (1<<5)
#define ANA_CLR_PWR_DET_WEN (1<<4)
#define ANA_DELAY_POWER_ON_WEN (1<<3)
#define ANA_FORCE_POWER_OFF_WEN (1<<2)
#define ANA_FORCE_POWER_ON_WEN (1<<1)
#define ANA_RTC_WEN (1<<0)
//RTC_ANACTL register fields defination
#define ANACTL_CLR_PWR (1<<4)
#define ANACTL_DELAY_POWER_ON (1<<3)
#define ANACTL_FORCE_POWER_OFF (1<<2)
#define ANACTL_FORCE_POWER_ON (1<<1)
#define ANACTL_COUNTER_EN (1<<0)
/* STATUS_REG */
#define STA_PWR_DET (1<<6)
#define STA_DELAY_ON (1<<5)
#define STA_FORCE_OFF (1<<4)
#define STA_FORCE_ON (1<<3)
#define STA_RCT_BUSY (1<<2)
#define STA_PERIOD_INT (1<<1)
#define STA_ALARM_INT (1<<0)
/* 2020-01-01 Wednesday */
static struct rtc_time default_tm = {
.tm_sec = 0,
.tm_min = 0,
.tm_hour = 0,
.tm_mday = 1,
.tm_mon = 0,
.tm_year = 120,
.tm_wday = 3,
.tm_yday = 1,
};
static const unsigned char rtc_days_in_month[] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
static const unsigned short rtc_ydays[2][13] = {
/* Normal years */
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
/* Leap years */
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
};
#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
/*
* The number of days in the month.
*/
int rtc_month_days(unsigned int month, unsigned int year)
{
return rtc_days_in_month[month] + (is_leap_year(year) && month == 1);
}
/*
* The number of days since January 1. (0 to 365)
*/
int rtc_year_days(unsigned int day, unsigned int month, unsigned int year)
{
return rtc_ydays[is_leap_year(year)][month] + day-1;
}
/*
* rtc_time_to_tm - Converts time to rtc_time.
* Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
*/
void rtc_time_to_tm(uint32_t time, struct rtc_time *tm)
{
unsigned int month, year;
unsigned long secs;
int days;
/* time must be positive */
days = time / 86400;
secs = time - (unsigned int) days * 86400;
/* day of the week, 1970-01-01 was a Thursday */
tm->tm_wday = (days + 4) % 7;
year = 1970 + days / 365;
days -= (year - 1970) * 365
+ LEAPS_THRU_END_OF(year - 1)
- LEAPS_THRU_END_OF(1970 - 1);
if (days < 0) {
year -= 1;
days += 365 + is_leap_year(year);
}
tm->tm_year = year - 1900;
tm->tm_yday = days + 1;
for (month = 0; month < 11; month++) {
int newdays;
newdays = days - rtc_month_days(month, year);
if (newdays < 0)
break;
days = newdays;
}
tm->tm_mon = month;
tm->tm_mday = days + 1;
tm->tm_hour = secs / 3600;
secs -= tm->tm_hour * 3600;
tm->tm_min = secs / 60;
tm->tm_sec = secs - tm->tm_min * 60;
}
/*
* Does the rtc_time represent a valid date/time?
*/
int rtc_valid_tm(struct rtc_time *tm)
{
if (tm->tm_year < 70
|| ((unsigned)tm->tm_mon) >= 12
|| tm->tm_mday < 1
|| tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year + 1900)
|| ((unsigned)tm->tm_hour) >= 24
|| ((unsigned)tm->tm_min) >= 60
|| ((unsigned)tm->tm_sec) >= 60)
return -EINVAL;
return 0;
}
/*
* mktime - Converts date to seconds.
* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
* Assumes input in normal date format, i.e. 1980-12-31 23:59:59
* => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
*
* [For the Julian calendar (which was used in Russia before 1917,
* Britain & colonies before 1752, anywhere else before 1582,
* and is still in use by some communities) leave out the
* -year/100+year/400 terms, and add 10.]
*
* This algorithm was first published by Gauss (I think).
*
* A leap second can be indicated by calling this function with sec as
* 60 (allowable under ISO 8601). The leap second is treated the same
* as the following second since they don't exist in UNIX time.
*
* An encoding of midnight at the end of the day as 24:00:00 - ie. midnight
* tomorrow - (allowable under ISO 8601) is supported.
*/
uint32_t mktime(const unsigned int year0, const unsigned int mon0,
const unsigned int day, const unsigned int hour,
const unsigned int min, const unsigned int sec)
{
unsigned int mon = mon0, year = year0;
/* 1..12 -> 11,12,1..10 */
if (0 >= (int) (mon -= 2)) {
mon += 12; /* Puts Feb last since it has leap day */
year -= 1;
}
return ((((uint32_t)
(year/4 - year/100 + year/400 + 367*mon/12 + day) +
year*365 - 719499
)*24 + hour /* now have hours - midnight tomorrow handled here */
)*60 + min /* now have minutes */
)*60 + sec; /* finally seconds */
}
/*
* rtc_tm_to_time - Converts rtc_time to time.
* Convert Gregorian date to seconds since 01-01-1970 00:00:00.
*/
uint32_t rtc_tm_to_time(struct rtc_time *tm)
{
return mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
}
static __INLINE void rtc_clear_interrupt(void)
{
unsigned int val;
val = readl(REGS_RTC_BASE + RTC_STA);
val &= ~CTL_ALARM_INT_EN;
writel(val, REGS_RTC_BASE + RTC_STA);
}
static __INLINE void rtc_enable_interrupt(void)
{
unsigned int val;
val = readl(REGS_RTC_BASE + RTC_CTL);
if (!(val & CTL_ALARM_INT_EN)) {
rtc_clear_interrupt();
val |= CTL_ALARM_INT_EN;
writel(val, REGS_RTC_BASE + RTC_CTL);
}
}
static __INLINE void rtc_disable_interrupt(void)
{
unsigned int val;
val = readl(REGS_RTC_BASE + RTC_CTL);
if (val & CTL_ALARM_INT_EN) {
val &= ~CTL_ALARM_INT_EN;
writel(val, REGS_RTC_BASE + RTC_CTL);
}
}
static void rtc_wait_not_busy(void)
{
int status, count = 0;
/* Assuming BUSY may stay active for 80 msec) */
for (count = 0; count < 0x1000; count++) {
status = readl(REGS_RTC_BASE + RTC_STA);
if ((status & STA_RCT_BUSY) == 0)
break;
/* check status busy, after each msec */
vTaskDelay(pdMS_TO_TICKS(1));
}
}
static void rtc_isr(void *para)
{
unsigned int irq_data;
irq_data = readl(REGS_RTC_BASE + RTC_STA);
if ((irq_data & CTL_ALARM_INT_EN)) {
rtc_clear_interrupt();
return;
} else
return;
}
static void rtc_update_time(unsigned int time)
{
unsigned int val;
int timeout = 100000;
val = readl(REGS_RTC_BASE + RTC_ANAWEN);
writel(val | ANA_RTC_WEN, REGS_RTC_BASE + RTC_ANAWEN);
val = readl(REGS_RTC_BASE + RTC_ANACTL);
writel(val | ANACTL_COUNTER_EN, REGS_RTC_BASE + RTC_ANACTL);
//wait rtc_busy;
rtc_wait_not_busy();
val = readl(REGS_RTC_BASE + RTC_ANAWEN);
writel(val | ANA_CNT_WEN, REGS_RTC_BASE + RTC_ANAWEN);
writel(time, REGS_RTC_BASE + RTC_CNTH);
//wait rtc_busy;
rtc_wait_not_busy();
while(readl(REGS_RTC_BASE + RTC_CNTH) != time) {
if (timeout-- == 0)
break;
taskYIELD();
}
}
/*
* rtc_read_time - set the time
* @tm: holds date and time
*
* This function read time and date. On success it will return 0
* otherwise -ve error is returned.
*/
static int rtc_read_time(struct rtc_time *tm)
{
unsigned int time;
/* we don't report wday/yday/isdst ... */
rtc_wait_not_busy();
time = readl(REGS_RTC_BASE + RTC_CNTH);
rtc_time_to_tm(time, tm);
return 0;
}
/*
* rtc_set_time - set the time
* @tm: holds date and time
*
* This function set time and date. On success it will return 0
* otherwise -ve error is returned.
*/
static int rtc_set_time(struct rtc_time *tm)
{
long unsigned int time;
if (rtc_valid_tm(tm) < 0)
return -EINVAL;
/* convert tm to seconds. */
time = rtc_tm_to_time(tm);
rtc_update_time(time);
return 0;
}
#if 0
static void rtc_update_alarm_time(unsigned int time)
{
unsigned int val;
int timeout = 100000;
val = readl(REGS_RTC_BASE + RTC_CTL);
writel(val | CTL_ALM_DATA_WEN, REGS_RTC_BASE + RTC_CTL);
writel(time, REGS_RTC_BASE + RTC_ALMDAT);
//wait rtc_busy;
rtc_wait_not_busy();
while(readl(REGS_RTC_BASE + RTC_ALMDAT) != time) {
if (timeout-- == 0)
break;
taskYIELD();
}
}
/*
* rtc_read_alarm - read the alarm time
* @alm: holds alarm date and time
*
* This function read alarm time and date. On success it will return 0
* otherwise -ve error is returned.
*/
static int rtc_read_alarm(struct rtc_wkalrm *alm)
{
unsigned int time;
rtc_wait_not_busy();
time = readl(REGS_RTC_BASE + RTC_ALMDAT);
rtc_time_to_tm(time, &alm->time);
alm->enabled = readl(REGS_RTC_BASE + RTC_CTL) & CTL_ALARM_INT_EN;
return 0;
}
/*
* rtc_set_alarm - set the alarm time
* @alm: holds alarm date and time
*
* This function set alarm time and date. On success it will return 0
* otherwise -ve error is returned.
*/
static int rtc_set_alarm(struct rtc_wkalrm *alm)
{
long unsigned int time;
if (rtc_valid_tm(&alm->time) < 0)
return -EINVAL;
/* convert tm to seconds. */
time = rtc_tm_to_time(&alm->time);
rtc_update_alarm_time(time);
if (alm->enabled)
rtc_enable_interrupt();
else
rtc_disable_interrupt();
return 0;
}
#endif
static int alarm_irq_enable(unsigned int enabled)
{
int ret = 0;
rtc_clear_interrupt();
switch (enabled) {
case 0:
/* alarm off */
rtc_disable_interrupt();
break;
case 1:
/* alarm on */
rtc_enable_interrupt();
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
int rtc_init(void)
{
struct rtc_time tm;
writel(0, REGS_RTC_BASE + RTC_CTL);
writel(CTL_SOFT_STR_SET|CTL_SOFT_STR_VALUE(1), REGS_RTC_BASE + RTC_CTL);
writel(CTL_OSC_EN_SET|CTL_OSC_EN_VALUE(0), REGS_RTC_BASE + RTC_CTL);
writel(CTL_CTL0_SET|CTL_CTL0_VALUE(0), REGS_RTC_BASE + RTC_CTL);
writel(CTL_CTL1_SET|CTL_CTL1_VALUE(0), REGS_RTC_BASE + RTC_CTL);
writel(CTL_CTL2_SET|CTL_CTL2_VALUE(0), REGS_RTC_BASE + RTC_CTL);
writel(CTL_CTL3_SET|CTL_CTL3_VALUE(0), REGS_RTC_BASE + RTC_CTL);
writel(CTL_BIAS_TRM_SET|CTL_BIAS_TRM_VALUE(1)|CTL_CTL3_VALUE(0), REGS_RTC_BASE + RTC_CTL);
udelay(1000);
writel(CTL_OSC_EN_SET|CTL_OSC_EN_VALUE(1), REGS_RTC_BASE + RTC_CTL);
udelay(1000);
request_irq(RTC_PRD_IRQn, 0, rtc_isr, NULL);
alarm_irq_enable(0);
rtc_read_time(&tm);
if (tm.tm_year == 70) {
rtc_set_time(&default_tm);
}
return 0;
}
int iGetLocalTime(SystemTime_t *tm)
{
rtc_read_time(tm);
tm->tm_year += 1900;
tm->tm_mon += 1;
return 0;
}
void vSetLocalTime(SystemTime_t *tm)
{
tm->tm_year -= 1900;
tm->tm_mon -= 1;
rtc_set_time(tm);
}

View File

@ -0,0 +1,197 @@
#include <string.h>
#include "FreeRTOS.h"
#include "trace.h"
#include "mmcsd_core.h"
#define SECTOR_SIZE 512
int32_t mmcsd_num_wr_blocks(struct mmcsd_card *card)
{
int32_t err;
uint32_t blocks;
struct mmcsd_req req;
struct mmcsd_cmd cmd;
struct mmcsd_data data;
uint32_t timeout_us;
memset(&cmd, 0, sizeof(struct mmcsd_cmd));
cmd.cmd_code = APP_CMD;
cmd.arg = card->rca << 16;
cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_AC;
err = mmcsd_send_cmd(card->host, &cmd, 0);
if (err)
return -1;
if (!controller_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD))
return -1;
memset(&cmd, 0, sizeof(struct mmcsd_cmd));
cmd.cmd_code = SD_APP_SEND_NUM_WR_BLKS;
cmd.arg = 0;
cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC;
memset(&data, 0, sizeof(struct mmcsd_data));
data.timeout_ns = card->tacc_ns * 100;
data.timeout_clks = card->tacc_clks * 100;
timeout_us = data.timeout_ns / 1000;
timeout_us += data.timeout_clks * 1000 /
(card->host->io_cfg.clock / 1000);
if (timeout_us > 100000)
{
data.timeout_ns = 100000000;
data.timeout_clks = 0;
}
data.blksize = 4;
data.blks = 1;
data.flags = DATA_DIR_READ;
data.buf = &blocks;
memset(&req, 0, sizeof(struct mmcsd_req));
req.cmd = &cmd;
req.data = &data;
mmcsd_send_request(card->host, &req);
if (cmd.err || data.err)
return -1;
return blocks;
}
int mmcsd_req_blk(struct mmcsd_card *card,
uint32_t sector,
void *buf,
size_t blks,
uint8_t dir)
{
struct mmcsd_cmd cmd, stop;
struct mmcsd_data data;
struct mmcsd_req req;
struct mmcsd_host *host = card->host;
uint32_t r_cmd, w_cmd;
mmcsd_host_lock(host);
memset(&req, 0, sizeof(struct mmcsd_req));
memset(&cmd, 0, sizeof(struct mmcsd_cmd));
memset(&stop, 0, sizeof(struct mmcsd_cmd));
memset(&data, 0, sizeof(struct mmcsd_data));
req.cmd = &cmd;
req.data = &data;
cmd.arg = sector;
if (!(card->flags & CARD_FLAG_SDHC))
{
cmd.arg <<= 9;
}
cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC;
data.blksize = SECTOR_SIZE;
data.blks = blks;
if (blks > 1)
{
if (!controller_is_spi(card->host) || !dir)
{
req.stop = &stop;
stop.cmd_code = STOP_TRANSMISSION;
stop.arg = 0;
stop.flags = RESP_SPI_R1B | RESP_R1B | CMD_AC;
}
r_cmd = READ_MULTIPLE_BLOCK;
w_cmd = WRITE_MULTIPLE_BLOCK;
}
else
{
req.stop = NULL;
r_cmd = READ_SINGLE_BLOCK;
w_cmd = WRITE_BLOCK;
}
if (!dir)
{
cmd.cmd_code = r_cmd;
data.flags |= DATA_DIR_READ;
}
else
{
cmd.cmd_code = w_cmd;
data.flags |= DATA_DIR_WRITE;
}
mmcsd_set_data_timeout(&data, card);
data.buf = buf;
mmcsd_send_request(host, &req);
if (!controller_is_spi(card->host) && dir != 0)
{
do
{
int32_t err;
cmd.cmd_code = SEND_STATUS;
cmd.arg = card->rca << 16;
cmd.flags = RESP_R1 | CMD_AC;
err = mmcsd_send_cmd(card->host, &cmd, 5);
if (err)
{
TRACE_ERROR("error %d requesting status", err);
break;
}
/*
* Some cards mishandle the status bits,
* so make sure to check both the busy
* indication and the card state.
*/
} while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
(R1_CURRENT_STATE(cmd.resp[0]) == 7));
}
mmcsd_host_unlock(host);
if (cmd.err || data.err || stop.err)
{
TRACE_ERROR("mmcsd request blocks error");
TRACE_ERROR("%d,%d,%d, 0x%08x,0x%08x",
cmd.err, data.err, stop.err, data.flags, sector);
return -1;
}
return 0;
}
int32_t mmcsd_set_blksize(struct mmcsd_card *card)
{
struct mmcsd_cmd cmd;
int err;
/* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
if (card->flags & CARD_FLAG_SDHC)
return 0;
mmcsd_host_lock(card->host);
cmd.cmd_code = SET_BLOCKLEN;
cmd.arg = 512;
cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_AC;
err = mmcsd_send_cmd(card->host, &cmd, 5);
mmcsd_host_unlock(card->host);
if (err)
{
TRACE_ERROR("MMCSD: unable to set block size to %d: %d", cmd.arg, err);
return -1;
}
return 0;
}

View File

@ -0,0 +1,575 @@
#include <string.h>
#include "FreeRTOS.h"
#include "trace.h"
#include "errno.h"
#include "mmcsd_core.h"
#include "mmc.h"
static const uint32_t tran_unit[] =
{
10000, 100000, 1000000, 10000000,
0, 0, 0, 0
};
static const uint8_t tran_value[] =
{
0, 10, 12, 13, 15, 20, 25, 30,
35, 40, 45, 50, 55, 60, 70, 80,
};
static const uint32_t tacc_uint[] =
{
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
};
static const uint8_t tacc_value[] =
{
0, 10, 12, 13, 15, 20, 25, 30,
35, 40, 45, 50, 55, 60, 70, 80,
};
static inline uint32_t GET_BITS(uint32_t *resp,
uint32_t start,
uint32_t size)
{
const int32_t __size = size;
const uint32_t __mask = (__size < 32 ? 1 << __size : 0) - 1;
const int32_t __off = 3 - ((start) / 32);
const int32_t __shft = (start) & 31;
uint32_t __res;
__res = resp[__off] >> __shft;
if (__size + __shft > 32)
__res |= resp[__off-1] << ((32 - __shft) % 32);
return __res & __mask;
}
/*
* Given a 128-bit response, decode to our card CSD structure.
*/
static int32_t mmcsd_parse_csd(struct mmcsd_card *card)
{
uint32_t a, b;
struct mmcsd_csd *csd = &card->csd;
uint32_t *resp = card->resp_csd;
/*
* We only understand CSD structure v1.1 and v1.2.
* v1.2 has extra information in bits 15, 11 and 10.
* We also support eMMC v4.4 & v4.41.
*/
csd->csd_structure = GET_BITS(resp, 126, 2);
if (csd->csd_structure == 0) {
TRACE_ERROR("unrecognised CSD structure version %d!", csd->csd_structure);
return -1;
}
csd->taac = GET_BITS(resp, 112, 8);
csd->nsac = GET_BITS(resp, 104, 8);
csd->tran_speed = GET_BITS(resp, 96, 8);
csd->card_cmd_class = GET_BITS(resp, 84, 12);
csd->rd_blk_len = GET_BITS(resp, 80, 4);
csd->rd_blk_part = GET_BITS(resp, 79, 1);
csd->wr_blk_misalign = GET_BITS(resp, 78, 1);
csd->rd_blk_misalign = GET_BITS(resp, 77, 1);
csd->dsr_imp = GET_BITS(resp, 76, 1);
csd->c_size = GET_BITS(resp, 62, 12);
csd->c_size_mult = GET_BITS(resp, 47, 3);
csd->r2w_factor = GET_BITS(resp, 26, 3);
csd->wr_blk_len = GET_BITS(resp, 22, 4);
csd->wr_blk_partial = GET_BITS(resp, 21, 1);
csd->csd_crc = GET_BITS(resp, 1, 7);
card->card_blksize = 1 << csd->rd_blk_len;
card->card_blknr = (csd->c_size + 1) << (csd->c_size_mult + 2);
card->card_capacity = card->card_blknr * card->card_blksize;
card->card_capacity >>= 10; /* unit:KB */
card->tacc_clks = csd->nsac * 100;
card->tacc_ns = (tacc_uint[csd->taac&0x07] * tacc_value[(csd->taac&0x78)>>3] + 9) / 10;
card->max_data_rate = tran_unit[csd->tran_speed&0x07] * tran_value[(csd->tran_speed&0x78)>>3];
if (csd->wr_blk_len >= 9) {
a = GET_BITS(resp, 42, 5);
b = GET_BITS(resp, 37, 5);
card->erase_size = (a + 1) * (b + 1);
card->erase_size <<= csd->wr_blk_len - 9;
}
return 0;
}
/*
* Read extended CSD.
*/
static int mmc_get_ext_csd(struct mmcsd_card *card, uint8_t **new_ext_csd)
{
void *ext_csd;
struct mmcsd_req req;
struct mmcsd_cmd cmd;
struct mmcsd_data data;
*new_ext_csd = NULL;
if (GET_BITS(card->resp_cid, 122, 4) < 4)
return 0;
/*
* As the ext_csd is so large and mostly unused, we don't store the
* raw block in mmc_card.
*/
ext_csd = pvPortMalloc(512);
if (!ext_csd) {
TRACE_ERROR("alloc memory failed when get ext csd!");
return -ENOMEM;
}
memset(&req, 0, sizeof(struct mmcsd_req));
memset(&cmd, 0, sizeof(struct mmcsd_cmd));
memset(&data, 0, sizeof(struct mmcsd_data));
req.cmd = &cmd;
req.data = &data;
cmd.cmd_code = SEND_EXT_CSD;
cmd.arg = 0;
/* NOTE HACK: the RESP_SPI_R1 is always correct here, but we
* rely on callers to never use this with "native" calls for reading
* CSD or CID. Native versions of those commands use the R2 type,
* not R1 plus a data block.
*/
cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC;
data.blksize = 512;
data.blks = 1;
data.flags = DATA_DIR_READ;
data.buf = ext_csd;
/*
* Some cards require longer data read timeout than indicated in CSD.
* Address this by setting the read timeout to a "reasonably high"
* value. For the cards tested, 300ms has proven enough. If necessary,
* this value can be increased if other problematic cards require this.
*/
data.timeout_ns = 300000000;
data.timeout_clks = 0;
mmcsd_send_request(card->host, &req);
if (cmd.err)
return cmd.err;
if (data.err)
return data.err;
*new_ext_csd = ext_csd;
return 0;
}
/*
* Decode extended CSD.
*/
static int mmc_parse_ext_csd(struct mmcsd_card *card, uint8_t *ext_csd)
{
uint64_t card_capacity = 0;
if(card == NULL || ext_csd == NULL)
{
TRACE_ERROR("emmc parse ext csd fail, invaild args");
return -1;
}
card->flags |= CARD_FLAG_HIGHSPEED;
card->hs_max_data_rate = 52000000;
card_capacity = *((uint32_t *)&ext_csd[EXT_CSD_SEC_CNT]);
card_capacity *= card->card_blksize;
card_capacity >>= 10; /* unit:KB */
card->card_capacity = card_capacity;
TRACE_INFO("emmc card capacity %d KB.", card->card_capacity);
return 0;
}
/**
* mmc_switch - modify EXT_CSD register
* @card: the MMC card associated with the data transfer
* @set: cmd set values
* @index: EXT_CSD register index
* @value: value to program into EXT_CSD register
*
* Modifies the EXT_CSD register for selected card.
*/
static int mmc_switch(struct mmcsd_card *card, uint8_t set,
uint8_t index, uint8_t value)
{
int err;
struct mmcsd_host *host = card->host;
struct mmcsd_cmd cmd = {0};
cmd.cmd_code = SWITCH;
cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
(index << 16) | (value << 8) | set;
cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_AC;
err = mmcsd_send_cmd(host, &cmd, 3);
if (err)
return err;
return 0;
}
static int mmc_compare_ext_csds(struct mmcsd_card *card,
uint8_t *ext_csd, uint32_t bus_width)
{
uint8_t *bw_ext_csd;
int err;
if (bus_width == MMCSD_BUS_WIDTH_1)
return 0;
err = mmc_get_ext_csd(card, &bw_ext_csd);
if (err || bw_ext_csd == NULL) {
err = -1;
goto out;
}
/* only compare read only fields */
err = !((ext_csd[EXT_CSD_PARTITION_SUPPORT] == bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) &&
(ext_csd[EXT_CSD_ERASED_MEM_CONT] == bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) &&
(ext_csd[EXT_CSD_REV] == bw_ext_csd[EXT_CSD_REV]) &&
(ext_csd[EXT_CSD_STRUCTURE] == bw_ext_csd[EXT_CSD_STRUCTURE]) &&
(ext_csd[EXT_CSD_CARD_TYPE] == bw_ext_csd[EXT_CSD_CARD_TYPE]) &&
(ext_csd[EXT_CSD_S_A_TIMEOUT] == bw_ext_csd[EXT_CSD_S_A_TIMEOUT]) &&
(ext_csd[EXT_CSD_HC_WP_GRP_SIZE] == bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE]) &&
(ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] == bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]) &&
(ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] == bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) &&
(ext_csd[EXT_CSD_SEC_TRIM_MULT] == bw_ext_csd[EXT_CSD_SEC_TRIM_MULT]) &&
(ext_csd[EXT_CSD_SEC_ERASE_MULT] == bw_ext_csd[EXT_CSD_SEC_ERASE_MULT]) &&
(ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] == bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]) &&
(ext_csd[EXT_CSD_TRIM_MULT] == bw_ext_csd[EXT_CSD_TRIM_MULT]) &&
(ext_csd[EXT_CSD_SEC_CNT + 0] == bw_ext_csd[EXT_CSD_SEC_CNT + 0]) &&
(ext_csd[EXT_CSD_SEC_CNT + 1] == bw_ext_csd[EXT_CSD_SEC_CNT + 1]) &&
(ext_csd[EXT_CSD_SEC_CNT + 2] == bw_ext_csd[EXT_CSD_SEC_CNT + 2]) &&
(ext_csd[EXT_CSD_SEC_CNT + 3] == bw_ext_csd[EXT_CSD_SEC_CNT + 3]) &&
(ext_csd[EXT_CSD_PWR_CL_52_195] == bw_ext_csd[EXT_CSD_PWR_CL_52_195]) &&
(ext_csd[EXT_CSD_PWR_CL_26_195] == bw_ext_csd[EXT_CSD_PWR_CL_26_195]) &&
(ext_csd[EXT_CSD_PWR_CL_52_360] == bw_ext_csd[EXT_CSD_PWR_CL_52_360]) &&
(ext_csd[EXT_CSD_PWR_CL_26_360] == bw_ext_csd[EXT_CSD_PWR_CL_26_360]) &&
(ext_csd[EXT_CSD_PWR_CL_200_195] == bw_ext_csd[EXT_CSD_PWR_CL_200_195]) &&
(ext_csd[EXT_CSD_PWR_CL_200_360] == bw_ext_csd[EXT_CSD_PWR_CL_200_360]) &&
(ext_csd[EXT_CSD_PWR_CL_DDR_52_195] == bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
(ext_csd[EXT_CSD_PWR_CL_DDR_52_360] == bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
(ext_csd[EXT_CSD_PWR_CL_DDR_200_360] == bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
if (err)
err = -1;
out:
vPortFree(bw_ext_csd);
return err;
}
/*
* Select the bus width amoung 4-bit and 8-bit(SDR).
* If the bus width is changed successfully, return the selected width value.
* Zero is returned instead of error value if the wide width is not supported.
*/
static int mmc_select_bus_width(struct mmcsd_card *card, uint8_t *ext_csd)
{
uint32_t ext_csd_bits[] = {
EXT_CSD_BUS_WIDTH_8,
EXT_CSD_BUS_WIDTH_4,
EXT_CSD_BUS_WIDTH_1
};
uint32_t bus_widths[] = {
MMCSD_BUS_WIDTH_8,
MMCSD_BUS_WIDTH_4,
MMCSD_BUS_WIDTH_1
};
struct mmcsd_host *host = card->host;
unsigned idx, bus_width = 0;
int err = 0;
if (GET_BITS(card->resp_cid, 122, 4) < 4)
return 0;
/*
* Unlike SD, MMC cards dont have a configuration register to notify
* supported bus width. So bus test command should be run to identify
* the supported bus width or compare the ext csd values of current
* bus width and ext csd values of 1 bit mode read earlier.
*/
for (idx = 0; idx < sizeof(bus_widths)/sizeof(uint32_t); idx++) {
/*
* Host is capable of 8bit transfer, then switch
* the device to work in 8bit transfer mode. If the
* mmc switch command returns error then switch to
* 4bit transfer mode. On success set the corresponding
* bus width on the host. Meanwhile, mmc core would
* bail out early if corresponding bus capable wasn't
* set by drivers.
*/
if ((!(host->flags & MMCSD_BUSWIDTH_8) &&
ext_csd_bits[idx] == EXT_CSD_BUS_WIDTH_8) ||
(!(host->flags & MMCSD_BUSWIDTH_4) &&
(ext_csd_bits[idx] == EXT_CSD_BUS_WIDTH_4 ||
ext_csd_bits[idx] == EXT_CSD_BUS_WIDTH_8)))
continue;
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
ext_csd_bits[idx]);
if (err)
continue;
bus_width = bus_widths[idx];
mmcsd_set_bus_width(host, bus_width);
mmcsd_delay_ms(20); //delay 10ms
err = mmc_compare_ext_csds(card, ext_csd, bus_width);
if (!err) {
err = bus_width;
break;
} else {
switch(ext_csd_bits[idx]){
case 0:
TRACE_ERROR("switch to bus width 1 bit failed!");
break;
case 1:
TRACE_ERROR("switch to bus width 4 bit failed!");
break;
case 2:
TRACE_ERROR("switch to bus width 8 bit failed!");
break;
default:
break;
}
}
}
return err;
}
int mmc_send_op_cond(struct mmcsd_host *host,
uint32_t ocr, uint32_t *rocr)
{
struct mmcsd_cmd cmd;
uint32_t i;
int err = 0;
memset(&cmd, 0, sizeof(struct mmcsd_cmd));
cmd.cmd_code = SEND_OP_COND;
cmd.arg = controller_is_spi(host) ? 0 : ocr;
cmd.flags = RESP_SPI_R1 | RESP_R3 | CMD_BCR;
for (i = 100; i; i--) {
err = mmcsd_send_cmd(host, &cmd, 3);
if (err)
break;
/* if we're just probing, do a single pass */
if (ocr == 0)
break;
/* otherwise wait until reset completes */
if (controller_is_spi(host)) {
if (!(cmd.resp[0] & R1_SPI_IDLE))
break;
} else {
if (cmd.resp[0] & CARD_BUSY)
break;
}
err = -1;
mmcsd_delay_ms(10); //delay 10ms
}
if (rocr && !controller_is_spi(host))
*rocr = cmd.resp[0];
return err;
}
static int mmc_set_card_addr(struct mmcsd_host *host, uint32_t rca)
{
int err;
struct mmcsd_cmd cmd;
memset(&cmd, 0, sizeof(struct mmcsd_cmd));
cmd.cmd_code = SET_RELATIVE_ADDR;
cmd.arg = rca << 16;
cmd.flags = RESP_R1 | CMD_AC;
err = mmcsd_send_cmd(host, &cmd, 3);
if (err)
return err;
return 0;
}
static int32_t mmcsd_mmc_init_card(struct mmcsd_host *host,
uint32_t ocr)
{
int32_t err;
uint32_t resp[4];
uint32_t rocr = 0;
uint32_t max_data_rate;
uint8_t *ext_csd = NULL;
struct mmcsd_card *card = NULL;
mmcsd_go_idle(host);
/* The extra bit indicates that we support high capacity */
err = mmc_send_op_cond(host, ocr | (1 << 30), &rocr);
if (err)
goto err;
if (controller_is_spi(host))
{
err = mmcsd_spi_use_crc(host, 1);
if (err)
goto err1;
}
if (controller_is_spi(host))
err = mmcsd_get_cid(host, resp);
else
err = mmcsd_all_get_cid(host, resp);
if (err)
goto err;
card = pvPortMalloc(sizeof(struct mmcsd_card));
if (!card)
{
TRACE_ERROR("malloc card failed!");
err = -ENOMEM;
goto err;
}
memset(card, 0, sizeof(struct mmcsd_card));
card->card_type = CARD_TYPE_MMC;
card->host = host;
card->rca = 1;
memcpy(card->resp_cid, resp, sizeof(card->resp_cid));
/*
* For native busses: get card RCA and quit open drain mode.
*/
if (!controller_is_spi(host))
{
err = mmc_set_card_addr(host, card->rca);
if (err)
goto err1;
mmcsd_set_bus_mode(host, MMCSD_BUSMODE_PUSHPULL);
}
err = mmcsd_get_csd(card, card->resp_csd);
if (err)
goto err1;
err = mmcsd_parse_csd(card);
if (err)
goto err1;
if (!controller_is_spi(host))
{
err = mmcsd_select_card(card);
if (err)
goto err1;
}
/*
* Fetch and process extended CSD.
*/
err = mmc_get_ext_csd(card, &ext_csd);
if (err)
goto err1;
err = mmc_parse_ext_csd(card, ext_csd);
if (err)
goto err1;
/* If doing byte addressing, check if required to do sector
* addressing. Handle the case of <2GB cards needing sector
* addressing. See section 8.1 JEDEC Standard JED84-A441;
* ocr register has bit 30 set for sector addressing.
*/
if (!(card->flags & CARD_FLAG_SDHC) && (rocr & (1<<30)))
card->flags |= CARD_FLAG_SDHC;
/* set bus speed */
if (card->flags & CARD_FLAG_HIGHSPEED)
max_data_rate = card->hs_max_data_rate;
else
max_data_rate = card->max_data_rate;
mmcsd_set_clock(host, max_data_rate);
/*switch bus width*/
mmc_select_bus_width(card, ext_csd);
host->card = card;
vPortFree(ext_csd);
return 0;
err1:
vPortFree(card);
err:
return err;
}
/*
* Starting point for mmc card init.
*/
int32_t init_mmc(struct mmcsd_host *host, uint32_t ocr)
{
int32_t err;
uint32_t current_ocr;
/*
* We need to get OCR a different way for SPI.
*/
if (controller_is_spi(host))
{
err = mmcsd_spi_read_ocr(host, 0, &ocr);
if (err)
goto err;
}
current_ocr = mmcsd_select_voltage(host, ocr);
/*
* Can we support the voltage(s) of the card(s)?
*/
if (!current_ocr)
{
err = -1;
goto err;
}
/*
* Detect and init the card.
*/
err = mmcsd_mmc_init_card(host, current_ocr);
if (err)
goto err;
mmcsd_host_unlock(host);
mmcsd_host_lock(host);
return 0;
err:
TRACE_ERROR("init MMC card failed!");
return err;
}

View File

@ -0,0 +1,771 @@
#include "FreeRTOS.h"
#include "os_adapt.h"
#include "trace.h"
#include "errno.h"
#include "ff_sddisk.h"
#include "mmcsd_core.h"
#include "sd.h"
#include "mmc.h"
#include "sdio.h"
#define MMCSD_STACK_SIZE 2048
#define MMCSD_THREAD_PREORITY 0x16
#define SDMMC_MOUNT_PATH "/sd"
struct mmcsd_card *sdmmc_cardinfo = NULL;
FF_Disk_t *sdmmc_disk;
static TaskHandle_t mmcsd_detect_thread;
static QueueHandle_t mmcsd_detect_mb;
static QueueHandle_t mmcsd_hotpluge_mb;
static QueueHandle_t mmcsd_sdio_ready_mb;
static QueueHandle_t mmcsd_mmc_ready_mb;
void mmcsd_host_lock(struct mmcsd_host *host)
{
xSemaphoreTake(host->bus_lock, portMAX_DELAY);
}
void mmcsd_host_unlock(struct mmcsd_host *host)
{
xSemaphoreGive(host->bus_lock);
}
void mmcsd_req_complete(struct mmcsd_host *host)
{
xSemaphoreGive(host->sem_ack);
}
void mmcsd_send_request(struct mmcsd_host *host, struct mmcsd_req *req)
{
do {
req->cmd->retries--;
req->cmd->err = 0;
req->cmd->mrq = req;
if (req->data)
{
req->cmd->data = req->data;
req->data->err = 0;
req->data->mrq = req;
if (req->stop)
{
req->data->stop = req->stop;
req->stop->err = 0;
req->stop->mrq = req;
}
}
host->ops->request(host, req);
xSemaphoreTake(host->sem_ack, portMAX_DELAY);
} while(req->cmd->err && (req->cmd->retries > 0));
}
int32_t mmcsd_send_cmd(struct mmcsd_host *host,
struct mmcsd_cmd *cmd,
int retries)
{
struct mmcsd_req req;
memset(&req, 0, sizeof(struct mmcsd_req));
memset(cmd->resp, 0, sizeof(cmd->resp));
cmd->retries = retries;
req.cmd = cmd;
cmd->data = NULL;
mmcsd_send_request(host, &req);
return cmd->err;
}
int32_t mmcsd_go_idle(struct mmcsd_host *host)
{
int32_t err;
struct mmcsd_cmd cmd;
if (!controller_is_spi(host))
{
mmcsd_set_chip_select(host, MMCSD_CS_HIGH);
mmcsd_delay_ms(1);
}
memset(&cmd, 0, sizeof(struct mmcsd_cmd));
cmd.cmd_code = GO_IDLE_STATE;
cmd.arg = 0;
cmd.flags = RESP_SPI_R1 | RESP_NONE | CMD_BC;
err = mmcsd_send_cmd(host, &cmd, 0);
mmcsd_delay_ms(1);
if (!controller_is_spi(host))
{
mmcsd_set_chip_select(host, MMCSD_CS_IGNORE);
mmcsd_delay_ms(1);
}
return err;
}
int32_t mmcsd_spi_read_ocr(struct mmcsd_host *host,
int32_t high_capacity,
uint32_t *ocr)
{
struct mmcsd_cmd cmd;
int32_t err;
memset(&cmd, 0, sizeof(struct mmcsd_cmd));
cmd.cmd_code = SPI_READ_OCR;
cmd.arg = high_capacity ? (1 << 30) : 0;
cmd.flags = RESP_SPI_R3;
err = mmcsd_send_cmd(host, &cmd, 0);
*ocr = cmd.resp[1];
return err;
}
int32_t mmcsd_all_get_cid(struct mmcsd_host *host, uint32_t *cid)
{
int32_t err;
struct mmcsd_cmd cmd;
memset(&cmd, 0, sizeof(struct mmcsd_cmd));
cmd.cmd_code = ALL_SEND_CID;
cmd.arg = 0;
cmd.flags = RESP_R2 | CMD_BCR;
err = mmcsd_send_cmd(host, &cmd, 3);
if (err)
return err;
memcpy(cid, cmd.resp, sizeof(uint32_t) * 4);
return 0;
}
int32_t mmcsd_get_cid(struct mmcsd_host *host, uint32_t *cid)
{
int32_t err, i;
struct mmcsd_req req;
struct mmcsd_cmd cmd;
struct mmcsd_data data;
uint32_t *buf = NULL;
if (!controller_is_spi(host))
{
if (!host->card)
return -1;
memset(&cmd, 0, sizeof(struct mmcsd_cmd));
cmd.cmd_code = SEND_CID;
cmd.arg = host->card->rca << 16;
cmd.flags = RESP_R2 | CMD_AC;
err = mmcsd_send_cmd(host, &cmd, 3);
if (err)
return err;
memcpy(cid, cmd.resp, sizeof(uint32_t) * 4);
return 0;
}
buf = (uint32_t *)pvPortMalloc(16);
if (!buf)
{
TRACE_ERROR("allocate memory failed!");
return -ENOMEM;
}
memset(&req, 0, sizeof(struct mmcsd_req));
memset(&cmd, 0, sizeof(struct mmcsd_cmd));
memset(&data, 0, sizeof(struct mmcsd_data));
req.cmd = &cmd;
req.data = &data;
cmd.cmd_code = SEND_CID;
cmd.arg = 0;
/* NOTE HACK: the RESP_SPI_R1 is always correct here, but we
* rely on callers to never use this with "native" calls for reading
* CSD or CID. Native versions of those commands use the R2 type,
* not R1 plus a data block.
*/
cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC;
data.blksize = 16;
data.blks = 1;
data.flags = DATA_DIR_READ;
data.buf = buf;
/*
* The spec states that CSR and CID accesses have a timeout
* of 64 clock cycles.
*/
data.timeout_ns = 0;
data.timeout_clks = 64;
mmcsd_send_request(host, &req);
if (cmd.err || data.err)
{
vPortFree(buf);
return -1;
}
for (i = 0;i < 4;i++)
cid[i] = buf[i];
vPortFree(buf);
return 0;
}
int32_t mmcsd_get_csd(struct mmcsd_card *card, uint32_t *csd)
{
int32_t err, i;
struct mmcsd_req req;
struct mmcsd_cmd cmd;
struct mmcsd_data data;
uint32_t *buf = NULL;
if (!controller_is_spi(card->host))
{
memset(&cmd, 0, sizeof(struct mmcsd_cmd));
cmd.cmd_code = SEND_CSD;
cmd.arg = card->rca << 16;
cmd.flags = RESP_R2 | CMD_AC;
err = mmcsd_send_cmd(card->host, &cmd, 3);
if (err)
return err;
memcpy(csd, cmd.resp, sizeof(uint32_t) * 4);
return 0;
}
buf = (uint32_t*)pvPortMalloc(16);
if (!buf)
{
TRACE_ERROR("allocate memory failed!");
return -ENOMEM;
}
memset(&req, 0, sizeof(struct mmcsd_req));
memset(&cmd, 0, sizeof(struct mmcsd_cmd));
memset(&data, 0, sizeof(struct mmcsd_data));
req.cmd = &cmd;
req.data = &data;
cmd.cmd_code = SEND_CSD;
cmd.arg = 0;
/* NOTE HACK: the RESP_SPI_R1 is always correct here, but we
* rely on callers to never use this with "native" calls for reading
* CSD or CID. Native versions of those commands use the R2 type,
* not R1 plus a data block.
*/
cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC;
data.blksize = 16;
data.blks = 1;
data.flags = DATA_DIR_READ;
data.buf = buf;
/*
* The spec states that CSR and CID accesses have a timeout
* of 64 clock cycles.
*/
data.timeout_ns = 0;
data.timeout_clks = 64;
mmcsd_send_request(card->host, &req);
if (cmd.err || data.err)
{
vPortFree(buf);
return -1;
}
for (i = 0;i < 4;i++)
csd[i] = buf[i];
vPortFree(buf);
return 0;
}
static int32_t _mmcsd_select_card(struct mmcsd_host *host,
struct mmcsd_card *card)
{
int32_t err;
struct mmcsd_cmd cmd;
memset(&cmd, 0, sizeof(struct mmcsd_cmd));
cmd.cmd_code = SELECT_CARD;
if (card)
{
cmd.arg = card->rca << 16;
cmd.flags = RESP_R1 | CMD_AC;
}
else
{
cmd.arg = 0;
cmd.flags = RESP_NONE | CMD_AC;
}
err = mmcsd_send_cmd(host, &cmd, 3);
if (err)
return err;
return 0;
}
int32_t mmcsd_select_card(struct mmcsd_card *card)
{
return _mmcsd_select_card(card->host, card);
}
int32_t mmcsd_deselect_cards(struct mmcsd_card *card)
{
return _mmcsd_select_card(card->host, NULL);
}
int32_t mmcsd_spi_use_crc(struct mmcsd_host *host, int32_t use_crc)
{
struct mmcsd_cmd cmd;
int32_t err;
memset(&cmd, 0, sizeof(struct mmcsd_cmd));
cmd.cmd_code = SPI_CRC_ON_OFF;
cmd.flags = RESP_SPI_R1;
cmd.arg = use_crc;
err = mmcsd_send_cmd(host, &cmd, 0);
if (!err)
host->spi_use_crc = use_crc;
return err;
}
static inline void mmcsd_set_iocfg(struct mmcsd_host *host)
{
struct mmcsd_io_cfg *io_cfg = &host->io_cfg;
mmcsd_dbg("clock %uHz busmode %u powermode %u cs %u Vdd %u "
"width %u \n",
io_cfg->clock, io_cfg->bus_mode,
io_cfg->power_mode, io_cfg->chip_select, io_cfg->vdd,
io_cfg->bus_width);
host->ops->set_iocfg(host, io_cfg);
}
/*
* Control chip select pin on a host.
*/
void mmcsd_set_chip_select(struct mmcsd_host *host, int32_t mode)
{
host->io_cfg.chip_select = mode;
mmcsd_set_iocfg(host);
}
/*
* Sets the host clock to the highest possible frequency that
* is below "hz".
*/
void mmcsd_set_clock(struct mmcsd_host *host, uint32_t clk)
{
if (clk < host->freq_min)
{
TRACE_WARNING("clock too low!");
}
host->io_cfg.clock = clk;
mmcsd_set_iocfg(host);
}
/*
* Change the bus mode (open drain/push-pull) of a host.
*/
void mmcsd_set_bus_mode(struct mmcsd_host *host, uint32_t mode)
{
host->io_cfg.bus_mode = mode;
mmcsd_set_iocfg(host);
}
/*
* Change data bus width of a host.
*/
void mmcsd_set_bus_width(struct mmcsd_host *host, uint32_t width)
{
host->io_cfg.bus_width = width;
mmcsd_set_iocfg(host);
}
void mmcsd_set_data_timeout(struct mmcsd_data *data,
const struct mmcsd_card *card)
{
uint32_t mult;
if (card->card_type == CARD_TYPE_SDIO)
{
data->timeout_ns = 1000000000; /* SDIO card 1s */
data->timeout_clks = 0;
return;
}
/*
* SD cards use a 100 multiplier rather than 10
*/
mult = (card->card_type == CARD_TYPE_SD) ? 100 : 10;
/*
* Scale up the multiplier (and therefore the timeout) by
* the r2w factor for writes.
*/
if (data->flags & DATA_DIR_WRITE)
mult <<= card->csd.r2w_factor;
data->timeout_ns = card->tacc_ns * mult;
data->timeout_clks = card->tacc_clks * mult;
/*
* SD cards also have an upper limit on the timeout.
*/
if (card->card_type == CARD_TYPE_SD)
{
uint32_t timeout_us, limit_us;
timeout_us = data->timeout_ns / 1000;
timeout_us += data->timeout_clks * 1000 /
(card->host->io_cfg.clock / 1000);
if (data->flags & DATA_DIR_WRITE)
/*
* The limit is really 250 ms, but that is
* insufficient for some crappy cards.
*/
limit_us = 300000;
else
limit_us = 100000;
/*
* SDHC cards always use these fixed values.
*/
if (timeout_us > limit_us || card->flags & CARD_FLAG_SDHC)
{
data->timeout_ns = limit_us * 1000; /* SDHC card fixed 250ms */
data->timeout_clks = 0;
}
}
if (controller_is_spi(card->host))
{
if (data->flags & DATA_DIR_WRITE)
{
if (data->timeout_ns < 1000000000)
data->timeout_ns = 1000000000; /* 1s */
}
else
{
if (data->timeout_ns < 100000000)
data->timeout_ns = 100000000; /* 100ms */
}
}
}
/*
* Mask off any voltages we don't support and select
* the lowest voltage
*/
uint32_t mmcsd_select_voltage(struct mmcsd_host *host, uint32_t ocr)
{
int bit;
ocr &= host->valid_ocr;
bit = ffs(ocr);
if (bit)
{
bit -= 1;
ocr &= 3 << bit;
host->io_cfg.vdd = bit;
mmcsd_set_iocfg(host);
}
else
{
TRACE_WARNING("host doesn't support card's voltages!");
ocr = 0;
}
return ocr;
}
static void mmcsd_power_up(struct mmcsd_host *host)
{
int bit = fls(host->valid_ocr) - 1;
host->io_cfg.vdd = bit;
if (controller_is_spi(host))
{
host->io_cfg.chip_select = MMCSD_CS_HIGH;
host->io_cfg.bus_mode = MMCSD_BUSMODE_PUSHPULL;
}
else
{
host->io_cfg.chip_select = MMCSD_CS_IGNORE;
host->io_cfg.bus_mode = MMCSD_BUSMODE_OPENDRAIN;
}
host->io_cfg.power_mode = MMCSD_POWER_UP;
host->io_cfg.bus_width = MMCSD_BUS_WIDTH_1;
mmcsd_set_iocfg(host);
/*
* This delay should be sufficient to allow the power supply
* to reach the minimum voltage.
*/
mmcsd_delay_ms(10);
host->io_cfg.clock = host->freq_min;
host->io_cfg.power_mode = MMCSD_POWER_ON;
mmcsd_set_iocfg(host);
/*
* This delay must be at least 74 clock sizes, or 1 ms, or the
* time required to reach a stable voltage.
*/
mmcsd_delay_ms(10);
}
static void mmcsd_power_off(struct mmcsd_host *host)
{
host->io_cfg.clock = 0;
host->io_cfg.vdd = 0;
if (!controller_is_spi(host))
{
host->io_cfg.bus_mode = MMCSD_BUSMODE_OPENDRAIN;
host->io_cfg.chip_select = MMCSD_CS_IGNORE;
}
host->io_cfg.power_mode = MMCSD_POWER_OFF;
host->io_cfg.bus_width = MMCSD_BUS_WIDTH_1;
mmcsd_set_iocfg(host);
}
int mmcsd_wait_cd_changed(uint32_t timeout)
{
struct mmcsd_host *host;
if (xQueueReceive(mmcsd_hotpluge_mb, &host, timeout) == pdPASS)
{
if(host->card == NULL)
{
return MMCSD_HOST_UNPLUGED;
}
else
{
return MMCSD_HOST_PLUGED;
}
}
return -1;
}
int mmcsd_wait_sdio_ready(int32_t timeout)
{
struct mmcsd_host *host;
if (xQueueReceive(mmcsd_sdio_ready_mb, &host, timeout) == pdPASS)
return MMCSD_HOST_PLUGED;
return -1;
}
int mmcsd_wait_mmc_ready(uint32_t timeout)
{
struct mmcsd_host *host;
if (xQueueReceive(mmcsd_mmc_ready_mb, &host, timeout) == pdPASS)
return MMCSD_HOST_PLUGED;
return -1;
}
void mmcsd_change(struct mmcsd_host *host)
{
xQueueSend(mmcsd_detect_mb, &host, 0);
}
void mmcsd_change_from_isr(struct mmcsd_host *host)
{
xQueueSendFromISR(mmcsd_detect_mb, &host, 0);
}
void mmcsd_detect(void *param)
{
struct mmcsd_host *host;
uint32_t ocr;
int32_t err;
while (1)
{
if (xQueueReceive(mmcsd_detect_mb, &host, portMAX_DELAY) == pdPASS)
{
if (host->card == NULL)
{
mmcsd_host_lock(host);
mmcsd_power_up(host);
mmcsd_go_idle(host);
mmcsd_send_if_cond(host, host->valid_ocr);
#if DEVICE_TYPE_SELECT != EMMC_FLASH
err = sdio_io_send_op_cond(host, 0, &ocr);
if (!err)
{
if (init_sdio(host, ocr))
mmcsd_power_off(host);
else
xQueueSend(mmcsd_sdio_ready_mb, &host, 0);
mmcsd_host_unlock(host);
continue;
}
/*
* detect SD card
*/
err = mmcsd_send_app_op_cond(host, 0, &ocr);
if (!err)
{
if (init_sd(host, ocr)) {
mmcsd_power_off(host);
} else {
sdmmc_cardinfo = host->card;
mmcsd_host_unlock(host);
sdmmc_disk = FF_SDDiskInit(SDMMC_MOUNT_PATH);
xQueueSend(mmcsd_hotpluge_mb, &host, 0);
}
continue;
}
#else
/*
* detect mmc card
*/
err = mmc_send_op_cond(host, 0, &ocr);
if (!err)
{
if (init_mmc(host, ocr)) {
mmcsd_power_off(host);
} else {
sdmmc_cardinfo = host->card;
mmcsd_host_unlock(host);
sdmmc_disk = FF_SDDiskInit(SDMMC_MOUNT_PATH);
xQueueSend(mmcsd_mmc_ready_mb, &host, 0);
}
continue;
}
#endif
mmcsd_host_unlock(host);
}
else
{
/* card removed */
mmcsd_host_lock(host);
if (host->card->sdio_function_num != 0)
{
TRACE_WARNING("unsupport sdio card plug out!\r\n");
}
else
{
if (host->card->card_type == CARD_TYPE_SD || host->card->card_type == CARD_TYPE_MMC) {
FF_SDDiskDelete(sdmmc_disk);
sdmmc_cardinfo = NULL;
}
vPortFree(host->card);
host->card = NULL;
}
mmcsd_host_unlock(host);
xQueueSend(mmcsd_hotpluge_mb, &host, 0);
}
}
}
}
struct mmcsd_host *mmcsd_alloc_host(void)
{
struct mmcsd_host *host;
host = pvPortMalloc(sizeof(struct mmcsd_host));
if (!host)
{
TRACE_ERROR("alloc host failed");
return NULL;
}
memset(host, 0, sizeof(struct mmcsd_host));
host->max_seg_size = 65535;
host->max_dma_segs = 1;
host->max_blk_size = 512;
host->max_blk_count = 4096;
host->bus_lock = xSemaphoreCreateMutex();
host->sem_ack= xSemaphoreCreateBinary();
return host;
}
void mmcsd_free_host(struct mmcsd_host *host)
{
vSemaphoreDelete(host->bus_lock);
vSemaphoreDelete(host->sem_ack);
vPortFree(host);
}
int mmcsd_core_init(void)
{
/* initialize detect SD cart thread */
/* initialize mailbox and create detect SD card thread */
mmcsd_detect_mb = xQueueCreate(4, sizeof(uint32_t));
configASSERT(mmcsd_detect_mb);
mmcsd_hotpluge_mb = xQueueCreate(4, sizeof(uint32_t));
configASSERT(mmcsd_hotpluge_mb);
mmcsd_sdio_ready_mb = xQueueCreate(4, sizeof(uint32_t));
configASSERT(mmcsd_sdio_ready_mb);
mmcsd_mmc_ready_mb = xQueueCreate(4, sizeof(uint32_t));
configASSERT(mmcsd_mmc_ready_mb);
xTaskCreate(mmcsd_detect, "mmcsd_detect", MMCSD_STACK_SIZE,
NULL, MMCSD_THREAD_PREORITY, &mmcsd_detect_thread);
#if DEVICE_TYPE_SELECT != EMMC_FLASH
sdio_init();
#endif
return 0;
}
struct mmcsd_card *mmcsd_get_sdmmc_card_info(void)
{
return sdmmc_cardinfo;
}

View File

@ -0,0 +1,687 @@
#include <string.h>
#include "FreeRTOS.h"
#include "trace.h"
#include "errno.h"
#include "mmcsd_core.h"
#include "sd.h"
static const uint32_t tran_unit[] =
{
10000, 100000, 1000000, 10000000,
0, 0, 0, 0
};
static const uint8_t tran_value[] =
{
0, 10, 12, 13, 15, 20, 25, 30,
35, 40, 45, 50, 55, 60, 70, 80,
};
static const uint32_t tacc_uint[] =
{
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
};
static const uint8_t tacc_value[] =
{
0, 10, 12, 13, 15, 20, 25, 30,
35, 40, 45, 50, 55, 60, 70, 80,
};
static inline uint32_t GET_BITS(uint32_t *resp,
uint32_t start,
uint32_t size)
{
const int32_t __size = size;
const uint32_t __mask = (__size < 32 ? 1 << __size : 0) - 1;
const int32_t __off = 3 - ((start) / 32);
const int32_t __shft = (start) & 31;
uint32_t __res;
__res = resp[__off] >> __shft;
if (__size + __shft > 32)
__res |= resp[__off-1] << ((32 - __shft) % 32);
return __res & __mask;
}
static int32_t mmcsd_parse_csd(struct mmcsd_card *card)
{
struct mmcsd_csd *csd = &card->csd;
uint32_t *resp = card->resp_csd;
csd->csd_structure = GET_BITS(resp, 126, 2);
switch (csd->csd_structure)
{
case 0:
csd->taac = GET_BITS(resp, 112, 8);
csd->nsac = GET_BITS(resp, 104, 8);
csd->tran_speed = GET_BITS(resp, 96, 8);
csd->card_cmd_class = GET_BITS(resp, 84, 12);
csd->rd_blk_len = GET_BITS(resp, 80, 4);
csd->rd_blk_part = GET_BITS(resp, 79, 1);
csd->wr_blk_misalign = GET_BITS(resp, 78, 1);
csd->rd_blk_misalign = GET_BITS(resp, 77, 1);
csd->dsr_imp = GET_BITS(resp, 76, 1);
csd->c_size = GET_BITS(resp, 62, 12);
csd->c_size_mult = GET_BITS(resp, 47, 3);
csd->r2w_factor = GET_BITS(resp, 26, 3);
csd->wr_blk_len = GET_BITS(resp, 22, 4);
csd->wr_blk_partial = GET_BITS(resp, 21, 1);
csd->csd_crc = GET_BITS(resp, 1, 7);
card->card_blksize = 1 << csd->rd_blk_len;
card->card_blknr = (csd->c_size + 1) << (csd->c_size_mult + 2);
card->card_capacity = card->card_blknr * card->card_blksize;
card->card_capacity >>= 10; /* unit:KB */
card->tacc_clks = csd->nsac * 100;
card->tacc_ns = (tacc_uint[csd->taac&0x07] * tacc_value[(csd->taac&0x78)>>3] + 9) / 10;
card->max_data_rate = tran_unit[csd->tran_speed&0x07] * tran_value[(csd->tran_speed&0x78)>>3];
break;
case 1:
card->flags |= CARD_FLAG_SDHC;
/*This field is fixed to 0Eh, which indicates 1 ms.
The host should not use TAAC, NSAC, and R2W_FACTOR
to calculate timeout and should uses fixed timeout
values for read and write operations*/
csd->taac = GET_BITS(resp, 112, 8);
csd->nsac = GET_BITS(resp, 104, 8);
csd->tran_speed = GET_BITS(resp, 96, 8);
csd->card_cmd_class = GET_BITS(resp, 84, 12);
csd->rd_blk_len = GET_BITS(resp, 80, 4);
csd->rd_blk_part = GET_BITS(resp, 79, 1);
csd->wr_blk_misalign = GET_BITS(resp, 78, 1);
csd->rd_blk_misalign = GET_BITS(resp, 77, 1);
csd->dsr_imp = GET_BITS(resp, 76, 1);
csd->c_size = GET_BITS(resp, 48, 22);
csd->r2w_factor = GET_BITS(resp, 26, 3);
csd->wr_blk_len = GET_BITS(resp, 22, 4);
csd->wr_blk_partial = GET_BITS(resp, 21, 1);
csd->csd_crc = GET_BITS(resp, 1, 7);
card->card_blknr = (csd->c_size + 1) << 10;
card->card_blksize = 512;
card->card_capacity = (csd->c_size + 1) * 512; /* unit:KB */
card->tacc_clks = 0;
card->tacc_ns = 0;
card->max_data_rate = tran_unit[csd->tran_speed&0x07] * tran_value[(csd->tran_speed&0x78)>>3];
break;
default:
TRACE_ERROR("unrecognised CSD structure version %d!", csd->csd_structure);
return -1;
}
TRACE_INFO("SD card capacity %d KB.", card->card_capacity);
return 0;
}
static int32_t mmcsd_parse_scr(struct mmcsd_card *card)
{
struct sd_scr *scr = &card->scr;
uint32_t resp[4];
resp[3] = card->resp_scr[1];
resp[2] = card->resp_scr[0];
scr->sd_version = GET_BITS(resp, 56, 4);
scr->sd_bus_widths = GET_BITS(resp, 48, 4);
return 0;
}
static int32_t mmcsd_switch(struct mmcsd_card *card)
{
int32_t err;
struct mmcsd_host *host = card->host;
struct mmcsd_req req;
struct mmcsd_cmd cmd;
struct mmcsd_data data;
uint8_t *buf;
buf = (uint8_t*)pvPortMalloc(64);
if (!buf)
{
TRACE_ERROR("alloc memory failed!");
return -ENOMEM;
}
if (card->card_type != CARD_TYPE_SD)
goto err;
if (card->scr.sd_version < SCR_SPEC_VER_1)
goto err;
memset(&cmd, 0, sizeof(struct mmcsd_cmd));
cmd.cmd_code = SD_SWITCH;
cmd.arg = 0x00FFFFF1;
cmd.flags = RESP_R1 | CMD_ADTC;
memset(&data, 0, sizeof(struct mmcsd_data));
mmcsd_set_data_timeout(&data, card);
data.blksize = 64;
data.blks = 1;
data.flags = DATA_DIR_READ;
data.buf = (uint32_t *)buf;
memset(&req, 0, sizeof(struct mmcsd_req));
req.cmd = &cmd;
req.data = &data;
mmcsd_send_request(host, &req);
if (cmd.err || data.err)
{
goto err1;
}
if (buf[13] & 0x02)
card->hs_max_data_rate = 50000000;
memset(&cmd, 0, sizeof(struct mmcsd_cmd));
cmd.cmd_code = SD_SWITCH;
cmd.arg = 0x80FFFFF1;
cmd.flags = RESP_R1 | CMD_ADTC;
memset(&data, 0, sizeof(struct mmcsd_data));
mmcsd_set_data_timeout(&data, card);
data.blksize = 64;
data.blks = 1;
data.flags = DATA_DIR_READ;
data.buf = (uint32_t *)buf;
memset(&req, 0, sizeof(struct mmcsd_req));
req.cmd = &cmd;
req.data = &data;
mmcsd_send_request(host, &req);
if (cmd.err || data.err)
{
goto err1;
}
if ((buf[16] & 0xF) != 1)
{
TRACE_INFO("switching card to high speed failed!");
goto err;
}
card->flags |= CARD_FLAG_HIGHSPEED;
err:
vPortFree(buf);
return 0;
err1:
if (cmd.err)
err = cmd.err;
if (data.err)
err = data.err;
return err;
}
static int mmcsd_app_cmd(struct mmcsd_host *host,
struct mmcsd_card *card)
{
int err;
struct mmcsd_cmd cmd = {0};
cmd.cmd_code = APP_CMD;
if (card)
{
cmd.arg = card->rca << 16;
cmd.flags = RESP_R1 | CMD_AC;
}
else
{
cmd.arg = 0;
cmd.flags = RESP_R1 | CMD_BCR;
}
err = mmcsd_send_cmd(host, &cmd, 0);
if (err)
return err;
/* Check that card supported application commands */
if (!controller_is_spi(host) && !(cmd.resp[0] & R1_APP_CMD))
return -1;
return 0;
}
int mmcsd_send_app_cmd(struct mmcsd_host *host,
struct mmcsd_card *card,
struct mmcsd_cmd *cmd,
int retry)
{
struct mmcsd_req req;
uint32_t i;
int err;
err = -1;
/*
* We have to resend MMC_APP_CMD for each attempt so
* we cannot use the retries field in mmc_command.
*/
for (i = 0;i <= retry;i++)
{
memset(&req, 0, sizeof(struct mmcsd_req));
err = mmcsd_app_cmd(host, card);
if (err)
{
/* no point in retrying; no APP commands allowed */
if (controller_is_spi(host))
{
if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
break;
}
continue;
}
memset(&req, 0, sizeof(struct mmcsd_req));
memset(cmd->resp, 0, sizeof(cmd->resp));
req.cmd = cmd;
//cmd->data = NULL;
mmcsd_send_request(host, &req);
err = cmd->err;
if (!cmd->err)
break;
/* no point in retrying illegal APP commands */
if (controller_is_spi(host))
{
if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
break;
}
}
return err;
}
int mmcsd_app_set_bus_width(struct mmcsd_card *card, int32_t width)
{
int err;
struct mmcsd_cmd cmd;
memset(&cmd, 0, sizeof(struct mmcsd_cmd));
cmd.cmd_code = SD_APP_SET_BUS_WIDTH;
cmd.flags = RESP_R1 | CMD_AC;
switch (width)
{
case MMCSD_BUS_WIDTH_1:
cmd.arg = MMCSD_BUS_WIDTH_1;
break;
case MMCSD_BUS_WIDTH_4:
cmd.arg = MMCSD_BUS_WIDTH_4;
break;
default:
return -1;
}
err = mmcsd_send_app_cmd(card->host, card, &cmd, 3);
if (err)
return err;
return 0;
}
int mmcsd_send_app_op_cond(struct mmcsd_host *host,
uint32_t ocr,
uint32_t *rocr)
{
struct mmcsd_cmd cmd;
uint32_t i;
int err = 0;
memset(&cmd, 0, sizeof(struct mmcsd_cmd));
cmd.cmd_code = SD_APP_OP_COND;
if (controller_is_spi(host))
cmd.arg = ocr & (1 << 30); /* SPI only defines one bit */
else
cmd.arg = ocr;
cmd.flags = RESP_SPI_R1 | RESP_R3 | CMD_BCR;
for (i = 100; i; i--)
{
err = mmcsd_send_app_cmd(host, NULL, &cmd, 3);
if (err)
break;
/* if we're just probing, do a single pass */
if (ocr == 0)
break;
/* otherwise wait until reset completes */
if (controller_is_spi(host))
{
if (!(cmd.resp[0] & R1_SPI_IDLE))
break;
}
else
{
if (cmd.resp[0] & CARD_BUSY)
break;
}
err = -1;
mmcsd_delay_ms(10); //delay 10ms
}
if (rocr && !controller_is_spi(host))
*rocr = cmd.resp[0];
return err;
}
/*
* To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
* before SD_APP_OP_COND. This command will harmlessly fail for
* SD 1.0 cards.
*/
int mmcsd_send_if_cond(struct mmcsd_host *host, uint32_t ocr)
{
struct mmcsd_cmd cmd;
int err;
uint8_t pattern;
cmd.cmd_code = SD_SEND_IF_COND;
cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | 0xAA;
cmd.flags = RESP_SPI_R7 | RESP_R7 | CMD_BCR;
err = mmcsd_send_cmd(host, &cmd, 0);
if (err)
return err;
if (controller_is_spi(host))
pattern = cmd.resp[1] & 0xFF;
else
pattern = cmd.resp[0] & 0xFF;
if (pattern != 0xAA)
return -1;
return 0;
}
int mmcsd_get_card_addr(struct mmcsd_host *host, uint32_t *rca)
{
int err;
struct mmcsd_cmd cmd;
memset(&cmd, 0, sizeof(struct mmcsd_cmd));
cmd.cmd_code = SD_SEND_RELATIVE_ADDR;
cmd.arg = 0;
cmd.flags = RESP_R6 | CMD_BCR;
err = mmcsd_send_cmd(host, &cmd, 3);
if (err)
return err;
*rca = cmd.resp[0] >> 16;
return 0;
}
#define be32_to_cpu(x) ((uint32_t)( \
(((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \
(((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \
(((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \
(((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24)))
int32_t mmcsd_get_scr(struct mmcsd_card *card, uint32_t *scr)
{
int32_t err;
struct mmcsd_req req;
struct mmcsd_cmd cmd;
struct mmcsd_data data;
err = mmcsd_app_cmd(card->host, card);
if (err)
return err;
memset(&req, 0, sizeof(struct mmcsd_req));
memset(&cmd, 0, sizeof(struct mmcsd_cmd));
memset(&data, 0, sizeof(struct mmcsd_data));
req.cmd = &cmd;
req.data = &data;
cmd.cmd_code = SD_APP_SEND_SCR;
cmd.arg = 0;
cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC;
data.blksize = 8;
data.blks = 1;
data.flags = DATA_DIR_READ;
data.buf = scr;
mmcsd_set_data_timeout(&data, card);
mmcsd_send_request(card->host, &req);
if (cmd.err)
return cmd.err;
if (data.err)
return data.err;
scr[0] = be32_to_cpu(scr[0]);
scr[1] = be32_to_cpu(scr[1]);
return 0;
}
static int32_t mmcsd_sd_init_card(struct mmcsd_host *host,
uint32_t ocr)
{
struct mmcsd_card *card;
int32_t err;
uint32_t resp[4];
uint32_t max_data_rate;
mmcsd_go_idle(host);
/*
* If SD_SEND_IF_COND indicates an SD 2.0
* compliant card and we should set bit 30
* of the ocr to indicate that we can handle
* block-addressed SDHC cards.
*/
err = mmcsd_send_if_cond(host, ocr);
if (!err)
ocr |= 1 << 30;
err = mmcsd_send_app_op_cond(host, ocr, NULL);
if (err)
goto err;
if (controller_is_spi(host))
err = mmcsd_get_cid(host, resp);
else
err = mmcsd_all_get_cid(host, resp);
if (err)
goto err;
card = pvPortMalloc(sizeof(struct mmcsd_card));
if (!card)
{
TRACE_ERROR("malloc card failed!");
err = -ENOMEM;
goto err;
}
memset(card, 0, sizeof(struct mmcsd_card));
card->card_type = CARD_TYPE_SD;
card->host = host;
memcpy(card->resp_cid, resp, sizeof(card->resp_cid));
/*
* For native busses: get card RCA and quit open drain mode.
*/
if (!controller_is_spi(host))
{
err = mmcsd_get_card_addr(host, &card->rca);
if (err)
goto err1;
mmcsd_set_bus_mode(host, MMCSD_BUSMODE_PUSHPULL);
}
err = mmcsd_get_csd(card, card->resp_csd);
if (err)
goto err1;
err = mmcsd_parse_csd(card);
if (err)
goto err1;
if (!controller_is_spi(host))
{
err = mmcsd_select_card(card);
if (err)
goto err1;
}
err = mmcsd_get_scr(card, card->resp_scr);
if (err)
goto err1;
mmcsd_parse_scr(card);
if (controller_is_spi(host))
{
err = mmcsd_spi_use_crc(host, 1);
if (err)
goto err1;
}
/*
* change SD card to high-speed, only SD2.0 spec
*/
err = mmcsd_switch(card);
if (err)
goto err1;
/* set bus speed */
max_data_rate = (unsigned int)-1;
if (card->flags & CARD_FLAG_HIGHSPEED)
{
if (max_data_rate > card->hs_max_data_rate)
max_data_rate = card->hs_max_data_rate;
}
else if (max_data_rate > card->max_data_rate)
{
max_data_rate = card->max_data_rate;
}
mmcsd_set_clock(host, max_data_rate);
/*switch bus width*/
if ((host->flags & MMCSD_BUSWIDTH_4) &&
(card->scr.sd_bus_widths & SD_SCR_BUS_WIDTH_4))
{
err = mmcsd_app_set_bus_width(card, MMCSD_BUS_WIDTH_4);
if (err)
goto err1;
mmcsd_set_bus_width(host, MMCSD_BUS_WIDTH_4);
}
host->card = card;
return 0;
err1:
vPortFree(card);
err:
return err;
}
/*
* Starting point for SD card init.
*/
int32_t init_sd(struct mmcsd_host *host, uint32_t ocr)
{
int32_t err;
uint32_t current_ocr;
/*
* We need to get OCR a different way for SPI.
*/
if (controller_is_spi(host))
{
mmcsd_go_idle(host);
err = mmcsd_spi_read_ocr(host, 0, &ocr);
if (err)
goto err;
}
if (ocr & VDD_165_195)
{
TRACE_INFO(" SD card claims to support the "
"incompletely defined 'low voltage range'. This "
"will be ignored.");
ocr &= ~VDD_165_195;
}
current_ocr = mmcsd_select_voltage(host, ocr);
/*
* Can we support the voltage(s) of the card(s)?
*/
if (!current_ocr)
{
err = -1;
goto err;
}
/*
* Detect and init the card.
*/
err = mmcsd_sd_init_card(host, current_ocr);
if (err)
goto err;
mmcsd_host_unlock(host);
mmcsd_host_lock(host);
return 0;
err:
TRACE_DEBUG("init SD card failed!");
return err;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,191 @@
#include <stdio.h>
#include <string.h>
#include "FreeRTOS.h"
#include "board.h"
#include "sfud.h"
#include "sysinfo.h"
#include "sfud_data.h"
#include "pwm.h"
#ifndef WITH_MVVM
SfudData_t sfud_data_saved ={0};
#define SFUD_DATA_FLASH_OFFSET 0xfff000
SfudMileData_t sfud_mile_data ={0};
static uint32_t save_addr = 0;
static uint16_t User_data_index = 0;
#define SFUD_MILE_DATA_FLASH_OFFSET 0xffe000//0xffe000
#define MILE_FLASH_OFFSET 0x1000
void read_mileage(uint32_t trip_data,uint32_t total_data)
{
uint32_t i;
sfud_flash *sflash = sfud_get_device(0);
save_addr = SFUD_MILE_DATA_FLASH_OFFSET;
sfud_read(sflash, save_addr, sizeof(SfudMileData_t), (void*)&sfud_mile_data);
//生产时初始化为0
if(sfud_mile_data.TOTAL_mileage == 0XFFFFFFFF)
{
sfud_mile_data.TOTAL_mileage = 0;
sfud_mile_data.TRIP_mileage = 0;
User_data_index = 0;
sfud_write(sflash,save_addr,sizeof(SfudMileData_t),(void*)&sfud_mile_data);
printf("Init mileage\r\n");
}
else
{
for(i=0;i<256;i++) //数据区长度4k
{
sfud_read(sflash, save_addr, sizeof(SfudMileData_t), (void*)&sfud_mile_data);
if(sfud_mile_data.TOTAL_mileage == 0XFFFFFFFF)
{
break;
}
save_addr += 8;
}
save_addr -= 8;
sfud_read(sflash, save_addr, sizeof(SfudMileData_t), (void*)&sfud_mile_data);
if(sfud_mile_data.TRIP_mileage > sfud_mile_data.TOTAL_mileage)
sfud_mile_data.TRIP_mileage = sfud_mile_data.TOTAL_mileage;
Set_sys_trip_mileage(sfud_mile_data.TRIP_mileage);
Set_sys_total_mileage(sfud_mile_data.TOTAL_mileage);
User_data_index = i;
printf("Read mileage\r\n");
}
}
// void ReadMileageData(void){
// SfudMileData_t flash_data = {0};
// sfud_flash *sflash = sfud_get_device(0);
// if(sfud_read(sflash, SFUD_MILE_DATA_FLASH_OFFSET, sizeof(SfudMileData_t), (void*)&flash_data)==SFUD_SUCCESS){
// printf("sfud_read >>>>>>>>>>>>>>>>> OK .add = %08X , %08X , %08X .\r\n",SFUD_MILE_DATA_FLASH_OFFSET,flash_data.TOTAL_mileage,flash_data.TRIP_mileage);
// }
// }
void SaveMileageData(uint32_t trip_data,uint32_t total_data){
SfudMileData_t flash_data = {0};
sfud_flash *sflash = sfud_get_device(0);
uint8_t buff[sizeof(SfudMileData_t)];//定义buff用于保存结构体
memset(buff,0,sizeof(buff));//将buff内存清零
for(uint8_t i = 0;i<8;i++){
if(User_data_index < 255)
{
User_data_index++;
save_addr += 8;
}else{
User_data_index = 0;
save_addr = SFUD_MILE_DATA_FLASH_OFFSET;
sfud_erase(sflash, save_addr, MILE_FLASH_OFFSET);
printf("erase data\r\n");
}
((SfudMileData_t *)buff)->TRIP_mileage = trip_data;
((SfudMileData_t *)buff)->TOTAL_mileage = total_data;
printf("User_data_index = %d ,save_addr =%08X .\r\n",User_data_index,save_addr);
if (sfud_write(sflash,save_addr,sizeof(buff),buff)!=SFUD_SUCCESS){
printf("i = %d .save sfud mile error.\r\n",i);
}else{
break;
}
}
}
void Classify_SaveDataToFlash(SfudData_t user_data,uint8_t type){
uint8_t buff[sizeof(SfudData_t)];//定义buff用于保存结构体
memset(buff,0,sizeof(buff));//将buff内存清零
switch(type){
case 0:
((SfudData_t *)buff)->language = user_data.language;
break;
case 1:
((SfudData_t *)buff)->theme = user_data.theme;
break;
case 2:
((SfudData_t *)buff)->theme_state = user_data.theme_state;
break;
case 3:
((SfudData_t *)buff)->light_value = user_data.light_value;
break;
case 4:
((SfudData_t *)buff)->bt_on_off = user_data.bt_on_off;
break;
case 5:
strcpy(((SfudData_t *)buff)->f_mac_address,user_data.f_mac_address);
break;
case 6:
strcpy(((SfudData_t *)buff)->r_mac_address,user_data.r_mac_address);
break;
default:
break;
}
sfud_flash *sflash = sfud_get_device(0);
if (sfud_erase_write(sflash,SFUD_DATA_FLASH_OFFSET,sizeof(buff),buff)!=SFUD_SUCCESS){
printf("sfud data write error.\r\n");
}
}
void SaveDataToFlash(SfudData_t user_data){
uint8_t buff[sizeof(SfudData_t)];//定义buff用于保存结构体
memset(buff,0,sizeof(buff));//将buff内存清零
printf("**************save flash***********************\r\n");
// printf("user_data==> %d-%d-%d-%d-%d,%d",user_data.language,user_data.display_unit,user_data.theme
// ,user_data.theme_state,user_data.light_value,user_data.bt_on_off);
printf("mac:%02X%02X%02X%02X%02X%02X , %02X%02X%02X%02X%02X%02X end\r\n",user_data.f_mac_address[0],user_data.f_mac_address[1],user_data.f_mac_address[2]
,user_data.f_mac_address[3],user_data.f_mac_address[4],user_data.f_mac_address[5]
,user_data.r_mac_address[0],user_data.r_mac_address[1],user_data.r_mac_address[2]
,user_data.r_mac_address[3],user_data.r_mac_address[4],user_data.r_mac_address[5]);
// printf("data:%02X %02X%02X , %02X %02X%02X end\r\n"
// ,user_data.f_mac_address[6],user_data.f_mac_address[7],user_data.f_mac_address[8]
// ,user_data.r_mac_address[6],user_data.r_mac_address[7],user_data.r_mac_address[8]);
// printf("*************************************\r\n");
// printf("mile data: %02X,%02X end\r\n"
// ,user_data.maintenance_mileage,user_data.mileage_flag);
printf("*************************************\r\n");
if(user_data.light_value==0)
user_data.light_value=1;
else if(user_data.light_value>6)
user_data.light_value=5;
((SfudData_t *)buff)->factory_reset = 1;
((SfudData_t *)buff)->language = user_data.language;
((SfudData_t *)buff)->display_unit = user_data.display_unit;
((SfudData_t *)buff)->theme = user_data.theme;
((SfudData_t *)buff)->theme_state = user_data.theme_state;
((SfudData_t *)buff)->light_value = user_data.light_value;
((SfudData_t *)buff)->bt_on_off = user_data.bt_on_off;
//((SfudData_t *)buff)->trip_uint = user_data.trip_uint;
strcpy(((SfudData_t *)buff)->f_mac_address,user_data.f_mac_address);
strcpy(((SfudData_t *)buff)->r_mac_address,user_data.r_mac_address);
((SfudData_t *)buff)->maintenance_mileage = user_data.maintenance_mileage;
((SfudData_t *)buff)->mileage_flag = user_data.mileage_flag;
sfud_flash *sflash = sfud_get_device(0);
if (sfud_erase_write(sflash,SFUD_DATA_FLASH_OFFSET,sizeof(buff),buff)!=SFUD_SUCCESS){
printf("sfud data write error.\r\n");
}
}
void ReadDataToFlash(void){
sfud_flash *sflash = sfud_get_device(0);
sfud_read(sflash, SFUD_DATA_FLASH_OFFSET, sizeof(SfudData_t), (void*)&sfud_data_saved);
}
SfudData_t* userData_getSfudSaved(void)
{
/*printf("userData_getSfudSaved: %d-%d-%d-%d-%d-%d \r\n",sfud_data_saved.language,
sfud_data_saved.display_unit,sfud_data_saved.theme,sfud_data_saved.theme_state,
sfud_data_saved.light_value,sfud_data_saved.bt_on_off);*/
return &sfud_data_saved;
}
#endif /*WITH_MVVM*/

View File

@ -0,0 +1,152 @@
#include <string.h>
#include "FreeRTOS.h"
#include "chip.h"
#include "errno.h"
#define MAX_SPI_DEVICE_NUM 2
static struct spi_slave *spi_devs[MAX_SPI_DEVICE_NUM] = {NULL};
static int spi_devices_count = 0;
int spi_add_slave(struct spi_slave *slave)
{
if (spi_devices_count >= MAX_SPI_DEVICE_NUM)
return -1;
spi_devs[spi_devices_count++] = slave;
return 0;
}
struct spi_slave *spi_open(const char *spidev)
{
struct spi_slave *slave;
int i;
for (i = 0; i < spi_devices_count; i++) {
slave = spi_devs[i];
if (!strcmp(slave->name, spidev)) {
slave->open_count++;
if (slave->open_count == 1)
slave->xMutex = xSemaphoreCreateMutex();
return slave;
}
}
return NULL;
}
void spi_close(struct spi_slave *slave)
{
if (slave && --slave->open_count == 0)
vSemaphoreDelete(slave->xMutex);
}
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 result;
struct spi_message message = {0};
/* send data */
message.send_buf = send_buf;
message.recv_buf = NULL;
message.length = send_length;
message.cs_take = 1;
message.cs_release = 0;
message.next = NULL;
result = slave->xfer(slave, &message);
if (result < 0)
{
result = -EIO;
goto __exit;
}
/* recv data */
message.send_buf = NULL;
message.recv_buf = recv_buf;
message.length = recv_length;
message.cs_take = 0;
message.cs_release = 1;
message.next = NULL;
result = slave->xfer(slave, &message);
if (result < 0)
{
result = -EIO;
goto __exit;
}
result = ENOERR;
__exit:
return result;
}
int spi_transfer(struct spi_slave *slave, const void *send_buf,
void *recv_buf, size_t length)
{
int result;
struct spi_message message = {0};
configASSERT(slave != NULL);
xSemaphoreTake(slave->xMutex, portMAX_DELAY);
/* initial message */
message.send_buf = send_buf;
message.recv_buf = recv_buf;
message.length = length;
message.cs_take = 1;
message.cs_release = 1;
message.next = NULL;
/* transfer message */
result = slave->xfer(slave, &message);
if (result < 0)
{
result = -EIO;
goto __exit;
}
__exit:
xSemaphoreGive(slave->xMutex);
return result;
}
int spi_configure(struct spi_slave *slave, struct spi_configuration *cfg)
{
int ret;
configASSERT(slave && cfg);
xSemaphoreTake(slave->xMutex, portMAX_DELAY);
ret = slave->configure(slave, cfg);
xSemaphoreGive(slave->xMutex);
return ret;
}
int spi_recv(struct spi_slave *slave, void *recv_buf, size_t length)
{
return spi_transfer(slave, NULL, recv_buf, length);
}
int spi_send(struct spi_slave *slave, const void *send_buf, size_t length)
{
return spi_transfer(slave, send_buf, NULL, length);
}
void spi_init(void)
{
ecspi_init();
dwspi_init();
}

View File

@ -0,0 +1,366 @@
#include "chip.h"
void vSysctlConfigure(uint32_t regoffset, uint32_t bitoffset, uint32_t mask, uint32_t val)
{
uint32_t tmp = readl(REGS_SYSCTL_BASE + regoffset);
tmp &= ~(mask << bitoffset);
tmp |= val << bitoffset;
writel(tmp, REGS_SYSCTL_BASE + regoffset);
}
void sys_soft_reset (int reset_dev)
{
unsigned int mask;
volatile unsigned int* reg;
switch (reset_dev)
{
case softreset_imc:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 31;
break;
case softreset_usbphy:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 30;
break;
case softreset_ddr:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 29;
break;
case softreset_icu:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 28;
break;
case softreset_aes:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 27;
break;
case softreset_rcrt:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 26;
break;
case softreset_adc:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 25;
break;
case softreset_rtc:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 24;
break;
case softreset_i2s:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 23;
break;
case softreset_wdt:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 22;
break;
case softreset_pwm:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 21;
break;
case softreset_timer3:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 20;
break;
case softreset_timer2:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 19;
break;
case softreset_timer1:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 18;
break;
case softreset_timer0:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 17;
break;
case softreset_gpio:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 16;
break;
case softreset_uart3:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 15;
break;
case softreset_uart2:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 14;
break;
case softreset_uart1:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 13;
break;
case softreset_uart0:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 12;
break;
case softreset_i2c1:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 11;
break;
case softreset_i2c:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 10;
break;
case softreset_ssp1:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 9;
break;
case softreset_ssp:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 8;
break;
case softreset_pxp:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 7;
break;
case softreset_gpu:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 6;
break;
case softreset_itu:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 5;
break;
case softreset_card:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 4;
break;
case softreset_usb:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 3;
break;
case softreset_jpeg:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 2;
break;
case softreset_dma:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 1;
break;
case softreset_lcd:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 0;
break;
case softreset_can0:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x60));
mask = 0;
break;
case softreset_can1:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x60));
mask = 1;
break;
case softreset_h2xdma:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x60));
mask = 2;
break;
case softreset_h2xusb:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x60));
mask = 3;
break;
case softreset_mipi:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x60));
mask = 4;
break;
case softreset_usb_utmi:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x60));
mask = 5;
break;
case softreset_vpu:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x60));
mask = 6;
break;
case softreset_i2s1:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x60));
mask = 8;
break;
default:
printf ("illegal reset device (%d)\n", reset_dev);
return;
}
portENTER_CRITICAL();
*reg &= ~(1 << mask);
udelay (100);
*reg |= (1 << mask);
portEXIT_CRITICAL();
}
void sys_soft_reset_from_isr (int reset_dev)
{
unsigned int mask;
volatile unsigned int* reg;
switch (reset_dev)
{
case softreset_imc:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 31;
break;
case softreset_usbphy:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 30;
break;
case softreset_ddr:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 29;
break;
case softreset_icu:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 28;
break;
case softreset_aes:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 27;
break;
case softreset_rcrt:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 26;
break;
case softreset_adc:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 25;
break;
case softreset_rtc:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 24;
break;
case softreset_i2s:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 23;
break;
case softreset_wdt:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 22;
break;
case softreset_pwm:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 21;
break;
case softreset_timer3:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 20;
break;
case softreset_timer2:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 19;
break;
case softreset_timer1:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 18;
break;
case softreset_timer0:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 17;
break;
case softreset_gpio:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 16;
break;
case softreset_uart3:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 15;
break;
case softreset_uart2:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 14;
break;
case softreset_uart1:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 13;
break;
case softreset_uart0:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 12;
break;
case softreset_i2c1:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 11;
break;
case softreset_i2c:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 10;
break;
case softreset_ssp1:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 9;
break;
case softreset_ssp:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 8;
break;
case softreset_pxp:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 7;
break;
case softreset_gpu:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 6;
break;
case softreset_itu:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 5;
break;
case softreset_card:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 4;
break;
case softreset_usb:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 3;
break;
case softreset_jpeg:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 2;
break;
case softreset_dma:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 1;
break;
case softreset_lcd:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x5c));
mask = 0;
break;
case softreset_can0:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x60));
mask = 0;
break;
case softreset_can1:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x60));
mask = 1;
break;
case softreset_h2xdma:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x60));
mask = 2;
break;
case softreset_h2xusb:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x60));
mask = 3;
break;
case softreset_mipi:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x60));
mask = 4;
break;
case softreset_usb_utmi:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x60));
mask = 5;
break;
case softreset_vpu:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x60));
mask = 6;
break;
case softreset_i2s1:
reg = ((volatile unsigned int *)(REGS_SYSCTL_BASE+0x60));
mask = 8;
break;
default:
printf ("illegal reset device (%d)\n", reset_dev);
return;
}
*reg &= ~(1 << mask);
udelay (100);
*reg |= (1 << mask);
}

View File

@ -0,0 +1,148 @@
#include <stdint.h>
#include "amt630hv100.h"
#include "clock.h"
#include "timer.h"
#include "chip.h"
#define TIMER_PERIOD 1000000
#define TIMER_LOAD_VAL 0xFFFFFFFF
/* For convenience the high frequency timer increments a variable that is then
used as the time base for the run time stats. */
volatile uint32_t ulHighFrequencyTimerCounts = 0;
void vTimerInit(uint32_t id, int32_t inten, int32_t periodic, uint32_t rate)
{
uint32_t regbase = REGS_TIMER_BASE;
uint32_t ctrl = TIMER_CTRL_INT_MASK;
if (inten) ctrl &= ~TIMER_CTRL_INT_MASK;
if (periodic) ctrl |= TIMER_CTRL_PERIODIC;
writel(0, regbase + TIMER_CTRL(id));
writel(ulClkGetRate(CLK_TIMER) / rate, regbase + TIMER_LOAD_COUNT(id));
writel(ctrl, regbase + TIMER_CTRL(id));
}
void vTimerEnable(uint32_t id)
{
uint32_t regbase = REGS_TIMER_BASE;
writel(readl(regbase + TIMER_CTRL(id)) | TIMER_CTRL_ENABLE, regbase + TIMER_CTRL(id));
}
void vTimerDisable(uint32_t id)
{
uint32_t regbase = REGS_TIMER_BASE;
writel(readl(regbase + TIMER_CTRL(id)) & ~TIMER_CTRL_ENABLE, regbase + TIMER_CTRL(id));
}
void vTimerClrInt(uint32_t id)
{
uint32_t regbase = REGS_TIMER_BASE;
volatile uint32_t val;
val = readl(regbase + TIMER_EOI(id));
}
/*-----------------------------------------------------------*/
static void prvRunTimer_Handler( void *para )
{
vTimerClrInt((uint32_t)para);
ulHighFrequencyTimerCounts++;
}
void vInitialiseTimerForRunTimeState(void)
{
vTimerInit(TIMER_ID1, 1, 1, configTICK_RATE_HZ * 20);
request_irq(TIMER1_IRQn, 1, prvRunTimer_Handler, (void*)TIMER_ID1);
vTimerEnable(TIMER_ID1);
}
uint32_t ulGetRunTimeCountValue(void)
{
uint32_t regbase = REGS_TIMER_BASE;
return TIMER_LOAD_VAL - readl(regbase + TIMER_CURRENT_VAL(TIMER_ID1));
}
void vInitialiseTimerForDelay(void)
{
uint32_t regbase = REGS_TIMER_BASE;
writel(0, regbase + TIMER_CTRL(TIMER_ID2));
writel(TIMER_LOAD_VAL, regbase + TIMER_LOAD_COUNT(TIMER_ID2));
writel(TIMER_CTRL_INT_MASK | TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE,
regbase + TIMER_CTRL(TIMER_ID2));
}
void udelay(uint32_t usec)
{
uint32_t regbase = REGS_TIMER_BASE;
long tmo = usec * (ulClkGetRate(CLK_TIMER) / TIMER_PERIOD);
unsigned long last = readl(regbase + TIMER_CURRENT_VAL(TIMER_ID2));
unsigned long now;
while (tmo > 0) {
now = readl(regbase + TIMER_CURRENT_VAL(TIMER_ID2));
if (last >= now)
tmo -= last - now;
else
tmo -= last + (TIMER_LOAD_VAL - now);
last = now;
}
}
void mdelay(uint32_t msec)
{
udelay(msec * 1000);
}
void vTimerUdelay(uint32_t usec)
{
udelay(usec);
}
void vTimerMdelay(uint32_t msec)
{
vTimerUdelay(msec * 1000);
}
static unsigned long long timestamp;
static unsigned long lastdec;
uint32_t get_timer_masked(void)
{
uint32_t regbase = REGS_TIMER_BASE;
unsigned long now = readl(regbase + TIMER_CURRENT_VAL(TIMER_ID2));
if (lastdec >= now) { /* normal mode (non roll) */
/* normal mode */
timestamp += lastdec - now; /* move stamp fordward with absoulte diff ticks */
} else { /* we have overflow of the count down timer */
/* nts = ts + ld + (TLV - now)
* ts=old stamp, ld=time that passed before passing through -1
* (TLV-now) amount of time after passing though -1
* nts = new "advancing time stamp"...it could also roll and cause problems.
*/
timestamp += lastdec + (TIMER_LOAD_VAL - now);
}
lastdec = now;
return timestamp / (ulClkGetRate(CLK_TIMER) / TIMER_PERIOD);
}
uint32_t get_timer(uint32_t base)
{
uint32_t now = get_timer_masked();
if (now >= base) {
return now - base;
} else {
return 0xffffffff - base + now;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,415 @@
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <time.h>
#include "FreeRTOS.h"
#include "chip.h"
#include "board.h"
#include "serial.h"
#include "sysinfo.h"
#define BUFFER_LEN 500//26
/************************* 蓝牙协议 ****************************/
void TXCMD_Other_Set(unsigned char time_buffer[],uint8_t len);
//配置为GPIO
void UART3_Modification_Type(void){
#if 0
u32 val=0;
val = rSYS_PAD_CTRL02;
val &= ~(0x3<<24);
rSYS_PAD_CTRL02 = val;
#endif
vSysctlConfigure(SYS_PAD_CTRL02, 24, 0xf, 0);
}
//配置为UART 正常接收数据
void UART3_Type_regression(void){
#if 0
u32 val=0;
val = rSYS_PAD_CTRL02;
val &= ~(0x3<<24);
val |= ~(0x01<<24);
rSYS_PAD_CTRL02 = val;
#endif
vSysctlConfigure(SYS_PAD_CTRL02, 24, 0xf, 5);
}
#define UUP_PACKET_SIZE 128
#define UUP_MAX_FRAME_LEN (UUP_PACKET_SIZE + 16)
#define UUP_PACKET_A27_SIZE 4096
#define UUP_MAX_FRAME_A27_LEN (UUP_PACKET_A27_SIZE + 16)
#define UUP_RX_FRAME_NUM 16
#define BYTESPERPAGE 256
#define PAGESPERSECTORS 16
#define UUP_BUF_SIZE (BYTESPERPAGE * PAGESPERSECTORS)
static unsigned char uup_rx_buf[UUP_RX_FRAME_NUM][4096];
static unsigned char *uup_rx_ptr;
static int uup_rx_rev_len = 0;
static int uup_rx_head = 0;
static int uup_rx_tail = 0;
static int uup_rx_state = 0;
static int upgrade_state = 0;
static int uup_rx_data_len = 0;
static int timeout = 0;
unsigned char uart_time_request[13] = {0};
static uint8_t uart_tx_flag = 0;
static void protocol_uart_tx_thread(void *param)
{
UartPort_t *uap = param;
uint8_t uarttx[32] = "hello, i am amt630h";
//char* cmd = "AT\r\n";
for (;;)
{
if(uart_tx_flag){
if (uart_time_request[0] != 0 && uart_time_request[0] == 0xAA)
{
//printf("UART3 tx-->>> ");
for (uint8_t i = 0; i < 9; i++)
{
//printf("%02x ", uart_time_request[i]);
uarttx[i] = uart_time_request[i];
}
if(uart_time_request[1]==0x10){
for (uint8_t i = 9; i < 19; i++)
{
//printf("%02x ", uart_time_request[i]);
uarttx[i] = uart_time_request[i];
}
//printf("\r\n");
iUartWrite(uap, uarttx, 19, pdMS_TO_TICKS(100)); // 发送数据
uart_time_request[0] = 0;
}else{
//printf("\r\n");
iUartWrite(uap, uarttx, 9, pdMS_TO_TICKS(100)); // 发送数据
uart_time_request[0] = 0;
}
}else if(uart_time_request[0] != 0 && uart_time_request[0] == 0x7E){
//DEBUG_PRINT("UART3 tx-->>> ");
for (uint8_t i = 0; i < 8; i++)
{
//DEBUG_PRINT("%02x ", uart_time_request[i]);
uarttx[i] = uart_time_request[i];
}
//DEBUG_PRINT("\r\n");
iUartWrite(uap, uarttx, 8, pdMS_TO_TICKS(100)); // 发送数据
uart_time_request[0] = 0;
}else{
}
uart_tx_flag = 0;
}
vTaskDelay(50);
}
}
//计算数据校验和
static uint16_t calculate_cumulative_sum(uint8_t *buf)
{
uint32_t sum = 0;
uint8_t len, i;
len = buf[1];
for (i = 2; i < len + 1; i++)
{
sum += buf[i];
}
sum &= 0xFF;
return sum;
}
extern uint8_t uart3_flag;
static void protocol_uart_rx_thread(void *param)
{
UartPort_t *uap = xUartOpen(UART_BT_PORT);
////测试使用串口2
uint8_t uartrx[BUFFER_LEN];
int len;
int data_len =0;
int str_len =0;
int i;
uint8_t tlv_data_value[128] = {0};
unsigned char ota_request[8] = {0x7e,0x00,0x05,0x02,0x03,0x01,0x00,0x01};
uint32_t sum = 0;
uint8_t equipment_data = 0;
uint8_t mac_data = 0;
if (!uap)
{
//DEBUG_PRINT("open uart %d fail.\n", UART_BT_PORT);
vTaskDelete(NULL);
return;
}
vUartInit(uap, 115200, 0);
if (xTaskCreate(protocol_uart_tx_thread, "uartsend", configMINIMAL_STACK_SIZE, uap,
configMAX_PRIORITIES / 3, NULL) != pdPASS)
{
//DEBUG_PRINT("create uart tx demo task fail.\n");
vTaskDelete(NULL);
return;
}
for (;;)
{
len = iUartRead(uap, uartrx, BUFFER_LEN, pdMS_TO_TICKS(10));
if(uart3_flag){
if(len==0)
uart3_flag = 0;
else
printf("len!=0.\r\n");
}else if(Get_sys_power_on_self_test() != 150){
for(i=0;i<len;i++){
switch (upgrade_state) {
case 0:
if (uartrx[i] == 0xAA){
upgrade_state++;
tlv_data_value[str_len] = uartrx[i];
str_len++;
equipment_data = 0;
mac_data = 0;
}
break;
case 1:
if (uartrx[i] == 0x18){
tlv_data_value[str_len] = uartrx[i];
str_len++;
data_len = uartrx[i];
upgrade_state++;
}else if(uartrx[i] == 0x1b){
tlv_data_value[str_len] = uartrx[i];
str_len++;
data_len = uartrx[i];
upgrade_state++;
mac_data = 1;
}else if(uartrx[i] == 0x47){
tlv_data_value[str_len] = uartrx[i];
str_len++;
data_len = uartrx[i];
upgrade_state++;
equipment_data = 1;
}else
upgrade_state = 0;
break;
case 2:
tlv_data_value[str_len] = uartrx[i];
str_len++;
if(str_len > data_len+1){
upgrade_state++;
}
break;
case 3:
if (uartrx[i] == 0x0a){
sum = calculate_cumulative_sum(tlv_data_value);
if(sum != tlv_data_value[str_len-1]){
//printf("error.\r\n");
}else{
if(equipment_data){
device_data_analysis(tlv_data_value);
equipment_data = 0;
}else if(mac_data){
tire_pressure_data_analysis(tlv_data_value);
mac_data = 0;
}else
data_analysis(tlv_data_value);
}
// }else{
//DEBUG_PRINT("\nuartrx[i] = %x .\n",uartrx[i]);
}
upgrade_state=0;
str_len = 0;
data_len = 0;
break;
}
/*
switch (uup_rx_state) {
case 0:
if (uartrx[i] == 0x7e)
uup_rx_state++;
break;
case 1:
if (uartrx[i] == 0x05)
uup_rx_state++;
else
uup_rx_state = 0;
break;
case 2:
if (uartrx[i] == 0x02)
uup_rx_state++;
else
uup_rx_state = 0;
break;
case 3:
if (uartrx[i] == 0x03)
uup_rx_state++;
else
uup_rx_state = 0;
break;
case 4:
if (uartrx[i] == 0x01)
uup_rx_state++;
else
uup_rx_state = 0;
break;
case 5:
if (uartrx[i] == Get_sys_softwar_host())
uup_rx_state++;
else
uup_rx_state = 0;
break;
case 6:
if (uartrx[i] == Get_sys_softwar_order()){
if(Get_sys_veer_velocity()){
//DEBUG_PRINT("error ota sj. Speed present\n");
ota_request[1] = 0x01;
ota_request[6] = Get_sys_softwar_host();
ota_request[7] = Get_sys_softwar_order();
TXCMD_Other_Set(ota_request,8);
}else{
//DEBUG_PRINT("enter ota sj.\n");
Set_sys_power_on_self_test(150);
// extern uint8_t now_theme_state;
// now_theme_state = 5;
Set_sys_upgrade_Flag(1);//进入ota界面
ota_request[6] = Get_sys_softwar_host();
ota_request[7] = Get_sys_softwar_order();
vTaskDelay(100);
TXCMD_Other_Set(ota_request,8);
if(timeout)
timeout=0;
}
}
uup_rx_state = 0;
break;
}
}
}else{//升级逻辑
timeout ++;
for (i = 0; i < len; i++) {
switch (uup_rx_state) {
case 0:
if (uartrx[i] == 0x55) {
uup_rx_state++;
uup_rx_rev_len = 0;
uup_rx_ptr = &uup_rx_buf[uup_rx_head][0];
}
break;
case 1:
if (uartrx[i] == 0x81)
uup_rx_state++;
else
uup_rx_state = 0;
*uup_rx_ptr++ = uartrx[i];
break;
case 2:
if (uartrx[i] == 0xc6)
uup_rx_state++;
else
uup_rx_state = 0;
*uup_rx_ptr++ = uartrx[i];
break;
case 3:
uup_rx_data_len = uartrx[i];
//uup_rx_data_len = (uartrx[i]<<8);
uup_rx_state++;
*uup_rx_ptr++ = uartrx[i];
break;
case 4:
//uup_rx_data_len |= uartrx[i];
uup_rx_data_len = (uartrx[i]<<8) | uup_rx_data_len;
if((uup_rx_data_len > UUP_PACKET_A27_SIZE + 2)) { //4096 + 2
//DEBUG_PRINT("Invalid uup_rx_data_len %d\n", uup_rx_data_len);
uup_rx_state = 0;
} else {
uup_rx_state++;
*uup_rx_ptr++ = uartrx[i];
}
break;
case 5:
*uup_rx_ptr++ = uartrx[i];
if (++uup_rx_rev_len == uup_rx_data_len)
uup_rx_state++;
break;
case 6:
*uup_rx_ptr++ = uartrx[i];
uup_rx_head = (uup_rx_head + 1) % UUP_RX_FRAME_NUM;
uup_rx_state = 0;
break;
}
}
if (uup_rx_tail != uup_rx_head) {
unsigned char *buf;
unsigned char checksum = 0;
buf = &uup_rx_buf[uup_rx_tail][0];
//len = (buf[2]<<8)+buf[3];
len = buf[2];
len = buf[3]<<8 | len;
for (i = 0; i < len + 4; i++)
checksum ^= buf[i];
////DEBUG_PRINT("checksum = 0x%x , buf[len + 4] = 0x%x\n",checksum,buf[len + 4]);
if (checksum == buf[len + 4]) {
timeout =0;
// uup_ota_update(uap, buf + 4, len);
//DEBUG_PRINT("rev frame checksum err.\n");
}
uup_rx_tail = (uup_rx_tail + 1) % UUP_RX_FRAME_NUM;
}
if(timeout >= 3000){//超时退出升级 大约40s
//DEBUG_PRINT("exit ota sj.\n");
Set_sys_power_on_self_test(100);
Set_sys_upgrade_Flag(2);
//DEBUG_PRINT("UART3_Type_regression .\n");
extern void UART3_Type_regression(void);
UART3_Type_regression();
timeout = 0;
}
*/
}
}
}
}
int uart_communicates_with_bt(void)
{
/* Create a task to process uart rx data */
if (xTaskCreate(protocol_uart_rx_thread, "uart3rx", configMINIMAL_STACK_SIZE, NULL,
configMAX_PRIORITIES / 3, NULL) != pdPASS)
{
//printf("create uart rx demo task fail.\n");
return -1;
}
return 0;
}
void TXCMD_Other_Set(unsigned char time_buffer[],uint8_t len)
{
if(uart_tx_flag == 0)
uart_tx_flag = 1;
for (uint8_t i = 0; i < len; i++)
{
uart_time_request[i] = time_buffer[i];
}
}

View File

@ -0,0 +1,840 @@
#include "usb_os_adapter.h"
#include "trace.h"
#include <asm/dma-mapping.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include "core.h"
#include "hcd.h"
#include "ark_dwc2.h"
#include "semphr.h"
#include "timers.h"
#include "usbroothubdes.h"
#include "sysctl.h"
#include "board.h"
struct dwc2_host_data {
struct dwc2_hsotg *host;
struct usb_hcd hcd;
enum usb_device_speed host_speed;
int root_hub_devnum;
struct usb_host_endpoint hep_in[16];
struct usb_host_endpoint hep_out[16];
struct hc_driver *dw2_hc_driver;
List_t free_urb_list;
spinlock_t lock;
};
struct urb_user_ctx {
struct usb_device* dev;
struct usb_host_endpoint *hep;
unsigned long pipe;
void *buffer;
int length;
int num_iso_packets;
int interval;
int alloc_flag;
};
int dwc2_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
int dwc2_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
extern int dwc2_driver_init(struct dwc2_hsotg **dev, struct usb_hcd *hcd);
extern int dwc2_driver_uninit(struct dwc2_hsotg *hsotg);
extern struct hc_driver* dwc2_get_driver();
static int dwc_otg_submit_rh_msg(struct usb_device *dev,
unsigned long pipe, void *buffer, int txlen,
struct devrequest *cmd);
struct dwc2_host_data dwc2_host;
struct urb_user_ctx urb_user_handle[8];
void *alloc_urb_user_ctx()
{
int i;
struct urb_user_ctx* handle = NULL;
for (i = 0; i < 8; i++) {
handle = &urb_user_handle[i];
if (handle->alloc_flag == 0) {
handle->alloc_flag = 1;
break;
}
}
return handle;
}
void free_urb_user_ctx(void *ctx)
{
struct urb_user_ctx* handle = (struct urb_user_ctx*)ctx;
handle->alloc_flag = 0;
}
static void dwc2_host_complete_urb(struct urb *urb)
{
if (urb->status != 0) {
printf("#urb transfer err:%d\r\n", urb->status);
}
urb->dev->status &= ~USB_ST_NOT_PROC;
urb->dev->act_len = urb->actual_length;
//printf("actual_length:%d\r\n", urb->actual_length);
xQueueSendFromISR((QueueHandle_t)urb->queueHandle, NULL, 0);
}
static void usb_urb_release(struct urb *urb)
{
if (NULL == urb)
return;
spin_lock(&dwc2_host.lock);
list_add_tail(&urb->urb_list, &dwc2_host.free_urb_list);
spin_unlock(&dwc2_host.lock);
}
static struct urb *usb_urb_alloc(struct dwc2_host_data *ctx,
int iso_desc_count,
gfp_t mem_flags)
{
struct urb *urb = NULL;
QueueHandle_t complete;
u32 size = sizeof(*urb) + iso_desc_count *
sizeof(struct usb_iso_packet_descriptor);
ListItem_t *pxListItem = NULL;
int found = 0, flags;
spin_lock_irqsave(&ctx->lock, flags);
list_for_each_entry(pxListItem, urb, &ctx->free_urb_list) {
if (urb->number_of_packets == iso_desc_count) {
found = 1;
break;
}
}
if (found) {
void *queueHandle = urb->queueHandle;
list_del_init(&urb->urb_list);
spin_unlock_irqrestore(&ctx->lock, flags);
memset(urb, 0, sizeof(struct urb));
urb->number_of_packets = iso_desc_count;
INIT_LIST_ITEM(&urb->urb_list);
listSET_LIST_ITEM_OWNER(&urb->urb_list, urb);
urb->queueHandle = queueHandle;
xQueueReset(urb->queueHandle);
return urb;
}
spin_unlock_irqrestore(&ctx->lock, flags);
urb = (struct urb *)kzalloc(size, mem_flags);
if (urb) {
urb->number_of_packets = iso_desc_count;
INIT_LIST_ITEM(&urb->urb_list);
listSET_LIST_ITEM_OWNER(&urb->urb_list, urb);
complete = xQueueCreate(1, 0);
urb->queueHandle = complete;
}
return urb;
}
static void construct_urb(struct urb *urb, struct usb_host_endpoint *hep,
struct usb_device *dev, int endpoint_type,
unsigned long pipe, void *buffer, int len,
struct devrequest *setup, int interval)
{
int epnum = usb_pipeendpoint(pipe);
int is_in = usb_pipein(pipe);
INIT_LIST_HEAD(&hep->urb_list);
#ifndef NO_GNU
INIT_LIST_HEAD(&urb->urb_list);
#else
INIT_LIST_ITEM(&urb->urb_list);
urb->urb_list.pvOwner = (void *)urb;
#endif
urb->ep = hep;
urb->complete = dwc2_host_complete_urb;
urb->status = -EINPROGRESS;
urb->dev = dev;
urb->pipe = pipe;
urb->transfer_buffer = buffer;
urb->transfer_dma = (dma_addr_t)buffer;
urb->transfer_buffer_length = len;
urb->setup_packet = (unsigned char *)setup;
urb->setup_dma = (dma_addr_t)setup;
urb->transfer_flags &= ~(URB_DIR_MASK | URB_DMA_MAP_SINGLE |
URB_DMA_MAP_PAGE | URB_DMA_MAP_SG | URB_MAP_LOCAL |
URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL |
URB_DMA_SG_COMBINED);
urb->transfer_flags |= (is_in ? URB_DIR_IN : URB_DIR_OUT);
urb->ep->desc.wMaxPacketSize =
__cpu_to_le16(is_in ? dev->epmaxpacketin[epnum] :
dev->epmaxpacketout[epnum]);
urb->ep->desc.bmAttributes = endpoint_type;
urb->ep->desc.bEndpointAddress =
(is_in ? USB_DIR_IN : USB_DIR_OUT) | epnum;
urb->ep->desc.bInterval = interval;
}
static int submit_urb(struct usb_hcd *hcd, struct urb *urb)
{
int ret;
ret = dwc2_urb_enqueue(hcd, urb, 0);
if (ret < 0) {
printf("Failed to enqueue URB to controller ret=%d \r\n", ret);
return ret;
}
return ret;
}
static int _dwc2_submit_control_msg(struct dwc2_host_data *host,
struct usb_device *dev, unsigned long pipe,
void *buffer, int len, struct devrequest *setup, int timeout)
{
struct urb *urb = NULL;
struct usb_host_endpoint *hep = NULL;
int epnum = usb_pipeendpoint(pipe);
int is_in = usb_pipein(pipe);
int ret = 0;
if (epnum > 8 || epnum < 0)
return -EINVAL;
if (is_in) {
hep = &host->hep_in[epnum];
} else {
hep = &host->hep_out[epnum];
}
urb = usb_urb_alloc(host, 0, IRQ_NONE);
if (urb == NULL)
return -ENOMEM;
construct_urb(urb, hep, dev, USB_ENDPOINT_XFER_CONTROL,
pipe, buffer, len, setup, 0);
/* Fix speed for non hub-attached devices */
if (!usb_dev_get_parent(dev))
dev->speed = host->host_speed;
//unsigned char *a = urb->setup_packet;
//if (a)
//printf("setup-->%02x %02x %02x %02x %02x %02x %02x %02x\r\n", a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
ret = submit_urb(&host->hcd, urb);
if (ret < 0) {
printf("%s:%d\r\n", __func__, __LINE__);
//dwc2_urb_dequeue(&host->hcd, urb, 0);
//printf("%s:%d\r\n", __func__, __LINE__);
goto exit;
}
ret = xQueueReceive((QueueHandle_t)urb->queueHandle, NULL, timeout);
if (ret != pdTRUE || 0 != urb->status) {//timeout
printf("%s:%d\r\n", __func__, __LINE__);
dwc2_urb_dequeue(&host->hcd, urb, 0);
printf("%s:%d\r\n", __func__, __LINE__);
if (0 != urb->status)
printf("usb control urb error:%d\r\n", urb->status);
ret = urb->status;
} else {
ret = urb->actual_length;
}
exit:
usb_urb_release(urb);
return ret;
}
int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len, int *actual_length, int timeout)
{
struct urb *urb = NULL;
struct usb_host_endpoint *hep = NULL;
int epnum = usb_pipeendpoint(pipe);
int is_in = usb_pipein(pipe);
int ret = 0;
struct dwc2_host_data *host = &dwc2_host;
if (epnum > 8 || epnum < 0)
return -EINVAL;
if (is_in) {
hep = &host->hep_in[epnum];
} else {
hep = &host->hep_out[epnum];
}
urb = usb_urb_alloc(host, 0, IRQ_NONE);
if (urb == NULL)
return -ENOMEM;
construct_urb(urb, hep, dev, USB_ENDPOINT_XFER_BULK,
pipe, buffer, transfer_len, NULL, 0);
ret = submit_urb(&host->hcd, urb);
if (ret < 0) {
printf("%s:%d\r\n", __func__, __LINE__);
//dwc2_urb_dequeue(&host->hcd, urb, 0);
//printf("%s:%d\r\n", __func__, __LINE__);
goto exit;
}
ret = xQueueReceive((QueueHandle_t)urb->queueHandle, NULL, timeout);
if (ret != pdTRUE || 0 != urb->status) {//timeout
printf("%s:%d\r\n", __func__, __LINE__);
dwc2_urb_dequeue(&host->hcd, urb, 0);
printf("%s:%d\r\n", __func__, __LINE__);
if (actual_length)
*actual_length = 0;
if (0 != urb->status)
printf("usb bulk urb error:%d\r\n", urb->status);
ret = urb->status;
} else {
if (actual_length)
*actual_length = urb->actual_length;
}
exit:
usb_urb_release(urb);
return ret;
}
static int _dwc2_submit_int_msg(struct dwc2_host_data *host, struct usb_device *dev, unsigned long pipe, void *buffer, int len, int interval, int timeout)
{
struct urb *urb = NULL;
struct usb_host_endpoint *hep = NULL;
int epnum = usb_pipeendpoint(pipe);
int is_in = usb_pipein(pipe);
int ret = 0;
if (epnum > 8 || epnum < 0)
return -EINVAL;
if (is_in) {
hep = &host->hep_in[epnum];
} else {
hep = &host->hep_out[epnum];
}
urb = usb_urb_alloc(host, 0, IRQ_NONE);
if (urb == NULL)
return -ENOMEM;
construct_urb(urb, hep, dev, USB_ENDPOINT_XFER_INT,
pipe, buffer, len, NULL, interval);
ret = submit_urb(&host->hcd, urb);
if (ret < 0) {
dwc2_urb_dequeue(&host->hcd, urb, 0);
goto exit;
}
ret = xQueueReceive((QueueHandle_t)urb->queueHandle, NULL, timeout);
if (ret != pdTRUE) {//timeout
dwc2_urb_dequeue(&host->hcd, urb, 0);
}
exit:
usb_urb_release(urb);
return ret;
}
#if 0
static int _dwc2_reset_root_port(struct dwc2_host_data *host,
struct usb_device *dev)
{
mdelay(50);
host->host_speed = USB_SPEED_HIGH;
mdelay((host->host_speed == USB_SPEED_LOW) ? 200 : 50);
return 0;
}
#endif
void usb_reset_endpoint()
{
int i;
struct dwc2_host_data *host = &dwc2_host;
if ((NULL == host->dw2_hc_driver) || (NULL == host->dw2_hc_driver->endpoint_reset))
return;
for (i = 0; i < 16; i++) {
host->dw2_hc_driver->endpoint_reset(&(host->hcd), &host->hep_in[i]);
host->dw2_hc_driver->endpoint_reset(&(host->hcd), &host->hep_out[i]);
}
}
void usb_disable_endpoint()
{
int i;
struct dwc2_host_data *host = &dwc2_host;
if ((NULL == host->dw2_hc_driver) || (NULL == host->dw2_hc_driver->endpoint_disable))
return;
for (i = 0; i < 16; i++) {
host->dw2_hc_driver->endpoint_disable(&(host->hcd), &host->hep_in[i]);
host->dw2_hc_driver->endpoint_disable(&(host->hcd), &host->hep_out[i]);
}
}
void reset_usb_phy()
{
vSysctlConfigure(SYS_SOFT_RST, 30, 1, 0);//phy reset
mdelay(10);
vSysctlConfigure(SYS_SOFT_RST, 30, 1, 1);//phy reset
}
void usb_sysctrl_init()
{
vSysctlConfigure(SYS_ANA_CFG, 8, 0xff, 4);
vSysctlConfigure(SYS_SOFT_RST, 30, 1, 0);//phy reset
vSysctlConfigure(SYS_SOFT_RST, 3, 1, 0);
vSysctlConfigure(SYS_SOFT1_RST, 5, 1, 0);
mdelay(10);
vSysctlConfigure(SYS_SOFT_RST, 30, 1, 1);//phy reset
vSysctlConfigure(SYS_SOFT_RST, 3, 1, 1);
vSysctlConfigure(SYS_SOFT1_RST, 5, 1, 1);
if (!get_usb_mode())
vSysctlConfigure(SYS_ANA_CFG, 24, 3, 1);// usb host
else
vSysctlConfigure(SYS_ANA_CFG, 24, 3, 3);// usb dev
mdelay(10);
}
int hub_status_data(char buf[8])
{
int ret = 1;
struct dwc2_host_data *host = &dwc2_host;
//printf("prvUsbPortScanTimerCallback\r\n");
ret = host->dw2_hc_driver->hub_status_data(&(host->hcd), buf);
if (ret != 0) {
//printf("state:%d usb state changed now!\r\n", buf[0]);
}
return ret;
}
void usb_dwc2_lowlevel_restart()
{
struct dwc2_host_data *host = &dwc2_host;
if (host->dw2_hc_driver && host->dw2_hc_driver->stop) {
host->dw2_hc_driver->stop(&(host->hcd));
}
msleep(50);
if (host->dw2_hc_driver && host->dw2_hc_driver->start) {
host->dw2_hc_driver->start(&(host->hcd));
}
}
int usb_dwc2_reset(int inIrq, int isDev)
{
struct dwc2_hsotg *hsotg = dwc2_host.host;
struct wq_msg *pmsg = &hsotg->xmsg;
if (isDev)
pmsg->id = OTG_WQ_MSG_ID_DEV_RESET;
else
pmsg->id = OTG_WQ_MSG_ID_HOST_RESET;
pmsg->delay = 50;
if (inIrq) {
xQueueSendFromISR(hsotg->wq_otg, (void*)pmsg, 0);
} else {
xQueueSend(hsotg->wq_otg, (void*)pmsg, 0);
}
return 0;
}
//#define mainTIMER_SCAN_FREQUENCY_MS pdMS_TO_TICKS( 1000UL )
int usb_dwc2_lowlevel_init()
{
struct dwc2_host_data *host = &dwc2_host;
int ret;
INIT_LIST_HEAD(&host->free_urb_list);
spin_lock_init(&host->lock);
ret = dwc2_driver_init(&host->host, &(host->hcd));
if (!host->host) {
printf("MUSB host is not registered\n");
return -ENODEV;
}
host->dw2_hc_driver = dwc2_get_driver();
return ret;
}
int usb_dwc2_lowlevel_uninit()
{
if (!dwc2_host.host) {
printf("MUSB host is not registered\n");
return -ENODEV;
}
dwc2_driver_uninit(dwc2_host.host);
return 0;
}
int submit_control_msg(struct usb_device *dev, unsigned long pipe,
void *buffer, int length, struct devrequest *setup, int timeout)
{
if (dev->parent == NULL) {
return dwc_otg_submit_rh_msg(dev, pipe, buffer, length, setup);
} else {
return _dwc2_submit_control_msg(&dwc2_host, dev, pipe, buffer, length, setup, timeout);
}
}
int submit_int_msg(struct usb_device *dev, unsigned long pipe,
void *buffer, int length, int interval)
{
return _dwc2_submit_int_msg(&dwc2_host, dev, pipe, buffer, length, interval, 0);
}
static void construct_iso_urb(struct urb *urb, struct usb_host_endpoint *hep,
struct usb_device *dev, int endpoint_type,
unsigned long pipe, void *buffer, int len,
int num_iso_packets, int interval)
{
int epnum = usb_pipeendpoint(pipe);
int is_in = usb_pipein(pipe);
int i;
int psize = 512;
INIT_LIST_HEAD(&hep->urb_list);
#ifndef NO_GNU
INIT_LIST_HEAD(&urb->urb_list);
#else
INIT_LIST_ITEM(&urb->urb_list);
urb->urb_list.pvOwner = (void *)urb;
#endif
urb->ep = hep;
urb->complete = dwc2_host_complete_urb;
urb->status = -EINPROGRESS;
urb->dev = dev;
urb->pipe = pipe;
urb->transfer_buffer = buffer;
urb->transfer_dma = (dma_addr_t)buffer;
urb->transfer_buffer_length = len;
urb->transfer_flags &= ~(URB_DIR_MASK | URB_DMA_MAP_SINGLE |
URB_DMA_MAP_PAGE | URB_DMA_MAP_SG | URB_MAP_LOCAL |
URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL |
URB_DMA_SG_COMBINED);
urb->transfer_flags |= (is_in ? URB_DIR_IN : URB_DIR_OUT);
urb->ep->desc.wMaxPacketSize =
__cpu_to_le16(is_in ? dev->epmaxpacketin[epnum] :
dev->epmaxpacketout[epnum]);
urb->ep->desc.bmAttributes = endpoint_type;
urb->ep->desc.bEndpointAddress =
(is_in ? USB_DIR_IN : USB_DIR_OUT) | epnum;
urb->ep->desc.bInterval = interval;
if (num_iso_packets > 0)
psize = len / num_iso_packets;
for (i = 0; i < num_iso_packets; ++i) {
urb->iso_frame_desc[i].offset = i * psize;
urb->iso_frame_desc[i].length = psize;
}
}
int submit_iso_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len, int *actual_length, int timeout)
{
struct urb *urb = NULL;
struct usb_host_endpoint *hep = NULL;
int epnum = usb_pipeendpoint(pipe);
int is_in = usb_pipein(pipe);
int ret = 0;
struct dwc2_host_data *host = &dwc2_host;
int num_iso_packets = 1;
if (epnum > 8 || epnum < 0)
return -EINVAL;
if (is_in) {
hep = &host->hep_in[epnum];
} else {
hep = &host->hep_out[epnum];
}
urb = usb_urb_alloc(host, num_iso_packets, IRQ_NONE);
if (urb == NULL)
return -ENOMEM;
construct_iso_urb(urb, hep, dev, USB_ENDPOINT_XFER_BULK,
pipe, buffer, transfer_len, num_iso_packets, 0);
ret = submit_urb(&host->hcd, urb);
if (ret < 0) {
dwc2_urb_dequeue(&host->hcd, urb, 0);
if (actual_length)
*actual_length = 0;
goto exit;
}
ret = xQueueReceive((QueueHandle_t)urb->queueHandle, NULL, timeout);
if (ret != pdTRUE || 0 != urb->status) {
dwc2_urb_dequeue(&host->hcd, urb, 0);
if (actual_length)
*actual_length = 0;
if (0 != urb->status)
printf("usb iso urb error:%d\r\n", urb->status);
ret = urb->status;
} else {
if (actual_length) {
int i, tmp_len = 0;
for (i = 0; i < urb->number_of_packets; i++) {
tmp_len += urb->iso_frame_desc[i].actual_length;
}
*actual_length = tmp_len;
}
}
exit:
usb_urb_release(urb);
return ret;
}
/*
* DWC2 to USB API interface
*/
/* Direction: In ; Request: Status */
static int dwc_otg_submit_rh_msg_in_status(struct usb_device *dev, void *buffer,
int txlen, struct devrequest *cmd)
{
int len = 0;
int stat = 0;
switch (cmd->requesttype & ~USB_DIR_IN) {
case 0:
*(uint16_t *)buffer = cpu_to_le16(1);
len = 2;
break;
case USB_RECIP_INTERFACE:
case USB_RECIP_ENDPOINT:
*(uint16_t *)buffer = cpu_to_le16(0);
len = 2;
break;
case USB_TYPE_CLASS:
*(uint32_t *)buffer = cpu_to_le32(0);
len = 4;
break;
case USB_RECIP_OTHER | USB_TYPE_CLASS:
len = 4;
stat = dwc2_host.dw2_hc_driver->hub_control(&dwc2_host.hcd, (cmd->requesttype << 8) | (cmd->request),
cmd->value, cmd->index, (char*)buffer, len);
break;
default:
//puts("unsupported root hub command\n");
stat = USB_ST_STALLED;
}
dev->act_len = min(len, txlen);
dev->status = stat;
return stat;
}
/* Direction: In ; Request: Descriptor */
/* roothub.a masks */
#define RH_A_NDP (0xff << 0) /* number of downstream ports */
#define RH_A_PSM (1 << 8) /* power switching mode */
#define RH_A_NPS (1 << 9) /* no power switching */
#define RH_A_DT (1 << 10) /* device type (mbz) */
#define RH_A_OCPM (1 << 11) /* over current protection mode */
#define RH_A_NOCP (1 << 12) /* no over current protection */
#define RH_A_POTPGT (0xffUL << 24) /* power on to power good time */
/* roothub.b masks */
#define RH_B_DR 0x0000ffff /* device removable flags */
#define RH_B_PPCM 0xffff0000 /* port power control mask */
static int dwc_otg_submit_rh_msg_in_descriptor(struct usb_device *dev,
void *buffer, int txlen,
struct devrequest *cmd)
{
unsigned char data[32];
uint32_t dsc;
int len = 0;
int stat = 0;
uint16_t wValue = cpu_to_le16(cmd->value);
uint16_t wLength = cpu_to_le16(cmd->length);
switch (cmd->requesttype & ~USB_DIR_IN) {
case 0:
{
switch (wValue & 0xff00) {
case 0x0100: /* device descriptor */
len = min3(txlen, (int)sizeof(root_hub_dev_des), (int)wLength);
memcpy(buffer, root_hub_dev_des, len);
break;
case 0x0200: /* configuration descriptor */
len = min3(txlen, (int)sizeof(root_hub_config_des), (int)wLength);
memcpy(buffer, root_hub_config_des, len);
break;
case 0x0300: /* string descriptors */
switch (wValue & 0xff) {
case 0x00:
len = min3(txlen, (int)sizeof(root_hub_str_index0),
(int)wLength);
memcpy(buffer, root_hub_str_index0, len);
break;
case 0x01:
len = min3(txlen, (int)sizeof(root_hub_str_index1),
(int)wLength);
memcpy(buffer, root_hub_str_index1, len);
break;
}
break;
default:
stat = USB_ST_STALLED;
}
break;
}
case USB_TYPE_CLASS:
/* Root port config, set 1 port and nothing else. */
dsc = 0x00000001;
data[0] = 9; /* min length; */
data[1] = 0x29;
data[2] = dsc & RH_A_NDP;
data[3] = 0;
if (dsc & RH_A_PSM)
data[3] |= 0x1;
if (dsc & RH_A_NOCP)
data[3] |= 0x10;
else if (dsc & RH_A_OCPM)
data[3] |= 0x8;
/* corresponds to data[4-7] */
data[5] = (dsc & RH_A_POTPGT) >> 24;
data[7] = dsc & RH_B_DR;
if (data[2] < 7) {
data[8] = 0xff;
} else {
data[0] += 2;
data[8] = (dsc & RH_B_DR) >> 8;
data[9] = 0xff;
data[10] = data[9];
}
len = min3(txlen, (int)data[0], (int)wLength);
memcpy(buffer, data, len);
break;
default:
//puts("unsupported root hub command\n");
stat = USB_ST_STALLED;
}
dev->act_len = min(len, txlen);
dev->status = stat;
return stat;
}
/* Direction: In ; Request: Configuration */
static int dwc_otg_submit_rh_msg_in_configuration(struct usb_device *dev,
void *buffer, int txlen,
struct devrequest *cmd)
{
int len = 0;
int stat = 0;
switch (cmd->requesttype & ~USB_DIR_IN) {
case 0:
*(uint8_t *)buffer = 0x01;
len = 1;
break;
default:
//puts("unsupported root hub command\n");
stat = USB_ST_STALLED;
}
dev->act_len = min(len, txlen);
dev->status = stat;
return stat;
}
/* Direction: In */
static int dwc_otg_submit_rh_msg_in(
struct usb_device *dev, void *buffer,
int txlen, struct devrequest *cmd)
{
switch (cmd->request) {
case USB_REQ_GET_STATUS:
return dwc_otg_submit_rh_msg_in_status(dev, buffer,
txlen, cmd);
case USB_REQ_GET_DESCRIPTOR:
return dwc_otg_submit_rh_msg_in_descriptor(dev, buffer,
txlen, cmd);
case USB_REQ_GET_CONFIGURATION:
return dwc_otg_submit_rh_msg_in_configuration(dev, buffer,
txlen, cmd);
default:
//puts("unsupported root hub command\n");
return USB_ST_STALLED;
}
}
/* Direction: Out */
static int dwc_otg_submit_rh_msg_out(
struct usb_device *dev,
void *buffer, int txlen,
struct devrequest *cmd)
{
int len = 0;
int stat = 0;
uint16_t bmrtype_breq = cmd->requesttype | (cmd->request << 8);
uint16_t wValue = cpu_to_le16(cmd->value);
switch (bmrtype_breq & ~USB_DIR_IN) {
case (USB_REQ_CLEAR_FEATURE << 8) | USB_RECIP_ENDPOINT:
case (USB_REQ_CLEAR_FEATURE << 8) | USB_TYPE_CLASS:
break;
case (USB_REQ_CLEAR_FEATURE << 8) | USB_RECIP_OTHER | USB_TYPE_CLASS:
case (USB_REQ_SET_FEATURE << 8) | USB_RECIP_OTHER | USB_TYPE_CLASS:
dwc2_host.dw2_hc_driver->hub_control(&dwc2_host.hcd, (cmd->requesttype << 8) | (cmd->request),
cmd->value, cmd->index, (char*)buffer, txlen);
break;
case (USB_REQ_SET_ADDRESS << 8):
dwc2_host.root_hub_devnum = wValue;
dwc2_host.dw2_hc_driver->hub_control(&dwc2_host.hcd, (cmd->requesttype << 8) | (cmd->request),
cmd->value, cmd->index, (char*)buffer, txlen);
break;
case (USB_REQ_SET_CONFIGURATION << 8):
break;
default:
//puts("unsupported root hub command\n");
stat = USB_ST_STALLED;
}
len = min(len, txlen);
dev->act_len = len;
dev->status = stat;
return stat;
}
static int dwc_otg_submit_rh_msg(struct usb_device *dev,
unsigned long pipe, void *buffer, int txlen,
struct devrequest *cmd)
{
int stat = 0;
if (usb_pipeint(pipe)) {
//puts("Root-Hub submit IRQ: NOT implemented\n");
return 0;
}
if (cmd->requesttype & USB_DIR_IN)
stat = dwc_otg_submit_rh_msg_in(dev, buffer, txlen, cmd);
else
stat = dwc_otg_submit_rh_msg_out(dev, buffer, txlen, cmd);
stat = dev->act_len;
return stat;
}

View File

@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* MUSB OTG driver u-boot specific functions
*
* Copyright © 2015 Hans de Goede <hdegoede@redhat.com>
*/
#ifndef __ARK_USB_DWC2_H__
#define __ARK_USB_DWC2_H__
int usb_dwc2_lowlevel_init();
int usb_dwc2_lowlevel_uninit();
void usb_sysctrl_init();
void reset_usb_phy();
void usb_disable_endpoint();
void usb_reset_endpoint();
void usb_dwc2_lowlevel_restart();
int usb_dwc2_reset(int inIrq, int isDev);
#endif

View File

@ -0,0 +1,843 @@
/*
* core.c - DesignWare HS OTG Controller common routines
*
* Copyright (C) 2004-2013 Synopsys, Inc.
*
* 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,
* without modification.
* 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. The names of the above-listed copyright holders may not be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any
* later version.
*
* 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.
*/
/*
* The Core code provides basic services for accessing and managing the
* DWC_otg hardware. These services are used by both the Host Controller
* Driver and the Peripheral Controller Driver.
*/
#define VERBOSE_DEBUG
#include "usb_os_adapter.h"
#include "trace.h"
#include <asm/dma-mapping.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include "core.h"
#include "hcd.h"
/**
* dwc2_backup_global_registers() - Backup global controller registers.
* When suspending usb bus, registers needs to be backuped
* if controller power is disabled once suspended.
*
* @hsotg: Programming view of the DWC_otg controller
*/
static int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg)
{
struct dwc2_gregs_backup *gr;
int i;
/* Backup global regs */
gr = &hsotg->gr_backup;
gr->gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
gr->gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
gr->gahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
gr->gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
gr->grxfsiz = dwc2_readl(hsotg->regs + GRXFSIZ);
gr->gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ);
gr->hptxfsiz = dwc2_readl(hsotg->regs + HPTXFSIZ);
gr->gdfifocfg = dwc2_readl(hsotg->regs + GDFIFOCFG);
for (i = 0; i < MAX_EPS_CHANNELS; i++)
gr->dtxfsiz[i] = dwc2_readl(hsotg->regs + DPTXFSIZN(i));
gr->valid = true;
return 0;
}
/**
* dwc2_restore_global_registers() - Restore controller global registers.
* When resuming usb bus, device registers needs to be restored
* if controller power were disabled.
*
* @hsotg: Programming view of the DWC_otg controller
*/
static int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg)
{
struct dwc2_gregs_backup *gr;
int i;
dev_dbg(hsotg->dev, "%s\n", __func__);
/* Restore global regs */
gr = &hsotg->gr_backup;
if (!gr->valid) {
dev_err(hsotg->dev, "%s: no global registers to restore\n",
__func__);
return -EINVAL;
}
gr->valid = false;
dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);
dwc2_writel(gr->gotgctl, hsotg->regs + GOTGCTL);
dwc2_writel(gr->gintmsk, hsotg->regs + GINTMSK);
dwc2_writel(gr->gusbcfg, hsotg->regs + GUSBCFG);
dwc2_writel(gr->gahbcfg, hsotg->regs + GAHBCFG);
dwc2_writel(gr->grxfsiz, hsotg->regs + GRXFSIZ);
dwc2_writel(gr->gnptxfsiz, hsotg->regs + GNPTXFSIZ);
dwc2_writel(gr->hptxfsiz, hsotg->regs + HPTXFSIZ);
dwc2_writel(gr->gdfifocfg, hsotg->regs + GDFIFOCFG);
for (i = 0; i < MAX_EPS_CHANNELS; i++)
dwc2_writel(gr->dtxfsiz[i], hsotg->regs + DPTXFSIZN(i));
return 0;
}
/**
* dwc2_exit_hibernation() - Exit controller from Partial Power Down.
*
* @hsotg: Programming view of the DWC_otg controller
* @restore: Controller registers need to be restored
*/
int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore)
{
u32 pcgcctl;
int ret = 0;
if (!hsotg->params.hibernation)
return -ENOTSUPP;
pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
pcgcctl &= ~PCGCTL_STOPPCLK;
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
pcgcctl &= ~PCGCTL_PWRCLMP;
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
pcgcctl &= ~PCGCTL_RSTPDWNMODULE;
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
udelay(100);
if (restore) {
ret = dwc2_restore_global_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to restore registers\n",
__func__);
return ret;
}
if (dwc2_is_host_mode(hsotg)) {
ret = dwc2_restore_host_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to restore host registers\n",
__func__);
return ret;
}
} else {
ret = dwc2_restore_device_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to restore device registers\n",
__func__);
return ret;
}
}
}
return ret;
}
/**
* dwc2_enter_hibernation() - Put controller in Partial Power Down.
*
* @hsotg: Programming view of the DWC_otg controller
*/
int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg)
{
u32 pcgcctl;
int ret = 0;
if (!hsotg->params.hibernation)
return -ENOTSUPP;
/* Backup all registers */
ret = dwc2_backup_global_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to backup global registers\n",
__func__);
return ret;
}
if (dwc2_is_host_mode(hsotg)) {
ret = dwc2_backup_host_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to backup host registers\n",
__func__);
return ret;
}
} else {
ret = dwc2_backup_device_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to backup device registers\n",
__func__);
return ret;
}
}
/*
* Clear any pending interrupts since dwc2 will not be able to
* clear them after entering hibernation.
*/
dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);
/* Put the controller in low power state */
pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
pcgcctl |= PCGCTL_PWRCLMP;
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
udelay(20);
pcgcctl |= PCGCTL_RSTPDWNMODULE;
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
udelay(20);
pcgcctl |= PCGCTL_STOPPCLK;
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
return ret;
}
/**
* dwc2_wait_for_mode() - Waits for the controller mode.
* @hsotg: Programming view of the DWC_otg controller.
* @host_mode: If true, waits for host mode, otherwise device mode.
*/
static void dwc2_wait_for_mode(struct dwc2_hsotg *hsotg,
bool host_mode)
{
uint32_t tick = xTaskGetTickCount();
unsigned int timeout = 110;//ms
dev_vdbg(hsotg->dev, "Waiting for %s mode\n",
host_mode ? "host" : "device");
//timeout = tick + configTICK_RATE_HZ / 10;
timeout += tick;
while (1) {
__s64 ms;
if (dwc2_is_host_mode(hsotg) == host_mode) {
dev_vdbg(hsotg->dev, "%s mode set\n",
host_mode ? "Host" : "Device");
break;
}
ms = (__s64)xTaskGetTickCount();
if (ms >= (__s64)timeout) {
dev_warn(hsotg->dev, "%s: Couldn't set %s mode\n",
__func__, host_mode ? "host" : "device");
break;
}
vTaskDelay(2000 / portTICK_RATE_MS);
}
}
/**
* dwc2_iddig_filter_enabled() - Returns true if the IDDIG debounce
* filter is enabled.
*/
static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg)
{
u32 gsnpsid;
u32 ghwcfg4;
if (!dwc2_hw_is_otg(hsotg))
return false;
/* Check if core configuration includes the IDDIG filter. */
ghwcfg4 = dwc2_readl(hsotg->regs + GHWCFG4);
if (!(ghwcfg4 & GHWCFG4_IDDIG_FILT_EN))
return false;
/*
* Check if the IDDIG debounce filter is bypassed. Available
* in core version >= 3.10a.
*/
gsnpsid = dwc2_readl(hsotg->regs + GSNPSID);
if (gsnpsid >= DWC2_CORE_REV_3_10a) {
u32 gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
if (gotgctl & GOTGCTL_DBNCE_FLTR_BYPASS)
return false;
}
return true;
}
/*
* Do core a soft reset of the core. Be careful with this because it
* resets all the internal state machines of the core.
*/
int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
{
u32 greset;
int count = 0;
bool wait_for_host_mode = false;
dev_vdbg(hsotg->dev, "%s()\n", __func__);
/*
* If the current mode is host, either due to the force mode
* bit being set (which persists after core reset) or the
* connector id pin, a core soft reset will temporarily reset
* the mode to device. A delay from the IDDIG debounce filter
* will occur before going back to host mode.
*
* Determine whether we will go back into host mode after a
* reset and account for this delay after the reset.
*/
if (dwc2_iddig_filter_enabled(hsotg)) {
u32 gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
u32 gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
if (!(gotgctl & GOTGCTL_CONID_B) ||
(gusbcfg & GUSBCFG_FORCEHOSTMODE)) {
wait_for_host_mode = true;
}
}
/* Core Soft Reset */
greset = dwc2_readl(hsotg->regs + GRSTCTL);
greset |= GRSTCTL_CSFTRST;
dwc2_writel(greset, hsotg->regs + GRSTCTL);
do {
udelay(1);
greset = dwc2_readl(hsotg->regs + GRSTCTL);
if (++count > 50) {
dev_warn(hsotg->dev,
"%s() HANG! Soft Reset GRSTCTL=%0x\n",
__func__, greset);
return -EBUSY;
}
} while (greset & GRSTCTL_CSFTRST);
/* Wait for AHB master IDLE state */
count = 0;
do {
udelay(1);
greset = dwc2_readl(hsotg->regs + GRSTCTL);
if (++count > 50) {
dev_warn(hsotg->dev,
"%s() HANG! AHB Idle GRSTCTL=%0x\n",
__func__, greset);
return -EBUSY;
}
} while (!(greset & GRSTCTL_AHBIDLE));
if (wait_for_host_mode && !skip_wait)
dwc2_wait_for_mode(hsotg, true);
return 0;
}
/*
* Force the mode of the controller.
*
* Forcing the mode is needed for two cases:
*
* 1) If the dr_mode is set to either HOST or PERIPHERAL we force the
* controller to stay in a particular mode regardless of ID pin
* changes. We do this usually after a core reset.
*
* 2) During probe we want to read reset values of the hw
* configuration registers that are only available in either host or
* device mode. We may need to force the mode if the current mode does
* not allow us to access the register in the mode that we want.
*
* In either case it only makes sense to force the mode if the
* controller hardware is OTG capable.
*
* Checks are done in this function to determine whether doing a force
* would be valid or not.
*
* If a force is done, it requires a IDDIG debounce filter delay if
* the filter is configured and enabled. We poll the current mode of
* the controller to account for this delay.
*/
static bool dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host)
{
u32 gusbcfg;
u32 set;
u32 clear;
dev_dbg(hsotg->dev, "Forcing mode to %s\n", host ? "host" : "device");
/*
* Force mode has no effect if the hardware is not OTG.
*/
if (!dwc2_hw_is_otg(hsotg))
return false;
/*
* If dr_mode is either peripheral or host only, there is no
* need to ever force the mode to the opposite mode.
*/
#ifndef NO_GNU
if (WARN_ON(host && hsotg->dr_mode == USB_DR_MODE_PERIPHERAL))
return false;
if (WARN_ON(!host && hsotg->dr_mode == USB_DR_MODE_HOST))
return false;
#else
WARN_ON(host && hsotg->dr_mode == USB_DR_MODE_PERIPHERAL);
WARN_ON(!host && hsotg->dr_mode == USB_DR_MODE_HOST);
#endif
gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
set = host ? GUSBCFG_FORCEHOSTMODE : GUSBCFG_FORCEDEVMODE;
clear = host ? GUSBCFG_FORCEDEVMODE : GUSBCFG_FORCEHOSTMODE;
gusbcfg &= ~clear;
gusbcfg |= set;
dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
dwc2_wait_for_mode(hsotg, host);
return true;
}
/**
* dwc2_clear_force_mode() - Clears the force mode bits.
*
* After clearing the bits, wait up to 100 ms to account for any
* potential IDDIG filter delay. We can't know if we expect this delay
* or not because the value of the connector ID status is affected by
* the force mode. We only need to call this once during probe if
* dr_mode == OTG.
*/
void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg)
{
u32 gusbcfg;
gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
gusbcfg &= ~GUSBCFG_FORCEDEVMODE;
dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
if (dwc2_iddig_filter_enabled(hsotg))
msleep(100);
}
/*
* Sets or clears force mode based on the dr_mode parameter.
*/
void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg)
{
bool ret;
switch (hsotg->dr_mode) {
case USB_DR_MODE_HOST:
ret = dwc2_force_mode(hsotg, true);
/*
* NOTE: This is required for some rockchip soc based
* platforms on their host-only dwc2.
*/
if (!ret)
msleep(50);
break;
case USB_DR_MODE_PERIPHERAL:
dwc2_force_mode(hsotg, false);
break;
case USB_DR_MODE_OTG:
dwc2_clear_force_mode(hsotg);
break;
default:
dev_warn(hsotg->dev, "%s() Invalid dr_mode=%d\n",
__func__, hsotg->dr_mode);
break;
}
}
/*
* Do core a soft reset of the core. Be careful with this because it
* resets all the internal state machines of the core.
*
* Additionally this will apply force mode as per the hsotg->dr_mode
* parameter.
*/
int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg)
{
int retval;
retval = dwc2_core_reset(hsotg, false);
if (retval)
return retval;
dwc2_force_dr_mode(hsotg);
return 0;
}
/**
* dwc2_dump_host_registers() - Prints the host registers
*
* @hsotg: Programming view of DWC_otg controller
*
* NOTE: This function will be removed once the peripheral controller code
* is integrated and the driver is stable
*/
void dwc2_dump_host_registers(struct dwc2_hsotg *hsotg)
{
#ifdef DEBUG
u32 addr;//u32 __iomem *addr;
u32 value;
int i;
dev_dbg(hsotg->dev, "Host Global Registers\n");
addr = hsotg->regs + HCFG;
value = dwc2_readl(addr);
dev_dbg(hsotg->dev, "HCFG @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + HFIR;
value = dwc2_readl(addr);
dev_dbg(hsotg->dev, "HFIR @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + HFNUM;
dev_dbg(hsotg->dev, "HFNUM @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + HPTXSTS;
value = dwc2_readl(addr);
dev_dbg(hsotg->dev, "HPTXSTS @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + HAINT;
value = dwc2_readl(addr);
dev_dbg(hsotg->dev, "HAINT @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + HAINTMSK;
value = dwc2_readl(addr);
dev_dbg(hsotg->dev, "HAINTMSK @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
if (hsotg->params.dma_desc_enable) {
addr = hsotg->regs + HFLBADDR;
value = dwc2_readl(addr);
dev_dbg(hsotg->dev, "HFLBADDR @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
}
addr = hsotg->regs + HPRT0;
value = dwc2_readl(addr);
dev_dbg(hsotg->dev, "HPRT0 @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
for (i = 0; i < hsotg->params.host_channels; i++) {
dev_dbg(hsotg->dev, "Host Channel %d Specific Registers\n", i);
addr = hsotg->regs + HCCHAR(i);
value = dwc2_readl(addr);
dev_dbg(hsotg->dev, "HCCHAR @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + HCSPLT(i);
value = dwc2_readl(addr);
dev_dbg(hsotg->dev, "HCSPLT @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + HCINT(i);
value = dwc2_readl(addr);
dev_dbg(hsotg->dev, "HCINT @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + HCINTMSK(i);
value = dwc2_readl(addr);
dev_dbg(hsotg->dev, "HCINTMSK @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + HCTSIZ(i);
value = dwc2_readl(addr);
dev_dbg(hsotg->dev, "HCTSIZ @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + HCDMA(i);
value = dwc2_readl(addr);
dev_dbg(hsotg->dev, "HCDMA @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
if (hsotg->params.dma_desc_enable) {
addr = hsotg->regs + HCDMAB(i);
value = dwc2_readl(addr);
dev_dbg(hsotg->dev, "HCDMAB @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
}
}
USB_UNUSED(value);
#endif
}
/**
* dwc2_dump_global_registers() - Prints the core global registers
*
* @hsotg: Programming view of DWC_otg controller
*
* NOTE: This function will be removed once the peripheral controller code
* is integrated and the driver is stable
*/
void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg)
{
#ifdef DEBUG
//u32 __iomem *addr;
u32 addr;
dev_dbg(hsotg->dev, "Core Global Registers\n");
addr = hsotg->regs + GOTGCTL;
dev_dbg(hsotg->dev, "GOTGCTL @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + GOTGINT;
dev_dbg(hsotg->dev, "GOTGINT @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + GAHBCFG;
dev_dbg(hsotg->dev, "GAHBCFG @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + GUSBCFG;
dev_dbg(hsotg->dev, "GUSBCFG @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + GRSTCTL;
dev_dbg(hsotg->dev, "GRSTCTL @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + GINTSTS;
dev_dbg(hsotg->dev, "GINTSTS @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + GINTMSK;
dev_dbg(hsotg->dev, "GINTMSK @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + GRXSTSR;
dev_dbg(hsotg->dev, "GRXSTSR @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + GRXFSIZ;
dev_dbg(hsotg->dev, "GRXFSIZ @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + GNPTXFSIZ;
dev_dbg(hsotg->dev, "GNPTXFSIZ @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + GNPTXSTS;
dev_dbg(hsotg->dev, "GNPTXSTS @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + GI2CCTL;
dev_dbg(hsotg->dev, "GI2CCTL @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + GPVNDCTL;
dev_dbg(hsotg->dev, "GPVNDCTL @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + GGPIO;
dev_dbg(hsotg->dev, "GGPIO @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + GUID;
dev_dbg(hsotg->dev, "GUID @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + GSNPSID;
dev_dbg(hsotg->dev, "GSNPSID @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + GHWCFG1;
dev_dbg(hsotg->dev, "GHWCFG1 @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + GHWCFG2;
dev_dbg(hsotg->dev, "GHWCFG2 @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + GHWCFG3;
dev_dbg(hsotg->dev, "GHWCFG3 @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + GHWCFG4;
dev_dbg(hsotg->dev, "GHWCFG4 @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + GLPMCFG;
dev_dbg(hsotg->dev, "GLPMCFG @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + GPWRDN;
dev_dbg(hsotg->dev, "GPWRDN @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + GDFIFOCFG;
dev_dbg(hsotg->dev, "GDFIFOCFG @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + HPTXFSIZ;
dev_dbg(hsotg->dev, "HPTXFSIZ @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
addr = hsotg->regs + PCGCTL;
dev_dbg(hsotg->dev, "PCGCTL @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr));
USB_UNUSED(addr);
#endif
}
/**
* dwc2_flush_tx_fifo() - Flushes a Tx FIFO
*
* @hsotg: Programming view of DWC_otg controller
* @num: Tx FIFO to flush
*/
void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num)
{
u32 greset;
int count = 0;
dev_vdbg(hsotg->dev, "Flush Tx FIFO %d\n", num);
greset = GRSTCTL_TXFFLSH;
greset |= num << GRSTCTL_TXFNUM_SHIFT & GRSTCTL_TXFNUM_MASK;
dwc2_writel(greset, hsotg->regs + GRSTCTL);
do {
greset = dwc2_readl(hsotg->regs + GRSTCTL);
if (++count > 10000) {
dev_warn(hsotg->dev,
"%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n",
__func__, greset,
dwc2_readl(hsotg->regs + GNPTXSTS));
break;
}
udelay(1);
} while (greset & GRSTCTL_TXFFLSH);
/* Wait for at least 3 PHY Clocks */
udelay(1);
}
/**
* dwc2_flush_rx_fifo() - Flushes the Rx FIFO
*
* @hsotg: Programming view of DWC_otg controller
*/
void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg)
{
u32 greset;
int count = 0;
dev_vdbg(hsotg->dev, "%s()\n", __func__);
greset = GRSTCTL_RXFFLSH;
dwc2_writel(greset, hsotg->regs + GRSTCTL);
do {
greset = dwc2_readl(hsotg->regs + GRSTCTL);
if (++count > 10000) {
dev_warn(hsotg->dev, "%s() HANG! GRSTCTL=%0x\n",
__func__, greset);
break;
}
udelay(1);
} while (greset & GRSTCTL_RXFFLSH);
/* Wait for at least 3 PHY Clocks */
udelay(1);
}
/*
* Forces either host or device mode if the controller is not
* currently in that mode.
*
* Returns true if the mode was forced.
*/
bool dwc2_force_mode_if_needed(struct dwc2_hsotg *hsotg, bool host)
{
if (host && dwc2_is_host_mode(hsotg))
return false;
else if (!host && dwc2_is_device_mode(hsotg))
return false;
return dwc2_force_mode(hsotg, host);
}
bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg)
{
if (dwc2_readl(hsotg->regs + GSNPSID) == 0xffffffff)
return false;
else
return true;
}
/**
* dwc2_enable_global_interrupts() - Enables the controller's Global
* Interrupt in the AHB Config register
*
* @hsotg: Programming view of DWC_otg controller
*/
void dwc2_enable_global_interrupts(struct dwc2_hsotg *hsotg)
{
u32 ahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
ahbcfg |= GAHBCFG_GLBL_INTR_EN;
dwc2_writel(ahbcfg, hsotg->regs + GAHBCFG);
}
/**
* dwc2_disable_global_interrupts() - Disables the controller's Global
* Interrupt in the AHB Config register
*
* @hsotg: Programming view of DWC_otg controller
*/
void dwc2_disable_global_interrupts(struct dwc2_hsotg *hsotg)
{
u32 ahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
ahbcfg &= ~GAHBCFG_GLBL_INTR_EN;
dwc2_writel(ahbcfg, hsotg->regs + GAHBCFG);
}
/* Returns the controller's GHWCFG2.OTG_MODE. */
unsigned int dwc2_op_mode(struct dwc2_hsotg *hsotg)
{
u32 ghwcfg2 = dwc2_readl(hsotg->regs + GHWCFG2);
return (ghwcfg2 & GHWCFG2_OP_MODE_MASK) >>
GHWCFG2_OP_MODE_SHIFT;
}
/* Returns true if the controller is capable of DRD. */
bool dwc2_hw_is_otg(struct dwc2_hsotg *hsotg)
{
unsigned int op_mode = dwc2_op_mode(hsotg);
return (op_mode == GHWCFG2_OP_MODE_HNP_SRP_CAPABLE) ||
(op_mode == GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE) ||
(op_mode == GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE);
}
/* Returns true if the controller is host-only. */
bool dwc2_hw_is_host(struct dwc2_hsotg *hsotg)
{
unsigned int op_mode = dwc2_op_mode(hsotg);
return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_HOST) ||
(op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST);
}
/* Returns true if the controller is device-only. */
bool dwc2_hw_is_device(struct dwc2_hsotg *hsotg)
{
unsigned int op_mode = dwc2_op_mode(hsotg);
return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) ||
(op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE);
}
#ifndef NO_GNU
MODULE_DESCRIPTION("DESIGNWARE HS OTG Core");
MODULE_AUTHOR("Synopsys, Inc.");
MODULE_LICENSE("Dual BSD/GPL");
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,518 @@
/*
* core_intr.c - DesignWare HS OTG Controller common interrupt handling
*
* Copyright (C) 2004-2013 Synopsys, Inc.
*
* 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,
* without modification.
* 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. The names of the above-listed copyright holders may not be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any
* later version.
*
* 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.
*/
/*
* This file contains the common interrupt handlers
*/
#include "usb_os_adapter.h"
#include "trace.h"
#include <asm/dma-mapping.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include "core.h"
#include "hcd.h"
const char *dwc2_op_state_str(struct dwc2_hsotg *hsotg)
{
switch (hsotg->op_state) {
case OTG_STATE_A_HOST:
return "a_host";
case OTG_STATE_A_SUSPEND:
return "a_suspend";
case OTG_STATE_A_PERIPHERAL:
return "a_peripheral";
case OTG_STATE_B_PERIPHERAL:
return "b_peripheral";
case OTG_STATE_B_HOST:
return "b_host";
default:
return "unknown";
}
}
/**
* dwc2_handle_usb_port_intr - handles OTG PRTINT interrupts.
* When the PRTINT interrupt fires, there are certain status bits in the Host
* Port that needs to get cleared.
*
* @hsotg: Programming view of DWC_otg controller
*/
static void dwc2_handle_usb_port_intr(struct dwc2_hsotg *hsotg)
{
u32 hprt0 = dwc2_readl(hsotg->regs + HPRT0);
if (hprt0 & HPRT0_ENACHG) {
hprt0 &= ~HPRT0_ENA;
dwc2_writel(hprt0, hsotg->regs + HPRT0);
}
}
/**
* dwc2_handle_mode_mismatch_intr() - Logs a mode mismatch warning message
*
* @hsotg: Programming view of DWC_otg controller
*/
static void dwc2_handle_mode_mismatch_intr(struct dwc2_hsotg *hsotg)
{
/* Clear interrupt */
dwc2_writel(GINTSTS_MODEMIS, hsotg->regs + GINTSTS);
dev_warn(hsotg->dev, "Mode Mismatch Interrupt: currently in %s mode\n",
dwc2_is_host_mode(hsotg) ? "Host" : "Device");
}
/**
* dwc2_handle_otg_intr() - Handles the OTG Interrupts. It reads the OTG
* Interrupt Register (GOTGINT) to determine what interrupt has occurred.
*
* @hsotg: Programming view of DWC_otg controller
*/
static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
{
u32 gotgint;
u32 gotgctl;
u32 gintmsk;
gotgint = dwc2_readl(hsotg->regs + GOTGINT);
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
dev_dbg(hsotg->dev, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint,
dwc2_op_state_str(hsotg));
if (gotgint & GOTGINT_SES_END_DET) {
dev_dbg(hsotg->dev,
" ++OTG Interrupt: Session End Detected++ (%s)\n",
dwc2_op_state_str(hsotg));
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
if (dwc2_is_device_mode(hsotg))
dwc2_hsotg_disconnect(hsotg);
if (hsotg->op_state == OTG_STATE_B_HOST) {
hsotg->op_state = OTG_STATE_B_PERIPHERAL;
} else {
/*
* If not B_HOST and Device HNP still set, HNP did
* not succeed!
*/
if (gotgctl & GOTGCTL_DEVHNPEN) {
dev_dbg(hsotg->dev, "Session End Detected\n");
dev_err(hsotg->dev,
"Device Not Connected/Responding!\n");
}
/*
* If Session End Detected the B-Cable has been
* disconnected
*/
/* Reset to a clean state */
hsotg->lx_state = DWC2_L0;
}
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
gotgctl &= ~GOTGCTL_DEVHNPEN;
dwc2_writel(gotgctl, hsotg->regs + GOTGCTL);
}
if (gotgint & GOTGINT_SES_REQ_SUC_STS_CHNG) {
dev_dbg(hsotg->dev,
" ++OTG Interrupt: Session Request Success Status Change++\n");
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
if (gotgctl & GOTGCTL_SESREQSCS) {
if (hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS &&
hsotg->params.i2c_enable) {
hsotg->srp_success = 1;
} else {
/* Clear Session Request */
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
gotgctl &= ~GOTGCTL_SESREQ;
dwc2_writel(gotgctl, hsotg->regs + GOTGCTL);
}
}
}
if (gotgint & GOTGINT_HST_NEG_SUC_STS_CHNG) {
/*
* Print statements during the HNP interrupt handling
* can cause it to fail
*/
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
/*
* WA for 3.00a- HW is not setting cur_mode, even sometimes
* this does not help
*/
if (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a)
udelay(100);
if (gotgctl & GOTGCTL_HSTNEGSCS) {
if (dwc2_is_host_mode(hsotg)) {
hsotg->op_state = OTG_STATE_B_HOST;
/*
* Need to disable SOF interrupt immediately.
* When switching from device to host, the PCD
* interrupt handler won't handle the interrupt
* if host mode is already set. The HCD
* interrupt handler won't get called if the
* HCD state is HALT. This means that the
* interrupt does not get handled and Linux
* complains loudly.
*/
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
gintmsk &= ~GINTSTS_SOF;
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
/*
* Call callback function with spin lock
* released
*/
spin_unlock(&hsotg->lock);
/* Initialize the Core for Host mode */
dwc2_hcd_start_isr(hsotg);
spin_lock(&hsotg->lock);
hsotg->op_state = OTG_STATE_B_HOST;
}
} else {
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
gotgctl &= ~(GOTGCTL_HNPREQ | GOTGCTL_DEVHNPEN);
dwc2_writel(gotgctl, hsotg->regs + GOTGCTL);
dev_dbg(hsotg->dev, "HNP Failed\n");
dev_err(hsotg->dev,
"Device Not Connected/Responding\n");
}
}
if (gotgint & GOTGINT_HST_NEG_DET) {
/*
* The disconnect interrupt is set at the same time as
* Host Negotiation Detected. During the mode switch all
* interrupts are cleared so the disconnect interrupt
* handler will not get executed.
*/
dev_dbg(hsotg->dev,
" ++OTG Interrupt: Host Negotiation Detected++ (%s)\n",
(dwc2_is_host_mode(hsotg) ? "Host" : "Device"));
if (dwc2_is_device_mode(hsotg)) {
dev_dbg(hsotg->dev, "a_suspend->a_peripheral (%d)\n",
hsotg->op_state);
spin_unlock(&hsotg->lock);
dwc2_hcd_disconnect(hsotg, false);
spin_lock(&hsotg->lock);
hsotg->op_state = OTG_STATE_A_PERIPHERAL;
} else {
/* Need to disable SOF interrupt immediately */
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
gintmsk &= ~GINTSTS_SOF;
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
spin_unlock(&hsotg->lock);
dwc2_hcd_start_isr(hsotg);
spin_lock(&hsotg->lock);
hsotg->op_state = OTG_STATE_A_HOST;
}
}
if (gotgint & GOTGINT_A_DEV_TOUT_CHG)
dev_dbg(hsotg->dev,
" ++OTG Interrupt: A-Device Timeout Change++\n");
if (gotgint & GOTGINT_DBNCE_DONE)
dev_dbg(hsotg->dev, " ++OTG Interrupt: Debounce Done++\n");
/* Clear GOTGINT */
dwc2_writel(gotgint, hsotg->regs + GOTGINT);
}
/**
* dwc2_handle_conn_id_status_change_intr() - Handles the Connector ID Status
* Change Interrupt
*
* @hsotg: Programming view of DWC_otg controller
*
* Reads the OTG Interrupt Register (GOTCTL) to determine whether this is a
* Device to Host Mode transition or a Host to Device Mode transition. This only
* occurs when the cable is connected/removed from the PHY connector.
*/
static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg)
{
u32 gintmsk;
/* Clear interrupt */
dwc2_writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS);
/* Need to disable SOF interrupt immediately */
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
gintmsk &= ~GINTSTS_SOF;
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
dev_dbg(hsotg->dev, " ++Connector ID Status Change Interrupt++ (%s)\n",
dwc2_is_host_mode(hsotg) ? "Host" : "Device");
/*
* Need to schedule a work, as there are possible DELAY function calls.
* Release lock before scheduling workq as it holds spinlock during
* scheduling.
*/
if (hsotg->wq_otg) {
spin_unlock(&hsotg->lock);
struct wq_msg *pmsg = &hsotg->xmsg;
pmsg->id = OTG_WQ_MSG_ID_STATE_CHANGE;
pmsg->delay = 0;
xQueueSendFromISR(hsotg->wq_otg, (void*)pmsg, 0);
spin_lock(&hsotg->lock);
}
}
/**
* dwc2_handle_session_req_intr() - This interrupt indicates that a device is
* initiating the Session Request Protocol to request the host to turn on bus
* power so a new session can begin
*
* @hsotg: Programming view of DWC_otg controller
*
* This handler responds by turning on bus power. If the DWC_otg controller is
* in low power mode, this handler brings the controller out of low power mode
* before turning on bus power.
*/
static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
{
int ret;
/* Clear interrupt */
dwc2_writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS);
dev_dbg(hsotg->dev, "Session request interrupt - lx_state=%d\n",
hsotg->lx_state);
if (dwc2_is_device_mode(hsotg)) {
if (hsotg->lx_state == DWC2_L2) {
ret = dwc2_exit_hibernation(hsotg, true);
if (ret && (ret != -ENOTSUPP))
dev_err(hsotg->dev,
"exit hibernation failed\n");
}
/*
* Report disconnect if there is any previous session
* established
*/
dwc2_hsotg_disconnect(hsotg);
}
}
/*
* This interrupt indicates that a device has been disconnected from the
* root port
*/
int dwc2_disconnect_flag;
void usb_stor_disconnect_isr();
static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
{
usb_stor_disconnect_isr();
dwc2_writel(GINTSTS_DISCONNINT, hsotg->regs + GINTSTS);
dev_dbg(hsotg->dev, "++Disconnect Detected Interrupt++ (%s) %s\n",
dwc2_is_host_mode(hsotg) ? "Host" : "Device",
dwc2_op_state_str(hsotg));
if (hsotg->op_state == OTG_STATE_A_HOST)
dwc2_hcd_disconnect(hsotg, false);
dwc2_disconnect_flag = 1;
}
/*
* This interrupt indicates that SUSPEND state has been detected on the USB.
*
* For HNP the USB Suspend interrupt signals the change from "a_peripheral"
* to "a_host".
*
* When power management is enabled the core will be put in low power mode.
*/
static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
{
u32 dsts;
int ret;
/* Clear interrupt */
dwc2_writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS);
dev_dbg(hsotg->dev, "USB SUSPEND\n");
if (dwc2_is_device_mode(hsotg)) {
/*
* Check the Device status register to determine if the Suspend
* state is active
*/
dsts = dwc2_readl(hsotg->regs + DSTS);
dev_dbg(hsotg->dev, "DSTS=0x%0x\n", dsts);
dev_dbg(hsotg->dev,
"DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d\n",
!!(dsts & DSTS_SUSPSTS),
hsotg->hw_params.power_optimized);
if ((dsts & DSTS_SUSPSTS) && hsotg->hw_params.power_optimized) {
/* Ignore suspend request before enumeration */
if (!dwc2_is_device_connected(hsotg)) {
dev_dbg(hsotg->dev,
"ignore suspend request before enumeration\n");
return;
}
ret = dwc2_enter_hibernation(hsotg);
if (ret) {
if (ret != -ENOTSUPP)
dev_err(hsotg->dev,
"enter hibernation failed\n");
goto skip_power_saving;
}
udelay(100);
skip_power_saving:
/*
* Change to L2 (suspend) state before releasing
* spinlock
*/
hsotg->lx_state = DWC2_L2;
/* Call gadget suspend callback */
call_gadget(hsotg, suspend);
} else if (dsts & DSTS_SUSPSTS) {
/* Call gadget disconnect callback */
call_gadget(hsotg, disconnect);
}
} else {
if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) {
dev_dbg(hsotg->dev, "a_peripheral->a_host\n");
/* Change to L2 (suspend) state */
hsotg->lx_state = DWC2_L2;
/* Clear the a_peripheral flag, back to a_host */
spin_unlock(&hsotg->lock);
dwc2_hcd_start_isr(hsotg);
spin_lock(&hsotg->lock);
hsotg->op_state = OTG_STATE_A_HOST;
}
}
}
#define GINTMSK_COMMON (GINTSTS_WKUPINT | GINTSTS_SESSREQINT | \
GINTSTS_CONIDSTSCHNG | GINTSTS_OTGINT | \
GINTSTS_MODEMIS | GINTSTS_DISCONNINT | \
GINTSTS_USBSUSP | GINTSTS_PRTINT)
/*
* This function returns the Core Interrupt register
*/
static u32 dwc2_read_common_intr(struct dwc2_hsotg *hsotg)
{
u32 gintsts;
u32 gintmsk;
u32 gahbcfg;
u32 gintmsk_common = GINTMSK_COMMON;
gintsts = dwc2_readl(hsotg->regs + GINTSTS);
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
gahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
/* If any common interrupts set */
if (gintsts & gintmsk_common)
dev_dbg(hsotg->dev, "gintsts=%08x gintmsk=%08x\n",
gintsts, gintmsk);
if (gahbcfg & GAHBCFG_GLBL_INTR_EN)
return gintsts & gintmsk & gintmsk_common;
else
return 0;
}
/*
* Common interrupt handler
*
* The common interrupts are those that occur in both Host and Device mode.
* This handler handles the following interrupts:
* - Mode Mismatch Interrupt
* - OTG Interrupt
* - Connector ID Status Change Interrupt
* - Disconnect Interrupt
* - Session Request Interrupt
* - Resume / Remote Wakeup Detected Interrupt
* - Suspend Interrupt
*/
irqreturn_t dwc2_handle_common_intr(int irq, void *dev)
{
struct dwc2_hsotg *hsotg = dev;
u32 gintsts;
irqreturn_t retval = IRQ_NONE;
if (!dwc2_is_controller_alive(hsotg)) {
dev_warn(hsotg->dev, "Controller is dead\n");
goto out;
}
gintsts = dwc2_read_common_intr(hsotg);
if (gintsts & ~GINTSTS_PRTINT)
retval = IRQ_HANDLED;
if (gintsts & GINTSTS_MODEMIS)
dwc2_handle_mode_mismatch_intr(hsotg);
if (gintsts & GINTSTS_OTGINT)
dwc2_handle_otg_intr(hsotg);
if (gintsts & GINTSTS_CONIDSTSCHNG)
dwc2_handle_conn_id_status_change_intr(hsotg);
if (gintsts & GINTSTS_DISCONNINT)
dwc2_handle_disconnect_intr(hsotg);
if (gintsts & GINTSTS_SESSREQINT)
dwc2_handle_session_req_intr(hsotg);
if (gintsts & GINTSTS_WKUPINT)
dwc2_writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS);
if (gintsts & GINTSTS_USBSUSP)
dwc2_handle_usb_suspend_intr(hsotg);
if (gintsts & GINTSTS_PRTINT) {
/*
* The port interrupt occurs while in device mode with HPRT0
* Port Enable/Disable
*/
if (dwc2_is_device_mode(hsotg)) {
dev_dbg(hsotg->dev,
" --Port interrupt received in Device mode--\n");
dwc2_handle_usb_port_intr(hsotg);
retval = IRQ_HANDLED;
}
}
out:
return retval;
}

View File

@ -0,0 +1,138 @@
#ifndef _DWC2_COMPAT_H
#define _DWC2_COMPAT_H
/* OTG defines lots of enumeration states before device reset */
enum usb_otg_state {
OTG_STATE_UNDEFINED = 0,
/* single-role peripheral, and dual-role default-b */
OTG_STATE_B_IDLE,
OTG_STATE_B_SRP_INIT,
OTG_STATE_B_PERIPHERAL,
/* extra dual-role default-b states */
OTG_STATE_B_WAIT_ACON,
OTG_STATE_B_HOST,
/* dual-role default-a */
OTG_STATE_A_IDLE,
OTG_STATE_A_WAIT_VRISE,
OTG_STATE_A_WAIT_BCON,
OTG_STATE_A_HOST,
OTG_STATE_A_SUSPEND,
OTG_STATE_A_PERIPHERAL,
OTG_STATE_A_WAIT_VFALL,
OTG_STATE_A_VBUS_ERR,
};
enum usb_dr_mode {
USB_DR_MODE_UNKNOWN,
USB_DR_MODE_HOST,
USB_DR_MODE_PERIPHERAL,
USB_DR_MODE_OTG,
};
#define URB_DIR_IN 0x0200 /* Transfer from device to host */
#define URB_DIR_OUT 0
#define URB_DIR_MASK URB_DIR_IN
#define URB_DMA_MAP_SINGLE 0x00010000 /* Non-scatter-gather mapping */
#define URB_DMA_MAP_PAGE 0x00020000 /* HCD-unsupported S-G */
#define URB_DMA_MAP_SG 0x00040000 /* HCD-supported S-G */
#define URB_MAP_LOCAL 0x00080000 /* HCD-local-memory mapping */
#define URB_SETUP_MAP_SINGLE 0x00100000 /* Setup packet DMA mapped */
#define URB_SETUP_MAP_LOCAL 0x00200000 /* HCD-local setup packet */
#define URB_DMA_SG_COMBINED 0x00400000 /* S-G entries were combined */
#define URB_ALIGNED_TEMP_BUFFER 0x00800000 /* Temp buffer was alloc'd */
#define USB_RESUME_TIMEOUT 40 /* ms */
/* class requests from the USB 2.0 hub spec, table 11-15 */
#define HUB_CLASS_REQ(dir, type, request) ((((dir) | (type)) << 8) | (request))
/* GetBusState and SetHubDescriptor are optional, omitted */
#define ClearHubFeature HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_HUB, USB_REQ_CLEAR_FEATURE)
#define ClearPortFeature HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_PORT, USB_REQ_CLEAR_FEATURE)
#define GetHubDescriptor HUB_CLASS_REQ(USB_DIR_IN, USB_RT_HUB, USB_REQ_GET_DESCRIPTOR)
#define GetHubStatus HUB_CLASS_REQ(USB_DIR_IN, USB_RT_HUB, USB_REQ_GET_STATUS)
#define GetPortStatus HUB_CLASS_REQ(USB_DIR_IN, USB_RT_PORT, USB_REQ_GET_STATUS)
#define SetHubFeature HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_HUB, USB_REQ_SET_FEATURE)
#define SetPortFeature HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_PORT, USB_REQ_SET_FEATURE)
/*
* Port feature numbers
* See USB 2.0 spec Table 11-17
*/
#define USB_PORT_FEAT_CONNECTION 0
#define USB_PORT_FEAT_ENABLE 1
#define USB_PORT_FEAT_SUSPEND 2 /* L2 suspend */
#define USB_PORT_FEAT_OVER_CURRENT 3
#define USB_PORT_FEAT_RESET 4
#define USB_PORT_FEAT_L1 5 /* L1 suspend */
#define USB_PORT_FEAT_POWER 8
#define USB_PORT_FEAT_LOWSPEED 9 /* Should never be used */
#define USB_PORT_FEAT_C_CONNECTION 16
#define USB_PORT_FEAT_C_ENABLE 17
#define USB_PORT_FEAT_C_SUSPEND 18
#define USB_PORT_FEAT_C_OVER_CURRENT 19
#define USB_PORT_FEAT_C_RESET 20
#define USB_PORT_FEAT_TEST 21
#define USB_PORT_FEAT_INDICATOR 22
#define USB_PORT_FEAT_C_PORT_L1 23
/*
* wPortChange bit field
* See USB 2.0 spec Table 11-22 and USB 2.0 LPM ECN Table-4.10
* Bits 0 to 5 shown, bits 6 to 15 are reserved
*/
#define USB_PORT_STAT_C_CONNECTION 0x0001
#define USB_PORT_STAT_C_ENABLE 0x0002
#define USB_PORT_STAT_C_SUSPEND 0x0004
#define USB_PORT_STAT_C_OVERCURRENT 0x0008
#define USB_PORT_STAT_C_RESET 0x0010
#define USB_PORT_STAT_C_L1 0x0020
/*
* wPortStatus bit field
* See USB 2.0 spec Table 11-21
*/
#define USB_PORT_STAT_CONNECTION 0x0001
#define USB_PORT_STAT_ENABLE 0x0002
#define USB_PORT_STAT_SUSPEND 0x0004
#define USB_PORT_STAT_OVERCURRENT 0x0008
#define USB_PORT_STAT_RESET 0x0010
#define USB_PORT_STAT_L1 0x0020
/* bits 6 to 7 are reserved */
#define USB_PORT_STAT_POWER 0x0100
#define USB_PORT_STAT_LOW_SPEED 0x0200
#define USB_PORT_STAT_HIGH_SPEED 0x0400
#define USB_PORT_STAT_TEST 0x0800
#define USB_PORT_STAT_INDICATOR 0x1000
/* bits 13 to 15 are reserved */
/*
* wHubCharacteristics (masks)
* See USB 2.0 spec Table 11-13, offset 3
*/
#define HUB_CHAR_LPSM 0x0003 /* Logical Power Switching Mode mask */
#define HUB_CHAR_COMMON_LPSM 0x0000 /* All ports power control at once */
#define HUB_CHAR_INDV_PORT_LPSM 0x0001 /* per-port power control */
#define HUB_CHAR_NO_LPSM 0x0002 /* no power switching */
#define HUB_CHAR_COMPOUND 0x0004 /* hub is part of a compound device */
#define HUB_CHAR_OCPM 0x0018 /* Over-Current Protection Mode mask */
#define HUB_CHAR_COMMON_OCPM 0x0000 /* All ports Over-Current reporting */
#define HUB_CHAR_INDV_PORT_OCPM 0x0008 /* per-port Over-current reporting */
#define HUB_CHAR_NO_OCPM 0x0010 /* No Over-current Protection support */
#define HUB_CHAR_TTTT 0x0060 /* TT Think Time mask */
#define HUB_CHAR_PORTIND 0x0080 /* per-port indicators (LEDs) */
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,893 @@
/*
* hcd.h - DesignWare HS OTG Controller host-mode declarations
*
* Copyright (C) 2004-2013 Synopsys, Inc.
*
* 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,
* without modification.
* 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. The names of the above-listed copyright holders may not be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any
* later version.
*
* 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.
*/
#ifndef __DWC2_HCD_H__
#define __DWC2_HCD_H__
#include "usb-compat.h"
/*
* This file contains the structures, constants, and interfaces for the
* Host Contoller Driver (HCD)
*
* The Host Controller Driver (HCD) is responsible for translating requests
* from the USB Driver into the appropriate actions on the DWC_otg controller.
* It isolates the USBD from the specifics of the controller by providing an
* API to the USBD.
*/
struct dwc2_qh;
/**
* struct dwc2_host_chan - Software host channel descriptor
*
* @hc_num: Host channel number, used for register address lookup
* @dev_addr: Address of the device
* @ep_num: Endpoint of the device
* @ep_is_in: Endpoint direction
* @speed: Device speed. One of the following values:
* - USB_SPEED_LOW
* - USB_SPEED_FULL
* - USB_SPEED_HIGH
* @ep_type: Endpoint type. One of the following values:
* - USB_ENDPOINT_XFER_CONTROL: 0
* - USB_ENDPOINT_XFER_ISOC: 1
* - USB_ENDPOINT_XFER_BULK: 2
* - USB_ENDPOINT_XFER_INTR: 3
* @max_packet: Max packet size in bytes
* @data_pid_start: PID for initial transaction.
* 0: DATA0
* 1: DATA2
* 2: DATA1
* 3: MDATA (non-Control EP),
* SETUP (Control EP)
* @multi_count: Number of additional periodic transactions per
* (micro)frame
* @xfer_buf: Pointer to current transfer buffer position
* @xfer_dma: DMA address of xfer_buf
* @align_buf: In Buffer DMA mode this will be used if xfer_buf is not
* DWORD aligned
* @xfer_len: Total number of bytes to transfer
* @xfer_count: Number of bytes transferred so far
* @start_pkt_count: Packet count at start of transfer
* @xfer_started: True if the transfer has been started
* @ping: True if a PING request should be issued on this channel
* @error_state: True if the error count for this transaction is non-zero
* @halt_on_queue: True if this channel should be halted the next time a
* request is queued for the channel. This is necessary in
* slave mode if no request queue space is available when
* an attempt is made to halt the channel.
* @halt_pending: True if the host channel has been halted, but the core
* is not finished flushing queued requests
* @do_split: Enable split for the channel
* @complete_split: Enable complete split
* @hub_addr: Address of high speed hub for the split
* @hub_port: Port of the low/full speed device for the split
* @xact_pos: Split transaction position. One of the following values:
* - DWC2_HCSPLT_XACTPOS_MID
* - DWC2_HCSPLT_XACTPOS_BEGIN
* - DWC2_HCSPLT_XACTPOS_END
* - DWC2_HCSPLT_XACTPOS_ALL
* @requests: Number of requests issued for this channel since it was
* assigned to the current transfer (not counting PINGs)
* @schinfo: Scheduling micro-frame bitmap
* @ntd: Number of transfer descriptors for the transfer
* @halt_status: Reason for halting the host channel
* @hcint Contents of the HCINT register when the interrupt came
* @qh: QH for the transfer being processed by this channel
* @hc_list_entry: For linking to list of host channels
* @desc_list_addr: Current QH's descriptor list DMA address
* @desc_list_sz: Current QH's descriptor list size
* @split_order_list_entry: List entry for keeping track of the order of splits
*
* This structure represents the state of a single host channel when acting in
* host mode. It contains the data items needed to transfer packets to an
* endpoint via a host channel.
*/
struct dwc2_host_chan {
u8 hc_num;
unsigned dev_addr:7;
unsigned ep_num:4;
unsigned ep_is_in:1;
unsigned speed:4;
unsigned ep_type:2;
unsigned max_packet:11;
unsigned data_pid_start:2;
#define DWC2_HC_PID_DATA0 TSIZ_SC_MC_PID_DATA0
#define DWC2_HC_PID_DATA2 TSIZ_SC_MC_PID_DATA2
#define DWC2_HC_PID_DATA1 TSIZ_SC_MC_PID_DATA1
#define DWC2_HC_PID_MDATA TSIZ_SC_MC_PID_MDATA
#define DWC2_HC_PID_SETUP TSIZ_SC_MC_PID_SETUP
unsigned multi_count:2;
u8 *xfer_buf;
dma_addr_t xfer_dma;
dma_addr_t align_buf;
u32 xfer_len;
u32 xfer_count;
u16 start_pkt_count;
u8 xfer_started;
u8 do_ping;
u8 error_state;
u8 halt_on_queue;
u8 halt_pending;
u8 do_split;
u8 complete_split;
u8 hub_addr;
u8 hub_port;
u8 xact_pos;
#define DWC2_HCSPLT_XACTPOS_MID HCSPLT_XACTPOS_MID
#define DWC2_HCSPLT_XACTPOS_END HCSPLT_XACTPOS_END
#define DWC2_HCSPLT_XACTPOS_BEGIN HCSPLT_XACTPOS_BEGIN
#define DWC2_HCSPLT_XACTPOS_ALL HCSPLT_XACTPOS_ALL
u8 requests;
u8 schinfo;
u16 ntd;
enum dwc2_halt_status halt_status;
u32 hcint;
struct dwc2_qh *qh;
#ifndef NO_GNU
struct list_head hc_list_entry;
#else
ListItem_t hc_list_entry;
#endif
dma_addr_t desc_list_addr;
u32 desc_list_sz;
#ifndef NO_GNU
struct list_head split_order_list_entry;
#else
ListItem_t split_order_list_entry;
#endif
};
struct dwc2_hcd_pipe_info {
u8 dev_addr;
u8 ep_num;
u8 pipe_type;
u8 pipe_dir;
u16 mps;
};
struct dwc2_hcd_iso_packet_desc {
u32 offset;
u32 length;
u32 actual_length;
int status;
};
struct dwc2_qtd;
struct dwc2_hcd_urb {
void *priv;
struct dwc2_qtd *qtd;
void *buf;
dma_addr_t dma;
void *setup_packet;
dma_addr_t setup_dma;
u32 length;
u32 actual_length;
int status;
u32 error_count;
u32 packet_count;
u32 flags;
u16 interval;
#ifdef NO_GNU
ListItem_t free_list_entry;
#endif
struct dwc2_hcd_pipe_info pipe_info;
struct dwc2_hcd_iso_packet_desc iso_descs[0];
};
/* Phases for control transfers */
enum dwc2_control_phase {
DWC2_CONTROL_SETUP,
DWC2_CONTROL_DATA,
DWC2_CONTROL_STATUS,
};
/* Transaction types */
enum dwc2_transaction_type {
DWC2_TRANSACTION_NONE,
DWC2_TRANSACTION_PERIODIC,
DWC2_TRANSACTION_NON_PERIODIC,
DWC2_TRANSACTION_ALL,
};
/* The number of elements per LS bitmap (per port on multi_tt) */
#define DWC2_ELEMENTS_PER_LS_BITMAP DIV_ROUND_UP(DWC2_LS_SCHEDULE_SLICES, \
BITS_PER_LONG)
/**
* struct dwc2_tt - dwc2 data associated with a usb_tt
*
* @refcount: Number of Queue Heads (QHs) holding a reference.
* @usb_tt: Pointer back to the official usb_tt.
* @periodic_bitmaps: Bitmap for which parts of the 1ms frame are accounted
* for already. Each is DWC2_ELEMENTS_PER_LS_BITMAP
* elements (so sizeof(long) times that in bytes).
*
* This structure is stored in the hcpriv of the official usb_tt.
*/
struct dwc2_tt {
int refcount;
struct usb_tt *usb_tt;
unsigned long periodic_bitmaps[];
};
/**
* struct dwc2_hs_transfer_time - Info about a transfer on the high speed bus.
*
* @start_schedule_usecs: The start time on the main bus schedule. Note that
* the main bus schedule is tightly packed and this
* time should be interpreted as tightly packed (so
* uFrame 0 starts at 0 us, uFrame 1 starts at 100 us
* instead of 125 us).
* @duration_us: How long this transfer goes.
*/
struct dwc2_hs_transfer_time {
u32 start_schedule_us;
u16 duration_us;
};
/**
* struct dwc2_qh - Software queue head structure
*
* @hsotg: The HCD state structure for the DWC OTG controller
* @ep_type: Endpoint type. One of the following values:
* - USB_ENDPOINT_XFER_CONTROL
* - USB_ENDPOINT_XFER_BULK
* - USB_ENDPOINT_XFER_INT
* - USB_ENDPOINT_XFER_ISOC
* @ep_is_in: Endpoint direction
* @maxp: Value from wMaxPacketSize field of Endpoint Descriptor
* @dev_speed: Device speed. One of the following values:
* - USB_SPEED_LOW
* - USB_SPEED_FULL
* - USB_SPEED_HIGH
* @data_toggle: Determines the PID of the next data packet for
* non-controltransfers. Ignored for control transfers.
* One of the following values:
* - DWC2_HC_PID_DATA0
* - DWC2_HC_PID_DATA1
* @ping_state: Ping state
* @do_split: Full/low speed endpoint on high-speed hub requires split
* @td_first: Index of first activated isochronous transfer descriptor
* @td_last: Index of last activated isochronous transfer descriptor
* @host_us: Bandwidth in microseconds per transfer as seen by host
* @device_us: Bandwidth in microseconds per transfer as seen by device
* @host_interval: Interval between transfers as seen by the host. If
* the host is high speed and the device is low speed this
* will be 8 times device interval.
* @device_interval: Interval between transfers as seen by the device.
* interval.
* @next_active_frame: (Micro)frame _before_ we next need to put something on
* the bus. We'll move the qh to active here. If the
* host is in high speed mode this will be a uframe. If
* the host is in low speed mode this will be a full frame.
* @start_active_frame: If we are partway through a split transfer, this will be
* what next_active_frame was when we started. Otherwise
* it should always be the same as next_active_frame.
* @num_hs_transfers: Number of transfers in hs_transfers.
* Normally this is 1 but can be more than one for splits.
* Always >= 1 unless the host is in low/full speed mode.
* @hs_transfers: Transfers that are scheduled as seen by the high speed
* bus. Not used if host is in low or full speed mode (but
* note that it IS USED if the device is low or full speed
* as long as the HOST is in high speed mode).
* @ls_start_schedule_slice: Start time (in slices) on the low speed bus
* schedule that's being used by this device. This
* will be on the periodic_bitmap in a
* "struct dwc2_tt". Not used if this device is high
* speed. Note that this is in "schedule slice" which
* is tightly packed.
* @ls_duration_us: Duration on the low speed bus schedule.
* @ntd: Actual number of transfer descriptors in a list
* @dw_align_buf: Used instead of original buffer if its physical address
* is not dword-aligned
* @dw_align_buf_dma: DMA address for dw_align_buf
* @qtd_list: List of QTDs for this QH
* @channel: Host channel currently processing transfers for this QH
* @qh_list_entry: Entry for QH in either the periodic or non-periodic
* schedule
* @desc_list: List of transfer descriptors
* @desc_list_dma: Physical address of desc_list
* @desc_list_sz: Size of descriptors list
* @n_bytes: Xfer Bytes array. Each element corresponds to a transfer
* descriptor and indicates original XferSize value for the
* descriptor
* @unreserve_timer: Timer for releasing periodic reservation.
* @dwc2_tt: Pointer to our tt info (or NULL if no tt).
* @ttport: Port number within our tt.
* @tt_buffer_dirty True if clear_tt_buffer_complete is pending
* @unreserve_pending: True if we planned to unreserve but haven't yet.
* @schedule_low_speed: True if we have a low/full speed component (either the
* host is in low/full speed mode or do_split).
*
* A Queue Head (QH) holds the static characteristics of an endpoint and
* maintains a list of transfers (QTDs) for that endpoint. A QH structure may
* be entered in either the non-periodic or periodic schedule.
*/
struct dwc2_qh {
struct dwc2_hsotg *hsotg;
u8 ep_type;
u8 ep_is_in;
u16 maxp;
u8 dev_speed;
u8 data_toggle;
u8 ping_state;
u8 do_split;
u8 td_first;
u8 td_last;
u16 host_us;
u16 device_us;
u16 host_interval;
u16 device_interval;
u16 next_active_frame;
u16 start_active_frame;
s16 num_hs_transfers;
struct dwc2_hs_transfer_time hs_transfers[DWC2_HS_SCHEDULE_UFRAMES];
u32 ls_start_schedule_slice;
u16 ntd;
u8 *dw_align_buf;
dma_addr_t dw_align_buf_dma;
#ifndef NO_GNU
struct list_head qtd_list;
#else
List_t qtd_list;
#endif
struct dwc2_host_chan *channel;
#ifndef NO_GNU
struct list_head qh_list_entry;
#else
ListItem_t qh_list_entry;
#endif
struct dwc2_dma_desc *desc_list;
dma_addr_t desc_list_dma;
u32 desc_list_sz;
u32 *n_bytes;
struct timer_list unreserve_timer;
struct dwc2_tt *dwc_tt;
int ttport;
unsigned tt_buffer_dirty:1;
unsigned unreserve_pending:1;
unsigned schedule_low_speed:1;
};
/**
* struct dwc2_qtd - Software queue transfer descriptor (QTD)
*
* @control_phase: Current phase for control transfers (Setup, Data, or
* Status)
* @in_process: Indicates if this QTD is currently processed by HW
* @data_toggle: Determines the PID of the next data packet for the
* data phase of control transfers. Ignored for other
* transfer types. One of the following values:
* - DWC2_HC_PID_DATA0
* - DWC2_HC_PID_DATA1
* @complete_split: Keeps track of the current split type for FS/LS
* endpoints on a HS Hub
* @isoc_split_pos: Position of the ISOC split in full/low speed
* @isoc_frame_index: Index of the next frame descriptor for an isochronous
* transfer. A frame descriptor describes the buffer
* position and length of the data to be transferred in the
* next scheduled (micro)frame of an isochronous transfer.
* It also holds status for that transaction. The frame
* index starts at 0.
* @isoc_split_offset: Position of the ISOC split in the buffer for the
* current frame
* @ssplit_out_xfer_count: How many bytes transferred during SSPLIT OUT
* @error_count: Holds the number of bus errors that have occurred for
* a transaction within this transfer
* @n_desc: Number of DMA descriptors for this QTD
* @isoc_frame_index_last: Last activated frame (packet) index, used in
* descriptor DMA mode only
* @urb: URB for this transfer
* @qh: Queue head for this QTD
* @qtd_list_entry: For linking to the QH's list of QTDs
*
* A Queue Transfer Descriptor (QTD) holds the state of a bulk, control,
* interrupt, or isochronous transfer. A single QTD is created for each URB
* (of one of these types) submitted to the HCD. The transfer associated with
* a QTD may require one or multiple transactions.
*
* A QTD is linked to a Queue Head, which is entered in either the
* non-periodic or periodic schedule for execution. When a QTD is chosen for
* execution, some or all of its transactions may be executed. After
* execution, the state of the QTD is updated. The QTD may be retired if all
* its transactions are complete or if an error occurred. Otherwise, it
* remains in the schedule so more transactions can be executed later.
*/
struct dwc2_qtd {
enum dwc2_control_phase control_phase;
u8 in_process;
u8 data_toggle;
u8 complete_split;
u8 isoc_split_pos;
u16 isoc_frame_index;
u16 isoc_split_offset;
u16 isoc_td_last;
u16 isoc_td_first;
u32 ssplit_out_xfer_count;
u8 error_count;
u8 n_desc;
u16 isoc_frame_index_last;
struct dwc2_hcd_urb *urb;
struct dwc2_qh *qh;
#ifndef NO_GNU
struct list_head qtd_list_entry;
#else
ListItem_t qtd_list_entry;
#endif
};
#ifdef DEBUG
struct hc_xfer_info {
struct dwc2_hsotg *hsotg;
struct dwc2_host_chan *chan;
};
#endif
u32 dwc2_calc_frame_interval(struct dwc2_hsotg *hsotg);
/* Gets the struct usb_hcd that contains a struct dwc2_hsotg */
static inline struct usb_hcd *dwc2_hsotg_to_hcd(struct dwc2_hsotg *hsotg)
{
return (struct usb_hcd *)hsotg->priv;
}
/*
* Inline used to disable one channel interrupt. Channel interrupts are
* disabled when the channel is halted or released by the interrupt handler.
* There is no need to handle further interrupts of that type until the
* channel is re-assigned. In fact, subsequent handling may cause crashes
* because the channel structures are cleaned up when the channel is released.
*/
static inline void disable_hc_int(struct dwc2_hsotg *hsotg, int chnum, u32 intr)
{
u32 mask = dwc2_readl(hsotg->regs + HCINTMSK(chnum));
mask &= ~intr;
dwc2_writel(mask, hsotg->regs + HCINTMSK(chnum));
}
void dwc2_hc_cleanup(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan);
void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
enum dwc2_halt_status halt_status);
void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg,
struct dwc2_host_chan *chan);
/*
* Reads HPRT0 in preparation to modify. It keeps the WC bits 0 so that if they
* are read as 1, they won't clear when written back.
*/
static inline u32 dwc2_read_hprt0(struct dwc2_hsotg *hsotg)
{
u32 hprt0 = dwc2_readl(hsotg->regs + HPRT0);
hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET | HPRT0_ENACHG | HPRT0_OVRCURRCHG);
return hprt0;
}
static inline u8 dwc2_hcd_get_ep_num(struct dwc2_hcd_pipe_info *pipe)
{
return pipe->ep_num;
}
static inline u8 dwc2_hcd_get_pipe_type(struct dwc2_hcd_pipe_info *pipe)
{
return pipe->pipe_type;
}
static inline u16 dwc2_hcd_get_mps(struct dwc2_hcd_pipe_info *pipe)
{
return pipe->mps;
}
static inline u8 dwc2_hcd_get_dev_addr(struct dwc2_hcd_pipe_info *pipe)
{
return pipe->dev_addr;
}
static inline u8 dwc2_hcd_is_pipe_isoc(struct dwc2_hcd_pipe_info *pipe)
{
return pipe->pipe_type == USB_ENDPOINT_XFER_ISOC;
}
static inline u8 dwc2_hcd_is_pipe_int(struct dwc2_hcd_pipe_info *pipe)
{
return pipe->pipe_type == USB_ENDPOINT_XFER_INT;
}
static inline u8 dwc2_hcd_is_pipe_bulk(struct dwc2_hcd_pipe_info *pipe)
{
return pipe->pipe_type == USB_ENDPOINT_XFER_BULK;
}
static inline u8 dwc2_hcd_is_pipe_control(struct dwc2_hcd_pipe_info *pipe)
{
return pipe->pipe_type == USB_ENDPOINT_XFER_CONTROL;
}
static inline u8 dwc2_hcd_is_pipe_in(struct dwc2_hcd_pipe_info *pipe)
{
return pipe->pipe_dir == USB_DIR_IN;
}
static inline u8 dwc2_hcd_is_pipe_out(struct dwc2_hcd_pipe_info *pipe)
{
return !dwc2_hcd_is_pipe_in(pipe);
}
void dwc2_hcd_irq(struct dwc2_hsotg *hsotg);
int dwc2_hcd_init(struct dwc2_hsotg *hsotg, struct usb_hcd *hcd);
void dwc2_hcd_remove(struct dwc2_hsotg *hsotg);
/* Transaction Execution Functions */
enum dwc2_transaction_type dwc2_hcd_select_transactions(
struct dwc2_hsotg *hsotg);
void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg,
enum dwc2_transaction_type tr_type);
/* Schedule Queue Functions */
/* Implemented in hcd_queue.c */
struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
struct dwc2_hcd_urb *urb,
gfp_t mem_flags);
void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
int sched_csplit);
void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb);
int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
struct dwc2_qh *qh);
/* Unlinks and frees a QTD */
static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg,
struct dwc2_qtd *qtd,
struct dwc2_qh *qh)
{
list_del(&qtd->qtd_list_entry);
#ifndef NO_GNU
kfree(qtd);
#else
list_add_tail(&qtd->qtd_list_entry, &hsotg->free_qtd_list);
#endif
qtd = NULL;
}
/* Descriptor DMA support functions */
void dwc2_hcd_start_xfer_ddma(struct dwc2_hsotg *hsotg,
struct dwc2_qh *qh);
void dwc2_hcd_complete_xfer_ddma(struct dwc2_hsotg *hsotg,
struct dwc2_host_chan *chan, int chnum,
enum dwc2_halt_status halt_status);
int dwc2_hcd_qh_init_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
gfp_t mem_flags);
void dwc2_hcd_qh_free_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
/* Check if QH is non-periodic */
#define dwc2_qh_is_non_per(_qh_ptr_) \
((_qh_ptr_)->ep_type == USB_ENDPOINT_XFER_BULK || \
(_qh_ptr_)->ep_type == USB_ENDPOINT_XFER_CONTROL)
#ifdef CONFIG_USB_DWC2_DEBUG_PERIODIC
static inline bool dbg_hc(struct dwc2_host_chan *hc) { return true; }
static inline bool dbg_qh(struct dwc2_qh *qh) { return true; }
static inline bool dbg_urb(struct urb *urb) { return true; }
static inline bool dbg_perio(void) { return true; }
#else /* !CONFIG_USB_DWC2_DEBUG_PERIODIC */
static inline bool dbg_hc(struct dwc2_host_chan *hc)
{
return hc->ep_type == USB_ENDPOINT_XFER_BULK ||
hc->ep_type == USB_ENDPOINT_XFER_CONTROL;
}
static inline bool dbg_qh(struct dwc2_qh *qh)
{
return qh->ep_type == USB_ENDPOINT_XFER_BULK ||
qh->ep_type == USB_ENDPOINT_XFER_CONTROL;
}
static inline bool dbg_urb(struct urb *urb)
{
return true;
/*return usb_pipetype(urb->pipe) == PIPE_BULK ||
usb_pipetype(urb->pipe) == PIPE_CONTROL;*/
}
static inline bool dbg_perio(void) { return false; }
#endif
/* High bandwidth multiplier as encoded in highspeed endpoint descriptors */
#define dwc2_hb_mult(wmaxpacketsize) (1 + (((wmaxpacketsize) >> 11) & 0x03))
/* Packet size for any kind of endpoint descriptor */
#define dwc2_max_packet(wmaxpacketsize) ((wmaxpacketsize) & 0x07ff)
/*
* Returns true if frame1 index is greater than frame2 index. The comparison
* is done modulo FRLISTEN_64_SIZE. This accounts for the rollover of the
* frame number when the max index frame number is reached.
*/
static inline bool dwc2_frame_idx_num_gt(u16 fr_idx1, u16 fr_idx2)
{
u16 diff = fr_idx1 - fr_idx2;
u16 sign = diff & (FRLISTEN_64_SIZE >> 1);
return diff && !sign;
}
/*
* Returns true if frame1 is less than or equal to frame2. The comparison is
* done modulo HFNUM_MAX_FRNUM. This accounts for the rollover of the
* frame number when the max frame number is reached.
*/
static inline int dwc2_frame_num_le(u16 frame1, u16 frame2)
{
return ((frame2 - frame1) & HFNUM_MAX_FRNUM) <= (HFNUM_MAX_FRNUM >> 1);
}
/*
* Returns true if frame1 is greater than frame2. The comparison is done
* modulo HFNUM_MAX_FRNUM. This accounts for the rollover of the frame
* number when the max frame number is reached.
*/
static inline int dwc2_frame_num_gt(u16 frame1, u16 frame2)
{
return (frame1 != frame2) &&
((frame1 - frame2) & HFNUM_MAX_FRNUM) < (HFNUM_MAX_FRNUM >> 1);
}
/*
* Increments frame by the amount specified by inc. The addition is done
* modulo HFNUM_MAX_FRNUM. Returns the incremented value.
*/
static inline u16 dwc2_frame_num_inc(u16 frame, u16 inc)
{
return (frame + inc) & HFNUM_MAX_FRNUM;
}
static inline u16 dwc2_frame_num_dec(u16 frame, u16 dec)
{
return (frame + HFNUM_MAX_FRNUM + 1 - dec) & HFNUM_MAX_FRNUM;
}
static inline u16 dwc2_full_frame_num(u16 frame)
{
return (frame & HFNUM_MAX_FRNUM) >> 3;
}
static inline u16 dwc2_micro_frame_num(u16 frame)
{
return frame & 0x7;
}
/*
* Returns the Core Interrupt Status register contents, ANDed with the Core
* Interrupt Mask register contents
*/
static inline u32 dwc2_read_core_intr(struct dwc2_hsotg *hsotg)
{
return dwc2_readl(hsotg->regs + GINTSTS) &
dwc2_readl(hsotg->regs + GINTMSK);
}
static inline u32 dwc2_hcd_urb_get_status(struct dwc2_hcd_urb *dwc2_urb)
{
return dwc2_urb->status;
}
static inline u32 dwc2_hcd_urb_get_actual_length(
struct dwc2_hcd_urb *dwc2_urb)
{
return dwc2_urb->actual_length;
}
static inline u32 dwc2_hcd_urb_get_error_count(struct dwc2_hcd_urb *dwc2_urb)
{
return dwc2_urb->error_count;
}
static inline void dwc2_hcd_urb_set_iso_desc_params(
struct dwc2_hcd_urb *dwc2_urb, int desc_num, u32 offset,
u32 length)
{
dwc2_urb->iso_descs[desc_num].offset = offset;
dwc2_urb->iso_descs[desc_num].length = length;
}
static inline u32 dwc2_hcd_urb_get_iso_desc_status(
struct dwc2_hcd_urb *dwc2_urb, int desc_num)
{
return dwc2_urb->iso_descs[desc_num].status;
}
static inline u32 dwc2_hcd_urb_get_iso_desc_actual_length(
struct dwc2_hcd_urb *dwc2_urb, int desc_num)
{
return dwc2_urb->iso_descs[desc_num].actual_length;
}
static inline int dwc2_hcd_is_bandwidth_allocated(struct dwc2_hsotg *hsotg,
struct usb_host_endpoint *ep)
{
struct dwc2_qh *qh = (struct dwc2_qh *)ep->hcpriv;
#ifndef NO_GNU
if (qh && !list_empty(&qh->qh_list_entry))
return 1;
#else
if (qh && !list_item_empty(&qh->qh_list_entry))
return 1;
#endif
return 0;
}
static inline u16 dwc2_hcd_get_ep_bandwidth(struct dwc2_hsotg *hsotg,
struct usb_host_endpoint *ep)
{
struct dwc2_qh *qh = (struct dwc2_qh *)ep->hcpriv;
if (!qh) {
WARN_ON(1);
return 0;
}
return qh->host_us;
}
void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg,
struct dwc2_host_chan *chan, int chnum,
struct dwc2_qtd *qtd);
/* HCD Core API */
/**
* dwc2_handle_hcd_intr() - Called on every hardware interrupt
*
* @hsotg: The DWC2 HCD
*
* Returns IRQ_HANDLED if interrupt is handled
* Return IRQ_NONE if interrupt is not handled
*/
irqreturn_t dwc2_handle_hcd_intr(struct dwc2_hsotg *hsotg);
/**
* dwc2_hcd_stop() - Halts the DWC_otg host mode operation
*
* @hsotg: The DWC2 HCD
*/
void dwc2_hcd_stop(struct dwc2_hsotg *hsotg);
/**
* dwc2_hcd_is_b_host() - Returns 1 if core currently is acting as B host,
* and 0 otherwise
*
* @hsotg: The DWC2 HCD
*/
int dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg);
/**
* dwc2_hcd_dump_state() - Dumps hsotg state
*
* @hsotg: The DWC2 HCD
*
* NOTE: This function will be removed once the peripheral controller code
* is integrated and the driver is stable
*/
void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg);
/**
* dwc2_hcd_dump_frrem() - Dumps the average frame remaining at SOF
*
* @hsotg: The DWC2 HCD
*
* This can be used to determine average interrupt latency. Frame remaining is
* also shown for start transfer and two additional sample points.
*
* NOTE: This function will be removed once the peripheral controller code
* is integrated and the driver is stable
*/
void dwc2_hcd_dump_frrem(struct dwc2_hsotg *hsotg);
/* URB interface */
/* Transfer flags */
#define URB_GIVEBACK_ASAP 0x1
#define URB_SEND_ZERO_PACKET 0x2
/* Host driver callbacks */
struct dwc2_tt *dwc2_host_get_tt_info(struct dwc2_hsotg *hsotg,
void *context, gfp_t mem_flags,
int *ttport);
void dwc2_host_put_tt_info(struct dwc2_hsotg *hsotg,
struct dwc2_tt *dwc_tt);
int dwc2_host_get_speed(struct dwc2_hsotg *hsotg, void *context);
void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
int status);
#ifdef DEBUG
/*
* Macro to sample the remaining PHY clocks left in the current frame. This
* may be used during debugging to determine the average time it takes to
* execute sections of code. There are two possible sample points, "a" and
* "b", so the _letter_ argument must be one of these values.
*
* To dump the average sample times, read the "hcd_frrem" sysfs attribute. For
* example, "cat /sys/devices/lm0/hcd_frrem".
*/
#define dwc2_sample_frrem(_hcd_, _qh_, _letter_) \
do { \
struct hfnum_data _hfnum_; \
struct dwc2_qtd *_qtd_; \
\
_qtd_ = list_entry((_qh_)->qtd_list.next, struct dwc2_qtd, \
qtd_list_entry); \
if (usb_pipeint(_qtd_->urb->pipe) && \
(_qh_)->start_active_frame != 0 && !_qtd_->complete_split) { \
_hfnum_.d32 = dwc2_readl((_hcd_)->regs + HFNUM); \
switch (_hfnum_.b.frnum & 0x7) { \
case 7: \
(_hcd_)->hfnum_7_samples_##_letter_++; \
(_hcd_)->hfnum_7_frrem_accum_##_letter_ += \
_hfnum_.b.frrem; \
break; \
case 0: \
(_hcd_)->hfnum_0_samples_##_letter_++; \
(_hcd_)->hfnum_0_frrem_accum_##_letter_ += \
_hfnum_.b.frrem; \
break; \
default: \
(_hcd_)->hfnum_other_samples_##_letter_++; \
(_hcd_)->hfnum_other_frrem_accum_##_letter_ += \
_hfnum_.b.frrem; \
break; \
} \
} \
} while (0)
#else
#define dwc2_sample_frrem(_hcd_, _qh_, _letter_) do {} while (0)
#endif
void dwc2_hcd_start_isr(struct dwc2_hsotg *hsotg);
#endif /* __DWC2_HCD_H__ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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