in solos-pci.c [624:739]
static int flash_upgrade(struct solos_card *card, int chip)
{
const struct firmware *fw;
const char *fw_name;
int blocksize = 0;
int numblocks = 0;
int offset;
switch (chip) {
case 0:
fw_name = "solos-FPGA.bin";
if (card->atmel_flash)
blocksize = ATMEL_FPGA_BLOCK;
else
blocksize = SPI_FLASH_BLOCK;
break;
case 1:
fw_name = "solos-Firmware.bin";
if (card->atmel_flash)
blocksize = ATMEL_SOLOS_BLOCK;
else
blocksize = SPI_FLASH_BLOCK;
break;
case 2:
if (card->fpga_version > LEGACY_BUFFERS){
fw_name = "solos-db-FPGA.bin";
if (card->atmel_flash)
blocksize = ATMEL_FPGA_BLOCK;
else
blocksize = SPI_FLASH_BLOCK;
} else {
dev_info(&card->dev->dev, "FPGA version doesn't support"
" daughter board upgrades\n");
return -EPERM;
}
break;
case 3:
if (card->fpga_version > LEGACY_BUFFERS){
fw_name = "solos-Firmware.bin";
if (card->atmel_flash)
blocksize = ATMEL_SOLOS_BLOCK;
else
blocksize = SPI_FLASH_BLOCK;
} else {
dev_info(&card->dev->dev, "FPGA version doesn't support"
" daughter board upgrades\n");
return -EPERM;
}
break;
default:
return -ENODEV;
}
if (request_firmware(&fw, fw_name, &card->dev->dev))
return -ENOENT;
dev_info(&card->dev->dev, "Flash upgrade starting\n");
/* New FPGAs require driver version before permitting flash upgrades */
iowrite32(DRIVER_VERSION, card->config_regs + DRIVER_VER);
numblocks = fw->size / blocksize;
dev_info(&card->dev->dev, "Firmware size: %zd\n", fw->size);
dev_info(&card->dev->dev, "Number of blocks: %d\n", numblocks);
dev_info(&card->dev->dev, "Changing FPGA to Update mode\n");
iowrite32(1, card->config_regs + FPGA_MODE);
(void) ioread32(card->config_regs + FPGA_MODE);
/* Set mode to Chip Erase */
if(chip == 0 || chip == 2)
dev_info(&card->dev->dev, "Set FPGA Flash mode to FPGA Chip Erase\n");
if(chip == 1 || chip == 3)
dev_info(&card->dev->dev, "Set FPGA Flash mode to Solos Chip Erase\n");
iowrite32((chip * 2), card->config_regs + FLASH_MODE);
iowrite32(1, card->config_regs + WRITE_FLASH);
wait_event(card->fw_wq, !ioread32(card->config_regs + FLASH_BUSY));
for (offset = 0; offset < fw->size; offset += blocksize) {
int i;
/* Clear write flag */
iowrite32(0, card->config_regs + WRITE_FLASH);
/* Set mode to Block Write */
/* dev_info(&card->dev->dev, "Set FPGA Flash mode to Block Write\n"); */
iowrite32(((chip * 2) + 1), card->config_regs + FLASH_MODE);
/* Copy block to buffer, swapping each 16 bits for Atmel flash */
for(i = 0; i < blocksize; i += 4) {
uint32_t word;
if (card->atmel_flash)
word = swahb32p((uint32_t *)(fw->data + offset + i));
else
word = *(uint32_t *)(fw->data + offset + i);
if(card->fpga_version > LEGACY_BUFFERS)
iowrite32(word, FLASH_BUF + i);
else
iowrite32(word, RX_BUF(card, 3) + i);
}
/* Specify block number and then trigger flash write */
iowrite32(offset / blocksize, card->config_regs + FLASH_BLOCK);
iowrite32(1, card->config_regs + WRITE_FLASH);
wait_event(card->fw_wq, !ioread32(card->config_regs + FLASH_BUSY));
}
release_firmware(fw);
iowrite32(0, card->config_regs + WRITE_FLASH);
iowrite32(0, card->config_regs + FPGA_MODE);
iowrite32(0, card->config_regs + FLASH_MODE);
dev_info(&card->dev->dev, "Returning FPGA to Data mode\n");
return 0;
}