[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[cdi-devel] [PATCH 6/7] e1000: Implement support for 8086:10f5 e1000e chip
This adds support for the e1000e in my Thinkpad T500.
The main difference between the already supported e1000 cards and the
8086:10f5 is that the EEPROM can't be accessed using EERD, but must use
the flash interface. Apart from that, only the settings in TCTL differ.
Signed-off-by: Kevin Wolf <kevin@xxxxxxxxxx>
---
e1000/device.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
e1000/device.h | 32 +++++++++++++++++++++++
e1000/e1000_io.h | 29 +++++++++++++++++++++
3 files changed, 139 insertions(+), 1 deletion(-)
diff --git a/e1000/device.c b/e1000/device.c
index 6356721..d9e65c5 100644
--- a/e1000/device.c
+++ b/e1000/device.c
@@ -247,6 +247,63 @@ static uint32_t e1000e_read_eerd(struct e1000_device *device, uint16_t offset)
}
#endif
+static uint32_t e1000e_read_flash(struct e1000_device *device, uint16_t offset)
+{
+ uint16_t hsfsts;
+ uint32_t linear_address;
+
+ /* Convert from words to bytes */
+ offset *= 2;
+
+ if (device->flash_base == NULL) {
+ printf("e1000: Cannot read from flash without flash BAR\n");
+ return (uint32_t) -1;
+ }
+
+ if (offset + 2 > device->flash_size) {
+ printf("e1000: Cannot read from flash offset %d (size %d)\n",
+ offset, device->flash_size);
+ return (uint32_t) -1;
+ }
+
+ /* Check that hardware sequencing is supported */
+ hsfsts = flash_reg_inw(device, FLASH_REG_HSFSTS);
+ if ((hsfsts & HSFSTS_FDV) == 0) {
+ /* TODO Implement access using Software Sequencing registers */
+ printf("e1000: Cannot read from flash without hardware sequencing\n");
+ return (uint32_t) -1;
+ }
+
+ /* Check that no SPI cycle is in progress */
+ if (hsfsts & HSFSTS_SCIP) {
+ printf("e1000: Cannot read from flash while SPI cycle in progress\n");
+ return (uint32_t) -1;
+ }
+
+ /* Start a new cycle */
+ linear_address = device->flash_base_offset + offset;
+ flash_reg_outl(device, FLASH_REG_FADDR, linear_address);
+
+ flash_reg_outw(device, FLASH_REG_HSFSTS,
+ HSFSTS_FDONE | HSFSTS_FCERR | HSFSTS_AEL);
+ flash_reg_outw(device, FLASH_REG_HSFCTL,
+ HSFCTL_FGO | HSFCTL_FCYCLE_READ | HSFCTL_FDBC_WORD);
+
+ CDI_CONDITION_WAIT_SLEEP(
+ flash_reg_inw(device, FLASH_REG_HSFSTS) & HSFSTS_FDONE, 100, 1);
+
+ hsfsts = flash_reg_inw(device, FLASH_REG_HSFSTS);
+ if ((hsfsts & (HSFSTS_FDONE | HSFSTS_FCERR)) == HSFSTS_FDONE) {
+ return flash_reg_inl(device, FLASH_REG_FDATA0);
+ } else if ((hsfsts & HSFSTS_FDONE) == 0){
+ printf("e1000: Timeout while reading from flash\n");
+ } else {
+ printf("e1000: Error while reading from flash\n");
+ }
+
+ return (uint32_t) -1;
+}
+
static uint16_t e1000_eeprom_read(struct e1000_device* device, uint16_t offset)
{
static int eerd_safe = 1;
@@ -287,6 +344,18 @@ static void reset_nic(struct e1000_device* netcard)
cdi_sleep_ms(10);
while (reg_inl(netcard, REG_CTL) & CTL_RESET);
+ // Flash-Basisadresse
+ if (netcard->flash_base) {
+ uint32_t glfpr = flash_reg_inl(netcard, FLASH_REG_GLFPR);
+ uint32_t base = (glfpr & 0x1fff) << 12;
+ uint32_t limit = ((glfpr >> 16) & 0x1fff) << 12;
+
+ netcard->flash_base_offset = base;
+ netcard->flash_size = limit - base;
+
+ printf("e1000: Flash base offset %x; size %x\n", base, limit - base);
+ }
+
// Kontrollregister initialisieren
reg_outl(netcard, REG_CTL, CTL_AUTO_SPEED | CTL_LINK_UP);
@@ -377,6 +446,11 @@ static struct e1000_model models[] = {
.device_id = 0x100f,
.tctl_flags = TCTL_COLL_DIST_E1000,
.eeprom_read = e1000_read_eerd,
+ }, {
+ .vendor_id = 0x8086,
+ .device_id = 0x10f5,
+ .tctl_flags = TCTL_COLL_DIST_E1000E | TCTL_RRTHRESH,
+ .eeprom_read = e1000e_read_flash,
}
};
@@ -418,9 +492,12 @@ found:
cdi_list_t reslist = pci->resources;
struct cdi_pci_resource* res;
for (i = 0; (res = cdi_list_get(reslist, i)); i++) {
- if (res->type == CDI_PCI_MEMORY) {
+ if (res->type == CDI_PCI_MEMORY && res->index == 0) {
struct cdi_mem_area* mmio = cdi_mem_map(res->start, res->length);
netcard->mem_base = mmio->vaddr;
+ } else if (res->type == CDI_PCI_MEMORY && res->index == 1) {
+ struct cdi_mem_area* mmio = cdi_mem_map(res->start, res->length);
+ netcard->flash_base = mmio->vaddr;
}
}
diff --git a/e1000/device.h b/e1000/device.h
index 2eebf8a..638e6f9 100644
--- a/e1000/device.h
+++ b/e1000/device.h
@@ -93,6 +93,10 @@ enum {
/* e1000 specific values */
TCTL_COLL_DIST_E1000 = (0x40 << 12), /* COLD - Collision Distance */
+
+ /* e1000e specific values */
+ TCTL_COLL_DIST_E1000E = (0x3f << 12), /* COLD - Collision Distance */
+ TCTL_RRTHRESH = (0x03 << 28), /* Read Request Threshold */
};
enum {
@@ -101,6 +105,31 @@ enum {
};
enum {
+ FLASH_REG_GLFPR = 0x0, /* Gigabit LAN Flash Primary Region */
+ FLASH_REG_HSFSTS = 0x4, /* Hardware Sequencing Flash Status */
+ FLASH_REG_HSFCTL = 0x6, /* Hardware Sequencing Flash Control */
+ FLASH_REG_FADDR = 0x8, /* Flash Address Register */
+ FLASH_REG_FDATA0 = 0x10, /* Flash Data 0 Register */
+};
+
+enum {
+ HSFSTS_FDONE = (1 << 0),
+ HSFSTS_FCERR = (1 << 1),
+ HSFSTS_AEL = (1 << 2),
+ HSFSTS_SCIP = (1 << 5),
+ HSFSTS_FDV = (1 << 14),
+};
+
+enum {
+ HSFCTL_FGO = (1 << 0),
+ HSFCTL_FCYCLE_READ = (0 << 1),
+ /*HSFCTL_FCYCLE_WRITE = (2 << 1),*/
+ HSFCTL_FDBC_BYTE = (0 << 8),
+ HSFCTL_FDBC_WORD = (1 << 8),
+ HSFCTL_FDBC_DWORD = (3 << 8),
+};
+
+enum {
EEPROM_OFS_MAC = 0x0,
};
@@ -190,6 +219,9 @@ struct e1000_device {
uint32_t rx_cur_buffer;
void* mem_base;
+ void* flash_base;
+ uint32_t flash_base_offset;
+ uint32_t flash_size;
uint8_t revision;
struct e1000_model* model;
diff --git a/e1000/e1000_io.h b/e1000/e1000_io.h
index 68937a9..2432b1c 100644
--- a/e1000/e1000_io.h
+++ b/e1000/e1000_io.h
@@ -74,4 +74,33 @@ static inline uint32_t reg_inl(struct e1000_device* netcard, uint16_t reg)
return *mmio;
}
+
+/* Flash register access */
+
+static inline void flash_reg_outw
+ (struct e1000_device* netcard, uint16_t reg, uint16_t value)
+{
+ volatile uint16_t* mmio = (uint16_t*) (((char*)netcard->flash_base) + reg);
+ *mmio = value;
+}
+
+static inline void flash_reg_outl
+ (struct e1000_device* netcard, uint16_t reg, uint32_t value)
+{
+ volatile uint32_t* mmio = (uint32_t*) (((char*)netcard->flash_base) + reg);
+ *mmio = value;
+}
+
+static inline uint16_t flash_reg_inw(struct e1000_device* netcard, uint16_t reg)
+{
+ volatile uint16_t* mmio = (uint16_t*) (((char*)netcard->flash_base) + reg);
+ return *mmio;
+}
+
+static inline uint32_t flash_reg_inl(struct e1000_device* netcard, uint16_t reg)
+{
+ volatile uint32_t* mmio = (uint32_t*) (((char*)netcard->flash_base) + reg);
+ return *mmio;
+}
+
#endif
--
2.1.4