mirror of
				https://review.coreboot.org/flashrom.git
				synced 2025-10-31 05:10:41 +01:00 
			
		
		
		
	Implement on-the-fly reprogramming of the ICH SPI OPCODE table
Corresponding to flashrom svn r1193. Signed-off-by: Helge Wagner <helge.wagner@ge.com> Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
This commit is contained in:
		 Helge Wagner
					Helge Wagner
				
			
				
					committed by
					
						 Carl-Daniel Hailfinger
						Carl-Daniel Hailfinger
					
				
			
			
				
	
			
			
			 Carl-Daniel Hailfinger
						Carl-Daniel Hailfinger
					
				
			
						parent
						
							17da61ea32
						
					
				
				
					commit
					738e252112
				
			
							
								
								
									
										99
									
								
								ichspi.c
									
									
									
									
									
								
							
							
						
						
									
										99
									
								
								ichspi.c
									
									
									
									
									
								
							| @@ -30,6 +30,7 @@ | |||||||
|  * ST M25P32 already tested |  * ST M25P32 already tested | ||||||
|  * ST M25P64 |  * ST M25P64 | ||||||
|  * AT 25DF321 already tested |  * AT 25DF321 already tested | ||||||
|  |  * ... and many more SPI flash devices | ||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| @@ -197,8 +198,76 @@ static OPCODES O_ST_M25P = { | |||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | /* List of opcodes with their corresponding spi_type | ||||||
|  |  * It is used to reprogram the chipset OPCODE table on-the-fly if an opcode | ||||||
|  |  * is needed which is currently not in the chipset OPCODE table | ||||||
|  |  */ | ||||||
|  | static OPCODE POSSIBLE_OPCODES[] = { | ||||||
|  | 	 {JEDEC_BYTE_PROGRAM, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0},	// Write Byte | ||||||
|  | 	 {JEDEC_READ, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0},	// Read Data | ||||||
|  | 	 {JEDEC_BE_D8, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0},	// Erase Sector | ||||||
|  | 	 {JEDEC_RDSR, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0},	// Read Device Status Reg | ||||||
|  | 	 {JEDEC_REMS, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0},	// Read Electronic Manufacturer Signature | ||||||
|  | 	 {JEDEC_WRSR, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0},	// Write Status Register | ||||||
|  | 	 {JEDEC_RDID, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0},	// Read JDEC ID | ||||||
|  | 	 {JEDEC_CE_C7, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0},	// Bulk erase | ||||||
|  | 	 {JEDEC_SE, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0},	// Sector erase | ||||||
|  | 	 {JEDEC_BE_52, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0},	// Block erase | ||||||
|  | 	 {JEDEC_AAI_WORD_PROGRAM, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0},	// Auto Address Increment | ||||||
|  | }; | ||||||
|  |  | ||||||
| static OPCODES O_EXISTING = {}; | static OPCODES O_EXISTING = {}; | ||||||
|  |  | ||||||
|  | static uint8_t lookup_spi_type(uint8_t opcode) | ||||||
|  | { | ||||||
|  | 	int a; | ||||||
|  |  | ||||||
|  | 	for (a = 0; a < sizeof(POSSIBLE_OPCODES)/sizeof(POSSIBLE_OPCODES[0]); a++) { | ||||||
|  | 		if (POSSIBLE_OPCODES[a].opcode == opcode) | ||||||
|  | 			return POSSIBLE_OPCODES[a].spi_type; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return 0xFF; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int reprogram_opcode_on_the_fly(uint8_t opcode, unsigned int writecnt, unsigned int readcnt) | ||||||
|  | { | ||||||
|  | 	uint8_t spi_type; | ||||||
|  |  | ||||||
|  | 	spi_type = lookup_spi_type(opcode); | ||||||
|  | 	if (spi_type > 3) { | ||||||
|  | 		/* Try to guess spi type from read/write sizes. | ||||||
|  | 		 * The following valid writecnt/readcnt combinations exist: | ||||||
|  | 		 * writecnt  = 4, readcnt >= 0 | ||||||
|  | 		 * writecnt  = 1, readcnt >= 0 | ||||||
|  | 		 * writecnt >= 4, readcnt  = 0 | ||||||
|  | 		 * writecnt >= 1, readcnt  = 0 | ||||||
|  | 		 * writecnt >= 1 is guaranteed for all commands. | ||||||
|  | 		 */ | ||||||
|  | 		if (readcnt == 0) | ||||||
|  | 			/* if readcnt=0 and writecount >= 4, we don't know if it is WRITE_NO_ADDRESS | ||||||
|  | 			 * or WRITE_WITH_ADDRESS. But if we use WRITE_NO_ADDRESS and the first 3 data | ||||||
|  | 			 * bytes are actual the address, they go to the bus anyhow | ||||||
|  | 			 */ | ||||||
|  | 			spi_type = SPI_OPCODE_TYPE_WRITE_NO_ADDRESS; | ||||||
|  | 		else if (writecnt == 1) // and readcnt is > 0 | ||||||
|  | 			spi_type = SPI_OPCODE_TYPE_READ_NO_ADDRESS; | ||||||
|  | 		else if (writecnt == 4) // and readcnt is > 0 | ||||||
|  | 			spi_type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS; | ||||||
|  | 		// else we have an invalid case, will be handled below | ||||||
|  | 	} | ||||||
|  | 	if (spi_type <= 3) { | ||||||
|  | 		int oppos=2;	// use original JEDEC_BE_D8 offset | ||||||
|  | 		curopcodes->opcode[oppos].opcode = opcode; | ||||||
|  | 		curopcodes->opcode[oppos].spi_type = spi_type; | ||||||
|  | 		program_opcodes(curopcodes); | ||||||
|  | 		oppos = find_opcode(curopcodes, opcode); | ||||||
|  | 		msg_pdbg ("on-the-fly OPCODE (0x%02X) re-programmed, op-pos=%d\n", opcode, oppos); | ||||||
|  | 		return oppos; | ||||||
|  | 	} | ||||||
|  | 	return -1; | ||||||
|  | } | ||||||
|  |  | ||||||
| static int find_opcode(OPCODES *op, uint8_t opcode) | static int find_opcode(OPCODES *op, uint8_t opcode) | ||||||
| { | { | ||||||
| 	int a; | 	int a; | ||||||
| @@ -710,11 +779,12 @@ int ich_spi_send_command(unsigned int writecnt, unsigned int readcnt, | |||||||
| 	/* find cmd in opcodes-table */ | 	/* find cmd in opcodes-table */ | ||||||
| 	opcode_index = find_opcode(curopcodes, cmd); | 	opcode_index = find_opcode(curopcodes, cmd); | ||||||
| 	if (opcode_index == -1) { | 	if (opcode_index == -1) { | ||||||
| 		/* FIXME: Reprogram opcodes if possible. Autodetect type of | 		if (!ichspi_lock) | ||||||
| 		 * opcode by checking readcnt/writecnt. | 			opcode_index = reprogram_opcode_on_the_fly(cmd, writecnt, readcnt); | ||||||
| 		 */ | 		if (opcode_index == -1) { | ||||||
| 		msg_pdbg("Invalid OPCODE 0x%02x\n", cmd); | 			msg_pdbg("Invalid OPCODE 0x%02x\n", cmd); | ||||||
| 		return SPI_INVALID_OPCODE; | 			return SPI_INVALID_OPCODE; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	opcode = &(curopcodes->opcode[opcode_index]); | 	opcode = &(curopcodes->opcode[opcode_index]); | ||||||
| @@ -827,21 +897,10 @@ int ich_spi_send_multicommand(struct spi_command *cmds) | |||||||
| 				 * No need to bother with fixups. | 				 * No need to bother with fixups. | ||||||
| 				 */ | 				 */ | ||||||
| 				if (!ichspi_lock) { | 				if (!ichspi_lock) { | ||||||
| 					msg_pdbg("%s: FIXME: Add on-the-fly" | 					oppos = reprogram_opcode_on_the_fly((cmds + 1)->writearr[0], (cmds + 1)->writecnt, (cmds + 1)->readcnt); | ||||||
| 						     " reprogramming of the " | 					if (oppos == -1) | ||||||
| 						     "chipset opcode list.\n", | 						continue; | ||||||
| 						     __func__); | 					curopcodes->opcode[oppos].atomic = preoppos + 1; | ||||||
| 				 	/* FIXME: Reprogram opcode menu. |  | ||||||
| 					 * Find a less-useful opcode, replace it |  | ||||||
| 					 * with the wanted opcode, detect optype |  | ||||||
| 					 * and reprogram the opcode menu. |  | ||||||
| 					 * Update oppos so the next if-statement |  | ||||||
| 					 * can do something useful. |  | ||||||
| 					 */ |  | ||||||
| 					//curopcodes.opcode[lessusefulindex] = (cmds + 1)->writearr[0]); |  | ||||||
| 					//update_optypes(curopcodes); |  | ||||||
| 					//program_opcodes(curopcodes); |  | ||||||
| 					//oppos = find_opcode(curopcodes, (cmds + 1)->writearr[0]); |  | ||||||
| 					continue; | 					continue; | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user