Add serial flash implementation for PSoC 6

pull/11355/head
Ryan Morse 2019-08-26 18:00:28 +01:00 committed by Kyle Kearney
parent ea582f3e11
commit ee944cf850
3 changed files with 417 additions and 0 deletions

View File

@ -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 <stdbool.h>
#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

View File

@ -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 <stddef.h>
#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 */

View File

@ -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 <stdint.h>
#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 */