Commit 004f4b79 authored by Idwer Vollering's avatar Idwer Vollering Committed by Uwe Hermann
Browse files

Add Intel Gigabit NIC SPI flashing support


Tested on a 82541PI (0x8086, 0x107c) using 32-bit hardware.

The last line in nicintel_request_spibus() could be changed so that FL_BUSY
is used instead.

Shortened sample log:
[...]
Found "Intel 82541PI Gigabit Ethernet Controller" (8086:107c, BDF 01:03.0).
Found chip "ST M25P10.RES" (128 KB, SPI) at physical address 0xfffe0000.
Multiple flash chips were detected: M25P05.RES M25P10.RES
Please specify which chip to use with the -c <chipname> option.
[...]

Corresponding to flashrom svn r1151.
Signed-off-by: default avatarIdwer Vollering <vidwer@gmail.com>
Acked-by: default avatarUwe Hermann <uwe@hermann-uwe.de>
parent 67db2eb9
...@@ -121,9 +121,13 @@ else ...@@ -121,9 +121,13 @@ else
ifeq ($(CONFIG_INTERNAL), yes) ifeq ($(CONFIG_INTERNAL), yes)
override CONFIG_BITBANG_SPI = yes override CONFIG_BITBANG_SPI = yes
else else
ifeq ($(CONFIG_NICINTEL_SPI), yes)
override CONFIG_BITBANG_SPI = yes
else
CONFIG_BITBANG_SPI ?= no CONFIG_BITBANG_SPI ?= no
endif endif
endif endif
endif
# Always enable 3Com NICs for now. # Always enable 3Com NICs for now.
CONFIG_NIC3COM ?= yes CONFIG_NIC3COM ?= yes
...@@ -153,6 +157,9 @@ CONFIG_NICREALTEK ?= yes ...@@ -153,6 +157,9 @@ CONFIG_NICREALTEK ?= yes
# Disable National Semiconductor NICs until support is complete and tested. # Disable National Semiconductor NICs until support is complete and tested.
CONFIG_NICNATSEMI ?= no CONFIG_NICNATSEMI ?= no
# Always enable SPI on Intel NICs for now.
CONFIG_NICINTEL_SPI ?= yes
# Always enable Bus Pirate SPI for now. # Always enable Bus Pirate SPI for now.
CONFIG_BUSPIRATE_SPI ?= yes CONFIG_BUSPIRATE_SPI ?= yes
...@@ -244,6 +251,12 @@ PROGRAMMER_OBJS += nicnatsemi.o ...@@ -244,6 +251,12 @@ PROGRAMMER_OBJS += nicnatsemi.o
NEED_PCI := yes NEED_PCI := yes
endif endif
ifeq ($(CONFIG_NICINTEL_SPI), yes)
FEATURE_CFLAGS += -D'CONFIG_NICINTEL_SPI=1'
PROGRAMMER_OBJS += nicintel_spi.o
NEED_PCI := yes
endif
ifeq ($(CONFIG_BUSPIRATE_SPI), yes) ifeq ($(CONFIG_BUSPIRATE_SPI), yes)
FEATURE_CFLAGS += -D'CONFIG_BUSPIRATE_SPI=1' FEATURE_CFLAGS += -D'CONFIG_BUSPIRATE_SPI=1'
PROGRAMMER_OBJS += buspirate_spi.o PROGRAMMER_OBJS += buspirate_spi.o
......
...@@ -190,6 +190,9 @@ based USB SPI programmer)" ...@@ -190,6 +190,9 @@ based USB SPI programmer)"
.BR "* rayer_spi" " (for SPI flash ROMs attached to a RayeR parport \ .BR "* rayer_spi" " (for SPI flash ROMs attached to a RayeR parport \
based programmer)" based programmer)"
.sp .sp
.BR "* nicintel_spi" " (for SPI flash ROMs attached to an Intel Gigabit \
network cards)"
.sp
Some programmers have optional or mandatory parameters which are described Some programmers have optional or mandatory parameters which are described
in detail in the in detail in the
.B PROGRAMMER SPECIFIC INFO .B PROGRAMMER SPECIFIC INFO
......
...@@ -49,7 +49,7 @@ enum programmer programmer = PROGRAMMER_DUMMY; ...@@ -49,7 +49,7 @@ enum programmer programmer = PROGRAMMER_DUMMY;
* if more than one of them is selected. If only one is selected, it is clear * if more than one of them is selected. If only one is selected, it is clear
* that the user wants that one to become the default. * that the user wants that one to become the default.
*/ */
#if CONFIG_NIC3COM+CONFIG_NICREALTEK+CONFIG_NICNATSEMI+CONFIG_GFXNVIDIA+CONFIG_DRKAISER+CONFIG_SATASII+CONFIG_ATAHPT+CONFIG_FT2232_SPI+CONFIG_SERPROG+CONFIG_BUSPIRATE_SPI+CONFIG_DEDIPROG+CONFIG_RAYER_SPI > 1 #if CONFIG_NIC3COM+CONFIG_NICREALTEK+CONFIG_NICNATSEMI+CONFIG_GFXNVIDIA+CONFIG_DRKAISER+CONFIG_SATASII+CONFIG_ATAHPT+CONFIG_FT2232_SPI+CONFIG_SERPROG+CONFIG_BUSPIRATE_SPI+CONFIG_DEDIPROG+CONFIG_RAYER_SPI+CONFIG_NICINTEL_SPI > 1
#error Please enable either CONFIG_DUMMY or CONFIG_INTERNAL or disable support for all programmers except one. #error Please enable either CONFIG_DUMMY or CONFIG_INTERNAL or disable support for all programmers except one.
#endif #endif
enum programmer programmer = enum programmer programmer =
...@@ -90,6 +90,9 @@ enum programmer programmer = ...@@ -90,6 +90,9 @@ enum programmer programmer =
#if CONFIG_RAYER_SPI == 1 #if CONFIG_RAYER_SPI == 1
PROGRAMMER_RAYER_SPI PROGRAMMER_RAYER_SPI
#endif #endif
#if CONFIG_NICINTEL_SPI == 1
PROGRAMMER_NICINTEL_SPI
#endif
; ;
#endif #endif
...@@ -414,6 +417,25 @@ const struct programmer_entry programmer_table[] = { ...@@ -414,6 +417,25 @@ const struct programmer_entry programmer_table[] = {
}, },
#endif #endif
#if CONFIG_NICINTEL_SPI == 1
{
.name = "nicintel_spi",
.init = nicintel_spi_init,
.shutdown = nicintel_spi_shutdown,
.map_flash_region = fallback_map,
.unmap_flash_region = fallback_unmap,
.chip_readb = noop_chip_readb,
.chip_readw = fallback_chip_readw,
.chip_readl = fallback_chip_readl,
.chip_readn = fallback_chip_readn,
.chip_writeb = noop_chip_writeb,
.chip_writew = fallback_chip_writew,
.chip_writel = fallback_chip_writel,
.chip_writen = fallback_chip_writen,
.delay = internal_delay,
},
#endif
{}, /* This entry corresponds to PROGRAMMER_INVALID. */ {}, /* This entry corresponds to PROGRAMMER_INVALID. */
}; };
......
/*
* This file is part of the flashrom project.
*
* Copyright (C) 2010 Carl-Daniel Hailfinger
* Copyright (C) 2010 Idwer Vollering
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* Datasheet:
* PCI/PCI-X Family of Gigabit Ethernet Controllers Software Developer's Manual
* 82540EP/EM, 82541xx, 82544GC/EI, 82545GM/EM, 82546GB/EB, and 82547xx
* http://download.intel.com/design/network/manuals/8254x_GBe_SDM.pdf
*/
#include <stdlib.h>
#include "flash.h"
#include "programmer.h"
#define PCI_VENDOR_ID_INTEL 0x8086
#define EECD 0x10
#define FLA 0x1c
/*
* Register bits of EECD.
*
* Bit 04, 05: FWE (Flash Write Enable Control)
* 00b = not allowed
* 01b = flash writes disabled
* 10b = flash writes enabled
* 11b = not allowed
*/
#define FLASH_WRITES_DISABLED 0x10 /* FWE: 10000b */
#define FLASH_WRITES_ENABLED 0x20 /* FWE: 100000b */
/* Flash Access register bits */
/* Table 13-9 */
#define FL_SCK 0
#define FL_CS 1
#define FL_SI 2
#define FL_SO 3
#define FL_REQ 4
#define FL_GNT 5
/* Currently unused */
// #define FL_BUSY 30
// #define FL_ER 31
uint8_t *nicintel_spibar;
const struct pcidev_status nics_intel_spi[] = {
{PCI_VENDOR_ID_INTEL, 0x107c, OK, "Intel", "82541PI Gigabit Ethernet Controller"},
{},
};
static void nicintel_request_spibus(void)
{
uint32_t tmp;
tmp = pci_mmio_readl(nicintel_spibar + FLA);
tmp |= 1 << FL_REQ;
pci_mmio_writel(tmp, nicintel_spibar + FLA);
/* Wait until we are allowed to use the SPI bus. */
while (!(pci_mmio_readl(nicintel_spibar + FLA) & (1 << FL_GNT))) ;
}
static void nicintel_release_spibus(void)
{
uint32_t tmp;
tmp = pci_mmio_readl(nicintel_spibar + FLA);
tmp &= ~(1 << FL_REQ);
pci_mmio_writel(tmp, nicintel_spibar + FLA);
}
static void nicintel_bitbang_set_cs(int val)
{
uint32_t tmp;
/*
* Requesting and releasing the SPI bus is handled in here to allow
* the chipset to use its own SPI engine for native reads.
*/
if (val == 0)
nicintel_request_spibus();
tmp = pci_mmio_readl(nicintel_spibar + FLA);
tmp &= ~(1 << FL_CS);
tmp |= (val << FL_CS);
pci_mmio_writel(tmp, nicintel_spibar + FLA);
if (val == 1)
nicintel_release_spibus();
}
static void nicintel_bitbang_set_sck(int val)
{
uint32_t tmp;
tmp = pci_mmio_readl(nicintel_spibar + FLA);
tmp &= ~(1 << FL_SCK);
tmp |= (val << FL_SCK);
pci_mmio_writel(tmp, nicintel_spibar + FLA);
}
static void nicintel_bitbang_set_mosi(int val)
{
uint32_t tmp;
tmp = pci_mmio_readl(nicintel_spibar + FLA);
tmp &= ~(1 << FL_SI);
tmp |= (val << FL_SI);
pci_mmio_writel(tmp, nicintel_spibar + FLA);
}
static int nicintel_bitbang_get_miso(void)
{
uint32_t tmp;
tmp = pci_mmio_readl(nicintel_spibar + FLA);
tmp = (tmp >> FL_SO) & 0x1;
return tmp;
}
static const struct bitbang_spi_master bitbang_spi_master_nicintel = {
.type = BITBANG_SPI_MASTER_NICINTEL,
.set_cs = nicintel_bitbang_set_cs,
.set_sck = nicintel_bitbang_set_sck,
.set_mosi = nicintel_bitbang_set_mosi,
.get_miso = nicintel_bitbang_get_miso,
};
int nicintel_spi_init(void)
{
uint32_t tmp;
get_io_perms();
io_base_addr = pcidev_init(PCI_VENDOR_ID_INTEL, PCI_BASE_ADDRESS_0,
nics_intel_spi);
nicintel_spibar = physmap("Intel Gigabit NIC w/ SPI flash",
io_base_addr, 4096);
tmp = pci_mmio_readl(nicintel_spibar + EECD);
tmp &= ~FLASH_WRITES_DISABLED;
tmp |= FLASH_WRITES_ENABLED;
pci_mmio_writel(tmp, nicintel_spibar + EECD);
/* 1 usec halfperiod delay for now. */
if (bitbang_spi_init(&bitbang_spi_master_nicintel, 1))
return 1;
buses_supported = CHIP_BUSTYPE_SPI;
spi_controller = SPI_CONTROLLER_NICINTEL;
return 0;
}
int nicintel_spi_shutdown(void)
{
uint32_t tmp;
tmp = pci_mmio_readl(nicintel_spibar + EECD);
tmp &= ~FLASH_WRITES_ENABLED;
tmp |= FLASH_WRITES_DISABLED;
pci_mmio_writel(tmp, nicintel_spibar + EECD);
physunmap(nicintel_spibar, 4096);
pci_cleanup(pacc);
release_io_perms();
return 0;
}
...@@ -255,6 +255,9 @@ void print_supported(void) ...@@ -255,6 +255,9 @@ void print_supported(void)
#if CONFIG_ATAHPT == 1 #if CONFIG_ATAHPT == 1
print_supported_pcidevs(ata_hpt); print_supported_pcidevs(ata_hpt);
#endif #endif
#if CONFIG_NICINTEL_SPI == 1
print_supported_pcidevs(nics_intel_spi);
#endif
#if CONFIG_FT2232_SPI+CONFIG_DEDIPROG >= 1 #if CONFIG_FT2232_SPI+CONFIG_DEDIPROG >= 1
printf("\nSupported USB devices flashrom can use " printf("\nSupported USB devices flashrom can use "
......
...@@ -295,6 +295,9 @@ void print_supported_wiki(void) ...@@ -295,6 +295,9 @@ void print_supported_wiki(void)
#endif #endif
#if CONFIG_ATAHPT == 1 #if CONFIG_ATAHPT == 1
print_supported_pcidevs_wiki(ata_hpt); print_supported_pcidevs_wiki(ata_hpt);
#endif
#if CONFIG_NICINTEL_SPI == 1
print_supported_pcidevs_wiki(nics_intel_spi);
#endif #endif
printf("\n|}\n"); printf("\n|}\n");
} }
......
...@@ -37,10 +37,10 @@ enum programmer { ...@@ -37,10 +37,10 @@ enum programmer {
#if CONFIG_NICREALTEK == 1 #if CONFIG_NICREALTEK == 1
PROGRAMMER_NICREALTEK, PROGRAMMER_NICREALTEK,
PROGRAMMER_NICREALTEK2, PROGRAMMER_NICREALTEK2,
#endif #endif
#if CONFIG_NICNATSEMI == 1 #if CONFIG_NICNATSEMI == 1
PROGRAMMER_NICNATSEMI, PROGRAMMER_NICNATSEMI,
#endif #endif
#if CONFIG_GFXNVIDIA == 1 #if CONFIG_GFXNVIDIA == 1
PROGRAMMER_GFXNVIDIA, PROGRAMMER_GFXNVIDIA,
#endif #endif
...@@ -72,6 +72,9 @@ enum programmer { ...@@ -72,6 +72,9 @@ enum programmer {
#endif #endif
#if CONFIG_RAYER_SPI == 1 #if CONFIG_RAYER_SPI == 1
PROGRAMMER_RAYER_SPI, PROGRAMMER_RAYER_SPI,
#endif
#if CONFIG_NICINTEL_SPI == 1
PROGRAMMER_NICINTEL_SPI,
#endif #endif
PROGRAMMER_INVALID /* This must always be the last entry. */ PROGRAMMER_INVALID /* This must always be the last entry. */
}; };
...@@ -110,6 +113,9 @@ enum bitbang_spi_master_type { ...@@ -110,6 +113,9 @@ enum bitbang_spi_master_type {
#if CONFIG_RAYER_SPI == 1 #if CONFIG_RAYER_SPI == 1
BITBANG_SPI_MASTER_RAYER, BITBANG_SPI_MASTER_RAYER,
#endif #endif
#if CONFIG_NICINTEL_SPI == 1
BITBANG_SPI_MASTER_NICINTEL,
#endif
#if CONFIG_INTERNAL == 1 #if CONFIG_INTERNAL == 1
#if defined(__i386__) || defined(__x86_64__) #if defined(__i386__) || defined(__x86_64__)
BITBANG_SPI_MASTER_MCP, BITBANG_SPI_MASTER_MCP,
...@@ -207,7 +213,7 @@ uint32_t pcidev_init(uint16_t vendor_id, uint32_t bar, const struct pcidev_statu ...@@ -207,7 +213,7 @@ uint32_t pcidev_init(uint16_t vendor_id, uint32_t bar, const struct pcidev_statu
#endif #endif
/* print.c */ /* print.c */
#if CONFIG_NIC3COM+CONFIG_NICREALTEK+CONFIG_NICNATSEMI+CONFIG_GFXNVIDIA+CONFIG_DRKAISER+CONFIG_SATASII+CONFIG_ATAHPT >= 1 #if CONFIG_NIC3COM+CONFIG_NICREALTEK+CONFIG_NICNATSEMI+CONFIG_GFXNVIDIA+CONFIG_DRKAISER+CONFIG_SATASII+CONFIG_ATAHPT+CONFIG_NICINTEL_SPI >= 1
void print_supported_pcidevs(const struct pcidev_status *devs); void print_supported_pcidevs(const struct pcidev_status *devs);
#endif #endif
...@@ -378,6 +384,16 @@ uint8_t nicnatsemi_chip_readb(const chipaddr addr); ...@@ -378,6 +384,16 @@ uint8_t nicnatsemi_chip_readb(const chipaddr addr);
extern const struct pcidev_status nics_natsemi[]; extern const struct pcidev_status nics_natsemi[];
#endif #endif
/* nicintel_spi.c */
#if CONFIG_NICINTEL_SPI == 1
int nicintel_spi_init(void);
int nicintel_spi_shutdown(void);
int nicintel_spi_send_command(unsigned int writecnt, unsigned int readcnt,
const unsigned char *writearr, unsigned char *readarr);
void nicintel_spi_chip_writeb(uint8_t val, chipaddr addr);
extern const struct pcidev_status nics_intel_spi[];
#endif
/* satasii.c */ /* satasii.c */
#if CONFIG_SATASII == 1 #if CONFIG_SATASII == 1
int satasii_init(void); int satasii_init(void);
...@@ -493,6 +509,9 @@ enum spi_controller { ...@@ -493,6 +509,9 @@ enum spi_controller {
#endif #endif
#if CONFIG_RAYER_SPI == 1 #if CONFIG_RAYER_SPI == 1
SPI_CONTROLLER_RAYER, SPI_CONTROLLER_RAYER,
#endif
#if CONFIG_NICINTEL_SPI == 1
SPI_CONTROLLER_NICINTEL,
#endif #endif
SPI_CONTROLLER_INVALID /* This must always be the last entry. */ SPI_CONTROLLER_INVALID /* This must always be the last entry. */
}; };
......
...@@ -136,6 +136,15 @@ const struct spi_programmer spi_programmer[] = { ...@@ -136,6 +136,15 @@ const struct spi_programmer spi_programmer[] = {
}, },
#endif #endif
#if CONFIG_NICINTEL_SPI == 1
{ /* SPI_CONTROLLER_NICINTEL */
.command = bitbang_spi_send_command,
.multicommand = default_spi_send_multicommand,
.read = bitbang_spi_read,
.write_256 = bitbang_spi_write_256,
},
#endif
{}, /* This entry corresponds to SPI_CONTROLLER_INVALID. */ {}, /* This entry corresponds to SPI_CONTROLLER_INVALID. */
}; };
......
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