Changeset 1477


Ignore:
Timestamp:
12/20/11 02:54:19 (5 months ago)
Author:
hailfinger
Message:

Speed up dediprog SPI page writes

All chips which use spi_chip_write_256 should be written at native
speed. Chips using spi_chip_write_1 or spi_chip_write_aai will
still be slow.

Thanks to Steven A. Falco for testing with a ST/Numonyx M25P16.
Thanks to David Hendricks for testing with a Winbond W25Q64.

Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@…>
Acked-by: Steven A. Falco <sfalco@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/dediprog.c

    r1474 r1477  
    300300} 
    301301 
     302/* Bulk write interface, will read multiple page_size byte chunks aligned to page_size bytes. 
     303 * @start       start address 
     304 * @len         length 
     305 * @return      0 on success, 1 on failure 
     306 */ 
     307static int dediprog_spi_bulk_write(struct flashctx *flash, uint8_t *buf, 
     308                                   unsigned int start, unsigned int len) 
     309{ 
     310        int ret; 
     311        unsigned int i; 
     312        /* USB transfer size must be 512, other sizes will NOT work at all. 
     313         * chunksize is the real data size per USB bulk transfer. The remaining 
     314         * space in a USB bulk transfer must be filled with 0xff padding. 
     315         */ 
     316        const unsigned int chunksize = flash->page_size; 
     317        const unsigned int count = len / chunksize; 
     318        const char count_and_chunk[] = {count & 0xff, 
     319                                        (count >> 8) & 0xff, 
     320                                        chunksize & 0xff, 
     321                                        (chunksize >> 8) & 0xff}; 
     322        char usbbuf[512]; 
     323 
     324        if ((start % chunksize) || (len % chunksize)) { 
     325                msg_perr("%s: Unaligned start=%i, len=%i! Please report a bug " 
     326                         "at flashrom@flashrom.org\n", __func__, start, len); 
     327                return 1; 
     328        } 
     329 
     330        /* No idea if the hardware can handle empty writes, so chicken out. */ 
     331        if (!len) 
     332                return 0; 
     333        /* Command Write SPI Bulk. No idea which write command is used on the 
     334         * SPI side. 
     335         */ 
     336        ret = usb_control_msg(dediprog_handle, 0x42, 0x30, start % 0x10000, 
     337                              start / 0x10000, (char *)count_and_chunk, 
     338                              sizeof(count_and_chunk), DEFAULT_TIMEOUT); 
     339        if (ret != sizeof(count_and_chunk)) { 
     340                msg_perr("Command Write SPI Bulk failed, %i %s!\n", ret, 
     341                         usb_strerror()); 
     342                return 1; 
     343        } 
     344 
     345        for (i = 0; i < count; i++) { 
     346                memset(usbbuf, 0xff, sizeof(usbbuf)); 
     347                memcpy(usbbuf, buf + i * chunksize, chunksize); 
     348                ret = usb_bulk_write(dediprog_handle, dediprog_endpoint, 
     349                                    usbbuf, 512, 
     350                                    DEFAULT_TIMEOUT); 
     351                if (ret != 512) { 
     352                        msg_perr("SPI bulk write failed, expected %i, got %i " 
     353                                 "%s!\n", 512, ret, usb_strerror()); 
     354                        return 1; 
     355                } 
     356        } 
     357 
     358        return 0; 
     359} 
     360 
    302361static int dediprog_spi_write_256(struct flashctx *flash, uint8_t *buf, 
    303362                                  unsigned int start, unsigned int len) 
    304363{ 
    305364        int ret; 
     365        const unsigned int chunksize = flash->page_size; 
     366        unsigned int residue = start % chunksize ? chunksize - start % chunksize : 0; 
     367        unsigned int bulklen; 
    306368 
    307369        dediprog_set_leds(PASS_OFF|BUSY_ON|ERROR_OFF); 
    308370 
    309         /* No idea about the real limit. Maybe 12, maybe more, maybe less. */ 
    310         ret = spi_write_chunked(flash, buf, start, len, 12); 
    311  
    312         if (ret) 
     371        if (residue) { 
     372                msg_pdbg("Slow write for partial block from 0x%x, length 0x%x\n", 
     373                         start, residue); 
     374                /* No idea about the real limit. Maybe 12, maybe more. */ 
     375                ret = spi_write_chunked(flash, buf, start, residue, 12); 
     376                if (ret) { 
     377                        dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON); 
     378                        return ret; 
     379                } 
     380        } 
     381 
     382        /* Round down. */ 
     383        bulklen = (len - residue) / chunksize * chunksize; 
     384        ret = dediprog_spi_bulk_write(flash, buf + residue, start + residue, 
     385                                     bulklen); 
     386        if (ret) { 
    313387                dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON); 
    314         else 
    315                 dediprog_set_leds(PASS_ON|BUSY_OFF|ERROR_OFF); 
    316  
    317         return ret; 
     388                return ret; 
     389        } 
     390 
     391        len -= residue + bulklen; 
     392        if (len) { 
     393                msg_pdbg("Slow write for partial block from 0x%x, length 0x%x\n", 
     394                         start, len); 
     395                ret = spi_write_chunked(flash, buf + residue + bulklen, 
     396                                        start + residue + bulklen, len, 12); 
     397                if (ret) { 
     398                        dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON); 
     399                        return ret; 
     400                } 
     401        } 
     402 
     403        dediprog_set_leds(PASS_ON|BUSY_OFF|ERROR_OFF); 
     404        return 0; 
    318405} 
    319406 
     
    491578        if (ret != 0x1) { 
    492579                msg_perr("Command F failed (%s)!\n", usb_strerror()); 
     580                return 1; 
     581        } 
     582        return 0; 
     583} 
     584 
     585/* Start/stop blinking? 
     586 * Present in eng_detect_blink.log with firmware 3.1.8 
     587 * Preceded by Command J 
     588 */ 
     589static int dediprog_command_g(void) 
     590{ 
     591        int ret; 
     592 
     593        ret = usb_control_msg(dediprog_handle, 0x42, 0x07, 0x09, 0x03, NULL, 0x0, DEFAULT_TIMEOUT); 
     594        if (ret != 0x0) { 
     595                msg_perr("Command G failed (%s)!\n", usb_strerror()); 
     596                return 1; 
     597        } 
     598        return 0; 
     599} 
     600 
     601/* Something. 
     602 * Present in all logs with firmware 5.1.5 
     603 * Always preceded by Command Receive Device String 
     604 * Always followed by Command Set SPI Voltage nonzero 
     605 */ 
     606static int dediprog_command_h(void) 
     607{ 
     608        int ret; 
     609 
     610        ret = usb_control_msg(dediprog_handle, 0x42, 0x07, 0x09, 0x05, NULL, 0x0, DEFAULT_TIMEOUT); 
     611        if (ret != 0x0) { 
     612                msg_perr("Command H failed (%s)!\n", usb_strerror()); 
     613                return 1; 
     614        } 
     615        return 0; 
     616} 
     617 
     618/* Shutdown for firmware 5.x? 
     619 * Present in all logs with firmware 5.1.5 
     620 * Often preceded by a SPI operation (Command Read SPI Bulk or Receive SPI) 
     621 * Always followed by Command Set SPI Voltage 0x0000 
     622 */ 
     623static int dediprog_command_i(void) 
     624{ 
     625        int ret; 
     626 
     627        ret = usb_control_msg(dediprog_handle, 0x42, 0x07, 0x09, 0x06, NULL, 0x0, DEFAULT_TIMEOUT); 
     628        if (ret != 0x0) { 
     629                msg_perr("Command I failed (%s)!\n", usb_strerror()); 
     630                return 1; 
     631        } 
     632        return 0; 
     633} 
     634 
     635/* Start/stop blinking? 
     636 * Present in all logs with firmware 5.1.5 
     637 * Always preceded by Command Receive Device String on 5.1.5 
     638 * Always followed by Command Set SPI Voltage nonzero on 5.1.5 
     639 * Present in eng_detect_blink.log with firmware 3.1.8 
     640 * Preceded by Command B in eng_detect_blink.log 
     641 * Followed by Command G in eng_detect_blink.log 
     642 */ 
     643static int dediprog_command_j(void) 
     644{ 
     645        int ret; 
     646 
     647        ret = usb_control_msg(dediprog_handle, 0x42, 0x07, 0x09, 0x07, NULL, 0x0, DEFAULT_TIMEOUT); 
     648        if (ret != 0x0) { 
     649                msg_perr("Command J failed (%s)!\n", usb_strerror()); 
    493650                return 1; 
    494651        } 
     
    559716        msg_pspew("%s\n", __func__); 
    560717 
     718#if 0 
     719        /* Shutdown on firmware 5.x */ 
     720        if (dediprog_firmwareversion == 5) 
     721                if (dediprog_command_i()) 
     722                        return 1; 
     723#endif 
     724 
    561725        /* URB 28. Command Set SPI Voltage to 0. */ 
    562726        if (dediprog_set_spi_voltage(0x0)) 
Note: See TracChangeset for help on using the changeset viewer.