An error occurred while loading the file. Please try again.
-
Tomasz Wlostowski authored2c7fdcbc
svec-flasher.c 8.01 KiB
/*
* Copyright (C) 2013 CERN (www.cern.ch)
* Author: Tomasz Włostowski <tomasz.wlostowski@cern.ch>
*
* Released according to the GNU GPL, version 2 or any later version.
*
* svec-flasher: a trivial VME-SPI flasher application.
*/
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <libvmebus.h>
//#include <libsdbfs.h>
#include "sxldr_regs.h"
#define BOOTLOADER_BASE 0x70000
#define BOOTLOADER_VERSION 2
#define BOOTLOADER_BITSTREAM_BASE 0x100000
#define BOOTLOADER_SDB_BASE 0x600000
#define ID_M25P128 0x202018
#define FLASH_PAGE_SIZE 256
#define FLASH_SECTOR_SIZE 0x40000
#define FLASH_SIZE 0x1000000
/* M25Pxxx SPI flash commands */
#define FLASH_WREN 0x06
#define FLASH_WRDI 0x04
#define FLASH_RDID 0x9F
#define FLASH_RDSR 0x05
#define FLASH_WRSR 0x01
#define FLASH_READ 0x03
#define FLASH_FAST_READ 0x0B
#define FLASH_PP 0x02
#define FLASH_SE 0xD8
#define FLASH_BE 0xC7
/* SDB filesystem header. Fixed for the time being, the final version should simply use libsdbfs. */
const uint8_t sdb_header[] = {
0x53, 0x44, 0x42, 0x2d, 0x00, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0xc0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xce, 0x42, 0x00, 0x00, 0x5f, 0xec,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x2c, 0x13, 0xe9, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61,
0x61, 0x66, 0x70, 0x67, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x61, 0x66, 0x70, 0x67, 0x61, 0x2e, 0x62, 0x69, 0x6e, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x33, 0x93, 0x46, 0x69, 0x6c, 0x65,
0x44, 0x61, 0x74, 0x61, 0x62, 0x6f, 0x6f, 0x74, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x62, 0x6f, 0x6f, 0x74, 0x6c, 0x64, 0x72, 0x2e,
0x62, 0x69, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01
};
struct vme_mapping map;
void *vme_va;
void release_vme()
{
vme_unmap(&map, 1);
}
void init_vme(int slot)
{
memset(&map, 0, sizeof(struct vme_mapping));
map.am = 0x2f;
map.data_width = 32;
map.sizel = 0x1000;
map.vme_addrl = slot * 0x80000 + BOOTLOADER_BASE;
if ((vme_va = vme_map(&map, 1)) == NULL) {
fprintf(stderr, "Could not map VME CSR space at 0x%08x\n",
map.vme_addrl);
exit(1);
}
atexit(release_vme);
}
static void csr_writel(uint32_t data, uint32_t addr)
{
*(volatile uint32_t *)(vme_va + addr) = htonl(data);
}
static uint32_t csr_readl(uint32_t addr)
{
return ntohl(*(volatile uint32_t *)(vme_va + addr));
}
void enter_bootloader()
{
int i = 0;
const uint32_t boot_seq[8] =
{ 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe };
/* magic sequence: unlock bootloader mode, disable application FPGA */
for (i = 0; i < 8; i++)
csr_writel(boot_seq[i], SXLDR_REG_BTRIGR);
if (csr_readl(SXLDR_REG_IDR) != 0x53564543) { /* "SVEC" in hex */
fprintf(stderr,
"The bootloader is not responding. Are you sure the slot you've\
specified hosts a SVEC card? Is the SVEC's System FPGA programmer (the \"SFPGA\
Done\" LED next to the fuses should be on).\n");
exit(-1);
}
}
/* Tests the presence of the SPI master in the bootloader to check if we are running
version > 1 (v1 does not have the version ID register) */
int spi_test_presence()
{
csr_writel( SXLDR_FAR_XFER | SXLDR_FAR_DATA_W(0xff),
SXLDR_REG_FAR);
usleep(100000);
uint32_t far = csr_readl(SXLDR_REG_FAR);
/* transaction is not complete after so much time? no SPI... */
return (far & SXLDR_FAR_READY);
}
void spi_cs(int cs)
{
csr_writel(cs ? SXLDR_FAR_CS : 0, SXLDR_REG_FAR);
usleep(1);
}
uint8_t spi_read8()
{
uint32_t far;
csr_writel(SXLDR_FAR_XFER | SXLDR_FAR_DATA_W(0xff) | SXLDR_FAR_CS,
SXLDR_REG_FAR);
do {
far = csr_readl(SXLDR_REG_FAR);
} while (!(far & SXLDR_FAR_READY));
return SXLDR_FAR_DATA_R(far);
}
void spi_write8(uint8_t data)
{
uint32_t far;
csr_writel(SXLDR_FAR_XFER | SXLDR_FAR_DATA_W(data) | SXLDR_FAR_CS,
SXLDR_REG_FAR);
do {
far = csr_readl(SXLDR_REG_FAR);
} while (!(far & SXLDR_FAR_READY));
}
uint32_t flash_read_id()
{
uint32_t val = 0;
/* make sure the flash is in known state (idle) */
spi_cs(0);
usleep(10);
spi_cs(1);
usleep(10);
spi_cs(1);
spi_write8(FLASH_RDID);
val = (spi_read8() << 16);
val += (spi_read8() << 8);
val += spi_read8();
spi_cs(0);
return val;
}
static void flash_wait_completion()
{
int not_done = 1;
while (not_done) {
spi_cs(1);
spi_write8(FLASH_RDSR); /* Read Status register */
uint8_t stat = spi_read8();
not_done = (stat & 0x01);
spi_cs(0);
}
}
void flash_erase_sector(uint32_t addr)
{
spi_cs(1);
spi_write8(FLASH_SE);
spi_write8((addr >> 16) & 0xff);
spi_write8((addr >> 8) & 0xff);
spi_write8((addr >> 0) & 0xff);
spi_cs(0);
flash_wait_completion();
}
void flash_write_enable()
{
spi_cs(1);
spi_write8(FLASH_WREN);
spi_cs(0);
}
void flash_program_page(uint32_t addr, const uint8_t * data, int size)
{
int i;
spi_cs(1);
spi_write8(FLASH_PP); /* Page Program */
spi_write8((addr >> 16) & 0x00ff); /* Address to start writing (MSB) */
spi_write8((addr >> 8) & 0x00ff); /* Address to start writing */
spi_write8(addr & 0x00ff); /* Address to start writing (LSB) */
for (i = 0; i < size; i++)
spi_write8(data[i]);
for (; i < FLASH_PAGE_SIZE; i++)
spi_write8(0xff);
spi_cs(0);
flash_wait_completion();
}
void flash_program(uint32_t addr, const uint8_t * data, int size)
{
int n = 0;
int sector_map[FLASH_SIZE / FLASH_SECTOR_SIZE];
memset(sector_map, 0, sizeof(sector_map));
const uint8_t *p = data;
while (n < size) {
int plen = (size > FLASH_PAGE_SIZE ? FLASH_PAGE_SIZE : size);
int sector = ((addr + n) / FLASH_SECTOR_SIZE);
if (!sector_map[sector]) {
flash_write_enable();
fprintf(stderr, "Erasing sector 0x%x \r",
addr + n);
flash_erase_sector(addr + n);
sector_map[sector] = 1;
}
flash_write_enable();
flash_program_page(addr + n, data + n, plen);
fprintf(stderr, "Programming page %d/%d. \r",
n / FLASH_PAGE_SIZE,
(size + FLASH_PAGE_SIZE - 1) / FLASH_PAGE_SIZE - 1);
n += plen;
}
spi_cs(1);
spi_write8(FLASH_READ);
spi_write8((addr >> 16) & 0xff);
spi_write8((addr >> 8) & 0xff);
spi_write8((addr >> 0) & 0xff);
fprintf(stderr, "\nVerification...\n");
for (n = 0, p = data; n < size; p++, n++) {
uint8_t d = spi_read8();
if (d != *p) {
fprintf(stderr,
"Verification failed at offset 0x%06x (is: 0x%02x, should be: 0x%02x)\n.",
addr + n, d, *p);
spi_cs(0);
exit(-1);
}
}
spi_cs(0);
}
int main(int argc, char *argv[])
{
FILE *f;
void *buf;
uint32_t size;
int slot;
if (argc < 3) {
printf("usage: %s slot bitstream.bin\n", argv[0]);
return -1;
}
printf("Programming the Application FPGA flash with bitstream %s.\n",
argv[2]);
f = fopen(argv[2], "rb");
if (!f) {
perror("fopen()");
return -1;
}
fseek(f, 0, SEEK_END);
size = ftell(f);
rewind(f);
buf = malloc(size);
fread(buf, 1, size, f);
fclose(f);
slot = atoi(argv[1]);
init_vme(slot);
enter_bootloader();
if (!spi_test_presence())
{
fprintf(stderr,
"SPI Master core not responding. You are probably be running an old version of the bootloader that doesn't support flash programming via VME.\n");
exit(-1);
}
if (flash_read_id() != ID_M25P128) {
fprintf(stderr,
"Flash memory ID invalid. You are probably be running an old version of the bootloader that doesn't support flash programming via VME.\n");
exit(-1);
}
int version = SXLDR_CSR_VERSION_R(csr_readl( SXLDR_REG_CSR ));
printf("Bootloader version: %d\n", version);
flash_program(BOOTLOADER_SDB_BASE, sdb_header, sizeof(sdb_header));
flash_program(BOOTLOADER_BITSTREAM_BASE, buf, size);
free(buf);
printf("Programming OK.\n");
return 0;
}