New tool fm10k-flash #1
4 changed files with 440 additions and 271 deletions
12
Makefile
12
Makefile
|
@ -1,14 +1,20 @@
|
||||||
CC=cc
|
CC=cc
|
||||||
CFLAGS=-Wall -Wno-unknown-warning-option -Wno-packed-bitfield-compat
|
CFLAGS=-Wall -Wno-unknown-warning-option -Wno-packed-bitfield-compat
|
||||||
|
|
||||||
default: fm10k-dump
|
default: all
|
||||||
|
|
||||||
|
all: fm10k-dump
|
||||||
|
|
||||||
|
fm10k.o: fm10k.c
|
||||||
|
$(CC) -c fm10k.c -o fm10k.o $(CFLAGS)
|
||||||
|
|
||||||
fm10k-dump.o: fm10k-dump.c
|
fm10k-dump.o: fm10k-dump.c
|
||||||
$(CC) -c fm10k-dump.c -o fm10k-dump.o $(CFLAGS)
|
$(CC) -c fm10k-dump.c -o fm10k-dump.o $(CFLAGS)
|
||||||
|
|
||||||
fm10k-dump: fm10k-dump.o
|
fm10k-dump: fm10k-dump.o fm10k.o
|
||||||
$(CC) fm10k-dump.o -o fm10k-dump $(CFLAGS)
|
$(CC) fm10k-dump.o fm10k.o -o fm10k-dump $(CFLAGS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
-rm -f fm10k-dump
|
-rm -f fm10k-dump
|
||||||
-rm -f fm10k-dump.o
|
-rm -f fm10k-dump.o
|
||||||
|
-rm -f fm10k.o
|
||||||
|
|
269
fm10k-dump.c
269
fm10k-dump.c
|
@ -32,280 +32,13 @@
|
||||||
* 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 <stdlib.h>
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.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_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) {
|
|
||||||
*value = *(((uint32_t*)mem) + addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WriteRegister32(uintptr_t mem, uint32_t addr, uint32_t value) {
|
|
||||||
*(uint32_t volatile*)(((uint32_t*)mem) + addr) = value;
|
|
||||||
|
|
||||||
//If returning instantly this will caused missed writes. nanosleep wait of 1 nsec was too much. Busy wait works
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
|
||||||
volatile uint32_t dummy;
|
|
||||||
for(uint32_t i = 0; i < 100; ++i){
|
|
||||||
dummy = i;
|
|
||||||
}
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t get_interval_diff(struct timeval *begin, struct timeval *end) {
|
|
||||||
struct timeval endT;
|
|
||||||
struct timeval diff;
|
|
||||||
|
|
||||||
if (end == NULL) {
|
|
||||||
gettimeofday(&endT, NULL);
|
|
||||||
} else {
|
|
||||||
endT.tv_sec = end->tv_sec;
|
|
||||||
endT.tv_usec = end->tv_usec;
|
|
||||||
}
|
|
||||||
|
|
||||||
diff.tv_sec = endT.tv_sec - begin->tv_sec;
|
|
||||||
diff.tv_usec = endT.tv_usec - begin->tv_usec;
|
|
||||||
|
|
||||||
return (diff.tv_sec * 1000 + diff.tv_usec / 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t fm10k_uio_spi_SetCtrlReg(uintptr_t mem, SPI_CTRL value){
|
|
||||||
struct timeval startTime;
|
|
||||||
uint8_t isTimeout = 0;
|
|
||||||
SPI_CTRL spiCtrl = {0};
|
|
||||||
|
|
||||||
WriteRegister32(mem, FM10K_REGISTER_SPI_CTRL, value.value);
|
|
||||||
|
|
||||||
gettimeofday(&startTime, NULL);
|
|
||||||
do{
|
|
||||||
if(isTimeout){
|
|
||||||
printf("Timeout waiting for SPI_CTRL.Busy 0x%02x\n", spiCtrl.value);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(get_interval_diff(&startTime, NULL) > 50){
|
|
||||||
isTimeout = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &spiCtrl.value);
|
|
||||||
|
|
||||||
} while (spiCtrl.fields.Busy);
|
|
||||||
|
|
||||||
/* write back SPI_CTRL with command = 0 */
|
|
||||||
spiCtrl.fields.Command = 0;
|
|
||||||
WriteRegister32(mem, FM10K_REGISTER_SPI_CTRL, spiCtrl.value);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fm10k_uio_spi_Enable(uintptr_t mem){
|
|
||||||
//ENABLE SPI
|
|
||||||
SPI_CTRL spiCtrl;
|
|
||||||
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &spiCtrl.value);
|
|
||||||
/* keep current freq setting and set SPI Enable */
|
|
||||||
SPI_CTRL newSpiCtrl;
|
|
||||||
newSpiCtrl.value = 0;
|
|
||||||
newSpiCtrl.fields.Freq = spiCtrl.fields.Freq;
|
|
||||||
newSpiCtrl.fields.Enable = 1;
|
|
||||||
WriteRegister32(mem, FM10K_REGISTER_SPI_CTRL, newSpiCtrl.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fm10k_uio_spi_Disable(uintptr_t mem){
|
|
||||||
//DISABLE SPI
|
|
||||||
SPI_CTRL spiCtrl;
|
|
||||||
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &spiCtrl.value);
|
|
||||||
/* keep current freq setting and set SPI Enable = 0 */
|
|
||||||
SPI_CTRL newSpiCtrl;
|
|
||||||
newSpiCtrl.value = 0;
|
|
||||||
newSpiCtrl.fields.Freq = spiCtrl.fields.Freq;
|
|
||||||
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 = {0};
|
|
||||||
|
|
||||||
uint32_t rxData;
|
|
||||||
uint32_t header;
|
|
||||||
int32_t freq;
|
|
||||||
int32_t cnt;
|
|
||||||
int32_t numRead;
|
|
||||||
|
|
||||||
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) + address (3 bytes) */
|
|
||||||
header = (FM10K_SPI_HEADER_COMMAND_READ_BYTES << 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] */
|
|
||||||
numRead = (len - cnt) > 3 ? 4 : (len - cnt);
|
|
||||||
/* set 'shift data' flag and number of data bytes */
|
|
||||||
spiCtrl.fields.Command |= 0b0100;
|
|
||||||
spiCtrl.fields.DataSize = numRead & 0b11;
|
|
||||||
|
|
||||||
if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get data */
|
|
||||||
ReadRegister32(mem, FM10K_REGISTER_SPI_RX_DATA, &rxData);
|
|
||||||
|
|
||||||
/* push the read data into the array */
|
|
||||||
while (numRead) {
|
|
||||||
numRead--;
|
|
||||||
data[cnt++] = (rxData >> (numRead * 8)) & 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char** argv){
|
int main(int argc, char** argv){
|
||||||
int fdUIO;
|
int fdUIO;
|
||||||
|
|
319
fm10k.c
Normal file
319
fm10k.c
Normal file
|
@ -0,0 +1,319 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* File: fm10k.c
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "fm10k.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void ReadRegister32(uintptr_t mem, uint32_t addr, uint32_t* value) {
|
||||||
|
*value = *(((uint32_t*)mem) + addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteRegister32(uintptr_t mem, uint32_t addr, uint32_t value) {
|
||||||
|
*(uint32_t volatile*)(((uint32_t*)mem) + addr) = value;
|
||||||
|
|
||||||
|
//If returning instantly this will caused missed writes. nanosleep wait of 1 nsec was too much. Busy wait works
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
||||||
|
volatile uint32_t dummy;
|
||||||
|
for(uint32_t i = 0; i < 100; ++i){
|
||||||
|
dummy = i;
|
||||||
|
}
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t get_interval_diff(struct timeval *begin, struct timeval *end) {
|
||||||
|
struct timeval endT;
|
||||||
|
struct timeval diff;
|
||||||
|
|
||||||
|
if (end == NULL) {
|
||||||
|
gettimeofday(&endT, NULL);
|
||||||
|
} else {
|
||||||
|
endT.tv_sec = end->tv_sec;
|
||||||
|
endT.tv_usec = end->tv_usec;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff.tv_sec = endT.tv_sec - begin->tv_sec;
|
||||||
|
diff.tv_usec = endT.tv_usec - begin->tv_usec;
|
||||||
|
|
||||||
|
return (diff.tv_sec * 1000 + diff.tv_usec / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t fm10k_uio_spi_SetCtrlReg(uintptr_t mem, SPI_CTRL value){
|
||||||
|
struct timeval startTime;
|
||||||
|
uint8_t isTimeout = 0;
|
||||||
|
SPI_CTRL spiCtrl = {0};
|
||||||
|
|
||||||
|
WriteRegister32(mem, FM10K_REGISTER_SPI_CTRL, value.value);
|
||||||
|
|
||||||
|
gettimeofday(&startTime, NULL);
|
||||||
|
do{
|
||||||
|
if(isTimeout){
|
||||||
|
printf("Timeout waiting for SPI_CTRL.Busy 0x%02x\n", spiCtrl.value);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(get_interval_diff(&startTime, NULL) > 50){
|
||||||
|
isTimeout = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &spiCtrl.value);
|
||||||
|
|
||||||
|
} while (spiCtrl.fields.Busy);
|
||||||
|
|
||||||
|
/* write back SPI_CTRL with command = 0 */
|
||||||
|
spiCtrl.fields.Command = 0;
|
||||||
|
WriteRegister32(mem, FM10K_REGISTER_SPI_CTRL, spiCtrl.value);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fm10k_uio_spi_Enable(uintptr_t mem){
|
||||||
|
//ENABLE SPI
|
||||||
|
SPI_CTRL spiCtrl;
|
||||||
|
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &spiCtrl.value);
|
||||||
|
/* keep current freq setting and set SPI Enable */
|
||||||
|
SPI_CTRL newSpiCtrl;
|
||||||
|
newSpiCtrl.value = 0;
|
||||||
|
newSpiCtrl.fields.Freq = spiCtrl.fields.Freq;
|
||||||
|
newSpiCtrl.fields.Enable = 1;
|
||||||
|
WriteRegister32(mem, FM10K_REGISTER_SPI_CTRL, newSpiCtrl.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fm10k_uio_spi_Disable(uintptr_t mem){
|
||||||
|
//DISABLE SPI
|
||||||
|
SPI_CTRL spiCtrl;
|
||||||
|
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &spiCtrl.value);
|
||||||
|
/* keep current freq setting and set SPI Enable = 0 */
|
||||||
|
SPI_CTRL newSpiCtrl;
|
||||||
|
newSpiCtrl.value = 0;
|
||||||
|
newSpiCtrl.fields.Freq = spiCtrl.fields.Freq;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t rxData;
|
||||||
|
/* get data */
|
||||||
|
ReadRegister32(mem, FM10K_REGISTER_SPI_RX_DATA, &rxData);
|
||||||
|
|
||||||
|
result.value = ((rxData>>24)&0xff) | ((rxData<<8)&0xff0000) | ((rxData>>8)&0xff00) | ((rxData<<24)&0xff000000);
|
||||||
|
|
||||||
|
|
||||||
|
/* 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, uint32_t len){
|
||||||
|
|
||||||
|
SPI_CTRL currentSpiCtrl;
|
||||||
|
SPI_CTRL spiCtrl = {0};
|
||||||
|
|
||||||
|
uint32_t rxData;
|
||||||
|
uint32_t header;
|
||||||
|
int32_t freq;
|
||||||
|
uint32_t cnt;
|
||||||
|
uint32_t numRead;
|
||||||
|
|
||||||
|
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) + address (3 bytes) */
|
||||||
|
header = (FM10K_SPI_HEADER_COMMAND_READ_BYTES << 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] */
|
||||||
|
numRead = (len - cnt) > 3 ? 4 : (len - cnt);
|
||||||
|
/* set 'shift data' flag and number of data bytes */
|
||||||
|
spiCtrl.fields.Command |= 0b0100;
|
||||||
|
spiCtrl.fields.DataSize = numRead & 0b11;
|
||||||
|
|
||||||
|
if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get data */
|
||||||
|
ReadRegister32(mem, FM10K_REGISTER_SPI_RX_DATA, &rxData);
|
||||||
|
|
||||||
|
/* push the read data into the array */
|
||||||
|
while (numRead) {
|
||||||
|
numRead--;
|
||||||
|
data[cnt++] = (rxData >> (numRead * 8)) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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: PAGE_PROGRAM) + address (3 bytes) */
|
||||||
|
header = (FM10K_SPI_HEADER_COMMAND_PAGE_PROGRAM << 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;
|
||||||
|
}
|
111
fm10k.h
Normal file
111
fm10k.h
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* 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_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 manufacturerId : 8;
|
||||||
|
uint8_t familyCode : 3;
|
||||||
|
uint8_t densityCode : 5;
|
||||||
|
uint8_t subCode : 3;
|
||||||
|
uint8_t productVariant : 5;
|
||||||
|
uint8_t RESERVED : 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 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);
|
||||||
|
|
||||||
|
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