From patchwork Thu Oct 10 10:13:11 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: RFC: high level operations support and an example implementation in serprog Date: Thu, 10 Oct 2013 10:13:11 -0000 From: Urja Rannikko X-Patchwork-Id: 4077 Message-Id: To: flashrom@flashrom.org Hi, Add mechanism to allow the external programmer to take over a higher level operation than previously. As an useful first example jedec toggle ready on serprog is included. Signed-off-by: Urja Rannikko ----- I dont have much to say about this, except that there is one more patch following this to make proper use of the speed improvement this allows to write_jedec_1, and that serprog LPC support still depends on http://patchwork.coreboot.org/patch/3465/ or something similar. What do you think? Oh and there is an example of the device code for this added serprog operation here: https://github.com/urjaman/frser-atmega644 Index: flash.h =================================================================== --- flash.h (revision 1757) +++ flash.h (working copy) @@ -29,6 +29,7 @@ #include #include #include +#include #ifdef _WIN32 #include #undef min @@ -40,6 +41,7 @@ /* Error codes */ #define ERROR_OOM -100 #define TIMEOUT_ERROR -101 +struct flashctx; /* TODO: check using code for correct usage of types */ typedef uintptr_t chipaddr; @@ -53,10 +55,15 @@ #define PRIxCHIPADDR "06"PRIx32 #define PRIuCHIPSIZE PRIu32 +enum highlevel_cmd { + HL_ID_TOGGLE_READY_JEDEC = 1 +}; + int register_shutdown(int (*function) (void *data), void *data); void *programmer_map_flash_region(const char *descr, uintptr_t phys_addr, size_t len); void programmer_unmap_flash_region(void *virt_addr, size_t len); void programmer_delay(int usecs); +int programmer_highlevel(const struct flashctx *flash, enum highlevel_cmd id, ...); #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) @@ -120,7 +127,6 @@ #define FEATURE_OTP (1 << 8) #define FEATURE_QPI (1 << 9) -struct flashctx; typedef int (erasefunc_t)(struct flashctx *flash, unsigned int addr, unsigned int blocklen); struct flashchip { Index: jedec.c =================================================================== --- jedec.c (revision 1757) +++ jedec.c (working copy) @@ -22,6 +22,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #include "flash.h" #define MAX_REFLASH_TRIES 0x10 @@ -43,6 +44,8 @@ unsigned int i = 0; uint8_t tmp1, tmp2; + if (programmer_highlevel(flash, HL_ID_TOGGLE_READY_JEDEC, dst, delay)) return; + tmp1 = chip_readb(flash, dst) & 0x40; while (i++ < 0xFFFFFFF) { Index: serprog.c =================================================================== --- serprog.c (revision 1757) +++ serprog.c (working copy) @@ -886,6 +886,47 @@ sp_prev_was_write = 0; } +int serprog_highlevel(const struct flashctx *flash, enum highlevel_cmd id, va_list ap) +{ + switch (id) { + default: /* Any new ids, by default not handled. */ + return 0; + case HL_ID_TOGGLE_READY_JEDEC: + if (sp_check_commandavail(S_CMD_O_TOGGLERDY)) { + + uint8_t buf[7]; + if ((sp_max_write_n) && (sp_write_n_bytes)) + sp_pass_writen(); + sp_check_opbuf_usage(8); + unsigned int addr = va_arg(ap,unsigned int); + int usecs = va_arg(ap,int); + buf[0] = ((usecs >> 0) & 0xFF); + buf[1] = ((usecs >> 8) & 0xFF); + buf[2] = ((usecs >> 16) & 0xFF); + buf[3] = ((usecs >> 24) & 0xFF); + buf[4] = ((addr >> 0) & 0xFF); + buf[5] = ((addr >> 8) & 0xFF); + buf[6] = ((addr >> 16) & 0xFF); + sp_stream_buffer_op(S_CMD_O_TOGGLERDY, 7, buf); + sp_opbuf_usage += 8; + sp_prev_was_write = 0; + msg_pspew(MSGHEADER "highlevel toggle ready dly=%d addr=0x%x\n", + usecs,addr); + if (sp_opbuf_usage > (sp_device_opbuf_size/3)) { + /* Since this was previously a natural exec point, + execute if we have more than 33% of opbuf in use. */ + /* FIXME: Return error. */ + sp_execute_opbuf_noflush(); + } + return 1; /* Handled by programmer. */ + } + return 0; + + } + /* If you accidentally fall here, not handled. */ + return 0; +} + static int serprog_spi_send_command(struct flashctx *flash, unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, Index: serprog.h =================================================================== --- serprog.h (revision 1757) +++ serprog.h (working copy) @@ -23,3 +23,4 @@ #define S_CMD_O_SPIOP 0x13 /* Perform SPI operation. */ #define S_CMD_S_SPI_FREQ 0x14 /* Set SPI clock frequency */ #define S_CMD_S_PIN_STATE 0x15 /* Enable/disable output drivers */ +#define S_CMD_O_TOGGLERDY 0x16 /* Write to opbuf: Wait Jedec Toggle */ Index: Documentation/serprog-protocol.txt =================================================================== --- Documentation/serprog-protocol.txt (revision 1757) +++ Documentation/serprog-protocol.txt (working copy) @@ -35,6 +35,8 @@ + slen bytes of data 0x14 Set SPI clock frequency in Hz 32-bit requested frequency ACK + 32-bit set frequency / NAK 0x15 Toggle flash chip pin drivers 8-bit (0 disable, else enable) ACK / NAK +0x16 Write to opbuf: Toggle Ready 32-bit delay + 24-bit addr ACK / NAK (NOTE: 8 bytes in opbuf) + JEDEC 0x?? unimplemented command - invalid. Index: flashrom.c =================================================================== --- flashrom.c (revision 1757) +++ flashrom.c (working copy) @@ -194,6 +194,7 @@ .map_flash_region = fallback_map, .unmap_flash_region = fallback_unmap, .delay = serprog_delay, + .highlevel = serprog_highlevel, }, #endif @@ -490,6 +491,17 @@ programmer_table[programmer].delay(usecs); } +int programmer_highlevel(const struct flashctx *flash, enum highlevel_cmd id, ...) +{ + int rv = 0; + va_list ap; + va_start(ap,id); + if (programmer_table[programmer].highlevel) + rv = programmer_table[programmer].highlevel(flash,id,ap); + va_end(ap); + return rv; +} + void map_flash_registers(struct flashctx *flash) { size_t size = flash->chip->total_size * 1024; Index: programmer.h =================================================================== --- programmer.h (revision 1757) +++ programmer.h (working copy) @@ -121,6 +121,8 @@ void (*unmap_flash_region) (void *virt_addr, size_t len); void (*delay) (int usecs); + + int (*highlevel) (const struct flashctx *flash, enum highlevel_cmd id, va_list ap); }; extern const struct programmer_entry programmer_table[]; @@ -655,6 +657,7 @@ #if CONFIG_SERPROG == 1 int serprog_init(void); void serprog_delay(int usecs); +int serprog_highlevel(const struct flashctx *flash, enum highlevel_cmd id, va_list ap); #endif /* serial.c */