Skip to content

Commit

Permalink
drivers: flash: stm32g0: dual bank handling
Browse files Browse the repository at this point in the history
This commit fixes dual bank flash handling on stm32g0 targets.
In contrast to other Series (G4, L5) the flash page size does not change
in single bank configuration (2KiB in both configurations).

nSWAP_BANK:
While the reference manual(RM) only documents:
"This bit selects the bank that is the subject of empty check upon boot"
as expected, this behaves similar to BFB2 on G4 and SWAP_BANK on L5.
It has been observed that this bit swaps the address mapping of bank1
and bank2, regardless of DUAL_BANK bit being set or not.
As documented in the RM the nSWAP_BANK bit is ignored when the BOOT_LOOK
bit is set. This applies to the empty check as well as the address
mapping.

On this Series FLASH_CR_BKER must be set in single-bank as well as
dual-bank configuration for erase operations on bank2 regardless of
the swap status.

On a G0B1RE (dev-id: 0x467) I could not observe a difference between
DUAL_BANK flash option bit set and not.
It this may be different on 256KiB Flash targets.
The HAL indicates that "FLASH_SALES_TYPE_0" only uses a single bank if
OB_DUAL_BANK_VALUE is not set, but as I don't know which SoC this is
and I can't test the behaviour and the driver does not take this into
account.

Signed-off-by: Thomas Stranger <[email protected]>
  • Loading branch information
str4t0m authored and cfriedt committed Nov 17, 2021
1 parent 5bf11c2 commit cfac53b
Showing 1 changed file with 52 additions and 0 deletions.
52 changes: 52 additions & 0 deletions drivers/flash/flash_stm32g0x.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,19 @@ LOG_MODULE_REGISTER(LOG_DOMAIN);
#include "flash_stm32.h"


/* FLASH_DBANK_SUPPORT is defined in the HAL for all G0Bx and G0C1 SoCs,
* while only those with 256KiB and 512KiB Flash have two banks.
*/
#if defined(FLASH_DBANK_SUPPORT) && (CONFIG_FLASH_SIZE > (128))
#define STM32G0_DBANK_SUPPORT
#endif

#if defined(STM32G0_DBANK_SUPPORT)
#define STM32G0_BANK_COUNT 2
#define STM32G0_BANK2_START_PAGE_NR 256
#else
#define STM32G0_BANK_COUNT 1
#endif

#define STM32G0_FLASH_SIZE (FLASH_SIZE)
#define STM32G0_FLASH_PAGE_SIZE (FLASH_PAGE_SIZE)
Expand All @@ -31,6 +43,8 @@ LOG_MODULE_REGISTER(LOG_DOMAIN);
/*
* offset and len must be aligned on 8 for write,
* positive and not beyond end of flash
* On dual-bank SoCs memory accesses starting on the first bank and continuing
* beyond the first bank into the second bank are allowed.
*/
bool flash_stm32_valid_range(const struct device *dev, off_t offset,
uint32_t len,
Expand Down Expand Up @@ -125,6 +139,21 @@ static int erase_page(const struct device *dev, unsigned int offset)
tmp = regs->CR;
page = offset / STM32G0_FLASH_PAGE_SIZE;

#if defined(STM32G0_DBANK_SUPPORT)
bool swap_enabled = (regs->OPTR & FLASH_OPTR_nSWAP_BANK) == 0;

/* big page-nr w/o swap or small page-nr w/ swap indicate bank2 */
if ((page >= STM32G0_PAGES_PER_BANK) != swap_enabled) {
page = (page % STM32G0_PAGES_PER_BANK) + STM32G0_BANK2_START_PAGE_NR;
tmp |= FLASH_CR_BKER;
LOG_DBG("Erase page %d on bank 2", page);
} else {
page = page % STM32G0_PAGES_PER_BANK;
tmp &= ~FLASH_CR_BKER;
LOG_DBG("Erase page %d on bank 1", page);
}
#endif

/* Set the PER bit and select the page you wish to erase */
tmp |= FLASH_CR_PER;
tmp &= ~FLASH_CR_PNB_Msk;
Expand Down Expand Up @@ -174,6 +203,16 @@ int flash_stm32_write_range(const struct device *dev, unsigned int offset,
return rc;
}

/*
* The address space is always continuous, even though a subset of G0 SoCs has
* two flash banks.
* Only the "physical" flash page-NRs are not continuous on those SoCs.
* As a result the page numbers used in the zephyr flash api differs
* from the "physical" flash page number.
* The first is equal to the address offset divided by the page size, while
* "physical" pages are numbered starting with 0 on bank1 and 256 on bank2.
* As a result only a single homogeneous flash page layout needs to be defined.
*/
void flash_stm32_page_layout(const struct device *dev,
const struct flash_pages_layout **layout,
size_t *layout_size)
Expand All @@ -194,3 +233,16 @@ void flash_stm32_page_layout(const struct device *dev,
*layout = &stm32g0_flash_layout;
*layout_size = 1;
}

/* Override weak function */
int flash_stm32_check_configuration(void)
{
#if defined(STM32G0_DBANK_SUPPORT) && (CONFIG_FLASH_SIZE == 256)
/* Single bank mode not supported on dual bank SoCs with 256kiB flash */
if ((regs->OPTR & FLASH_OPTR_DUAL_BANK) == 0) {
LOG_ERR("Single bank configuration not supported by the driver");
return -ENOTSUP;
}
#endif
return 0;
}

0 comments on commit cfac53b

Please sign in to comment.