This is an automated email from Gerrit. Andreas Bolsch (hyphen0br...@gmail.com) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/3918
-- gerrit commit bc9b8777c3efdd0359076f9849f0bcca42d76693 Author: Andreas Bolsch <hyphen0br...@gmail.com> Date: Wed Dec 21 10:35:58 2016 +0100 Flash driver for QUADSPI interface in various STM32 variants. Changes relative to #3162: - programming in stmqspi now using "target_run_flash_async_algorithm", on STM32F746G-discovery approx. 30% reduction of programming time - write speed up to 100 kByte/s on STM32L476G-discovery - tested with STM32F746G-discovery (128Mbit flash, 3-byte addresses), STM32F769I-discovery (512Mbit flash, 4-byte addresses), and STM32L476G-discovery (128Mbit flash, 3-byte addresses) - suitable cfg for STM32F746G-discovery, STM32F769I-discovery, and STM32L476G-discovery included - additional sanity check regarding flash size vs. FSIZE field - protection now disengaged by default - some LOG messages changed from USER to DEBUG What's left from comments on #3162: - return from within macro Untested: - dual flash mode (sorry, no appropriate hardware available) Requirements: GPIOs must be initialized appropriately, and SPI flash chip be configured to simple spi (aka 1-line) mode and to 4-byte addresses depending on capacity. This is board/chip specific, cf. included cfg files. Note that 'flash write_image' with automatic erase is NOT feasible if huge portion of spi flash is to be rewritten. Sector erase is incredible slow for large capacity flash (one second per sector), so always prefer 'stmqspi mass_erase' when possible. Disappointing: Read/verify is much slower than write :-( Read and verify is not done by stmqspi, however. On STM32L476G-disco 'adapter_khz 4000' allows 100kByte/s write speed successfully, whereas even at 'adapter_khz 2000' st-link crashes instantly on read/verify. Only after power-up reset a reconnect is possible ... Change-Id: Id584afec683d32c26cbb418e92f70623ddaa2f31 Signed-off-by: Andreas Bolsch <hyphen0br...@gmail.com> diff --git a/contrib/loaders/flash/stmqspi.S b/contrib/loaders/flash/stmqspi.S index dd47382..3d91fe5 100644 --- a/contrib/loaders/flash/stmqspi.S +++ b/contrib/loaders/flash/stmqspi.S @@ -1,6 +1,6 @@ /*************************************************************************** - * Copyright (C) 2015 by Andreas Bolsch * + * Copyright (C) 2016 by Andreas Bolsch * * andreas.bol...@mni.thm.de * * * * This program is free software; you can redistribute it and/or modify * @@ -34,14 +34,17 @@ */ /* Params: - * r0 - total count (bytes) + * r0 - total count (bytes), status (out) * r1 - flash page size - * r2 - adress offset into flash + * r2 - address offset into flash * r3 - QSPI io_base + * r8 - fifo start + * r9 - fifo end + 1 + * Clobbered: - * r4 - QSPI DR address - * r5 - ptr into buffer - * r6 - single / dual + * r4 - rp + * r5 - offset of QSPI_DR + * r6 - single 0x0 / dual 0x1 * r7 - tmp */ @@ -49,120 +52,130 @@ .macro wait_busy 0: - ldr r7, [r3, #QSPI_SR] /* load status */ - lsrs r7, r7, #(QSPI_BUSY+1) /* shift BUSY into C */ - bcs 0b /* loop till BUSY cleared */ - movs r7, #(1<<QSPI_TCF) /* TCF bitmask */ - str r7, [r3, #QSPI_FCR] /* clear TCF flag */ - .endm - - .macro wait_fifo -1: - ldr r7, [r3, #QSPI_SR] /* load status */ - lsrs r7, #(QSPI_FTF+1) /* wait for FTF to be set */ - bcc 1b /* if not, then test again */ + ldr r7, [r3, #QSPI_SR] /* load status */ + lsrs r7, r7, #(QSPI_BUSY+1) /* shift BUSY into C */ + bcs 0b /* loop till BUSY cleared */ + movs r7, #(1<<QSPI_TCF) /* TCF bitmask */ + str r7, [r3, #QSPI_FCR] /* clear TCF flag */ .endm start: - subs r0, #1 /* decrement count for DLR */ - subs r1, #1 /* page size mask and for DLR */ - movs r4, r3 /* copy base address */ - adds r4, #QSPI_DR /* QSPI DR address */ - adr r5, buffer /* buffer start address */ - movs r6, #0 /* one byte per default */ - ldr r7, [r3, #QSPI_CR] /* get QSPI CR register */ - lsrs r7, #(QSPI_DUAL_FLASH+1) /* dual bit into carry */ - bcc wip_loop /* skip if single */ - adds r6, #1 /* two bytes for dual */ + subs r0, #1 /* decrement count for DLR */ + subs r1, #1 /* page size mask and for DLR */ + ldr r4, rp /* load rp */ + ldr r6, [r3, #QSPI_CR] /* get QSPI_CR register */ + lsls r6, r6, #(31-QSPI_DUAL_FLASH) /* clear higher order bits */ + lsrs r6, r6, #31 /* DUAL_FLASH bit into bit 0 */ + +abort: + movs r5, #(1<<QSPI_ABORT) /* abort bit mask */ + ldr r7, [r3, #QSPI_CR] /* get QSPI_CR register */ + orrs r7, r5 /* set abort bit */ + str r7, [r3, #QSPI_CR] /* store new CR register */ + movs r5, #QSPI_DR /* load QSPI_DR address offset */ wip_loop: wait_busy - str r6, [r3, #QSPI_DLR] /* one or two bytes */ - ldr r7, ccr_read_status /* CCR for status read */ - str r7, [r3, #QSPI_CCR] /* initiate status read */ - wait_fifo - ldrb r7, [r4, #0] /* get first status register */ - lsrs r7, #(SPIFLASH_WIP+1) /* if first flash busy, */ - bcs wip_loop /* then poll again */ - tst r6, r6 /* dual flash? */ - beq write_enable /* no, then ok */ - wait_fifo - ldrb r7, [r4, #0] /* get second status register */ - lsrs r7, #(SPIFLASH_WIP+1) /* if second flash busy, */ - bcs wip_loop /* then poll again */ + str r6, [r3, #QSPI_DLR] /* one or two (for dual) bytes */ + ldr r7, ccr_read_status /* CCR for status read */ + str r7, [r3, #QSPI_CCR] /* initiate status read */ + ldr r7, [r3, #QSPI_SR] /* delay for fifo startup */ + ldrb r7, [r3, r5] /* get first status register */ + lsrs r7, r7, #(SPIFLASH_WIP+1) /* if first flash busy, */ + bcs abort /* then poll again */ + tst r6, r6 /* dual mode ? */ + beq write_enable /* not dual, then ok */ + ldrb r7, [r3, r5] /* get second status register */ + lsrs r7, r7, #(SPIFLASH_WIP+1) /* if second flash busy, */ + bcs abort /* then poll again */ write_enable: + tst r0, r0 /* test residual count */ + bmi exit /* if negative, then finished */ wait_busy - ldr r7, ccr_write_enable /* CCR for write enable */ - str r7, [r3, #QSPI_CCR] /* initiate write enable */ - -is_enabled: - wait_busy - str r6, [r3, #QSPI_DLR] /* one or two bytes */ - ldr r7, ccr_read_status /* CCR for status read */ - str r7, [r3, #QSPI_CCR] /* initiate status read */ - wait_fifo - ldrb r7, [r4, #0] /* get first status register */ - lsrs r7, #(SPIFLASH_WEL+1) /* if first flash */ - bcc error /* not enabled, then error */ - tst r6, r6 /* dual flash? */ - beq busy_loop /* no, then ok */ - wait_fifo - ldrb r7, [r4, #0] /* get second status register */ - lsrs r7, #(SPIFLASH_WEL+1) /* if second flash */ - bcc error /* not enabled, then error */ - -busy_loop: + ldr r7, ccr_write_enable /* CCR for write enable */ + str r7, [r3, #QSPI_CCR] /* initiate write enable */ wait_busy - cmp r0, r1 /* if count > page size */ - bhi page_write /* then write one page only */ - str r0, [r3, #QSPI_DLR] /* remaining count in DLR register */ - b start_write - -page_write: - str r1, [r3, #QSPI_DLR] /* page size in DLR register */ + str r6, [r3, #QSPI_DLR] /* one or two (for dual) bytes */ + ldr r7, ccr_read_status /* CCR for status read */ + str r7, [r3, #QSPI_CCR] /* initiate status read */ + ldr r7, [r3, #QSPI_SR] /* delay for fifo startup */ + ldrb r7, [r3, r5] /* get first status register */ + lsrs r7, r7, #(SPIFLASH_WEL+1) /* if first flash not */ + bcc error /* write enabled, then error */ + tst r6, r6 /* dual mode ? */ + beq start_write /* not dual, then ok */ + ldrb r7, [r3, r5] /* get second status register */ + lsrs r7, r7, #(SPIFLASH_WEL+1) /* if second flash not */ + bcc error /* write enabled, then error */ start_write: - ldr r7, ccr_page_write /* CCR for page write */ - str r7, [r3, #QSPI_CCR] /* initiate transfer */ - str r2, [r3, #QSPI_AR] /* store SPI start address */ + mov r7, r0 /* get remaining count */ + cmp r0, r1 /* if count <= page size */ + bls write_dlr /* then write all remaining */ + mov r7, r1 /* else exactly one page */ +write_dlr: + str r7, [r3, #QSPI_DLR] /* size-1 in DLR register */ + ldr r7, ccr_page_write /* CCR for page write */ + str r7, [r3, #QSPI_CCR] /* initiate transfer */ + str r2, [r3, #QSPI_AR] /* store SPI start address */ write_loop: - wait_fifo - ldrb r7,[r5, #0] /* load and */ - strb r7,[r4, #0] /* store next byte */ - adds r5, #1 /* increment buffer ptr */ - adds r2, #1 /* increment address */ - subs r0, #1 /* decrement count */ - bmi page_end /* stop if no data left */ - tst r2, r1 /* page end ? */ - bne write_loop /* if not, then next byte */ - + ldr r7, wp /* get wp */ + cmp r7, #0 /* if wp equals 0 */ + beq exit /* then abort */ + cmp r4, r7 /* check if fifo empty */ + beq write_loop /* wait till not empty */ + ldrb r7, [r4, #0] /* read next byte */ + strb r7, [r3, r5] /* write next byte to DR */ + adds r2, #1 /* increment address */ + adds r4, #1 /* increment internal rp */ + cmp r4, r9 /* internal rp beyond end? */ + blo write_loop1 /* if no, the ok */ + mov r4, r8 /* else wrap around */ +write_loop1: + subs r0, #1 /* decrement count */ + bmi page_end /* stop if no data left */ + tst r2, r1 /* page end ? */ + bne write_loop /* if not, then next byte */ page_end: - ldr r7, [r3, #QSPI_SR] /* load status */ - lsrs r7, r7, #(QSPI_TCF+1) /* shift TCF into C */ - bcc page_end /* wait till TCF set */ - movs r0, r0 /* test residual count */ - bpl wip_loop /* if non-negative, then next page */ - adds r0, #1 /* correct count */ - b exit + ldr r7, [r3, #QSPI_SR] /* load status */ + lsrs r7, r7, #(QSPI_TCF+1) /* shift TCF into C */ + bcc page_end /* wait till TCF set */ + adr r7, rp /* get address of rp */ + str r4, [r7, #0] /* store updated rp */ + + movs r7, r1 /* one iteration per byte */ +wait: + subs r7, #1 /* short delay loop */ + bne wait /* before testing WIP flag */ + b wip_loop /* then next page */ error: - movs r0, #0 - subs r0, #1 /* return 0xFFFFFFFF for error */ - + movs r0, #0 /* return 0xFFFFFFFF */ + subs r0, #2 /* for error */ exit: - .align 2 /* align to word, bkpt is 4 words */ - bkpt #0 /* before code end for exit_point */ - .align 2 /* align to word */ + adds r0, #1 /* correct count */ + movs r6, #(1<<QSPI_ABORT) /* abort bit mask */ + ldr r7, [r3, #QSPI_CR] /* get QSPI CR register */ + orrs r7, r6 /* set abort bit */ + str r7, [r3, #QSPI_CR] /* store new CR register */ + + .align 2 /* align to word, bkpt is 4 words */ + bkpt #0 /* before code end for exit_point */ + .align 2 /* align to word */ ccr_read_status: - .space 4 /* QSPI_CCR value for READ_STATUS command */ + .space 4 /* QSPI_CCR value for READ_STATUS command */ ccr_write_enable: - .space 4 /* QSPI_CCR value for WRITE_ENABLE command */ + .space 4 /* QSPI_CCR value for WRITE_ENABLE command */ ccr_page_write: - .space 4 /* QSPI_CCR value for PAGE_WRITE command */ + .space 4 /* QSPI_CCR value for PAGE_WRITE command */ + + .equ wp, . /* wp, uint32_t */ + + .equ rp, wp + 4 /* rp, uint32_t */ -buffer: /* buffer follows right away */ + .equ buffer, rp + 4 /* buffer follows right away */ diff --git a/doc/openocd.texi b/doc/openocd.texi index 06b555b..057587a 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -4920,7 +4920,7 @@ quite board specific (that's why booting from this memory is not possible) and the flash driver infers all parameters from current controller register values. Normal OpenOCD commands like @command{mdw} can be used to display -the flash content, but only after proper controller initialzation. +the flash content, but only after proper controller initialization. @example flash bank $_FLASHNAME stmqspi 0x90000000 0 0 0 $_TARGETNAME diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 6d15755..a8416b6 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -44,6 +44,7 @@ NOR_DRIVERS = \ %D%/spi.c \ %D%/stmsmi.c \ %D%/stmqspi.c \ + %D%/stellaris.c \ %D%/stm32f1x.c \ %D%/stm32f2x.c \ %D%/stm32lx.c \ diff --git a/src/flash/nor/spi.c b/src/flash/nor/spi.c index 6501fbc..48acbc4 100644 --- a/src/flash/nor/spi.c +++ b/src/flash/nor/spi.c @@ -67,6 +67,7 @@ const struct flash_device flash_devices[] = { FLASH_ID("mac 25l1605", 0xd8, 0xc7, 0x001520c2, 0x100, 0x10000, 0x200000), FLASH_ID("mac 25l3205", 0xd8, 0xc7, 0x001620c2, 0x100, 0x10000, 0x400000), FLASH_ID("mac 25l6405", 0xd8, 0xc7, 0x001720c2, 0x100, 0x10000, 0x800000), + FLASH_ID("mac 25l51245", 0xd8, 0xc7, 0x001a20c2, 0x100, 0x10000, 0x4000000), FLASH_ID("micron n25q064", 0xd8, 0xc7, 0x0017ba20, 0x100, 0x10000, 0x800000), FLASH_ID("micron n25q128", 0xd8, 0xc7, 0x0018ba20, 0x100, 0x10000, 0x1000000), FLASH_ID("win w25q80bv", 0xd8, 0xc7, 0x001440ef, 0x100, 0x10000, 0x100000), diff --git a/src/flash/nor/stmqspi.c b/src/flash/nor/stmqspi.c index 234ac15..1883d8b 100644 --- a/src/flash/nor/stmqspi.c +++ b/src/flash/nor/stmqspi.c @@ -166,7 +166,10 @@ struct stmqspi_target { static const struct stmqspi_target target_devices[] = { /* name, device_id, qspi_base, io_base */ - { "stm32l4x6", 0x415, 0x90000000, 0xA0001000 }, + { "stm32l431_433_443", 0x435, 0x90000000, 0xA0001000 }, + { "stm32l4x1_4x5_4x6", 0x415, 0x90000000, 0xA0001000 }, + { "stm32f412", 0x441, 0x90000000, 0xA0001000 }, + { "stm32f413_423", 0x463, 0x90000000, 0xA0001000 }, { "stm32f446", 0x421, 0x90000000, 0xA0001000 }, { "stm32f469_479", 0x434, 0x90000000, 0xA0001000 }, { "stm32f74x_75x", 0x449, 0x90000000, 0xA0001000 }, @@ -291,7 +294,7 @@ static int wait_till_ready(struct flash_bank *bank, int timeout) if ((status & (((1<<SPIFLASH_WIP)<<8) || (1<<SPIFLASH_WIP))) == 0) return ERROR_OK; - alive_sleep(1); + alive_sleep(25); } while (timeval_ms() < endtime); LOG_ERROR("timeout"); @@ -334,6 +337,7 @@ static int qspi_write_enable(struct flash_bank *bank) LOG_ERROR("Cannot enable write to flash2. Status=0x%08" PRIx32, status); return ERROR_FAIL; } + return ERROR_OK; } @@ -344,7 +348,7 @@ COMMAND_HANDLER(stmqspi_handle_mass_erase_command) struct stmqspi_flash_bank *stmqspi_info; struct duration bench; uint32_t io_base, status; - int retval, sector, dual; + int retval, sector; LOG_DEBUG("%s", __func__); @@ -388,21 +392,6 @@ COMMAND_HANDLER(stmqspi_handle_mass_erase_command) if (retval != ERROR_OK) return retval; - dual = (stmqspi_info->dual_mask & (1<<QSPI_DUAL_FLASH)) ? 1 : 0; - - /* Clear block protect bits */ - QSPI_WRITE_REG(QSPI_CCR, QSPI_CCR_WRITE_STATUS); - QSPI_WRITE_REG(QSPI_DLR, dual); - QSPI_WRITE_REG(QSPI_DR, (1<<SPIFLASH_WEL)); - if (dual) - QSPI_WRITE_REG(QSPI_DR, (1<<SPIFLASH_WEL)); - - /* Wait for busy to be cleared */ - QSPI_POLL_BUSY(QSPI_PROBE_TIMEOUT); - - /* clear transmit finished flag */ - QSPI_CLEAR_TCF(); - retval = qspi_write_enable(bank); if (retval != ERROR_OK) return retval; @@ -482,7 +471,7 @@ static int qspi_erase_sector(struct flash_bank *bank, int sector) retval = wait_till_ready(bank, QSPI_MAX_TIMEOUT); /* erasure takes a long time, so some sort of progress message is a good idea */ - LOG_USER("sector %4d erased", sector); + LOG_DEBUG("sector %4d erased", sector); /* Switch to memory mapped mode before return to prompt */ QSPI_SET_MM_MODE(); @@ -532,6 +521,9 @@ static int stmqspi_erase(struct flash_bank *bank, int first, int last) keep_alive(); } + if (retval != ERROR_OK) + LOG_ERROR("Flash sector_erase failed on sector %d", sector); + return retval; } @@ -545,64 +537,134 @@ static int stmqspi_protect(struct flash_bank *bank, int set, return ERROR_OK; } -static int qspi_write_buffer(struct flash_bank *bank, struct working_area *write_algorithm, - const uint32_t code_len, const uint32_t flash_offset, const uint32_t page_size, - uint32_t count, const uint8_t *buffer) +static int qspi_write_block(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) { struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; uint32_t io_base = stmqspi_info->io_base; - struct reg_param reg_params[4]; + struct reg_param reg_params[6]; struct armv7m_algorithm armv7m_info; + struct working_area *write_algorithm; + uint32_t page_size, fifo_start, fifo_size, buffer_size; uint32_t exit_point, remaining; - int retval = ERROR_OK; + int dual, retval = ERROR_OK; LOG_DEBUG("%s: offset=0x%08" PRIx32 " len=0x%08" PRIx32, - __func__, flash_offset, count); + __func__, offset, count); - /* after breakpoint instruction (halfword) one nop (halfword) and - * 3 words follow till end of code, that makes exactly 4 words */ - exit_point = write_algorithm->address + code_len - 4 * sizeof(uint32_t); - target_write_buffer(target, write_algorithm->address + code_len, - count, buffer); + /* see contrib/loaders/flash/stmqspi.S for src */ + static const uint8_t stmqspi_flash_write_code[] = { + 0x01, 0x38, 0x01, 0x39, 0x32, 0x4c, 0x1e, 0x68, 0x76, 0x06, 0xf6, 0x0f, + 0x02, 0x25, 0x1f, 0x68, 0x2f, 0x43, 0x1f, 0x60, 0x20, 0x25, 0x9f, 0x68, + 0xbf, 0x09, 0xfc, 0xd2, 0x02, 0x27, 0xdf, 0x60, 0x1e, 0x61, 0x27, 0x4f, + 0x5f, 0x61, 0x9f, 0x68, 0x5f, 0x5d, 0x7f, 0x08, 0xee, 0xd2, 0x36, 0x42, + 0x02, 0xd0, 0x5f, 0x5d, 0x7f, 0x08, 0xe9, 0xd2, 0x00, 0x42, 0x3a, 0xd4, + 0x9f, 0x68, 0xbf, 0x09, 0xfc, 0xd2, 0x02, 0x27, 0xdf, 0x60, 0x1f, 0x4f, + 0x5f, 0x61, 0x9f, 0x68, 0xbf, 0x09, 0xfc, 0xd2, 0x02, 0x27, 0xdf, 0x60, + 0x1e, 0x61, 0x1a, 0x4f, 0x5f, 0x61, 0x9f, 0x68, 0x5f, 0x5d, 0xbf, 0x08, + 0x25, 0xd3, 0x36, 0x42, 0x02, 0xd0, 0x5f, 0x5d, 0xbf, 0x08, 0x20, 0xd3, + 0x07, 0x46, 0x88, 0x42, 0x00, 0xd9, 0x0f, 0x46, 0x1f, 0x61, 0x14, 0x4f, + 0x5f, 0x61, 0x9a, 0x61, 0x13, 0x4f, 0x00, 0x2f, 0x17, 0xd0, 0xbc, 0x42, + 0xfa, 0xd0, 0x27, 0x78, 0x5f, 0x55, 0x01, 0x32, 0x01, 0x34, 0x4c, 0x45, + 0x00, 0xd3, 0x44, 0x46, 0x01, 0x38, 0x01, 0xd4, 0x0a, 0x42, 0xef, 0xd1, + 0x9f, 0x68, 0xbf, 0x08, 0xfc, 0xd3, 0x0b, 0xa7, 0x3c, 0x60, 0x0f, 0x00, + 0x01, 0x3f, 0xfd, 0xd1, 0xb3, 0xe7, 0x00, 0x20, 0x02, 0x38, 0x01, 0x30, + 0x02, 0x26, 0x1f, 0x68, 0x37, 0x43, 0x1f, 0x60, 0x00, 0xbe, 0xc0, 0x46, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + /* This will overlay the last 3 words of stmqspi_flash_write_code in target */ + uint32_t ccr_buffer[] = { + h_to_le_32(QSPI_CCR_READ_STATUS), + h_to_le_32(QSPI_CCR_WRITE_ENABLE), + h_to_le_32(QSPI_CCR_PAGE_WRITE), + }; - init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* count (in), count (out) */ + /* memory buffer, we assume sectorsize to be a power of 2 times page_size */ + dual = (stmqspi_info->dual_mask & (1<<QSPI_DUAL_FLASH)) ? 1 : 0; + page_size = stmqspi_info->dev->pagesize << dual; + fifo_size = stmqspi_info->dev->sectorsize << dual; + while (buffer_size = sizeof(stmqspi_flash_write_code) + 2 * sizeof(uint32_t) + fifo_size, + target_alloc_working_area_try(target, buffer_size, &write_algorithm) != ERROR_OK) { + fifo_size /= 2; + if (fifo_size < page_size) { + /* we already allocated the writing code, but failed to get a + * buffer, free the algorithm */ + target_free_working_area(target, write_algorithm); + + LOG_WARNING("not enough working area, can't do QSPI page writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + }; + + /* prepare flash write code, excluding ccr_buffer */ + retval = target_write_buffer(target, write_algorithm->address, + sizeof(stmqspi_flash_write_code) - sizeof(ccr_buffer), + stmqspi_flash_write_code); + if (retval != ERROR_OK) + goto err; + + /* prepare QSPI_CCR register values */ + retval = target_write_buffer(target, write_algorithm->address + + sizeof(stmqspi_flash_write_code) - sizeof(ccr_buffer), + sizeof(ccr_buffer), (uint8_t *) ccr_buffer); + if (retval != ERROR_OK) + goto err; + + /* target buffer starts right after flash_write_code, i. e. + * wp and rp are implicitly included in buffer!!! */ + fifo_start = write_algorithm->address + sizeof(stmqspi_flash_write_code) + + 2 * sizeof(uint32_t); + + init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* count (in), status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* page_size */ - init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* offset into flash address */ + init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT); /* offset into flash address */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* QSPI io_base */ + init_reg_param(®_params[4], "r8", 32, PARAM_OUT); /* fifo start */ + init_reg_param(®_params[5], "r9", 32, PARAM_OUT); /* fifo end + 1 */ buf_set_u32(reg_params[0].value, 0, 32, count); buf_set_u32(reg_params[1].value, 0, 32, page_size); - buf_set_u32(reg_params[2].value, 0, 32, flash_offset); + buf_set_u32(reg_params[2].value, 0, 32, offset); buf_set_u32(reg_params[3].value, 0, 32, io_base); + buf_set_u32(reg_params[4].value, 0, 32, fifo_start); + buf_set_u32(reg_params[5].value, 0, 32, fifo_start + fifo_size); armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; - retval = target_start_algorithm(target, 0, NULL, - sizeof(reg_params) / sizeof(struct reg_param), reg_params, - write_algorithm->address, exit_point, &armv7m_info); + /* after breakpoint instruction (halfword) one nop (halfword) and + * 3 words follow till end of code, that makes exactly 4 words */ + exit_point = write_algorithm->address + + sizeof(stmqspi_flash_write_code) - 4 * sizeof(uint32_t); - retval = target_wait_algorithm(target, 0, NULL, - sizeof(reg_params) / sizeof(struct reg_param), reg_params, - exit_point, QSPI_MAX_TIMEOUT, &armv7m_info); + retval = target_run_flash_async_algorithm(target, buffer, count, 1, + 0, NULL, + 6, reg_params, + write_algorithm->address + sizeof(stmqspi_flash_write_code), + fifo_size + 2 * sizeof(uint32_t), + write_algorithm->address, exit_point, + &armv7m_info); remaining = buf_get_u32(reg_params[0].value, 0, 32); if ((retval == ERROR_OK) && remaining) retval = ERROR_FLASH_OPERATION_FAILED; if (retval != ERROR_OK) { + offset = buf_get_u32(reg_params[2].value, 0, 32); LOG_ERROR("flash write failed at address 0x%" PRIx32 ", remaining 0x%" PRIx32, - flash_offset, remaining); - } else { - /* programming takes a long time, so some sort of progress message is a good idea */ - LOG_USER("pages %6d to %6d programmed", flash_offset / page_size, - (flash_offset + count - 1) / page_size); + offset, remaining); } destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); + destroy_reg_param(®_params[4]); + destroy_reg_param(®_params[5]); + +err: + target_free_working_area(target, write_algorithm); /* Switch to memory mapped mode before return to prompt */ QSPI_SET_MM_MODE(); @@ -611,64 +673,31 @@ static int qspi_write_buffer(struct flash_bank *bank, struct working_area *write } static int stmqspi_write(struct flash_bank *bank, const uint8_t *buffer, - uint32_t flash_offset, uint32_t count) + uint32_t offset, uint32_t count) { struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; - struct working_area *write_algorithm; - uint32_t io_base = stmqspi_info->io_base; - uint32_t cur_count, page_size, buffer_size; - int sector; - int dual; - int retval = ERROR_OK; - - /* see contrib/loaders/flash/stmqspi.S for src */ - static const uint8_t stmqspi_flash_write_code[] = { - 0x01, 0x38, 0x01, 0x39, 0x1c, 0x00, 0x20, 0x34, 0x30, 0xa5, 0x00, 0x26, - 0x1f, 0x68, 0xff, 0x09, 0x00, 0xd3, 0x01, 0x36, 0x9f, 0x68, 0xbf, 0x09, - 0xfc, 0xd2, 0x02, 0x27, 0xdf, 0x60, 0x1e, 0x61, 0x27, 0x4f, 0x5f, 0x61, - 0x9f, 0x68, 0xff, 0x08, 0xfc, 0xd3, 0x27, 0x78, 0x7f, 0x08, 0xf1, 0xd2, - 0x36, 0x42, 0x05, 0xd0, 0x9f, 0x68, 0xff, 0x08, 0xfc, 0xd3, 0x27, 0x78, - 0x7f, 0x08, 0xe9, 0xd2, 0x9f, 0x68, 0xbf, 0x09, 0xfc, 0xd2, 0x02, 0x27, - 0xdf, 0x60, 0x1e, 0x4f, 0x5f, 0x61, 0x9f, 0x68, 0xbf, 0x09, 0xfc, 0xd2, - 0x02, 0x27, 0xdf, 0x60, 0x1e, 0x61, 0x19, 0x4f, 0x5f, 0x61, 0x9f, 0x68, - 0xff, 0x08, 0xfc, 0xd3, 0x27, 0x78, 0xbf, 0x08, 0x26, 0xd3, 0x36, 0x42, - 0x05, 0xd0, 0x9f, 0x68, 0xff, 0x08, 0xfc, 0xd3, 0x27, 0x78, 0xbf, 0x08, - 0x1e, 0xd3, 0x9f, 0x68, 0xbf, 0x09, 0xfc, 0xd2, 0x02, 0x27, 0xdf, 0x60, - 0x88, 0x42, 0x01, 0xd8, 0x18, 0x61, 0x00, 0xe0, 0x19, 0x61, 0x0e, 0x4f, - 0x5f, 0x61, 0x9a, 0x61, 0x9f, 0x68, 0xff, 0x08, 0xfc, 0xd3, 0x2f, 0x78, - 0x27, 0x70, 0x01, 0x35, 0x01, 0x32, 0x01, 0x38, 0x01, 0xd4, 0x0a, 0x42, - 0xf4, 0xd1, 0x9f, 0x68, 0xbf, 0x08, 0xfc, 0xd3, 0x00, 0x00, 0xaf, 0xd5, - 0x01, 0x30, 0x01, 0xe0, 0x00, 0x20, 0x01, 0x38, 0x00, 0xbe, 0xc0, 0x46, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - - /* This will overlay the last 3 words of stmqspi_flash_write_code in target */ - uint32_t ccr_buffer[] = { - h_to_le_32(QSPI_CCR_READ_STATUS), - h_to_le_32(QSPI_CCR_WRITE_ENABLE), - h_to_le_32(QSPI_CCR_PAGE_WRITE), - }; + int sector, dual; LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, - __func__, flash_offset, count); + __func__, offset, count); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } - if (flash_offset + count > stmqspi_info->dev->size_in_bytes) { - LOG_WARNING("Write past end of flash. Extra data discarded."); - count = stmqspi_info->dev->size_in_bytes - flash_offset; + if (offset + count > stmqspi_info->dev->size_in_bytes) { + LOG_WARNING("Write beyond end of flash. Extra data discarded."); + count = stmqspi_info->dev->size_in_bytes - offset; } /* Check sector protection */ for (sector = 0; sector < bank->num_sectors; sector++) { /* Start offset in or before this sector? */ /* End offset in or behind this sector? */ - if ((flash_offset < (bank->sectors[sector].offset + bank->sectors[sector].size)) - && ((flash_offset + count - 1) >= bank->sectors[sector].offset) + if ((offset < (bank->sectors[sector].offset + bank->sectors[sector].size)) + && ((offset + count - 1) >= bank->sectors[sector].offset) && bank->sectors[sector].is_protected) { LOG_ERROR("Flash sector %d protected", sector); return ERROR_FAIL; @@ -676,87 +705,14 @@ static int stmqspi_write(struct flash_bank *bank, const uint8_t *buffer, } dual = (stmqspi_info->dual_mask & (1<<QSPI_DUAL_FLASH)) ? 1 : 0; - if (dual & ((flash_offset & 1) != 0 || (count & 1) != 0)) { + if (dual & ((offset & 1) != 0 || (count & 1) != 0)) { LOG_ERROR("For dual-QSPI writes must be two byte aligned: " "%s: address=0x%08" PRIx32 " len=0x%08" PRIx32, __func__, - flash_offset, count); + offset, count); return ERROR_FAIL; } - page_size = stmqspi_info->dev->pagesize << dual; - - /* memory buffer, we assume sectorsize to be a power of 2 times page_size */ - buffer_size = stmqspi_info->dev->sectorsize << dual; - while (target_alloc_working_area_try(target, - sizeof(stmqspi_flash_write_code) + buffer_size, - &write_algorithm) != ERROR_OK) { - buffer_size /= 2; - if (buffer_size < page_size) { - /* we already allocated the writing code, but failed to get a - * buffer, free the algorithm */ - target_free_working_area(target, write_algorithm); - - LOG_WARNING("not enough working area, can't do QSPI page writes"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - }; - /* prepare flash write code, excluding ccr_buffer */ - retval = target_write_buffer(target, write_algorithm->address, - sizeof(stmqspi_flash_write_code) - sizeof(ccr_buffer), - stmqspi_flash_write_code); - if (retval != ERROR_OK) - goto err; - - /* prepare QSPI_CCR register values */ - retval = target_write_buffer(target, write_algorithm->address - + sizeof(stmqspi_flash_write_code) - sizeof(ccr_buffer), - sizeof(ccr_buffer), (uint8_t *) ccr_buffer); - if (retval != ERROR_OK) - goto err; - - /* Abort any previous operation */ - QSPI_WRITE_REG(QSPI_CR, QSPI_READ_REG(QSPI_CR) | (1<<QSPI_ABORT)); - - /* buffer head not aligned to page size */ - if (count > 0 && (flash_offset & (page_size - 1)) != 0) { - cur_count = page_size - (flash_offset & (page_size - 1)); - if (cur_count > count) - cur_count = count; - retval = qspi_write_buffer(bank, write_algorithm, - sizeof(stmqspi_flash_write_code), flash_offset, - page_size, cur_count, buffer); - if (retval != ERROR_OK) - goto err; - flash_offset += cur_count; - buffer += cur_count; - count -= cur_count; - } - - /* central part, aligned to page size */ - while (count > 0) { - /* clip block at buffer_size */ - if (count > buffer_size) - cur_count = buffer_size; - else - cur_count = count; - - retval = qspi_write_buffer(bank, write_algorithm, - sizeof(stmqspi_flash_write_code), flash_offset, - page_size, cur_count, buffer); - if (retval != ERROR_OK) - goto err; - - flash_offset += cur_count; - buffer += cur_count; - count -= cur_count; - - keep_alive(); - } - -err: - target_free_working_area(target, write_algorithm); - - return retval; + return qspi_write_block(bank, buffer, offset, count); } /* Return ID of flash device(s) */ @@ -773,6 +729,7 @@ static int read_flash_id(struct flash_bank *bank, uint32_t *id1, uint32_t *id2) return ERROR_TARGET_NOT_HALTED; } + QSPI_WRITE_REG(QSPI_CR, QSPI_READ_REG(QSPI_CR) | (1<<QSPI_ABORT)); /* poll WIP */ retval = wait_till_ready(bank, QSPI_PROBE_TIMEOUT); if (retval != ERROR_OK) @@ -788,6 +745,9 @@ static int read_flash_id(struct flash_bank *bank, uint32_t *id1, uint32_t *id2) QSPI_WRITE_REG(QSPI_CCR, (QSPI_READ_REG(QSPI_CCR) & 0xF0000000) | ((QSPI_READ_MODE | QSPI_1LINE_MODE | QSPI_ADDR3 | SPIFLASH_READ_ID) & QSPI_NO_ADDR)); + /* Three address bytes, could be dummy for some chips */ + QSPI_WRITE_REG(QSPI_AR, 0); + /* Poll transmit finished flag */ QSPI_POLL_TCF(QSPI_CMD_TIMEOUT); @@ -799,26 +759,32 @@ static int read_flash_id(struct flash_bank *bank, uint32_t *id1, uint32_t *id2) if ((stmqspi_info->dual_mask & ((1<<QSPI_DUAL_FLASH) | (1<<QSPI_FSEL_FLASH))) != (1<<QSPI_FSEL_FLASH)) { *id1 |= (QSPI_READ_REGB(QSPI_DR) << shift); - if (!*id1) { - LOG_ERROR("No response from QSPI flash1"); - return ERROR_FAIL; - } - } if ((stmqspi_info->dual_mask & ((1<<QSPI_DUAL_FLASH) | (1<<QSPI_FSEL_FLASH))) != 0) { *id2 |= (QSPI_READ_REGB(QSPI_DR) << shift); - if (!*id2) { - LOG_ERROR("No response from QSPI flash2"); - return ERROR_FAIL; - } + } + } + + if ((stmqspi_info->dual_mask & ((1<<QSPI_DUAL_FLASH) | + (1<<QSPI_FSEL_FLASH))) != (1<<QSPI_FSEL_FLASH)) { + if (!*id1) { + LOG_ERROR("No response from QSPI flash1"); + retval = ERROR_FAIL; + } + } + if ((stmqspi_info->dual_mask & ((1<<QSPI_DUAL_FLASH) | + (1<<QSPI_FSEL_FLASH))) != 0) { + if (!*id2) { + LOG_ERROR("No response from QSPI flash2"); + retval = ERROR_FAIL; } } /* Switch to memory mapped mode before return to prompt */ QSPI_SET_MM_MODE(); - return ERROR_OK; + return retval; } static int stmqspi_probe(struct flash_bank *bank) @@ -830,8 +796,7 @@ static int stmqspi_probe(struct flash_bank *bank) uint32_t id1 = 0, id2 = 0; const struct stmqspi_target *target_device; const struct flash_device *p; - int dual; - int retval; + int dual, fsize, retval; if (stmqspi_info->probed) free(bank->sectors); @@ -849,17 +814,15 @@ static int stmqspi_probe(struct flash_bank *bank) if (!target_device->name) { LOG_ERROR("Device ID 0x%" PRIx32 " is not known as STM QSPI capable", - target->tap->idcode); + target->tap->idcode); return ERROR_FAIL; } - switch (bank->base - target_device->qspi_base) { - case 0*QSPI_BANK_SIZE: - stmqspi_info->bank_num = QSPI_SEL_BANK0; - break; - default: - LOG_ERROR("Invalid QSPI base address 0x%" PRIx32, bank->base); - return ERROR_FAIL; + if (bank->base == target_device->qspi_base) { + stmqspi_info->bank_num = QSPI_SEL_BANK0; + } else { + LOG_ERROR("Invalid QSPI base address 0x%" PRIx32, bank->base); + return ERROR_FAIL; } io_base = target_device->io_base; stmqspi_info->io_base = io_base; @@ -868,8 +831,8 @@ static int stmqspi_probe(struct flash_bank *bank) stmqspi_info->dual_mask = QSPI_READ_REG(QSPI_CR); /* save current QSPI_CCR value */; stmqspi_info->saved_ccr = QSPI_READ_REG(QSPI_CCR); - LOG_DEBUG("Valid QSPI on device %s at 0x%" PRIx32 ", QSPI_CR 0x%" - PRIx32 ", QSPI_CCR 0x%" PRIx32 ",%s", target_device->name, + LOG_DEBUG("Valid QSPI in device %s at 0x%" PRIx32 ", QSPI_CR 0x%" + PRIx32 ", QSPI_CCR 0x%" PRIx32 ", %s", target_device->name, bank->base, stmqspi_info->dual_mask, stmqspi_info->saved_ccr, (QSPI_ADDR_MASK == QSPI_ADDR4) ? "4 byte addr" : " 3 byte addr"); @@ -886,22 +849,24 @@ static int stmqspi_probe(struct flash_bank *bank) for (p = flash_devices; id1 && p->name ; p++) { if (p->device_id == id1) { stmqspi_info->dev = p; - LOG_INFO("Found flash1 device \'%s\' (ID 0x%06" PRIx32 ")", - p->name, id1); + LOG_INFO("flash1 \'%s\' id = 0x%06" PRIx32 + "\nflash1 size = %lukbytes", + p->name, id1, p->size_in_bytes>>10); break; } } if (id1 && !p->name) { - LOG_ERROR("Unknown flash1 device (ID 0x%06" PRIx32 ")", id1); + LOG_ERROR("Unknown flash1 device id = 0x%06" PRIx32, id1); return ERROR_FAIL; } /* identify flash2 */ for (p = flash_devices; id2 && p->name ; p++) { if (p->device_id == id2) { - LOG_INFO("Found flash2 device \'%s\' (ID 0x%06" PRIx32 ")", - p->name, id2); + LOG_INFO("flash2 \'%s\' id = 0x%06" PRIx32 + "\nflash2 size = %lukbytes", + p->name, id2, p->size_in_bytes>>10); if (!stmqspi_info->dev) stmqspi_info->dev = p; @@ -920,15 +885,21 @@ static int stmqspi_probe(struct flash_bank *bank) } if (id2 && !p->name) { - LOG_ERROR("Unknown flash2 device (ID 0x%06" PRIx32 ")", id2); + LOG_ERROR("Unknown flash2 device id = 0x%06" PRIx32, id2); return ERROR_FAIL; } - dual = (stmqspi_info->dual_mask & (1<<QSPI_DUAL_FLASH)) ? 1 : 0; - /* Set correct size value */ + dual = (stmqspi_info->dual_mask & (1<<QSPI_DUAL_FLASH)) ? 1 : 0; bank->size = stmqspi_info->dev->size_in_bytes << dual; + fsize = (QSPI_READ_REG(QSPI_DCR)>>QSPI_FSIZE0) & ((1<<QSPI_FSIZE_LEN) - 1); + LOG_DEBUG("FSIZE = 0x%04x", fsize); + if (bank->size != (1U<<(fsize + 1))) { + LOG_ERROR("FSIZE field in QSPI_DCR doesn't match actual capacity. Initialzation error?"); + return ERROR_FAIL; + } + /* create and fill sectors array */ bank->num_sectors = stmqspi_info->dev->size_in_bytes / stmqspi_info->dev->sectorsize; @@ -942,7 +913,7 @@ static int stmqspi_probe(struct flash_bank *bank) sectors[sector].offset = sector * (stmqspi_info->dev->sectorsize << dual); sectors[sector].size = (stmqspi_info->dev->sectorsize << dual); sectors[sector].is_erased = -1; - sectors[sector].is_protected = 1; + sectors[sector].is_protected = 0; } bank->sectors = sectors; @@ -954,6 +925,7 @@ static int stmqspi_probe(struct flash_bank *bank) static int stmqspi_auto_probe(struct flash_bank *bank) { struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + if (stmqspi_info->probed) return ERROR_OK; return stmqspi_probe(bank); @@ -975,9 +947,8 @@ static int get_stmqspi_info(struct flash_bank *bank, char *buf, int buf_size) return ERROR_OK; } - snprintf(buf, buf_size, "\nQSPI flash information:" - " Device \'%s\' (ID 0x%06" PRIx32 ")\n", - stmqspi_info->dev->name, stmqspi_info->dev->device_id); + snprintf(buf, buf_size, "\'%s\' %dkbytes id = 0x%06" PRIx32, + stmqspi_info->dev->name, bank->size>>10, stmqspi_info->dev->device_id); return ERROR_OK; } @@ -1017,5 +988,4 @@ struct flash_driver stmqspi_flash = { .erase_check = default_flash_blank_check, .protect_check = stmqspi_protect_check, .info = get_stmqspi_info, - .usage = "", }; diff --git a/src/flash/nor/stmqspi.h b/src/flash/nor/stmqspi.h index abb34d4..362cfb8 100644 --- a/src/flash/nor/stmqspi.h +++ b/src/flash/nor/stmqspi.h @@ -25,6 +25,7 @@ /* register offsets */ #define QSPI_CR (0x00) /* Control register */ +#define QSPI_DCR (0x04) /* Configuration register */ #define QSPI_SR (0x08) /* Status register */ #define QSPI_FCR (0x0C) /* Flag clear register */ #define QSPI_DLR (0x10) /* Data length register */ @@ -38,6 +39,10 @@ #define QSPI_DUAL_FLASH 6 /* Dual flash mode */ #define QSPI_ABORT 1 /* Abort bit */ +/* bits in QSPI_DCR */ +#define QSPI_FSIZE0 16 /* bottom of FSIZE field */ +#define QSPI_FSIZE_LEN 5 /* width of FSIZE field */ + /* bits in QSPI_SR */ #define QSPI_BUSY 5 /* Busy flag */ #define QSPI_FTF 2 /* FIFO threshold flag */ @@ -48,8 +53,8 @@ #define QSPI_READ_MODE 0x04000000 /* indirect read mode */ #define QSPI_MM_MODE 0x0C000000 /* memory mapped mode */ #define QSPI_1LINE_MODE 0x01000500 /* 1 line for address, data */ -#define QSPI_2LINE_MODE 0x02000900 /* 2 lines for address, data */ -#define QSPI_4LINE_MODE 0x03000D00 /* 4 lines for address, data */ +#define QSPI_2LINE_MODE 0x02000A00 /* 2 lines for address, data */ +#define QSPI_4LINE_MODE 0x03000F00 /* 4 lines for address, data */ #define QSPI_NO_DATA (~0x03000000) /* no data */ #define QSPI_NO_ADDR (~0x00000C00) /* no address */ #define QSPI_ADDR3 0x00002000 /* 3 byte address */ diff --git a/tcl/board/stm32f746g-disco_stlink.cfg b/tcl/board/stm32f746g-disco_stlink.cfg index 71afa83..3b2061b 100644 --- a/tcl/board/stm32f746g-disco_stlink.cfg +++ b/tcl/board/stm32f746g-disco_stlink.cfg @@ -12,13 +12,13 @@ set WORKAREASIZE 0x40000 source [find target/stm32f7x.cfg] $_TARGETNAME configure -event reset-init { - # QUADSPI initialization + # QUADSPI initialization mmw 0x40023830 0x000007FF 0 ;# RCC_AHB1ENR |= GPIOA-GPIOK (enable clocks) mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) sleep 1 ;# Wait for clock startup - # PB2: CLK, PB6: BK1_nCS, PD13: BK1_IO3, PE2: BK1_IO2, PD12: BK1_IO1, PD11: BK1_IO0 + # PB2: CLK, PB6: BK1_nCS, PD13: BK1_IO3, PE2: BK1_IO2, PD12: BK1_IO1, PD11: BK1_IO0 mmw 0x40020400 0x00002020 0x00001010 ;# PB6, PB2 alternate mmw 0x40020408 0x00003030 0x00000000 ;# high speed mmw 0x40020420 0x0A000900 0x05000600 ;# AF10, AF9 @@ -33,6 +33,8 @@ $_TARGETNAME configure -event reset-init { mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0 mww 0xA0001000 0x01500318 ;# QUADSPI_CR: PRESCALER=1, APMS=1, FTHRES=3, SSHIFT=1, TCEN=1 - mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1 mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # memory-mapped read mode with 3-byte addresses + mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=READ } diff --git a/tcl/board/stm32f769i-disco_stlink.cfg b/tcl/board/stm32f769i-disco_stlink.cfg index 3cef71c..97fa1fd 100644 --- a/tcl/board/stm32f769i-disco_stlink.cfg +++ b/tcl/board/stm32f769i-disco_stlink.cfg @@ -12,20 +12,20 @@ set WORKAREASIZE 0x40000 source [find target/stm32f7x.cfg] $_TARGETNAME configure -event reset-init { - # QUADSPI initialization + # QUADSPI initialization mmw 0x40023830 0x000007FF 0 ;# RCC_AHB1ENR |= GPIOA-GPIOK (enable clocks) mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) sleep 1 ;# Wait for clock startup - # PB2: CLK, PB6: BK1_nCS, PD13: BK1_IO3, PE2: BK1_IO2, PC10: BK1_IO1, PC9: BK1_IO0 + # PB2: CLK, PB6: BK1_nCS, PD13: BK1_IO3, PE2: BK1_IO2, PC10: BK1_IO1, PC9: BK1_IO0 mmw 0x40020400 0x00002020 0x00001010 ;# PB6, PB2 alternate mmw 0x40020408 0x00003030 0x00000000 ;# high speed mmw 0x40020420 0x0A000900 0x05000600 ;# AF10, AF9 mmw 0x40020800 0x00280000 0x00140000 ;# PC10, PC9 alternate mmw 0x40020808 0x003C0000 0x00000000 ;# high speed - mmw 0x40020424 0x00000990 0x00000660 ;# AF9, AF9 + mmw 0x40020824 0x00000990 0x00000660 ;# AF9, AF9 mmw 0x40020C00 0x08000000 0x04000000 ;# PD13 alternate mmw 0x40020C08 0x0C000000 0x00000000 ;# high speed @@ -35,8 +35,18 @@ $_TARGETNAME configure -event reset-init { mmw 0x40021008 0x00000030 0x00000000 ;# high speed mmw 0x40021020 0x00000900 0x00000600 ;# AF9 - mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0 mww 0xA0001000 0x01500318 ;# QUADSPI_CR: PRESCALER=1, APMS=1, FTHRES=3, SSHIFT=1, TCEN=1 - mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1 + mww 0xA0001004 0x00190100 ;# QUADSPI_DCR: FSIZE=0x19, CSHT=0x01, CKMODE=0 mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # 1-line spi mode + mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO + sleep 1 + + # 4-byte address mode + mww 0xA0001014 0x000001B7 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=EN4B + sleep 1 + + # memory-mapped read mode with 4-byte addresses + mww 0xA0001014 0x0D003503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=READ } diff --git a/tcl/board/stm32l476g-disco_stlink.cfg b/tcl/board/stm32l476g-disco_stlink.cfg new file mode 100644 index 0000000..4c8b07a --- /dev/null +++ b/tcl/board/stm32l476g-disco_stlink.cfg @@ -0,0 +1,32 @@ +# This is an STM32L476G discovery board with a single STM32L476VGT6 chip. +# http://www.st.com/en/evaluation-tools/32l476gdiscovery.html + +# This is for using the onboard STLINK/V2-1 +source [find interface/stlink-v2-1.cfg] + +transport select hla_swd + +# increase working area to 96KB +set WORKAREASIZE 0x18000 + +source [find target/stm32l4x.cfg] + +$_TARGETNAME configure -event reset-init { + + # QUADSPI initialization + mmw 0x4002104C 0x000000FF 0 ;# RCC_AHB2ENR |= GPIOA-GPIOK (enable clocks) + mmw 0x40021050 0x00000100 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) + sleep 1 ;# Wait for clock startup + + # PE10: CLK, PE11: BK1_nCS, PE15: BK1_IO3, PE14: BK1_IO2, PE13: BK1_IO1, PE12: BK1_IO0 + mmw 0x48001000 0xAAA00000 0x55500000 ;# PB15-10 alternate + mmw 0x48001008 0xFFF00000 0x00000000 ;# high speed + mmw 0x48001024 0xAAAAAA00 0x55555500 ;# AF10, AF10, AF10, AF10, AF10, AF10 + + mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0 + mww 0xA0001000 0x01500318 ;# QUADSPI_CR: PRESCALER=1, APMS=1, FTHRES=3, SSHIFT=1, TCEN=1 + mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # memory-mapped read mode with 3-byte addresses + mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=READ +} diff --git a/tcl/target/stm32f7x.cfg b/tcl/target/stm32f7x.cfg index 05470d4..b4cb86b 100755 --- a/tcl/target/stm32f7x.cfg +++ b/tcl/target/stm32f7x.cfg @@ -58,6 +58,9 @@ $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32f2x 0 0 0 0 $_TARGETNAME +set _QSPINAME $_CHIPNAME.qspi +flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_TARGETNAME + # adapter speed should be <= F_CPU/6. F_CPU after reset is 16MHz, so use F_JTAG = 2MHz adapter_khz 2000 diff --git a/tcl/target/stm32l4x.cfg b/tcl/target/stm32l4x.cfg index 9cad7c4..eccd938 100644 --- a/tcl/target/stm32l4x.cfg +++ b/tcl/target/stm32l4x.cfg @@ -49,6 +49,9 @@ $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME +set _QSPINAME $_CHIPNAME.qspi +flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_TARGETNAME + # Common knowledges tells JTAG speed should be <= F_CPU/6. # F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on # the safe side. -- ------------------------------------------------------------------------------ Developer Access Program for Intel Xeon Phi Processors Access to Intel Xeon Phi processor-based developer platforms. With one year of Intel Parallel Studio XE. Training and support from Colfax. Order your platform today.http://sdm.link/intel _______________________________________________ OpenOCD-devel mailing list OpenOCD-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openocd-devel