RTL00_HelloWorld/lib/fwlib/src/hal_ssi.c
2016-09-13 12:31:00 +03:00

377 lines
No EOL
13 KiB
C

/*
* Routines to access hardware
*
* Copyright (c) 2013 Realtek Semiconductor Corp.
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*/
#include "rtl8195a.h"
#include "hal_ssi.h"
const HAL_GDMA_CHNL Ssi2_TX_GDMA_Chnl_Option[] = {
{0,4,GDMA0_CHANNEL4_IRQ,0},
{0,5,GDMA0_CHANNEL5_IRQ,0},
{0,3,GDMA0_CHANNEL3_IRQ,0},
{0,0,GDMA0_CHANNEL0_IRQ,0},
{0,1,GDMA0_CHANNEL1_IRQ,0},
{0,2,GDMA0_CHANNEL2_IRQ,0},
{0xff,0,0,0} // end
};
const HAL_GDMA_CHNL Ssi2_RX_GDMA_Chnl_Option[] = {
{1,4,GDMA1_CHANNEL4_IRQ,0},
{1,5,GDMA1_CHANNEL5_IRQ,0},
{1,3,GDMA1_CHANNEL3_IRQ,0},
{1,0,GDMA1_CHANNEL0_IRQ,0},
{1,1,GDMA1_CHANNEL1_IRQ,0},
{1,2,GDMA1_CHANNEL2_IRQ,0},
{0xff,0,0,0} // end
};
//TODO: Load default Setting: It should be loaded from external setting file.
const DW_SSI_DEFAULT_SETTING SpiDefaultSetting =
{
.RxCompCallback = NULL,
.RxCompCbPara = NULL,
.RxData = NULL,
.TxCompCallback = NULL,
.TxCompCbPara = NULL,
.TxData = NULL,
.DmaRxDataLevel = 7, // RX FIFO stored bytes > (DMARDLR(7) + 1) then trigger DMA transfer
.DmaTxDataLevel = 48, // TX FIFO free space > (FIFO_SPACE(64)-DMATDLR(48)) then trigger DMA transfer
.InterruptPriority = 0x20,
.RxLength = 0,
.RxLengthRemainder = 0,
.RxThresholdLevel = 7, // if number of entries in th RX FIFO >= (RxThresholdLevel+1), RX interrupt asserted
.TxLength = 0,
.TxThresholdLevel = 8, // if number of entries in th TX FIFO <= TxThresholdLevel, TX interrupt asserted
.SlaveSelectEnable = 0,
.ClockDivider = SSI_CLK_SPI0_2/1000000, // SCLK=1M
.DataFrameNumber = 0,
.ControlFrameSize = CFS_1_BIT,
.DataFrameFormat = FRF_MOTOROLA_SPI,
.DataFrameSize = DFS_8_BITS,
.DmaControl = 0, // default DMA is disable
.InterruptMask = 0x0,
.MicrowireDirection = MW_DIRECTION_MASTER_TO_SLAVE,
.MicrowireHandshaking = MW_HANDSHAKE_DISABLE,
.MicrowireTransferMode = MW_TMOD_NONSEQUENTIAL,
.SclkPhase = SCPH_TOGGLES_AT_START,
.SclkPolarity = SCPOL_INACTIVE_IS_HIGH,
.SlaveOutputEnable = SLV_TXD_ENABLE, // Slave
.TransferMode = TMOD_TR,
.TransferMechanism = SSI_DTM_INTERRUPT
};
extern HAL_Status HalSsiInitRtl8195a_Patch(VOID *Adaptor);
extern HAL_Status HalSsiPinmuxEnableRtl8195a_Patch(VOID *Adaptor);
extern HAL_Status HalSsiPinmuxDisableRtl8195a(VOID *Adaptor);
extern HAL_Status HalSsiDeInitRtl8195a(VOID * Adapter);
extern HAL_Status HalSsiClockOffRtl8195a(VOID * Adapter);
extern HAL_Status HalSsiClockOnRtl8195a(VOID * Adapter);
extern HAL_Status HalSsiIntReadRtl8195a(VOID *Adapter, VOID *RxData, u32 Length);
extern HAL_Status HalSsiIntWriteRtl8195a(VOID *Adapter, u8 *pTxData, u32 Length);
extern VOID HalSsiSetSclkRtl8195a(VOID *Adapter, u32 ClkRate);
#ifdef CONFIG_GDMA_EN
extern VOID HalSsiDmaInitRtl8195a(VOID *Adapter);
#endif
VOID HalSsiOpInit(VOID *Adaptor)
{
PHAL_SSI_OP pHalSsiOp = (PHAL_SSI_OP) Adaptor;
// pHalSsiOp->HalSsiPinmuxEnable = HalSsiPinmuxEnableRtl8195a;
pHalSsiOp->HalSsiPinmuxEnable = HalSsiPinmuxEnableRtl8195a_Patch;
pHalSsiOp->HalSsiPinmuxDisable = HalSsiPinmuxDisableRtl8195a;
pHalSsiOp->HalSsiEnable = HalSsiEnableRtl8195a;
pHalSsiOp->HalSsiDisable = HalSsiDisableRtl8195a;
// pHalSsiOp->HalSsiInit = HalSsiInitRtl8195a;
pHalSsiOp->HalSsiInit = HalSsiInitRtl8195a_Patch;
pHalSsiOp->HalSsiSetSclkPolarity = HalSsiSetSclkPolarityRtl8195a;
pHalSsiOp->HalSsiSetSclkPhase = HalSsiSetSclkPhaseRtl8195a;
pHalSsiOp->HalSsiWrite = HalSsiWriteRtl8195a;
pHalSsiOp->HalSsiRead = HalSsiReadRtl8195a;
pHalSsiOp->HalSsiGetRxFifoLevel = HalSsiGetRxFifoLevelRtl8195a;
pHalSsiOp->HalSsiGetTxFifoLevel = HalSsiGetTxFifoLevelRtl8195a;
pHalSsiOp->HalSsiGetStatus = HalSsiGetStatusRtl8195a;
pHalSsiOp->HalSsiGetInterruptStatus = HalSsiGetInterruptStatusRtl8195a;
pHalSsiOp->HalSsiLoadSetting = HalSsiLoadSettingRtl8195a;
pHalSsiOp->HalSsiSetInterruptMask = HalSsiSetInterruptMaskRtl8195a;
pHalSsiOp->HalSsiGetInterruptMask = HalSsiGetInterruptMaskRtl8195a;
pHalSsiOp->HalSsiSetDeviceRole = HalSsiSetDeviceRoleRtl8195a;
pHalSsiOp->HalSsiWriteable = HalSsiWriteableRtl8195a;
pHalSsiOp->HalSsiReadable = HalSsiReadableRtl8195a;
pHalSsiOp->HalSsiBusy = HalSsiBusyRtl8195a;
pHalSsiOp->HalSsiInterruptEnable = HalSsiInterruptEnableRtl8195a;
pHalSsiOp->HalSsiInterruptDisable = HalSsiInterruptDisableRtl8195a;
// pHalSsiOp->HalSsiReadInterrupt = HalSsiReadInterruptRtl8195a;
pHalSsiOp->HalSsiReadInterrupt = HalSsiIntReadRtl8195a;
pHalSsiOp->HalSsiSetRxFifoThresholdLevel = HalSsiSetRxFifoThresholdLevelRtl8195a;
pHalSsiOp->HalSsiSetTxFifoThresholdLevel = HalSsiSetTxFifoThresholdLevelRtl8195a;
// pHalSsiOp->HalSsiWriteInterrupt = HalSsiWriteInterruptRtl8195a;
pHalSsiOp->HalSsiWriteInterrupt = HalSsiIntWriteRtl8195a;
pHalSsiOp->HalSsiGetRawInterruptStatus = HalSsiGetRawInterruptStatusRtl8195a;
pHalSsiOp->HalSsiGetSlaveEnableRegister = HalSsiGetSlaveEnableRegisterRtl8195a;
pHalSsiOp->HalSsiSetSlaveEnableRegister = HalSsiSetSlaveEnableRegisterRtl8195a;
}
#ifdef CONFIG_GDMA_EN
HAL_Status
HalSsiTxGdmaInit(
IN PHAL_SSI_OP pHalSsiOp,
IN PHAL_SSI_ADAPTOR pHalSsiAdapter
)
{
PHAL_GDMA_ADAPTER pHalGdmaAdapter;
PSSI_DMA_CONFIG pDmaConfig;
HAL_GDMA_CHNL *pgdma_chnl;
PHAL_GDMA_OP pHalGdmaOp;
if ((NULL == pHalSsiOp) || (NULL == pHalSsiAdapter)) {
return HAL_ERR_PARA;
}
pDmaConfig = &pHalSsiAdapter->DmaConfig;
// Load default setting
HalSsiTxGdmaLoadDefRtl8195a((void*)pHalSsiAdapter);
// Start to patch the default setting
pHalGdmaAdapter = (PHAL_GDMA_ADAPTER)pDmaConfig->pTxHalGdmaAdapter;
if (HalGdmaChnlRegister(pHalGdmaAdapter->GdmaIndex, pHalGdmaAdapter->ChNum) != HAL_OK) {
// The default GDMA Channel is not available, try others
if (pHalSsiAdapter->Index == 2) {
// SSI2 TX Only can use GDMA 0
pgdma_chnl = HalGdmaChnlAlloc((HAL_GDMA_CHNL*)Ssi2_TX_GDMA_Chnl_Option);
}
else {
pgdma_chnl = HalGdmaChnlAlloc(NULL);
}
if (pgdma_chnl == NULL) {
// No Available DMA channel
return HAL_BUSY;
}
else {
pHalGdmaAdapter->GdmaIndex = pgdma_chnl->GdmaIndx;
pHalGdmaAdapter->ChNum = pgdma_chnl->GdmaChnl;
pHalGdmaAdapter->ChEn = 0x0101 << pgdma_chnl->GdmaChnl;
pDmaConfig->TxGdmaIrqHandle.IrqNum = pgdma_chnl->IrqNum;
}
}
DBG_SSI_INFO("HalSsiTxGdmaInit: GdmaIndex=%d ChNum=%d \r\n", pHalGdmaAdapter->GdmaIndex, pHalGdmaAdapter->ChNum);
pHalGdmaOp = (PHAL_GDMA_OP)pDmaConfig->pHalGdmaOp;
pHalGdmaOp->HalGdmaOnOff((VOID*)(pHalGdmaAdapter));
pHalGdmaOp->HalGdmaChIsrEnAndDis((VOID*)(pHalGdmaAdapter));
HalSsiDmaInit(pHalSsiAdapter);
InterruptRegister(&pDmaConfig->TxGdmaIrqHandle);
InterruptEn(&pDmaConfig->TxGdmaIrqHandle);
return HAL_OK;
}
VOID
HalSsiTxGdmaDeInit(
IN PHAL_SSI_ADAPTOR pHalSsiAdapter
)
{
PSSI_DMA_CONFIG pDmaConfig;
PHAL_GDMA_ADAPTER pHalGdmaAdapter;
HAL_GDMA_CHNL GdmaChnl;
if (NULL == pHalSsiAdapter) {
return;
}
pDmaConfig = &pHalSsiAdapter->DmaConfig;
pHalGdmaAdapter = (PHAL_GDMA_ADAPTER)pDmaConfig->pTxHalGdmaAdapter;
GdmaChnl.GdmaIndx = pHalGdmaAdapter->GdmaIndex;
GdmaChnl.GdmaChnl = pHalGdmaAdapter->ChNum;
GdmaChnl.IrqNum = pDmaConfig->TxGdmaIrqHandle.IrqNum;
HalGdmaChnlFree(&GdmaChnl);
}
HAL_Status
HalSsiRxGdmaInit(
IN PHAL_SSI_OP pHalSsiOp,
IN PHAL_SSI_ADAPTOR pHalSsiAdapter
)
{
PHAL_GDMA_ADAPTER pHalGdmaAdapter;
PSSI_DMA_CONFIG pDmaConfig;
HAL_GDMA_CHNL *pgdma_chnl;
PHAL_GDMA_OP pHalGdmaOp;
if ((NULL == pHalSsiOp) || (NULL == pHalSsiAdapter)) {
return HAL_ERR_PARA;
}
pDmaConfig = &pHalSsiAdapter->DmaConfig;
// Load default setting
HalSsiRxGdmaLoadDefRtl8195a((void*)pHalSsiAdapter);
// Start to patch the default setting
pHalGdmaAdapter = (PHAL_GDMA_ADAPTER)pDmaConfig->pRxHalGdmaAdapter;
if (HalGdmaChnlRegister(pHalGdmaAdapter->GdmaIndex, pHalGdmaAdapter->ChNum) != HAL_OK) {
// The default GDMA Channel is not available, try others
if (pHalSsiAdapter->Index == 2) {
// SSI2 RX Only can use GDMA 1
pgdma_chnl = HalGdmaChnlAlloc((HAL_GDMA_CHNL*)Ssi2_RX_GDMA_Chnl_Option);
}
else {
pgdma_chnl = HalGdmaChnlAlloc(NULL);
}
if (pgdma_chnl == NULL) {
// No Available DMA channel
return HAL_BUSY;
}
else {
pHalGdmaAdapter->GdmaIndex = pgdma_chnl->GdmaIndx;
pHalGdmaAdapter->ChNum = pgdma_chnl->GdmaChnl;
pHalGdmaAdapter->ChEn = 0x0101 << pgdma_chnl->GdmaChnl;
pDmaConfig->RxGdmaIrqHandle.IrqNum = pgdma_chnl->IrqNum;
}
}
DBG_SSI_INFO("HalSsiRxGdmaInit: GdmaIndex=%d ChNum=%d \r\n", pHalGdmaAdapter->GdmaIndex, pHalGdmaAdapter->ChNum);
pHalGdmaOp = (PHAL_GDMA_OP)pDmaConfig->pHalGdmaOp;
pHalGdmaOp->HalGdmaOnOff((VOID*)(pHalGdmaAdapter));
pHalGdmaOp->HalGdmaChIsrEnAndDis((VOID*)(pHalGdmaAdapter));
HalSsiDmaInit(pHalSsiAdapter);
InterruptRegister(&pDmaConfig->RxGdmaIrqHandle);
InterruptEn(&pDmaConfig->RxGdmaIrqHandle);
return HAL_OK;
}
VOID
HalSsiRxGdmaDeInit(
IN PHAL_SSI_ADAPTOR pHalSsiAdapter
)
{
PSSI_DMA_CONFIG pDmaConfig;
PHAL_GDMA_ADAPTER pHalGdmaAdapter;
HAL_GDMA_CHNL GdmaChnl;
if (NULL == pHalSsiAdapter) {
return;
}
pDmaConfig = &pHalSsiAdapter->DmaConfig;
pHalGdmaAdapter = (PHAL_GDMA_ADAPTER)pDmaConfig->pRxHalGdmaAdapter;
GdmaChnl.GdmaIndx = pHalGdmaAdapter->GdmaIndex;
GdmaChnl.GdmaChnl = pHalGdmaAdapter->ChNum;
GdmaChnl.IrqNum = pDmaConfig->RxGdmaIrqHandle.IrqNum;
HalGdmaChnlFree(&GdmaChnl);
}
#endif // end of "#ifdef CONFIG_GDMA_EN"
HAL_Status
HalSsiInit(VOID *Data)
{
HAL_Status ret;
PHAL_SSI_ADAPTOR pHalSsiAdapter = (PHAL_SSI_ADAPTOR) Data;
#ifdef CONFIG_SOC_PS_MODULE
REG_POWER_STATE SsiPwrState;
#endif
ret = HalSsiInitRtl8195a_Patch(pHalSsiAdapter);
#ifdef CONFIG_SOC_PS_MODULE
if(ret == HAL_OK) {
// To register a new peripheral device power state
SsiPwrState.FuncIdx = SPI0+ pHalSsiAdapter->Index;
SsiPwrState.PwrState = ACT;
RegPowerState(SsiPwrState);
}
#endif
return ret;
}
HAL_Status
HalSsiDeInit(VOID *Data)
{
HAL_Status ret;
PHAL_SSI_ADAPTOR pHalSsiAdapter = (PHAL_SSI_ADAPTOR) Data;
#ifdef CONFIG_SOC_PS_MODULE
REG_POWER_STATE SsiPwrState;
u8 HardwareState;
SsiPwrState.FuncIdx= SPI0+ pHalSsiAdapter->Index;
QueryRegPwrState(SsiPwrState.FuncIdx, &(SsiPwrState.PwrState), &HardwareState);
if(SsiPwrState.PwrState != HardwareState){
DBG_SSI_ERR("Registered State is not the Hardware State");
return HAL_ERR_UNKNOWN;
}
else{
if((SsiPwrState.PwrState != INACT) && (SsiPwrState.PwrState !=ACT)){
DBG_SSI_INFO("Return to ACT state before DeInit");
HalSsiEnable(pHalSsiAdapter);
QueryRegPwrState(SsiPwrState.FuncIdx, &(SsiPwrState.PwrState), &HardwareState);
}
if(SsiPwrState.PwrState == ACT){
SsiPwrState.PwrState = INACT;
RegPowerState(SsiPwrState);
}
}
#endif
ret = HalSsiDeInitRtl8195a(pHalSsiAdapter);
return ret;
}
HAL_Status
HalSsiEnable(VOID *Data)
{
HAL_Status ret;
PHAL_SSI_ADAPTOR pHalSsiAdapter = (PHAL_SSI_ADAPTOR) Data;
#ifdef CONFIG_SOC_PS_MODULE
REG_POWER_STATE SsiPwrState;
#endif
ret = HalSsiClockOnRtl8195a(pHalSsiAdapter);
#ifdef CONFIG_SOC_PS_MODULE
if(ret == HAL_OK) {
// To register a new peripheral device power state
SsiPwrState.FuncIdx = SPI0+ pHalSsiAdapter->Index;
SsiPwrState.PwrState = ACT;
RegPowerState(SsiPwrState);
}
#endif
return ret;
}
HAL_Status
HalSsiDisable(VOID *Data)
{
HAL_Status ret;
PHAL_SSI_ADAPTOR pHalSsiAdapter = (PHAL_SSI_ADAPTOR) Data;
#ifdef CONFIG_SOC_PS_MODULE
REG_POWER_STATE SsiPwrState;
#endif
ret = HalSsiClockOffRtl8195a(pHalSsiAdapter);
#ifdef CONFIG_SOC_PS_MODULE
if(ret == HAL_OK) {
// To register a new peripheral device power state
SsiPwrState.FuncIdx = SPI0+ pHalSsiAdapter->Index;
SsiPwrState.PwrState = SLPCG;
RegPowerState(SsiPwrState);
}
#endif
return ret;
}