mirror of
https://review.coreboot.org/flashrom.git
synced 2025-04-27 15:12:36 +02:00
Revert MMIO space writes on shutdown as needed
Reversible MMIO space writes now use rmmio_write*(). Reversible PCI MMIO space writes now use pci_rmmio_write*(). If a MMIO value needs to be queued for restore without writing it, use rmmio_val*(). MMIO space writes which are one-shot (e.g. communication with some chip) should continue to use the permanent mmio_write* variants. Corresponding to flashrom svn r1292. Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net> David tested it successfully on some NM10/ICH7 platforms which switch between SPI and LPC targets (x86 BIOS ROM vs. EC firmware ROM). Acked-by: David Hendricks <dhendrix@google.com>
This commit is contained in:
parent
8ed293416d
commit
54ce73a1f5
101
hwaccess.c
101
hwaccess.c
@ -184,3 +184,104 @@ uint32_t mmio_le_readl(void *addr)
|
|||||||
{
|
{
|
||||||
return le_to_cpu32(mmio_readl(addr));
|
return le_to_cpu32(mmio_readl(addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum mmio_write_type {
|
||||||
|
mmio_write_type_b,
|
||||||
|
mmio_write_type_w,
|
||||||
|
mmio_write_type_l,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct undo_mmio_write_data {
|
||||||
|
void *addr;
|
||||||
|
int reg;
|
||||||
|
enum mmio_write_type type;
|
||||||
|
union {
|
||||||
|
uint8_t bdata;
|
||||||
|
uint16_t wdata;
|
||||||
|
uint32_t ldata;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
void undo_mmio_write(void *p)
|
||||||
|
{
|
||||||
|
struct undo_mmio_write_data *data = p;
|
||||||
|
msg_pdbg("Restoring MMIO space at %p\n", data->addr);
|
||||||
|
switch (data->type) {
|
||||||
|
case mmio_write_type_b:
|
||||||
|
mmio_writeb(data->bdata, data->addr);
|
||||||
|
break;
|
||||||
|
case mmio_write_type_w:
|
||||||
|
mmio_writew(data->wdata, data->addr);
|
||||||
|
break;
|
||||||
|
case mmio_write_type_l:
|
||||||
|
mmio_writel(data->ldata, data->addr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* p was allocated in register_undo_mmio_write. */
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define register_undo_mmio_write(a, c) \
|
||||||
|
{ \
|
||||||
|
struct undo_mmio_write_data *undo_mmio_write_data; \
|
||||||
|
undo_mmio_write_data = malloc(sizeof(struct undo_mmio_write_data)); \
|
||||||
|
undo_mmio_write_data->addr = a; \
|
||||||
|
undo_mmio_write_data->type = mmio_write_type_##c; \
|
||||||
|
undo_mmio_write_data->c##data = mmio_read##c(a); \
|
||||||
|
register_shutdown(undo_mmio_write, undo_mmio_write_data); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define register_undo_mmio_writeb(a) register_undo_mmio_write(a, b)
|
||||||
|
#define register_undo_mmio_writew(a) register_undo_mmio_write(a, w)
|
||||||
|
#define register_undo_mmio_writel(a) register_undo_mmio_write(a, l)
|
||||||
|
|
||||||
|
void rmmio_writeb(uint8_t val, void *addr)
|
||||||
|
{
|
||||||
|
register_undo_mmio_writeb(addr);
|
||||||
|
mmio_writeb(val, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rmmio_writew(uint16_t val, void *addr)
|
||||||
|
{
|
||||||
|
register_undo_mmio_writew(addr);
|
||||||
|
mmio_writew(val, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rmmio_writel(uint32_t val, void *addr)
|
||||||
|
{
|
||||||
|
register_undo_mmio_writel(addr);
|
||||||
|
mmio_writel(val, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rmmio_le_writeb(uint8_t val, void *addr)
|
||||||
|
{
|
||||||
|
register_undo_mmio_writeb(addr);
|
||||||
|
mmio_le_writeb(val, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rmmio_le_writew(uint16_t val, void *addr)
|
||||||
|
{
|
||||||
|
register_undo_mmio_writew(addr);
|
||||||
|
mmio_le_writew(val, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rmmio_le_writel(uint32_t val, void *addr)
|
||||||
|
{
|
||||||
|
register_undo_mmio_writel(addr);
|
||||||
|
mmio_le_writel(val, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rmmio_valb(void *addr)
|
||||||
|
{
|
||||||
|
register_undo_mmio_writeb(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rmmio_valw(void *addr)
|
||||||
|
{
|
||||||
|
register_undo_mmio_writew(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rmmio_vall(void *addr)
|
||||||
|
{
|
||||||
|
register_undo_mmio_writel(addr);
|
||||||
|
}
|
||||||
|
50
ichspi.c
50
ichspi.c
@ -163,7 +163,7 @@ static uint16_t REGREAD8(int X)
|
|||||||
static int find_opcode(OPCODES *op, uint8_t opcode);
|
static int find_opcode(OPCODES *op, uint8_t opcode);
|
||||||
static int find_preop(OPCODES *op, uint8_t preop);
|
static int find_preop(OPCODES *op, uint8_t preop);
|
||||||
static int generate_opcodes(OPCODES * op);
|
static int generate_opcodes(OPCODES * op);
|
||||||
static int program_opcodes(OPCODES * op);
|
static int program_opcodes(OPCODES *op, int enable_undo);
|
||||||
static int run_opcode(OPCODE op, uint32_t offset,
|
static int run_opcode(OPCODE op, uint32_t offset,
|
||||||
uint8_t datalength, uint8_t * data);
|
uint8_t datalength, uint8_t * data);
|
||||||
|
|
||||||
@ -269,7 +269,7 @@ static int reprogram_opcode_on_the_fly(uint8_t opcode, unsigned int writecnt, un
|
|||||||
int oppos=2; // use original JEDEC_BE_D8 offset
|
int oppos=2; // use original JEDEC_BE_D8 offset
|
||||||
curopcodes->opcode[oppos].opcode = opcode;
|
curopcodes->opcode[oppos].opcode = opcode;
|
||||||
curopcodes->opcode[oppos].spi_type = spi_type;
|
curopcodes->opcode[oppos].spi_type = spi_type;
|
||||||
program_opcodes(curopcodes);
|
program_opcodes(curopcodes, 0);
|
||||||
oppos = find_opcode(curopcodes, opcode);
|
oppos = find_opcode(curopcodes, opcode);
|
||||||
msg_pdbg ("on-the-fly OPCODE (0x%02X) re-programmed, op-pos=%d\n", opcode, oppos);
|
msg_pdbg ("on-the-fly OPCODE (0x%02X) re-programmed, op-pos=%d\n", opcode, oppos);
|
||||||
return oppos;
|
return oppos;
|
||||||
@ -357,7 +357,7 @@ static int generate_opcodes(OPCODES * op)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int program_opcodes(OPCODES * op)
|
static int program_opcodes(OPCODES *op, int enable_undo)
|
||||||
{
|
{
|
||||||
uint8_t a;
|
uint8_t a;
|
||||||
uint16_t preop, optype;
|
uint16_t preop, optype;
|
||||||
@ -391,16 +391,30 @@ int program_opcodes(OPCODES * op)
|
|||||||
switch (spi_controller) {
|
switch (spi_controller) {
|
||||||
case SPI_CONTROLLER_ICH7:
|
case SPI_CONTROLLER_ICH7:
|
||||||
case SPI_CONTROLLER_VIA:
|
case SPI_CONTROLLER_VIA:
|
||||||
REGWRITE16(ICH7_REG_PREOP, preop);
|
/* Register undo only for enable_undo=1, i.e. first call. */
|
||||||
REGWRITE16(ICH7_REG_OPTYPE, optype);
|
if (enable_undo) {
|
||||||
REGWRITE32(ICH7_REG_OPMENU, opmenu[0]);
|
rmmio_valw(ich_spibar + ICH7_REG_PREOP);
|
||||||
REGWRITE32(ICH7_REG_OPMENU + 4, opmenu[1]);
|
rmmio_valw(ich_spibar + ICH7_REG_OPTYPE);
|
||||||
|
rmmio_vall(ich_spibar + ICH7_REG_OPMENU);
|
||||||
|
rmmio_vall(ich_spibar + ICH7_REG_OPMENU + 4);
|
||||||
|
}
|
||||||
|
mmio_writew(preop, ich_spibar + ICH7_REG_PREOP);
|
||||||
|
mmio_writew(optype, ich_spibar + ICH7_REG_OPTYPE);
|
||||||
|
mmio_writel(opmenu[0], ich_spibar + ICH7_REG_OPMENU);
|
||||||
|
mmio_writel(opmenu[1], ich_spibar + ICH7_REG_OPMENU + 4);
|
||||||
break;
|
break;
|
||||||
case SPI_CONTROLLER_ICH9:
|
case SPI_CONTROLLER_ICH9:
|
||||||
REGWRITE16(ICH9_REG_PREOP, preop);
|
/* Register undo only for enable_undo=1, i.e. first call. */
|
||||||
REGWRITE16(ICH9_REG_OPTYPE, optype);
|
if (enable_undo) {
|
||||||
REGWRITE32(ICH9_REG_OPMENU, opmenu[0]);
|
rmmio_valw(ich_spibar + ICH9_REG_PREOP);
|
||||||
REGWRITE32(ICH9_REG_OPMENU + 4, opmenu[1]);
|
rmmio_valw(ich_spibar + ICH9_REG_OPTYPE);
|
||||||
|
rmmio_vall(ich_spibar + ICH9_REG_OPMENU);
|
||||||
|
rmmio_vall(ich_spibar + ICH9_REG_OPMENU + 4);
|
||||||
|
}
|
||||||
|
mmio_writew(preop, ich_spibar + ICH9_REG_PREOP);
|
||||||
|
mmio_writew(optype, ich_spibar + ICH9_REG_OPTYPE);
|
||||||
|
mmio_writel(opmenu[0], ich_spibar + ICH9_REG_OPMENU);
|
||||||
|
mmio_writel(opmenu[1], ich_spibar + ICH9_REG_OPMENU + 4);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
msg_perr("%s: unsupported chipset\n", __func__);
|
msg_perr("%s: unsupported chipset\n", __func__);
|
||||||
@ -426,9 +440,11 @@ void ich_set_bbar(uint32_t minaddr)
|
|||||||
msg_pdbg("Reserved bits in BBAR not zero: 0x%04x",
|
msg_pdbg("Reserved bits in BBAR not zero: 0x%04x",
|
||||||
ichspi_bbar);
|
ichspi_bbar);
|
||||||
ichspi_bbar |= minaddr;
|
ichspi_bbar |= minaddr;
|
||||||
mmio_writel(ichspi_bbar, ich_spibar + 0x50);
|
rmmio_writel(ichspi_bbar, ich_spibar + 0x50);
|
||||||
ichspi_bbar = mmio_readl(ich_spibar + 0x50);
|
ichspi_bbar = mmio_readl(ich_spibar + 0x50);
|
||||||
/* We don't have any option except complaining. */
|
/* We don't have any option except complaining. And if the write
|
||||||
|
* failed, the restore will fail as well, so no problem there.
|
||||||
|
*/
|
||||||
if (ichspi_bbar != minaddr)
|
if (ichspi_bbar != minaddr)
|
||||||
msg_perr("Setting BBAR failed!\n");
|
msg_perr("Setting BBAR failed!\n");
|
||||||
break;
|
break;
|
||||||
@ -438,9 +454,11 @@ void ich_set_bbar(uint32_t minaddr)
|
|||||||
msg_pdbg("Reserved bits in BBAR not zero: 0x%04x",
|
msg_pdbg("Reserved bits in BBAR not zero: 0x%04x",
|
||||||
ichspi_bbar);
|
ichspi_bbar);
|
||||||
ichspi_bbar |= minaddr;
|
ichspi_bbar |= minaddr;
|
||||||
mmio_writel(ichspi_bbar, ich_spibar + 0xA0);
|
rmmio_writel(ichspi_bbar, ich_spibar + 0xA0);
|
||||||
ichspi_bbar = mmio_readl(ich_spibar + 0xA0);
|
ichspi_bbar = mmio_readl(ich_spibar + 0xA0);
|
||||||
/* We don't have any option except complaining. */
|
/* We don't have any option except complaining. And if the write
|
||||||
|
* failed, the restore will fail as well, so no problem there.
|
||||||
|
*/
|
||||||
if (ichspi_bbar != minaddr)
|
if (ichspi_bbar != minaddr)
|
||||||
msg_perr("Setting BBAR failed!\n");
|
msg_perr("Setting BBAR failed!\n");
|
||||||
break;
|
break;
|
||||||
@ -470,7 +488,7 @@ static int ich_init_opcodes(void)
|
|||||||
} else {
|
} else {
|
||||||
msg_pdbg("Programming OPCODES... ");
|
msg_pdbg("Programming OPCODES... ");
|
||||||
curopcodes_done = &O_ST_M25P;
|
curopcodes_done = &O_ST_M25P;
|
||||||
rc = program_opcodes(curopcodes_done);
|
rc = program_opcodes(curopcodes_done, 1);
|
||||||
/* Technically not part of opcode init, but it allows opcodes
|
/* Technically not part of opcode init, but it allows opcodes
|
||||||
* to run without transaction errors by setting the lowest
|
* to run without transaction errors by setting the lowest
|
||||||
* allowed address to zero.
|
* allowed address to zero.
|
||||||
|
@ -148,6 +148,11 @@ int nicintel_spi_init(void)
|
|||||||
|
|
||||||
nicintel_spibar = physmap("Intel Gigabit NIC w/ SPI flash",
|
nicintel_spibar = physmap("Intel Gigabit NIC w/ SPI flash",
|
||||||
io_base_addr, 4096);
|
io_base_addr, 4096);
|
||||||
|
/* Automatic restore of EECD on shutdown is not possible because EECD
|
||||||
|
* does not only contain FLASH_WRITES_DISABLED|FLASH_WRITES_ENABLED,
|
||||||
|
* but other bits with side effects as well. Those other bits must be
|
||||||
|
* left untouched.
|
||||||
|
*/
|
||||||
tmp = pci_mmio_readl(nicintel_spibar + EECD);
|
tmp = pci_mmio_readl(nicintel_spibar + EECD);
|
||||||
tmp &= ~FLASH_WRITES_DISABLED;
|
tmp &= ~FLASH_WRITES_DISABLED;
|
||||||
tmp |= FLASH_WRITES_ENABLED;
|
tmp |= FLASH_WRITES_ENABLED;
|
||||||
@ -167,6 +172,9 @@ int nicintel_spi_shutdown(void)
|
|||||||
{
|
{
|
||||||
uint32_t tmp;
|
uint32_t tmp;
|
||||||
|
|
||||||
|
/* Disable writes manually. See the comment about EECD in
|
||||||
|
* nicintel_spi_init() for details.
|
||||||
|
*/
|
||||||
tmp = pci_mmio_readl(nicintel_spibar + EECD);
|
tmp = pci_mmio_readl(nicintel_spibar + EECD);
|
||||||
tmp &= ~FLASH_WRITES_ENABLED;
|
tmp &= ~FLASH_WRITES_ENABLED;
|
||||||
tmp |= FLASH_WRITES_DISABLED;
|
tmp |= FLASH_WRITES_DISABLED;
|
||||||
|
12
programmer.h
12
programmer.h
@ -316,6 +316,18 @@ uint32_t mmio_le_readl(void *addr);
|
|||||||
#define pci_mmio_readb mmio_le_readb
|
#define pci_mmio_readb mmio_le_readb
|
||||||
#define pci_mmio_readw mmio_le_readw
|
#define pci_mmio_readw mmio_le_readw
|
||||||
#define pci_mmio_readl mmio_le_readl
|
#define pci_mmio_readl mmio_le_readl
|
||||||
|
void rmmio_writeb(uint8_t val, void *addr);
|
||||||
|
void rmmio_writew(uint16_t val, void *addr);
|
||||||
|
void rmmio_writel(uint32_t val, void *addr);
|
||||||
|
void rmmio_le_writeb(uint8_t val, void *addr);
|
||||||
|
void rmmio_le_writew(uint16_t val, void *addr);
|
||||||
|
void rmmio_le_writel(uint32_t val, void *addr);
|
||||||
|
#define pci_rmmio_writeb rmmio_le_writeb
|
||||||
|
#define pci_rmmio_writew rmmio_le_writew
|
||||||
|
#define pci_rmmio_writel rmmio_le_writel
|
||||||
|
void rmmio_valb(void *addr);
|
||||||
|
void rmmio_valw(void *addr);
|
||||||
|
void rmmio_vall(void *addr);
|
||||||
|
|
||||||
/* programmer.c */
|
/* programmer.c */
|
||||||
int noop_shutdown(void);
|
int noop_shutdown(void);
|
||||||
|
6
satamv.c
6
satamv.c
@ -102,8 +102,7 @@ int satamv_init(void)
|
|||||||
msg_pspew("BAR2Sz=0x%01x\n", (tmp >> 19) & 0x7);
|
msg_pspew("BAR2Sz=0x%01x\n", (tmp >> 19) & 0x7);
|
||||||
tmp &= 0xffffffc0;
|
tmp &= 0xffffffc0;
|
||||||
tmp |= 0x0000001f;
|
tmp |= 0x0000001f;
|
||||||
/* FIXME: This needs to be an auto-reversible write. */
|
pci_rmmio_writel(tmp, mv_bar + PCI_BAR2_CONTROL);
|
||||||
pci_mmio_writel(tmp, mv_bar + PCI_BAR2_CONTROL);
|
|
||||||
|
|
||||||
/* Enable flash: GPIO Port Control Register 0x104f0 */
|
/* Enable flash: GPIO Port Control Register 0x104f0 */
|
||||||
tmp = pci_mmio_readl(mv_bar + GPIO_PORT_CONTROL);
|
tmp = pci_mmio_readl(mv_bar + GPIO_PORT_CONTROL);
|
||||||
@ -114,8 +113,7 @@ int satamv_init(void)
|
|||||||
"values!\n");
|
"values!\n");
|
||||||
tmp &= 0xfffffffc;
|
tmp &= 0xfffffffc;
|
||||||
tmp |= 0x2;
|
tmp |= 0x2;
|
||||||
/* FIXME: This needs to be an auto-reversible write. */
|
pci_rmmio_writel(tmp, mv_bar + GPIO_PORT_CONTROL);
|
||||||
pci_mmio_writel(tmp, mv_bar + GPIO_PORT_CONTROL);
|
|
||||||
|
|
||||||
/* Get I/O BAR location. */
|
/* Get I/O BAR location. */
|
||||||
tmp = pci_read_long(pcidev_dev, PCI_BASE_ADDRESS_2) &
|
tmp = pci_read_long(pcidev_dev, PCI_BASE_ADDRESS_2) &
|
||||||
|
Loading…
x
Reference in New Issue
Block a user