drivers: flash: Add xmc4xxx flash drivers
Add xmc4xxx flash drivers. Signed-off-by: Andriy Gelman <andriy.gelman@gmail.com>
This commit is contained in:
parent
2c22d7c63b
commit
072a428f78
13 changed files with 271 additions and 3 deletions
|
@ -36,6 +36,30 @@
|
||||||
zephyr,flash = &flash0;
|
zephyr,flash = &flash0;
|
||||||
zephyr,console = &usic1ch1;
|
zephyr,console = &usic1ch1;
|
||||||
zephyr,shell-uart = &usic1ch1;
|
zephyr,shell-uart = &usic1ch1;
|
||||||
|
zephyr,flash-controller = &flash_controller;
|
||||||
|
zephyr,code-partition = &code_partition;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
&flash_controller {
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&flash0 {
|
||||||
|
partitions {
|
||||||
|
compatible = "fixed-partitions";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
code_partition: partition@0 {
|
||||||
|
reg = <0x0 0x80000>;
|
||||||
|
read-only;
|
||||||
|
};
|
||||||
|
|
||||||
|
storage_partition: partition@80000 {
|
||||||
|
label = "storage";
|
||||||
|
reg = <0x80000 0x80000>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -14,3 +14,4 @@ CONFIG_SERIAL=y
|
||||||
# enable console
|
# enable console
|
||||||
CONFIG_CONSOLE=y
|
CONFIG_CONSOLE=y
|
||||||
CONFIG_UART_CONSOLE=y
|
CONFIG_UART_CONSOLE=y
|
||||||
|
CONFIG_USE_DT_CODE_PARTITION=y
|
||||||
|
|
|
@ -28,6 +28,7 @@ zephyr_library_sources_ifdef(CONFIG_FLASH_MCUX_FLEXSPI_HYPERFLASH flash_mcux_fle
|
||||||
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_ESP32 flash_esp32.c)
|
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_ESP32 flash_esp32.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SMARTBOND flash_smartbond.c)
|
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SMARTBOND flash_smartbond.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_FLASH_CAD_QSPI_NOR flash_cadence_qspi_nor.c flash_cadence_qspi_nor_ll.c)
|
zephyr_library_sources_ifdef(CONFIG_FLASH_CAD_QSPI_NOR flash_cadence_qspi_nor.c flash_cadence_qspi_nor_ll.c)
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_XMC4XXX soc_flash_xmc4xxx.c)
|
||||||
|
|
||||||
if(CONFIG_FLASH_MCUX_FLEXSPI_XIP)
|
if(CONFIG_FLASH_MCUX_FLEXSPI_XIP)
|
||||||
dt_chosen(chosen_flash PROPERTY "zephyr,flash")
|
dt_chosen(chosen_flash PROPERTY "zephyr,flash")
|
||||||
|
|
|
@ -110,4 +110,6 @@ source "drivers/flash/Kconfig.cadence_qspi_nor"
|
||||||
|
|
||||||
source "drivers/flash/Kconfig.gd32"
|
source "drivers/flash/Kconfig.gd32"
|
||||||
|
|
||||||
|
source "drivers/flash/Kconfig.xmc4xxx"
|
||||||
|
|
||||||
endif # FLASH
|
endif # FLASH
|
||||||
|
|
11
drivers/flash/Kconfig.xmc4xxx
Normal file
11
drivers/flash/Kconfig.xmc4xxx
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# Copyright (c) 2022 Schlumberger
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
config SOC_FLASH_XMC4XXX
|
||||||
|
bool "XMC4XXX flash driver"
|
||||||
|
default y
|
||||||
|
depends on DT_HAS_INFINEON_XMC4XXX_FLASH_CONTROLLER_ENABLED
|
||||||
|
select FLASH_HAS_PAGE_LAYOUT
|
||||||
|
select FLASH_HAS_DRIVER_ENABLED
|
||||||
|
help
|
||||||
|
Enables XMC4XXX flash driver.
|
197
drivers/flash/soc_flash_xmc4xxx.c
Normal file
197
drivers/flash/soc_flash_xmc4xxx.c
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Schlumberger
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DT_DRV_COMPAT infineon_xmc4xxx_flash_controller
|
||||||
|
|
||||||
|
#define FLASH_WRITE_BLK_SZ DT_PROP(DT_INST(0, infineon_xmc4xxx_nv_flash), write_block_size)
|
||||||
|
|
||||||
|
#include <zephyr/device.h>
|
||||||
|
#include <zephyr/drivers/flash.h>
|
||||||
|
|
||||||
|
#include <xmc_flash.h>
|
||||||
|
|
||||||
|
struct flash_xmc4xxx_data {
|
||||||
|
struct k_sem sem;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct flash_xmc4xxx_config {
|
||||||
|
uint32_t base;
|
||||||
|
uint32_t size;
|
||||||
|
struct flash_parameters parameters;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline bool is_aligned_32(uint32_t data)
|
||||||
|
{
|
||||||
|
return (data & 0x3) ? false : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int flash_xmc4xxx_init(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct flash_xmc4xxx_data *dev_data = dev->data;
|
||||||
|
|
||||||
|
k_sem_init(&dev_data->sem, 1, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SET_PAGES(node_id) \
|
||||||
|
{.pages_count = DT_PROP(node_id, pages_count), .pages_size = DT_PROP(node_id, pages_size)},
|
||||||
|
|
||||||
|
#if CONFIG_FLASH_PAGE_LAYOUT
|
||||||
|
static const struct flash_pages_layout flash_xmc4xxx_pages_layout[] = {
|
||||||
|
DT_FOREACH_CHILD(DT_NODELABEL(pages_layout), SET_PAGES)};
|
||||||
|
|
||||||
|
static void flash_xmc4xxx_page_layout(const struct device *dev,
|
||||||
|
const struct flash_pages_layout **layout, size_t *layout_size)
|
||||||
|
{
|
||||||
|
*layout = &flash_xmc4xxx_pages_layout[0];
|
||||||
|
*layout_size = ARRAY_SIZE(flash_xmc4xxx_pages_layout);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int flash_xmc4xxx_read(const struct device *dev, off_t offset, void *data, size_t len)
|
||||||
|
{
|
||||||
|
const struct flash_xmc4xxx_config *dev_config = dev->config;
|
||||||
|
|
||||||
|
if (offset < 0 || offset + len > dev_config->size) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memcpy(data, (void *)(dev_config->base + offset), len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __aligned(4) uint8_t
|
||||||
|
aligned_page[DT_PROP(DT_INST(0, infineon_xmc4xxx_nv_flash), write_block_size)];
|
||||||
|
|
||||||
|
static int flash_xmc4xxx_write(const struct device *dev, off_t offset, const void *data, size_t len)
|
||||||
|
{
|
||||||
|
struct flash_xmc4xxx_data *dev_data = dev->data;
|
||||||
|
const struct flash_xmc4xxx_config *dev_config = dev->config;
|
||||||
|
uint32_t irq_key;
|
||||||
|
uint32_t flash_addr = dev_config->base;
|
||||||
|
const uint8_t *src = data;
|
||||||
|
int num_pages;
|
||||||
|
|
||||||
|
if (offset < 0 || offset + len > dev_config->size) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len % dev_config->parameters.write_block_size ||
|
||||||
|
offset % dev_config->parameters.write_block_size > 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
k_sem_take(&dev_data->sem, K_FOREVER);
|
||||||
|
|
||||||
|
/* erase and write operations must be on the uncached base address */
|
||||||
|
flash_addr |= 0xc000000;
|
||||||
|
flash_addr += offset;
|
||||||
|
|
||||||
|
num_pages = len / dev_config->parameters.write_block_size;
|
||||||
|
for (int i = 0; i < num_pages; i++) {
|
||||||
|
uint32_t *src_ptr = (uint32_t *)src;
|
||||||
|
|
||||||
|
/* XMC_FLASH_ProgramPage() needs a 32 bit aligned input. */
|
||||||
|
/* Copy the data to an aligned array if needed. */
|
||||||
|
if (!is_aligned_32((uint32_t)src)) {
|
||||||
|
memcpy(aligned_page, src, dev_config->parameters.write_block_size);
|
||||||
|
src_ptr = (uint32_t *)aligned_page;
|
||||||
|
}
|
||||||
|
|
||||||
|
irq_key = irq_lock();
|
||||||
|
XMC_FLASH_ProgramPage((uint32_t *)flash_addr, src_ptr);
|
||||||
|
irq_unlock(irq_key);
|
||||||
|
flash_addr += dev_config->parameters.write_block_size;
|
||||||
|
src += dev_config->parameters.write_block_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
k_sem_give(&dev_data->sem);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CONFIG_FLASH_PAGE_LAYOUT
|
||||||
|
static int flash_xmc4xxx_erase(const struct device *dev, off_t offset, size_t size)
|
||||||
|
{
|
||||||
|
struct flash_xmc4xxx_data *dev_data = dev->data;
|
||||||
|
const struct flash_xmc4xxx_config *dev_config = dev->config;
|
||||||
|
uint32_t irq_key;
|
||||||
|
uint32_t offset_page = 0;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (offset < 0 || offset > dev_config->size) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
k_sem_take(&dev_data->sem, K_FOREVER);
|
||||||
|
|
||||||
|
for (int i = 0; i < ARRAY_SIZE(flash_xmc4xxx_pages_layout); i++) {
|
||||||
|
for (int k = 0; k < flash_xmc4xxx_pages_layout[i].pages_count; k++) {
|
||||||
|
uint32_t pages_size = flash_xmc4xxx_pages_layout[i].pages_size;
|
||||||
|
/* erase and write operations must be on the uncached base address */
|
||||||
|
uint32_t flash_addr = dev_config->base | 0xc000000;
|
||||||
|
|
||||||
|
if (offset == offset_page && size >= pages_size) {
|
||||||
|
flash_addr += offset;
|
||||||
|
irq_key = irq_lock();
|
||||||
|
XMC_FLASH_EraseSector((uint32_t *)flash_addr);
|
||||||
|
irq_unlock(irq_key);
|
||||||
|
|
||||||
|
size -= pages_size;
|
||||||
|
offset += pages_size;
|
||||||
|
}
|
||||||
|
offset_page += pages_size;
|
||||||
|
|
||||||
|
if (size == 0) {
|
||||||
|
ret = 0;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* page not aligned with offset address */
|
||||||
|
if (offset_page > offset) {
|
||||||
|
ret = -1;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
finish:
|
||||||
|
k_sem_give(&dev_data->sem);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static int flash_xmc4xxx_erase(const struct device *dev, off_t offset, size_t size)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(dev);
|
||||||
|
ARG_UNUSED(offset);
|
||||||
|
ARG_UNUSED(size);
|
||||||
|
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const struct flash_parameters *flash_xmc4xxx_get_parameters(const struct device *dev)
|
||||||
|
{
|
||||||
|
const struct flash_xmc4xxx_config *dev_config = dev->config;
|
||||||
|
|
||||||
|
return &dev_config->parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct flash_driver_api flash_xmc4xxx_api = {.erase = flash_xmc4xxx_erase,
|
||||||
|
.write = flash_xmc4xxx_write,
|
||||||
|
.read = flash_xmc4xxx_read,
|
||||||
|
#ifdef CONFIG_FLASH_PAGE_LAYOUT
|
||||||
|
.page_layout = flash_xmc4xxx_page_layout,
|
||||||
|
#endif
|
||||||
|
.get_parameters =
|
||||||
|
flash_xmc4xxx_get_parameters};
|
||||||
|
|
||||||
|
static struct flash_xmc4xxx_data flash_xmc4xxx_data_0;
|
||||||
|
static struct flash_xmc4xxx_config flash_xmc4xxx_cfg_0 = {
|
||||||
|
.base = DT_REG_ADDR(DT_INST(0, infineon_xmc4xxx_nv_flash)),
|
||||||
|
.size = DT_REG_SIZE(DT_INST(0, infineon_xmc4xxx_nv_flash)),
|
||||||
|
.parameters = {.write_block_size = FLASH_WRITE_BLK_SZ, .erase_value = 0}};
|
||||||
|
|
||||||
|
DEVICE_DT_INST_DEFINE(0, flash_xmc4xxx_init, NULL, &flash_xmc4xxx_data_0, &flash_xmc4xxx_cfg_0,
|
||||||
|
POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY, &flash_xmc4xxx_api);
|
|
@ -22,6 +22,20 @@
|
||||||
|
|
||||||
&flash0 {
|
&flash0 {
|
||||||
reg = <0xc000000 DT_SIZE_M(1)>;
|
reg = <0xc000000 DT_SIZE_M(1)>;
|
||||||
|
pages_layout: pages_layout {
|
||||||
|
pages_layout_16k: pages_layout_16k {
|
||||||
|
pages-count = <8>;
|
||||||
|
pages-size = <DT_SIZE_K(16)>;
|
||||||
|
};
|
||||||
|
pages_layout_128k: pages_layout_128k {
|
||||||
|
pages-count = <1>;
|
||||||
|
pages-size = <DT_SIZE_K(128)>;
|
||||||
|
};
|
||||||
|
pages_layout_256k: pages_layout_256k {
|
||||||
|
pages-count = <3>;
|
||||||
|
pages-size = <DT_SIZE_K(256)>;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
&gpio0 {
|
&gpio0 {
|
||||||
|
|
|
@ -33,8 +33,15 @@
|
||||||
compatible = "mmio-sram";
|
compatible = "mmio-sram";
|
||||||
};
|
};
|
||||||
|
|
||||||
flash0: serial-flash@c000000 {
|
flash_controller: flash_controller@58001000 {
|
||||||
compatible = "serial-flash";
|
compatible = "infineon,xmc4xxx-flash-controller";
|
||||||
|
reg = <0x58001000 0x1400>;
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
flash0: flash@c000000 {
|
||||||
|
compatible = "infineon,xmc4xxx-nv-flash","soc-nv-flash";
|
||||||
|
write-block-size = <256>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
sysclk: system-clock {
|
sysclk: system-clock {
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
description: XMC4XXX flash controller
|
||||||
|
|
||||||
|
compatible: "infineon,xmc4xxx-flash-controller"
|
||||||
|
|
||||||
|
include: flash-controller.yaml
|
|
@ -15,4 +15,8 @@ config HAS_XMCLIB_UART
|
||||||
help
|
help
|
||||||
Enable XMCLIB Universal asynchronous receiver transmitter (UART)
|
Enable XMCLIB Universal asynchronous receiver transmitter (UART)
|
||||||
|
|
||||||
|
config HAS_XMCLIB_FLASH
|
||||||
|
bool
|
||||||
|
help
|
||||||
|
Enable XMCLIB Flash
|
||||||
endif # HAS_XMCLIB
|
endif # HAS_XMCLIB
|
||||||
|
|
|
@ -13,5 +13,6 @@ config SOC_SERIES_XMC_4XXX
|
||||||
select CPU_HAS_ARM_MPU
|
select CPU_HAS_ARM_MPU
|
||||||
select CPU_HAS_FPU
|
select CPU_HAS_FPU
|
||||||
select HAS_XMCLIB_UART
|
select HAS_XMCLIB_UART
|
||||||
|
select HAS_XMCLIB_FLASH
|
||||||
help
|
help
|
||||||
Enable support for XMC 4xxx MCU series
|
Enable support for XMC 4xxx MCU series
|
||||||
|
|
1
tests/drivers/flash/boards/xmc45_relax_kit.conf
Normal file
1
tests/drivers/flash/boards/xmc45_relax_kit.conf
Normal file
|
@ -0,0 +1 @@
|
||||||
|
CONFIG_MPU_ALLOW_FLASH_WRITE=y
|
2
west.yml
2
west.yml
|
@ -73,7 +73,7 @@ manifest:
|
||||||
groups:
|
groups:
|
||||||
- hal
|
- hal
|
||||||
- name: hal_infineon
|
- name: hal_infineon
|
||||||
revision: 4af06965f57ba1e7d170e6a97d24c33785543a8c
|
revision: 5b0c7700a7be049e02835dfa0950d378aac39e67
|
||||||
path: modules/hal/infineon
|
path: modules/hal/infineon
|
||||||
groups:
|
groups:
|
||||||
- hal
|
- hal
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue