Rewritten SPI_CTRL using a bitfield instead of raw values for ease of documentation
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
DataHoarder 2020-12-19 20:32:00 +01:00
parent 28519977cf
commit 5e21afe140
3 changed files with 70 additions and 31 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
/fm10k-dump
/*.o
/.idea

View file

@ -2,10 +2,10 @@
default: fm10k-dump
fm10k-dump.o: fm10k-dump.c
gcc -c fm10k-dump.c -o fm10k-dump.o
gcc -c fm10k-dump.c -o fm10k-dump.o -Wall -Wno-packed-bitfield-compat
fm10k-dump: fm10k-dump.o
gcc fm10k-dump.o -o fm10k-dump
gcc fm10k-dump.o -o fm10k-dump -Wall
clean:
-rm -f fm10k-dump

View file

@ -53,7 +53,31 @@
#define FM10K_SPI_FREQ_KHZ 50000
#define FM10K_SPI_HEADER_COMMAND_READ_BYTES 0x3
/* 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))
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;
#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);
@ -63,10 +87,13 @@ 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) {
@ -86,17 +113,18 @@ uint32_t get_interval_diff(struct timeval *begin, struct timeval *end) {
return (diff.tv_sec * 1000 + diff.tv_usec / 1000);
}
uint32_t fm10k_uio_spi_SetCtrlReg(uintptr_t mem, uint32_t value){
uint32_t spiCtrl;
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;
WriteRegister32(mem, FM10K_REGISTER_SPI_CTRL, value);
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);
printf("Timeout waiting for SPI_CTRL.Busy 0x%02x\n", spiCtrl.value);
return 1;
}
@ -104,39 +132,46 @@ uint32_t fm10k_uio_spi_SetCtrlReg(uintptr_t mem, uint32_t value){
isTimeout = 1;
}
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &spiCtrl);
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &spiCtrl.value);
} while ((spiCtrl >> 21) & 1); //While "Busy"
} while (spiCtrl.fields.Busy);
/* write back SPI_CTRL with command = 0 */
spiCtrl &= 0xffff87ff;
WriteRegister32(mem, FM10K_REGISTER_SPI_CTRL, spiCtrl);
spiCtrl.fields.Command = 0;
WriteRegister32(mem, FM10K_REGISTER_SPI_CTRL, spiCtrl.value);
return 0;
}
void fm10k_uio_spi_Enable(uintptr_t mem){
//ENABLE SPI
uint32_t spiCtrl = 0;
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &spiCtrl);
SPI_CTRL spiCtrl;
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &spiCtrl.value);
/* keep current freq setting and set SPI Enable */
spiCtrl &= 0x3ff;
spiCtrl |= 1<<10;
WriteRegister32(mem, FM10K_REGISTER_SPI_CTRL, spiCtrl);
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
uint32_t spiCtrl = 0;
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &spiCtrl);
/* keep current freq setting and set SPI Disable */
spiCtrl &= 0x3ff;
WriteRegister32(mem, FM10K_REGISTER_SPI_CTRL, spiCtrl);
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);
}
uint32_t fm10k_uio_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data, int32_t len){
uint32_t spiCtrl;
SPI_CTRL currentSpiCtrl;
SPI_CTRL spiCtrl;
spiCtrl.value = 0;
uint32_t rxData;
uint32_t header;
int32_t freq;
@ -146,32 +181,32 @@ uint32_t fm10k_uio_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data,
fm10k_uio_spi_Enable(mem);
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &spiCtrl);
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &currentSpiCtrl.value);
if(FM10K_SPI_FREQ_KHZ > 0){
freq = ((100000 / (int)FM10K_SPI_FREQ_KHZ) / 2) - 1;
if (freq < 0){
freq = 0;
}
spiCtrl ^= ((spiCtrl >> 0) ^ freq) & ((2 << 9) - 1); //Set Freq
spiCtrl.fields.Freq = freq;
}
spiCtrl &= 0x7ff;
spiCtrl.fields.Enable = currentSpiCtrl.fields.Enable;
/* header: command (1 byte: READ_BYTES) + address (3 bytes) */
header = (0x3 << 24) | (address & 0xffffff);
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 |= (0x1 << 11);
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 |= ((0x4 << 11) | ((numRead & 0x03) << 17));
spiCtrl.fields.Command |= 0b0100;
spiCtrl.fields.DataSize = numRead & 0b11;
if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){
return 1;
@ -186,11 +221,12 @@ uint32_t fm10k_uio_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data,
data[cnt++] = (rxData >> (numRead * 8)) & 0xff;
}
spiCtrl &= 0x7ff;
spiCtrl.fields.Command = 0b0000;
spiCtrl.fields.DataSize = 0b0000;
}
/* release CS */
spiCtrl |= (0x8 << 11);
spiCtrl.fields.Command = 0b1000;
if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){
return 1;
}
@ -233,7 +269,7 @@ int main(int argc, char** argv){
unsigned int mbToRead = 1;
if(argc > 3){
sscanf(argv[3], "%u", &mbToRead);
mbToRead = strtoul(argv[3], NULL, 10);
}
if(mbToRead > 128){