mirror of
				https://review.coreboot.org/flashrom.git
				synced 2025-10-31 05:10:41 +01: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:
		
							
								
								
									
										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) & | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Carl-Daniel Hailfinger
					Carl-Daniel Hailfinger