Skip to content

Commit 09464ca

Browse files
dgarskedanielinux
authored andcommitted
API's to support OTP flash read/write on the STM32H7. Enabled with FLASH_OTP_ROT.
1 parent 0ddde6f commit 09464ca

1 file changed

Lines changed: 130 additions & 5 deletions

File tree

hal/stm32h7.c

Lines changed: 130 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -205,17 +205,21 @@
205205
/*** QSPI ***/
206206
/* See hal/spi/spi_drv_stm32.c */
207207

208+
208209
/*** FLASH ***/
209210
#define SYSCFG_APB4_CLOCK_ER_VAL (1 << 0) /* RM0433 - 7.7.48 - RCC_APB4ENR - SYSCFGEN */
210211

211212
#define FLASH_BASE (0x52002000) /* RM0433 - Table 8 */
212213
#define FLASH_ACR (*(volatile uint32_t *)(FLASH_BASE + 0x00)) /* RM0433 - 3.9.1 - FLASH_ACR */
213-
#define FLASH_OPTSR_CUR (*(volatile uint32_t *)(FLASH_BASE + 0x1C))
214+
215+
#define FLASH_OPTKEYR (*(volatile uint32_t *)(FLASH_BASE + 0x08)) /* FLASH option key register */
216+
#define FLASH_OPTCR (*(volatile uint32_t *)(FLASH_BASE + 0x18)) /* FLASH option control register */
217+
#define FLASH_OPTSR_CUR (*(volatile uint32_t *)(FLASH_BASE + 0x1C)) /* FLASH option status register */
214218

215219
/* Bank 1 */
216220
#define FLASH_KEYR1 (*(volatile uint32_t *)(FLASH_BASE + 0x04)) /* RM0433 - 3.9.2 - FLASH_KEYR 1 */
217-
#define FLASH_SR1 (*(volatile uint32_t *)(FLASH_BASE + 0x10)) /* RM0433 - 3.9.5 - FLASH_SR 1 */
218221
#define FLASH_CR1 (*(volatile uint32_t *)(FLASH_BASE + 0x0C)) /* RM0433 - 3.9.4 - FLASH_CR 1 */
222+
#define FLASH_SR1 (*(volatile uint32_t *)(FLASH_BASE + 0x10)) /* RM0433 - 3.9.5 - FLASH_SR 1 */
219223

220224
/* Bank 2 */
221225
#define FLASH_KEYR2 (*(volatile uint32_t *)(FLASH_BASE + 0x104)) /* RM0433 - 3.9.24 - FLASH_KEYR 2 */
@@ -255,12 +259,38 @@
255259

256260
#define FLASH_OPTSR_CUR_BSY (1 << 0)
257261

262+
#define FLASH_OPTCR_OPTLOCK (1 << 0) /* lock option configuration bit */
263+
#define FLASH_OPTCR_OPTSTART (1 << 1) /* Option byte start change option configuration bit */
264+
#define FLASH_OPTCR_MER (1 << 4) /* Mass erase request */
265+
#define FLASH_OPTCR_PG_OTP (1 << 5) /* OTP program control bit */
266+
#define FLASH_OPTCR_OPTCHANGEERRIE (1 << 30) /* Option byte change error interrupt enable bit */
267+
#define FLASH_OPTCR_SWAP_BANK (1 << 31) /* Bank swapping option configuration bit */
268+
258269
#define FLASH_CR_SNB_SHIFT 8 /* SNB bits 10:8 */
259270
#define FLASH_CR_SNB_MASK 0x7 /* SNB bits 10:8 - 3 bits */
260271

261-
#define FLASH_KEY1 (0x45670123)
262-
#define FLASH_KEY2 (0xCDEF89AB)
263-
272+
#define FLASH_KEY1 (0x45670123U)
273+
#define FLASH_KEY2 (0xCDEF89ABU)
274+
275+
#define FLASH_OPT_KEY1 (0x08192A3BU)
276+
#define FLASH_OPT_KEY2 (0x4C5D6E7FU)
277+
278+
#ifdef FLASH_OTP_ROT
279+
#ifndef FLASH_OTP_BASE
280+
#define FLASH_OTP_BASE 0x08FFF000
281+
#endif
282+
#ifndef FLASH_OTP_END
283+
#define FLASH_OTP_END 0x08FFF3FF
284+
#endif
285+
#ifndef OTP_SIZE
286+
#define OTP_SIZE 1024
287+
#endif
288+
#ifndef OTP_BLOCKS
289+
#define OTP_BLOCKS 16
290+
#endif
291+
292+
#define OTP_BLOCK_SIZE (OTP_SIZE / OTP_BLOCKS) /* 64 bytes */
293+
#endif
264294

265295
/* STM32H7: Due to ECC functionality, it is not possible to write partition/sector
266296
* flags and signature more than once. This flags_cache is used to intercept write operations and
@@ -777,3 +807,98 @@ void hal_prepare_boot(void)
777807
#endif
778808
clock_pll_off();
779809
}
810+
811+
#ifdef FLASH_OTP_ROT
812+
813+
static void hal_flash_wait_otp(void)
814+
{
815+
/* Wait for the FLASH operation to complete by polling on QW flag to be reset. */
816+
while ( (FLASH_SR1 & FLASH_SR_QW) == FLASH_SR_QW ) {
817+
/* TODO: check timeout */
818+
}
819+
820+
/* Check FLASH End of Operation flag */
821+
if ( (FLASH_SR1 & FLASH_SR_EOP) == FLASH_SR_EOP ) {
822+
FLASH_SR1 &= FLASH_SR_EOP; /* Clear FLASH End of Operation pending bit */
823+
}
824+
}
825+
826+
static void hal_flash_otp_unlock(void)
827+
{
828+
if ((FLASH_OPTCR & FLASH_OPTCR_OPTLOCK) != 0U) {
829+
FLASH_OPTKEYR = FLASH_OPT_KEY1;
830+
FLASH_OPTKEYR = FLASH_OPT_KEY2;
831+
}
832+
}
833+
834+
static void hal_flash_otp_lock(void)
835+
{
836+
/* Set the OPTLOCK Bit to lock the FLASH Option Byte Registers access */
837+
FLASH_OPTCR |= FLASH_OPTCR_OPTLOCK;
838+
}
839+
840+
int hal_flash_otp_write(uint32_t flashAddress, uint16_t* data, uint16_t length)
841+
{
842+
volatile uint16_t tmp;
843+
uint16_t idx = 0;
844+
if (!(flashAddress >= FLASH_OTP_BASE && flashAddress <= FLASH_OTP_END)) {
845+
return -1;
846+
}
847+
848+
hal_flash_unlock();
849+
hal_flash_otp_unlock();
850+
851+
while (idx < length && flashAddress <= FLASH_OTP_END-1) {
852+
/* Clear errors */
853+
flash_clear_errors(0); /* bank 1 */
854+
/* Wait for last operation to be completed */
855+
hal_flash_wait_otp();
856+
857+
FLASH_OPTCR &= ~(FLASH_OPTCR_OPTLOCK); /* unlock FLASH_OPTCR register */
858+
859+
/* Set OTP_PG bit */
860+
FLASH_OPTCR |= FLASH_OPTCR_PG_OTP;
861+
862+
ISB();
863+
DSB();
864+
865+
/* Program an OTP word (16 bits) */
866+
*(volatile uint16_t*)flashAddress = *(volatile uint16_t*)data;
867+
868+
/* Read it back */
869+
tmp = *(volatile uint16_t*)flashAddress;
870+
(void)tmp; /* avoid unused warnings */
871+
flashAddress += sizeof(uint16_t);
872+
data++;
873+
idx += sizeof(uint16_t);
874+
875+
/* Wait for last operation to be completed */
876+
hal_flash_wait_otp();
877+
878+
/* clear OTP_PG bit */
879+
FLASH_OPTCR &= ~FLASH_OPTCR_PG_OTP;
880+
}
881+
882+
hal_flash_otp_lock();
883+
hal_flash_lock();
884+
return 0;
885+
}
886+
887+
int hal_flash_otp_read(uint32_t flashAddress, uint16_t* data, uint32_t length)
888+
{
889+
uint32_t i;
890+
if (!(flashAddress >= FLASH_OTP_BASE && flashAddress <= FLASH_OTP_END)) {
891+
return -1;
892+
}
893+
for (i = 0;
894+
(i < length) && (flashAddress <= (FLASH_OTP_END-1));
895+
i += sizeof(uint16_t))
896+
{
897+
*data = *(volatile uint16_t*)flashAddress;
898+
flashAddress += sizeof(uint16_t);
899+
data++;
900+
}
901+
return 0;
902+
}
903+
904+
#endif /* FLASH_OTP_ROT */

0 commit comments

Comments
 (0)