summaryrefslogtreecommitdiffstats
path: root/nicintel_eeprom.c
diff options
context:
space:
mode:
Diffstat (limited to 'nicintel_eeprom.c')
-rw-r--r--nicintel_eeprom.c278
1 files changed, 158 insertions, 120 deletions
diff --git a/nicintel_eeprom.c b/nicintel_eeprom.c
index 4d45f7913..6a734b050 100644
--- a/nicintel_eeprom.c
+++ b/nicintel_eeprom.c
@@ -34,7 +34,8 @@
#include "flash.h"
#include "spi.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_physmap.h"
+#include "platform/pci.h"
#define PCI_VENDOR_ID_INTEL 0x8086
#define MEMMAP_SIZE 0x1c /* Only EEC, EERD and EEWR are needed. */
@@ -68,27 +69,33 @@
#define EEWR_ADDR 2
#define EEWR_DATA 16
-#define BIT(x) (1<<x)
#define EE_PAGE_MASK 0x3f
-static uint8_t *nicintel_eebar;
-static struct pci_dev *nicintel_pci;
-static bool done_i20_write = false;
-
#define UNPROG_DEVICE 0x1509
+struct nicintel_eeprom_data {
+ struct pci_dev *nicintel_pci;
+ uint8_t *nicintel_eebar;
+
+ /* Intel 82580 variable(s) */
+ uint32_t eec;
+
+ /* Intel I210 variable(s) */
+ bool done_i210_write;
+};
+
/*
* Warning: is_i210() below makes assumptions on these PCI ids.
* It may have to be updated when this list is extended.
*/
-const struct dev_entry nics_intel_ee[] = {
+static const struct dev_entry nics_intel_ee[] = {
{PCI_VENDOR_ID_INTEL, 0x150e, OK, "Intel", "82580 Quad Gigabit Ethernet Controller (Copper)"},
{PCI_VENDOR_ID_INTEL, 0x150f, NT , "Intel", "82580 Quad Gigabit Ethernet Controller (Fiber)"},
{PCI_VENDOR_ID_INTEL, 0x1510, NT , "Intel", "82580 Quad Gigabit Ethernet Controller (Backplane)"},
{PCI_VENDOR_ID_INTEL, 0x1511, NT , "Intel", "82580 Quad Gigabit Ethernet Controller (Ext. PHY)"},
{PCI_VENDOR_ID_INTEL, 0x1511, NT , "Intel", "82580 Dual Gigabit Ethernet Controller (Copper)"},
{PCI_VENDOR_ID_INTEL, UNPROG_DEVICE, OK, "Intel", "Unprogrammed 82580 Quad/Dual Gigabit Ethernet Controller"},
- {PCI_VENDOR_ID_INTEL, 0x1531, NT, "Intel", "I210 Gigabit Network Connection Unprogrammed"},
+ {PCI_VENDOR_ID_INTEL, 0x1531, OK, "Intel", "I210 Gigabit Network Connection Unprogrammed"},
{PCI_VENDOR_ID_INTEL, 0x1532, NT, "Intel", "I211 Gigabit Network Connection Unprogrammed"},
{PCI_VENDOR_ID_INTEL, 0x1533, OK, "Intel", "I210 Gigabit Network Connection"},
{PCI_VENDOR_ID_INTEL, 0x1536, NT, "Intel", "I210 Gigabit Network Connection SERDES Fiber"},
@@ -108,8 +115,8 @@ static int nicintel_ee_probe_i210(struct flashctx *flash)
/* Emulated eeprom has a fixed size of 4 KB */
flash->chip->total_size = 4;
flash->chip->page_size = flash->chip->total_size * 1024;
- flash->chip->tested = TEST_OK_PREW;
- flash->chip->gran = write_gran_1byte_implicit_erase;
+ flash->chip->tested = TEST_OK_PREWB;
+ flash->chip->gran = WRITE_GRAN_1BYTE_IMPLICIT_ERASE;
flash->chip->block_erasers->eraseblocks[0].size = flash->chip->page_size;
flash->chip->block_erasers->eraseblocks[0].count = 1;
@@ -118,10 +125,12 @@ static int nicintel_ee_probe_i210(struct flashctx *flash)
static int nicintel_ee_probe_82580(struct flashctx *flash)
{
- if (nicintel_pci->device_id == UNPROG_DEVICE)
+ const struct nicintel_eeprom_data *data = flash->mst->opaque.data;
+
+ if (data->nicintel_pci->device_id == UNPROG_DEVICE)
flash->chip->total_size = 16; /* Fall back to minimum supported size. */
else {
- uint32_t tmp = pci_mmio_readl(nicintel_eebar + EEC);
+ uint32_t tmp = pci_mmio_readl(data->nicintel_eebar + EEC);
tmp = ((tmp >> EE_SIZE) & EE_SIZE_MASK);
switch (tmp) {
case 7:
@@ -131,14 +140,14 @@ static int nicintel_ee_probe_82580(struct flashctx *flash)
flash->chip->total_size = 32;
break;
default:
- msg_cerr("Unsupported chip size 0x%x\n", tmp);
+ msg_cerr("Unsupported chip size 0x%"PRIx32"\n", tmp);
return 0;
}
}
flash->chip->page_size = EE_PAGE_MASK + 1;
- flash->chip->tested = TEST_OK_PREW;
- flash->chip->gran = write_gran_1byte_implicit_erase;
+ flash->chip->tested = TEST_OK_PREWB;
+ flash->chip->gran = WRITE_GRAN_1BYTE_IMPLICIT_ERASE;
flash->chip->block_erasers->eraseblocks[0].size = (EE_PAGE_MASK + 1);
flash->chip->block_erasers->eraseblocks[0].count = (flash->chip->total_size * 1024) / (EE_PAGE_MASK + 1);
@@ -146,15 +155,15 @@ static int nicintel_ee_probe_82580(struct flashctx *flash)
}
#define MAX_ATTEMPTS 10000000
-static int nicintel_ee_read_word(unsigned int addr, uint16_t *data)
+static int nicintel_ee_read_word(uint8_t *eebar, unsigned int addr, uint16_t *data)
{
uint32_t tmp = BIT(EERD_START) | (addr << EERD_ADDR);
- pci_mmio_writel(tmp, nicintel_eebar + EERD);
+ pci_mmio_writel(tmp, eebar + EERD);
/* Poll done flag. 10.000.000 cycles seem to be enough. */
uint32_t i;
for (i = 0; i < MAX_ATTEMPTS; i++) {
- tmp = pci_mmio_readl(nicintel_eebar + EERD);
+ tmp = pci_mmio_readl(eebar + EERD);
if (tmp & BIT(EERD_DONE)) {
*data = (tmp >> EERD_DATA) & 0xffff;
return 0;
@@ -166,12 +175,13 @@ static int nicintel_ee_read_word(unsigned int addr, uint16_t *data)
static int nicintel_ee_read(struct flashctx *flash, uint8_t *buf, unsigned int addr, unsigned int len)
{
+ const struct nicintel_eeprom_data *opaque_data = flash->mst->opaque.data;
uint16_t data;
/* The NIC interface always reads 16 b words so we need to convert the address and handle odd address
* explicitly at the start (and also at the end in the loop below). */
if (addr & 1) {
- if (nicintel_ee_read_word(addr / 2, &data))
+ if (nicintel_ee_read_word(opaque_data->nicintel_eebar, addr / 2, &data))
return -1;
*buf++ = data & 0xff;
addr++;
@@ -179,7 +189,7 @@ static int nicintel_ee_read(struct flashctx *flash, uint8_t *buf, unsigned int a
}
while (len > 0) {
- if (nicintel_ee_read_word(addr / 2, &data))
+ if (nicintel_ee_read_word(opaque_data->nicintel_eebar, addr / 2, &data))
return -1;
*buf++ = data & 0xff;
addr++;
@@ -194,19 +204,19 @@ static int nicintel_ee_read(struct flashctx *flash, uint8_t *buf, unsigned int a
return 0;
}
-static int nicintel_ee_write_word_i210(unsigned int addr, uint16_t data)
+static int nicintel_ee_write_word_i210(uint8_t *eebar, unsigned int addr, uint16_t data)
{
uint32_t eewr;
eewr = addr << EEWR_ADDR;
eewr |= data << EEWR_DATA;
eewr |= BIT(EEWR_CMDV);
- pci_mmio_writel(eewr, nicintel_eebar + EEWR);
+ pci_mmio_writel(eewr, eebar + EEWR);
- programmer_delay(5);
+ default_delay(5);
int i;
for (i = 0; i < MAX_ATTEMPTS; i++)
- if (pci_mmio_readl(nicintel_eebar + EEWR) & BIT(EEWR_DONE))
+ if (pci_mmio_readl(eebar + EEWR) & BIT(EEWR_DONE))
return 0;
return -1;
}
@@ -214,12 +224,13 @@ static int nicintel_ee_write_word_i210(unsigned int addr, uint16_t data)
static int nicintel_ee_write_i210(struct flashctx *flash, const uint8_t *buf,
unsigned int addr, unsigned int len)
{
- done_i20_write = true;
+ struct nicintel_eeprom_data *opaque_data = flash->mst->opaque.data;
+ opaque_data->done_i210_write = true;
if (addr & 1) {
uint16_t data;
- if (nicintel_ee_read_word(addr / 2, &data)) {
+ if (nicintel_ee_read_word(opaque_data->nicintel_eebar, addr / 2, &data)) {
msg_perr("Timeout reading heading byte\n");
return -1;
}
@@ -227,7 +238,7 @@ static int nicintel_ee_write_i210(struct flashctx *flash, const uint8_t *buf,
data &= 0xff;
data |= (buf ? (buf[0]) : 0xff) << 8;
- if (nicintel_ee_write_word_i210(addr / 2, data)) {
+ if (nicintel_ee_write_word_i210(opaque_data->nicintel_eebar, addr / 2, data)) {
msg_perr("Timeout writing heading word\n");
return -1;
}
@@ -242,7 +253,7 @@ static int nicintel_ee_write_i210(struct flashctx *flash, const uint8_t *buf,
uint16_t data;
if (len == 1) {
- if (nicintel_ee_read_word(addr / 2, &data)) {
+ if (nicintel_ee_read_word(opaque_data->nicintel_eebar, addr / 2, &data)) {
msg_perr("Timeout reading tail byte\n");
return -1;
}
@@ -256,7 +267,7 @@ static int nicintel_ee_write_i210(struct flashctx *flash, const uint8_t *buf,
data = 0xffff;
}
- if (nicintel_ee_write_word_i210(addr / 2, data)) {
+ if (nicintel_ee_write_word_i210(opaque_data->nicintel_eebar, addr / 2, data)) {
msg_perr("Timeout writing Shadow RAM\n");
return -1;
}
@@ -278,35 +289,35 @@ static int nicintel_ee_erase_i210(struct flashctx *flash, unsigned int addr, uns
return nicintel_ee_write_i210(flash, NULL, addr, len);
}
-static int nicintel_ee_bitset(int reg, int bit, bool val)
+static int nicintel_ee_bitset(uint8_t *eebar, int reg, int bit, bool val)
{
uint32_t tmp;
- tmp = pci_mmio_readl(nicintel_eebar + reg);
+ tmp = pci_mmio_readl(eebar + reg);
if (val)
tmp |= BIT(bit);
else
tmp &= ~BIT(bit);
- pci_mmio_writel(tmp, nicintel_eebar + reg);
+ pci_mmio_writel(tmp, eebar + reg);
return -1;
}
/* Shifts one byte out while receiving another one by bitbanging (denoted "direct access" in the datasheet). */
-static int nicintel_ee_bitbang(uint8_t mosi, uint8_t *miso)
+static int nicintel_ee_bitbang(uint8_t *eebar, uint8_t mosi, uint8_t *miso)
{
uint8_t out = 0x0;
int i;
for (i = 7; i >= 0; i--) {
- nicintel_ee_bitset(EEC, EE_SI, mosi & BIT(i));
- nicintel_ee_bitset(EEC, EE_SCK, 1);
+ nicintel_ee_bitset(eebar, EEC, EE_SI, mosi & BIT(i));
+ nicintel_ee_bitset(eebar, EEC, EE_SCK, 1);
if (miso != NULL) {
- uint32_t tmp = pci_mmio_readl(nicintel_eebar + EEC);
+ uint32_t tmp = pci_mmio_readl(eebar + EEC);
if (tmp & BIT(EE_SO))
out |= BIT(i);
}
- nicintel_ee_bitset(EEC, EE_SCK, 0);
+ nicintel_ee_bitset(eebar, EEC, EE_SCK, 0);
}
if (miso != NULL)
@@ -316,18 +327,18 @@ static int nicintel_ee_bitbang(uint8_t mosi, uint8_t *miso)
}
/* Polls the WIP bit of the status register of the attached EEPROM via bitbanging. */
-static int nicintel_ee_ready(void)
+static int nicintel_ee_ready(uint8_t *eebar)
{
unsigned int i;
for (i = 0; i < 1000; i++) {
- nicintel_ee_bitset(EEC, EE_CS, 0);
+ nicintel_ee_bitset(eebar, EEC, EE_CS, 0);
- nicintel_ee_bitbang(JEDEC_RDSR, NULL);
+ nicintel_ee_bitbang(eebar, JEDEC_RDSR, NULL);
uint8_t rdsr;
- nicintel_ee_bitbang(0x00, &rdsr);
+ nicintel_ee_bitbang(eebar, 0x00, &rdsr);
- nicintel_ee_bitset(EEC, EE_CS, 1);
- programmer_delay(1);
+ nicintel_ee_bitset(eebar, EEC, EE_CS, 1);
+ default_delay(1);
if (!(rdsr & SPI_SR_WIP)) {
return 0;
}
@@ -336,57 +347,60 @@ static int nicintel_ee_ready(void)
}
/* Requests direct access to the SPI pins. */
-static int nicintel_ee_req(void)
+static int nicintel_ee_req(uint8_t *eebar)
{
uint32_t tmp;
- nicintel_ee_bitset(EEC, EE_REQ, 1);
+ nicintel_ee_bitset(eebar, EEC, EE_REQ, 1);
- tmp = pci_mmio_readl(nicintel_eebar + EEC);
+ tmp = pci_mmio_readl(eebar + EEC);
if (!(tmp & BIT(EE_GNT))) {
msg_perr("Enabling eeprom access failed.\n");
return 1;
}
- nicintel_ee_bitset(EEC, EE_SCK, 0);
+ nicintel_ee_bitset(eebar, EEC, EE_SCK, 0);
return 0;
}
static int nicintel_ee_write_82580(struct flashctx *flash, const uint8_t *buf, unsigned int addr, unsigned int len)
{
- if (nicintel_ee_req())
+ const struct nicintel_eeprom_data *opaque_data = flash->mst->opaque.data;
+ uint8_t *eebar = opaque_data->nicintel_eebar;
+
+ if (nicintel_ee_req(eebar))
return -1;
int ret = -1;
- if (nicintel_ee_ready())
+ if (nicintel_ee_ready(eebar))
goto out;
while (len > 0) {
/* WREN */
- nicintel_ee_bitset(EEC, EE_CS, 0);
- nicintel_ee_bitbang(JEDEC_WREN, NULL);
- nicintel_ee_bitset(EEC, EE_CS, 1);
- programmer_delay(1);
+ nicintel_ee_bitset(eebar, EEC, EE_CS, 0);
+ nicintel_ee_bitbang(eebar, JEDEC_WREN, NULL);
+ nicintel_ee_bitset(eebar, EEC, EE_CS, 1);
+ default_delay(1);
/* data */
- nicintel_ee_bitset(EEC, EE_CS, 0);
- nicintel_ee_bitbang(JEDEC_BYTE_PROGRAM, NULL);
- nicintel_ee_bitbang((addr >> 8) & 0xff, NULL);
- nicintel_ee_bitbang(addr & 0xff, NULL);
+ nicintel_ee_bitset(eebar, EEC, EE_CS, 0);
+ nicintel_ee_bitbang(eebar, JEDEC_BYTE_PROGRAM, NULL);
+ nicintel_ee_bitbang(eebar, (addr >> 8) & 0xff, NULL);
+ nicintel_ee_bitbang(eebar, addr & 0xff, NULL);
while (len > 0) {
- nicintel_ee_bitbang((buf) ? *buf++ : 0xff, NULL);
+ nicintel_ee_bitbang(eebar, (buf) ? *buf++ : 0xff, NULL);
len--;
addr++;
if (!(addr & EE_PAGE_MASK))
break;
}
- nicintel_ee_bitset(EEC, EE_CS, 1);
- programmer_delay(1);
- if (nicintel_ee_ready())
+ nicintel_ee_bitset(eebar, EEC, EE_CS, 1);
+ default_delay(1);
+ if (nicintel_ee_ready(eebar))
goto out;
}
ret = 0;
out:
- nicintel_ee_bitset(EEC, EE_REQ, 0); /* Give up direct access. */
+ nicintel_ee_bitset(eebar, EEC, EE_REQ, 0); /* Give up direct access. */
return ret;
}
@@ -395,64 +409,83 @@ static int nicintel_ee_erase_82580(struct flashctx *flash, unsigned int addr, un
return nicintel_ee_write_82580(flash, NULL, addr, len);
}
-static const struct opaque_master opaque_master_nicintel_ee_82580 = {
- .probe = nicintel_ee_probe_82580,
- .read = nicintel_ee_read,
- .write = nicintel_ee_write_82580,
- .erase = nicintel_ee_erase_82580,
-};
-
-static const struct opaque_master opaque_master_nicintel_ee_i210 = {
- .probe = nicintel_ee_probe_i210,
- .read = nicintel_ee_read,
- .write = nicintel_ee_write_i210,
- .erase = nicintel_ee_erase_i210,
-};
-
-static int nicintel_ee_shutdown_i210(void *arg)
+static int nicintel_ee_shutdown_i210(void *opaque_data)
{
- if (!done_i20_write)
- return 0;
+ struct nicintel_eeprom_data *data = opaque_data;
+ int ret = 0;
- uint32_t flup = pci_mmio_readl(nicintel_eebar + EEC);
+ if (!data->done_i210_write)
+ goto out;
+
+ uint32_t flup = pci_mmio_readl(data->nicintel_eebar + EEC);
flup |= BIT(EE_FLUPD);
- pci_mmio_writel(flup, nicintel_eebar + EEC);
+ pci_mmio_writel(flup, data->nicintel_eebar + EEC);
int i;
for (i = 0; i < MAX_ATTEMPTS; i++)
- if (pci_mmio_readl(nicintel_eebar + EEC) & BIT(EE_FLUDONE))
- return 0;
+ if (pci_mmio_readl(data->nicintel_eebar + EEC) & BIT(EE_FLUDONE))
+ goto out;
+ ret = -1;
msg_perr("Flash update failed\n");
- return -1;
+out:
+ free(data);
+ return ret;
}
-static int nicintel_ee_shutdown_82580(void *eecp)
+static int nicintel_ee_shutdown_82580(void *opaque_data)
{
- uint32_t old_eec = *(uint32_t *)eecp;
- /* Request bitbanging and unselect the chip first to be safe. */
- if (nicintel_ee_req() || nicintel_ee_bitset(EEC, EE_CS, 1))
- return -1;
+ struct nicintel_eeprom_data *data = opaque_data;
+ uint8_t *eebar = data->nicintel_eebar;
+ int ret = 0;
+
+ if (data->nicintel_pci->device_id != UNPROG_DEVICE) {
+ uint32_t old_eec = data->eec;
+ /* Request bitbanging and unselect the chip first to be safe. */
+ if (nicintel_ee_req(eebar) || nicintel_ee_bitset(eebar, EEC, EE_CS, 1)) {
+ ret = -1;
+ goto out;
+ }
- /* Try to restore individual bits we care about. */
- int ret = nicintel_ee_bitset(EEC, EE_SCK, old_eec & BIT(EE_SCK));
- ret |= nicintel_ee_bitset(EEC, EE_SI, old_eec & BIT(EE_SI));
- ret |= nicintel_ee_bitset(EEC, EE_CS, old_eec & BIT(EE_CS));
- /* REQ will be cleared by hardware anyway after 2 seconds of inactivity on the SPI pins (3.3.2.1). */
- ret |= nicintel_ee_bitset(EEC, EE_REQ, old_eec & BIT(EE_REQ));
+ /* Try to restore individual bits we care about. */
+ ret = nicintel_ee_bitset(eebar, EEC, EE_SCK, old_eec & BIT(EE_SCK));
+ ret |= nicintel_ee_bitset(eebar, EEC, EE_SI, old_eec & BIT(EE_SI));
+ ret |= nicintel_ee_bitset(eebar, EEC, EE_CS, old_eec & BIT(EE_CS));
+ /* REQ will be cleared by hardware anyway after 2 seconds of inactivity
+ * on the SPI pins (3.3.2.1). */
+ ret |= nicintel_ee_bitset(eebar, EEC, EE_REQ, old_eec & BIT(EE_REQ));
+ }
- free(eecp);
+out:
+ free(data);
return ret;
}
-int nicintel_ee_init(void)
+static const struct opaque_master opaque_master_nicintel_ee_82580 = {
+ .probe = nicintel_ee_probe_82580,
+ .read = nicintel_ee_read,
+ .write = nicintel_ee_write_82580,
+ .erase = nicintel_ee_erase_82580,
+ .shutdown = nicintel_ee_shutdown_82580,
+};
+
+static const struct opaque_master opaque_master_nicintel_ee_i210 = {
+ .probe = nicintel_ee_probe_i210,
+ .read = nicintel_ee_read,
+ .write = nicintel_ee_write_i210,
+ .erase = nicintel_ee_erase_i210,
+ .shutdown = nicintel_ee_shutdown_i210,
+};
+
+static int nicintel_ee_init(const struct programmer_cfg *cfg)
{
- if (rget_io_perms())
- return 1;
+ const struct opaque_master *mst;
+ uint32_t eec = 0;
+ uint8_t *eebar;
- struct pci_dev *dev = pcidev_init(nics_intel_ee, PCI_BASE_ADDRESS_0);
+ struct pci_dev *dev = pcidev_init(cfg, nics_intel_ee, PCI_BASE_ADDRESS_0);
if (!dev)
return 1;
@@ -461,13 +494,12 @@ int nicintel_ee_init(void)
return 1;
if (!is_i210(dev->device_id)) {
- nicintel_eebar = rphysmap("Intel Gigabit NIC w/ SPI EEPROM", io_base_addr, MEMMAP_SIZE);
- if (!nicintel_eebar)
+ eebar = rphysmap("Intel Gigabit NIC w/ SPI EEPROM", io_base_addr, MEMMAP_SIZE);
+ if (!eebar)
return 1;
- nicintel_pci = dev;
- if ((dev->device_id != UNPROG_DEVICE)) {
- uint32_t eec = pci_mmio_readl(nicintel_eebar + EEC);
+ if (dev->device_id != UNPROG_DEVICE) {
+ eec = pci_mmio_readl(eebar + EEC);
/* C.f. 3.3.1.5 for the detection mechanism (maybe? contradicting
the EE_PRES definition),
@@ -476,28 +508,34 @@ int nicintel_ee_init(void)
msg_perr("Controller reports no EEPROM is present.\n");
return 1;
}
-
- uint32_t *eecp = malloc(sizeof(uint32_t));
- if (eecp == NULL)
- return 1;
- *eecp = eec;
-
- if (register_shutdown(nicintel_ee_shutdown_82580, eecp))
- return 1;
}
- return register_opaque_master(&opaque_master_nicintel_ee_82580);
+ mst = &opaque_master_nicintel_ee_82580;
} else {
- nicintel_eebar = rphysmap("Intel i210 NIC w/ emulated EEPROM",
+ eebar = rphysmap("Intel i210 NIC w/ emulated EEPROM",
io_base_addr + 0x12000, MEMMAP_SIZE);
- if (!nicintel_eebar)
+ if (!eebar)
return 1;
- if (register_shutdown(nicintel_ee_shutdown_i210, NULL))
- return 1;
+ mst = &opaque_master_nicintel_ee_i210;
+ }
- return register_opaque_master(&opaque_master_nicintel_ee_i210);
+ struct nicintel_eeprom_data *data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("Unable to allocate space for OPAQUE master data\n");
+ return 1;
}
+ data->nicintel_pci = dev;
+ data->nicintel_eebar = eebar;
+ data->eec = eec;
+ data->done_i210_write = false;
- return 1;
+ return register_opaque_master(mst, data);
}
+
+const struct programmer_entry programmer_nicintel_eeprom = {
+ .name = "nicintel_eeprom",
+ .type = PCI,
+ .devs.dev = nics_intel_ee,
+ .init = nicintel_ee_init,
+};