From 623e799d631a3f57b0c9611346099e911c67c38a Mon Sep 17 00:00:00 2001 From: Dustin Crossman Date: Tue, 25 May 2021 14:51:14 -0700 Subject: [PATCH] Update serial-flash to 1.1.0.20805 --- .../common/cy_serial_flash_prog.c | 98 -- .../common/cy_serial_flash_qspi.c | 234 ----- .../common/{ => serial-flash}/LICENSE | 0 .../serial-flash/cy_serial_flash_prog.c | 97 ++ .../serial-flash/cy_serial_flash_qspi.c | 868 ++++++++++++++++++ .../{ => serial-flash}/cy_serial_flash_qspi.h | 148 ++- .../common/serial-flash/version.xml | 1 + .../TARGET_PSOC6/common/version.xml | 1 - 8 files changed, 1082 insertions(+), 365 deletions(-) delete mode 100644 targets/TARGET_Cypress/TARGET_PSOC6/common/cy_serial_flash_prog.c delete mode 100644 targets/TARGET_Cypress/TARGET_PSOC6/common/cy_serial_flash_qspi.c rename targets/TARGET_Cypress/TARGET_PSOC6/common/{ => serial-flash}/LICENSE (100%) mode change 100644 => 100755 create mode 100755 targets/TARGET_Cypress/TARGET_PSOC6/common/serial-flash/cy_serial_flash_prog.c create mode 100755 targets/TARGET_Cypress/TARGET_PSOC6/common/serial-flash/cy_serial_flash_qspi.c rename targets/TARGET_Cypress/TARGET_PSOC6/common/{ => serial-flash}/cy_serial_flash_qspi.h (52%) mode change 100644 => 100755 create mode 100755 targets/TARGET_Cypress/TARGET_PSOC6/common/serial-flash/version.xml delete mode 100644 targets/TARGET_Cypress/TARGET_PSOC6/common/version.xml diff --git a/targets/TARGET_Cypress/TARGET_PSOC6/common/cy_serial_flash_prog.c b/targets/TARGET_Cypress/TARGET_PSOC6/common/cy_serial_flash_prog.c deleted file mode 100644 index c5f547fafa..0000000000 --- a/targets/TARGET_Cypress/TARGET_PSOC6/common/cy_serial_flash_prog.c +++ /dev/null @@ -1,98 +0,0 @@ -/***************************************************************************//** -* \file cy_serial_flash_prog.c -* -* \brief -* Provides variables necessary to inform programming tools how to program the -* attached serial flash memory. The variables used here must be placed at -* specific locations in order to be detected and used by programming tools -* to know that there is an attached memory and its characteristics. Uses the -* configuration provided as part of BSP. -* -******************************************************************************** -* \copyright -* Copyright 2018-2020 Cypress Semiconductor Corporation -* SPDX-License-Identifier: Apache-2.0 -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*******************************************************************************/ - -/** -* \addtogroup group_board_libs -* \{ -* In addition to the APIs for reading and writting to memory at runtime, this library also -* provides support for informing programming tools about the external memory so it can be -* be written at the same time as internal flash. This support can be enabled by defining -* CY_ENABLE_XIP_PROGRAM while building the application. With this define in place, code -* will be generated in the .cy_sflash_user_data & .cy_toc_part2 sections. These locations -* can be read by programming tools (eg: Cypress Programmer, OpenOCD, pyOCD) to know that -* there is a memory device attached and how to program it. -* \} group_board_libs -*/ - -#include - -#if defined(__cplusplus) -extern "C" { -#endif - -#if defined(CY_ENABLE_XIP_PROGRAM) - -#include "cycfg_qspi_memslot.h" - -typedef struct -{ - const cy_stc_smif_block_config_t * smifCfg; /* Pointer to SMIF top-level configuration */ - const uint32_t null_t; /* NULL termination */ -} stc_smif_ipblocks_arr_t; - -/* - * This data can be placed anywhere in the internal memory, but it must be at a location that - * can be determined and used for the calculation of the CRC16 checksum in the cyToc below. There - * are multiple ways this can be accomplished including: - * 1) Placing it in a dedicated memory block with a known address. (as done here) - * 2) Placing it at an absolute location via a the linker script - * 3) Using 'cymcuelftool -S' to recompute the checksum and patch the elf file after linking - */ -CY_SECTION(".cy_sflash_user_data") __attribute__( (used) ) -const stc_smif_ipblocks_arr_t smifIpBlocksArr = {&smifBlockConfig, 0x00000000}; - -/* - * This data is used to populate the table of contents part 2. When present, it is used by the boot - * process and programming tools to determine key characteristics about the memory usage including - * where the boot process should start the application from and what external memories are connected - * (if any). This must consume a full row of flash memory row. The last entry is a checksum of the - * other values in the ToC which must be updated if any other value changes. This can be done manually - * or by running 'cymcuelftool -S' to recompute the checksum. - */ -CY_SECTION(".cy_toc_part2") __attribute__( (used) ) -const uint32_t cyToc[128] = -{ - 0x200-4, /* Offset=0x0000: Object Size, bytes */ - 0x01211220, /* Offset=0x0004: Magic Number (TOC Part 2, ID) */ - 0, /* Offset=0x0008: Key Storage Address */ - (int)&smifIpBlocksArr, /* Offset=0x000C: This points to a null terminated array of SMIF structures. */ - 0x10000000u, /* Offset=0x0010: App image start address */ - /* Offset=0x0014-0x01F7: Reserved */ - [126] = 0x000002C2, /* Offset=0x01F8: Bits[ 1: 0] CLOCK_CONFIG (0=8MHz, 1=25MHz, 2=50MHz, 3=100MHz) - Bits[ 4: 2] LISTEN_WINDOW (0=20ms, 1=10ms, 2=1ms, 3=0ms, 4=100ms) - Bits[ 6: 5] SWJ_PINS_CTL (0/1/3=Disable SWJ, 2=Enable SWJ) - Bits[ 8: 7] APP_AUTHENTICATION (0/2/3=Enable, 1=Disable) - Bits[10: 9] FB_BOOTLOADER_CTL: UNUSED */ - [127] = 0x3BB30000 /* Offset=0x01FC: CRC16-CCITT (the upper 2 bytes contain the CRC and the lower 2 bytes are 0) */ -}; - -#endif /* defined(CY_ENABLE_XIP_PROGRAM) */ - -#if defined(__cplusplus) -} -#endif diff --git a/targets/TARGET_Cypress/TARGET_PSOC6/common/cy_serial_flash_qspi.c b/targets/TARGET_Cypress/TARGET_PSOC6/common/cy_serial_flash_qspi.c deleted file mode 100644 index 945f5af283..0000000000 --- a/targets/TARGET_Cypress/TARGET_PSOC6/common/cy_serial_flash_qspi.c +++ /dev/null @@ -1,234 +0,0 @@ -/***************************************************************************//** -* \file cy_serial_flash_qspi.c -* -* \brief -* Provides APIs for interacting with an external flash connected to the SPI or -* QSPI interface, uses SFDP to auto-discover memory properties if SFDP is -* enabled in the configuration. -* -******************************************************************************** -* \copyright -* Copyright 2018-2020 Cypress Semiconductor Corporation -* SPDX-License-Identifier: Apache-2.0 -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*******************************************************************************/ - -#include -#include "cy_serial_flash_qspi.h" -#include "cyhal_qspi.h" -#include "cy_utils.h" - -#ifdef CY_IP_MXSMIF - -#if defined(__cplusplus) -extern "C" { -#endif - - -/** \cond INTERNAL */ - -/** Timeout to apply while polling the memory for its ready status after quad - * enable command has been sent out. Quad enable is a non-volatile write. -*/ -#define CY_SERIAL_FLASH_QUAD_ENABLE_TIMEOUT_US (5000lu) /* in microseconds */ - -/* Number of memories supported by the driver */ -#define SMIF_MEM_DEVICES (1u) - -/* SMIF slot from which the memory configuration is picked up - fixed to 0 as the driver - * supports only one device */ -#define MEM_SLOT (0u) - -/** \endcond */ - -static cyhal_qspi_t qspi_obj; - -static cy_stc_smif_mem_config_t * qspi_mem_config[SMIF_MEM_DEVICES]; - -static cy_stc_smif_block_config_t qspi_block_config = -{ - /* The number of SMIF memories defined. */ - .memCount = SMIF_MEM_DEVICES, - /* The pointer to the array of memory config structures of size memCount. */ - .memConfig = (cy_stc_smif_mem_config_t**)qspi_mem_config, - /* The version of the SMIF driver. */ - .majorVersion = CY_SMIF_DRV_VERSION_MAJOR, - /* The version of the SMIF driver. */ - .minorVersion = CY_SMIF_DRV_VERSION_MINOR -}; - -/* The driver supports only one memory. When multiple memory configurations - * are generated by the SMIF configurator tool, provide only the - * configuration for memory that need to be supported by the driver. - * Memory configuration can be changed by deinit followed by init with new - * configuration */ -cy_rslt_t cy_serial_flash_qspi_init( - const cy_stc_smif_mem_config_t* mem_config, - cyhal_gpio_t io0, - cyhal_gpio_t io1, - cyhal_gpio_t io2, - cyhal_gpio_t io3, - cyhal_gpio_t io4, - cyhal_gpio_t io5, - cyhal_gpio_t io6, - cyhal_gpio_t io7, - cyhal_gpio_t sclk, - cyhal_gpio_t ssel, - uint32_t hz) -{ - cy_en_smif_status_t smifStatus = CY_SMIF_SUCCESS; - - - cy_rslt_t result = cyhal_qspi_init(&qspi_obj, io0, io1, io2, io3, io4, io5, io6, io7, - sclk, ssel, hz, 0); - - qspi_mem_config[MEM_SLOT] = (cy_stc_smif_mem_config_t*) mem_config; - - if(CY_RSLT_SUCCESS == result) - { - /* Perform SFDP detection and XIP register configuration depending on the - * memory configuration. - */ - smifStatus = Cy_SMIF_MemInit(qspi_obj.base, &qspi_block_config, &qspi_obj.context); - if(CY_SMIF_SUCCESS == smifStatus) - { - /* Enable Quad mode (1-1-4 or 1-4-4 modes) to use all the four I/Os during - * communication. - */ - - if(qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->readCmd->dataWidth == CY_SMIF_WIDTH_QUAD - || qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->programCmd->dataWidth == CY_SMIF_WIDTH_QUAD) - { - bool isQuadEnabled = false; - smifStatus = Cy_SMIF_MemIsQuadEnabled(qspi_obj.base, qspi_block_config.memConfig[MEM_SLOT], &isQuadEnabled, &qspi_obj.context); - if(CY_SMIF_SUCCESS == smifStatus) - { - if(!isQuadEnabled) - { - smifStatus = Cy_SMIF_MemEnableQuadMode(qspi_obj.base, qspi_block_config.memConfig[MEM_SLOT], CY_SERIAL_FLASH_QUAD_ENABLE_TIMEOUT_US, &qspi_obj.context); - } - } - } - } - } - - if((CY_RSLT_SUCCESS != result) || (CY_SMIF_SUCCESS != smifStatus)) - { - cy_serial_flash_qspi_deinit(); - - if(CY_SMIF_SUCCESS != smifStatus) - { - result = (cy_rslt_t)smifStatus; - } - } - - return result; -} - -void cy_serial_flash_qspi_deinit(void) -{ - if (qspi_obj.base != NULL) - { - Cy_SMIF_MemDeInit(qspi_obj.base); - } - - cyhal_qspi_free(&qspi_obj); -} - -size_t cy_serial_flash_qspi_get_size(void) -{ - return (size_t)qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->memSize; -} - -/* address is ignored for the memory with uniform sector size. Currently, - * QSPI Configurator does not support memories with hybrid sectors. - */ -size_t cy_serial_flash_qspi_get_erase_size(uint32_t addr) -{ - CY_UNUSED_PARAMETER(addr); - return (size_t)qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->eraseSize; -} - -size_t cy_serial_flash_qspi_get_prog_size(uint32_t addr) -{ - CY_UNUSED_PARAMETER(addr); - return (size_t)qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->programSize; -} - -cy_rslt_t cy_serial_flash_qspi_read(uint32_t addr, size_t length, uint8_t *buf) -{ - /* Cy_SMIF_MemRead() returns error if (addr + length) > total flash size. */ - return (cy_rslt_t)Cy_SMIF_MemRead(qspi_obj.base, qspi_block_config.memConfig[MEM_SLOT], addr, buf, length, &qspi_obj.context); -} - -cy_rslt_t cy_serial_flash_qspi_write(uint32_t addr, size_t length, const uint8_t *buf) -{ - /* Cy_SMIF_MemWrite() returns error if (addr + length) > total flash size. */ - return (cy_rslt_t)Cy_SMIF_MemWrite(qspi_obj.base, qspi_block_config.memConfig[MEM_SLOT], addr, (uint8_t *)buf, length, &qspi_obj.context); -} - -/* Does not support hybrid sectors, sector size must be uniform on the entire - * chip. Use cy_serial_flash_qspi_get_erase_size(addr) to implement hybrid sector - * support when QSPI Configurator and PDL supports memories with hybrid sectors. - */ -cy_rslt_t cy_serial_flash_qspi_erase(uint32_t addr, size_t length) -{ - cy_en_smif_status_t smifStatus; - - /* If the erase is for the entire chip, use chip erase command */ - if((addr == 0u) && (length == cy_serial_flash_qspi_get_size())) - { - smifStatus = Cy_SMIF_MemEraseChip(qspi_obj.base, qspi_block_config.memConfig[MEM_SLOT], &qspi_obj.context); - } - else - { - /* Cy_SMIF_MemEraseSector() returns error if (addr + length) > total flash size - * or if addr is not aligned to erase sector size or if (addr + length) - * is not aligned to erase sector size. - */ - smifStatus = Cy_SMIF_MemEraseSector(qspi_obj.base, qspi_block_config.memConfig[MEM_SLOT], addr, length, &qspi_obj.context); - } - - return (cy_rslt_t)smifStatus; -} - -// This function enables or disables XIP on the MCU, does not send any command -// to the serial flash. XIP register configuration is already done as part of -// cy_serial_flash_qspi_init() if MMIO mode is enabled in the QSPI -// Configurator. -cy_rslt_t cy_serial_flash_qspi_enable_xip(bool enable) -{ - if(enable) - { - Cy_SMIF_SetMode(qspi_obj.base, CY_SMIF_MEMORY); - } - else - { - Cy_SMIF_SetMode(qspi_obj.base, CY_SMIF_NORMAL); - } - - return CY_RSLT_SUCCESS; -} - -void cy_serial_flash_qspi_set_interrupt_priority(uint8_t priority) -{ - NVIC_SetPriority(smif_interrupt_IRQn, priority); -} - -#if defined(__cplusplus) -} -#endif - -#endif /* CY_IP_MXSMIF */ - diff --git a/targets/TARGET_Cypress/TARGET_PSOC6/common/LICENSE b/targets/TARGET_Cypress/TARGET_PSOC6/common/serial-flash/LICENSE old mode 100644 new mode 100755 similarity index 100% rename from targets/TARGET_Cypress/TARGET_PSOC6/common/LICENSE rename to targets/TARGET_Cypress/TARGET_PSOC6/common/serial-flash/LICENSE diff --git a/targets/TARGET_Cypress/TARGET_PSOC6/common/serial-flash/cy_serial_flash_prog.c b/targets/TARGET_Cypress/TARGET_PSOC6/common/serial-flash/cy_serial_flash_prog.c new file mode 100755 index 0000000000..d499acb592 --- /dev/null +++ b/targets/TARGET_Cypress/TARGET_PSOC6/common/serial-flash/cy_serial_flash_prog.c @@ -0,0 +1,97 @@ +/***********************************************************************************************//** + * \file cy_serial_flash_prog.c + * + * \brief + * Provides variables necessary to inform programming tools how to program the + * attached serial flash memory. The variables used here must be placed at + * specific locations in order to be detected and used by programming tools + * to know that there is an attached memory and its characteristics. Uses the + * configuration provided as part of BSP. + * + *************************************************************************************************** + * \copyright + * Copyright 2018-2021 Cypress Semiconductor Corporation + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **************************************************************************************************/ + +/** + * \addtogroup group_board_libs + * \{ + * In addition to the APIs for reading and writting to memory at runtime, this library also + * provides support for informing programming tools about the external memory so it can be + * be written at the same time as internal flash. This support can be enabled by defining + * CY_ENABLE_XIP_PROGRAM while building the application. With this define in place, code + * will be generated in the .cy_sflash_user_data & .cy_toc_part2 sections. These locations + * can be read by programming tools (eg: Cypress Programmer, OpenOCD, pyOCD) to know that + * there is a memory device attached and how to program it. + * \} group_board_libs + */ + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(CY_ENABLE_XIP_PROGRAM) + +#include "cycfg_qspi_memslot.h" + +typedef struct +{ + const cy_stc_smif_block_config_t* smifCfg; // Pointer to SMIF top-level configuration + const uint32_t null_t; // NULL termination +} stc_smif_ipblocks_arr_t; + +// This data can be placed anywhere in the internal memory, but it must be at a location that +// can be determined and used for the calculation of the CRC16 checksum in the cyToc below. There +// are multiple ways this can be accomplished including: +// 1) Placing it in a dedicated memory block with a known address. (as done here) +// 2) Placing it at an absolute location via a the linker script +// 3) Using 'cymcuelftool -S' to recompute the checksum and patch the elf file after linking +CY_SECTION(".cy_sflash_user_data") __attribute__((used)) +const stc_smif_ipblocks_arr_t smifIpBlocksArr = { &smifBlockConfig, 0x00000000 }; + +// This data is used to populate the table of contents part 2. When present, it is used by the boot +// process and programming tools to determine key characteristics about the memory usage including +// where the boot process should start the application from and what external memories are connected +// (if any). This must consume a full row of flash memory row. The last entry is a checksum of the +// other values in the ToC which must be updated if any other value changes. This can be done +// manually or by running 'cymcuelftool -S' to recompute the checksum. +CY_SECTION(".cy_toc_part2") __attribute__((used)) +const uint32_t cyToc[128] = +{ + 0x200-4, // Offset=0x0000: Object Size, bytes + 0x01211220, // Offset=0x0004: Magic Number (TOC Part 2, ID) + 0, // Offset=0x0008: Key Storage Address + (int)&smifIpBlocksArr, // Offset=0x000C: This points to a null terminated array of SMIF + // structures. + 0x10000000u, // Offset=0x0010: App image start address + // Offset=0x0014-0x01F7: Reserved + [126] = 0x000002C2, // Offset=0x01 + // Bits[ 1: 0] CLOCK_CONFIG (0=8MHz, 1=25MHz, 2=50MHz, 3=100MHz) + // Bits[ 4: 2] LISTEN_WINDOW (0=20ms, 1=10ms, 2=1ms, 3=0ms, 4=100ms) + // Bits[ 6: 5] SWJ_PINS_CTL (0/1/3=Disable SWJ, 2=Enable SWJ) + // Bits[ 8: 7] APP_AUTHENTICATION (0/2/3=Enable, 1=Disable) + // Bits[10: 9] FB_BOOTLOADER_CTL: UNUSED + [127] = 0x3BB30000 // Offset=0x01FC: CRC16-CCITT + // (the upper 2 bytes contain the CRC and the lower 2 bytes are 0) +}; + +#endif // defined(CY_ENABLE_XIP_PROGRAM) + +#if defined(__cplusplus) +} +#endif diff --git a/targets/TARGET_Cypress/TARGET_PSOC6/common/serial-flash/cy_serial_flash_qspi.c b/targets/TARGET_Cypress/TARGET_PSOC6/common/serial-flash/cy_serial_flash_qspi.c new file mode 100755 index 0000000000..19bc4de3e1 --- /dev/null +++ b/targets/TARGET_Cypress/TARGET_PSOC6/common/serial-flash/cy_serial_flash_qspi.c @@ -0,0 +1,868 @@ +/***********************************************************************************************//** + * \file cy_serial_flash_qspi.c + * + * \brief + * Provides APIs for interacting with an external flash connected to the SPI or + * QSPI interface, uses SFDP to auto-discover memory properties if SFDP is + * enabled in the configuration. + * + *************************************************************************************************** + * \copyright + * Copyright 2018-2021 Cypress Semiconductor Corporation + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **************************************************************************************************/ + +#include +#include "cy_serial_flash_qspi.h" +#include "cyhal_qspi.h" +#include "cy_trigmux.h" +#include "cy_dma.h" +#include "cy_utils.h" + +#if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE) +#include +#include "cyabs_rtos.h" +#endif /* #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE) */ + +#ifdef CY_IP_MXSMIF + +#if defined(__cplusplus) +extern "C" { +#endif + + +/** \cond INTERNAL */ + +/** Timeout to apply while polling the memory for its ready status after quad + * enable command has been sent out. Quad enable is a non-volatile write. + */ +#define CY_SERIAL_FLASH_QUAD_ENABLE_TIMEOUT_US (5000lu) // in microseconds + +/** Number of loops to run while polling the SMIF for its busy status. */ +#define SMIF_BUSY_CHECK_LOOP_COUNT (10lu) + +/** Timeout to apply per loop while polling the SMIF for its busy status. */ +#define SMIF_BUSY_CHECK_TIMEOUT_MS (1lu) // in milliseconds + +// Number of memories supported by the driver +#define SMIF_MEM_DEVICES (1u) + +// SMIF slot from which the memory configuration is picked up - fixed to 0 as +// the driver supports only one device +#define MEM_SLOT (0u) + +/* Maximum number of bytes that can be read by SMIF in one transfer */ +#define SMIF_MAX_RX_COUNT (65536lu) + +#define DMA_YCOUNT_ONE_LOOP (1lu) + +#define MSB_SHIFT_EIGHT (0x08u) +#define LSB_MASK (0xFFlu) + +/* Masks used for checking the flag bits */ +#define FLAG_QSPI_HAL_INIT_DONE (0x01lu << 0) +#define FLAG_DMA_INIT_DONE (0x01lu << 1) +#define FLAG_READ_IN_PROGRESS (0x01lu << 2) + +#define IS_FLAG_SET(mask) (status_flags & (mask)) +#define SET_FLAG(mask) (status_flags |= (mask)) +#define CLEAR_FLAG(mask) (status_flags &= ~(mask)) + +#if defined(CY_DEVICE_PSOC6ABLE2) +/* You cannot simply change these values. The trigger mux connect code in + * _init_dma() needs to be updated correspondingly. + */ + #define RX_DMA_INSTANCE DW1 + #define RX_DMA_CHANNEL_NUM (15lu) + #define RX_DMA_CH0_IRQn (cpuss_interrupts_dw1_0_IRQn) +#elif defined(CY_DEVICE_PSOC6A2M) || defined(CY_DEVICE_PSOC6A512K) || defined(CY_DEVICE_PSOC6256K) +/* In these devices, only 1to1 triggers are available between SMIF and a + * specific combination of DW instances and channel numbers. + * i.e. TX trigger request from SMIF can connect only to DW1 CH22 and + * RX trigger request from SMIF can connect only to DW1 CH23. + */ + #define RX_DMA_INSTANCE DW1 + #define RX_DMA_CHANNEL_NUM (23lu) + #define RX_DMA_CH0_IRQn (cpuss_interrupts_dw1_0_IRQn) + + #define DEVICE_GROUP_1TO1_TRIGGER +#else // if defined(CY_DEVICE_PSOC6ABLE2) + #define DMA_UNSUPPORTED +#endif // if defined(CY_DEVICE_PSOC6ABLE2) + +#define DMA_CHANNEL_PRIORITY (3lu) +#define DMA_INTR_PRIORITY (7lu) + +/** \endcond */ + +static cyhal_qspi_t qspi_obj; +static volatile uint32_t status_flags; +static cy_stc_smif_mem_config_t* qspi_mem_config[SMIF_MEM_DEVICES]; + +static cy_stc_smif_block_config_t qspi_block_config = +{ + // The number of SMIF memories defined. + .memCount = SMIF_MEM_DEVICES, + // The pointer to the array of memory config structures of size memCount. + .memConfig = (cy_stc_smif_mem_config_t**)qspi_mem_config, + // The version of the SMIF driver. + .majorVersion = CY_SMIF_DRV_VERSION_MAJOR, + // The version of the SMIF driver. + .minorVersion = CY_SMIF_DRV_VERSION_MINOR +}; + +#if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE) +static cy_mutex_t serial_flash_mutex; +#endif /* #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE) */ + +#ifndef DMA_UNSUPPORTED +typedef struct +{ + uint32_t addr; + size_t length; + uint8_t* buf; + cy_serial_flash_qspi_read_complete_callback_t callback; + void* callback_arg; +} read_txfr_info_t; + +static read_txfr_info_t read_txfr_info; + +/* DMA related variables */ +static cy_stc_dma_descriptor_t dma_descr; + +/* Default DW descriptor config */ +static cy_stc_dma_descriptor_config_t dma_descr_config = +{ + .retrigger = CY_DMA_RETRIG_4CYC, + .interruptType = CY_DMA_DESCR, + .triggerOutType = CY_DMA_DESCR_CHAIN, + .channelState = CY_DMA_CHANNEL_ENABLED, + .triggerInType = CY_DMA_DESCR, + .dataSize = CY_DMA_BYTE, + .srcTransferSize = CY_DMA_TRANSFER_SIZE_WORD, + .dstTransferSize = CY_DMA_TRANSFER_SIZE_DATA, + .descriptorType = CY_DMA_2D_TRANSFER, + .srcAddress = 0, + .dstAddress = 0, + .srcXincrement = 0U, + .dstXincrement = 1U, + .xCount = 1UL, + .srcYincrement = 0U, + .dstYincrement = CY_DMA_LOOP_COUNT_MAX, + .yCount = 1UL, + .nextDescriptor = &dma_descr, +}; + +/* Default DW channel config */ +static cy_stc_dma_channel_config_t dma_channel_config = +{ + .descriptor = &dma_descr, + .preemptable = false, + .priority = DMA_CHANNEL_PRIORITY, + .enable = false, + .bufferable = false, +}; + +static const cyhal_resource_inst_t DW_obj = +{ + .type = CYHAL_RSC_DW, + .block_num = ((uint32_t)RX_DMA_INSTANCE - DW0_BASE)/sizeof(DW_Type), + .channel_num = RX_DMA_CHANNEL_NUM +}; + +static cy_rslt_t _init_dma(void); +static cy_rslt_t _deinit_dma(void); +static void _rx_dma_irq_handler(void); +static cy_en_smif_status_t _read_next_chunk(void); +static void _value_to_byte_array(uint32_t value, uint8_t* byte_array, uint32_t start_pos, + uint32_t size); + +#endif /* #ifndef DMA_UNSUPPORTED */ + +static inline cy_rslt_t _mutex_acquire(void); +static inline cy_rslt_t _mutex_release(void); + +//-------------------------------------------------------------------------------------------------- +// cy_serial_flash_qspi_init +// +// The driver supports only one memory. When multiple memory configurations are generated by the +// SMIF configurator tool, provide only the configuration for memory that need to be supported by +// the driver. Memory configuration can be changed by deinit followed by init with new +// configuration +//-------------------------------------------------------------------------------------------------- +cy_rslt_t cy_serial_flash_qspi_init( + const cy_stc_smif_mem_config_t* mem_config, + cyhal_gpio_t io0, + cyhal_gpio_t io1, + cyhal_gpio_t io2, + cyhal_gpio_t io3, + cyhal_gpio_t io4, + cyhal_gpio_t io5, + cyhal_gpio_t io6, + cyhal_gpio_t io7, + cyhal_gpio_t sclk, + cyhal_gpio_t ssel, + uint32_t hz) +{ + cy_en_smif_status_t smif_status = CY_SMIF_SUCCESS; + + + cy_rslt_t result = cyhal_qspi_init(&qspi_obj, io0, io1, io2, io3, io4, io5, io6, io7, + sclk, ssel, hz, 0); + + qspi_mem_config[MEM_SLOT] = (cy_stc_smif_mem_config_t*)mem_config; + + if (CY_RSLT_SUCCESS == result) + { + SET_FLAG(FLAG_QSPI_HAL_INIT_DONE); + + // Perform SFDP detection and XIP register configuration depending on the memory + // configuration. + smif_status = Cy_SMIF_MemInit(qspi_obj.base, &qspi_block_config, &qspi_obj.context); + if (CY_SMIF_SUCCESS == smif_status) + { + // Enable Quad mode (1-1-4 or 1-4-4 modes) to use all the four I/Os during + // communication. + + if ((qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->readCmd->dataWidth == + CY_SMIF_WIDTH_QUAD) || + (qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->programCmd->dataWidth == + CY_SMIF_WIDTH_QUAD)) + { + bool isQuadEnabled = false; + smif_status = + Cy_SMIF_MemIsQuadEnabled(qspi_obj.base, qspi_block_config.memConfig[MEM_SLOT], + &isQuadEnabled, &qspi_obj.context); + if ((CY_SMIF_SUCCESS == smif_status) && !isQuadEnabled) + { + smif_status = + Cy_SMIF_MemEnableQuadMode(qspi_obj.base, + qspi_block_config.memConfig[MEM_SLOT], + CY_SERIAL_FLASH_QUAD_ENABLE_TIMEOUT_US, + &qspi_obj.context); + } + + if (CY_SMIF_SUCCESS == smif_status) + { + #ifndef DMA_UNSUPPORTED + result = _init_dma(); + + if (CY_RSLT_SUCCESS == result) + { + SET_FLAG(FLAG_DMA_INIT_DONE); + #endif /* #ifndef DMA_UNSUPPORTED */ + + #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE) + /* Initialize the mutex */ + result = cy_rtos_init_mutex(&serial_flash_mutex); + #endif /* #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE) */ + + #ifndef DMA_UNSUPPORTED + } + #endif /* #ifndef DMA_UNSUPPORTED */ + } + } + } + } + + if ((CY_RSLT_SUCCESS != result) || (CY_SMIF_SUCCESS != smif_status)) + { + cy_serial_flash_qspi_deinit(); + + if (CY_SMIF_SUCCESS != smif_status) + { + result = (cy_rslt_t)smif_status; + } + } + + return result; +} + + +//-------------------------------------------------------------------------------------------------- +// cy_serial_flash_qspi_deinit +//-------------------------------------------------------------------------------------------------- +void cy_serial_flash_qspi_deinit(void) +{ + cy_rslt_t result; + + if (IS_FLAG_SET(FLAG_QSPI_HAL_INIT_DONE)) + { + if (qspi_obj.base != NULL) + { + /* There is no harm in calling this even if Cy_SMIF_MemInit() did + * not succeed since anyway we own the QSPI object. + */ + Cy_SMIF_MemDeInit(qspi_obj.base); + } + + cyhal_qspi_free(&qspi_obj); + CLEAR_FLAG(FLAG_QSPI_HAL_INIT_DONE); + + #ifndef DMA_UNSUPPORTED + if (IS_FLAG_SET(FLAG_DMA_INIT_DONE)) + { + result = _deinit_dma(); + CY_ASSERT(CY_RSLT_SUCCESS == result); + + CLEAR_FLAG(FLAG_DMA_INIT_DONE); + #endif /* #ifndef DMA_UNSUPPORTED */ + + #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE) + result = cy_rtos_deinit_mutex(&serial_flash_mutex); + CY_ASSERT(CY_RSLT_SUCCESS == result); + #endif /* #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE) */ + + #ifndef DMA_UNSUPPORTED + } + #endif /* #ifndef DMA_UNSUPPORTED */ + } + + CY_UNUSED_PARAMETER(result); /* To avoid compiler warning in Release mode. */ +} + + +//-------------------------------------------------------------------------------------------------- +// cy_serial_flash_qspi_get_size +//-------------------------------------------------------------------------------------------------- +size_t cy_serial_flash_qspi_get_size(void) +{ + return (size_t)qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->memSize; +} + + +//-------------------------------------------------------------------------------------------------- +// cy_serial_flash_qspi_get_erase_size +//-------------------------------------------------------------------------------------------------- +size_t cy_serial_flash_qspi_get_erase_size(uint32_t addr) +{ + size_t erase_sector_size; + cy_stc_smif_hybrid_region_info_t* hybrid_info = NULL; + + cy_en_smif_status_t smif_status = + Cy_SMIF_MemLocateHybridRegion(qspi_block_config.memConfig[MEM_SLOT], &hybrid_info, addr); + + if (CY_SMIF_SUCCESS != smif_status) + { + erase_sector_size = (size_t)qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->eraseSize; + } + else + { + erase_sector_size = (size_t)hybrid_info->eraseSize; + } + + return erase_sector_size; +} + + +//-------------------------------------------------------------------------------------------------- +// cy_serial_flash_qspi_get_prog_size +//-------------------------------------------------------------------------------------------------- +size_t cy_serial_flash_qspi_get_prog_size(uint32_t addr) +{ + CY_UNUSED_PARAMETER(addr); + return (size_t)qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->programSize; +} + + +//-------------------------------------------------------------------------------------------------- +// cy_serial_flash_qspi_read +//-------------------------------------------------------------------------------------------------- +cy_rslt_t cy_serial_flash_qspi_read(uint32_t addr, size_t length, uint8_t* buf) +{ + cy_rslt_t result_mutex_rel = CY_RSLT_SUCCESS; + + cy_rslt_t result = _mutex_acquire(); + + if (CY_RSLT_SUCCESS == result) + { + // Cy_SMIF_MemRead() returns error if (addr + length) > total flash size. + result = (cy_rslt_t)Cy_SMIF_MemRead(qspi_obj.base, qspi_block_config.memConfig[MEM_SLOT], + addr, + buf, length, &qspi_obj.context); + result_mutex_rel = _mutex_release(); + } + + /* Give priority to the status of SMIF operation when both SMIF operation + * and mutex release fail. + */ + return ((CY_RSLT_SUCCESS == result) ? result_mutex_rel : result); +} + + +//-------------------------------------------------------------------------------------------------- +// cy_serial_flash_qspi_abort_read +//-------------------------------------------------------------------------------------------------- +cy_rslt_t cy_serial_flash_qspi_abort_read(void) +{ + #ifndef DMA_UNSUPPORTED + cy_rslt_t result; + + /* Wait until SMIF finishes any pending transfer. */ + for (uint32_t loop = 0; loop < SMIF_BUSY_CHECK_LOOP_COUNT; loop++) + { + if (!Cy_SMIF_BusyCheck(qspi_obj.base)) + { + break; + } + + cyhal_system_delay_ms(SMIF_BUSY_CHECK_TIMEOUT_MS); + } + + if (Cy_SMIF_BusyCheck(qspi_obj.base)) + { + SET_FLAG(FLAG_READ_IN_PROGRESS); + result = CY_RSLT_SERIAL_FLASH_ERR_QSPI_BUSY; + } + else + { + Cy_DMA_Channel_Disable(RX_DMA_INSTANCE, RX_DMA_CHANNEL_NUM); + result = CY_RSLT_SUCCESS; + CLEAR_FLAG(FLAG_READ_IN_PROGRESS); + } + + return result; + #else // ifndef DMA_UNSUPPORTED + return CY_RSLT_SERIAL_FLASH_ERR_UNSUPPORTED; + #endif /* #ifndef DMA_UNSUPPORTED */ +} + + +//-------------------------------------------------------------------------------------------------- +// cy_serial_flash_qspi_read_async +//-------------------------------------------------------------------------------------------------- +cy_rslt_t cy_serial_flash_qspi_read_async(uint32_t addr, size_t length, uint8_t* buf, + cy_serial_flash_qspi_read_complete_callback_t callback, + void* callback_arg) +{ + #ifndef DMA_UNSUPPORTED + cy_rslt_t result = CY_RSLT_SERIAL_FLASH_ERR_BAD_PARAM; + cy_rslt_t result_mutex_rel = CY_RSLT_SUCCESS; + + CY_ASSERT(NULL != buf); + + if (IS_FLAG_SET(FLAG_READ_IN_PROGRESS)) + { + result = CY_RSLT_SERIAL_FLASH_ERR_READ_BUSY; /* Previous read request is not yet complete. + */ + } + else if ((addr + length) <= cy_serial_flash_qspi_get_size()) + { + result = _mutex_acquire(); + + if (CY_RSLT_SUCCESS == result) + { + read_txfr_info.addr = addr; + read_txfr_info.length = length; + read_txfr_info.buf = buf; + read_txfr_info.callback = callback; + read_txfr_info.callback_arg = callback_arg; + + /* Enable the DMA channel */ + Cy_DMA_Channel_Enable(RX_DMA_INSTANCE, RX_DMA_CHANNEL_NUM); + + SET_FLAG(FLAG_READ_IN_PROGRESS); + result = (cy_rslt_t)_read_next_chunk(); /* Start the read transfer */ + + if (CY_RSLT_SUCCESS != result) + { + CLEAR_FLAG(FLAG_READ_IN_PROGRESS); + } + + result_mutex_rel = _mutex_release(); + } + } + + /* Give priority to the status of SMIF operation when both SMIF operation + * and mutex release fail. + */ + return ((CY_RSLT_SUCCESS == result) ? result_mutex_rel : result); + #else // ifndef DMA_UNSUPPORTED + CY_UNUSED_PARAMETER(addr); + CY_UNUSED_PARAMETER(length); + CY_UNUSED_PARAMETER(buf); + CY_UNUSED_PARAMETER(callback); + CY_UNUSED_PARAMETER(callback_arg); + + return CY_RSLT_SERIAL_FLASH_ERR_UNSUPPORTED; + #endif /* #ifndef DMA_UNSUPPORTED */ +} + + +//-------------------------------------------------------------------------------------------------- +// cy_serial_flash_qspi_write +//-------------------------------------------------------------------------------------------------- +cy_rslt_t cy_serial_flash_qspi_write(uint32_t addr, size_t length, const uint8_t* buf) +{ + cy_rslt_t result_mutex_rel = CY_RSLT_SUCCESS; + + cy_rslt_t result = _mutex_acquire(); + + if (CY_RSLT_SUCCESS == result) + { + // Cy_SMIF_MemWrite() returns error if (addr + length) > total flash size. + result = (cy_rslt_t)Cy_SMIF_MemWrite(qspi_obj.base, qspi_block_config.memConfig[MEM_SLOT], + addr, + (uint8_t*)buf, length, &qspi_obj.context); + result_mutex_rel = _mutex_release(); + } + + /* Give priority to the status of SMIF operation when both SMIF operation + * and mutex release fail. + */ + return ((CY_RSLT_SUCCESS == result) ? result_mutex_rel : result); +} + + +//-------------------------------------------------------------------------------------------------- +// cy_serial_flash_qspi_erase +//-------------------------------------------------------------------------------------------------- +cy_rslt_t cy_serial_flash_qspi_erase(uint32_t addr, size_t length) +{ + cy_rslt_t result_mutex_rel = CY_RSLT_SUCCESS; + + cy_rslt_t result = _mutex_acquire(); + + if (CY_RSLT_SUCCESS == result) + { + // If the erase is for the entire chip, use chip erase command + if ((addr == 0u) && (length == cy_serial_flash_qspi_get_size())) + { + result = + (cy_rslt_t)Cy_SMIF_MemEraseChip(qspi_obj.base, + qspi_block_config.memConfig[MEM_SLOT], + &qspi_obj.context); + } + else + { + // Cy_SMIF_MemEraseSector() returns error if (addr + length) > total flash size or if + // addr is not aligned to erase sector size or if (addr + length) is not aligned to + // erase sector size. + result = + (cy_rslt_t)Cy_SMIF_MemEraseSector(qspi_obj.base, + qspi_block_config.memConfig[MEM_SLOT], + addr, length, &qspi_obj.context); + } + + result_mutex_rel = _mutex_release(); + } + + /* Give priority to the status of SMIF operation when both SMIF operation + * and mutex release fail. + */ + return ((CY_RSLT_SUCCESS == result) ? result_mutex_rel : result); +} + + +//-------------------------------------------------------------------------------------------------- +// cy_serial_flash_qspi_enable_xip +// +// This function enables or disables XIP on the MCU, does not send any command +// to the serial flash. XIP register configuration is already done as part of +// cy_serial_flash_qspi_init() if MMIO mode is enabled in the QSPI +// Configurator. +//-------------------------------------------------------------------------------------------------- +cy_rslt_t cy_serial_flash_qspi_enable_xip(bool enable) +{ + if (enable) + { + Cy_SMIF_SetMode(qspi_obj.base, CY_SMIF_MEMORY); + } + else + { + Cy_SMIF_SetMode(qspi_obj.base, CY_SMIF_NORMAL); + } + + return CY_RSLT_SUCCESS; +} + + +//-------------------------------------------------------------------------------------------------- +// cy_serial_flash_qspi_set_interrupt_priority +//-------------------------------------------------------------------------------------------------- +void cy_serial_flash_qspi_set_interrupt_priority(uint8_t priority) +{ + NVIC_SetPriority(smif_interrupt_IRQn, priority); +} + + +//-------------------------------------------------------------------------------------------------- +// cy_serial_flash_qspi_set_interrupt_priority +//-------------------------------------------------------------------------------------------------- +void cy_serial_flash_qspi_set_dma_interrupt_priority(uint8_t priority) +{ + #ifndef DMA_UNSUPPORTED + NVIC_SetPriority((IRQn_Type)(RX_DMA_CH0_IRQn + RX_DMA_CHANNEL_NUM), priority); + #else + CY_UNUSED_PARAMETER(priority); + #endif /* #ifndef DMA_UNSUPPORTED */ +} + + +#ifndef DMA_UNSUPPORTED +//-------------------------------------------------------------------------------------------------- +// _read_next_chunk +//-------------------------------------------------------------------------------------------------- +static cy_en_smif_status_t _read_next_chunk(void) +{ + cy_en_smif_status_t smif_status = CY_SMIF_SUCCESS; + uint32_t chunk; + uint8_t addr_array[CY_SMIF_FOUR_BYTES_ADDR] = { 0U }; + + if (read_txfr_info.length > 0UL) + { + /* SMIF can read only up to 65536 bytes in one go. Split the larger read into multiple + chunks */ + chunk = + (read_txfr_info.length > + SMIF_MAX_RX_COUNT) ? (SMIF_MAX_RX_COUNT) : read_txfr_info.length; + + /* In 2D transfer, (X_count x Y_count) should be a multiple of CY_DMA_LOOP_COUNT_MAX (256). + */ + if (chunk > CY_DMA_LOOP_COUNT_MAX) + { + /* Make chunk divisible by CY_DMA_LOOP_COUNT_MAX (256) by masking out the LS bits */ + chunk &= ~(CY_DMA_LOOP_COUNT_MAX - 1); + + dma_descr_config.yCount = chunk/CY_DMA_LOOP_COUNT_MAX; + dma_descr_config.xCount = CY_DMA_LOOP_COUNT_MAX; + } + else + { + dma_descr_config.yCount = DMA_YCOUNT_ONE_LOOP; + dma_descr_config.xCount = chunk; + } + + dma_descr_config.dstAddress = (void*)read_txfr_info.buf; + Cy_DMA_Descriptor_Init(&dma_descr, &dma_descr_config); + + /* Pass NULL for buffer (and callback) so that the function does not + * set up FIFO interrupt. We don't need FIFO interrupt to be setup + * since we will be using DMA. + */ + _value_to_byte_array(read_txfr_info.addr, &addr_array[0], 0UL, + qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->numOfAddrBytes); + smif_status = Cy_SMIF_MemCmdRead(qspi_obj.base, qspi_block_config.memConfig[MEM_SLOT], + addr_array, NULL, chunk, NULL, &qspi_obj.context); + + if (CY_SMIF_SUCCESS == smif_status) + { + /* Recalculate the next rxBuffer offset */ + read_txfr_info.length -= chunk; + read_txfr_info.addr += chunk; + read_txfr_info.buf += chunk; + } + } + + return smif_status; +} + + +//-------------------------------------------------------------------------------------------------- +// _init_dma +//-------------------------------------------------------------------------------------------------- +static cy_rslt_t _init_dma(void) +{ + cy_rslt_t result; + + /* Set the source address of the descriptor */ + dma_descr_config.srcAddress = (void*)&SMIF_RX_DATA_FIFO_RD1(qspi_obj.base); + + /* Configure the RX DMA */ + result = + (cy_rslt_t)Cy_DMA_Channel_Init(RX_DMA_INSTANCE, RX_DMA_CHANNEL_NUM, &dma_channel_config); + + if (CY_RSLT_SUCCESS == result) + { + Cy_DMA_Channel_SetInterruptMask(RX_DMA_INSTANCE, RX_DMA_CHANNEL_NUM, CY_DMA_INTR_MASK); + Cy_DMA_Enable(RX_DMA_INSTANCE); + + /* Configure interrupt for RX DMA */ + cy_stc_sysint_t dma_intr_config = + { .intrSrc = (IRQn_Type)(RX_DMA_CH0_IRQn + RX_DMA_CHANNEL_NUM), + .intrPriority = DMA_INTR_PRIORITY }; + + result = (cy_rslt_t)Cy_SysInt_Init(&dma_intr_config, _rx_dma_irq_handler); + + if (CY_RSLT_SUCCESS == result) + { + NVIC_EnableIRQ(dma_intr_config.intrSrc); + + /* Configure the trigger mux */ + #if defined(DEVICE_GROUP_1TO1_TRIGGER) + result = (cy_rslt_t)Cy_TrigMux_Select(TRIG_OUT_1TO1_3_SMIF_RX_TO_PDMA1_TR_IN23, false, + TRIGGER_TYPE_LEVEL); + #else + result = (cy_rslt_t)Cy_TrigMux_Connect(TRIG13_IN_SMIF_TR_RX_REQ, + TRIG13_OUT_TR_GROUP0_INPUT42, false, + TRIGGER_TYPE_LEVEL); + + if (CY_RSLT_SUCCESS == result) + { + result = (cy_rslt_t)Cy_TrigMux_Connect(TRIG1_IN_TR_GROUP13_OUTPUT15, + TRIG1_OUT_CPUSS_DW1_TR_IN15, false, + TRIGGER_TYPE_LEVEL); + } + #endif /* #if defined(DEVICE_GROUP_1TO1_TRIGGER) */ + } + } + + if (CY_RSLT_SUCCESS == result) + { + /* Reserve the DW instance so that HAL will not be able to use it later. */ + result = cyhal_hwmgr_reserve(&DW_obj); + } + + return result; +} + + +//-------------------------------------------------------------------------------------------------- +// _deinit_dma +//-------------------------------------------------------------------------------------------------- +static cy_rslt_t _deinit_dma(void) +{ + cy_rslt_t result = CY_RSLT_SUCCESS; + + NVIC_DisableIRQ((IRQn_Type)(RX_DMA_CH0_IRQn + RX_DMA_CHANNEL_NUM)); + + /* Disable only the channel, not the DW instance as it may be used by other + * part of the application. + */ + Cy_DMA_Channel_Disable(RX_DMA_INSTANCE, RX_DMA_CHANNEL_NUM); + + /* Free the DMA resource so that HAL can use it now */ + cyhal_hwmgr_free(&DW_obj); + + #if defined(DEVICE_GROUP_1TO1_TRIGGER) + result = (cy_rslt_t)Cy_TrigMux_Deselect(TRIG_OUT_1TO1_3_SMIF_RX_TO_PDMA1_TR_IN23); + #else + /* No PDL function is available for handling deinit for non-1to1 trigger muxes. */ + #endif /* #if defined(DEVICE_GROUP_1TO1_TRIGGER) */ + + return result; +} + + +//-------------------------------------------------------------------------------------------------- +// _rx_dma_irq_handler +//-------------------------------------------------------------------------------------------------- +static void _rx_dma_irq_handler(void) +{ + cy_en_smif_status_t smif_status = CY_SMIF_SUCCESS; + bool terminate_read_txfr = true; + cy_en_dma_intr_cause_t cause = Cy_DMA_Channel_GetStatus(RX_DMA_INSTANCE, RX_DMA_CHANNEL_NUM); + + Cy_DMA_Channel_ClearInterrupt(RX_DMA_INSTANCE, RX_DMA_CHANNEL_NUM); + + if (CY_DMA_INTR_CAUSE_COMPLETION == cause) + { + if (read_txfr_info.length > 0UL) + { + smif_status = _read_next_chunk(); + + if (CY_SMIF_SUCCESS == smif_status) + { + terminate_read_txfr = false; + } + } + } + else + { + smif_status = (cy_en_smif_status_t)CY_RSLT_SERIAL_FLASH_ERR_DMA; + } + + if (terminate_read_txfr) + { + Cy_DMA_Channel_Disable(RX_DMA_INSTANCE, RX_DMA_CHANNEL_NUM); + CLEAR_FLAG(FLAG_READ_IN_PROGRESS); + + /* Execute the callback */ + if (NULL != read_txfr_info.callback) + { + read_txfr_info.callback((cy_rslt_t)smif_status, read_txfr_info.callback_arg); + } + } +} + + +/******************************************************************************* +* Function Name: _value_to_byte_array +****************************************************************************//** +* +* Unpacks the specified number of bytes from a 32-bit value into the given byte +* array. +* +* \param value +* The 32-bit (4-byte) value to unpack. +* +* \param byte_array +* The byte array to fill. +* +* \param start_pos +* The start position of the byte array to begin filling from. +* +* \param size +* The number of bytes to unpack. +* +*******************************************************************************/ +static void _value_to_byte_array(uint32_t value, uint8_t* byte_array, uint32_t start_pos, + uint32_t size) +{ + CY_ASSERT((0lu < size) && (CY_SMIF_FOUR_BYTES_ADDR >= size)); + CY_ASSERT(NULL != byte_array); + + do + { + size--; + byte_array[size + start_pos] = (uint8_t)(value & LSB_MASK); + value >>= MSB_SHIFT_EIGHT; /* Shift to get the next byte */ + } while (size > 0U); +} + + +#endif /* #ifndef DMA_UNSUPPORTED */ + +//-------------------------------------------------------------------------------------------------- +// _mutex_acquire +//-------------------------------------------------------------------------------------------------- +static inline cy_rslt_t _mutex_acquire(void) +{ + #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE) + return cy_rtos_get_mutex(&serial_flash_mutex, CY_RTOS_NEVER_TIMEOUT); + #else + return CY_RSLT_SUCCESS; + #endif /* #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE) */ +} + + +//-------------------------------------------------------------------------------------------------- +// _mutex_release +//-------------------------------------------------------------------------------------------------- +static inline cy_rslt_t _mutex_release(void) +{ + #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE) + return cy_rtos_set_mutex(&serial_flash_mutex); + #else + return CY_RSLT_SUCCESS; + #endif /* #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE) */ +} + + +#if defined(__cplusplus) +} +#endif + +#endif // CY_IP_MXSMIF diff --git a/targets/TARGET_Cypress/TARGET_PSOC6/common/cy_serial_flash_qspi.h b/targets/TARGET_Cypress/TARGET_PSOC6/common/serial-flash/cy_serial_flash_qspi.h old mode 100644 new mode 100755 similarity index 52% rename from targets/TARGET_Cypress/TARGET_PSOC6/common/cy_serial_flash_qspi.h rename to targets/TARGET_Cypress/TARGET_PSOC6/common/serial-flash/cy_serial_flash_qspi.h index 27bf4e986c..d497653a8f --- a/targets/TARGET_Cypress/TARGET_PSOC6/common/cy_serial_flash_qspi.h +++ b/targets/TARGET_Cypress/TARGET_PSOC6/common/serial-flash/cy_serial_flash_qspi.h @@ -1,33 +1,45 @@ -/***************************************************************************//** -* \file cy_serial_flash_qspi.h -* -* \brief -* Provides APIs for interacting with an external flash connected to the SPI or -* QSPI interface. Flash operations read, write, and erase are implemented as -* blocking functions. -* -******************************************************************************** -* \copyright -* Copyright 2018-2020 Cypress Semiconductor Corporation -* SPDX-License-Identifier: Apache-2.0 -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*******************************************************************************/ +/***********************************************************************************************//** + * \file cy_serial_flash_qspi.h + * + * \brief + * Provides APIs for interacting with an external flash connected to the SPI or + * QSPI interface. Read is implemented as both blocking and non-blocking whereas + * write, and erase are implemented as blocking functions. + * + *************************************************************************************************** + * \copyright + * Copyright 2018-2021 Cypress Semiconductor Corporation + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **************************************************************************************************/ /** -* \addtogroup group_board_libs Serial Flash -* \{ -*/ + * \addtogroup group_board_libs Serial Flash + * \ingroup group_lib + * \{ + * + * \section section_resource_usage DMA Resource Usage + * This library uses fixed DMA (Datawire or DW) resources and supports DMA only + * for the following devices. DMA is not supported for other devices and the + * functions \ref cy_serial_flash_qspi_read_async() and + * \ref cy_serial_flash_qspi_abort_read() will return + * \ref CY_RSLT_SERIAL_FLASH_ERR_UNSUPPORTED error and + * \ref cy_serial_flash_qspi_set_dma_interrupt_priority() will simply return + * doing nothing. + * * CY8C6xx4, CY8C6xx5, CY8C6xx8, CY8C6xxA, CYB06xx5, CYB06xxA, CYS06xxA: DW1, Channel 23 + * * CY8C6xx6, CY8C6xx7, CYB06xx7: DW1, Channel 15 + */ #pragma once @@ -43,7 +55,37 @@ extern "C" { #endif /** The function or operation is not supported on the target or the memory */ -#define CY_RSLT_SERIAL_FLASH_ERR_UNSUPPORTED (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_BOARD_LIB_SERIAL_FLASH, 1)) +#define CY_RSLT_SERIAL_FLASH_ERR_UNSUPPORTED \ + (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_BOARD_LIB_SERIAL_FLASH, 1)) + +/** Parameters passed to a function are invalid */ +#define CY_RSLT_SERIAL_FLASH_ERR_BAD_PARAM \ + (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_BOARD_LIB_SERIAL_FLASH, 2)) + +/** A previously initiated read operation is not yet complete */ +#define CY_RSLT_SERIAL_FLASH_ERR_READ_BUSY \ + (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_BOARD_LIB_SERIAL_FLASH, 3)) + +/** A DMA error occurred during read transfer */ +#define CY_RSLT_SERIAL_FLASH_ERR_DMA \ + (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_BOARD_LIB_SERIAL_FLASH, 4)) + +/** Read abort failed. QSPI block is busy. */ +#define CY_RSLT_SERIAL_FLASH_ERR_QSPI_BUSY \ + (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_BOARD_LIB_SERIAL_FLASH, 5)) + +#ifdef DOXYGEN +/** Enables thread-safety for use with multi-threaded RTOS environment. */ +#define CY_SERIAL_FLASH_QSPI_THREAD_SAFE +#endif /* #ifdef DOXYGEN */ + +/** + * Callback pointer to use with \ref cy_serial_flash_qspi_read_async(). + * \param peration_status Status of the read operation + * \param callback_arg Pointer to be passed back to the callback function + */ +typedef void (* cy_serial_flash_qspi_read_complete_callback_t)(cy_rslt_t operation_status, + void* callback_arg); /** * \brief Initializes the serial flash memory. This function accepts up to 8 @@ -84,6 +126,10 @@ cy_rslt_t cy_serial_flash_qspi_init( /** * \brief De-initializes the serial flash memory. + * Before calling this function, ensure that an ongoing asynchronous read + * operation is either completed or successfully aborted. + * Async read is started by calling \ref cy_serial_flash_qspi_read_async() and + * aborted by calling \ref cy_serial_flash_qspi_abort_read(). */ void cy_serial_flash_qspi_deinit(void); @@ -120,6 +166,7 @@ __STATIC_INLINE uint32_t cy_serial_flash_get_sector_start_address(uint32_t addr) return (addr & ~(cy_serial_flash_qspi_get_erase_size(addr) - 1)); } + /** * \brief Reads data from the serial flash memory. This is a blocking * function. Returns error if (addr + length) exceeds the flash size. @@ -128,7 +175,34 @@ __STATIC_INLINE uint32_t cy_serial_flash_get_sector_start_address(uint32_t addr) * \param buf Pointer to the buffer to store the data read from the memory * \returns CY_RSLT_SUCCESS if the read was successful, an error code otherwise. */ -cy_rslt_t cy_serial_flash_qspi_read(uint32_t addr, size_t length, uint8_t *buf); +cy_rslt_t cy_serial_flash_qspi_read(uint32_t addr, size_t length, uint8_t* buf); + +/** + * \brief Reads data from the serial flash memory. This is a non-blocking + * function. Returns error if (addr + length) exceeds the flash size. + * Uses fixed DMA (DW) instance and channel for transferring the data from + * QSPI RX FIFO to the user-provided buffer. + * \param addr Starting address to read from + * \param length Number of data bytes to read + * \param buf Pointer to the buffer to store the data read from the memory + * \param callback Pointer to the callback function to be called after the read + * operation is complete. Callback is invoked from the DMA ISR. + * \param callback_arg Pointer to the argument to be passed to the callback + * function + * \returns CY_RSLT_SUCCESS if the read was successful, an error code otherwise. + */ +cy_rslt_t cy_serial_flash_qspi_read_async(uint32_t addr, size_t length, uint8_t* buf, + cy_serial_flash_qspi_read_complete_callback_t callback, + void* callback_arg); + +/** + * \brief Aborts an ongoing asynchronous read initiated by calling + * \ref cy_serial_flash_qspi_read_async(). + * + * \returns CY_RSLT_SUCCESS if the abort was successful, an error code + * if the QSPI block is still busy after a timeout. + */ +cy_rslt_t cy_serial_flash_qspi_abort_read(void); /** * \brief Writes the data to the serial flash memory. The program area @@ -141,13 +215,16 @@ cy_rslt_t cy_serial_flash_qspi_read(uint32_t addr, size_t length, uint8_t *buf); * \returns CY_RSLT_SUCCESS if the write was successful, an error code * otherwise. */ -cy_rslt_t cy_serial_flash_qspi_write(uint32_t addr, size_t length, const uint8_t *buf); +cy_rslt_t cy_serial_flash_qspi_write(uint32_t addr, size_t length, const uint8_t* buf); /** * \brief Erases the serial flash memory, uses chip erase command when * addr = 0 and length = flash_size otherwise uses sector erase command. This is * a blocking function. Returns error if addr or (addr + length) is not aligned * to the sector size or if (addr + length) exceeds the flash size. + * For memories with hybrid sectors, returns error if the end address + * (=addr + length) is not aligned to the size of the sector in which the end + * address is located. * Call \ref cy_serial_flash_qspi_get_size() to get the flash size and * call \ref cy_serial_flash_qspi_get_erase_size() to get the size of an erase * sector. @@ -177,10 +254,17 @@ cy_rslt_t cy_serial_flash_qspi_enable_xip(bool enable); */ void cy_serial_flash_qspi_set_interrupt_priority(uint8_t priority); +/** + * \brief Changes the DMA interrupt priority + * \param priority interrupt priority to be set + */ +void cy_serial_flash_qspi_set_dma_interrupt_priority(uint8_t priority); + + #if defined(__cplusplus) } #endif -#endif /* CY_IP_MXSMIF */ +#endif // CY_IP_MXSMIF /** \} group_board_libs */ diff --git a/targets/TARGET_Cypress/TARGET_PSOC6/common/serial-flash/version.xml b/targets/TARGET_Cypress/TARGET_PSOC6/common/serial-flash/version.xml new file mode 100755 index 0000000000..7393eb91cf --- /dev/null +++ b/targets/TARGET_Cypress/TARGET_PSOC6/common/serial-flash/version.xml @@ -0,0 +1 @@ +1.1.0.20805 diff --git a/targets/TARGET_Cypress/TARGET_PSOC6/common/version.xml b/targets/TARGET_Cypress/TARGET_PSOC6/common/version.xml deleted file mode 100644 index 7a00e5148c..0000000000 --- a/targets/TARGET_Cypress/TARGET_PSOC6/common/version.xml +++ /dev/null @@ -1 +0,0 @@ -.19214