diff --git a/fm10k-dump.c b/fm10k-dump.c index b0c210d..6088f4d 100644 --- a/fm10k-dump.c +++ b/fm10k-dump.c @@ -3,7 +3,7 @@ * 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: gcc -o fm10k-dump fm10k-dump.c - * Usage: ./fm10k-dump [readSizeInMegabytes=1] + * Usage: ./fm10k-dump [readSizeInMegabits=8] * * Copyright (c) 2014 - 2015, Intel Corporation * Copyright (c) 2020, FM10K-Documentation Contributors @@ -54,9 +54,11 @@ #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)) + typedef union { struct { uint16_t Freq : 10; // Actual speed is PCIE_REFCLK/(2*(1+Freq)) @@ -75,6 +77,19 @@ typedef union { } __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 @@ -116,8 +131,7 @@ uint32_t get_interval_diff(struct timeval *begin, struct timeval *end) { uint32_t fm10k_uio_spi_SetCtrlReg(uintptr_t mem, SPI_CTRL value){ struct timeval startTime; uint8_t isTimeout = 0; - SPI_CTRL spiCtrl; - spiCtrl.value = 0; + SPI_CTRL spiCtrl = {0}; WriteRegister32(mem, FM10K_REGISTER_SPI_CTRL, value.value); @@ -166,11 +180,67 @@ void fm10k_uio_spi_Disable(uintptr_t mem){ WriteRegister32(mem, FM10K_REGISTER_SPI_CTRL, newSpiCtrl.value); } + +//Error if result.value is 0x00 +SPI_COMMAND_READ_MANUFACTURER_RESULT fm10k_uio_spi_ReadManufacturerData(uintptr_t mem){ + + SPI_COMMAND_READ_MANUFACTURER_RESULT result = {0}; + 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 = currentSpiCtrl.fields.Enable; + + /* header: command (1 byte: READ_BYTES) */ + header = FM10K_SPI_HEADER_COMMAND_READ_MANUFACTURER_INFORMATION; + WriteRegister32(mem, FM10K_REGISTER_SPI_HEADER, header); + + /* first loop only: set send header flag. Following loops: shift only data. */ + spiCtrl.fields.Command |= 0b0001; + spiCtrl.fields.Command |= 0b0100; + spiCtrl.fields.HeaderSize = 1; + spiCtrl.fields.DataSize = 4 & 0b11; + + if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){ + return result; + } + + /* get data */ + ReadRegister32(mem, FM10K_REGISTER_SPI_RX_DATA, &result.value); + + /* release CS */ + spiCtrl.fields.Command = 0b1000; + if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){ + result.value = 0; + return result; + } + + + fm10k_uio_spi_Disable(mem); + + return result; +} + + uint32_t fm10k_uio_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data, int32_t len){ SPI_CTRL currentSpiCtrl; - SPI_CTRL spiCtrl; - spiCtrl.value = 0; + SPI_CTRL spiCtrl = {0}; uint32_t rxData; uint32_t header; @@ -242,7 +312,7 @@ int main(int argc, char** argv){ FILE* fdOutput; if(argc < 3){ - printf("Usage: %s [sizeInMB, default 1]\n", argv[0]); + printf("Usage: %s [forceSizeInMegabits, default 8]\n", argv[0]); return 1; } @@ -266,26 +336,53 @@ int main(int argc, char** argv){ return 1; } - unsigned int mbToRead = 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); - if(argc > 3){ - mbToRead = strtoul(argv[3], NULL, 10); + unsigned int mbitsToRead = 8; + + + switch (manufacturerInfo.value >> 8) { + case 0x1f2701: + printf("Device: Adesto AT45Dxxx Standard:1 32Mbit\n"); + mbitsToRead = 32; + break; + default: + printf("Device: Unknown, defaulting %uMbit size\n", mbitsToRead); + break; } - if(mbToRead > 128){ - printf("Too many MB: %u\n", mbToRead); + 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; } - uint32_t bootImageSize = mbToRead * 1024 * 1024; + 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 = 1024; for(uint32_t addr = 0; addr < bootImageSize; addr += strideSize){ - printf("\rLOC 0x%08x MAX 0x%08x", addr, bootImageSize); - if(fm10k_uio_spi_ReadFlash((uintptr_t)(uint32_t *)memmapAddr, addr, value + 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; } }