New tool fm10k-flash #1
8 changed files with 715 additions and 156 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
||||||
/fm10k-dump
|
/fm10k-dump
|
||||||
/*.o
|
/fm10k-flash
|
||||||
|
*.o
|
||||||
/.idea
|
/.idea
|
25
COPYING
Normal file
25
COPYING
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
Copyright (c) 2014 - 2015, Intel Corporation
|
||||||
|
Copyright (c) 2020, FM10K-Documentation Contributors
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the copyright holders nor the names of its contributors
|
||||||
|
may be used to endorse or promote products derived from this software
|
||||||
|
without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
25
Makefile
25
Makefile
|
@ -1,14 +1,25 @@
|
||||||
CC=cc
|
CC=cc
|
||||||
CFLAGS=-Wall -Wno-unknown-warning-option -Wno-packed-bitfield-compat
|
CFLAGS=-ggdb -Og -Wall -Wno-unknown-warning-option -Wno-packed-bitfield-compat
|
||||||
|
|
||||||
default: fm10k-dump
|
default: all
|
||||||
|
|
||||||
fm10k-dump.o: fm10k-dump.c
|
all: fm10k-dump fm10k-flash
|
||||||
$(CC) -c fm10k-dump.c -o fm10k-dump.o $(CFLAGS)
|
|
||||||
|
|
||||||
fm10k-dump: fm10k-dump.o
|
fm10k.o: src/fm10k.c
|
||||||
$(CC) fm10k-dump.o -o fm10k-dump $(CFLAGS)
|
$(CC) -c src/fm10k.c -o src/fm10k.o $(CFLAGS)
|
||||||
|
|
||||||
|
fm10k-dump.o: src/fm10k-dump.c
|
||||||
|
$(CC) -c src/fm10k-dump.c -o src/fm10k-dump.o $(CFLAGS)
|
||||||
|
|
||||||
|
fm10k-dump: fm10k-dump.o fm10k.o
|
||||||
|
$(CC) src/fm10k-dump.o src/fm10k.o -o fm10k-dump $(CFLAGS)
|
||||||
|
|
||||||
|
fm10k-flash.o: src/fm10k-flash.c
|
||||||
|
$(CC) -c src/fm10k-flash.c -o src/fm10k-flash.o $(CFLAGS)
|
||||||
|
|
||||||
|
fm10k-flash: fm10k-flash.o fm10k.o
|
||||||
|
$(CC) src/fm10k-flash.o src/fm10k.o -o fm10k-flash $(CFLAGS)
|
||||||
clean:
|
clean:
|
||||||
-rm -f fm10k-dump
|
-rm -f fm10k-dump
|
||||||
-rm -f fm10k-dump.o
|
-rm -f fm10k-flash
|
||||||
|
-rm -f src/*.o
|
||||||
|
|
15
README.md
15
README.md
|
@ -1,6 +1,6 @@
|
||||||
# fm10k-dump
|
# fm10k-dump & fm10k-flash
|
||||||
|
|
||||||
Utility that allows dumping the SPI Flash Non-Volatile Memory of the FM10000 family of cards.
|
Utility that allows dumping/flashing the SPI Flash Non-Volatile Memory of the FM10000 family of cards.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
* GCC >= 4.4.0 or clang
|
* GCC >= 4.4.0 or clang
|
||||||
|
@ -13,13 +13,18 @@ Utility that allows dumping the SPI Flash Non-Volatile Memory of the FM10000 fam
|
||||||
## Compilation
|
## Compilation
|
||||||
* `$ make clean && make`
|
* `$ make clean && make`
|
||||||
* You can specify whether to use gcc or clang this way: `$ make CC=gcc` / `$ make CC=clang`
|
* You can specify whether to use gcc or clang this way: `$ make CC=gcc` / `$ make CC=clang`
|
||||||
* An executable named `./fm10k-dump` should now exist.
|
* Two executables named `./fm10k-dump` and `./fm10k-flash` should now exist.
|
||||||
|
|
||||||
## Usage example
|
## fm10k-dump usage example
|
||||||
* If the chip on the card is known to the tool, it'll set the image size to match. Alternatively it will use the platform minimum of 8Mbit.
|
* If the chip on the card is known to the tool, it'll set the image size to match. Alternatively it will use the platform minimum of 8Mbit.
|
||||||
* `# ./fm10k-dump /dev/uio0 outputImage.bin`
|
* `# ./fm10k-dump /dev/uio0 outputImage.bin`
|
||||||
* You can also force the image/chip size: `# ./fm10k-dump /dev/uio0 outputImage.bin 32`
|
* You can also force the image/chip size: `# ./fm10k-dump /dev/uio0 outputImage.bin 32`
|
||||||
|
|
||||||
|
## fm10k-flash usage example
|
||||||
|
* _fm10k-flash_ requires a backup of the existing image before flashing a new one, for safety measures. Use _fm10k-dump_ to take a backup copy of the current state before flashing.
|
||||||
|
* `# ./fm10k-dump /dev/uio0 backupImage.bin`
|
||||||
|
* `# ./fm10k-flash /dev/uio0 inputImage.bin backupImage.bin`
|
||||||
|
|
||||||
## License
|
## License
|
||||||
* BSD-3-Clause
|
* BSD-3-Clause
|
||||||
* See [fm10k-dump.c](fm10k-dump.c) header for more information.
|
* See [COPYING](COPYING) for the full license.
|
131
src/fm10k-dump.c
Normal file
131
src/fm10k-dump.c
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* File: fm10k-dump.c
|
||||||
|
* Creation Date: December 16, 2020
|
||||||
|
* Description: Utility to dump Non Volatile Memory on SPI for FM10K devices. Requires FM10K kernel module running with UIO enabled.
|
||||||
|
* Compile: make fm10k-dump
|
||||||
|
* Usage: ./fm10k-dump </dev/uio0> <output.bin> [readSizeInMegabits=8]
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 - 2015, Intel Corporation
|
||||||
|
* Copyright (c) 2020, FM10K-Documentation Contributors
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the copyright holders nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "fm10k.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char** argv){
|
||||||
|
int fdUIO;
|
||||||
|
FILE* fdOutput;
|
||||||
|
|
||||||
|
if(argc < 3){
|
||||||
|
printf("Usage: %s </dev/uio0> <output.bin> [forceSizeInMegabits, default 8]\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fdOutput = fopen(argv[2], "wb");
|
||||||
|
|
||||||
|
if(fdOutput == NULL){
|
||||||
|
printf("Could not create %s\n", argv[2]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fdUIO = open(argv[1], O_RDWR);
|
||||||
|
if(fdUIO <= 0){
|
||||||
|
printf("Unable to open uio device %s to read NVM\n", argv[1]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
void* memmapAddr;
|
||||||
|
memmapAddr = mmap(NULL, FM10K_UIO_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fdUIO, 0);
|
||||||
|
if (memmapAddr == MAP_FAILED) {
|
||||||
|
printf("Unable to map uio device %s to read NVM\n", argv[1]);
|
||||||
|
close(fdUIO);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPI_COMMAND_READ_MANUFACTURER_RESULT manufacturerInfo = fm10k_uio_spi_ReadManufacturerData((uintptr_t)memmapAddr);
|
||||||
|
if(manufacturerInfo.value == 0){
|
||||||
|
printf("Error getting manufacturer information\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("Manufacturer Info 0x%08x :: JEDEC Manufacturer ID 0x%02x family 0x%02x density 0x%02x %02x:%02x\n", manufacturerInfo.value, manufacturerInfo.fields.manufacturerId, manufacturerInfo.fields.familyCode, manufacturerInfo.fields.densityCode, manufacturerInfo.fields.subCode, manufacturerInfo.fields.productVariant);
|
||||||
|
|
||||||
|
unsigned int mbitsToRead = 8;
|
||||||
|
|
||||||
|
const KNOWN_FLASH_DEVICE* knownFlashDevice = getKnownFlashFromManufacturerData(manufacturerInfo);
|
||||||
|
|
||||||
|
if(knownFlashDevice != NULL){
|
||||||
|
printf("Device: %s\n", knownFlashDevice->name);
|
||||||
|
mbitsToRead = knownFlashDevice->sizeInMbit;
|
||||||
|
}else{
|
||||||
|
printf("Device: Unknown, defaulting %uMbit size\n", mbitsToRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(argc > 3){
|
||||||
|
if(mbitsToRead != 8){
|
||||||
|
printf("WARNING: %uMbit size was already auto-detected\n", mbitsToRead);
|
||||||
|
}
|
||||||
|
mbitsToRead = strtoul(argv[3], NULL, 10);
|
||||||
|
printf("Forcing %uMbit size\n", mbitsToRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mbitsToRead > 1024){
|
||||||
|
printf("Too many MBit: %u\n", mbitsToRead);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mbitsToRead < 8){
|
||||||
|
printf("Too few MBit: %u\n", mbitsToRead);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t bootImageSize = (mbitsToRead * 1024 * 1024) / 8;
|
||||||
|
|
||||||
|
uint8_t* value = malloc(bootImageSize);
|
||||||
|
|
||||||
|
uint32_t strideSize = 512;
|
||||||
|
|
||||||
|
for(uint32_t addr = 0; addr < bootImageSize; addr += strideSize){
|
||||||
|
printf("\rread @ 0x%08x / 0x%08x %d bytes", addr, bootImageSize, strideSize);
|
||||||
|
if(fm10k_uio_spi_ReadFlash((uintptr_t)memmapAddr, addr, value + addr, strideSize)){
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fwrite(value, 1, bootImageSize, fdOutput);
|
||||||
|
|
||||||
|
free(value);
|
||||||
|
|
||||||
|
fclose(fdOutput);
|
||||||
|
|
||||||
|
printf("\nRead %u bytes\n", bootImageSize);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
241
src/fm10k-flash.c
Normal file
241
src/fm10k-flash.c
Normal file
|
@ -0,0 +1,241 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* File: fm10k-flash.c
|
||||||
|
* Creation Date: December 20, 2020
|
||||||
|
* Description: Utility to flash Non Volatile Memory on SPI for FM10K devices. Requires FM10K kernel module running with UIO enabled.
|
||||||
|
* Compile: make fm10k-flash
|
||||||
|
* Usage: ./fm10k-flash </dev/uio0> <input.bin> <backup.bin>
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 - 2015, Intel Corporation
|
||||||
|
* Copyright (c) 2020, FM10K-Documentation Contributors
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the copyright holders nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "fm10k.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char** argv){
|
||||||
|
int fdUIO;
|
||||||
|
FILE* fdBackup;
|
||||||
|
FILE* fdInput;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if(argc < 4){
|
||||||
|
printf("Usage: %s </dev/uio0> <input.bin> <backup.bin>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fdInput = fopen(argv[2], "rb");
|
||||||
|
|
||||||
|
if(fdInput == NULL){
|
||||||
|
printf("Could not open %s\n", argv[2]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fdBackup = fopen(argv[3], "rb");
|
||||||
|
if(fdBackup == NULL){
|
||||||
|
printf("Could not open existing backup %s\n", argv[3]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(fdInput , 0, SEEK_END);
|
||||||
|
uint32_t fileSize = ftell(fdInput);
|
||||||
|
rewind(fdInput);
|
||||||
|
|
||||||
|
fseek(fdBackup , 0, SEEK_END);
|
||||||
|
uint32_t backupFileSize = ftell(fdBackup);
|
||||||
|
rewind(fdBackup);
|
||||||
|
|
||||||
|
if(backupFileSize < fileSize){
|
||||||
|
printf("Backup %d is smaller than new image %d\n", backupFileSize, fileSize);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fdUIO = open(argv[1], O_RDWR);
|
||||||
|
if(fdUIO <= 0){
|
||||||
|
printf("Unable to open uio device %s to write NVM\n", argv[1]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
void* memmapAddr;
|
||||||
|
memmapAddr = mmap(NULL, FM10K_UIO_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fdUIO, 0);
|
||||||
|
if (memmapAddr == MAP_FAILED) {
|
||||||
|
printf("Unable to map uio device %s to write NVM\n", argv[1]);
|
||||||
|
close(fdUIO);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPI_COMMAND_READ_MANUFACTURER_RESULT manufacturerInfo = fm10k_uio_spi_ReadManufacturerData((uintptr_t)memmapAddr);
|
||||||
|
if(manufacturerInfo.value == 0){
|
||||||
|
printf("Error getting manufacturer information\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("Manufacturer Info 0x%08x :: JEDEC Manufacturer ID 0x%02x family 0x%02x density 0x%02x %02x:%02x\n", manufacturerInfo.value, manufacturerInfo.fields.manufacturerId, manufacturerInfo.fields.familyCode, manufacturerInfo.fields.densityCode, manufacturerInfo.fields.subCode, manufacturerInfo.fields.productVariant);
|
||||||
|
|
||||||
|
unsigned int mbitsToReadMax = 8;
|
||||||
|
|
||||||
|
const KNOWN_FLASH_DEVICE* knownFlashDevice = getKnownFlashFromManufacturerData(manufacturerInfo);
|
||||||
|
|
||||||
|
if(knownFlashDevice != NULL){
|
||||||
|
printf("Device: %s\n", knownFlashDevice->name);
|
||||||
|
mbitsToReadMax = knownFlashDevice->sizeInMbit;
|
||||||
|
}else{
|
||||||
|
printf("Device: Unknown, defaulting max %uMbit size\n", mbitsToReadMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mbitsToReadMax > 1024){
|
||||||
|
printf("Too many MBit: %u\n", mbitsToReadMax);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mbitsToReadMax == 0){
|
||||||
|
printf("Too few MBit: %u\n", mbitsToReadMax);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t strideSize = 512;
|
||||||
|
uint32_t bootImageSizeMax = (mbitsToReadMax * 1024 * 1024) / 8;
|
||||||
|
|
||||||
|
if(fileSize > bootImageSizeMax){
|
||||||
|
printf("Image too large: have %d, can write max %d bytes.\n", fileSize, bootImageSizeMax);
|
||||||
|
return 1;
|
||||||
|
}else if(fileSize < bootImageSizeMax){
|
||||||
|
do{
|
||||||
|
bootImageSizeMax -= strideSize;
|
||||||
|
} while (fileSize < bootImageSizeMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* value = calloc(bootImageSizeMax, sizeof(uint8_t));
|
||||||
|
uint8_t* valueBackup = calloc(bootImageSizeMax, sizeof(uint8_t));
|
||||||
|
uint8_t* valueCheck = calloc(bootImageSizeMax, sizeof(uint8_t));
|
||||||
|
|
||||||
|
if(fread(value, 1, bootImageSizeMax, fdInput) != bootImageSizeMax){
|
||||||
|
printf("Error reading image file.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fread(valueBackup, 1, bootImageSizeMax, fdBackup) != bootImageSizeMax){
|
||||||
|
printf("Error reading backup image file.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(memcmp(value, valueBackup, bootImageSizeMax) == 0){
|
||||||
|
printf("NOTE: %s and %s have the same bytes.\n", argv[2], argv[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for(uint32_t addr = 0; addr < bootImageSizeMax; addr += strideSize){
|
||||||
|
printf("\rbackup check @ 0x%08x / 0x%08x %d bytes", addr, bootImageSizeMax, strideSize);
|
||||||
|
if(fm10k_uio_spi_ReadFlash((uintptr_t)memmapAddr, addr, valueCheck + addr, strideSize)){
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
if(memcmp(valueBackup, valueCheck, bootImageSizeMax) != 0){
|
||||||
|
printf("Backup image mismatch! Dump image again.\n");
|
||||||
|
return 1;
|
||||||
|
}else{
|
||||||
|
printf("Backup matches.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
|
|
||||||
|
printf("Disabling sector protection.\n");
|
||||||
|
fm10k_uio_spi_DisableSectorProtection((uintptr_t)memmapAddr);
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
|
|
||||||
|
|
||||||
|
for(uint32_t addr = 0; addr < bootImageSizeMax; addr += strideSize){
|
||||||
|
if(memcmp(valueBackup + addr, value + addr, strideSize) != 0){
|
||||||
|
printf("write @ 0x%08x\n", addr);
|
||||||
|
if(fm10k_uio_spi_WriteFlash((uintptr_t)memmapAddr, addr, value + addr, strideSize)){
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
|
|
||||||
|
|
||||||
|
for(uint32_t addr = 0; addr < bootImageSizeMax; addr += strideSize){
|
||||||
|
printf("\rverify check @ 0x%08x / 0x%08x %d bytes", addr, bootImageSizeMax, strideSize);
|
||||||
|
if(fm10k_uio_spi_ReadFlash((uintptr_t)memmapAddr, addr, valueCheck + addr, strideSize)){
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
for(uint32_t addr = 0; addr < bootImageSizeMax; addr += 4){
|
||||||
|
if(*(uint32_t*)(value + addr) != *(uint32_t*)(valueCheck + addr)){
|
||||||
|
printf("@0x%08x: 0x%08x != 0x%08x\n", addr, *(uint32_t*)(value + addr), *(uint32_t*)(valueCheck + addr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
|
|
||||||
|
if(memcmp(value, valueCheck, bootImageSizeMax) != 0){
|
||||||
|
printf("Data written mismatch! Replacing with backup.\n");
|
||||||
|
|
||||||
|
for(uint32_t addr = 0; addr < bootImageSizeMax; addr += strideSize){
|
||||||
|
if(memcmp(valueBackup + addr, valueCheck + addr, strideSize) != 0){
|
||||||
|
printf("write backup @ 0x%08x\n", addr);
|
||||||
|
if(fm10k_uio_spi_WriteFlash((uintptr_t)memmapAddr, addr, valueBackup + addr, strideSize)){
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
printf("Data written verified.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
free(value);
|
||||||
|
free(valueBackup);
|
||||||
|
free(valueCheck);
|
||||||
|
|
||||||
|
fclose(fdInput);
|
||||||
|
fclose(fdBackup);
|
||||||
|
|
||||||
|
printf("\nWritten %u bytes\n", bootImageSizeMax);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -1,9 +1,6 @@
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* File: fm10k-dump.c
|
* File: fm10k.c
|
||||||
* Creation Date: December 16, 2020
|
* Creation Date: December 20, 2020
|
||||||
* Description: Utility to dump Non Volatile Memory on SPI for FM10K devices. Requires FM10K kernel module running with UIO enabled.
|
|
||||||
* Compile: gcc -o fm10k-dump fm10k-dump.c
|
|
||||||
* Usage: ./fm10k-dump </dev/uio0> <output.bin> [readSizeInMegabits=8]
|
|
||||||
*
|
*
|
||||||
* Copyright (c) 2014 - 2015, Intel Corporation
|
* Copyright (c) 2014 - 2015, Intel Corporation
|
||||||
* Copyright (c) 2020, FM10K-Documentation Contributors
|
* Copyright (c) 2020, FM10K-Documentation Contributors
|
||||||
|
@ -32,67 +29,14 @@
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include "fm10k.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <time.h>
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
#define FM10K_UIO_SIZE 0x0000000004000000
|
KNOWN_FLASH_DEVICE KNOWN_FLASH_DEVICE_LIST[] = {
|
||||||
#define FM10K_UIO_OFFSET 0
|
{{0x0101271f}, "Adesto AT45DB321E 32-Mbit", 32},
|
||||||
|
{{0}, "", 0}
|
||||||
//From Datasheet, 11.25.1 MGMT Map, Table 11-37
|
};
|
||||||
#define FM10K_REGISTER_BASE 0
|
|
||||||
|
|
||||||
#define FM10K_REGISTER_SPI_TX_DATA ((0xC26) + (FM10K_REGISTER_BASE))
|
|
||||||
#define FM10K_REGISTER_SPI_RX_DATA ((0xC27) + (FM10K_REGISTER_BASE))
|
|
||||||
#define FM10K_REGISTER_SPI_HEADER ((0xC28) + (FM10K_REGISTER_BASE))
|
|
||||||
#define FM10K_REGISTER_SPI_CTRL ((0xC29) + (FM10K_REGISTER_BASE))
|
|
||||||
|
|
||||||
#define FM10K_SPI_FREQ_KHZ 50000
|
|
||||||
|
|
||||||
#define FM10K_SPI_HEADER_COMMAND_READ_BYTES 0x3
|
|
||||||
#define FM10K_SPI_HEADER_COMMAND_READ_MANUFACTURER_INFORMATION 0x9F
|
|
||||||
|
|
||||||
/* Test for GCC >= 4.4.0, see https://gcc.gnu.org/gcc-4.4/changes.html : Packed bit-fields of type char were not properly bit-packed on many targets prior to GCC 4.4 */
|
|
||||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 4)) || __clang__
|
|
||||||
|
|
||||||
typedef union {
|
|
||||||
struct {
|
|
||||||
uint16_t Freq : 10; // Actual speed is PCIE_REFCLK/(2*(1+Freq))
|
|
||||||
uint8_t Enable : 1;
|
|
||||||
uint8_t Command : 4; // 0b00 = reset
|
|
||||||
uint8_t HeaderSize : 2; // 0b00 = 4 bytes
|
|
||||||
uint8_t DataSize : 2; // 0b00 = 4 bytes
|
|
||||||
uint8_t DataShiftMethod : 2; // 0b00 = SINGLE, 0b01 = DUAL, 0b10 = QUAD, 0b11 = Reserved
|
|
||||||
uint8_t Busy : 1; // volatile ReadOnly
|
|
||||||
uint8_t Selected : 1; // volatile ReadOnly
|
|
||||||
uint8_t DirIO2 : 1; // 0b0 = Input, 0b1 = Output
|
|
||||||
uint8_t DirIO3 : 1; // 0b0 = Input, 0b1 = Output
|
|
||||||
uint8_t PinIO2 : 1; // volatile ReadWrite
|
|
||||||
uint8_t PinIO3 : 1; // volatile ReadWrite
|
|
||||||
uint8_t Reserved : 5;
|
|
||||||
} __attribute__((packed)) fields;
|
|
||||||
uint32_t value;
|
|
||||||
} SPI_CTRL;
|
|
||||||
|
|
||||||
typedef union {
|
|
||||||
struct {
|
|
||||||
uint8_t RESERVED : 8;
|
|
||||||
uint8_t productVariant : 5;
|
|
||||||
uint8_t subCode : 3;
|
|
||||||
uint8_t densityCode : 5;
|
|
||||||
uint8_t familyCode : 3;
|
|
||||||
uint8_t manufacturerId : 8;
|
|
||||||
} __attribute__((packed)) fields;
|
|
||||||
uint32_t value;
|
|
||||||
} SPI_COMMAND_READ_MANUFACTURER_RESULT;
|
|
||||||
|
|
||||||
#else
|
|
||||||
#error "Packed bit-fields of type char were not properly bit-packed on many targets prior to GCC 4.4, upgrade to GCC >= 4.4."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void ReadRegister32(uintptr_t mem, uint32_t addr, uint32_t* value) {
|
void ReadRegister32(uintptr_t mem, uint32_t addr, uint32_t* value) {
|
||||||
*value = *(((uint32_t*)mem) + addr);
|
*value = *(((uint32_t*)mem) + addr);
|
||||||
|
@ -220,8 +164,12 @@ SPI_COMMAND_READ_MANUFACTURER_RESULT fm10k_uio_spi_ReadManufacturerData(uintptr_
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t rxData;
|
||||||
/* get data */
|
/* get data */
|
||||||
ReadRegister32(mem, FM10K_REGISTER_SPI_RX_DATA, &result.value);
|
ReadRegister32(mem, FM10K_REGISTER_SPI_RX_DATA, &rxData);
|
||||||
|
|
||||||
|
result.value = ((rxData>>24)&0xff) | ((rxData<<8)&0xff0000) | ((rxData>>8)&0xff00) | ((rxData<<24)&0xff000000);
|
||||||
|
|
||||||
|
|
||||||
/* release CS */
|
/* release CS */
|
||||||
spiCtrl.fields.Command = 0b1000;
|
spiCtrl.fields.Command = 0b1000;
|
||||||
|
@ -236,8 +184,7 @@ SPI_COMMAND_READ_MANUFACTURER_RESULT fm10k_uio_spi_ReadManufacturerData(uintptr_
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t fm10k_uio_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data, uint32_t len){
|
||||||
uint32_t fm10k_uio_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data, int32_t len){
|
|
||||||
|
|
||||||
SPI_CTRL currentSpiCtrl;
|
SPI_CTRL currentSpiCtrl;
|
||||||
SPI_CTRL spiCtrl = {0};
|
SPI_CTRL spiCtrl = {0};
|
||||||
|
@ -245,8 +192,8 @@ uint32_t fm10k_uio_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data,
|
||||||
uint32_t rxData;
|
uint32_t rxData;
|
||||||
uint32_t header;
|
uint32_t header;
|
||||||
int32_t freq;
|
int32_t freq;
|
||||||
int32_t cnt;
|
uint32_t cnt;
|
||||||
int32_t numRead;
|
uint32_t numRead;
|
||||||
|
|
||||||
fm10k_uio_spi_Enable(mem);
|
fm10k_uio_spi_Enable(mem);
|
||||||
|
|
||||||
|
@ -307,94 +254,170 @@ uint32_t fm10k_uio_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv){
|
uint32_t fm10k_uio_spi_EnableSectorProtection(uintptr_t mem){
|
||||||
int fdUIO;
|
SPI_CTRL currentSpiCtrl;
|
||||||
FILE* fdOutput;
|
SPI_CTRL spiCtrl = {0};
|
||||||
|
|
||||||
if(argc < 3){
|
uint32_t header;
|
||||||
printf("Usage: %s </dev/uio0> <output.bin> [forceSizeInMegabits, default 8]\n", argv[0]);
|
int32_t freq;
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fdOutput = fopen(argv[2], "wb");
|
fm10k_uio_spi_Enable(mem);
|
||||||
|
|
||||||
if(fdOutput == NULL){
|
|
||||||
printf("Could not create %s\n", argv[2]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fdUIO = open(argv[1], O_RDWR);
|
|
||||||
if(fdUIO <= 0){
|
|
||||||
printf("Unable to open uio device %s to read NVM\n", argv[1]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
void* memmapAddr;
|
|
||||||
memmapAddr = mmap(NULL, FM10K_UIO_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fdUIO, 0);
|
|
||||||
if (memmapAddr == MAP_FAILED) {
|
|
||||||
printf("Unable to map uio device %s to read NVM\n", argv[1]);
|
|
||||||
close(fdUIO);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
SPI_COMMAND_READ_MANUFACTURER_RESULT manufacturerInfo = fm10k_uio_spi_ReadManufacturerData((uintptr_t)memmapAddr);
|
|
||||||
if(manufacturerInfo.value == 0){
|
|
||||||
printf("Error getting manufacturer information\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
printf("Manufacturer Info 0x%08x :: JEDEC Manufacturer ID 0x%02x family 0x%02x density 0x%02x %02x:%02x\n", manufacturerInfo.value, manufacturerInfo.fields.manufacturerId, manufacturerInfo.fields.familyCode, manufacturerInfo.fields.densityCode, manufacturerInfo.fields.subCode, manufacturerInfo.fields.productVariant);
|
|
||||||
|
|
||||||
unsigned int mbitsToRead = 8;
|
|
||||||
|
|
||||||
|
|
||||||
switch (manufacturerInfo.value >> 8) {
|
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, ¤tSpiCtrl.value);
|
||||||
case 0x1f2701:
|
|
||||||
printf("Device: Adesto AT45Dxxx Standard:1 32Mbit\n");
|
|
||||||
mbitsToRead = 32;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf("Device: Unknown, defaulting %uMbit size\n", mbitsToRead);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(argc > 3){
|
if(FM10K_SPI_FREQ_KHZ > 0){
|
||||||
if(mbitsToRead != 8){
|
freq = ((100000 / (int)FM10K_SPI_FREQ_KHZ) / 2) - 1;
|
||||||
printf("WARNING: %uMbit size was already auto-detected\n", mbitsToRead);
|
if (freq < 0){
|
||||||
|
freq = 0;
|
||||||
}
|
}
|
||||||
mbitsToRead = strtoul(argv[3], NULL, 10);
|
spiCtrl.fields.Freq = freq;
|
||||||
printf("Forcing %uMbit size\n", mbitsToRead);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mbitsToRead > 1024){
|
spiCtrl.fields.Enable = 1;
|
||||||
printf("Too many MBit: %u\n", mbitsToRead);
|
|
||||||
|
header = (0x3D << 24) | (0x2A << 16) | (0x7F) | (0xA9);
|
||||||
|
WriteRegister32(mem, FM10K_REGISTER_SPI_HEADER, header);
|
||||||
|
|
||||||
|
/* first loop only: set send header flag. Following loops: shift only data. */
|
||||||
|
spiCtrl.fields.Command |= 0b0001;
|
||||||
|
|
||||||
|
/* send command to the flash */
|
||||||
|
if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mbitsToRead < 8){
|
/* release CS */
|
||||||
printf("Too few MBit: %u\n", mbitsToRead);
|
spiCtrl.fields.Command = 0b1000;
|
||||||
|
if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t bootImageSize = (mbitsToRead * 1024 * 1024) / 8;
|
fm10k_uio_spi_Disable(mem);
|
||||||
|
|
||||||
uint8_t* value = malloc(bootImageSize);
|
|
||||||
|
|
||||||
uint32_t strideSize = 1024;
|
|
||||||
|
|
||||||
for(uint32_t addr = 0; addr < bootImageSize; addr += strideSize){
|
|
||||||
printf("\rread @ 0x%08x / 0x%08x %d bytes", addr, bootImageSize, strideSize);
|
|
||||||
if(fm10k_uio_spi_ReadFlash((uintptr_t)memmapAddr, addr, value + addr, strideSize)){
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fwrite(value, 1, bootImageSize, fdOutput);
|
|
||||||
|
|
||||||
free(value);
|
|
||||||
|
|
||||||
fclose(fdOutput);
|
|
||||||
|
|
||||||
printf("\nRead %u bytes\n", bootImageSize);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t fm10k_uio_spi_DisableSectorProtection(uintptr_t mem){
|
||||||
|
SPI_CTRL currentSpiCtrl;
|
||||||
|
SPI_CTRL spiCtrl = {0};
|
||||||
|
|
||||||
|
uint32_t header;
|
||||||
|
int32_t freq;
|
||||||
|
|
||||||
|
fm10k_uio_spi_Enable(mem);
|
||||||
|
|
||||||
|
|
||||||
|
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, ¤tSpiCtrl.value);
|
||||||
|
|
||||||
|
if(FM10K_SPI_FREQ_KHZ > 0){
|
||||||
|
freq = ((100000 / (int)FM10K_SPI_FREQ_KHZ) / 2) - 1;
|
||||||
|
if (freq < 0){
|
||||||
|
freq = 0;
|
||||||
|
}
|
||||||
|
spiCtrl.fields.Freq = freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
spiCtrl.fields.Enable = 1;
|
||||||
|
|
||||||
|
header = (0x3D << 24) | (0x2A << 16) | (0x7F) | (0x9A);
|
||||||
|
WriteRegister32(mem, FM10K_REGISTER_SPI_HEADER, header);
|
||||||
|
|
||||||
|
/* first loop only: set send header flag. Following loops: shift only data. */
|
||||||
|
spiCtrl.fields.Command |= 0b0001;
|
||||||
|
|
||||||
|
/* send command to the flash */
|
||||||
|
if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* release CS */
|
||||||
|
spiCtrl.fields.Command = 0b1000;
|
||||||
|
if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fm10k_uio_spi_Disable(mem);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t fm10k_uio_spi_WriteFlash(uintptr_t mem, uint32_t address, const uint8_t* data, uint32_t len){
|
||||||
|
|
||||||
|
SPI_CTRL currentSpiCtrl;
|
||||||
|
SPI_CTRL spiCtrl = {0};
|
||||||
|
|
||||||
|
uint32_t txData;
|
||||||
|
uint32_t header;
|
||||||
|
int32_t freq;
|
||||||
|
uint32_t cnt;
|
||||||
|
uint32_t numWrite;
|
||||||
|
|
||||||
|
fm10k_uio_spi_Enable(mem);
|
||||||
|
|
||||||
|
|
||||||
|
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, ¤tSpiCtrl.value);
|
||||||
|
|
||||||
|
if(FM10K_SPI_FREQ_KHZ > 0){
|
||||||
|
freq = ((100000 / (int)FM10K_SPI_FREQ_KHZ) / 2) - 1;
|
||||||
|
if (freq < 0){
|
||||||
|
freq = 0;
|
||||||
|
}
|
||||||
|
spiCtrl.fields.Freq = freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
spiCtrl.fields.Enable = 1;
|
||||||
|
|
||||||
|
/* header: command (1 byte: READ_MODIFY_WRITE) + address (3 bytes) */
|
||||||
|
header = (FM10K_SPI_HEADER_COMMAND_READ_MODIFY_WRITE_512 << 24) | (address & 0xffffff);
|
||||||
|
WriteRegister32(mem, FM10K_REGISTER_SPI_HEADER, header);
|
||||||
|
|
||||||
|
/* first loop only: set send header flag. Following loops: shift only data. */
|
||||||
|
spiCtrl.fields.Command |= 0b0001;
|
||||||
|
|
||||||
|
cnt = 0;
|
||||||
|
while (cnt < len){
|
||||||
|
/* determine the number of data bytes to read [1..4] */
|
||||||
|
numWrite = (len - cnt) > 3 ? 4 : (len - cnt);
|
||||||
|
/* set 'shift data' flag and number of data bytes */
|
||||||
|
spiCtrl.fields.Command |= 0b0100;
|
||||||
|
spiCtrl.fields.DataSize = numWrite & 0b11;
|
||||||
|
|
||||||
|
txData = 0;
|
||||||
|
while (numWrite--) {
|
||||||
|
txData = (txData << 8) | data[cnt++];
|
||||||
|
}
|
||||||
|
/* set data to be written */
|
||||||
|
WriteRegister32(mem, FM10K_REGISTER_SPI_TX_DATA, txData);
|
||||||
|
|
||||||
|
/* send command to the flash */
|
||||||
|
if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
spiCtrl.fields.Command = 0b0000;
|
||||||
|
spiCtrl.fields.DataSize = 0b0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* release CS */
|
||||||
|
spiCtrl.fields.Command = 0b1000;
|
||||||
|
if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fm10k_uio_spi_Disable(mem);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const KNOWN_FLASH_DEVICE* getKnownFlashFromManufacturerData(SPI_COMMAND_READ_MANUFACTURER_RESULT data){
|
||||||
|
uint32_t deviceCount = (sizeof(KNOWN_FLASH_DEVICE_LIST) / sizeof(KNOWN_FLASH_DEVICE)) - 1;
|
||||||
|
for(uint32_t i = 0; i < deviceCount; ++i){
|
||||||
|
if(KNOWN_FLASH_DEVICE_LIST[i].data.value == data.value){
|
||||||
|
return &KNOWN_FLASH_DEVICE_LIST[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
122
src/fm10k.h
Normal file
122
src/fm10k.h
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* File: fm10k.h
|
||||||
|
* Creation Date: December 20, 2020
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 - 2015, Intel Corporation
|
||||||
|
* Copyright (c) 2020, FM10K-Documentation Contributors
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the copyright holders nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#define FM10K_UIO_SIZE 0x0000000004000000
|
||||||
|
#define FM10K_UIO_OFFSET 0
|
||||||
|
|
||||||
|
//From Datasheet, 11.25.1 MGMT Map, Table 11-37
|
||||||
|
#define FM10K_REGISTER_BASE 0
|
||||||
|
|
||||||
|
#define FM10K_REGISTER_SPI_TX_DATA ((0xC26) + (FM10K_REGISTER_BASE))
|
||||||
|
#define FM10K_REGISTER_SPI_RX_DATA ((0xC27) + (FM10K_REGISTER_BASE))
|
||||||
|
#define FM10K_REGISTER_SPI_HEADER ((0xC28) + (FM10K_REGISTER_BASE))
|
||||||
|
#define FM10K_REGISTER_SPI_CTRL ((0xC29) + (FM10K_REGISTER_BASE))
|
||||||
|
|
||||||
|
#define FM10K_SPI_FREQ_KHZ 50000
|
||||||
|
|
||||||
|
#define FM10K_SPI_HEADER_COMMAND_PAGE_PROGRAM 0x02
|
||||||
|
#define FM10K_SPI_HEADER_COMMAND_READ_BYTES 0x03
|
||||||
|
#define FM10K_SPI_HEADER_COMMAND_READ_MODIFY_WRITE_512 0x58
|
||||||
|
#define FM10K_SPI_HEADER_COMMAND_READ_MANUFACTURER_INFORMATION 0x9F
|
||||||
|
|
||||||
|
/* Test for GCC >= 4.4.0, see https://gcc.gnu.org/gcc-4.4/changes.html : Packed bit-fields of type char were not properly bit-packed on many targets prior to GCC 4.4 */
|
||||||
|
#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 4)) || __clang__
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
uint32_t value;
|
||||||
|
struct {
|
||||||
|
uint16_t Freq : 10; // Actual speed is PCIE_REFCLK/(2*(1+Freq))
|
||||||
|
uint8_t Enable : 1;
|
||||||
|
uint8_t Command : 4; // 0b00 = reset
|
||||||
|
uint8_t HeaderSize : 2; // 0b00 = 4 bytes
|
||||||
|
uint8_t DataSize : 2; // 0b00 = 4 bytes
|
||||||
|
uint8_t DataShiftMethod : 2; // 0b00 = SINGLE, 0b01 = DUAL, 0b10 = QUAD, 0b11 = Reserved
|
||||||
|
uint8_t Busy : 1; // volatile ReadOnly
|
||||||
|
uint8_t Selected : 1; // volatile ReadOnly
|
||||||
|
uint8_t DirIO2 : 1; // 0b0 = Input, 0b1 = Output
|
||||||
|
uint8_t DirIO3 : 1; // 0b0 = Input, 0b1 = Output
|
||||||
|
uint8_t PinIO2 : 1; // volatile ReadWrite
|
||||||
|
uint8_t PinIO3 : 1; // volatile ReadWrite
|
||||||
|
uint8_t Reserved : 5;
|
||||||
|
} __attribute__((packed)) fields;
|
||||||
|
} SPI_CTRL;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
uint32_t value;
|
||||||
|
struct {
|
||||||
|
uint8_t manufacturerId : 8;
|
||||||
|
uint8_t densityCode : 5;
|
||||||
|
uint8_t familyCode : 3;
|
||||||
|
uint8_t productVariant : 5;
|
||||||
|
uint8_t subCode : 3;
|
||||||
|
uint8_t RESERVED : 8;
|
||||||
|
} __attribute__((packed)) fields;
|
||||||
|
} SPI_COMMAND_READ_MANUFACTURER_RESULT;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
SPI_COMMAND_READ_MANUFACTURER_RESULT data;
|
||||||
|
char name[64];
|
||||||
|
uint32_t sizeInMbit;
|
||||||
|
} KNOWN_FLASH_DEVICE;
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Packed bit-fields of type char were not properly bit-packed on many targets prior to GCC 4.4, upgrade to GCC >= 4.4."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void ReadRegister32(uintptr_t mem, uint32_t addr, uint32_t* value);
|
||||||
|
|
||||||
|
void WriteRegister32(uintptr_t mem, uint32_t addr, uint32_t value);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t get_interval_diff(struct timeval *begin, struct timeval *end);
|
||||||
|
|
||||||
|
uint32_t fm10k_uio_spi_SetCtrlReg(uintptr_t mem, SPI_CTRL value);
|
||||||
|
|
||||||
|
void fm10k_uio_spi_Enable(uintptr_t mem);
|
||||||
|
|
||||||
|
void fm10k_uio_spi_Disable(uintptr_t mem);
|
||||||
|
|
||||||
|
|
||||||
|
//Error if result.value is 0x00
|
||||||
|
SPI_COMMAND_READ_MANUFACTURER_RESULT fm10k_uio_spi_ReadManufacturerData(uintptr_t mem);
|
||||||
|
const KNOWN_FLASH_DEVICE* getKnownFlashFromManufacturerData(SPI_COMMAND_READ_MANUFACTURER_RESULT data);
|
||||||
|
|
||||||
|
uint32_t fm10k_uio_spi_EnableSectorProtection(uintptr_t mem);
|
||||||
|
uint32_t fm10k_uio_spi_DisableSectorProtection(uintptr_t mem);
|
||||||
|
|
||||||
|
uint32_t fm10k_uio_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data, uint32_t len);
|
||||||
|
uint32_t fm10k_uio_spi_WriteFlash(uintptr_t mem, uint32_t address, const uint8_t* data, uint32_t len);
|
Loading…
Reference in a new issue