// Copyright (c) Samsung Electronics. Co. LTD. All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Module Name : SPI.C
//
// Abstract : SPI Interface Routines for Samsung S3C6410 CPU
//
// Environment : Samsung S3C6410 / WinCE6.0
//
// 2008/10/
//
//-------------------------------------------------------------------------------------------------------------------------
#include <bsp.h>
#include <memory.h>
#include "spi.h"
#include "s3c6410_dma_controller.h"
#define MASTER_CS_ENABLE pSPIregs->SLAVE_SEL = 0
#define MASTER_CS_DISABLE pSPIregs->SLAVE_SEL = 1
#define TRAIL_CNT(n) (((n)&0x3FF)<<19)
#define SPI_POWER_ON (1<<21)
#define SPI_SCLK_ON (1<<20)
#define SPI_USBHOST_ON (1<<22)
#define PCLOCK (0)
#define USB_HOST_CLOCK (1)
#define EPLL_CLOCK (2)
#define SPI_CLOCK EPLL_CLOCK
#if (SPI_CLOCK == EPLL_CLOCK)
#define CLKSEL CLKSEL_EPLL
#elif (SPI_CLOCK == USB_HOST_CLOCK)
#define CLKSEL CLKSEL_USBCLK
#elif (SPI_CLOCK == PCLOCK)
#define CLKSEL CLKSEL_PCLK
#endif
//#define TEST_MODE
// MSG
#define SPI_MSG 0
#define SPI_INIT 1
S3C6410_SPI_REG *pRestoreSPIregs = NULL;
#define WRITE_TIME_OUT_CONSTANT 5000
#define WRITE_TIME_OUT_MULTIPLIER 1
#define READ_TIME_OUT_CONSTANT 5000
#define READ_TIME_OUT_MULTIPLIER 1
DWORD HW_Init(PSPI_PUBLIC_CONTEXT pPublicSpi);
DWORD ThreadForTx(PSPI_PUBLIC_CONTEXT pPublicSpi);
DWORD ThreadForRx(PSPI_PUBLIC_CONTEXT pPublicSpi);
DWORD ThreadForSpi(PSPI_PUBLIC_CONTEXT pPublicSpi);
DWORD ThreadForRxDmaDone(PSPI_PUBLIC_CONTEXT pPublicSpi);
DWORD ThreadForTxDmaDone(PSPI_PUBLIC_CONTEXT pPublicSpi);
static DMA_CH_CONTEXT g_OutputDMA;
static DMA_CH_CONTEXT g_InputDMA;
//DMA
//UINT nDmaLen;
UINT DmaDstAddress;
UINT DmaSrcAddress;
//DMA Buffer Address Alloc
#define Buffer_Mem_Size 1504
//Memory Physical Address
PHYSICAL_ADDRESS PhysDmaDstBufferAddr;
PHYSICAL_ADDRESS PhysDmaSrcBufferAddr;
// DMA Buffer Address Alloc
PBYTE pVirtDmaDstBufferAddr = NULL;
PBYTE pVirtDmaSrcBufferAddr = NULL;
BOOL
DllEntry(
HINSTANCE hinstDll,
DWORD dwReason,
LPVOID lpReserved
)
{
if ( dwReason == DLL_PROCESS_ATTACH )
{
DEBUGMSG (1, (TEXT("[SPI] Process Attach\r\n")));
}
if ( dwReason == DLL_PROCESS_DETACH )
{
DEBUGMSG (1, (TEXT("[SPI] Process Detach\r\n")));
}
return(TRUE);
}
DWORD
HW_Init(
PSPI_PUBLIC_CONTEXT pPublicSpi
)
{
BOOL bResult = TRUE;
PHYSICAL_ADDRESS ioPhysicalBase = {0,0};
if ( !pPublicSpi )
{
bResult = FALSE;
goto CleanUp;
}
// GPIO Virtual alloc
ioPhysicalBase.LowPart = S3C6410_BASE_REG_PA_GPIO;
pPublicSpi->pGPIOregs = (volatile S3C6410_GPIO_REG *)MmMapIoSpace(ioPhysicalBase, sizeof(S3C6410_GPIO_REG), FALSE);
if (pPublicSpi->pGPIOregs == NULL)
{
RETAILMSG(SPI_INIT,(TEXT("[SPI] For pGPIOregs: MmMapIoSpace failed!\r\n")));
bResult = FALSE;
goto CleanUp;
}
// HS-SPI Virtual alloc
ioPhysicalBase.LowPart = S3C6410_BASE_REG_PA_SPI0;
pPublicSpi->pSPIregs = (volatile S3C6410_SPI_REG *)MmMapIoSpace(ioPhysicalBase, sizeof(S3C6410_SPI_REG), FALSE);
if (pPublicSpi->pSPIregs == NULL)
{
RETAILMSG(SPI_INIT,(TEXT("[SPI] For pSPIregs: MmMapIoSpace failed!\r\n")));
bResult = FALSE;
goto CleanUp;
}
// Syscon Virtual alloc
ioPhysicalBase.LowPart = S3C6410_BASE_REG_PA_SYSCON;
pPublicSpi->pSYSCONregs = (volatile S3C6410_SYSCON_REG *)MmMapIoSpace(ioPhysicalBase, sizeof(S3C6410_SYSCON_REG), FALSE);
if (pPublicSpi->pSYSCONregs == NULL)
{
RETAILMSG(SPI_INIT,(TEXT("[SPI] For pSYSCONregs: MmMapIoSpace failed!\r\n")));
bResult = FALSE;
goto CleanUp;
}
// DMAC0 Virtual alloc
ioPhysicalBase.LowPart = S3C6410_BASE_REG_PA_DMA0;
pPublicSpi->pDMAC0regs = (volatile S3C6410_DMAC_REG *)MmMapIoSpace(ioPhysicalBase, sizeof(S3C6410_DMAC_REG), FALSE);
if (pPublicSpi->pDMAC0regs == NULL)
{
RETAILMSG(SPI_INIT,(TEXT("[SPI] For pDMAC0regs: MmMapIoSpace failed!\r\n")));
bResult = FALSE;
goto CleanUp;
}
// DMAC1 Virtual alloc
ioPhysicalBase.LowPart = S3C6410_BASE_REG_PA_DMA1;
pPublicSpi->pDMAC1regs = (volatile S3C6410_DMAC_REG *)MmMapIoSpace(ioPhysicalBase, sizeof(S3C6410_DMAC_REG), FALSE);
if (pPublicSpi->pDMAC1regs == NULL)
{
RETAILMSG(SPI_INIT,(TEXT("[SPI] For pDMAC1regs: MmMapIoSpace failed!\r\n")));
bResult = FALSE;
goto CleanUp;
}
CleanUp:
if (!bResult)
{
if (pPublicSpi->pGPIOregs)
{
MmUnmapIoSpace((PVOID)pPublicSpi->pGPIOregs, sizeof(S3C6410_GPIO_REG));
pPublicSpi->pGPIOregs = NULL;
}
if (pPublicSpi->pSPIregs)
{
MmUnmapIoSpace((PVOID)pPublicSpi->pSPIregs, sizeof(S3C6410_SPI_REG));
pPublicSpi->pSPIregs = NULL;
}
if (pPublicSpi->pDMAC0regs)
{
MmUnmapIoSpace((PVOID)pPublicSpi->pDMAC0regs, sizeof(S3C6410_DMAC_REG));
pPublicSpi->pDMAC0regs = NULL;
}
if (pPublicSpi->pDMAC1regs)
{
MmUnmapIoSpace((PVOID)pPublicSpi->pDMAC1regs, sizeof(S3C6410_DMAC_REG));
pPublicSpi->pDMAC1regs = NULL;
}
if (pPublicSpi->pSYSCONregs)
{
MmUnmapIoSpace((PVOID)pPublicSpi->pSYSCONregs, sizeof(S3C6410_SYSCON_REG));
pPublicSpi->pSYSCONregs = NULL;
}
bResult = FALSE;
}
//Configure HS-SPI Port Drive Strength
pPublicSpi->pGPIOregs->SPCON = pPublicSpi->pGPIOregs->SPCON & ~(0x3<<28) | (2<<28);
//Set GPIO for MISO, MOSI, SPICLK, SS
pPublicSpi->pGPIOregs->GPCPUD = pPublicSpi->pGPIOregs->GPCPUD & ~(0xFF<<0);
pPublicSpi->pGPIOregs->GPCCON = pPublicSpi->pGPIOregs->GPCCON & ~(0xFFFF<<0) | (2<<0) | (2<<4) | (2<<8) |(2<<12);
// Clock On
pPublicSpi->pSYSCONregs->PCLK_GATE |= SPI_POWER_ON;
#if (SPI_CLOCK == EPLL_CLOCK)
pPublicSpi->pSYSCONregs->SCLK_GATE |= SPI_SCLK_ON;
#elif (SPI_CLOCK == USB_HOST_CLOCK)
pPublicSpi->pSYSCONregs->SCLK_GATE |= SPI_USBHOST_ON;
#endif
DMA_initialize_register_address((void *)pPublicSpi->pDMAC0regs, (void *)pPublicSpi->pDMAC1regs, (void *)pPublicSpi->pSYSCONregs);
return bResult;
}
BOOL InitializeBuffer()
{
BOOL bResult = TRUE;
DMA_ADAPTER_OBJECT Adapter1, Adapter2;
RETAILMSG(SPI_INIT,(TEXT("+[SPI] InitializeBuffer\n")));
memset(&Adapter1, 0, sizeof(DMA_ADAPTER_OBJECT));
Adapter1.InterfaceType = Internal;
Adapter1.ObjectSize = sizeof(DMA_ADAPTER_OBJECT);
memset(&Adapter2, 0, sizeof(DMA_ADAPTER_OBJECT));
Adapter2.InterfaceType = Internal;
Adapter2.ObjectSize = sizeof(DMA_ADAPTER_OBJECT);
// Allocate a block of virtual memory (physically contiguous) for the DMA buffers.
//
pVirtDmaDstBufferAddr = (PBYTE)HalAllocateCommonBuffer(&Adapter1, Buffer_Mem_Size, &PhysDmaDstBufferAddr, FALSE);
RETAILMSG(FALSE, (TEXT("[SPIDD] InitializeBuffer() - pVirtDmaDstBufferAddr %x\r\n"),pVirtDmaDstBufferAddr));
if (pVirtDmaDstBufferAddr == NULL)
{
RETAILMSG(SPI_INIT, (TEXT("[SPI] InitializeBuffer() - Failed to allocate DMA buffer for SPI.\r\n")));
HalFreeCommonBuffer(0, 0, PhysDmaDstBufferAddr, pVirtDmaDstBufferAddr, FALSE);
bResult = FALSE;
goto CleanUp;