Browse Source
Initial version Signed-off-by: Sreeram Tatapudi <sreeram.praveen@infineon.com>pull/76425/head
14 changed files with 460 additions and 19 deletions
@ -0,0 +1,346 @@
@@ -0,0 +1,346 @@
|
||||
/*
|
||||
* Copyright 2024 Cypress Semiconductor Corporation (an Infineon company) or |
||||
* an affiliate of Cypress Semiconductor Corporation |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
|
||||
#define DT_DRV_COMPAT infineon_cat1_qspi_flash |
||||
#define SOC_NV_FLASH_NODE DT_PARENT(DT_INST(0, fixed_partitions)) |
||||
|
||||
#define PAGE_LEN DT_PROP(SOC_NV_FLASH_NODE, erase_block_size) |
||||
|
||||
#include <zephyr/kernel.h> |
||||
#include <zephyr/devicetree.h> |
||||
#include <zephyr/drivers/flash.h> |
||||
#include <zephyr/logging/log.h> |
||||
|
||||
#include "cy_serial_flash_qspi.h" |
||||
#include "cy_smif_memslot.h" |
||||
|
||||
LOG_MODULE_REGISTER(flash_infineon_cat1, CONFIG_FLASH_LOG_LEVEL); |
||||
|
||||
/* Device config structure */ |
||||
struct ifx_cat1_flash_config { |
||||
uint32_t base_addr; |
||||
uint32_t max_addr; |
||||
}; |
||||
|
||||
/* Data structure */ |
||||
struct ifx_cat1_flash_data { |
||||
cyhal_flash_t flash_obj; |
||||
struct k_sem sem; |
||||
}; |
||||
|
||||
static struct flash_parameters ifx_cat1_flash_parameters = { |
||||
.write_block_size = DT_PROP(SOC_NV_FLASH_NODE, write_block_size), |
||||
.erase_value = 0xFF, |
||||
}; |
||||
|
||||
cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_read_cmd = {0}; |
||||
|
||||
cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_write_en_cmd = {0}; |
||||
|
||||
cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_write_dis_cmd = {0}; |
||||
|
||||
cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_erase_cmd = {0}; |
||||
|
||||
cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_chip_erase_cmd = {0}; |
||||
|
||||
cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_program_cmd = {0}; |
||||
|
||||
cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_read_sts_reg_qe_cmd = {0}; |
||||
|
||||
cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_read_sts_reg_wip_cmd = {0}; |
||||
|
||||
cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_write_sts_reg_qe_cmd = {0}; |
||||
|
||||
cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_read_sts_reg_oe_cmd = {0}; |
||||
|
||||
cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_write_sts_reg_oe_cmd = {0}; |
||||
|
||||
cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_read_latency_cmd = {0}; |
||||
|
||||
cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_write_latency_cmd = {0}; |
||||
|
||||
cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_read_sfdp_cmd = { |
||||
/* The 8-bit command. 1 x I/O read command. */ |
||||
.command = 0x5AU, |
||||
/* The width of the command transfer. */ |
||||
.cmdWidth = CY_SMIF_WIDTH_SINGLE, |
||||
/* The width of the address transfer. */ |
||||
.addrWidth = CY_SMIF_WIDTH_SINGLE, |
||||
/* The 8-bit mode byte. This value is 0xFFFFFFFF when there is no mode present. */ |
||||
.mode = 0xFFFFFFFFU, |
||||
/* The width of the mode command transfer. */ |
||||
.modeWidth = CY_SMIF_WIDTH_SINGLE, |
||||
/* The number of dummy cycles. A zero value suggests no dummy cycles. */ |
||||
.dummyCycles = 8U, |
||||
/* The width of the data transfer. */ |
||||
.dataWidth = CY_SMIF_WIDTH_SINGLE, |
||||
}; |
||||
|
||||
cy_stc_smif_octal_ddr_en_seq_t oe_sequence_SFDP_SlaveSlot_0 = { |
||||
.cmdSeq1Len = CY_SMIF_SFDP_ODDR_CMD_SEQ_MAX_LEN, |
||||
.cmdSeq2Len = CY_SMIF_SFDP_ODDR_CMD_SEQ_MAX_LEN, |
||||
.cmdSeq1 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, |
||||
.cmdSeq2 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, |
||||
}; |
||||
|
||||
/* Support for memories with hybrid regions is added in the version 1.50
|
||||
* Please refer to the changelog in |
||||
* https://iot-webserver.aus.cypress.com/projects/iot_release/
|
||||
* ASSETS/repo/mtb-pdl-cat1/develop/Latest/deploy/docs/ |
||||
* pdl_api_reference_manual/html/group__group__smif.html |
||||
* for more details |
||||
*/ |
||||
#if (CY_SMIF_DRV_VERSION_MAJOR > 1) && (CY_SMIF_DRV_VERSION_MINOR >= 50) |
||||
static cy_stc_smif_hybrid_region_info_t sfdp_slave_slot_0_region_info_storage[16]; |
||||
|
||||
#define GENERATE_REGION_INFO_PTR(index, _) &sfdp_slave_slot_0_region_info_storage[index], |
||||
|
||||
static cy_stc_smif_hybrid_region_info_t *sfdp_slave_slot_0_region_info[16] = { |
||||
LISTIFY(16, GENERATE_REGION_INFO_PTR, ())}; |
||||
#endif |
||||
|
||||
cy_stc_smif_mem_device_cfg_t deviceCfg_SFDP_SlaveSlot_0 = { |
||||
/* Specifies the number of address bytes used by the memory slave device. */ |
||||
.numOfAddrBytes = 0x03U, |
||||
/* The size of the memory. */ |
||||
.memSize = 0x0000100U, |
||||
/* Specifies the Read command. */ |
||||
.readCmd = &sfdp_slave_slot_0_read_cmd, |
||||
/* Specifies the Write Enable command. */ |
||||
.writeEnCmd = &sfdp_slave_slot_0_write_en_cmd, |
||||
/* Specifies the Write Disable command. */ |
||||
.writeDisCmd = &sfdp_slave_slot_0_write_dis_cmd, |
||||
/* Specifies the Erase command. */ |
||||
.eraseCmd = &sfdp_slave_slot_0_erase_cmd, |
||||
/* Specifies the sector size of each erase. */ |
||||
.eraseSize = 0x0001000U, |
||||
/* Specifies the Chip Erase command. */ |
||||
.chipEraseCmd = &sfdp_slave_slot_0_chip_erase_cmd, |
||||
/* Specifies the Program command. */ |
||||
.programCmd = &sfdp_slave_slot_0_program_cmd, |
||||
/* Specifies the page size for programming. */ |
||||
.programSize = 0x0000100U, |
||||
/* Specifies the command to read the QE-containing status register. */ |
||||
.readStsRegQeCmd = &sfdp_slave_slot_0_read_sts_reg_qe_cmd, |
||||
/* Specifies the command to read the WIP-containing status register. */ |
||||
.readStsRegWipCmd = &sfdp_slave_slot_0_read_sts_reg_wip_cmd, |
||||
/* Specifies the read SFDP command */ |
||||
.readSfdpCmd = &sfdp_slave_slot_0_read_sfdp_cmd, |
||||
/* Specifies the command to write into the QE-containing status register. */ |
||||
.writeStsRegQeCmd = &sfdp_slave_slot_0_write_sts_reg_qe_cmd, |
||||
/* The mask for the status register. */ |
||||
.stsRegBusyMask = 0x00U, |
||||
/* The mask for the status register. */ |
||||
.stsRegQuadEnableMask = 0x00U, |
||||
/* The max time for the erase type-1 cycle-time in ms. */ |
||||
.eraseTime = 1U, |
||||
/* The max time for the chip-erase cycle-time in ms. */ |
||||
.chipEraseTime = 16U, |
||||
/* The max time for the page-program cycle-time in us. */ |
||||
.programTime = 8U, |
||||
#if (CY_SMIF_DRV_VERSION_MAJOR > 1) && (CY_SMIF_DRV_VERSION_MINOR >= 50) |
||||
/* Points to NULL or to structure with info about sectors for hybrid memory. */ |
||||
.hybridRegionCount = 0U, |
||||
.hybridRegionInfo = sfdp_slave_slot_0_region_info, |
||||
#endif |
||||
/* Specifies the command to read variable latency cycles configuration register */ |
||||
.readLatencyCmd = &sfdp_slave_slot_0_read_latency_cmd, |
||||
/* Specifies the command to write variable latency cycles configuration register */ |
||||
.writeLatencyCmd = &sfdp_slave_slot_0_write_latency_cmd, |
||||
/* Specifies the address for variable latency cycle address */ |
||||
.latencyCyclesRegAddr = 0x00U, |
||||
/* Specifies variable latency cycles Mask */ |
||||
.latencyCyclesMask = 0x00U, |
||||
/* Specifies data for memory with hybrid sectors */ |
||||
.octalDDREnableSeq = &oe_sequence_SFDP_SlaveSlot_0, |
||||
/* Specifies the command to read the OE-containing status register. */ |
||||
.readStsRegOeCmd = &sfdp_slave_slot_0_read_sts_reg_oe_cmd, |
||||
/* Specifies the command to write the OE-containing status register. */ |
||||
.writeStsRegOeCmd = &sfdp_slave_slot_0_write_sts_reg_oe_cmd, |
||||
/* QE mask for the status registers */ |
||||
.stsRegOctalEnableMask = 0x00U, |
||||
/* Octal enable register address */ |
||||
.octalEnableRegAddr = 0x00U, |
||||
/* Frequency of operation used in Octal mode */ |
||||
.freq_of_operation = CY_SMIF_100MHZ_OPERATION, |
||||
}; |
||||
|
||||
cy_stc_smif_mem_config_t sfdp_slave_slot_0 = { |
||||
/* Determines the slot number where the memory device is placed. */ |
||||
.slaveSelect = CY_SMIF_SLAVE_SELECT_0, |
||||
/* Flags. */ |
||||
.flags = CY_SMIF_FLAG_SMIF_REV_3 | CY_SMIF_FLAG_MEMORY_MAPPED | CY_SMIF_FLAG_WR_EN | |
||||
CY_SMIF_FLAG_DETECT_SFDP | CY_SMIF_FLAG_MERGE_ENABLE, |
||||
/* The data-line selection options for a slave device. */ |
||||
.dataSelect = CY_SMIF_DATA_SEL0, |
||||
/* The base address the memory slave
|
||||
* Valid when the memory-mapped mode is enabled. |
||||
*/ |
||||
.baseAddress = 0x60000000U, |
||||
/* The size allocated in the memory map, for the memory slave device.
|
||||
* The size is allocated from the base address. Valid when the memory mapped mode is |
||||
* enabled. |
||||
*/ |
||||
.memMappedSize = 0x100000U, |
||||
/* If this memory device is one of the devices in the dual quad SPI configuration.
|
||||
* Valid when the memory mapped mode is enabled. |
||||
*/ |
||||
.dualQuadSlots = 0, |
||||
/* The configuration of the device. */ |
||||
.deviceCfg = &deviceCfg_SFDP_SlaveSlot_0, |
||||
/** Continuous transfer merge timeout.
|
||||
* After this period the memory device is deselected. A later transfer, even from a |
||||
* continuous address, starts with the overhead phases (command, address, mode, dummy |
||||
* cycles). This configuration parameter is available for CAT1B devices. |
||||
*/ |
||||
.mergeTimeout = CY_SMIF_MERGE_TIMEOUT_1_CYCLE, |
||||
}; |
||||
|
||||
static inline void flash_ifx_sem_take(const struct device *dev) |
||||
{ |
||||
struct ifx_cat1_flash_data *data = dev->data; |
||||
|
||||
k_sem_take(&data->sem, K_FOREVER); |
||||
} |
||||
|
||||
static inline void flash_ifx_sem_give(const struct device *dev) |
||||
{ |
||||
struct ifx_cat1_flash_data *data = dev->data; |
||||
|
||||
k_sem_give(&data->sem); |
||||
} |
||||
|
||||
static int ifx_cat1_flash_read(const struct device *dev, off_t offset, void *data, size_t data_len) |
||||
{ |
||||
cy_rslt_t rslt = CY_RSLT_SUCCESS; |
||||
int ret = 0; |
||||
|
||||
if (!data_len) { |
||||
return 0; |
||||
} |
||||
|
||||
flash_ifx_sem_take(dev); |
||||
|
||||
rslt = cy_serial_flash_qspi_read(offset, data_len, data); |
||||
if (rslt != CY_RSLT_SUCCESS) { |
||||
LOG_ERR("Error reading @ %lu (Err:0x%x)", offset, rslt); |
||||
ret = -EIO; |
||||
} |
||||
|
||||
flash_ifx_sem_give(dev); |
||||
return ret; |
||||
} |
||||
|
||||
static int ifx_cat1_flash_write(const struct device *dev, off_t offset, const void *data, |
||||
size_t data_len) |
||||
{ |
||||
cy_rslt_t rslt = CY_RSLT_SUCCESS; |
||||
int ret = 0; |
||||
|
||||
if (data_len == 0) { |
||||
return 0; |
||||
} |
||||
|
||||
if (offset < 0) { |
||||
return -EINVAL; |
||||
} |
||||
|
||||
flash_ifx_sem_take(dev); |
||||
|
||||
rslt = cy_serial_flash_qspi_write(offset, data_len, data); |
||||
if (rslt != CY_RSLT_SUCCESS) { |
||||
LOG_ERR("Error in writing @ %lu (Err:0x%x)", offset, rslt); |
||||
ret = -EIO; |
||||
} |
||||
|
||||
flash_ifx_sem_give(dev); |
||||
return ret; |
||||
} |
||||
|
||||
static int ifx_cat1_flash_erase(const struct device *dev, off_t offset, size_t size) |
||||
{ |
||||
cy_rslt_t rslt; |
||||
int ret = 0; |
||||
|
||||
if (offset < 0) { |
||||
return -EINVAL; |
||||
} |
||||
|
||||
flash_ifx_sem_take(dev); |
||||
|
||||
rslt = cy_serial_flash_qspi_erase(offset, size); |
||||
if (rslt != CY_RSLT_SUCCESS) { |
||||
LOG_ERR("Error in erasing : 0x%x", rslt); |
||||
ret = -EIO; |
||||
} |
||||
|
||||
flash_ifx_sem_give(dev); |
||||
return ret; |
||||
} |
||||
|
||||
#if CONFIG_FLASH_PAGE_LAYOUT |
||||
static const struct flash_pages_layout ifx_cat1_flash_pages_layout = { |
||||
.pages_count = DT_REG_SIZE(SOC_NV_FLASH_NODE) / PAGE_LEN, |
||||
.pages_size = PAGE_LEN, |
||||
}; |
||||
|
||||
static void ifx_cat1_flash_page_layout(const struct device *dev, |
||||
const struct flash_pages_layout **layout, |
||||
size_t *layout_size) |
||||
{ |
||||
*layout = &ifx_cat1_flash_pages_layout; |
||||
|
||||
/*
|
||||
* For flash memories which have uniform page sizes, this routine |
||||
* returns an array of length 1, which specifies the page size and |
||||
* number of pages in the memory. |
||||
*/ |
||||
*layout_size = 1; |
||||
} |
||||
#endif /* CONFIG_FLASH_PAGE_LAYOUT */ |
||||
|
||||
static const struct flash_parameters *ifx_cat1_flash_get_parameters(const struct device *dev) |
||||
{ |
||||
ARG_UNUSED(dev); |
||||
|
||||
return &ifx_cat1_flash_parameters; |
||||
} |
||||
|
||||
static int ifx_cat1_flash_init(const struct device *dev) |
||||
{ |
||||
struct ifx_cat1_flash_data *data = dev->data; |
||||
cy_rslt_t rslt = CY_RSLT_SUCCESS; |
||||
|
||||
rslt = cy_serial_flash_qspi_init(&sfdp_slave_slot_0, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, |
||||
50000000lu); |
||||
if (rslt != CY_RSLT_SUCCESS) { |
||||
LOG_ERR("Serial Flash initialization failed [rslt: 0x%x]", rslt); |
||||
} |
||||
|
||||
k_sem_init(&data->sem, 1, 1); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static const struct flash_driver_api ifx_cat1_flash_driver_api = { |
||||
.read = ifx_cat1_flash_read, |
||||
.write = ifx_cat1_flash_write, |
||||
.erase = ifx_cat1_flash_erase, |
||||
.get_parameters = ifx_cat1_flash_get_parameters, |
||||
#ifdef CONFIG_FLASH_PAGE_LAYOUT |
||||
.page_layout = ifx_cat1_flash_page_layout, |
||||
#endif |
||||
}; |
||||
|
||||
static struct ifx_cat1_flash_data flash_data; |
||||
|
||||
static const struct ifx_cat1_flash_config flash_config = { |
||||
.base_addr = DT_REG_ADDR(SOC_NV_FLASH_NODE), |
||||
.max_addr = DT_REG_ADDR(SOC_NV_FLASH_NODE) + DT_REG_SIZE(SOC_NV_FLASH_NODE)}; |
||||
|
||||
DEVICE_DT_INST_DEFINE(0, ifx_cat1_flash_init, NULL, &flash_data, &flash_config, POST_KERNEL, |
||||
CONFIG_FLASH_INIT_PRIORITY, &ifx_cat1_flash_driver_api); |
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
description: Infineon CAT1 QSPI flash controller |
||||
|
||||
compatible: "infineon,cat1-qspi-flash" |
||||
|
||||
include: flash-controller.yaml |
@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
|
||||
# Copyright (c) 2024 Cypress Semiconductor Corporation (an Infineon company) or |
||||
# an affiliate of Cypress Semiconductor Corporation |
||||
# |
||||
# SPDX-License-Identifier: Apache-2.0 |
||||
|
||||
set(serial_flash_dir ${ZEPHYR_HAL_INFINEON_MODULE_DIR}/serial-flash) |
||||
|
||||
zephyr_include_directories(${serial_flash_dir}) |
||||
|
||||
zephyr_library_sources(${serial_flash_dir}/cy_serial_flash_qspi.c) |
Loading…
Reference in new issue