Commit 4a5b504d authored by Ben Hutchings's avatar Ben Hutchings Committed by Jeff Garzik

sfc: Export boot configuration in EEPROM through ethtool

Extend the SPI device setup code to support this.
Signed-off-by: default avatarBen Hutchings <bhutchings@solarflare.com>
Signed-off-by: default avatarJeff Garzik <jgarzik@redhat.com>
parent 4d566063
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "ethtool.h" #include "ethtool.h"
#include "falcon.h" #include "falcon.h"
#include "gmii.h" #include "gmii.h"
#include "spi.h"
#include "mac.h" #include "mac.h"
const char *efx_loopback_mode_names[] = { const char *efx_loopback_mode_names[] = {
...@@ -171,6 +172,11 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = { ...@@ -171,6 +172,11 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = {
/* Number of ethtool statistics */ /* Number of ethtool statistics */
#define EFX_ETHTOOL_NUM_STATS ARRAY_SIZE(efx_ethtool_stats) #define EFX_ETHTOOL_NUM_STATS ARRAY_SIZE(efx_ethtool_stats)
/* EEPROM range with gPXE configuration */
#define EFX_ETHTOOL_EEPROM_MAGIC 0xEFAB
#define EFX_ETHTOOL_EEPROM_MIN 0x100U
#define EFX_ETHTOOL_EEPROM_MAX 0x400U
/************************************************************************** /**************************************************************************
* *
* Ethtool operations * Ethtool operations
...@@ -532,6 +538,49 @@ static u32 efx_ethtool_get_link(struct net_device *net_dev) ...@@ -532,6 +538,49 @@ static u32 efx_ethtool_get_link(struct net_device *net_dev)
return efx->link_up; return efx->link_up;
} }
static int efx_ethtool_get_eeprom_len(struct net_device *net_dev)
{
struct efx_nic *efx = netdev_priv(net_dev);
struct efx_spi_device *spi = efx->spi_eeprom;
if (!spi)
return 0;
return min(spi->size, EFX_ETHTOOL_EEPROM_MAX) -
min(spi->size, EFX_ETHTOOL_EEPROM_MIN);
}
static int efx_ethtool_get_eeprom(struct net_device *net_dev,
struct ethtool_eeprom *eeprom, u8 *buf)
{
struct efx_nic *efx = netdev_priv(net_dev);
struct efx_spi_device *spi = efx->spi_eeprom;
size_t len;
int rc;
rc = falcon_spi_read(spi, eeprom->offset + EFX_ETHTOOL_EEPROM_MIN,
eeprom->len, &len, buf);
eeprom->magic = EFX_ETHTOOL_EEPROM_MAGIC;
eeprom->len = len;
return rc;
}
static int efx_ethtool_set_eeprom(struct net_device *net_dev,
struct ethtool_eeprom *eeprom, u8 *buf)
{
struct efx_nic *efx = netdev_priv(net_dev);
struct efx_spi_device *spi = efx->spi_eeprom;
size_t len;
int rc;
if (eeprom->magic != EFX_ETHTOOL_EEPROM_MAGIC)
return -EINVAL;
rc = falcon_spi_write(spi, eeprom->offset + EFX_ETHTOOL_EEPROM_MIN,
eeprom->len, &len, buf);
eeprom->len = len;
return rc;
}
static int efx_ethtool_get_coalesce(struct net_device *net_dev, static int efx_ethtool_get_coalesce(struct net_device *net_dev,
struct ethtool_coalesce *coalesce) struct ethtool_coalesce *coalesce)
{ {
...@@ -653,6 +702,9 @@ struct ethtool_ops efx_ethtool_ops = { ...@@ -653,6 +702,9 @@ struct ethtool_ops efx_ethtool_ops = {
.get_drvinfo = efx_ethtool_get_drvinfo, .get_drvinfo = efx_ethtool_get_drvinfo,
.nway_reset = efx_ethtool_nway_reset, .nway_reset = efx_ethtool_nway_reset,
.get_link = efx_ethtool_get_link, .get_link = efx_ethtool_get_link,
.get_eeprom_len = efx_ethtool_get_eeprom_len,
.get_eeprom = efx_ethtool_get_eeprom,
.set_eeprom = efx_ethtool_set_eeprom,
.get_coalesce = efx_ethtool_get_coalesce, .get_coalesce = efx_ethtool_get_coalesce,
.set_coalesce = efx_ethtool_set_coalesce, .set_coalesce = efx_ethtool_set_coalesce,
.get_pauseparam = efx_ethtool_get_pauseparam, .get_pauseparam = efx_ethtool_get_pauseparam,
......
...@@ -1620,64 +1620,195 @@ void falcon_fini_interrupt(struct efx_nic *efx) ...@@ -1620,64 +1620,195 @@ void falcon_fini_interrupt(struct efx_nic *efx)
/* Wait for SPI command completion */ /* Wait for SPI command completion */
static int falcon_spi_wait(struct efx_nic *efx) static int falcon_spi_wait(struct efx_nic *efx)
{ {
unsigned long timeout = jiffies + DIV_ROUND_UP(HZ, 10);
efx_oword_t reg; efx_oword_t reg;
int cmd_en, timer_active; bool cmd_en, timer_active;
int count;
count = 0; for (;;) {
do {
falcon_read(efx, &reg, EE_SPI_HCMD_REG_KER); falcon_read(efx, &reg, EE_SPI_HCMD_REG_KER);
cmd_en = EFX_OWORD_FIELD(reg, EE_SPI_HCMD_CMD_EN); cmd_en = EFX_OWORD_FIELD(reg, EE_SPI_HCMD_CMD_EN);
timer_active = EFX_OWORD_FIELD(reg, EE_WR_TIMER_ACTIVE); timer_active = EFX_OWORD_FIELD(reg, EE_WR_TIMER_ACTIVE);
if (!cmd_en && !timer_active) if (!cmd_en && !timer_active)
return 0; return 0;
udelay(10); if (time_after_eq(jiffies, timeout)) {
} while (++count < 10000); /* wait upto 100msec */ EFX_ERR(efx, "timed out waiting for SPI\n");
EFX_ERR(efx, "timed out waiting for SPI\n"); return -ETIMEDOUT;
return -ETIMEDOUT; }
cpu_relax();
}
} }
static int static int falcon_spi_cmd(const struct efx_spi_device *spi,
falcon_spi_read(struct efx_nic *efx, int device_id, unsigned int command, unsigned int command, int address,
unsigned int address, unsigned int addr_len, const void *in, void *out, unsigned int len)
void *data, unsigned int len)
{ {
struct efx_nic *efx = spi->efx;
bool addressed = (address >= 0);
bool reading = (out != NULL);
efx_oword_t reg; efx_oword_t reg;
int rc; int rc;
BUG_ON(len > FALCON_SPI_MAX_LEN); /* Input validation */
if (len > FALCON_SPI_MAX_LEN)
return -EINVAL;
/* Check SPI not currently being accessed */ /* Check SPI not currently being accessed */
rc = falcon_spi_wait(efx); rc = falcon_spi_wait(efx);
if (rc) if (rc)
return rc; return rc;
/* Program address register */ /* Program address register, if we have an address */
EFX_POPULATE_OWORD_1(reg, EE_SPI_HADR_ADR, address); if (addressed) {
falcon_write(efx, &reg, EE_SPI_HADR_REG_KER); EFX_POPULATE_OWORD_1(reg, EE_SPI_HADR_ADR, address);
falcon_write(efx, &reg, EE_SPI_HADR_REG_KER);
}
/* Program data register, if we have data */
if (in != NULL) {
memcpy(&reg, in, len);
falcon_write(efx, &reg, EE_SPI_HDATA_REG_KER);
}
/* Issue read command */ /* Issue read/write command */
EFX_POPULATE_OWORD_7(reg, EFX_POPULATE_OWORD_7(reg,
EE_SPI_HCMD_CMD_EN, 1, EE_SPI_HCMD_CMD_EN, 1,
EE_SPI_HCMD_SF_SEL, device_id, EE_SPI_HCMD_SF_SEL, spi->device_id,
EE_SPI_HCMD_DABCNT, len, EE_SPI_HCMD_DABCNT, len,
EE_SPI_HCMD_READ, EE_SPI_READ, EE_SPI_HCMD_READ, reading,
EE_SPI_HCMD_DUBCNT, 0, EE_SPI_HCMD_DUBCNT, 0,
EE_SPI_HCMD_ADBCNT, addr_len, EE_SPI_HCMD_ADBCNT,
(addressed ? spi->addr_len : 0),
EE_SPI_HCMD_ENC, command); EE_SPI_HCMD_ENC, command);
falcon_write(efx, &reg, EE_SPI_HCMD_REG_KER); falcon_write(efx, &reg, EE_SPI_HCMD_REG_KER);
/* Wait for read to complete */ /* Wait for read/write to complete */
rc = falcon_spi_wait(efx); rc = falcon_spi_wait(efx);
if (rc) if (rc)
return rc; return rc;
/* Read data */ /* Read data */
falcon_read(efx, &reg, EE_SPI_HDATA_REG_KER); if (out != NULL) {
memcpy(data, &reg, len); falcon_read(efx, &reg, EE_SPI_HDATA_REG_KER);
memcpy(out, &reg, len);
}
return 0; return 0;
} }
static unsigned int
falcon_spi_write_limit(const struct efx_spi_device *spi, unsigned int start)
{
return min(FALCON_SPI_MAX_LEN,
(spi->block_size - (start & (spi->block_size - 1))));
}
static inline u8
efx_spi_munge_command(const struct efx_spi_device *spi,
const u8 command, const unsigned int address)
{
return command | (((address >> 8) & spi->munge_address) << 3);
}
static int falcon_spi_fast_wait(const struct efx_spi_device *spi)
{
u8 status;
int i, rc;
/* Wait up to 1000us for flash/EEPROM to finish a fast operation. */
for (i = 0; i < 50; i++) {
udelay(20);
rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL,
&status, sizeof(status));
if (rc)
return rc;
if (!(status & SPI_STATUS_NRDY))
return 0;
}
EFX_ERR(spi->efx,
"timed out waiting for device %d last status=0x%02x\n",
spi->device_id, status);
return -ETIMEDOUT;
}
int falcon_spi_read(const struct efx_spi_device *spi, loff_t start,
size_t len, size_t *retlen, u8 *buffer)
{
unsigned int command, block_len, pos = 0;
int rc = 0;
while (pos < len) {
block_len = min((unsigned int)len - pos,
FALCON_SPI_MAX_LEN);
command = efx_spi_munge_command(spi, SPI_READ, start + pos);
rc = falcon_spi_cmd(spi, command, start + pos, NULL,
buffer + pos, block_len);
if (rc)
break;
pos += block_len;
/* Avoid locking up the system */
cond_resched();
if (signal_pending(current)) {
rc = -EINTR;
break;
}
}
if (retlen)
*retlen = pos;
return rc;
}
int falcon_spi_write(const struct efx_spi_device *spi, loff_t start,
size_t len, size_t *retlen, const u8 *buffer)
{
u8 verify_buffer[FALCON_SPI_MAX_LEN];
unsigned int command, block_len, pos = 0;
int rc = 0;
while (pos < len) {
rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0);
if (rc)
break;
block_len = min((unsigned int)len - pos,
falcon_spi_write_limit(spi, start + pos));
command = efx_spi_munge_command(spi, SPI_WRITE, start + pos);
rc = falcon_spi_cmd(spi, command, start + pos,
buffer + pos, NULL, block_len);
if (rc)
break;
rc = falcon_spi_fast_wait(spi);
if (rc)
break;
command = efx_spi_munge_command(spi, SPI_READ, start + pos);
rc = falcon_spi_cmd(spi, command, start + pos,
NULL, verify_buffer, block_len);
if (memcmp(verify_buffer, buffer + pos, block_len)) {
rc = -EIO;
break;
}
pos += block_len;
/* Avoid locking up the system */
cond_resched();
if (signal_pending(current)) {
rc = -EINTR;
break;
}
}
if (retlen)
*retlen = pos;
return rc;
}
/************************************************************************** /**************************************************************************
* *
* MAC wrapper * MAC wrapper
...@@ -2251,40 +2382,66 @@ static int falcon_reset_sram(struct efx_nic *efx) ...@@ -2251,40 +2382,66 @@ static int falcon_reset_sram(struct efx_nic *efx)
return -ETIMEDOUT; return -ETIMEDOUT;
} }
static int falcon_spi_device_init(struct efx_nic *efx,
struct efx_spi_device **spi_device_ret,
unsigned int device_id, u32 device_type)
{
struct efx_spi_device *spi_device;
if (device_type != 0) {
spi_device = kmalloc(sizeof(*spi_device), GFP_KERNEL);
if (!spi_device)
return -ENOMEM;
spi_device->device_id = device_id;
spi_device->size =
1 << SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_SIZE);
spi_device->addr_len =
SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_ADDR_LEN);
spi_device->munge_address = (spi_device->size == 1 << 9 &&
spi_device->addr_len == 1);
spi_device->block_size =
1 << SPI_DEV_TYPE_FIELD(device_type,
SPI_DEV_TYPE_BLOCK_SIZE);
spi_device->efx = efx;
} else {
spi_device = NULL;
}
kfree(*spi_device_ret);
*spi_device_ret = spi_device;
return 0;
}
static void falcon_remove_spi_devices(struct efx_nic *efx)
{
kfree(efx->spi_eeprom);
efx->spi_eeprom = NULL;
kfree(efx->spi_flash);
efx->spi_flash = NULL;
}
/* Extract non-volatile configuration */ /* Extract non-volatile configuration */
static int falcon_probe_nvconfig(struct efx_nic *efx) static int falcon_probe_nvconfig(struct efx_nic *efx)
{ {
struct falcon_nvconfig *nvconfig; struct falcon_nvconfig *nvconfig;
efx_oword_t nic_stat; struct efx_spi_device *spi;
int device_id;
unsigned addr_len;
size_t offset, len;
int magic_num, struct_ver, board_rev; int magic_num, struct_ver, board_rev;
int rc; int rc;
/* Find the boot device. */
falcon_read(efx, &nic_stat, NIC_STAT_REG);
if (EFX_OWORD_FIELD(nic_stat, SF_PRST)) {
device_id = EE_SPI_FLASH;
addr_len = 3;
} else if (EFX_OWORD_FIELD(nic_stat, EE_PRST)) {
device_id = EE_SPI_EEPROM;
addr_len = 2;
} else {
return -ENODEV;
}
nvconfig = kmalloc(sizeof(*nvconfig), GFP_KERNEL); nvconfig = kmalloc(sizeof(*nvconfig), GFP_KERNEL);
if (!nvconfig)
return -ENOMEM;
/* Read the whole configuration structure into memory. */ /* Read the whole configuration structure into memory. */
for (offset = 0; offset < sizeof(*nvconfig); offset += len) { spi = efx->spi_flash ? efx->spi_flash : efx->spi_eeprom;
len = min(sizeof(*nvconfig) - offset, rc = falcon_spi_read(spi, NVCONFIG_BASE, sizeof(*nvconfig),
(size_t) FALCON_SPI_MAX_LEN); NULL, (char *)nvconfig);
rc = falcon_spi_read(efx, device_id, SPI_READ, if (rc) {
NVCONFIG_BASE + offset, addr_len, EFX_ERR(efx, "Failed to read %s\n", efx->spi_flash ? "flash" :
(char *)nvconfig + offset, len); "EEPROM");
if (rc) goto fail1;
goto out;
} }
/* Read the MAC addresses */ /* Read the MAC addresses */
...@@ -2302,17 +2459,38 @@ static int falcon_probe_nvconfig(struct efx_nic *efx) ...@@ -2302,17 +2459,38 @@ static int falcon_probe_nvconfig(struct efx_nic *efx)
board_rev = 0; board_rev = 0;
} else { } else {
struct falcon_nvconfig_board_v2 *v2 = &nvconfig->board_v2; struct falcon_nvconfig_board_v2 *v2 = &nvconfig->board_v2;
struct falcon_nvconfig_board_v3 *v3 = &nvconfig->board_v3;
efx->phy_type = v2->port0_phy_type; efx->phy_type = v2->port0_phy_type;
efx->mii.phy_id = v2->port0_phy_addr; efx->mii.phy_id = v2->port0_phy_addr;
board_rev = le16_to_cpu(v2->board_revision); board_rev = le16_to_cpu(v2->board_revision);
if (struct_ver >= 3) {
__le32 fl = v3->spi_device_type[EE_SPI_FLASH];
__le32 ee = v3->spi_device_type[EE_SPI_EEPROM];
rc = falcon_spi_device_init(efx, &efx->spi_flash,
EE_SPI_FLASH,
le32_to_cpu(fl));
if (rc)
goto fail2;
rc = falcon_spi_device_init(efx, &efx->spi_eeprom,
EE_SPI_EEPROM,
le32_to_cpu(ee));
if (rc)
goto fail2;
}
} }
EFX_LOG(efx, "PHY is %d phy_id %d\n", efx->phy_type, efx->mii.phy_id); EFX_LOG(efx, "PHY is %d phy_id %d\n", efx->phy_type, efx->mii.phy_id);
efx_set_board_info(efx, board_rev); efx_set_board_info(efx, board_rev);
out: kfree(nvconfig);
return 0;
fail2:
falcon_remove_spi_devices(efx);
fail1:
kfree(nvconfig); kfree(nvconfig);
return rc; return rc;
} }
...@@ -2363,6 +2541,86 @@ static int falcon_probe_nic_variant(struct efx_nic *efx) ...@@ -2363,6 +2541,86 @@ static int falcon_probe_nic_variant(struct efx_nic *efx)
return 0; return 0;
} }
/* Probe all SPI devices on the NIC */
static void falcon_probe_spi_devices(struct efx_nic *efx)
{
efx_oword_t nic_stat, gpio_ctl, ee_vpd_cfg;
bool has_flash, has_eeprom, boot_is_external;
falcon_read(efx, &gpio_ctl, GPIO_CTL_REG_KER);
falcon_read(efx, &nic_stat, NIC_STAT_REG);
falcon_read(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER);
has_flash = EFX_OWORD_FIELD(nic_stat, SF_PRST);
has_eeprom = EFX_OWORD_FIELD(nic_stat, EE_PRST);
boot_is_external = EFX_OWORD_FIELD(gpio_ctl, BOOTED_USING_NVDEVICE);
if (has_flash) {
/* Default flash SPI device: Atmel AT25F1024
* 128 KB, 24-bit address, 32 KB erase block,
* 256 B write block
*/
u32 flash_device_type =
(17 << SPI_DEV_TYPE_SIZE_LBN)
| (3 << SPI_DEV_TYPE_ADDR_LEN_LBN)
| (0x52 << SPI_DEV_TYPE_ERASE_CMD_LBN)
| (15 << SPI_DEV_TYPE_ERASE_SIZE_LBN)
| (8 << SPI_DEV_TYPE_BLOCK_SIZE_LBN);
falcon_spi_device_init(efx, &efx->spi_flash,
EE_SPI_FLASH, flash_device_type);
if (!boot_is_external) {
/* Disable VPD and set clock dividers to safe
* values for initial programming.
*/
EFX_LOG(efx, "Booted from internal ASIC settings;"
" setting SPI config\n");
EFX_POPULATE_OWORD_3(ee_vpd_cfg, EE_VPD_EN, 0,
/* 125 MHz / 7 ~= 20 MHz */
EE_SF_CLOCK_DIV, 7,
/* 125 MHz / 63 ~= 2 MHz */
EE_EE_CLOCK_DIV, 63);
falcon_write(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER);
}
}
if (has_eeprom) {
u32 eeprom_device_type;
/* If it has no flash, it must have a large EEPROM
* for chip config; otherwise check whether 9-bit
* addressing is used for VPD configuration
*/
if (has_flash &&
(!boot_is_external ||
EFX_OWORD_FIELD(ee_vpd_cfg, EE_VPD_EN_AD9_MODE))) {
/* Default SPI device: Atmel AT25040 or similar
* 512 B, 9-bit address, 8 B write block
*/
eeprom_device_type =
(9 << SPI_DEV_TYPE_SIZE_LBN)
| (1 << SPI_DEV_TYPE_ADDR_LEN_LBN)
| (3 << SPI_DEV_TYPE_BLOCK_SIZE_LBN);
} else {
/* "Large" SPI device: Atmel AT25640 or similar
* 8 KB, 16-bit address, 32 B write block
*/
eeprom_device_type =
(13 << SPI_DEV_TYPE_SIZE_LBN)
| (2 << SPI_DEV_TYPE_ADDR_LEN_LBN)
| (5 << SPI_DEV_TYPE_BLOCK_SIZE_LBN);
}
falcon_spi_device_init(efx, &efx->spi_eeprom,
EE_SPI_EEPROM, eeprom_device_type);
}
EFX_LOG(efx, "flash is %s, EEPROM is %s\n",
(has_flash ? "present" : "absent"),
(has_eeprom ? "present" : "absent"));
}
int falcon_probe_nic(struct efx_nic *efx) int falcon_probe_nic(struct efx_nic *efx)
{ {
struct falcon_nic_data *nic_data; struct falcon_nic_data *nic_data;
...@@ -2413,6 +2671,8 @@ int falcon_probe_nic(struct efx_nic *efx) ...@@ -2413,6 +2671,8 @@ int falcon_probe_nic(struct efx_nic *efx)
(unsigned long long)efx->irq_status.dma_addr, (unsigned long long)efx->irq_status.dma_addr,
efx->irq_status.addr, virt_to_phys(efx->irq_status.addr)); efx->irq_status.addr, virt_to_phys(efx->irq_status.addr));
falcon_probe_spi_devices(efx);
/* Read in the non-volatile configuration */ /* Read in the non-volatile configuration */
rc = falcon_probe_nvconfig(efx); rc = falcon_probe_nvconfig(efx);
if (rc) if (rc)
...@@ -2432,6 +2692,7 @@ int falcon_probe_nic(struct efx_nic *efx) ...@@ -2432,6 +2692,7 @@ int falcon_probe_nic(struct efx_nic *efx)
return 0; return 0;
fail5: fail5:
falcon_remove_spi_devices(efx);
falcon_free_buffer(efx, &efx->irq_status); falcon_free_buffer(efx, &efx->irq_status);
fail4: fail4:
fail3: fail3:
...@@ -2608,6 +2869,7 @@ void falcon_remove_nic(struct efx_nic *efx) ...@@ -2608,6 +2869,7 @@ void falcon_remove_nic(struct efx_nic *efx)
rc = i2c_del_adapter(&efx->i2c_adap); rc = i2c_del_adapter(&efx->i2c_adap);
BUG_ON(rc); BUG_ON(rc);
falcon_remove_spi_devices(efx);
falcon_free_buffer(efx, &efx->irq_status); falcon_free_buffer(efx, &efx->irq_status);
falcon_reset_hw(efx, RESET_TYPE_ALL); falcon_reset_hw(efx, RESET_TYPE_ALL);
......
...@@ -92,6 +92,17 @@ ...@@ -92,6 +92,17 @@
/* SPI host data register */ /* SPI host data register */
#define EE_SPI_HDATA_REG_KER 0x0120 #define EE_SPI_HDATA_REG_KER 0x0120
/* SPI/VPD config register */
#define EE_VPD_CFG_REG_KER 0x0140
#define EE_VPD_EN_LBN 0
#define EE_VPD_EN_WIDTH 1
#define EE_VPD_EN_AD9_MODE_LBN 1
#define EE_VPD_EN_AD9_MODE_WIDTH 1
#define EE_EE_CLOCK_DIV_LBN 112
#define EE_EE_CLOCK_DIV_WIDTH 7
#define EE_SF_CLOCK_DIV_LBN 120
#define EE_SF_CLOCK_DIV_WIDTH 7
/* PCIE CORE ACCESS REG */ /* PCIE CORE ACCESS REG */
#define PCIE_CORE_ADDR_PCIE_DEVICE_CTRL_STAT 0x68 #define PCIE_CORE_ADDR_PCIE_DEVICE_CTRL_STAT 0x68
#define PCIE_CORE_ADDR_PCIE_LINK_CTRL_STAT 0x70 #define PCIE_CORE_ADDR_PCIE_LINK_CTRL_STAT 0x70
...@@ -115,6 +126,9 @@ ...@@ -115,6 +126,9 @@
#define STRAP_PCIE_LBN 0 #define STRAP_PCIE_LBN 0
#define STRAP_PCIE_WIDTH 1 #define STRAP_PCIE_WIDTH 1
#define BOOTED_USING_NVDEVICE_LBN 3
#define BOOTED_USING_NVDEVICE_WIDTH 1
/* GPIO control register */ /* GPIO control register */
#define GPIO_CTL_REG_KER 0x0210 #define GPIO_CTL_REG_KER 0x0210
#define GPIO_OUTPUTS_LBN (16) #define GPIO_OUTPUTS_LBN (16)
...@@ -1127,6 +1141,25 @@ struct falcon_nvconfig_board_v2 { ...@@ -1127,6 +1141,25 @@ struct falcon_nvconfig_board_v2 {
__le16 board_revision; __le16 board_revision;
} __packed; } __packed;
/* Board configuration v3 extra information */
struct falcon_nvconfig_board_v3 {
__le32 spi_device_type[2];
} __packed;
/* Bit numbers for spi_device_type */
#define SPI_DEV_TYPE_SIZE_LBN 0
#define SPI_DEV_TYPE_SIZE_WIDTH 5
#define SPI_DEV_TYPE_ADDR_LEN_LBN 6
#define SPI_DEV_TYPE_ADDR_LEN_WIDTH 2
#define SPI_DEV_TYPE_ERASE_CMD_LBN 8
#define SPI_DEV_TYPE_ERASE_CMD_WIDTH 8
#define SPI_DEV_TYPE_ERASE_SIZE_LBN 16
#define SPI_DEV_TYPE_ERASE_SIZE_WIDTH 5
#define SPI_DEV_TYPE_BLOCK_SIZE_LBN 24
#define SPI_DEV_TYPE_BLOCK_SIZE_WIDTH 5
#define SPI_DEV_TYPE_FIELD(type, field) \
(((type) >> EFX_LOW_BIT(field)) & EFX_MASK32(field))
#define NVCONFIG_BASE 0x300 #define NVCONFIG_BASE 0x300
#define NVCONFIG_BOARD_MAGIC_NUM 0xFA1C #define NVCONFIG_BOARD_MAGIC_NUM 0xFA1C
struct falcon_nvconfig { struct falcon_nvconfig {
...@@ -1144,6 +1177,8 @@ struct falcon_nvconfig { ...@@ -1144,6 +1177,8 @@ struct falcon_nvconfig {
__le16 board_struct_ver; __le16 board_struct_ver;
__le16 board_checksum; __le16 board_checksum;
struct falcon_nvconfig_board_v2 board_v2; struct falcon_nvconfig_board_v2 board_v2;
efx_oword_t ee_base_page_reg; /* 0x3B0 */
struct falcon_nvconfig_board_v3 board_v3;
} __packed; } __packed;
#endif /* EFX_FALCON_HWDEFS_H */ #endif /* EFX_FALCON_HWDEFS_H */
...@@ -638,6 +638,10 @@ union efx_multicast_hash { ...@@ -638,6 +638,10 @@ union efx_multicast_hash {
* This register is written with the SMP processor ID whenever an * This register is written with the SMP processor ID whenever an
* interrupt is handled. It is used by falcon_test_interrupt() * interrupt is handled. It is used by falcon_test_interrupt()
* to verify that an interrupt has occurred. * to verify that an interrupt has occurred.
* @spi_flash: SPI flash device
* This field will be %NULL if no flash device is present.
* @spi_eeprom: SPI EEPROM device
* This field will be %NULL if no EEPROM device is present.
* @n_rx_nodesc_drop_cnt: RX no descriptor drop count * @n_rx_nodesc_drop_cnt: RX no descriptor drop count
* @nic_data: Hardware dependant state * @nic_data: Hardware dependant state
* @mac_lock: MAC access lock. Protects @port_enabled, efx_monitor() and * @mac_lock: MAC access lock. Protects @port_enabled, efx_monitor() and
...@@ -709,6 +713,9 @@ struct efx_nic { ...@@ -709,6 +713,9 @@ struct efx_nic {
struct efx_buffer irq_status; struct efx_buffer irq_status;
volatile signed int last_irq_cpu; volatile signed int last_irq_cpu;
struct efx_spi_device *spi_flash;
struct efx_spi_device *spi_eeprom;
unsigned n_rx_nodesc_drop_cnt; unsigned n_rx_nodesc_drop_cnt;
struct falcon_nic_data *nic_data; struct falcon_nic_data *nic_data;
......
...@@ -19,53 +19,48 @@ ...@@ -19,53 +19,48 @@
* *
*************************************************************************/ *************************************************************************/
/* #define SPI_WRSR 0x01 /* Write status register */
* Commands common to all known devices. #define SPI_WRITE 0x02 /* Write data to memory array */
* #define SPI_READ 0x03 /* Read data from memory array */
#define SPI_WRDI 0x04 /* Reset write enable latch */
#define SPI_RDSR 0x05 /* Read status register */
#define SPI_WREN 0x06 /* Set write enable latch */
#define SPI_STATUS_WPEN 0x80 /* Write-protect pin enabled */
#define SPI_STATUS_BP2 0x10 /* Block protection bit 2 */
#define SPI_STATUS_BP1 0x08 /* Block protection bit 1 */
#define SPI_STATUS_BP0 0x04 /* Block protection bit 0 */
#define SPI_STATUS_WEN 0x02 /* State of the write enable latch */
#define SPI_STATUS_NRDY 0x01 /* Device busy flag */
/**
* struct efx_spi_device - an Efx SPI (Serial Peripheral Interface) device
* @efx: The Efx controller that owns this device
* @device_id: Controller's id for the device
* @size: Size (in bytes)
* @addr_len: Number of address bytes in read/write commands
* @munge_address: Flag whether addresses should be munged.
* Some devices with 9-bit addresses (e.g. AT25040A EEPROM)
* use bit 3 of the command byte as address bit A8, rather
* than having a two-byte address. If this flag is set, then
* commands should be munged in this way.
* @block_size: Write block size (in bytes).
* Write commands are limited to blocks with this size and alignment.
* @read: Read function for the device
* @write: Write function for the device
*/ */
struct efx_spi_device {
/* Write status register */ struct efx_nic *efx;
#define SPI_WRSR 0x01 int device_id;
unsigned int size;
/* Write data to memory array */ unsigned int addr_len;
#define SPI_WRITE 0x02 unsigned int munge_address:1;
unsigned int block_size;
/* Read data from memory array */ };
#define SPI_READ 0x03
int falcon_spi_read(const struct efx_spi_device *spi, loff_t start,
/* Reset write enable latch */ size_t len, size_t *retlen, u8 *buffer);
#define SPI_WRDI 0x04 int falcon_spi_write(const struct efx_spi_device *spi, loff_t start,
size_t len, size_t *retlen, const u8 *buffer);
/* Read status register */
#define SPI_RDSR 0x05
/* Set write enable latch */
#define SPI_WREN 0x06
/* SST: Enable write to status register */
#define SPI_SST_EWSR 0x50
/*
* Status register bits. Not all bits are supported on all devices.
*
*/
/* Write-protect pin enabled */
#define SPI_STATUS_WPEN 0x80
/* Block protection bit 2 */
#define SPI_STATUS_BP2 0x10
/* Block protection bit 1 */
#define SPI_STATUS_BP1 0x08
/* Block protection bit 0 */
#define SPI_STATUS_BP0 0x04
/* State of the write enable latch */
#define SPI_STATUS_WEN 0x02
/* Device busy flag */
#define SPI_STATUS_NRDY 0x01
#endif /* EFX_SPI_H */ #endif /* EFX_SPI_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment