Migrated etherfabric driver to using generic SPI layer.
This commit is contained in:
parent
2d8d21fe74
commit
d62c83a350
|
@ -22,7 +22,7 @@
|
||||||
#include <gpxe/pci.h>
|
#include <gpxe/pci.h>
|
||||||
#include <gpxe/bitbash.h>
|
#include <gpxe/bitbash.h>
|
||||||
#include <gpxe/i2c.h>
|
#include <gpxe/i2c.h>
|
||||||
#include <gpxe/nvs.h>
|
#include <gpxe/spi.h>
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#define dma_addr_t unsigned long
|
#define dma_addr_t unsigned long
|
||||||
#include "etherfabric.h"
|
#include "etherfabric.h"
|
||||||
|
@ -208,13 +208,15 @@ struct efab_nic {
|
||||||
/** INT_REG_KER for Falcon */
|
/** INT_REG_KER for Falcon */
|
||||||
efab_oword_t int_ker __attribute__ (( aligned ( 16 ) ));
|
efab_oword_t int_ker __attribute__ (( aligned ( 16 ) ));
|
||||||
|
|
||||||
/** EEPROM access */
|
/** I2C access */
|
||||||
struct i2c_bit_basher ef1002_i2c;
|
struct i2c_bit_basher ef1002_i2c;
|
||||||
unsigned long ef1002_i2c_outputs;
|
unsigned long ef1002_i2c_outputs;
|
||||||
struct i2c_device ef1002_eeprom;
|
struct i2c_device ef1002_eeprom;
|
||||||
|
|
||||||
/** NVS access */
|
/** SPI access */
|
||||||
struct nvs_device nvs;
|
struct spi_bus spi;
|
||||||
|
struct spi_device falcon_flash;
|
||||||
|
struct spi_device falcon_eeprom;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
|
@ -2209,19 +2211,6 @@ static int falcon_reset ( struct efab_nic *efab ) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** SPI device */
|
|
||||||
struct efab_spi_device {
|
|
||||||
/** Device ID */
|
|
||||||
unsigned int device_id;
|
|
||||||
/** Address length (in bytes) */
|
|
||||||
unsigned int addr_len;
|
|
||||||
/** Device size */
|
|
||||||
unsigned int len;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define SPI_WRITE_CMD 0x02
|
|
||||||
#define SPI_READ_CMD 0x03
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wait for SPI command completion
|
* Wait for SPI command completion
|
||||||
*
|
*
|
||||||
|
@ -2242,97 +2231,76 @@ static int falcon_spi_wait ( struct efab_nic *efab ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform SPI read
|
* Perform SPI read/write
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int falcon_spi_read ( struct efab_nic *efab,
|
static int falcon_spi_rw ( struct spi_bus *bus, struct spi_device *device,
|
||||||
struct efab_spi_device *spi, int address,
|
unsigned int command, int address,
|
||||||
void *data, unsigned int len ) {
|
const void *data_out, void *data_in, size_t len ) {
|
||||||
|
struct efab_nic *efab = container_of ( bus, struct efab_nic, spi );
|
||||||
efab_oword_t reg;
|
efab_oword_t reg;
|
||||||
|
|
||||||
/* Program address register */
|
/* Program address register */
|
||||||
EFAB_POPULATE_OWORD_1 ( reg, FCN_EE_SPI_HADR_ADR, address );
|
EFAB_POPULATE_OWORD_1 ( reg, FCN_EE_SPI_HADR_ADR, address );
|
||||||
falcon_write ( efab, ®, FCN_EE_SPI_HADR_REG_KER );
|
falcon_write ( efab, ®, FCN_EE_SPI_HADR_REG_KER );
|
||||||
|
|
||||||
/* Issue read command */
|
/* Program data register, if applicable */
|
||||||
|
if ( data_out ) {
|
||||||
|
memcpy ( ®, data_out, len );
|
||||||
|
falcon_write ( efab, ®, FCN_EE_SPI_HDATA_REG_KER );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Issue command */
|
||||||
EFAB_POPULATE_OWORD_7 ( reg,
|
EFAB_POPULATE_OWORD_7 ( reg,
|
||||||
FCN_EE_SPI_HCMD_CMD_EN, 1,
|
FCN_EE_SPI_HCMD_CMD_EN, 1,
|
||||||
FCN_EE_SPI_HCMD_SF_SEL, spi->device_id,
|
FCN_EE_SPI_HCMD_SF_SEL, device->slave,
|
||||||
FCN_EE_SPI_HCMD_DABCNT, len,
|
FCN_EE_SPI_HCMD_DABCNT, len,
|
||||||
FCN_EE_SPI_HCMD_READ, FCN_EE_SPI_READ,
|
FCN_EE_SPI_HCMD_READ, ( data_out ?
|
||||||
|
FCN_EE_SPI_WRITE : FCN_EE_SPI_READ ),
|
||||||
FCN_EE_SPI_HCMD_DUBCNT, 0,
|
FCN_EE_SPI_HCMD_DUBCNT, 0,
|
||||||
FCN_EE_SPI_HCMD_ADBCNT, spi->addr_len,
|
FCN_EE_SPI_HCMD_ADBCNT,
|
||||||
FCN_EE_SPI_HCMD_ENC, SPI_READ_CMD );
|
( device->address_len / 8 ),
|
||||||
|
FCN_EE_SPI_HCMD_ENC, command );
|
||||||
falcon_write ( efab, ®, FCN_EE_SPI_HCMD_REG_KER );
|
falcon_write ( efab, ®, FCN_EE_SPI_HCMD_REG_KER );
|
||||||
|
|
||||||
/* Wait for read to complete */
|
/* Wait for operation to complete */
|
||||||
if ( ! falcon_spi_wait ( efab ) )
|
if ( ! falcon_spi_wait ( efab ) )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Read data */
|
/* Read data, if applicable */
|
||||||
|
if ( data_in ) {
|
||||||
falcon_read ( efab, ®, FCN_EE_SPI_HDATA_REG_KER );
|
falcon_read ( efab, ®, FCN_EE_SPI_HDATA_REG_KER );
|
||||||
memcpy ( data, ®, len );
|
memcpy ( data_in, ®, len );
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform SPI write
|
* Initialise SPI bus and devices
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int falcon_spi_write ( struct efab_nic *efab,
|
static void falcon_init_spi ( struct efab_nic *efab ) {
|
||||||
struct efab_spi_device *spi, int address,
|
/* Initialise SPI bus */
|
||||||
const void *data, unsigned int len ) {
|
efab->spi.rw = falcon_spi_rw;
|
||||||
efab_oword_t reg;
|
efab->falcon_eeprom.bus = &efab->spi;
|
||||||
|
efab->falcon_eeprom.slave = FCN_EE_SPI_EEPROM;
|
||||||
|
efab->falcon_flash.bus = &efab->spi;
|
||||||
|
efab->falcon_flash.slave = FCN_EE_SPI_FLASH;
|
||||||
|
|
||||||
/* Program address register */
|
/* Initialise EEPROM, if present */
|
||||||
EFAB_POPULATE_OWORD_1 ( reg, FCN_EE_SPI_HADR_ADR, address );
|
if ( efab->has_flash ) {
|
||||||
falcon_write ( efab, ®, FCN_EE_SPI_HADR_REG_KER );
|
init_at25f1024 ( &efab->falcon_flash );
|
||||||
|
init_at25040 ( &efab->falcon_eeprom );
|
||||||
/* Program data register */
|
} else {
|
||||||
memcpy ( ®, data, len );
|
init_mc25xx640 ( &efab->falcon_eeprom );
|
||||||
falcon_write ( efab, ®, FCN_EE_SPI_HDATA_REG_KER );
|
/* Falcon's SPI interface cannot support a block size
|
||||||
|
* larger than 16, so forcibly reduce it
|
||||||
/* Issue write command */
|
*/
|
||||||
EFAB_POPULATE_OWORD_7 ( reg,
|
efab->falcon_eeprom.nvs.block_size = 16;
|
||||||
FCN_EE_SPI_HCMD_CMD_EN, 1,
|
}
|
||||||
FCN_EE_SPI_HCMD_SF_SEL, spi->device_id,
|
|
||||||
FCN_EE_SPI_HCMD_DABCNT, len,
|
|
||||||
FCN_EE_SPI_HCMD_READ, FCN_EE_SPI_WRITE,
|
|
||||||
FCN_EE_SPI_HCMD_DUBCNT, 0,
|
|
||||||
FCN_EE_SPI_HCMD_ADBCNT, spi->addr_len,
|
|
||||||
FCN_EE_SPI_HCMD_ENC, SPI_WRITE_CMD );
|
|
||||||
falcon_write ( efab, ®, FCN_EE_SPI_HCMD_REG_KER );
|
|
||||||
|
|
||||||
/* Wait for read to complete */
|
|
||||||
if ( ! falcon_spi_wait ( efab ) )
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define AT25F1024_ADDR_LEN 3
|
|
||||||
#define AT25040_ADDR_LEN 1
|
|
||||||
#define MC25XX640_ADDR_LEN 2
|
|
||||||
|
|
||||||
/** Falcon Flash SPI device */
|
|
||||||
static struct efab_spi_device falcon_spi_flash = {
|
|
||||||
.device_id = FCN_EE_SPI_FLASH,
|
|
||||||
.addr_len = AT25F1024_ADDR_LEN,
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Falcon EEPROM SPI device */
|
|
||||||
static struct efab_spi_device falcon_spi_large_eeprom = {
|
|
||||||
.device_id = FCN_EE_SPI_EEPROM,
|
|
||||||
.addr_len = MC25XX640_ADDR_LEN,
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Falcon EEPROM SPI device */
|
|
||||||
static struct efab_spi_device falcon_spi_small_eeprom = {
|
|
||||||
.device_id = FCN_EE_SPI_EEPROM,
|
|
||||||
.addr_len = AT25040_ADDR_LEN,
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Offset of MAC address within EEPROM or Flash */
|
/** Offset of MAC address within EEPROM or Flash */
|
||||||
#define FALCON_MAC_ADDRESS_OFFSET(port) ( 0x310 + 0x08 * (port) )
|
#define FALCON_MAC_ADDRESS_OFFSET(port) ( 0x310 + 0x08 * (port) )
|
||||||
|
|
||||||
|
@ -2341,53 +2309,16 @@ static struct efab_spi_device falcon_spi_small_eeprom = {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int falcon_read_eeprom ( struct efab_nic *efab ) {
|
static int falcon_read_eeprom ( struct efab_nic *efab ) {
|
||||||
struct efab_spi_device *spi;
|
struct nvs_device *nvs;
|
||||||
|
|
||||||
/* Determine the SPI device containing the MAC address */
|
/* Determine the NVS device containing the MAC address */
|
||||||
spi = efab->has_flash ? &falcon_spi_flash : &falcon_spi_large_eeprom;
|
nvs = ( efab->has_flash ?
|
||||||
return falcon_spi_read ( efab, spi,
|
&efab->falcon_flash.nvs : &efab->falcon_eeprom.nvs );
|
||||||
FALCON_MAC_ADDRESS_OFFSET ( efab->port ),
|
|
||||||
|
return nvs_read ( nvs, FALCON_MAC_ADDRESS_OFFSET ( efab->port ),
|
||||||
efab->mac_addr, sizeof ( efab->mac_addr ) );
|
efab->mac_addr, sizeof ( efab->mac_addr ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
#define FALCON_NVS_OFFSET 0x000
|
|
||||||
|
|
||||||
static int falcon_read_nvs ( struct nvs_device *nvs, unsigned int offset,
|
|
||||||
void *data, size_t len ) {
|
|
||||||
struct efab_nic *efab = container_of ( nvs, struct efab_nic, nvs );
|
|
||||||
struct efab_spi_device *spi = &falcon_spi_small_eeprom;
|
|
||||||
|
|
||||||
while ( len ) {
|
|
||||||
if ( ! falcon_spi_read ( efab, spi,
|
|
||||||
( offset + FALCON_NVS_OFFSET ),
|
|
||||||
data, 16 ) ) {
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
data += 16;
|
|
||||||
offset += 16;
|
|
||||||
len -=16;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int falcon_write_nvs ( struct nvs_device *nvs, unsigned int offset,
|
|
||||||
const void *data, size_t len ) {
|
|
||||||
struct efab_nic *efab = container_of ( nvs, struct efab_nic, nvs );
|
|
||||||
struct efab_spi_device *spi = &falcon_spi_large_eeprom;
|
|
||||||
|
|
||||||
while ( len ) {
|
|
||||||
if ( ! falcon_spi_write ( efab, spi,
|
|
||||||
( offset + FALCON_NVS_OFFSET ),
|
|
||||||
data, 16 ) ) {
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
data += 16;
|
|
||||||
offset += 16;
|
|
||||||
len -=16;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** RX descriptor */
|
/** RX descriptor */
|
||||||
typedef efab_qword_t falcon_rx_desc_t;
|
typedef efab_qword_t falcon_rx_desc_t;
|
||||||
|
|
||||||
|
@ -2962,12 +2893,12 @@ static int falcon_init_nic ( struct efab_nic *efab ) {
|
||||||
} else {
|
} else {
|
||||||
falcon_read ( efab, ®, FCN_GPIO_CTL_REG_KER );
|
falcon_read ( efab, ®, FCN_GPIO_CTL_REG_KER );
|
||||||
efab->has_flash = EFAB_OWORD_FIELD ( reg, FCN_FLASH_PRESENT );
|
efab->has_flash = EFAB_OWORD_FIELD ( reg, FCN_FLASH_PRESENT );
|
||||||
efab->has_eeprom = EFAB_OWORD_FIELD ( reg, FCN_EEPROM_PRESENT );
|
efab->has_eeprom = EFAB_OWORD_FIELD ( reg, FCN_EEPROM_PRESENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
EFAB_LOG ( "flash is %s, EEPROM is %s\n",
|
EFAB_LOG ( "flash is %s, EEPROM is %s\n",
|
||||||
( efab->has_flash ? "present" : "absent" ),
|
( efab->has_flash ? "present" : "absent" ),
|
||||||
( efab->has_eeprom ? "present" : "absent" ) );
|
( efab->has_eeprom ? "present" : "absent" ) );
|
||||||
|
falcon_init_spi ( efab );
|
||||||
|
|
||||||
/* Set up TX and RX descriptor caches in SRAM */
|
/* Set up TX and RX descriptor caches in SRAM */
|
||||||
EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_TX_DC_BASE_ADR,
|
EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_TX_DC_BASE_ADR,
|
||||||
|
|
|
@ -193,4 +193,47 @@ extern int spi_read ( struct nvs_device *nvs, unsigned int address,
|
||||||
extern int spi_write ( struct nvs_device *nvs, unsigned int address,
|
extern int spi_write ( struct nvs_device *nvs, unsigned int address,
|
||||||
const void *data, size_t len );
|
const void *data, size_t len );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup spidevs SPI device types
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline __attribute__ (( always_inline )) void
|
||||||
|
init_spi ( struct spi_device *device ) {
|
||||||
|
device->nvs.word_len_log2 = 0;
|
||||||
|
device->command_len = 8,
|
||||||
|
device->nvs.read = spi_read;
|
||||||
|
device->nvs.write = spi_write;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Atmel AT25F1024 serial flash */
|
||||||
|
static inline __attribute__ (( always_inline )) void
|
||||||
|
init_at25f1024 ( struct spi_device *device ) {
|
||||||
|
device->address_len = 24;
|
||||||
|
device->nvs.size = ( 128 * 1024 );
|
||||||
|
device->nvs.block_size = 256;
|
||||||
|
init_spi ( device );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Atmel 25040 serial EEPROM */
|
||||||
|
static inline __attribute__ (( always_inline )) void
|
||||||
|
init_at25040 ( struct spi_device *device ) {
|
||||||
|
device->address_len = 8;
|
||||||
|
device->munge_address = 1;
|
||||||
|
device->nvs.size = 512;
|
||||||
|
device->nvs.block_size = 8;
|
||||||
|
init_spi ( device );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Microchip 25XX640 serial EEPROM */
|
||||||
|
static inline __attribute__ (( always_inline )) void
|
||||||
|
init_mc25xx640 ( struct spi_device *device ) {
|
||||||
|
device->address_len = 16;
|
||||||
|
device->nvs.size = ( 8 * 1024 );
|
||||||
|
device->nvs.block_size = 32;
|
||||||
|
init_spi ( device );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
#endif /* _GPXE_SPI_H */
|
#endif /* _GPXE_SPI_H */
|
||||||
|
|
Reference in New Issue