blob: 30bec7feef73ef016d13dad11b466ef859f3a9c6 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2010
* Stefano Babic, DENX Software Engineering, sbabic@denx.de.
*
* (C) Copyright 2002
* Rich Ireland, Enterasys Networks, rireland@enterasys.com.
*
* ispVM functions adapted from Lattice's ispmVMEmbedded code:
* Copyright 2009 Lattice Semiconductor Corp.
*/
#include <common.h>
#include <malloc.h>
#include <fpga.h>
#include <lattice.h>
static lattice_board_specific_func *pfns;
static const char *fpga_image;
static unsigned long read_bytes;
static unsigned long bufsize;
static unsigned short expectedCRC;
/*
* External variables and functions declared in ivm_core.c module.
*/
extern unsigned short g_usCalculatedCRC;
extern unsigned short g_usDataType;
extern unsigned char *g_pucIntelBuffer;
extern unsigned char *g_pucHeapMemory;
extern unsigned short g_iHeapCounter;
extern unsigned short g_iHEAPSize;
extern unsigned short g_usIntelDataIndex;
extern unsigned short g_usIntelBufferSize;
extern char *const g_szSupportedVersions[];
/*
* ispVMDelay
*
* Users must implement a delay to observe a_usTimeDelay, where
* bit 15 of the a_usTimeDelay defines the unit.
* 1 = milliseconds
* 0 = microseconds
* Example:
* a_usTimeDelay = 0x0001 = 1 microsecond delay.
* a_usTimeDelay = 0x8001 = 1 millisecond delay.
*
* This subroutine is called upon to provide a delay from 1 millisecond to a few
* hundreds milliseconds each time.
* It is understood that due to a_usTimeDelay is defined as unsigned short, a 16
* bits integer, this function is restricted to produce a delay to 64000
* micro-seconds or 32000 milli-second maximum. The VME file will never pass on
* to this function a delay time > those maximum number. If it needs more than
* those maximum, the VME file will launch the delay function several times to
* realize a larger delay time cummulatively.
* It is perfectly alright to provide a longer delay than required. It is not
* acceptable if the delay is shorter.
*/
void ispVMDelay(unsigned short delay)
{
if (delay & 0x8000)
delay = (delay & ~0x8000) * 1000;
udelay(delay);
}
void writePort(unsigned char a_ucPins, unsigned char a_ucValue)
{
a_ucValue = a_ucValue ? 1 : 0;
switch (a_ucPins) {
case g_ucPinTDI:
pfns->jtag_set_tdi(a_ucValue);
break;
case g_ucPinTCK:
pfns->jtag_set_tck(a_ucValue);
break;
case g_ucPinTMS:
pfns->jtag_set_tms(a_ucValue);
break;
default:
printf("%s: requested unknown pin\n", __func__);
}
}
unsigned char readPort(void)
{
return pfns->jtag_get_tdo();
}
void sclock(void)
{
writePort(g_ucPinTCK, 0x01);
writePort(g_ucPinTCK, 0x00);
}
void calibration(void)
{
/* Apply 2 pulses to TCK. */
writePort(g_ucPinTCK, 0x00);
writePort(g_ucPinTCK, 0x01);
writePort(g_ucPinTCK, 0x00);
writePort(g_ucPinTCK, 0x01);
writePort(g_ucPinTCK, 0x00);
ispVMDelay(0x8001);
/* Apply 2 pulses to TCK. */
writePort(g_ucPinTCK, 0x01);
writePort(g_ucPinTCK, 0x00);
writePort(g_ucPinTCK, 0x01);
writePort(g_ucPinTCK, 0x00);
}
/*
* GetByte
*
* Returns a byte to the caller. The returned byte depends on the
* g_usDataType register. If the HEAP_IN bit is set, then the byte
* is returned from the HEAP. If the LHEAP_IN bit is set, then
* the byte is returned from the intelligent buffer. Otherwise,
* the byte is returned directly from the VME file.
*/
unsigned char GetByte(void)
{
unsigned char ucData;
unsigned int block_size = 4 * 1024;
if (g_usDataType & HEAP_IN) {
/*
* Get data from repeat buffer.
*/
if (g_iHeapCounter > g_iHEAPSize) {
/*
* Data over-run.
*/
return 0xFF;
}
ucData = g_pucHeapMemory[g_iHeapCounter++];
} else if (g_usDataType & LHEAP_IN) {
/*
* Get data from intel buffer.
*/
if (g_usIntelDataIndex >= g_usIntelBufferSize) {
return 0xFF;
}
ucData = g_pucIntelBuffer[g_usIntelDataIndex++];
} else {
if (read_bytes == bufsize) {
return 0xFF;
}
ucData = *fpga_image++;
read_bytes++;
if (!(read_bytes % block_size)) {
printf("Downloading FPGA %ld/%ld completed\r",
read_bytes,
bufsize);
}
if (expectedCRC != 0) {
ispVMCalculateCRC32(ucData);
}
}
return ucData;
}
signed char ispVM(void)
{
char szFileVersion[9] = { 0 };
signed char cRetCode = 0;
signed char cIndex = 0;
signed char cVersionIndex = 0;
unsigned char ucReadByte = 0;
unsigned short crc;
g_pucHeapMemory = NULL;
g_iHeapCounter = 0;
g_iHEAPSize = 0;
g_usIntelDataIndex = 0;
g_usIntelBufferSize = 0;
g_usCalculatedCRC = 0;
expectedCRC = 0;
ucReadByte = GetByte();
switch (ucReadByte) {
case FILE_CRC:
crc = (unsigned char)GetByte();
crc <<= 8;
crc |= GetByte();
expectedCRC = crc;
for (cIndex = 0; cIndex < 8; cIndex++)
szFileVersion[cIndex] = GetByte();
break;
default:
szFileVersion[0] = (signed char) ucReadByte;
for (cIndex = 1; cIndex < 8; cIndex++)
szFileVersion[cIndex] = GetByte();
break;
}
/*
*
* Compare the VME file version against the supported version.
*
*/
for (cVersionIndex = 0; g_szSupportedVersions[cVersionIndex] != 0;
cVersionIndex++) {
for (cIndex = 0; cIndex < 8; cIndex++) {
if (szFileVersion[cIndex] !=
g_szSupportedVersions[cVersionIndex][cIndex]) {
cRetCode = VME_VERSION_FAILURE;
break;
}
cRetCode = 0;
}
if (cRetCode == 0) {
break;
}
}
if (cRetCode < 0) {
return VME_VERSION_FAILURE;
}
printf("VME file checked: starting downloading to FPGA\n");
ispVMStart();
cRetCode = ispVMCode();
ispVMEnd();
ispVMFreeMem();
puts("\n");
if (cRetCode == 0 && expectedCRC != 0 &&
(expectedCRC != g_usCalculatedCRC)) {
printf("Expected CRC: 0x%.4X\n", expectedCRC);
printf("Calculated CRC: 0x%.4X\n", g_usCalculatedCRC);
return VME_CRC_FAILURE;
}
return cRetCode;
}
static int lattice_validate(Lattice_desc *desc, const char *fn)
{
int ret_val = false;
if (desc) {
if ((desc->family > min_lattice_type) &&
(desc->family < max_lattice_type)) {
if ((desc->iface > min_lattice_iface_type) &&
(desc->iface < max_lattice_iface_type)) {
if (desc->size) {
ret_val = true;
} else {
printf("%s: NULL part size\n", fn);
}
} else {
printf("%s: Invalid Interface type, %d\n",
fn, desc->iface);
}
} else {
printf("%s: Invalid family type, %d\n",
fn, desc->family);
}
} else {
printf("%s: NULL descriptor!\n", fn);
}
return ret_val;
}
int lattice_load(Lattice_desc *desc, const void *buf, size_t bsize)
{
int ret_val = FPGA_FAIL;
if (!lattice_validate(desc, (char *)__func__)) {
printf("%s: Invalid device descriptor\n", __func__);
} else {
pfns = desc->iface_fns;
switch (desc->family) {
case Lattice_XP2:
fpga_image = buf;
read_bytes = 0;
bufsize = bsize;
debug("%s: Launching the Lattice ISPVME Loader:"
" addr %p size 0x%lx...\n",
__func__, fpga_image, bufsize);
ret_val = ispVM();
if (ret_val)
printf("%s: error %d downloading FPGA image\n",
__func__, ret_val);
else
puts("FPGA downloaded successfully\n");
break;
default:
printf("%s: Unsupported family type, %d\n",
__func__, desc->family);
}
}
return ret_val;
}
int lattice_dump(Lattice_desc *desc, const void *buf, size_t bsize)
{
puts("Dump not supported for Lattice FPGA\n");
return FPGA_FAIL;
}
int lattice_info(Lattice_desc *desc)
{
int ret_val = FPGA_FAIL;
if (lattice_validate(desc, (char *)__func__)) {
printf("Family: \t");
switch (desc->family) {
case Lattice_XP2:
puts("XP2\n");
break;
/* Add new family types here */
default:
printf("Unknown family type, %d\n", desc->family);
}
puts("Interface type:\t");
switch (desc->iface) {
case lattice_jtag_mode:
puts("JTAG Mode\n");
break;
/* Add new interface types here */
default:
printf("Unsupported interface type, %d\n", desc->iface);
}
printf("Device Size: \t%d bytes\n",
desc->size);
if (desc->iface_fns) {
printf("Device Function Table @ 0x%p\n",
desc->iface_fns);
switch (desc->family) {
case Lattice_XP2:
break;
/* Add new family types here */
default:
break;
}
} else {
puts("No Device Function Table.\n");
}
if (desc->desc)
printf("Model: \t%s\n", desc->desc);
ret_val = FPGA_SUCCESS;
} else {
printf("%s: Invalid device descriptor\n", __func__);
}
return ret_val;
}