Commit 77d071da authored by Stoyan Bogdanov's avatar Stoyan Bogdanov Committed by Benjamin Cabé
Browse files

drivers: flash: Add support for cc23x0 flash



Add support for flash to cc23x0 SoC. The driver interacts with VIMS
(Versatile Instruction Memory System) internal bus standing before NVM.

Signed-off-by: default avatarStoyan Bogdanov <sbogdanov@baylibre.com>
Signed-off-by: default avatarJulien Panis <jpanis@baylibre.com>
parent c634d502
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ zephyr_library_sources_ifdef(CONFIG_FLASH_STM32_XSPI flash_stm32_xspi.c)
zephyr_library_sources_ifdef(CONFIG_INFINEON_CAT1_QSPI_FLASH flash_ifx_cat1_qspi.c)
zephyr_library_sources_ifdef(CONFIG_NORDIC_QSPI_NOR nrf_qspi_nor.c)
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_CC13XX_CC26XX soc_flash_cc13xx_cc26xx.c)
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_CC23X0 soc_flash_cc23x0.c)
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_ESP32 flash_esp32.c)
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_GECKO flash_gecko.c)
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_ITE_IT8XXX2 flash_ite_it8xxx2.c)
+1 −0
Original line number Diff line number Diff line
@@ -171,6 +171,7 @@ source "drivers/flash/Kconfig.b91"
source "drivers/flash/Kconfig.cadence_nand"
source "drivers/flash/Kconfig.cadence_qspi_nor"
source "drivers/flash/Kconfig.cc13xx_cc26xx"
source "drivers/flash/Kconfig.cc23x0"
source "drivers/flash/Kconfig.esp32"
source "drivers/flash/Kconfig.gd32"
source "drivers/flash/Kconfig.gecko"
+14 −0
Original line number Diff line number Diff line
# Copyright (c) 2024 Texas Instruments Incorporated
# Copyright (c) 2024 BayLibre, SAS
#
# SPDX-License-Identifier: Apache-2.0

config SOC_FLASH_CC23X0
	bool "TI SimpleLink CC23x0 flash controller driver"
	default y
	depends on DT_HAS_TI_CC23X0_FLASH_CONTROLLER_ENABLED
	select FLASH_HAS_PAGE_LAYOUT
	select FLASH_HAS_DRIVER_ENABLED
	select MPU_ALLOW_FLASH_WRITE if ARM_MPU
	help
	  Enables TI SimpleLink CC23x0 flash controller driver.
+239 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2024 Texas Instruments Incorporated
 * Copyright (c) 2024 BayLibre, SAS
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr/device.h>
#include <zephyr/drivers/flash.h>
#include <zephyr/irq.h>
#include <zephyr/kernel.h>
#include <string.h>

#include <driverlib/flash.h>
#include <driverlib/vims.h>

#define DT_DRV_COMPAT     ti_cc23x0_flash_controller
#define SOC_NV_FLASH_NODE DT_INST(0, soc_nv_flash)

#define FLASH_ADDR       DT_REG_ADDR(SOC_NV_FLASH_NODE)
#define FLASH_SIZE       DT_REG_SIZE(SOC_NV_FLASH_NODE)
#define FLASH_ERASE_SIZE DT_PROP(SOC_NV_FLASH_NODE, erase_block_size)
#define FLASH_WRITE_SIZE DT_PROP(SOC_NV_FLASH_NODE, write_block_size)

struct flash_cc23x0_data {
	struct k_sem mutex;
};

static const struct flash_parameters flash_cc23x0_parameters = {
	.write_block_size = FLASH_WRITE_SIZE,
	.erase_value = 0xff,
};

static int flash_cc23x0_init(const struct device *dev)
{
	struct flash_cc23x0_data *data = dev->data;

	k_sem_init(&data->mutex, 1, 1);

	return 0;
}

static void flash_cc23x0_cache_restore(uint32_t vims_mode)
{
	while (VIMSModeGet(VIMS_BASE) == VIMS_MODE_CHANGING) {
		;
	}

	/* Restore VIMS mode and line buffers */
	if (vims_mode != VIMS_MODE_DISABLED) {
		VIMSModeSafeSet(VIMS_BASE, vims_mode, true);
	}

	VIMSLineBufEnable(VIMS_BASE);
}

static uint32_t flash_cc23x0_cache_disable(void)
{
	uint32_t vims_mode;

	/* VIMS and both line buffers should be off during flash update */
	VIMSLineBufDisable(VIMS_BASE);

	while (VIMSModeGet(VIMS_BASE) == VIMS_MODE_CHANGING) {
		;
	}

	/* Save current VIMS mode for restoring it later */
	vims_mode = VIMSModeGet(VIMS_BASE);
	if (vims_mode != VIMS_MODE_DISABLED) {
		VIMSModeSafeSet(VIMS_BASE, VIMS_MODE_DISABLED, true);
	}

	return vims_mode;
}

static int flash_cc23x0_erase(const struct device *dev, off_t offs, size_t size)
{
	struct flash_cc23x0_data *data = dev->data;
	uint32_t vims_mode;
	unsigned int key;
	int i;
	int rc = 0;
	size_t cnt;

	if (!size) {
		return 0;
	}

	/* Offset and length should be multiple of erase size */
	if (((offs % FLASH_ERASE_SIZE) != 0) || ((size % FLASH_ERASE_SIZE) != 0)) {
		return -EINVAL;
	}

	if (k_sem_take(&data->mutex, K_FOREVER)) {
		return -EACCES;
	}

	vims_mode = flash_cc23x0_cache_disable();
	/*
	 * Disable all interrupts to prevent flash read, from TI's TRF:
	 *
	 * During a FLASH memory write or erase operation, the FLASH memory
	 * must not be read.
	 */
	key = irq_lock();

	/* Erase sector/page one by one, break out in case of an error */
	cnt = size / FLASH_ERASE_SIZE;
	for (i = 0; i < cnt; i++, offs += FLASH_ERASE_SIZE) {
		while (FlashCheckFsmForReady() != FAPI_STATUS_FSM_READY) {
			;
		}

		rc = FlashEraseSector(offs);
		if (rc != FAPI_STATUS_SUCCESS) {
			rc = -EIO;
			break;
		}
	}

	irq_unlock(key);

	flash_cc23x0_cache_restore(vims_mode);

	k_sem_give(&data->mutex);
	return rc;
}

static int flash_cc23x0_write(const struct device *dev, off_t offs, const void *data, size_t size)
{
	struct flash_cc23x0_data *flash_data = dev->data;
	uint32_t vims_mode;
	unsigned int key;
	int rc = 0;

	if (!size) {
		return 0;
	}

	if (offs < 0 || size < 1) {
		return -EINVAL;
	}

	if (offs + size > FLASH_SIZE) {
		return -EINVAL;
	}

	/*
	 * From TI's HAL 'driverlib/flash.h':
	 *
	 * The pui8DataBuffer pointer can not point to flash.
	 */
	if ((data >= (void *)FLASH_ADDR) && (data <= (void *)(FLASH_ADDR + FLASH_SIZE))) {
		return -EINVAL;
	}

	if (k_sem_take(&flash_data->mutex, K_FOREVER)) {
		return -EACCES;
	}

	vims_mode = flash_cc23x0_cache_disable();

	key = irq_lock();

	while (FlashCheckFsmForReady() != FAPI_STATUS_FSM_READY) {
		;
	}

	rc = FlashProgram((uint8_t *)data, offs, size);
	if (rc != FAPI_STATUS_SUCCESS) {
		rc = -EIO;
	}

	irq_unlock(key);

	flash_cc23x0_cache_restore(vims_mode);

	k_sem_give(&flash_data->mutex);

	return rc;
}

static int flash_cc23x0_read(const struct device *dev, off_t offs, void *data, size_t size)
{
	ARG_UNUSED(dev);

	if (!size) {
		return 0;
	}

	if (offs < 0 || size < 1) {
		return -EINVAL;
	}

	if (offs + size > FLASH_SIZE) {
		return -EINVAL;
	}

	memcpy(data, (void *)offs, size);

	return 0;
}

static const struct flash_parameters *flash_cc23x0_get_parameters(const struct device *dev)
{
	ARG_UNUSED(dev);

	return &flash_cc23x0_parameters;
}

#if defined(CONFIG_FLASH_PAGE_LAYOUT)
static const struct flash_pages_layout dev_layout = {
	.pages_count = FLASH_SIZE / FLASH_ERASE_SIZE,
	.pages_size = FLASH_ERASE_SIZE,
};

static void flash_cc23x0_layout(const struct device *dev, const struct flash_pages_layout **layout,
				size_t *layout_size)
{
	*layout = &dev_layout;
	*layout_size = 1;
}
#endif /* CONFIG_FLASH_PAGE_LAYOUT */

static const struct flash_driver_api flash_cc23x0_api = {
	.erase = flash_cc23x0_erase,
	.write = flash_cc23x0_write,
	.read = flash_cc23x0_read,
	.get_parameters = flash_cc23x0_get_parameters,
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
	.page_layout = flash_cc23x0_layout,
#endif
};

static struct flash_cc23x0_data cc23x0_flash_data;

DEVICE_DT_INST_DEFINE(0, flash_cc23x0_init, NULL, &cc23x0_flash_data, NULL, POST_KERNEL,
		      CONFIG_FLASH_INIT_PRIORITY, &flash_cc23x0_api);
+5 −0
Original line number Diff line number Diff line
description: Texas Instruments CC23X0 flash controller

compatible: "ti,cc23x0-flash-controller"

include: flash-controller.yaml