Commit ce5207e1 authored by Kyle Moffett's avatar Kyle Moffett Committed by Wolfgang Denk

e1000: Allow direct access to the E1000 SPI EEPROM device

As a part of the manufacturing process for some of our custom hardware,
we are programming the EEPROMs attached to our Intel 82571EB controllers
from software using U-Boot and Linux.

This code provides several conditionally-compiled features to assist in
our manufacturing process:

    This is a basic "e1000" command which allows querying the controller
    and (if other config options are set) performing EEPROM programming.
    In particular, with CONFIG_E1000_SPI this allows you to display a
    hex-dump of the EEPROM, copy to/from main memory, and verify/update
    the software checksum.

    Build a generic SPI driver providing the standard U-Boot SPI driver
    interface.  This allows commands such as "sspi" to access the bus
    attached to the E1000 controller.  Additionally, some E1000 chipsets
    can support user data in a reserved space in the E1000 EEPROM which
    could be used for U-Boot environment storage.

    The core SPI access code used by the above interfaces.

For example, the following commands allow you to program the EEPROM from
a USB device (assumes CONFIG_E1000_SPI and CONFIG_CMD_E1000 are enabled):
  usb start
  fatload usb 0 $loadaddr 82571EB_No_Mgmt_Discrete-LOM.bin
  e1000 0 spi program $loadaddr 0 1024
  e1000 0 spi checksum update

Please keep in mind that the Intel-provided .eep files are organized as
16-bit words.  When converting them to binary form for programming you
must byteswap each 16-bit word so that it is in little-endian form.

This means that when reading and writing words to the SPI EEPROM, the
bit ordering for each word looks like this on the wire:

  Time >>>
  ... [7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8], ...
  (MSB is 15, LSB is 0).
Signed-off-by: 's avatarKyle Moffett <>
Cc: Ben Warren <>
parent 2326a94d
......@@ -957,7 +957,20 @@ The following options need to be configured:
- NETWORK Support (PCI):
Support for Intel 8254x gigabit chips.
Support for Intel 8254x/8257x gigabit chips.
Utility code for direct access to the SPI bus on Intel 8257x.
This does not do anything useful unless you set at least one
Allow generic access to the SPI bus on the Intel 8257x, for
example with the "sspi" command.
Management command for E1000 devices. When used on devices
with SPI support you can reprogram the EEPROM from U-Boot.
default MAC for empty EEPROM after production.
......@@ -37,6 +37,7 @@ COBJS-$(CONFIG_DESIGNWARE_ETH) += designware.o
COBJS-$(CONFIG_DRIVER_DM9000) += dm9000x.o
COBJS-$(CONFIG_DNET) += dnet.o
COBJS-$(CONFIG_E1000) += e1000.o
COBJS-$(CONFIG_E1000_SPI) += e1000_spi.o
COBJS-$(CONFIG_EEPRO100) += eepro100.o
COBJS-$(CONFIG_ENC28J60) += enc28j60.o
COBJS-$(CONFIG_EP93XX) += ep93xx_eth.o
......@@ -5155,6 +5155,9 @@ void e1000_get_bus_type(struct e1000_hw *hw)
/* A list of all registered e1000 devices */
static LIST_HEAD(e1000_hw_list);
PROBE - Look for an adapter, this routine's visible to the outside
You should omit the last argument struct pci_device * for a non-PCI NIC
......@@ -5234,8 +5237,9 @@ e1000_initialize(bd_t * bis)
if (e1000_check_phy_reset_block(hw))
E1000_ERR(nic, "PHY Reset is blocked!\n");
/* Basic init was OK, reset the hardware */
/* Basic init was OK, reset the hardware and allow SPI access */
list_add_tail(&hw->list_node, &e1000_hw_list);
/* Validate the EEPROM and get chipset information */
#if !(defined(CONFIG_AP1000) || defined(CONFIG_MVBC_1G))
......@@ -5263,3 +5267,63 @@ e1000_initialize(bd_t * bis)
return i;
struct e1000_hw *e1000_find_card(unsigned int cardnum)
struct e1000_hw *hw;
list_for_each_entry(hw, &e1000_hw_list, list_node)
if (hw->cardnum == cardnum)
return hw;
return NULL;
#ifdef CONFIG_CMD_E1000
static int do_e1000(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
struct e1000_hw *hw;
if (argc < 3) {
return 1;
/* Make sure we can find the requested e1000 card */
hw = e1000_find_card(simple_strtoul(argv[1], NULL, 10));
if (!hw) {
printf("e1000: ERROR: No such device: e1000#%s\n", argv[1]);
return 1;
if (!strcmp(argv[2], "print-mac-address")) {
unsigned char *mac = hw->nic->enetaddr;
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return 0;
#ifdef CONFIG_E1000_SPI
/* Handle the "SPI" subcommand */
if (!strcmp(argv[2], "spi"))
return do_e1000_spi(cmdtp, hw, argc - 3, argv + 3);
return 1;
e1000, 7, 0, do_e1000,
"Intel e1000 controller management",
/* */"<card#> print-mac-address\n"
#ifdef CONFIG_E1000_SPI
"e1000 <card#> spi show [<offset> [<length>]]\n"
"e1000 <card#> spi dump <addr> <offset> <length>\n"
"e1000 <card#> spi program <addr> <offset> <length>\n"
"e1000 <card#> spi checksum [update]\n"
" - Manage the Intel E1000 PCI device"
#endif /* not CONFIG_CMD_E1000 */
......@@ -35,12 +35,17 @@
#define _E1000_HW_H_
#include <common.h>
#include <linux/list.h>
#include <malloc.h>
#include <net.h>
#include <netdev.h>
#include <asm/io.h>
#include <pci.h>
#ifdef CONFIG_E1000_SPI
#include <spi.h>
#define E1000_ERR(NIC, fmt, args...) \
printf("e1000: %s: ERROR: " fmt, (NIC)->name ,##args)
......@@ -72,12 +77,18 @@ struct e1000_hw;
struct e1000_hw_stats;
/* Internal E1000 helper functions */
struct e1000_hw *e1000_find_card(unsigned int cardnum);
int32_t e1000_acquire_eeprom(struct e1000_hw *hw);
void e1000_standby_eeprom(struct e1000_hw *hw);
void e1000_release_eeprom(struct e1000_hw *hw);
void e1000_raise_ee_clk(struct e1000_hw *hw, uint32_t *eecd);
void e1000_lower_ee_clk(struct e1000_hw *hw, uint32_t *eecd);
#ifdef CONFIG_E1000_SPI
int do_e1000_spi(cmd_tbl_t *cmdtp, struct e1000_hw *hw,
int argc, char * const argv[]);
typedef enum {
FALSE = 0,
TRUE = 1
......@@ -1068,7 +1079,11 @@ typedef enum {
/* Structure containing variables used by the shared code (e1000_hw.c) */
struct e1000_hw {
struct list_head list_node;
struct eth_device *nic;
#ifdef CONFIG_E1000_SPI
struct spi_slave spi;
unsigned int cardnum;
pci_dev_t pdev;
This diff is collapsed.
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