nxdrvlinux/libcifx/Toolkit/SerialDPM/SerialDPMInterface.c

476 lines
17 KiB
C
Raw Normal View History

/**************************************************************************************
Copyright (c) Hilscher Gesellschaft fuer Systemautomation mbH. All Rights Reserved.
***************************************************************************************
$Id: SerialDPMInterface.c 14801 2023-05-10 09:36:54Z RMayer $:
Description:
Serial DPM Interface
Changes:
Date Description
-----------------------------------------------------------------------------------
2023-05-10 Adapted netX Read/Write function definitions to new ulOption parameter
2019-08-06 Chip detection loop in SerialDPM_Init() reworked
2018-08-09 fixed pclint warnings
2014-08-01 initial version
**************************************************************************************/
/*****************************************************************************/
/*! \file SerialDPMInterface.c
* Serial DPM protocol implementation */
/*****************************************************************************/
#include "OS_Spi.h"
#include "cifXHWFunctions.h"
#include "SerialDPMInterface.h"
#include "cifXErrors.h"
#define MAX_CNT(array) (sizeof((array))/sizeof((array)[0]))
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX_TRANSFER_LEN 124
#define CMD_READ_NX50(len) (0x80 | len)
#define CMD_READ_NX10(len) ((len > 127)? 0x80:(0x80 | len))
#define CMD_WRITE_NX10(len) ((len > 127)? 0x00:len)
/*lint -emacro(572, CMD_READ_NX51 ) : Excessive shift value */
#define CMD_READ_NX51(addr) (0x80 | ((addr>>16)&0xF))
/*lint -emacro(572, CMD_WRITE_NX51 ) : Excessive shift value */
#define CMD_WRITE_NX51(addr) ((addr>>16)&0xF)
#define CMD_LEN_NX51(len) ((len > 255)? 0x00:len)
#ifndef CIFX_TOOLKIT_HWIF
#error "CIFX_TOOLKIT_HWIF must be explicitly enabled to support serial DPM!"
#endif
/*****************************************************************************/
/*! Read a number of bytes from SPI interface (netX50 Slave)
* \param ulOption 0 = memcpy / 1 = single transfer
* \param pvDevInstance Device Instance
* \param pvAddr Address offset in DPM to read data from
* \param pvData Buffer to store read data
* \param ulLen Number of bytes to read */
/*****************************************************************************/
static void* Read_NX50( uint32_t ulOption, void* pvDevInstance, void* pvAddr, void* pvData, uint32_t ulLen)
{
DEVICEINSTANCE* ptDevice = (DEVICEINSTANCE*) pvDevInstance;
uint8_t bUnused = 0x00;
uint32_t ulByteTimeout = 100;
uint32_t ulDpmAddr = (uint32_t)pvAddr;
uint8_t* pabData = (uint8_t*)pvData;
OS_SpiLock(ptDevice->pvOSDependent);
while (ulLen > 0)
{
uint8_t abSend[3];
uint32_t ulChunkLen = MIN(MAX_TRANSFER_LEN, ulLen);
ulLen -= ulChunkLen;
/* Assemble command */
abSend[0] = (uint8_t)((ulDpmAddr >> 8) & 0xFF);
abSend[1] = (uint8_t)((ulDpmAddr >> 0) & 0xFF);
abSend[2] = (uint8_t)(CMD_READ_NX50(ulChunkLen));
OS_SpiAssert(pvDevInstance);
OS_SpiTransfer(pvDevInstance, abSend, NULL, MAX_CNT(abSend));
do
{
if(ulByteTimeout == 0)
{
OS_SpiDeassert(pvDevInstance);
return pvData;
}
--ulByteTimeout;
/* get the idle bytes done */
OS_SpiTransfer(pvDevInstance, NULL, &bUnused, 1);
} while((bUnused & 0xFF) != 0xA5);
while(ulChunkLen--)
{
OS_SpiTransfer(pvDevInstance, &bUnused, pabData++, 1);
}
OS_SpiDeassert(pvDevInstance);
ulDpmAddr += MAX_TRANSFER_LEN;
}
OS_SpiUnlock(ptDevice->pvOSDependent);
return pvData;
}
/*****************************************************************************/
/*! Write a number of bytes to SPI interface (netX50 Slave)
* \param ulOption 0 = memcpy / 1 = single transfer
* \param pvDevInstance Device Instance
* \param pvAddr Address offset in DPM to write data to
* \param pvData Data to write to SPI interface
* \param ulLen Number of bytes to write */
/*****************************************************************************/
static void* Write_NX50( uint32_t ulOption, void* pvDevInstance, void* pvAddr, void* pvData, uint32_t ulLen)
{
DEVICEINSTANCE* ptDevice = (DEVICEINSTANCE*) pvDevInstance;
uint32_t ulDpmAddr = (uint32_t)pvAddr;
uint8_t* pabData = (uint8_t*)pvData;
OS_SpiLock(ptDevice->pvOSDependent);
while (ulLen > 0)
{
uint8_t abSend[3];
uint32_t ulChunkLen = MIN(MAX_TRANSFER_LEN, ulLen);
ulLen -= ulChunkLen;
/* Assemble command */
abSend[0] = (uint8_t)((ulDpmAddr >> 8) & 0xFF);
abSend[1] = (uint8_t)((ulDpmAddr >> 0) & 0xFF);
abSend[2] = (uint8_t)ulChunkLen;
OS_SpiAssert(pvDevInstance);
OS_SpiTransfer(pvDevInstance, abSend, NULL, MAX_CNT(abSend));
OS_SpiTransfer(pvDevInstance, pabData, NULL, ulChunkLen);
OS_SpiDeassert(pvDevInstance);
ulDpmAddr += ulChunkLen;
pabData += ulChunkLen; /*lint !e662 */
}
OS_SpiUnlock(ptDevice->pvOSDependent);
return pvAddr;
}
/*****************************************************************************/
/*! Read a number of bytes from SPI interface (netX500 Slave)
* \param ulOption 0 = memcpy / 1 = single transfer
* \param pvDevInstance Device Instance
* \param pvAddr Address offset in DPM to read data from
* \param pvData Buffer to store read data
* \param ulLen Number of bytes to read */
/*****************************************************************************/
static void* Read_NX500( uint32_t ulOption, void* pvDevInstance, void* pvAddr, void* pvData, uint32_t ulLen)
{
DEVICEINSTANCE* ptDevice = (DEVICEINSTANCE*) pvDevInstance;
uint8_t bUnused = 0x00;
uint32_t ulByteTimeout = 100;
uint32_t ulDpmAddr = (uint32_t)pvAddr;
uint8_t* pabData = (uint8_t*)pvData;
uint32_t ulPreLen = ulDpmAddr&0x3;
/* Align offset and length */
ulDpmAddr &= ~0x3;
OS_SpiLock(ptDevice->pvOSDependent);
while (ulLen > 0)
{
uint8_t abSend[3];
uint32_t ulChunkLen = MIN(MAX_TRANSFER_LEN, ulLen);
uint32_t ulAlignedLen = (ulChunkLen+3)&~0x3;
ulLen -= ulChunkLen;
/* Assemble command */
abSend[0] = (uint8_t)((ulDpmAddr >> 8) & 0xFF);
abSend[1] = (uint8_t)((ulDpmAddr >> 0) & 0xFF);
abSend[2] = (uint8_t)(CMD_READ_NX50(ulAlignedLen));
/* assert chip select */
OS_SpiAssert(pvDevInstance);
OS_SpiTransfer(pvDevInstance, abSend, NULL, MAX_CNT(abSend));
do
{
if(ulByteTimeout == 0)
{
OS_SpiDeassert(pvDevInstance);
return pvData;
}
--ulByteTimeout;
/* get the idle bytes done */
OS_SpiTransfer(pvDevInstance, NULL, &bUnused, 1);
} while((bUnused & 0xFF) != 0xA5);
if (ulPreLen)
{
OS_SpiTransfer(pvDevInstance, NULL, NULL, ulPreLen);
ulPreLen = 0;
}
OS_SpiTransfer(pvDevInstance, NULL, pabData, ulChunkLen);
if (0 != (ulAlignedLen - ulChunkLen))
{
OS_SpiTransfer(pvDevInstance, NULL, NULL, ulAlignedLen - ulChunkLen);
}
OS_SpiDeassert(pvDevInstance);
ulDpmAddr += ulChunkLen;
pabData += ulChunkLen; /*lint !e662 */
}
OS_SpiUnlock(ptDevice->pvOSDependent);
return pvData;
}
/*****************************************************************************/
/*! Read and modify number of bytes from SPI interface (netX500 Slave)
* \param ulOption 0 = memcpy / 1 = single transfer
* \param pvDevInstance Device Instance
* \param pvAddr Address offset in DPM to read/modify data
* \param pvData Data to write to SPI interface
* \param ulLen Number of bytes to write */
/*****************************************************************************/
static void* ReadModifyWrite_NX500( uint32_t ulOption, void* pvDevInstance, void* pvAddr, void* pvData, uint32_t ulLen)
{
uint32_t ulDpmAddr = (uint32_t)pvAddr;
uint8_t* pabData = (uint8_t*)pvData;
uint8_t abRead[4];
if (ulDpmAddr&0x3)
{
uint32_t ulAlignedAddr = ulDpmAddr&~0x3;
uint8_t* pabRead = &abRead[ulDpmAddr&0x3];
uint32_t ulPartLen = MIN(ulLen, (4 - (ulDpmAddr&0x3)));
ulLen -= ulPartLen;
ulDpmAddr += ulPartLen;
(void) Read_NX50( 0, pvDevInstance, (void*)ulAlignedAddr, abRead, 4);
while (ulPartLen--)
{
*pabRead++ = *pabData++;
}
(void) Write_NX50( 0, pvDevInstance, (void*)ulAlignedAddr, abRead, 4);
}
if (ulLen&~0x3)
{
uint32_t ulAlignedLen = ulLen&~0x3;
(void) Write_NX50( 0, pvDevInstance, (void*)ulDpmAddr, pabData, ulAlignedLen);
pabData += ulAlignedLen;
ulDpmAddr += ulAlignedLen;
ulLen -= ulAlignedLen;
}
if (ulLen&0x3)
{
uint8_t* pabRead = &abRead[0];
(void) Read_NX50( 0, pvDevInstance, (void*)ulDpmAddr, abRead, 4);
while (ulLen--)
{
*pabRead++ = *pabData++;
}
(void) Write_NX50( 0, pvDevInstance, (void*)ulDpmAddr, abRead, 4);
}
return pvAddr;
}
/*****************************************************************************/
/*! Read a number of bytes from SPI interface (netX10 Slave)
* \param ulOption 0 = memcpy / 1 = single transfer
* \param pvDevInstance Device Instance
* \param pvAddr Address offset in DPM to read data from
* \param pvData Buffer to store read data
* \param ulLen Number of bytes to read */
/*****************************************************************************/
static void* Read_NX10( uint32_t ulOption, void* pvDevInstance, void* pvAddr, void* pvData, uint32_t ulLen)
{
DEVICEINSTANCE* ptDevice = (DEVICEINSTANCE*) pvDevInstance;
uint8_t abSend[3];
/* Assemble command */
abSend[0] = (uint8_t)(((uint32_t)pvAddr >> 8) & 0xFF);
abSend[1] = (uint8_t)(((uint32_t)pvAddr >> 0) & 0xFF);
abSend[2] = (uint8_t)(CMD_READ_NX10(ulLen));
OS_SpiLock(ptDevice->pvOSDependent);
OS_SpiAssert(pvDevInstance);
OS_SpiTransfer(pvDevInstance, abSend, NULL, MAX_CNT(abSend));
OS_SpiTransfer(pvDevInstance, NULL, (uint8_t*)pvData, ulLen);
OS_SpiDeassert(pvDevInstance);
OS_SpiUnlock(ptDevice->pvOSDependent);
return pvData;
}
/*****************************************************************************/
/*! Write a number of bytes to SPI interface (netX10 Slave)
* \param ulOption 0 = memcpy / 1 = single transfer
* \param pvDevInstance Device Instance
* \param pvAddr Address offset in DPM to write data to
* \param pvData Data to write to SPI interface
* \param ulLen Number of bytes to write */
/*****************************************************************************/
static void* Write_NX10( uint32_t ulOption, void* pvDevInstance, void* pvAddr, void* pvData, uint32_t ulLen)
{
DEVICEINSTANCE* ptDevice = (DEVICEINSTANCE*) pvDevInstance;
uint8_t abSend[3];
/* Assemble command */
abSend[0] = (uint8_t)(((uint32_t)pvAddr >> 8) & 0xFF);
abSend[1] = (uint8_t)(((uint32_t)pvAddr >> 0) & 0xFF);
abSend[2] = (uint8_t)(CMD_WRITE_NX10(ulLen));
OS_SpiLock(ptDevice->pvOSDependent);
OS_SpiAssert(pvDevInstance);
OS_SpiTransfer(pvDevInstance, abSend, NULL, MAX_CNT(abSend));
OS_SpiTransfer(pvDevInstance, (uint8_t*)pvData, NULL, ulLen);
OS_SpiDeassert(pvDevInstance);
OS_SpiUnlock(ptDevice->pvOSDependent);
return pvAddr;
}
/*****************************************************************************/
/*! Read a number of bytes from SPI interface (netX51 Slave)
* \param ulOption 0 = memcpy / 1 = single transfer
* \param pvDevInstance Device Instance
* \param pvAddr Address offset in DPM to read data from
* \param pvData Buffer to store read data
* \param ulLen Number of bytes to read */
/*****************************************************************************/
static void* Read_NX51( uint32_t ulOption, void* pvDevInstance, void* pvAddr, void* pvData, uint32_t ulLen)
{
DEVICEINSTANCE* ptDevice = (DEVICEINSTANCE*) pvDevInstance;
uint8_t abSend[4];
/* Assemble command */
abSend[0] = (uint8_t)(CMD_READ_NX51((uint32_t)pvAddr));
abSend[1] = (uint8_t)(((uint32_t)pvAddr >> 8) & 0xFF);
abSend[2] = (uint8_t)(((uint32_t)pvAddr >> 0) & 0xFF);
abSend[3] = (uint8_t)(CMD_LEN_NX51(ulLen));
OS_SpiLock(ptDevice->pvOSDependent);
OS_SpiAssert(pvDevInstance);
OS_SpiTransfer(pvDevInstance, abSend, NULL, MAX_CNT(abSend));
OS_SpiTransfer(pvDevInstance, NULL, (uint8_t*)pvData, ulLen);
OS_SpiDeassert(pvDevInstance);
OS_SpiUnlock(ptDevice->pvOSDependent);
return pvData;
}
/*****************************************************************************/
/*! Write a number of bytes to SPI interface (netX51 Slave)
* \param ulOption 0 = memcpy / 1 = single transfer
* \param pvDevInstance Device Instance
* \param pvAddr Address offset in DPM to write data to
* \param pvData Data to write to SPI interface
* \param ulLen Number of bytes to write */
/*****************************************************************************/
static void* Write_NX51( uint32_t ulOption, void* pvDevInstance, void* pvAddr, void* pvData, uint32_t ulLen)
{
DEVICEINSTANCE* ptDevice = (DEVICEINSTANCE*) pvDevInstance;
uint8_t abSend[3];
/* Assemble command */
abSend[0] = (uint8_t)(CMD_WRITE_NX51((uint32_t)pvAddr));
abSend[1] = (uint8_t)(((uint32_t)pvAddr >> 8) & 0xFF);
abSend[2] = (uint8_t)(((uint32_t)pvAddr >> 0) & 0xFF);
OS_SpiLock(ptDevice->pvOSDependent);
OS_SpiAssert(pvDevInstance);
OS_SpiTransfer(pvDevInstance, abSend, NULL, MAX_CNT(abSend));
OS_SpiTransfer(pvDevInstance, (uint8_t*)pvData, NULL, ulLen);
OS_SpiDeassert(pvDevInstance);
OS_SpiUnlock(ptDevice->pvOSDependent);
return pvAddr;
}
/*****************************************************************************/
/*! Initialize serial DPM interface
* \param ptDevice Device Instance
* \return protocol type identifier */
/*****************************************************************************/
int SerialDPM_Init(DEVICEINSTANCE* ptDevice)
{
uint8_t bUnused;
int iSerDpmType = SERDPM_UNKNOWN;
int iDummyReadCnt = 0;
if (CIFX_NO_ERROR == OS_SpiInit(ptDevice->pvOSDependent))
{
uint32_t ulDetect = 0;
uint8_t abSend[] = {CMD_READ_NX51(0xFF), 0xFF, CMD_READ_NX50(4)};
OS_SpiLock(ptDevice->pvOSDependent);
/* ATTENTION: Some of the netX chips needs a DUMMY read before delivering valid data */
/* If the first access delivers a SERDPM_UNKNOWN result, */
/* the loop should be processed again a second time */
do
{
/* Execute the SPI chip detection */
OS_SpiAssert(ptDevice);
OS_SpiTransfer(ptDevice, abSend, (unsigned char*)&ulDetect, MAX_CNT(abSend));
OS_SpiDeassert(ptDevice);
if (0 == ulDetect)
{
iSerDpmType = SERDPM_NETX10;
} else if (0x00FFFFFF == ulDetect)
{
iSerDpmType = SERDPM_NETX50;
} else if (0x64 == (0xFF & ulDetect))
{
iSerDpmType = SERDPM_NETX100;
} else if (0x11 == (0x1F & ulDetect))
{
iSerDpmType = SERDPM_NETX51;
} else
{
iSerDpmType = SERDPM_UNKNOWN;
}
iDummyReadCnt++;
} while ((iDummyReadCnt < 2) && (iSerDpmType == SERDPM_UNKNOWN));
OS_SpiUnlock(ptDevice->pvOSDependent);
switch (iSerDpmType)
{
case SERDPM_NETX100:
ptDevice->pfnHwIfRead = Read_NX500;
ptDevice->pfnHwIfWrite = ReadModifyWrite_NX500;
break;
case SERDPM_NETX50:
ptDevice->pfnHwIfRead = Read_NX50;
ptDevice->pfnHwIfWrite = Write_NX50;
break;
case SERDPM_NETX10:
ptDevice->pfnHwIfRead = Read_NX10;
ptDevice->pfnHwIfWrite = Write_NX10;
/* Initialize SPI unit of slave by making 2 dummy reads */
(void) Read_NX10(0, ptDevice, 0, &bUnused, 1);
(void) Read_NX10(0, ptDevice, 0, &bUnused, 1);
break;
case SERDPM_NETX51:
ptDevice->pfnHwIfRead = Read_NX51;
ptDevice->pfnHwIfWrite = Write_NX51;
/* Initialize SPI unit of slave by making 2 dummy reads */
(void) Read_NX51(0, ptDevice, 0, &bUnused, 1);
(void) Read_NX51(0, ptDevice, 0, &bUnused, 1);
break;
default:
/* Protocol type detection failed */
break;
}
/* This is a SPI connection, not PCI! */
ptDevice->fPCICard = 0;
/* The DPM address must be zero, as we only transfer address offsets via the SPI interface. */
ptDevice->pbDPM = NULL;
}
return iSerDpmType;
}