stm32/h7: Implemented support for the Flash controller having untangled the previous pretending it was the F2/F4 controller mess
This commit is contained in:
committed by
Piotr Esden-Tempski
parent
ee418f1780
commit
cdd8f2adac
@@ -5,6 +5,8 @@
|
||||
*
|
||||
* @author @htmlonly © @endhtmlonly 2019
|
||||
* Brian Viele <vielster@allocor.tech>
|
||||
* @author @htmlonly © @endhtmlonly 2024
|
||||
* Rachel Mant <git@dragonmux.network>
|
||||
*/
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
@@ -26,11 +28,51 @@
|
||||
#ifndef LIBOPENCM3_FLASH_H
|
||||
#define LIBOPENCM3_FLASH_H
|
||||
|
||||
#include <libopencm3/stm32/common/flash_common_all.h>
|
||||
#include <libopencm3/stm32/common/flash_common_f.h>
|
||||
#include <libopencm3/stm32/common/flash_common_f24.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <libopencm3/stm32/common/flash_common_idcache.h>
|
||||
|
||||
/**@{*/
|
||||
#define FLASH_FPEC1_BASE (FLASH_MEM_INTERFACE_BASE + 0x000U)
|
||||
#define FLASH_FPEC2_BASE (FLASH_MEM_INTERFACE_BASE + 0x100U)
|
||||
|
||||
/** @defgroup flash_registers Flash Registers
|
||||
* @ingroup flash_defines
|
||||
@{*/
|
||||
/** Flash Access Control register */
|
||||
#define FLASH_ACR MMIO32(FLASH_MEM_INTERFACE_BASE + 0x00U)
|
||||
/** Flash Key register */
|
||||
#define FLASH_KEYR 0x04U
|
||||
/** Flash Option bytes key register */
|
||||
#define FLASH_OPTKEYR MMIO32(FLASH_MEM_INTERFACE_BASE + 0x08U)
|
||||
/** Flash Control register */
|
||||
#define FLASH_CR 0x0CU
|
||||
/** Flash Status register - NB: Read-only on H7!! */
|
||||
#define FLASH_SR 0x10U
|
||||
/** Flash Clear Control register */
|
||||
#define FLASH_CCR 0x14U
|
||||
/** Flash Option Control register */
|
||||
#define FLASH_OPTCR MMIO32(FLASH_MEM_INTERFACE_BASE + 0x18U)
|
||||
/** Flash Option Status read side register */
|
||||
#define FLASH_OPTSR_CUR MMIO32(FLASH_MEM_INTERFACE_BASE + 0x1CU)
|
||||
/** Flash Option Status write side register */
|
||||
#define FLASH_OPTSR MMIO32(FLASH_MEM_INTERFACE_BASE + 0x18U)
|
||||
/**@}*/
|
||||
|
||||
/** @defgroup flash_latency FLASH Wait States
|
||||
@ingroup flash_defines
|
||||
@{*/
|
||||
#define FLASH_ACR_LATENCY(w) ((w) & FLASH_ACR_LATENCY_MASK)
|
||||
#define FLASH_ACR_LATENCY_0WS FLASH_ACR_LATENCY(0U)
|
||||
#define FLASH_ACR_LATENCY_1WS FLASH_ACR_LATENCY(1U)
|
||||
#define FLASH_ACR_LATENCY_2WS FLASH_ACR_LATENCY(2U)
|
||||
#define FLASH_ACR_LATENCY_3WS FLASH_ACR_LATENCY(3U)
|
||||
#define FLASH_ACR_LATENCY_4WS FLASH_ACR_LATENCY(4U)
|
||||
#define FLASH_ACR_LATENCY_5WS FLASH_ACR_LATENCY(5U)
|
||||
#define FLASH_ACR_LATENCY_6WS FLASH_ACR_LATENCY(6U)
|
||||
#define FLASH_ACR_LATENCY_7WS FLASH_ACR_LATENCY(7U)
|
||||
/**@}*/
|
||||
#define FLASH_ACR_LATENCY_SHIFT 0U
|
||||
#define FLASH_ACR_LATENCY_MASK 0x0fU
|
||||
|
||||
/** @addtogroup flash_acr_values FLASH_ACR values
|
||||
* @ingroup flash_registers
|
||||
@@ -49,7 +91,205 @@
|
||||
#define FLASH_ACR_WRHIGHFREQ_MASK (0x3)
|
||||
#define FLASH_ACR_WRHIGHFREQ_SHIFT (0x4)
|
||||
|
||||
/* --- FLASH_SR values ----------------------------------------------------- */
|
||||
|
||||
#define FLASH_SR_BSY (1U << 0U)
|
||||
#define FLASH_SR_WBNE (1U << 1U)
|
||||
#define FLASH_SR_QW (1U << 2U)
|
||||
#define FLASH_SR_CRC_BUSY (1U << 3U)
|
||||
#define FLASH_SR_EOP (1U << 16U)
|
||||
#define FLASH_SR_WRPERR (1U << 17U)
|
||||
#define FLASH_SR_PGSERR (1U << 18U)
|
||||
#define FLASH_SR_STRBERR (1U << 19U)
|
||||
#define FLASH_SR_INCERR (1U << 21U)
|
||||
#define FLASH_SR_OPERR (1U << 22U)
|
||||
#define FLASH_SR_RDPERR (1U << 23U)
|
||||
#define FLASH_SR_RDSERR (1U << 24U)
|
||||
#define FLASH_SR_SNECCERR (1U << 25U)
|
||||
#define FLASH_SR_DBECCERR (1U << 26U)
|
||||
#define FLASH_SR_CRCEND (1U << 27U)
|
||||
#define FLASH_SR_CRCRDERR (1U << 28U)
|
||||
|
||||
#define FLASH_SR_READ_ERROR_MASK \
|
||||
(FLASH_SR_RDPERR | FLASH_SR_RDSERR | FLASH_SR_SNECCERR | FLASH_SR_DBECCERR)
|
||||
|
||||
#define FLASH_SR_ERROR_MASK ( \
|
||||
FLASH_SR_WRPERR | FLASH_SR_PGSERR | FLASH_SR_STRBERR | \
|
||||
FLASH_SR_INCERR | FLASH_SR_OPERR | FLASH_SR_READ_ERROR_MASK \
|
||||
)
|
||||
|
||||
/* --- FLASH_CR values ----------------------------------------------------- */
|
||||
|
||||
#define FLASH_CR_LOCK (1U << 0U)
|
||||
#define FLASH_CR_PG (1U << 1U)
|
||||
#define FLASH_CR_SER (1U << 2U)
|
||||
#define FLASH_CR_BER (1U << 3U)
|
||||
#define FLASH_CR_PROGRAM_MASK 0x3U
|
||||
#define FLASH_CR_PROGRAM_SHIFT (4U)
|
||||
#define FLASH_CR_FW (1U << 6U)
|
||||
#define FLASH_CR_STRT (1U << 7U)
|
||||
#define FLASH_CR_H7Bx_FW (1U << 4U)
|
||||
#define FLASH_CR_H7Bx_STRT (1U << 5U)
|
||||
#define FLASH_CR_SNB_SHIFT (8U)
|
||||
#define FLASH_CR_SNB_MASK (0x3U << FLASH_CR_SNB_SHIFT)
|
||||
#define FLASH_CR_H7Bx_SNB_SHIFT (6U)
|
||||
#define FLASH_CR_H7Bx_SNB_MASK (0x3U << FLASH_CR_H7Bx_SNB_SHIFT)
|
||||
#define FLASH_CR_CRC_EN (1U << 15U)
|
||||
#define FLASH_CR_EOPIE (1U << 16U)
|
||||
#define FLASH_CR_WRPERRIE (1U << 17U)
|
||||
#define FLASH_CR_PGSERRIE (1U << 18U)
|
||||
#define FLASH_CR_STRBERRIE (1U << 19U)
|
||||
#define FLASH_CR_INCERRIE (1U << 21U)
|
||||
#define FLASH_CR_OPERRIE (1U << 22U)
|
||||
#define FLASH_CR_RDPERRIE (1U << 23U)
|
||||
#define FLASH_CR_RDSERRIE (1U << 24U)
|
||||
#define FLASH_CR_SNECCERRIE (1U << 25U)
|
||||
#define FLASH_CR_DBECCERRIE (1U << 26U)
|
||||
#define FLASH_CR_CRCENDIE (1U << 27U)
|
||||
#define FLASH_CR_CRCRDERRIE (1U << 28U)
|
||||
/* The operation control bits are all in the lower half the register */
|
||||
#define FLASH_CR_OP_MASK (0x0000ffffU)
|
||||
|
||||
/** @defgroup flash_cr_program_width Flash programming width
|
||||
@ingroup flash_group
|
||||
|
||||
@{*/
|
||||
#define FLASH_CR_PROGRAM_X8 0U
|
||||
#define FLASH_CR_PROGRAM_X16 1U
|
||||
#define FLASH_CR_PROGRAM_X32 2U
|
||||
#define FLASH_CR_PROGRAM_X64 3U
|
||||
/**@}*/
|
||||
|
||||
/* --- FLASH_OPTCR values -------------------------------------------------- */
|
||||
|
||||
#define FLASH_OPTCR_OPTLOCK (1U << 0U)
|
||||
#define FLASH_OPTCR_OPTSTRT (1U << 1U)
|
||||
|
||||
/* --- Flash Keys -----------------------------------------------------------*/
|
||||
|
||||
#define FLASH_KEYR_KEY1 (0x45670123U)
|
||||
#define FLASH_KEYR_KEY2 (0xcdef89abU)
|
||||
|
||||
#define FLASH_OPTKEYR_KEY1 (0x08192a3bU)
|
||||
#define FLASH_OPTKEYR_KEY2 (0x4c5d6e7fU)
|
||||
|
||||
/* --- Flash Bank access constants ----------------------------------------- */
|
||||
|
||||
#define FLASH_BANK_MAX_SIZE (0x00100000U)
|
||||
#define FLASH_WRITE_BLOCK_SIZE (32U)
|
||||
#define FLASH_WRITE_BLOCK_MASK (0x0000001FU)
|
||||
|
||||
enum flash_bank {
|
||||
FLASH_BANK_1 = 1,
|
||||
FLASH_BANK_2,
|
||||
};
|
||||
|
||||
/* --- Function prototypes ------------------------------------------------- */
|
||||
|
||||
BEGIN_DECLS
|
||||
|
||||
/** Set the Number of Wait States.
|
||||
*
|
||||
* Used to match the system clock to the FLASH memory access time. See the
|
||||
* programming manual for more information on clock speed ranges. The latency must
|
||||
* be changed to the appropriate value <b>before</b> any increase in clock
|
||||
* speed, or <b>after</b> any decrease in clock speed.
|
||||
*
|
||||
* @param[in] wait_states values from @ref flash_latency.
|
||||
*/
|
||||
void flash_set_ws(uint32_t wait_states);
|
||||
|
||||
/** Check if the FPEC is currently busy with an operation */
|
||||
bool flash_is_busy(enum flash_bank bank);
|
||||
/** Clear the End of OPeration flag. */
|
||||
void flash_clear_eop_flag(enum flash_bank bank);
|
||||
/** Clear all status flags. */
|
||||
void flash_clear_status_flags(enum flash_bank bank);
|
||||
/** Wait until Last Operation has Ended.
|
||||
* This loops indefinitely until an operation (write or erase) has completed by
|
||||
* testing for EOP and nothing being left in the queue.
|
||||
*
|
||||
* Returns whether the operation was a success or not
|
||||
*/
|
||||
bool flash_wait_for_last_operation(enum flash_bank bank);
|
||||
|
||||
/** Check if the FPEC is currently locked for writes. */
|
||||
bool flash_is_locked(enum flash_bank bank);
|
||||
/** Unlock the Flash Program and Erase Controller.
|
||||
* This enables write access to the Flash memory. It is locked by default on
|
||||
* reset.
|
||||
*/
|
||||
void flash_unlock(enum flash_bank bank);
|
||||
/** Lock the Flash Program and Erase Controller.
|
||||
* Used to prevent spurious writes to FLASH.
|
||||
*/
|
||||
void flash_lock(enum flash_bank bank);
|
||||
|
||||
/** Erases a sector of a bank of Flash.
|
||||
*
|
||||
* NB: The second bank is not always valid on all STM32H7 parts. Check your part datasheet
|
||||
* to determine if it exists and is valid before using this function with FLASH_BANK_2.
|
||||
*
|
||||
* @param[in] bank one of the FLASH_BANK_* constants indicating which bank to erase
|
||||
* @param[in] sector the sector number in the bank to erase
|
||||
* @param[in] operation_parallelism the write parallelism to use for the erase -
|
||||
* one of the PROGRAM_SIZE_* constants
|
||||
*/
|
||||
void flash_erase_sector(enum flash_bank bank, uint8_t sector, uint8_t operation_parallelism);
|
||||
/** Erases a whole bank of Flash.
|
||||
*
|
||||
* Which banks are valid depends on your part as follows:
|
||||
* - H72x/H73x: Flash Bank 1 **only**
|
||||
* - H74x/H75x:
|
||||
* - H75xB: Flash Bank 1 **only** with 128kiB of Flash total
|
||||
* - H74xG: Both banks, split at 512kiB for 1MiB total
|
||||
* - H7xxI: Both banks, split at 1MiB for 2MiB total
|
||||
* - H7Bx:
|
||||
* - H7B0xB: Flash Bank 1 **only** with 128kiB of Flash total
|
||||
* - H7A3xG: Flash Bank 1 **only** for 1MiB total
|
||||
* - H7x3xI: Both banks, split at 1MiB for 2MiB total
|
||||
*
|
||||
* @param[in] bank one of the FLASH_BANK_* constants indicating which bank to erase
|
||||
* @param[in] operation_parallelism the write parallelism to use for the erase -
|
||||
* one of the PROGRAM_SIZE_* constants
|
||||
*/
|
||||
void flash_erase_bank(enum flash_bank bank, uint8_t operation_parallelism);
|
||||
|
||||
/** Enable writing the Flash in a bank and set the operation parallelism */
|
||||
void flash_program_enable(enum flash_bank bank, uint8_t operation_parallelism);
|
||||
/** Disable writing the Flash in a bank*/
|
||||
void flash_program_disable(enum flash_bank bank);
|
||||
/** Program one u8 to Flash (forced) */
|
||||
bool flash_program_byte(uintptr_t address, uint8_t data);
|
||||
/** Program one u16 to Flash (forced) */
|
||||
bool flash_program_half_word(uintptr_t address, uint16_t data);
|
||||
/** Program one u32 to Flash (forced) */
|
||||
bool flash_program_word(uintptr_t address, uint32_t data);
|
||||
/** Program one u64 to Flash (forced) */
|
||||
bool flash_program_double_word(uintptr_t address, uint64_t data);
|
||||
/** Program a block of data to Flash (forced) */
|
||||
bool flash_program(uintptr_t address, const uint8_t *data, size_t len);
|
||||
/** Force the write operation - required to flush out a non-full block of data to the Flash
|
||||
*
|
||||
* NB: This must be called only *after* setting up the operation with the above functions.
|
||||
*/
|
||||
void flash_program_force(enum flash_bank bank);
|
||||
|
||||
/** Unlock the Option Byte Access.
|
||||
* This enables write access to the option bytes. It is locked by default on
|
||||
* reset.
|
||||
*/
|
||||
void flash_unlock_option_bytes(void);
|
||||
/** Lock the Option Byte Access.
|
||||
* This disables write access to the option bytes.
|
||||
*/
|
||||
void flash_lock_option_bytes(void);
|
||||
/** Program the Option Bytes.
|
||||
* Write
|
||||
*/
|
||||
void flash_program_option_bytes(uint32_t data);
|
||||
|
||||
END_DECLS
|
||||
/**@}*/
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include <libopencm3/stm32/flash.h>
|
||||
|
||||
#if !defined(STM32H7)
|
||||
void flash_prefetch_enable(void)
|
||||
{
|
||||
FLASH_ACR |= FLASH_ACR_PRFTEN;
|
||||
@@ -32,6 +33,7 @@ void flash_prefetch_disable(void)
|
||||
{
|
||||
FLASH_ACR &= ~FLASH_ACR_PRFTEN;
|
||||
}
|
||||
#endif
|
||||
|
||||
void flash_set_ws(uint32_t ws)
|
||||
{
|
||||
|
||||
@@ -40,7 +40,7 @@ ARFLAGS = rcs
|
||||
OBJS += dac_common_all.o dac_common_v2.o
|
||||
OBJS += exti_common_all.o
|
||||
OBJS += fdcan.o fdcan_common.o
|
||||
OBJS += flash_common_all.o flash_common_f.o flash_common_f24.o
|
||||
OBJS += flash.o
|
||||
OBJS += fmc_common_f47.o
|
||||
OBJS += gpio_common_all.o gpio_common_f0234.o
|
||||
OBJS += pwr.o rcc.o
|
||||
|
||||
334
lib/stm32/h7/flash.c
Normal file
334
lib/stm32/h7/flash.c
Normal file
@@ -0,0 +1,334 @@
|
||||
/** @addtogroup flash_file FLASH peripheral API
|
||||
* @ingroup peripheral_apis
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2024 Rachel Mant <git@dragonmux.network>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
#include <string.h>
|
||||
#include <libopencm3/stm32/flash.h>
|
||||
|
||||
#define REBASE(x) MMIO32((x) + (bank_base_address))
|
||||
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
#define DBGMCU_IDCODE (DBGMCU_BASE + 0x000U)
|
||||
|
||||
/** @brief Set the Program Parallelism Size
|
||||
*
|
||||
* Set the programming parallelism width. Note carefully the power supply voltage
|
||||
* restrictions under which the different word sizes may be used. See the
|
||||
* programming manual for more information.
|
||||
* @param[in] psize The programming word width one of: @ref flash_cr_program_width
|
||||
*/
|
||||
static inline void flash_set_program_size(const uintptr_t bank_base_address, const uint32_t psize)
|
||||
{
|
||||
REBASE(FLASH_CR) &= ~(FLASH_CR_PROGRAM_MASK << FLASH_CR_PROGRAM_SHIFT);
|
||||
REBASE(FLASH_CR) |= psize << FLASH_CR_PROGRAM_SHIFT;
|
||||
}
|
||||
|
||||
/** @brief Translate a bank number to its FPEC base address */
|
||||
static inline uintptr_t flash_bank_address(const enum flash_bank bank)
|
||||
{
|
||||
switch (bank) {
|
||||
case FLASH_BANK_1:
|
||||
return FLASH_FPEC1_BASE;
|
||||
case FLASH_BANK_2:
|
||||
return FLASH_FPEC2_BASE;
|
||||
}
|
||||
/* We should never be able to reach this point */
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
static inline enum flash_bank flash_bank_from_address(const uintptr_t address)
|
||||
{
|
||||
/* Make it undefined behaviour to call this function with an address below the Flash range start */
|
||||
if (address < FLASH_BASE)
|
||||
__builtin_unreachable();
|
||||
/* Check if the addres falls in the first bank */
|
||||
if (address < FLASH_BASE + FLASH_BANK_MAX_SIZE)
|
||||
return FLASH_BANK_1;
|
||||
/* Check if the address falls in the second */
|
||||
if (address < FLASH_BASE + (FLASH_BANK_MAX_SIZE << 1U))
|
||||
return FLASH_BANK_2;
|
||||
/* Turn any other addresses passed in into UB too */
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
static inline enum device_variant mcu_variant(void)
|
||||
{
|
||||
/* Read the device DBGMCU ID code out */
|
||||
const uint32_t idcode = DBGMCU_IDCODE;
|
||||
/* Mask out and return the device ID component */
|
||||
return idcode & 0xfffU;
|
||||
}
|
||||
|
||||
void flash_set_ws(const uint32_t wait_states)
|
||||
{
|
||||
/* Read the current ACR value and mask out the wait states component */
|
||||
const uint32_t reg32 = FLASH_ACR & ~(FLASH_ACR_LATENCY_MASK << FLASH_ACR_LATENCY_SHIFT);
|
||||
/* Write back the new value, with the new wait states shifted in to place */
|
||||
FLASH_ACR = reg32 | (wait_states << FLASH_ACR_LATENCY_SHIFT);
|
||||
}
|
||||
|
||||
bool flash_is_busy(const enum flash_bank bank)
|
||||
{
|
||||
const uintptr_t bank_base_address = flash_bank_address(bank);
|
||||
/*
|
||||
* Read back the current status register value and check for there still
|
||||
* being items in the queue, and the EOP flag not yet being set.
|
||||
*/
|
||||
const uint32_t status = REBASE(FLASH_SR);
|
||||
return !(status & FLASH_SR_EOP) && (status & FLASH_SR_QW);
|
||||
}
|
||||
|
||||
void flash_clear_eop_flag(const enum flash_bank bank)
|
||||
{
|
||||
const uintptr_t bank_base_address = flash_bank_address(bank);
|
||||
/*
|
||||
* The H7 uses a special clear register for the control bits related
|
||||
* to errors and operation completion, which clears the *status* bits.
|
||||
* The status register is strictly read-only on this part.
|
||||
*/
|
||||
REBASE(FLASH_CCR) = FLASH_SR_EOP;
|
||||
}
|
||||
|
||||
void flash_clear_status_flags(const enum flash_bank bank)
|
||||
{
|
||||
const uintptr_t bank_base_address = flash_bank_address(bank);
|
||||
REBASE(FLASH_CCR) = FLASH_SR_ERROR_MASK | FLASH_SR_EOP;
|
||||
}
|
||||
|
||||
bool flash_wait_for_last_operation(const enum flash_bank bank)
|
||||
{
|
||||
const uintptr_t bank_base_address = flash_bank_address(bank);
|
||||
/* Wait in a busy loop while the controller says we're busy */
|
||||
while (flash_is_busy(bank))
|
||||
continue;
|
||||
/* Pull back if any errors occured and return accordingly */
|
||||
return !(REBASE(FLASH_SR) & FLASH_SR_ERROR_MASK);
|
||||
}
|
||||
|
||||
bool flash_is_locked(const enum flash_bank bank)
|
||||
{
|
||||
const uintptr_t bank_base_address = flash_bank_address(bank);
|
||||
return REBASE(FLASH_CR) & FLASH_CR_LOCK;
|
||||
}
|
||||
|
||||
void flash_unlock(const enum flash_bank bank)
|
||||
{
|
||||
const uintptr_t bank_base_address = flash_bank_address(bank);
|
||||
/* Authorize the FPEC access. */
|
||||
REBASE(FLASH_KEYR) = FLASH_KEYR_KEY1;
|
||||
REBASE(FLASH_KEYR) = FLASH_KEYR_KEY2;
|
||||
}
|
||||
|
||||
void flash_lock(const enum flash_bank bank)
|
||||
{
|
||||
const uintptr_t bank_base_address = flash_bank_address(bank);
|
||||
REBASE(FLASH_CR) |= FLASH_CR_LOCK;
|
||||
}
|
||||
|
||||
void flash_erase_sector(const enum flash_bank bank, const uint8_t sector, const uint8_t operation_parallelism)
|
||||
{
|
||||
const uintptr_t bank_base_address = flash_bank_address(bank);
|
||||
const enum device_variant variant = mcu_variant();
|
||||
/* Reset the bottom control register bits ready for the new operation */
|
||||
REBASE(FLASH_CR) &= ~FLASH_CR_OP_MASK;
|
||||
/* H7Bx does not have write parallelism bits */
|
||||
if (variant != STM32H7Bx)
|
||||
flash_set_program_size(bank_base_address, operation_parallelism);
|
||||
/*
|
||||
* The control register layout is dependant on the variant.
|
||||
* Set up the sector erase operation and then kick it off.
|
||||
*/
|
||||
switch (variant) {
|
||||
case STM32H7Bx:
|
||||
REBASE(FLASH_CR) |= FLASH_CR_SER | (sector << FLASH_CR_H7Bx_SNB_SHIFT);
|
||||
REBASE(FLASH_CR) |= FLASH_CR_H7Bx_STRT;
|
||||
break;
|
||||
default:
|
||||
REBASE(FLASH_CR) |= FLASH_CR_SER | (sector << FLASH_CR_SNB_SHIFT);
|
||||
REBASE(FLASH_CR) |= FLASH_CR_STRT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void flash_erase_bank(const enum flash_bank bank, const uint8_t operation_parallelism)
|
||||
{
|
||||
const uintptr_t bank_base_address = flash_bank_address(bank);
|
||||
const enum device_variant variant = mcu_variant();
|
||||
/* Reset the bottom control register bits ready for the new operation */
|
||||
REBASE(FLASH_CR) &= ~FLASH_CR_OP_MASK;
|
||||
/* H7Bx does not have write parallelism bits */
|
||||
if (variant != STM32H7Bx)
|
||||
flash_set_program_size(bank_base_address, operation_parallelism);
|
||||
/*
|
||||
* The control register layout is dependant on the variant.
|
||||
* Set up the bank erase operation and then kick it off.
|
||||
* NB: per §4.3.10 "Standard flash bank erase sequence" of RM0433 rev8, pg166
|
||||
* setting BER and start can be merged.
|
||||
*/
|
||||
switch (variant) {
|
||||
case STM32H7Bx:
|
||||
REBASE(FLASH_CR) |= FLASH_CR_BER | FLASH_CR_H7Bx_STRT;
|
||||
break;
|
||||
default:
|
||||
REBASE(FLASH_CR) |= FLASH_CR_BER | FLASH_CR_STRT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void flash_program_enable(const enum flash_bank bank, const uint8_t operation_parallelism)
|
||||
{
|
||||
const uintptr_t bank_base_address = flash_bank_address(bank);
|
||||
const enum device_variant variant = mcu_variant();
|
||||
/* Reset the bottom control register bits ready for the new operation */
|
||||
REBASE(FLASH_CR) &= ~FLASH_CR_OP_MASK;
|
||||
/* H7Bx does not have write parallelism bits */
|
||||
if (variant != STM32H7Bx)
|
||||
flash_set_program_size(bank_base_address, operation_parallelism);
|
||||
REBASE(FLASH_CR) |= FLASH_CR_PG;
|
||||
}
|
||||
|
||||
void flash_program_disable(const enum flash_bank bank)
|
||||
{
|
||||
const uintptr_t bank_base_address = flash_bank_address(bank);
|
||||
REBASE(FLASH_CR) &= ~FLASH_CR_PG;
|
||||
}
|
||||
|
||||
bool flash_program_byte(const uintptr_t address, const uint8_t data)
|
||||
{
|
||||
const enum flash_bank bank = flash_bank_from_address(address);
|
||||
flash_program_enable(bank, FLASH_CR_PROGRAM_X8);
|
||||
MMIO8(address) = data;
|
||||
flash_program_force(bank);
|
||||
return flash_wait_for_last_operation(bank);
|
||||
}
|
||||
|
||||
bool flash_program_half_word(const uintptr_t address, const uint16_t data)
|
||||
{
|
||||
const enum flash_bank bank = flash_bank_from_address(address);
|
||||
flash_program_enable(bank, FLASH_CR_PROGRAM_X16);
|
||||
MMIO16(address) = data;
|
||||
flash_program_force(bank);
|
||||
return flash_wait_for_last_operation(bank);
|
||||
}
|
||||
|
||||
bool flash_program_word(const uintptr_t address, const uint32_t data)
|
||||
{
|
||||
const enum flash_bank bank = flash_bank_from_address(address);
|
||||
flash_program_enable(bank, FLASH_CR_PROGRAM_X32);
|
||||
MMIO32(address) = data;
|
||||
flash_program_force(bank);
|
||||
return flash_wait_for_last_operation(bank);
|
||||
}
|
||||
|
||||
bool flash_program_double_word(const uintptr_t address, const uint64_t data)
|
||||
{
|
||||
const enum flash_bank bank = flash_bank_from_address(address);
|
||||
flash_program_enable(bank, FLASH_CR_PROGRAM_X64);
|
||||
MMIO64(address) = data;
|
||||
flash_program_force(bank);
|
||||
return flash_wait_for_last_operation(bank);
|
||||
}
|
||||
|
||||
bool flash_program(const uintptr_t address, const uint8_t *const data, const size_t len)
|
||||
{
|
||||
/* Begin operations */
|
||||
const enum flash_bank bank = flash_bank_from_address(address);
|
||||
const uintptr_t bank_base_address = flash_bank_address(bank);
|
||||
const enum device_variant variant = mcu_variant();
|
||||
flash_program_enable(bank, FLASH_CR_PROGRAM_X64);
|
||||
/* If the address to write does not start on a write block boundary, write out what we have and force write it */
|
||||
size_t offset = address & FLASH_WRITE_BLOCK_MASK;
|
||||
if (offset != 0U) {
|
||||
/* Figure out the amount of data that needs written to complete the block */
|
||||
const size_t amount = MIN(len, FLASH_WRITE_BLOCK_SIZE - offset);
|
||||
memcpy((void *)address, data, amount);
|
||||
flash_program_force(bank);
|
||||
if (!flash_wait_for_last_operation(bank))
|
||||
return false;
|
||||
offset = amount;
|
||||
/* Having completed the forced write, reset the FW bit */
|
||||
switch (variant) {
|
||||
case STM32H7Bx:
|
||||
REBASE(FLASH_CR) &= FLASH_CR_H7Bx_FW;
|
||||
break;
|
||||
default:
|
||||
REBASE(FLASH_CR) &= FLASH_CR_FW;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Now write out as many complete blocks as we have */
|
||||
for (; len - offset >= FLASH_WRITE_BLOCK_SIZE; offset += FLASH_WRITE_BLOCK_SIZE) {
|
||||
memcpy((void *)(address + offset), data + offset, FLASH_WRITE_BLOCK_SIZE);
|
||||
if (!flash_wait_for_last_operation(bank))
|
||||
return false;
|
||||
}
|
||||
/* Finally, figure out if we've got anything left to write, and flush that out too */
|
||||
const size_t amount = len - offset;
|
||||
if (amount != 0U) {
|
||||
memcpy((void *)(address + offset), data + offset, amount);
|
||||
flash_program_force(bank);
|
||||
if (!flash_wait_for_last_operation(bank))
|
||||
return false;
|
||||
/* Having completed the forced write, reset the FW bit */
|
||||
switch (variant) {
|
||||
case STM32H7Bx:
|
||||
REBASE(FLASH_CR) &= FLASH_CR_H7Bx_FW;
|
||||
break;
|
||||
default:
|
||||
REBASE(FLASH_CR) &= FLASH_CR_FW;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* We're done, clean up the enable bit and return success */
|
||||
flash_program_disable(bank);
|
||||
return true;
|
||||
}
|
||||
|
||||
void flash_program_force(const enum flash_bank bank)
|
||||
{
|
||||
const uintptr_t bank_base_address = flash_bank_address(bank);
|
||||
const enum device_variant variant = mcu_variant();
|
||||
/*
|
||||
* The control register layout is dependant on the variant.
|
||||
* Set the FW bit appropriately to force the write operation that's already been set up.
|
||||
*/
|
||||
switch (variant) {
|
||||
case STM32H7Bx:
|
||||
REBASE(FLASH_CR) |= FLASH_CR_H7Bx_FW;
|
||||
break;
|
||||
default:
|
||||
REBASE(FLASH_CR) |= FLASH_CR_FW;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void flash_unlock_option_bytes(void)
|
||||
{
|
||||
FLASH_OPTKEYR = FLASH_OPTKEYR_KEY1;
|
||||
FLASH_OPTKEYR = FLASH_OPTKEYR_KEY2;
|
||||
}
|
||||
|
||||
void flash_lock_option_bytes(void)
|
||||
{
|
||||
FLASH_OPTCR |= FLASH_OPTCR_OPTLOCK;
|
||||
}
|
||||
@@ -189,13 +189,8 @@ void rcc_clock_setup_pll(const struct rcc_pll_config *config) {
|
||||
pwr_set_mode(config->power_mode, config->smps_level);
|
||||
pwr_set_vos_scale(config->voltage_scale);
|
||||
|
||||
/* Set flash waitstates. Enable flash prefetch if we have at least 1WS */
|
||||
/* Set flash waitstates. H7 doesn't support prefetch, so nothing to do WRT this. */
|
||||
flash_set_ws(config->flash_waitstates);
|
||||
if (config->flash_waitstates > FLASH_ACR_LATENCY_0WS) {
|
||||
flash_prefetch_enable();
|
||||
} else {
|
||||
flash_prefetch_disable();
|
||||
}
|
||||
|
||||
/* User has specified an external oscillator, make sure we turn it on. */
|
||||
if (config->hse_frequency > 0) {
|
||||
|
||||
Reference in New Issue
Block a user