ameba-sdk-gcc-make/component/soc/realtek/8195a/fwlib/rtl8195a/src/rtl8195a_ssi.c
2016-06-04 19:09:35 +08:00

1271 lines
42 KiB
C
Executable file

/*
* 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 "rtl8195a_ssi.h"
#include "hal_ssi.h"
extern _LONG_CALL_
HAL_Status HalSsiInitRtl8195a(VOID *Adaptor);
extern _LONG_CALL_
u32 HalGetCpuClk(VOID);
VOID _SsiReadInterruptRtl8195a(VOID *Adapter)
{
SSI_DBG_ENTRANCE("_SsiReadInterrupt()\n");
PHAL_SSI_ADAPTOR pHalSsiAdapter = (PHAL_SSI_ADAPTOR) Adapter;
u32 ReceiveLevel;
volatile u32 Readable = HalSsiReadableRtl8195a(Adapter);
u8 Index = pHalSsiAdapter->Index;
while (Readable) {
ReceiveLevel = HalSsiGetRxFifoLevelRtl8195a(Adapter);
while (ReceiveLevel--) {
if (pHalSsiAdapter->RxData != NULL) {
if ((pHalSsiAdapter->DataFrameSize+1) > 8) {
// 16~9 bits mode
*((u16*)(pHalSsiAdapter->RxData)) = (u16)(HAL_SSI_READ32(Index, REG_DW_SSI_DR));
pHalSsiAdapter->RxData = (VOID*)(((u16*)pHalSsiAdapter->RxData) + 1);
}
else {
// 8~4 bits mode
*((u8*)(pHalSsiAdapter->RxData)) = (u8)(HAL_SSI_READ32(Index, REG_DW_SSI_DR));
pHalSsiAdapter->RxData = (VOID*)(((u8*)pHalSsiAdapter->RxData) + 1);
}
}
else {
// for Master mode, doing TX also will got RX data, so drop the dummy data
HAL_SSI_READ32(Index, REG_DW_SSI_DR);
}
if (pHalSsiAdapter->RxLength > 0) {
pHalSsiAdapter->RxLength--;
}
#if 0
else if (pHalSsiAdapter->RxLengthRemainder > 0) {
pHalSsiAdapter->RxLengthRemainder--;
}
// Fixed length receive Complete. (RxLength & RxLengthRemainder == 0)
if ((pHalSsiAdapter->RxLength == 0) && (pHalSsiAdapter->RxLengthRemainder == 0)) {
break;
}
#endif
if (pHalSsiAdapter->RxLength == 0) {
break;
}
}
if (pHalSsiAdapter->RxLength == 0) {
break;
}
Readable = HalSsiReadableRtl8195a(Adapter);
}
if ((pHalSsiAdapter->RxLength > 0) &&
(pHalSsiAdapter->RxLength < (pHalSsiAdapter->RxThresholdLevel+1))) {
SSI_DBG_INT_READ("Setting Rx FIFO Threshold Level to 1\n");
pHalSsiAdapter->RxThresholdLevel = 0;
HalSsiSetRxFifoThresholdLevelRtl8195a((VOID*)pHalSsiAdapter);
}
if (pHalSsiAdapter->RxLength == 0) {
DBG_SSI_INFO("_SsiReadInterruptRtl8195a: RX_Done\r\n");
pHalSsiAdapter->InterruptMask &= ~(BIT_IMR_RXFIM | BIT_IMR_RXOIM | BIT_IMR_RXUIM);
HalSsiSetInterruptMaskRtl8195a((VOID*)pHalSsiAdapter);
// if (pHalSsiAdapter->RxData != NULL) {
if (pHalSsiAdapter->RxCompCallback != NULL) {
pHalSsiAdapter->RxCompCallback(pHalSsiAdapter->RxCompCbPara);
}
// }
}
}
VOID _SsiWriteInterruptRtl8195a(VOID *Adapter)
{
SSI_DBG_ENTRANCE("_SsiWriteInterrupt()\n");
PHAL_SSI_ADAPTOR pHalSsiAdapter = (PHAL_SSI_ADAPTOR) Adapter;
u32 Writeable = HalSsiWriteableRtl8195a(Adapter);
u32 TxWriteMax = SSI_TX_FIFO_DEPTH - pHalSsiAdapter->TxThresholdLevel;
u8 Index = pHalSsiAdapter->Index;
if (Writeable) {
/* Disable Tx FIFO Empty IRQ */
pHalSsiAdapter->InterruptMask &= ~ BIT_IMR_TXEIM;
HalSsiSetInterruptMaskRtl8195a((VOID*)pHalSsiAdapter);
while (TxWriteMax--) {
if ((pHalSsiAdapter->DataFrameSize+1) > 8) {
// 16~9 bits mode
if (pHalSsiAdapter->TxData != NULL) {
HAL_SSI_WRITE16(Index, REG_DW_SSI_DR, *((u16*)(pHalSsiAdapter->TxData)));
pHalSsiAdapter->TxData = (VOID*)(((u16*)pHalSsiAdapter->TxData) + 1);
}
else {
// For master mode: Push a dummy to TX FIFO for Read
if (pHalSsiAdapter->Role == SSI_MASTER) {
HAL_SSI_WRITE16(Index, REG_DW_SSI_DR, (u16)SSI_DUMMY_DATA); // Dummy byte
}
}
}
else {
// 8~4 bits mode
if (pHalSsiAdapter->TxData != NULL) {
HAL_SSI_WRITE8(Index, REG_DW_SSI_DR, *((u8*)(pHalSsiAdapter->TxData)));
pHalSsiAdapter->TxData = (VOID*)(((u8*)pHalSsiAdapter->TxData) + 1);
}
else {
// For master mode: Push a dummy to TX FIFO for Read
if (pHalSsiAdapter->Role == SSI_MASTER) {
HAL_SSI_WRITE8(Index, REG_DW_SSI_DR, (u8)SSI_DUMMY_DATA); // Dummy byte
}
}
}
pHalSsiAdapter->TxLength--;
if (pHalSsiAdapter->TxLength == 0)
break;
}
/* Enable Tx FIFO Empty IRQ */
pHalSsiAdapter->InterruptMask |= BIT_IMR_TXEIM;
HalSsiSetInterruptMaskRtl8195a((VOID*)pHalSsiAdapter);
}
if (pHalSsiAdapter->TxLength == 0) {
DBG_SSI_INFO("_SsiWriteInterruptRtl8195a: TX_Done\r\n");
pHalSsiAdapter->InterruptMask &= ~(BIT_IMR_TXOIM | BIT_IMR_TXEIM);
HalSsiSetInterruptMaskRtl8195a((VOID*)pHalSsiAdapter);
// If it's not a dummy TX for master read SPI, then call the TX_done callback
if (pHalSsiAdapter->TxData != NULL) {
if (pHalSsiAdapter->TxCompCallback != NULL) {
pHalSsiAdapter->TxCompCallback(pHalSsiAdapter->TxCompCbPara);
}
}
}
}
u32 _SsiIrqHandleRtl8195a(VOID *Adaptor)
{
SSI_DBG_ENTRANCE("_SsiIrqHandle()\n");
PHAL_SSI_ADAPTOR pHalSsiAdaptor = (PHAL_SSI_ADAPTOR) Adaptor;
u32 InterruptStatus = HalSsiGetInterruptStatusRtl8195a(Adaptor);
u8 Index = pHalSsiAdaptor->Index;
if (InterruptStatus & BIT_ISR_TXOIS) {
SSI_DBG_INT_HNDLR("[INT][SSI%d] Transmit FIFO Overflow Interrupt\n", Index);
HAL_SSI_READ32(Index, REG_DW_SSI_TXOICR);
}
if (InterruptStatus & BIT_ISR_RXUIS) {
SSI_DBG_INT_HNDLR("[INT][SSI%d] Receive FIFO Underflow Interrupt\n", Index);
HAL_SSI_READ32(Index, REG_DW_SSI_RXUICR);
}
if (InterruptStatus & BIT_ISR_RXOIS) {
SSI_DBG_INT_HNDLR("[INT][SSI%d] Receive FIFO Overflow Interrupt\n", Index);
HAL_SSI_READ32(Index, REG_DW_SSI_RXOICR);
}
if (InterruptStatus & BIT_ISR_MSTIS) {
SSI_DBG_INT_HNDLR("[INT][SSI%d] Multi-Master Contention Interrupt\n", Index);
/* Another master is actively transferring data */
/* TODO: Do reading data... */
HAL_SSI_READ32(Index, REG_DW_SSI_MSTICR);
}
if ((InterruptStatus & BIT_ISR_RXFIS) ) {
SSI_DBG_INT_HNDLR("[INT][SSI%d] Receive FIFO Full Interrupt\n", Index);
_SsiReadInterruptRtl8195a(Adaptor);
}
if (InterruptStatus & BIT_ISR_TXEIS) {
/* Tx FIFO is empty, need to transfer data */
SSI_DBG_INT_HNDLR("[INT][SSI%d] Transmit FIFO Empty Interrupt\n", Index);
_SsiWriteInterruptRtl8195a(Adaptor);
}
return 0;
}
HAL_Status HalSsiInitRtl8195a_Patch(VOID *Adaptor)
{
SSI_DBG_ENTRANCE("HalSsiInitRtl8195a()\n");
PHAL_SSI_ADAPTOR pHalSsiAdaptor = (PHAL_SSI_ADAPTOR) Adaptor;
volatile IRQn_Type IrqNum;
u32 IRQ_UNKNOWN = -999;
u32 Ctrlr0Value = 0;
u32 Ctrlr1Value = 0;
u32 SerValue = 0;
u32 BaudrValue = 0;
u32 TxftlrValue = 0;
u32 RxftlrValue = 0;
u32 MwcrValue = 0;
u8 MicrowireTransferMode = pHalSsiAdaptor->MicrowireTransferMode;
u8 DataFrameFormat = pHalSsiAdaptor->DataFrameFormat;
u8 TransferMode = pHalSsiAdaptor->TransferMode;
u8 Index = pHalSsiAdaptor->Index;
u8 Role = pHalSsiAdaptor->Role;
if (Index > 2) {
DBG_SSI_ERR("HalSsiInitRtl8195a: Invalid SSI Idx %d\r\n", Index);
return HAL_ERR_PARA;
}
HalSsiPinmuxEnableRtl8195a_Patch(pHalSsiAdaptor);
HalSsiDisableRtl8195a(Adaptor);
/* REG_DW_SSI_CTRLR0 */
Ctrlr0Value |= BIT_CTRLR0_DFS(pHalSsiAdaptor->DataFrameSize);
Ctrlr0Value |= BIT_CTRLR0_FRF(pHalSsiAdaptor->DataFrameFormat);
Ctrlr0Value |= BIT_CTRLR0_SCPH(pHalSsiAdaptor->SclkPhase);
Ctrlr0Value |= BIT_CTRLR0_SCPOL(pHalSsiAdaptor->SclkPolarity);
Ctrlr0Value |= BIT_CTRLR0_TMOD(pHalSsiAdaptor->TransferMode);
Ctrlr0Value |= BIT_CTRLR0_CFS(pHalSsiAdaptor->ControlFrameSize);
if (Role == SSI_SLAVE)
Ctrlr0Value |= BIT_CTRLR0_SLV_OE(pHalSsiAdaptor->SlaveOutputEnable);
SSI_DBG_INIT("[1] Set SSI%d REG_DW_SSI_CTRLR0 Value: %X\n", Index, Ctrlr0Value);
HAL_SSI_WRITE32(Index, REG_DW_SSI_CTRLR0, Ctrlr0Value);
SSI_DBG_INIT("[2] SSI%d REG_DW_SSI_CTRLR0(%X) = %X\n", Index,
SSI0_REG_BASE + (SSI_REG_OFF * Index) + REG_DW_SSI_CTRLR0,
HAL_SSI_READ32(Index, REG_DW_SSI_CTRLR0));
/* REG_DW_SSI_TXFTLR */
TxftlrValue = BIT_TXFTLR_TFT(pHalSsiAdaptor->TxThresholdLevel);
SSI_DBG_INIT("[1] Set SSI%d REG_DW_SSI_TXFTLR Value: %X\n", Index, TxftlrValue);
HAL_SSI_WRITE32(Index, REG_DW_SSI_TXFTLR, TxftlrValue);
SSI_DBG_INIT("[2] SSI%d REG_DW_SSI_TXFTLR(%X) = %X\n", Index,
SSI0_REG_BASE + (SSI_REG_OFF * Index) + REG_DW_SSI_TXFTLR,
HAL_SSI_READ32(Index, REG_DW_SSI_TXFTLR));
/* REG_DW_SSI_RXFTLR */
RxftlrValue = BIT_RXFTLR_RFT(pHalSsiAdaptor->RxThresholdLevel);
SSI_DBG_INIT("[1] Set SSI%d REG_DW_SSI_RXFTLR Value: %X\n", Index, RxftlrValue);
HAL_SSI_WRITE32(Index, REG_DW_SSI_RXFTLR, RxftlrValue);
SSI_DBG_INIT("[2] SSI%d REG_DW_SSI_RXFTLR(%X) = %X\n", Index,
SSI0_REG_BASE + (SSI_REG_OFF * Index) + REG_DW_SSI_RXFTLR,
HAL_SSI_READ32(Index, REG_DW_SSI_RXFTLR));
/**
* Master Only
* REG_DW_SSI_CTRLR1, REG_DW_SSI_SER, REG_DW_SSI_BAUDR
*/
if (Role & SSI_MASTER) {
if ((TransferMode == TMOD_RO) || (TransferMode == TMOD_EEPROM_R) ||
((DataFrameFormat == FRF_NS_MICROWIRE) && (MicrowireTransferMode == MW_TMOD_SEQUENTIAL))) {
Ctrlr1Value = BIT_CTRLR1_NDF(pHalSsiAdaptor->DataFrameNumber);
SSI_DBG_INIT("[1] Set SSI%d REG_DW_SSI_CTRLR1 Value: %X\n", Index, Ctrlr1Value);
HAL_SSI_WRITE32(Index, REG_DW_SSI_CTRLR1, Ctrlr1Value);
SSI_DBG_INIT("[2] SSI%d REG_DW_SSI_CTRLR1(%X) = %X\n", Index,
SSI0_REG_BASE + (SSI_REG_OFF * Index) + REG_DW_SSI_CTRLR1,
HAL_SSI_READ32(Index, REG_DW_SSI_CTRLR1));
}
SerValue = BIT_SER_SER(1 << (pHalSsiAdaptor->SlaveSelectEnable));
SSI_DBG_INIT("[1] Set SSI%d REG_DW_SSI_SER Value: %X\n", Index, SerValue);
//HAL_SSI_WRITE32(Index, REG_DW_SSI_SER, SerValue);
HalSsiSetSlaveEnableRegisterRtl8195a(Adaptor, pHalSsiAdaptor->SlaveSelectEnable);
SSI_DBG_INIT("[2] SSI%d REG_DW_SSI_SER(%X) = %X\n", Index,
SSI0_REG_BASE + (SSI_REG_OFF * Index) + REG_DW_SSI_SER,
HalSsiGetSlaveEnableRegisterRtl8195a(Adaptor));
BaudrValue = BIT_BAUDR_SCKDV(pHalSsiAdaptor->ClockDivider);
SSI_DBG_INIT("[1] Set SSI%d REG_DW_SSI_BAUDR Value: %X\n", Index, BaudrValue);
HAL_SSI_WRITE32(Index, REG_DW_SSI_BAUDR, BaudrValue);
SSI_DBG_INIT("[2] SSI%d REG_DW_SSI_BAUDR(%X) = %X\n", Index,
SSI0_REG_BASE + (SSI_REG_OFF * Index) + REG_DW_SSI_BAUDR,
HAL_SSI_READ32(Index, REG_DW_SSI_BAUDR));
}
// Microwire
MwcrValue |= BIT_MWCR_MWMOD(pHalSsiAdaptor->MicrowireTransferMode);
MwcrValue |= BIT_MWCR_MDD(pHalSsiAdaptor->MicrowireDirection);
MwcrValue |= BIT_MWCR_MHS(pHalSsiAdaptor->MicrowireHandshaking);
SSI_DBG_INIT("[1] Set SSI%d REG_DW_SSI_MWCR Value: %X\n", Index, MwcrValue);
HAL_SSI_WRITE32(Index, REG_DW_SSI_MWCR, MwcrValue);
SSI_DBG_INIT("[2] SSI%d REG_DW_SSI_MWCR(%X) = %X\n", Index,
SSI0_REG_BASE + (SSI_REG_OFF * Index) + REG_DW_SSI_MWCR,
HAL_SSI_READ32(Index, REG_DW_SSI_MWCR));
SSI_DBG_INIT("SSI%d TransferMechanism: %d\n", Index, pHalSsiAdaptor->TransferMechanism);
if (pHalSsiAdaptor->TransferMechanism == SSI_DTM_INTERRUPT)
{
SSI_DBG_INIT("SSI%d Interrupt initialize, Interrupt: %X\n", Index, pHalSsiAdaptor->InterruptMask);
switch (Index) {
case 0:
IrqNum = SPI0_IRQ;
break;
case 1:
IrqNum = SPI1_IRQ;
break;
case 2:
IrqNum = SPI2_IRQ;
break;
default:
IrqNum = IRQ_UNKNOWN;
break;
}
if (likely(IrqNum != IRQ_UNKNOWN)) {
/* REG_DW_SSI_IMR */
HalSsiSetInterruptMaskRtl8195a(Adaptor);
pHalSsiAdaptor->IrqHandle.Data = (u32)pHalSsiAdaptor;
pHalSsiAdaptor->IrqHandle.IrqFun = (IRQ_FUN)_SsiIrqHandleRtl8195a;
pHalSsiAdaptor->IrqHandle.IrqNum = (IRQn_Type)IrqNum;
pHalSsiAdaptor->IrqHandle.Priority = pHalSsiAdaptor->InterruptPriority;
InterruptRegister(&pHalSsiAdaptor->IrqHandle);
InterruptEn(&pHalSsiAdaptor->IrqHandle);
}
else {
SSI_DBG_INIT("Unknown SSI Index.\n");
pHalSsiAdaptor->TransferMechanism = SSI_DTM_BASIC;
}
}
HalSsiEnableRtl8195a(Adaptor);
return HAL_OK;
}
HAL_Status HalSsiPinmuxEnableRtl8195a_Patch(VOID *Adaptor)
{
SSI_DBG_ENTRANCE("HalSsiPinmuxEnableRtl8195a()\n");
PHAL_SSI_ADAPTOR pHalSsiAdaptor = (PHAL_SSI_ADAPTOR) Adaptor;
volatile HAL_Status Result;
u32 PinmuxSelect = pHalSsiAdaptor->PinmuxSelect;
u8 Index = pHalSsiAdaptor->Index;
SSI_DBG_PINMUX("[1] SSI%d REG_SSI_MUX_CTRL(%X) = %X\n", Index,
PERI_ON_BASE + REG_SPI_MUX_CTRL,
HAL_READ32(PERI_ON_BASE, REG_SPI_MUX_CTRL));
switch (Index)
{
case 0:
{
ACTCK_SPI0_CCTRL(ON);
SLPCK_SPI0_CCTRL(ON);
PinCtrl(SPI0, PinmuxSelect, ON);
SPI0_FCTRL(ON);
Result = HAL_OK;
break;
}
case 1:
{
ACTCK_SPI1_CCTRL(ON);
SLPCK_SPI1_CCTRL(ON);
PinCtrl(SPI1, PinmuxSelect, ON);
SPI1_FCTRL(ON);
Result = HAL_OK;
break;
}
case 2:
{
ACTCK_SPI2_CCTRL(ON);
SLPCK_SPI2_CCTRL(ON);
PinCtrl(SPI2, PinmuxSelect, ON);
SPI2_FCTRL(ON);
Result = HAL_OK;
break;
}
default:
{
DBG_SSI_ERR("Invalid SSI Index %d!\n", Index);
Result = HAL_ERR_PARA;
break;
}
}
SSI_DBG_PINMUX("[2] SSI%d REG_SSI_MUX_CTRL(%X) = %X\n", Index,
PERI_ON_BASE + REG_SPI_MUX_CTRL,
HAL_READ32(PERI_ON_BASE, REG_SPI_MUX_CTRL));
return Result;
}
HAL_Status HalSsiPinmuxDisableRtl8195a(VOID *Adaptor)
{
SSI_DBG_ENTRANCE("HalSsiPinmuxEnableRtl8195a()\n");
PHAL_SSI_ADAPTOR pHalSsiAdaptor = (PHAL_SSI_ADAPTOR) Adaptor;
volatile HAL_Status Result;
u32 PinmuxSelect = pHalSsiAdaptor->PinmuxSelect;
u8 Index = pHalSsiAdaptor->Index;
SSI_DBG_PINMUX("[1] SSI%d REG_SSI_MUX_CTRL(%X) = %X\n", Index,
PERI_ON_BASE + REG_SPI_MUX_CTRL,
HAL_READ32(PERI_ON_BASE, REG_SPI_MUX_CTRL));
switch (Index)
{
case 0:
{
ACTCK_SPI0_CCTRL(OFF);
SLPCK_SPI0_CCTRL(OFF);
PinCtrl(SPI0, PinmuxSelect, OFF);
SPI0_FCTRL(OFF);
Result = HAL_OK;
break;
}
case 1:
{
ACTCK_SPI1_CCTRL(OFF);
SLPCK_SPI1_CCTRL(OFF);
PinCtrl(SPI1, PinmuxSelect, OFF);
SPI1_FCTRL(OFF);
Result = HAL_OK;
break;
}
case 2:
{
ACTCK_SPI2_CCTRL(OFF);
SLPCK_SPI2_CCTRL(OFF);
PinCtrl(SPI2, PinmuxSelect, OFF);
SPI2_FCTRL(OFF);
Result = HAL_OK;
break;
}
default:
{
DBG_SSI_ERR("Invalid SSI Index %d!\n", Index);
Result = HAL_ERR_PARA;
break;
}
}
SSI_DBG_PINMUX("[2] SSI%d REG_SSI_MUX_CTRL(%X) = %X\n", Index,
PERI_ON_BASE + REG_SPI_MUX_CTRL,
HAL_READ32(PERI_ON_BASE, REG_SPI_MUX_CTRL));
return Result;
}
HAL_Status HalSsiDeInitRtl8195a(VOID *Adapter)
{
PHAL_SSI_ADAPTOR pHalSsiAdapter = (PHAL_SSI_ADAPTOR) Adapter;
u8 Index;
volatile HAL_Status Result;
Index = pHalSsiAdapter->Index;
if(Index > 2){
DBG_SSI_ERR("Invalid SSI Index %d!\n", Index);
return HAL_ERR_PARA;
}
HalSsiInterruptDisableRtl8195a(pHalSsiAdapter);
HalSsiDisableRtl8195a(pHalSsiAdapter);
Result = HalSsiPinmuxDisableRtl8195a(pHalSsiAdapter);
if(Result != HAL_OK){
DBG_SSI_ERR("Pinmux Disable Error\n");
return Result;
}
return Result;
}
HAL_Status HalSsiClockOnRtl8195a(VOID *Adapter)
{
PHAL_SSI_ADAPTOR pHalSsiAdaptor = (PHAL_SSI_ADAPTOR) Adapter;
volatile HAL_Status Result;
u8 Index = pHalSsiAdaptor->Index;
switch (Index)
{
case 0:
{
ACTCK_SPI0_CCTRL(ON);
SLPCK_SPI0_CCTRL(ON);
Result = HAL_OK;
break;
}
case 1:
{
ACTCK_SPI1_CCTRL(ON);
SLPCK_SPI1_CCTRL(ON);
Result = HAL_OK;
break;
}
case 2:
{
ACTCK_SPI2_CCTRL(ON);
SLPCK_SPI2_CCTRL(ON);
Result = HAL_OK;
break;
}
default:
{
DBG_SSI_ERR("Invalid SSI Index %d!\n", Index);
Result = HAL_ERR_PARA;
break;
}
}
return Result;
}
HAL_Status HalSsiClockOffRtl8195a(VOID *Adapter)
{
PHAL_SSI_ADAPTOR pHalSsiAdaptor = (PHAL_SSI_ADAPTOR) Adapter;
volatile HAL_Status Result;
u8 Index = pHalSsiAdaptor->Index;
switch (Index)
{
case 0:
{
ACTCK_SPI0_CCTRL(OFF);
SLPCK_SPI0_CCTRL(OFF);
Result = HAL_OK;
break;
}
case 1:
{
ACTCK_SPI1_CCTRL(OFF);
SLPCK_SPI1_CCTRL(OFF);
Result = HAL_OK;
break;
}
case 2:
{
ACTCK_SPI2_CCTRL(OFF);
SLPCK_SPI2_CCTRL(OFF);
Result = HAL_OK;
break;
}
default:
{
DBG_SSI_ERR("Invalid SSI Index %d!\n", Index);
Result = HAL_ERR_PARA;
break;
}
}
return Result;
}
VOID HalSsiSetSclkRtl8195a(VOID *Adapter, u32 ClkRate)
{
PHAL_SSI_ADAPTOR pHalSsiAdapter = (PHAL_SSI_ADAPTOR) Adapter;
u32 ssi_clk;
u32 ClockDivider;
u32 SsiEn;
u32 RegValue;
u32 SystemClock;
u8 spi_idx = pHalSsiAdapter->Index;
// Set SCLK Freq only available for Master mode
// For Slave mode, the baud rate is depends on the Master side, max rate = ssi_clk/2
// Fsclk_out = Fssi_clk/SCKDV
SystemClock = HalGetCpuClk();
if (spi_idx == 1) {
ssi_clk = SystemClock >> 1;
RegValue = HAL_READ32(SYSTEM_CTRL_BASE, 0x250);
if (ClkRate > (ssi_clk/2)) {
// Use High speed clock: Fixed Freq.
RegValue |= BIT18;
ssi_clk = (200000000*5/6) >> 1;
}
else {
// Use Normal speed clock: CPU_Clk/2
RegValue &= ~BIT18;
}
HAL_WRITE32(SYSTEM_CTRL_BASE, 0x250, RegValue);
}
else {
ssi_clk = SystemClock >> 2;
}
if (pHalSsiAdapter->Role == SSI_MASTER) {
if (ClkRate > (ssi_clk/2)) {
DBG_SSI_ERR("spi_frequency: Freq %d is too high, available highest Freq=%d\r\n", ClkRate, (ssi_clk/2));
ClockDivider = 2;
}
else {
ClockDivider = ssi_clk/ClkRate + 1;
if ((ssi_clk%ClkRate) > (ClkRate/2)) {
ClockDivider++;
}
if (ClockDivider >= 0xFFFF) {
// devider is 16 bits
ClockDivider = 0xFFFE;
}
ClockDivider &= 0xFFFE; // bit 0 always is 0
}
DBG_SSI_INFO("spi_frequency: Set SCLK Freq=%d\r\n", (ssi_clk/ClockDivider));
pHalSsiAdapter->ClockDivider = ClockDivider;
SsiEn = HAL_SSI_READ32(spi_idx, REG_DW_SSI_SSIENR); // Backup SSI_EN register
// Disable SSI first, so we can modify the Clock Divider
RegValue = SsiEn & BIT_INVC_SSIENR_SSI_EN;
HAL_SSI_WRITE32(spi_idx, REG_DW_SSI_SSIENR, RegValue);
HAL_SSI_WRITE32(spi_idx, REG_DW_SSI_BAUDR, (pHalSsiAdapter->ClockDivider & 0xFFFF));
// recover the SSI_EN setting
HAL_SSI_WRITE32(spi_idx, REG_DW_SSI_SSIENR, SsiEn);
}
else {
if (ClkRate > (ssi_clk/10)) {
DBG_SSI_ERR("spi_frequency: Freq %d is too high, available highest Freq=%d\r\n", ClkRate, (ssi_clk/10));
}
}
}
HAL_Status HalSsiIntReadRtl8195a(VOID *Adapter, VOID *RxData, u32 Length)
{
PHAL_SSI_ADAPTOR pHalSsiAdapter = (PHAL_SSI_ADAPTOR) Adapter;
u32 RxFifoThresholdLevel;
u8 Index = pHalSsiAdapter->Index;
DBG_SSI_INFO("HalSsiIntReadRtl8195a: Idx=%d, RxData=0x%x, Len=0x%x\r\n", Index, RxData, Length);
if (HalSsiBusyRtl8195a(Adapter)) {
// As a Slave mode, if the peer(Master) side is power off, the BUSY flag is always on
DBG_SSI_WARN("HalSsiIntReadRtl8195a: SSI%d is busy\n", Index);
return HAL_BUSY;
}
if (Length == 0) {
SSI_DBG_INT_READ("SSI%d RxData addr: 0x%X, Length: %d\n", Index, RxData, Length);
return HAL_ERR_PARA;
}
if (Length > (pHalSsiAdapter->DefaultRxThresholdLevel)) {
RxFifoThresholdLevel = pHalSsiAdapter->DefaultRxThresholdLevel;
}
else {
RxFifoThresholdLevel = 0;
}
if (pHalSsiAdapter->RxThresholdLevel != RxFifoThresholdLevel) {
DBG_SSI_INFO("Setting Rx FIFO Threshold Level to %d\n", RxFifoThresholdLevel);
pHalSsiAdapter->RxThresholdLevel = RxFifoThresholdLevel;
HalSsiSetRxFifoThresholdLevelRtl8195a((VOID*)pHalSsiAdapter);
}
if ((pHalSsiAdapter->DataFrameSize+1) > 8) {
// 16~9 bits mode
pHalSsiAdapter->RxLength = Length >> 1; // 2 bytes(16 bit) every transfer
}
else {
// 8~4 bits mode
pHalSsiAdapter->RxLength = Length; // 1 byte(8 bit) every transfer
}
pHalSsiAdapter->RxData = RxData;
DBG_SSI_INFO("SSI%d RxData addr: 0x%X, Length: %d\n", Index,
pHalSsiAdapter->RxData, pHalSsiAdapter->RxLength);
pHalSsiAdapter->InterruptMask |= BIT_IMR_RXFIM | BIT_IMR_RXOIM | BIT_IMR_RXUIM;
HalSsiSetInterruptMaskRtl8195a((VOID*)pHalSsiAdapter);
return HAL_OK;
}
HAL_Status
HalSsiIntWriteRtl8195a(
IN VOID *Adapter, // PHAL_SSI_ADAPTOR
IN u8 *pTxData, // the Buffer to be send
IN u32 Length // the length of data to be send
)
{
PHAL_SSI_ADAPTOR pHalSsiAdapter = (PHAL_SSI_ADAPTOR) Adapter;
DBG_SSI_INFO("HalSsiIntWriteRtl8195a: Idx=%d, RxData=0x%x, Len=0x%x\r\n", pHalSsiAdapter->Index, pTxData, Length);
if ((Length == 0)) {
DBG_SSI_ERR("HalSsiIntSendRtl8195a: Err: pTxData=0x%x, Length=%d\n", pTxData, Length);
return HAL_ERR_PARA;
}
if ((pHalSsiAdapter->DataFrameSize+1) > 8) {
// 16~9 bits mode
pHalSsiAdapter->TxLength = Length >> 1; // 2 bytes(16 bit) every transfer
}
else {
// 8~4 bits mode
pHalSsiAdapter->TxLength = Length; // 1 byte(8 bit) every transfer
}
pHalSsiAdapter->TxData = (void*)pTxData;
pHalSsiAdapter->InterruptMask |= BIT_IMR_TXOIM | BIT_IMR_TXEIM;
HalSsiSetInterruptMaskRtl8195a((VOID*)pHalSsiAdapter);
return HAL_OK;
}
#ifdef CONFIG_GDMA_EN
/**
* GDMA IRQ Handler
*/
VOID SsiTxGdmaIrqHandle (VOID *Data)
{
PHAL_SSI_ADAPTOR pHalSsiAdapter = (PHAL_SSI_ADAPTOR) Data;
PSSI_DMA_CONFIG pDmaConfig = &pHalSsiAdapter->DmaConfig;;
PHAL_GDMA_ADAPTER pHalGdmaAdapter;
PHAL_GDMA_OP pHalGdmaOp;
pHalGdmaAdapter = (PHAL_GDMA_ADAPTER)pDmaConfig->pTxHalGdmaAdapter;
pHalGdmaOp = (PHAL_GDMA_OP)pDmaConfig->pHalGdmaOp;
/* Maintain Block Count */
#if 0
u8 IsrTypeMap = 0;
/* Clear Pending ISR */
IsrTypeMap = pHalGdmaOp->HalGdmaChIsrClean((VOID*)pHalGdmaAdapter);
if (IsrTypeMap & BlockType) {
DBG_SSI_WARN("DMA Block %d\n",pHalGdmaAdapter->MuliBlockCunt);
pHalGdmaAdapter->MuliBlockCunt++;
}
#else
/* Clear Pending ISR */
pHalGdmaOp->HalGdmaChIsrClean((VOID*)pHalGdmaAdapter);
#endif
#if 0
/* Set SSI DMA Disable */
HAL_SSI_WRITE32(pHalSsiAdapter->Index, REG_DW_SSI_DMACR, \
(HAL_SSI_READ32(pHalSsiAdapter->Index, REG_DW_SSI_DMACR) & ~SSI_TXDMA_ENABLE));
#endif
pHalGdmaOp->HalGdmaChDis((VOID*)(pHalGdmaAdapter));
// Call user TX complete callback
if (NULL != pHalSsiAdapter->TxCompCallback) {
pHalSsiAdapter->TxCompCallback(pHalSsiAdapter->TxCompCbPara);
}
}
VOID SsiRxGdmaIrqHandle (VOID *Data)
{
PHAL_SSI_ADAPTOR pHalSsiAdapter = (PHAL_SSI_ADAPTOR) Data;
PSSI_DMA_CONFIG pDmaConfig = &pHalSsiAdapter->DmaConfig;;
PHAL_GDMA_ADAPTER pHalGdmaAdapter;
PHAL_GDMA_OP pHalGdmaOp;
pHalGdmaAdapter = (PHAL_GDMA_ADAPTER)pDmaConfig->pRxHalGdmaAdapter;
pHalGdmaOp = (PHAL_GDMA_OP)pDmaConfig->pHalGdmaOp;
/* Maintain Block Count */
#if 0
u8 IsrTypeMap = 0;
/* Clear Pending ISR */
IsrTypeMap = pHalGdmaOp->HalGdmaChIsrClean((VOID*)pHalGdmaAdapter);
if (IsrTypeMap & BlockType) {
DBG_SSI_WARN("DMA Block %d\n",pHalGdmaAdapter->MuliBlockCunt);
pHalGdmaAdapter->MuliBlockCunt++;
}
#else
/* Clear Pending ISR */
pHalGdmaOp->HalGdmaChIsrClean((VOID*)pHalGdmaAdapter);
#endif
/* Set SSI DMA Disable */
HAL_SSI_WRITE32(pHalSsiAdapter->Index, REG_DW_SSI_DMACR, \
(HAL_SSI_READ32(pHalSsiAdapter->Index, REG_DW_SSI_DMACR) & ~SSI_RXDMA_ENABLE));
pHalGdmaOp->HalGdmaChDis((VOID*)(pHalGdmaAdapter));
// Call user RX complete callback
if (NULL != pHalSsiAdapter->RxCompCallback) {
pHalSsiAdapter->RxCompCallback(pHalSsiAdapter->RxCompCbPara);
}
}
VOID
HalSsiTxGdmaLoadDefRtl8195a(
IN VOID *Adapter
)
{
PHAL_SSI_ADAPTOR pHalSsiAdapter = (PHAL_SSI_ADAPTOR) Adapter;
PSSI_DMA_CONFIG pDmaConfig;
PHAL_GDMA_ADAPTER pHalGdmaAdapter;
u8 *pDst;
u8 DmaIdx;
u8 DmaCh;
u8 DstPer;
u8 ssi_idx;
u32 DmaChEn;
IRQn_Type IrqNum;
if ((NULL == pHalSsiAdapter)) {
return;
}
pDmaConfig = &pHalSsiAdapter->DmaConfig;
ssi_idx = pHalSsiAdapter->Index;
pHalGdmaAdapter = (PHAL_GDMA_ADAPTER)pDmaConfig->pTxHalGdmaAdapter;
if (NULL == pHalGdmaAdapter) {
DBG_SSI_ERR("HalSsiTxGdmaLoadDefRtl8195a: HalGdmaAdapter is NULL\r\n");
return;
}
_memset((void *)pHalGdmaAdapter, 0, sizeof(HAL_GDMA_ADAPTER));
pHalSsiAdapter->DmaControl |= SSI_TXDMA_ENABLE;
if ((pHalSsiAdapter->DataFrameSize+1) > 8) {
// 16~9 bits mode
pHalSsiAdapter->DmaTxDataLevel = 48; // When TX FIFO entity number <=48 then DMA Request asserted
}
else {
// 8~4 bits mode
pHalSsiAdapter->DmaTxDataLevel = 56; // When TX FIFO entity number <=56 then DMA Request asserted
}
switch (ssi_idx) {
case 0:
pDst = (u8*) (SSI0_REG_BASE + REG_DW_SSI_DR);
DmaIdx = 0;
DmaCh = 1;
DmaChEn = GdmaCh1;
IrqNum = GDMA0_CHANNEL1_IRQ;
DstPer = GDMA_HANDSHAKE_SSI0_TX;
break;
case 1:
pDst = (u8*) (SSI1_REG_BASE + REG_DW_SSI_DR);
DmaIdx = 1;
DmaCh = 1;
DmaChEn = GdmaCh1;
IrqNum = GDMA1_CHANNEL1_IRQ;
DstPer = GDMA_HANDSHAKE_SSI1_TX;
break;
case 2:
pDst = (u8*) (SSI2_REG_BASE + REG_DW_SSI_DR);
DmaIdx = 0; // SPI2 TX only can use GDMA0
DmaCh = 3;
DmaChEn = GdmaCh3;
IrqNum = GDMA0_CHANNEL3_IRQ;
DstPer = GDMA_HANDSHAKE_SSI2_TX;
break;
default:
return;
}
pHalGdmaAdapter->GdmaCtl.TtFc = TTFCMemToPeri;
pHalGdmaAdapter->GdmaCtl.Done = 1;
pHalGdmaAdapter->MuliBlockCunt = 0;
pHalGdmaAdapter->MaxMuliBlock = 1;
pHalGdmaAdapter->GdmaCfg.DestPer = DstPer;
pHalGdmaAdapter->ChDar = (u32)pDst;
pHalGdmaAdapter->GdmaIndex = DmaIdx;
pHalGdmaAdapter->ChNum = DmaCh;
pHalGdmaAdapter->ChEn = DmaChEn;
pHalGdmaAdapter->GdmaIsrType = (BlockType|TransferType|ErrType);
pHalGdmaAdapter->IsrCtrl = ENABLE;
pHalGdmaAdapter->GdmaOnOff = ON;
pHalGdmaAdapter->GdmaCtl.IntEn = 1;
pHalGdmaAdapter->GdmaCtl.SrcMsize = MsizeOne;
pHalGdmaAdapter->GdmaCtl.DestMsize = MsizeFour;
pHalGdmaAdapter->GdmaCtl.SrcTrWidth = TrWidthFourBytes;
pHalGdmaAdapter->GdmaCtl.DstTrWidth = TrWidthOneByte;
pHalGdmaAdapter->GdmaCtl.Dinc = NoChange;
pHalGdmaAdapter->GdmaCtl.Sinc = IncType;
pDmaConfig->TxGdmaIrqHandle.Data = (u32)pHalSsiAdapter;
pDmaConfig->TxGdmaIrqHandle.IrqNum = IrqNum;
pDmaConfig->TxGdmaIrqHandle.IrqFun = (IRQ_FUN)SsiTxGdmaIrqHandle;
pDmaConfig->TxGdmaIrqHandle.Priority = 0x10;
}
VOID
HalSsiRxGdmaLoadDefRtl8195a(
IN VOID *Adapter
)
{
PHAL_SSI_ADAPTOR pHalSsiAdapter = (PHAL_SSI_ADAPTOR) Adapter;
PSSI_DMA_CONFIG pDmaConfig;
PHAL_GDMA_ADAPTER pHalGdmaAdapter;
u8 *pSrc;
u8 DmaIdx;
u8 DmaCh;
u8 SrcPer;
u8 ssi_idx;
u32 DmaChEn;
IRQn_Type IrqNum;
if ((NULL == pHalSsiAdapter)) {
return;
}
pDmaConfig = &pHalSsiAdapter->DmaConfig;
ssi_idx = pHalSsiAdapter->Index;
pHalGdmaAdapter = (PHAL_GDMA_ADAPTER)pDmaConfig->pRxHalGdmaAdapter;
if (NULL == pHalGdmaAdapter) {
return;
}
_memset((void *)pHalGdmaAdapter, 0, sizeof(HAL_GDMA_ADAPTER));
pHalSsiAdapter->DmaControl |= SSI_RXDMA_ENABLE;
if ((pHalSsiAdapter->DataFrameSize+1) > 8) {
// 16~9 bits mode
pHalSsiAdapter->DmaRxDataLevel = 7; // RX FIFO stored bytes > (DMARDLR(7) + 1) then request DMA transfer
}
else {
// 8~4 bits mode
pHalSsiAdapter->DmaRxDataLevel = 3; // RX FIFO stored bytes > (DMARDLR(3) + 1) then request DMA transfer
}
switch (ssi_idx) {
case 0:
pSrc = (u8*) (SSI0_REG_BASE + REG_DW_SSI_DR);
DmaIdx = 0;
DmaCh = 2;
DmaChEn = GdmaCh2;
SrcPer = GDMA_HANDSHAKE_SSI0_RX;
IrqNum = GDMA0_CHANNEL2_IRQ;
break;
case 1:
pSrc = (u8*) (SSI1_REG_BASE + REG_DW_SSI_DR);
DmaIdx = 1;
DmaCh = 2;
DmaChEn = GdmaCh2;
SrcPer = GDMA_HANDSHAKE_SSI1_RX;
IrqNum = GDMA1_CHANNEL2_IRQ;
break;
case 2:
pSrc = (u8*) (SSI2_REG_BASE + REG_DW_SSI_DR);
DmaIdx = 1; // SSI2 RX only can use GDMA1
DmaCh = 3;
DmaChEn = GdmaCh3;
SrcPer = GDMA_HANDSHAKE_SSI2_RX;
IrqNum = GDMA1_CHANNEL3_IRQ;
break;
default:
return;
}
pHalGdmaAdapter->GdmaCtl.TtFc = TTFCPeriToMem;
pHalGdmaAdapter->GdmaCtl.Done = 1;
pHalGdmaAdapter->GdmaCfg.ReloadSrc = 1;
pHalGdmaAdapter->GdmaCfg.SrcPer = SrcPer;
pHalGdmaAdapter->MuliBlockCunt = 0;
pHalGdmaAdapter->MaxMuliBlock = 1;
pHalGdmaAdapter->ChSar = (u32)pSrc;
pHalGdmaAdapter->GdmaIndex = DmaIdx;
pHalGdmaAdapter->ChNum = DmaCh;
pHalGdmaAdapter->ChEn = DmaChEn;
pHalGdmaAdapter->GdmaIsrType = (BlockType|TransferType|ErrType);
pHalGdmaAdapter->IsrCtrl = ENABLE;
pHalGdmaAdapter->GdmaOnOff = ON;
pHalGdmaAdapter->GdmaCtl.IntEn = 1;
pHalGdmaAdapter->GdmaCtl.SrcMsize = MsizeEight;
pHalGdmaAdapter->GdmaCtl.DestMsize = MsizeFour;
pHalGdmaAdapter->GdmaCtl.SrcTrWidth = TrWidthTwoBytes;
pHalGdmaAdapter->GdmaCtl.DstTrWidth = TrWidthFourBytes;
pHalGdmaAdapter->GdmaCtl.Dinc = IncType;
pHalGdmaAdapter->GdmaCtl.Sinc = NoChange;
pDmaConfig->RxGdmaIrqHandle.Data = (u32)pHalSsiAdapter;
pDmaConfig->RxGdmaIrqHandle.IrqNum = IrqNum;
pDmaConfig->RxGdmaIrqHandle.IrqFun = (IRQ_FUN)SsiRxGdmaIrqHandle;
pDmaConfig->RxGdmaIrqHandle.Priority = 0x10;
}
VOID
HalSsiDmaInitRtl8195a(
IN VOID *Adapter
)
{
u32 RegValue;
PHAL_SSI_ADAPTOR pHalSsiAdapter = (PHAL_SSI_ADAPTOR) Adapter;
PSSI_DMA_CONFIG pDmaConfig;
PHAL_GDMA_ADAPTER pTxHalGdmaAdapter;
PHAL_GDMA_ADAPTER pRxHalGdmaAdapter;
u8 ssi_idx;
u32 hdk_tx_bit;
u32 hdk_rx_bit;
u32 DmatdlrValue = 0;
u32 DmardlrValue = 0;
pDmaConfig = &pHalSsiAdapter->DmaConfig;
pTxHalGdmaAdapter = (PHAL_GDMA_ADAPTER)pDmaConfig->pTxHalGdmaAdapter;
pRxHalGdmaAdapter = (PHAL_GDMA_ADAPTER)pDmaConfig->pRxHalGdmaAdapter;
ssi_idx = pHalSsiAdapter->Index;
// Set REG_PESOC_SOC_CTRL[28:16] to configure the GDMA handshake connection
// SSI2 handshake connection is hardware fixed
if (ssi_idx != 2) {
hdk_tx_bit = 16+pTxHalGdmaAdapter->GdmaCfg.DestPer;
hdk_rx_bit = 16+pRxHalGdmaAdapter->GdmaCfg.SrcPer;
}
else {
hdk_tx_bit = 0;
hdk_rx_bit = 0;
}
HalSsiDisableRtl8195a(pHalSsiAdapter);
RegValue = HAL_READ32(PERI_ON_BASE, REG_PESOC_SOC_CTRL);
if (pHalSsiAdapter->DmaControl & SSI_TXDMA_ENABLE) {
// TX DMA is enabled
if (pTxHalGdmaAdapter->GdmaIndex ==0) {
ACTCK_GDMA0_CCTRL(ON);
GDMA0_FCTRL(ON);
if (hdk_tx_bit != 0) {
RegValue &= ~(1<<hdk_tx_bit);
}
}
else {
ACTCK_GDMA1_CCTRL(ON);
GDMA1_FCTRL(ON);
if (hdk_tx_bit != 0) {
RegValue |= (1<<hdk_tx_bit);
}
}
/* Set TX FIFO water level to trigger Tx DMA transfer */
DmatdlrValue = BIT_DMATDLR_DMATDL(pHalSsiAdapter->DmaTxDataLevel);
HAL_SSI_WRITE32(ssi_idx, REG_DW_SSI_DMATDLR, DmatdlrValue);
/* Set SSI DMA Enable */
HAL_SSI_WRITE32(pHalSsiAdapter->Index, REG_DW_SSI_DMACR, \
(HAL_SSI_READ32(pHalSsiAdapter->Index, REG_DW_SSI_DMACR) | SSI_TXDMA_ENABLE));
}
if (pHalSsiAdapter->DmaControl & SSI_RXDMA_ENABLE) {
// RX DMA is enabled
if (pRxHalGdmaAdapter->GdmaIndex ==0) {
ACTCK_GDMA0_CCTRL(ON);
GDMA0_FCTRL(ON);
if (hdk_rx_bit != 0) {
RegValue &= ~(1<<hdk_rx_bit);
}
}
else {
ACTCK_GDMA1_CCTRL(ON);
GDMA1_FCTRL(ON);
if (hdk_rx_bit != 0) {
RegValue |= (1<<hdk_rx_bit);
}
}
/* Set RX FIFO water level to trigger Rx DMA transfer */
DmardlrValue = BIT_DMARDLR_DMARDL(pHalSsiAdapter->DmaRxDataLevel);
HAL_SSI_WRITE32(ssi_idx, REG_DW_SSI_DMARDLR, DmardlrValue);
// the RX DMA will be enabled at read start.
}
HAL_WRITE32(PERI_ON_BASE, REG_PESOC_SOC_CTRL, RegValue);
HalSsiEnableRtl8195a(pHalSsiAdapter);
}
HAL_Status
HalSsiDmaSendRtl8195a(
IN VOID *Adapter, // PHAL_SSI_ADAPTOR
IN u8 *pTxData, // the Buffer to be send
IN u32 Length // the length of data to be send
)
{
PHAL_SSI_ADAPTOR pHalSsiAdapter = (PHAL_SSI_ADAPTOR) Adapter;
PSSI_DMA_CONFIG pDmaConfig;
PHAL_GDMA_ADAPTER pHalGdmaAdapter;
PHAL_GDMA_OP pHalGdmaOp;
if ((pTxData == NULL) || (Length == 0)) {
DBG_SSI_ERR("HalSsiDmaSendRtl8195a: Err: pTxData=0x%x, Length=%d\n", pTxData, Length);
return HAL_ERR_PARA;
}
pDmaConfig = &pHalSsiAdapter->DmaConfig;
pHalGdmaAdapter = (PHAL_GDMA_ADAPTER)pDmaConfig->pTxHalGdmaAdapter;
pHalSsiAdapter->TxLength = Length;
pHalSsiAdapter->TxData = (void*)pTxData;
// Cofigure GDMA transfer
if ((pHalSsiAdapter->DataFrameSize+1) > 8) {
// 16~9 bits mode
if (((Length & 0x03)==0) &&
(((u32)(pTxData) & 0x03)==0)) {
// 4-bytes aligned, move 4 bytes each transfer
pHalGdmaAdapter->GdmaCtl.SrcMsize = MsizeFour;
pHalGdmaAdapter->GdmaCtl.SrcTrWidth = TrWidthFourBytes;
pHalGdmaAdapter->GdmaCtl.DestMsize = MsizeEight;
pHalGdmaAdapter->GdmaCtl.DstTrWidth = TrWidthTwoBytes;
pHalGdmaAdapter->GdmaCtl.BlockSize = Length >> 2;
}
else if (((Length & 0x01)==0) &&
(((u32)(pTxData) & 0x01)==0)) {
// 2-bytes aligned, move 2 bytes each transfer
pHalGdmaAdapter->GdmaCtl.SrcMsize = MsizeEight;
pHalGdmaAdapter->GdmaCtl.SrcTrWidth = TrWidthTwoBytes;
pHalGdmaAdapter->GdmaCtl.DestMsize = MsizeEight;
pHalGdmaAdapter->GdmaCtl.DstTrWidth = TrWidthTwoBytes;
pHalGdmaAdapter->GdmaCtl.BlockSize = Length >> 1;
}
else {
DBG_SSI_ERR("HalSsiDmaSendRtl8195a: Aligment Err: pTxData=0x%x, Length=%d\n", pTxData, Length);
return HAL_ERR_PARA;
}
}
else {
// 8~4 bits mode
if (((Length & 0x03)==0) &&
(((u32)(pTxData) & 0x03)==0)) {
// 4-bytes aligned, move 4 bytes each transfer
pHalGdmaAdapter->GdmaCtl.SrcMsize = MsizeOne;
pHalGdmaAdapter->GdmaCtl.SrcTrWidth = TrWidthFourBytes;
pHalGdmaAdapter->GdmaCtl.BlockSize = Length >> 2;
}
else {
pHalGdmaAdapter->GdmaCtl.SrcMsize = MsizeFour;
pHalGdmaAdapter->GdmaCtl.SrcTrWidth = TrWidthOneByte;
pHalGdmaAdapter->GdmaCtl.BlockSize = Length;
}
pHalGdmaAdapter->GdmaCtl.DestMsize = MsizeFour;
pHalGdmaAdapter->GdmaCtl.DstTrWidth = TrWidthOneByte;
}
DBG_SSI_INFO("SrcMsize=%d SrcTrWidth=%d DestMsize=%d DstTrWidth=%d BlockSize=%d\n", \
pHalGdmaAdapter->GdmaCtl.SrcMsize, pHalGdmaAdapter->GdmaCtl.SrcTrWidth, \
pHalGdmaAdapter->GdmaCtl.DestMsize, pHalGdmaAdapter->GdmaCtl.DstTrWidth, \
pHalGdmaAdapter->GdmaCtl.BlockSize);
if (pHalGdmaAdapter->GdmaCtl.BlockSize > 4096) {
// over Maximum block size 4096
DBG_SSI_ERR("HalSsiDmaSendRtl8195a: GDMA Block Size(%d) too big\n", pHalGdmaAdapter->GdmaCtl.BlockSize);
return HAL_ERR_PARA;
}
pHalGdmaAdapter->ChSar = (u32)pTxData;
// Enable GDMA for TX
pHalGdmaOp = (PHAL_GDMA_OP)pDmaConfig->pHalGdmaOp;
pHalGdmaOp->HalGdmaChSeting((VOID*)(pHalGdmaAdapter));
pHalGdmaOp->HalGdmaChEn((VOID*)(pHalGdmaAdapter));
#if 0
/* Set SSI DMA Enable */
// TODO: protect the enable DMA register, it may collision with the DMA disable in the GDMA done ISR
HAL_SSI_WRITE32(pHalSsiAdapter->Index, REG_DW_SSI_DMACR, \
(HAL_SSI_READ32(pHalSsiAdapter->Index, REG_DW_SSI_DMACR) | SSI_TXDMA_ENABLE));
#endif
return HAL_OK;
}
HAL_Status
HalSsiDmaRecvRtl8195a(
IN VOID *Adapter, // PHAL_SSI_ADAPTOR
IN u8 *pRxData, ///< Rx buffer
IN u32 Length // buffer length
)
{
PHAL_SSI_ADAPTOR pHalSsiAdapter = (PHAL_SSI_ADAPTOR) Adapter;
PSSI_DMA_CONFIG pDmaConfig;
PHAL_GDMA_ADAPTER pHalGdmaAdapter;
PHAL_GDMA_OP pHalGdmaOp;
if ((pRxData == NULL) || (Length == 0)) {
DBG_SSI_ERR("HalRuartDmaRecvRtl8195a: Null Err: pRxData=0x%x, Length=%d\n", pRxData, Length);
return HAL_ERR_PARA;
}
pDmaConfig = &pHalSsiAdapter->DmaConfig;
pHalGdmaAdapter = (PHAL_GDMA_ADAPTER)pDmaConfig->pRxHalGdmaAdapter;
pHalSsiAdapter->RxLength = Length;
pHalSsiAdapter->RxData = (void*)pRxData;
// Cofigure GDMA transfer
if ((pHalSsiAdapter->DataFrameSize+1) > 8) {
// 16~9 bits mode
pHalGdmaAdapter->GdmaCtl.SrcMsize = MsizeEight;
pHalGdmaAdapter->GdmaCtl.SrcTrWidth = TrWidthTwoBytes;
pHalGdmaAdapter->GdmaCtl.BlockSize = Length >> 1;
if (((Length & 0x03)==0) &&
(((u32)(pRxData) & 0x03)==0)) {
// 4-bytes aligned, move 4 bytes each transfer
pHalGdmaAdapter->GdmaCtl.DestMsize = MsizeFour;
pHalGdmaAdapter->GdmaCtl.DstTrWidth = TrWidthFourBytes;
}
else if (((Length & 0x01)==0) &&
(((u32)(pRxData) & 0x01)==0)) {
// 2-bytes aligned, move 2 bytes each transfer
pHalGdmaAdapter->GdmaCtl.DestMsize = MsizeEight;
pHalGdmaAdapter->GdmaCtl.DstTrWidth = TrWidthTwoBytes;
}
else {
DBG_SSI_ERR("HalSsiDmaSendRtl8195a: Aligment Err: pTxData=0x%x, Length=%d\n", pRxData, Length);
return HAL_ERR_PARA;
}
}
else {
// 8~4 bits mode
pHalGdmaAdapter->GdmaCtl.SrcMsize = MsizeFour;
pHalGdmaAdapter->GdmaCtl.SrcTrWidth = TrWidthOneByte;
pHalGdmaAdapter->GdmaCtl.BlockSize = Length;
if (((Length & 0x03)==0) &&
(((u32)(pRxData) & 0x03)==0)) {
// 4-bytes aligned, move 4 bytes each transfer
pHalGdmaAdapter->GdmaCtl.DestMsize = MsizeOne;
pHalGdmaAdapter->GdmaCtl.DstTrWidth = TrWidthFourBytes;
}
else {
pHalGdmaAdapter->GdmaCtl.DestMsize = MsizeFour;
pHalGdmaAdapter->GdmaCtl.DstTrWidth = TrWidthOneByte;
}
}
if (pHalGdmaAdapter->GdmaCtl.BlockSize > 4096) {
// over Maximum block size 4096
DBG_SSI_ERR("HalRuartDmaRecvRtl8195a: GDMA Block Size(%d) too big\n", pHalGdmaAdapter->GdmaCtl.BlockSize);
return HAL_ERR_PARA;
}
pHalGdmaAdapter->ChDar = (u32)pRxData;
// Enable GDMA for RX
pHalGdmaOp = (PHAL_GDMA_OP)pDmaConfig->pHalGdmaOp;
pHalGdmaOp->HalGdmaChSeting((VOID*)(pHalGdmaAdapter));
pHalGdmaOp->HalGdmaChEn((VOID*)(pHalGdmaAdapter));
/* Set SSI DMA Enable */
// TODO: protect the enable DMA register, it may collision with the DMA disable in the GDMA TX done ISR
HAL_SSI_WRITE32(pHalSsiAdapter->Index, REG_DW_SSI_DMACR, \
(HAL_SSI_READ32(pHalSsiAdapter->Index, REG_DW_SSI_DMACR) | SSI_RXDMA_ENABLE));
return HAL_OK;
}
#endif // end of "#ifdef CONFIG_GDMA_EN"