Boot Linux faster!

Check our new training course

Boot Linux faster!

Check our new training course
and Creative Commons CC-BY-SA
lecture and lab materials

Bootlin logo

Elixir Cross Referencer

/*
 * Copyright (c) 2016 RnDity Sp. z o.o.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <clock_control/stm32_clock_control.h>
#include <misc/__assert.h>
#include <string.h>

#include "flash_stm32f3x.h"

void flash_stm32_unlock(struct device *flash)
{
	const struct flash_stm32_dev_config *config = FLASH_CFG(flash);

	volatile struct stm32_flash *reg = FLASH_STRUCT(config->base);

	if ((reg->cr & FLASH_CR_LOCK) != 0) {
		/* Authorize the FLASH Registers access */
		reg->keyr = FLASH_KEY1;
		reg->keyr = FLASH_KEY2;
	}
}

void flash_stm32_lock(struct device *flash)
{
	const struct flash_stm32_dev_config *config = FLASH_CFG(flash);

	volatile struct stm32_flash *reg = FLASH_STRUCT(config->base);

	reg->cr |= FLASH_CR_LOCK;
}

uint8_t flash_stm32_program_halfword(struct device *flash,
				     uint32_t address,
				     uint16_t data)
{
	uint8_t status = FLASH_COMPLETE;

	const struct flash_stm32_dev_config *config = FLASH_CFG(flash);

	volatile struct stm32_flash *reg = FLASH_STRUCT(config->base);

	__ASSERT_NO_MSG(IS_FLASH_PROGRAM_ADDRESS(address));

	status = flash_stm32_wait_for_last_operation(flash,
			FLASH_ER_PRG_TIMEOUT);

	if (status == FLASH_COMPLETE) {
		reg->cr |= FLASH_CR_PG;

		*(volatile uint16_t *)address = data;

		status = flash_stm32_wait_for_last_operation(flash,
				FLASH_ER_PRG_TIMEOUT);

		reg->cr &= ~FLASH_CR_PG;
	}

	return status;
}

uint8_t flash_stm32_program_word(struct device *flash,
				 uint32_t address,
				 uint32_t data)
{
	uint8_t status = FLASH_COMPLETE;

	const struct flash_stm32_dev_config *config = FLASH_CFG(flash);

	volatile struct stm32_flash *reg = FLASH_STRUCT(config->base);

	__ASSERT_NO_MSG(IS_FLASH_PROGRAM_ADDRESS(address));

	status = flash_stm32_wait_for_last_operation(flash,
			FLASH_ER_PRG_TIMEOUT);

	if (status == FLASH_COMPLETE) {
		reg->cr |= FLASH_CR_PG;

		*(volatile uint16_t *)address = (uint16_t)data;

		status = flash_stm32_wait_for_last_operation(flash,
				FLASH_ER_PRG_TIMEOUT);

		if (status == FLASH_COMPLETE) {
			address += 2;

			*(volatile uint16_t *)address = data >> 16;

			status = flash_stm32_wait_for_last_operation(flash,
					FLASH_ER_PRG_TIMEOUT);
		}

		reg->cr &= ~FLASH_CR_PG;
	}

	return status;
}

uint8_t flash_stm32_wait_for_last_operation(struct device *flash,
					    uint32_t timeout)
{
	uint8_t status = FLASH_COMPLETE;

	/* Check for the FLASH Status */
	status = flash_stm32_get_status(flash);

	/* Wait for a FLASH operation to complete or a TIMEOUT to occur. */
	while ((status == FLASH_BUSY) && (timeout != 0x00)) {
		status = flash_stm32_get_status(flash);
		timeout--;
	}

	if (timeout == 0x00) {
		status = FLASH_TIMEOUT;
	}

	return status;
}

uint8_t flash_stm32_get_status(struct device *flash)
{
	uint8_t status = FLASH_COMPLETE;

	const struct flash_stm32_dev_config *config = FLASH_CFG(flash);

	volatile struct stm32_flash *reg = FLASH_STRUCT(config->base);

	do {
		if ((reg->sr & FLASH_SR_BSY) == FLASH_SR_BSY) {
			status = FLASH_BUSY;
			break;
		}

		if ((reg->sr & FLASH_SR_WRPERR) != (uint32_t)0x00) {
			status = FLASH_ERROR_WRITE_PROTECTION;
			break;
		}

		if ((reg->sr & FLASH_SR_PGERR) != (uint32_t)0x00) {
			status = FLASH_ERROR_PROGRAM;
			break;
		}
	} while (0);

	return status;
}

uint8_t flash_stm32_erase_page(struct device *flash,
			       uint32_t page_address)
{
	uint8_t status = FLASH_COMPLETE;

	const struct flash_stm32_dev_config *config = FLASH_CFG(flash);

	volatile struct stm32_flash *reg = FLASH_STRUCT(config->base);

	__ASSERT_NO_MSG(IS_FLASH_PROGRAM_ADDRESS(page_address));

	status = flash_stm32_wait_for_last_operation(flash,
			FLASH_ER_PRG_TIMEOUT);

	if (status == FLASH_COMPLETE) {
		reg->cr |= FLASH_CR_PER;
		reg->ar = page_address;
		reg->cr |= FLASH_CR_STRT;

		status = flash_stm32_wait_for_last_operation(flash,
				FLASH_ER_PRG_TIMEOUT);

		reg->cr &= ~FLASH_CR_PER;
	}

	return status;
}

uint8_t flash_stm32_erase_all_pages(struct device *flash)
{
	uint8_t status = FLASH_COMPLETE;

	const struct flash_stm32_dev_config *config = FLASH_CFG(flash);

	volatile struct stm32_flash *reg = FLASH_STRUCT(config->base);

	status = flash_stm32_wait_for_last_operation(flash,
			FLASH_ER_PRG_TIMEOUT);

	if (status == FLASH_COMPLETE) {
		reg->cr |= FLASH_CR_MER;
		reg->cr |= FLASH_CR_STRT;

		status = flash_stm32_wait_for_last_operation(flash,
				FLASH_ER_PRG_TIMEOUT);

		reg->cr &= ~FLASH_CR_MER;
	}

	return status;
}

void flash_stm32_read_data(void *data, uint32_t address, size_t len)
{
	uint8_t *addr = INT_TO_POINTER(address);

	memcpy(data, addr, len);
}