Skip to content

Initial support for Serial Flash on PSoC Devices #11355

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 180 additions & 0 deletions targets/TARGET_Cypress/TARGET_PSOC6/common/cybsp_serial_flash.c
Original file line number Diff line number Diff line change
@@ -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
143 changes: 143 additions & 0 deletions targets/TARGET_Cypress/TARGET_PSOC6/common/cybsp_serial_flash.h
Original file line number Diff line number Diff line change
@@ -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 */
Loading