From ee944cf8503afc2e189178d297e816cb1372481a Mon Sep 17 00:00:00 2001 From: Ryan Morse Date: Mon, 26 Aug 2019 18:00:28 +0100 Subject: [PATCH] Add serial flash implementation for PSoC 6 --- .../TARGET_PSOC6/common/cybsp_serial_flash.c | 180 ++++++++++++++++++ .../TARGET_PSOC6/common/cybsp_serial_flash.h | 143 ++++++++++++++ .../common/cybsp_serial_flash_prog.c | 94 +++++++++ 3 files changed, 417 insertions(+) create mode 100644 targets/TARGET_Cypress/TARGET_PSOC6/common/cybsp_serial_flash.c create mode 100644 targets/TARGET_Cypress/TARGET_PSOC6/common/cybsp_serial_flash.h create mode 100644 targets/TARGET_Cypress/TARGET_PSOC6/common/cybsp_serial_flash_prog.c diff --git a/targets/TARGET_Cypress/TARGET_PSOC6/common/cybsp_serial_flash.c b/targets/TARGET_Cypress/TARGET_PSOC6/common/cybsp_serial_flash.c new file mode 100644 index 0000000000..f8b5dac666 --- /dev/null +++ b/targets/TARGET_Cypress/TARGET_PSOC6/common/cybsp_serial_flash.c @@ -0,0 +1,180 @@ +/***************************************************************************//** +* \file cybsp_serial_flash.c +* +* \brief +* Provides APIs for interacting with an external flash connected to the SPI or +* QSPI interface, uses the configuration generated by the QSPI configurator, +* uses SFDP to auto-discover memory properties if SFDP is enabled in the +* configuration. +* +******************************************************************************** +* \copyright +* Copyright 2018-2019 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 "cybsp_serial_flash.h" +#include "cy_pdl.h" +#include "cyhal_qspi.h" +#include "cy_utils.h" +#include "cybsp.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(CYBSP_QSPI_SCK) +#include "cycfg_qspi_memslot.h" + +/** \cond internal */ + +#define QSPI_BUS_FREQUENCY_HZ (50000000lu) + +/** 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 CYBSP_SERIAL_FLASH_QUAD_ENABLE_TIMEOUT_US (5000lu) /* in microseconds */ + +/* SMIF slot number to which the memory is connected */ +#define MEM_SLOT (0u) + +/** \endcond */ + +static cyhal_qspi_t qspi_obj; + +cy_rslt_t cybsp_serial_flash_init(void) +{ + cy_en_smif_status_t smifStatus = CY_SMIF_SUCCESS; + + cy_rslt_t result = cyhal_qspi_init(&qspi_obj, CYBSP_QSPI_D0, CYBSP_QSPI_D1, CYBSP_QSPI_D2, CYBSP_QSPI_D3, NC, NC, NC, NC, + CYBSP_QSPI_SCK, CYBSP_QSPI_SS, QSPI_BUS_FREQUENCY_HZ, 0); + if(CY_RSLT_SUCCESS == result) + { + /* Perform SFDP detection and XIP register configuration depending on the + * memory configuration. + */ + smifStatus = Cy_SMIF_Memslot_Init(qspi_obj.base, (cy_stc_smif_block_config_t *) &smifBlockConfig, &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(smifMemConfigs[MEM_SLOT]->deviceCfg->readCmd->dataWidth == CY_SMIF_WIDTH_QUAD + || smifMemConfigs[MEM_SLOT]->deviceCfg->programCmd->dataWidth == CY_SMIF_WIDTH_QUAD) + { + bool isQuadEnabled = false; + smifStatus = Cy_SMIF_MemIsQuadEnabled(qspi_obj.base, smifMemConfigs[MEM_SLOT], &isQuadEnabled, &qspi_obj.context); + if(CY_SMIF_SUCCESS == smifStatus) + { + if(!isQuadEnabled) + { + smifStatus = Cy_SMIF_MemEnableQuadMode(qspi_obj.base, smifMemConfigs[MEM_SLOT], CYBSP_SERIAL_FLASH_QUAD_ENABLE_TIMEOUT_US, &qspi_obj.context); + } + } + } + } + } + + if((CY_RSLT_SUCCESS == result) && (CY_SMIF_SUCCESS == smifStatus)) + { + return CY_RSLT_SUCCESS; + } + else + { + cybsp_serial_flash_deinit(); + return (cy_rslt_t)smifStatus; + } +} + +void cybsp_serial_flash_deinit(void) +{ + cyhal_qspi_free(&qspi_obj); +} + +size_t cybsp_serial_flash_get_size(void) +{ + return (size_t)smifMemConfigs[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 cybsp_serial_flash_get_erase_size(uint32_t addr) +{ + CY_UNUSED_PARAMETER(addr); + return (size_t)smifMemConfigs[MEM_SLOT]->deviceCfg->eraseSize; +} + +cy_rslt_t cybsp_serial_flash_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, smifMemConfigs[MEM_SLOT], addr, buf, length, &qspi_obj.context); +} + +cy_rslt_t cybsp_serial_flash_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, smifMemConfigs[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 cybsp_serial_flash_get_erase_size(addr) to implement hybrid sector + * support when QSPI Configurator and PDL supports memories with hybrid sectors. + */ +cy_rslt_t cybsp_serial_flash_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 == cybsp_serial_flash_get_size())) + { + smifStatus = Cy_SMIF_MemEraseChip(qspi_obj.base, smifMemConfigs[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, smifMemConfigs[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 +// cybsp_serial_flash_init() if MMIO mode is enabled in the QSPI +// Configurator. +cy_rslt_t cybsp_serial_flash_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; +} + +#endif /* defined(CYBSP_QSPI_SCK) */ + +#if defined(__cplusplus) +} +#endif diff --git a/targets/TARGET_Cypress/TARGET_PSOC6/common/cybsp_serial_flash.h b/targets/TARGET_Cypress/TARGET_PSOC6/common/cybsp_serial_flash.h new file mode 100644 index 0000000000..cf55011274 --- /dev/null +++ b/targets/TARGET_Cypress/TARGET_PSOC6/common/cybsp_serial_flash.h @@ -0,0 +1,143 @@ +/***************************************************************************//** +* \file cybsp_serial_flash.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-2019 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_bsp_serial_flash Serial Flash +* \{ +* Driver for interfacing with the serial flash (QSPI NOR flash) on Cypress boards. +* +* \defgroup group_bsp_serial_flash_macros Macros +* \defgroup group_bsp_serial_flash_functions Functions +*/ + +#pragma once + +#include +#include "cy_result.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/** +* \addtogroup group_bsp_serial_flash_macros +* \{ +*/ + +/** The function or operation is not supported on the target or the memory */ +#define CYBSP_RSLT_SERIAL_FLASH_ERR_UNSUPPORTED (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_BSP, 6)) + +/** \} group_bsp_serial_flash_macros */ + +/** +* \addtogroup group_bsp_serial_flash_functions +* \{ +*/ + +/** + * \brief Initializes the serial flash on the board. + * \returns CY_RSLT_SUCCESS if the initialization was successful, an error code + * otherwise. + */ +cy_rslt_t cybsp_serial_flash_init(void); + +/** + * \brief De-initializes the serial flash on the board. + */ +void cybsp_serial_flash_deinit(void); + +/** + * \brief Returns the size of the serial flash on the board in bytes. + * \returns Memory size in bytes. + */ +size_t cybsp_serial_flash_get_size(void); + +/** + * \brief Returns the size of the erase sector to which the given address + * belongs. Address is used only for a memory with hybrid sector size. + * \param addr Address that belongs to the sector for which size is returned. + * \returns Erase sector size in bytes. + */ +size_t cybsp_serial_flash_get_erase_size(uint32_t addr); + +/** + * \brief Reads data from the serial flash on the board. This is a blocking + * function. Returns error if (addr + length) exceeds the flash size. + * \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 + * \returns CY_RSLT_SUCCESS if the read was successful, an error code otherwise. + */ +cy_rslt_t cybsp_serial_flash_read(uint32_t addr, size_t length, uint8_t *buf); + +/** + * \brief Writes the data to the serial flash on the board. The program area + * must have been erased prior to calling this API using + * \ref cybsp_serial_flash_erase() This is a blocking function. Returns error if + * (addr + length) exceeds the flash size. + * \param addr Starting address to write to + * \param length Number of bytes to write + * \param buf Pointer to the buffer storing the data to be written + * \returns CY_RSLT_SUCCESS if the write was successful, an error code + * otherwise. + */ +cy_rslt_t cybsp_serial_flash_write(uint32_t addr, size_t length, const uint8_t *buf); + +/** + * \brief Erases the serial flash on the board, 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. + * Call \ref cybsp_serial_flash_get_size() to get the flash size and + * call \ref cybsp_serial_flash_get_erase_size() to get the size of an erase + * sector. + * + * \param addr Starting address to begin erasing + * \param length Number of bytes to erase + * \returns CY_RSLT_SUCCESS if the erase was successful, an error code + * otherwise. + */ +cy_rslt_t cybsp_serial_flash_erase(uint32_t addr, size_t length); + +/** + * \brief Enables Execute-in-Place (memory mapped) mode on the MCU. This + * function does not send any command to the serial flash. This may not be + * supported on all the targets in which case + * CYBSP_RSLT_SERIAL_FLASH_ERR_UNSUPPORTED is returned. + * \param enable true: XIP mode is set, false: normal mode is set + * \returns CY_RSLT_SUCCESS if the operation was successful. + * CYBSP_RSLT_SERIAL_FLASH_ERR_UNSUPPORTED if the target does not + * support XIP. + */ +cy_rslt_t cybsp_serial_flash_enable_xip(bool enable); + +/** \} group_bsp_serial_flash_functions */ + +#if defined(__cplusplus) +} +#endif + +/** \} group_bsp_serial_flash */ diff --git a/targets/TARGET_Cypress/TARGET_PSOC6/common/cybsp_serial_flash_prog.c b/targets/TARGET_Cypress/TARGET_PSOC6/common/cybsp_serial_flash_prog.c new file mode 100644 index 0000000000..1948adcd61 --- /dev/null +++ b/targets/TARGET_Cypress/TARGET_PSOC6/common/cybsp_serial_flash_prog.c @@ -0,0 +1,94 @@ +/***************************************************************************//** +* \file cybsp_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. +* +******************************************************************************** +* \copyright +* Copyright 2018-2019 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_bsp_serial_flash Serial Flash +* \{ +* Variables for informing programming tools that there is an attached memory device and what +* its characteristics are so it can be programmed just like the on-chip memory. +* +* \defgroup group_bsp_serial_flash_variables Variables +*/ + +#include +#include "cybsp_types.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(CYBSP_QSPI_SCK) +#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; + +/** +* \addtogroup group_bsp_serial_flash_variables +* \{ +*/ + +/** + * 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 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. + */ +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 */ + [127] = 0x0B1F0000 /* Offset=0x01FC: CRC16-CCITT (the upper 2 bytes contain the CRC and the lower 2 bytes are 0) */ +}; + +/** \} group_bsp_serial_flash_variables */ +#endif /* defined(CYBSP_QSPI_SCK) */ + +#if defined(__cplusplus) +} +#endif + +/** \} group_bsp_serial_flash */