diff options
Diffstat (limited to 'platform/ext/target/arm/musca_s1/CMSIS_Driver/Driver_QSPI_Flash.c')
-rw-r--r-- | platform/ext/target/arm/musca_s1/CMSIS_Driver/Driver_QSPI_Flash.c | 352 |
1 files changed, 352 insertions, 0 deletions
diff --git a/platform/ext/target/arm/musca_s1/CMSIS_Driver/Driver_QSPI_Flash.c b/platform/ext/target/arm/musca_s1/CMSIS_Driver/Driver_QSPI_Flash.c new file mode 100644 index 0000000000..440ba94914 --- /dev/null +++ b/platform/ext/target/arm/musca_s1/CMSIS_Driver/Driver_QSPI_Flash.c @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2013-2021 Arm Limited. All rights reserved. + * + * 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 "Driver_Flash.h" + +#include <stdbool.h> +#include <string.h> +#include "cmsis_driver_config.h" +#include "RTE_Device.h" +#include "flash_layout.h" + + +#ifndef ARG_UNUSED +#define ARG_UNUSED(arg) ((void)arg) +#endif + +/* Driver version */ +#define ARM_FLASH_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(1, 0) + +static const ARM_DRIVER_VERSION DriverVersion = { + ARM_FLASH_API_VERSION, /* Defined in the CMSIS Flash Driver header file */ + ARM_FLASH_DRV_VERSION +}; + +/** + * \brief Flash driver capability macro definitions \ref ARM_FLASH_CAPABILITIES + */ +/* Flash Ready event generation capability values */ +#define EVENT_READY_NOT_AVAILABLE (0u) +#define EVENT_READY_AVAILABLE (1u) +/* Data access size values */ +#define DATA_WIDTH_8BIT (0u) +#define DATA_WIDTH_16BIT (1u) +#define DATA_WIDTH_32BIT (2u) +/* Chip erase capability values */ +#define CHIP_ERASE_NOT_SUPPORTED (0u) +#define CHIP_ERASE_SUPPORTED (1u) + +/* Driver Capabilities */ +static const ARM_FLASH_CAPABILITIES DriverCapabilities = { + EVENT_READY_NOT_AVAILABLE, + DATA_WIDTH_32BIT, + CHIP_ERASE_SUPPORTED +}; + +/* Valid entries for data item width */ +static const uint32_t data_width_byte[] = { + sizeof(uint8_t), + sizeof(uint16_t), + sizeof(uint32_t), +}; + +/** + * \brief Flash status macro definitions \ref ARM_FLASH_STATUS + */ +/* Busy status values of the Flash driver */ +#define DRIVER_STATUS_IDLE (0u) +#define DRIVER_STATUS_BUSY (1u) +/* Error status values of the Flash driver */ +#define DRIVER_STATUS_NO_ERROR (0u) +#define DRIVER_STATUS_ERROR (1u) + +/** + * \brief Arm Flash device structure. + */ +struct arm_flash_dev_t { + struct mt25ql_dev_t* dev; /*!< FLASH memory device structure */ + ARM_FLASH_INFO *data; /*!< FLASH memory device data */ +}; + +/** + * \brief Check if the Flash memory boundaries are not violated. + * \param[in] flash_dev Flash device structure \ref arm_flash_dev_t + * \param[in] offset Highest Flash memory address which would be accessed. + * \return Returns true if Flash memory boundaries are not violated, false + * otherwise. + */ +static bool is_range_valid(struct arm_flash_dev_t *flash_dev, + uint32_t offset) +{ + uint32_t flash_limit = 0; + + /* Calculating the highest address of the Flash memory address range */ + flash_limit = FLASH_TOTAL_SIZE - 1; + + return (offset > flash_limit) ? (false) : (true) ; +} + +/** + * \brief Check if the parameter is aligned to program_unit. + * \param[in] flash_dev Flash device structure \ref arm_flash_dev_t + * \param[in] param Any number that can be checked against the + * program_unit, e.g. Flash memory address or + * data length in bytes. + * \return Returns true if param is aligned to program_unit, false + * otherwise. + */ +static bool is_write_aligned(struct arm_flash_dev_t *flash_dev, + uint32_t param) +{ + return ((param % flash_dev->data->program_unit) != 0) ? (false) : (true); +} + +#if (RTE_QSPI_FLASH0) +static ARM_FLASH_INFO ARM_FLASH0_DEV_DATA = { + .sector_info = NULL, /* Uniform sector layout */ + .sector_count = FLASH_TOTAL_SIZE / SUBSECTOR_4KB, + .sector_size = SUBSECTOR_4KB, + .page_size = FLASH_PAGE_SIZE, + .program_unit = 1u, /* Minimum write size in bytes */ + .erased_value = 0xFF +}; + +static struct arm_flash_dev_t ARM_FLASH0_DEV = { + .dev = &QSPI_FLASH0_DEV, + .data = &(ARM_FLASH0_DEV_DATA) +}; + +/* Flash Status */ +static ARM_FLASH_STATUS ARM_FLASH0_STATUS = {0, 0, 0}; + +static ARM_DRIVER_VERSION ARM_Flash_GetVersion(void) +{ + return DriverVersion; +} + +static ARM_FLASH_CAPABILITIES ARM_Flash_GetCapabilities(void) +{ + return DriverCapabilities; +} + +static int32_t ARM_Flash_Initialize(ARM_Flash_SignalEvent_t cb_event) +{ + enum mt25ql_error_t err = MT25QL_ERR_NONE; + + ARG_UNUSED(cb_event); + + qspi_ip6514e_enable(ARM_FLASH0_DEV.dev->controller); + + /* Configure QSPI Flash controller to operate in single SPI mode and + * to use fast Flash commands */ + err = mt25ql_config_mode(ARM_FLASH0_DEV.dev, MT25QL_FUNC_STATE_FAST); + if(err != MT25QL_ERR_NONE) { + return ARM_DRIVER_ERROR; + } + + return ARM_DRIVER_OK; +} + +static int32_t ARM_Flash_Uninitialize(void) +{ + enum mt25ql_error_t err = MT25QL_ERR_NONE; + + /* Restores the QSPI Flash controller and MT25QL to reset state */ + err = mt25ql_restore_reset_state(ARM_FLASH0_DEV.dev); + if(err != MT25QL_ERR_NONE) { + return ARM_DRIVER_ERROR; + } + + return ARM_DRIVER_OK; +} + +static int32_t ARM_Flash_PowerControl(ARM_POWER_STATE state) +{ + switch(state) { + case ARM_POWER_FULL: + /* Nothing to be done */ + return ARM_DRIVER_OK; + case ARM_POWER_OFF: + case ARM_POWER_LOW: + return ARM_DRIVER_ERROR_UNSUPPORTED; + default: + return ARM_DRIVER_ERROR_PARAMETER; + } +} + +static int32_t ARM_Flash_ReadData(uint32_t addr, void *data, uint32_t cnt) +{ + /* Function includes a workaround for Musca-A QSPI flash when read data + * could be corrupted if read size is not 4 byte aligned. + */ + enum mt25ql_error_t err = MT25QL_ERR_NONE; + bool is_valid = true; + uint32_t extra_bytes = 0; + uint32_t extra_word = 0; + + ARM_FLASH0_STATUS.error = DRIVER_STATUS_NO_ERROR; + + /* Check Flash memory boundaries */ + is_valid = is_range_valid(&ARM_FLASH0_DEV, addr + cnt); + if(is_valid != true) { + ARM_FLASH0_STATUS.error = DRIVER_STATUS_ERROR; + return ARM_DRIVER_ERROR_PARAMETER; + } + + ARM_FLASH0_STATUS.busy = DRIVER_STATUS_BUSY; + + if (cnt % data_width_byte[DriverCapabilities.data_width] != 0) { + extra_bytes = cnt % data_width_byte[DriverCapabilities.data_width]; + cnt -= extra_bytes; + } + + err = mt25ql_command_read(ARM_FLASH0_DEV.dev, addr, data, cnt); + + if (extra_bytes != 0) { + err = mt25ql_command_read(ARM_FLASH0_DEV.dev, addr + cnt, &extra_word, + data_width_byte[DriverCapabilities.data_width]); + memcpy((char *) data + cnt, &extra_word, extra_bytes); + } + + ARM_FLASH0_STATUS.busy = DRIVER_STATUS_IDLE; + + if(err != MT25QL_ERR_NONE) { + ARM_FLASH0_STATUS.error = DRIVER_STATUS_ERROR; + return ARM_DRIVER_ERROR; + } + + return ARM_DRIVER_OK; +} + +static int32_t ARM_Flash_ProgramData(uint32_t addr, + const void *data, uint32_t cnt) +{ + enum mt25ql_error_t err = MT25QL_ERR_NONE; + + ARM_FLASH0_STATUS.error = DRIVER_STATUS_NO_ERROR; + + /* Check Flash memory boundaries and alignment with minimum write size + * (program_unit), data size also needs to be a multiple of program_unit. + */ + if(!(is_range_valid(&ARM_FLASH0_DEV, addr + cnt) && + is_write_aligned(&ARM_FLASH0_DEV, addr) && + is_write_aligned(&ARM_FLASH0_DEV, cnt) )) { + + ARM_FLASH0_STATUS.error = DRIVER_STATUS_ERROR; + return ARM_DRIVER_ERROR_PARAMETER; + } + + ARM_FLASH0_STATUS.busy = DRIVER_STATUS_BUSY; + + err = mt25ql_command_write(ARM_FLASH0_DEV.dev, addr, data, cnt); + + ARM_FLASH0_STATUS.busy = DRIVER_STATUS_IDLE; + + if(err != MT25QL_ERR_NONE) { + ARM_FLASH0_STATUS.error = DRIVER_STATUS_ERROR; + return ARM_DRIVER_ERROR; + } + + return ARM_DRIVER_OK; +} + +static int32_t ARM_Flash_EraseSector(uint32_t addr) +{ + enum mt25ql_error_t err = MT25QL_ERR_NONE; + + ARM_FLASH0_STATUS.error = DRIVER_STATUS_NO_ERROR; + ARM_FLASH0_STATUS.busy = DRIVER_STATUS_BUSY; + + /* The erase function checks whether the address is aligned with + * the sector or subsector and checks the Flash memory boundaries. + */ + err = mt25ql_erase(ARM_FLASH0_DEV.dev, addr, + (enum mt25ql_erase_t) ARM_FLASH0_DEV.data->sector_size); + + ARM_FLASH0_STATUS.busy = DRIVER_STATUS_IDLE; + + if(err != MT25QL_ERR_NONE) { + ARM_FLASH0_STATUS.error = DRIVER_STATUS_ERROR; + + if((err == MT25QL_ERR_ADDR_NOT_ALIGNED) || + (err == MT25QL_ERR_ADDR_TOO_BIG) || + (err == MT25QL_ERR_WRONG_ARGUMENT) ) { + return ARM_DRIVER_ERROR_PARAMETER; + } + return ARM_DRIVER_ERROR; + } + + return ARM_DRIVER_OK; +} + +static int32_t ARM_Flash_EraseChip(void) +{ + enum mt25ql_error_t err = MT25QL_ERR_NONE; + + if(DriverCapabilities.erase_chip == 1) { + + ARM_FLASH0_STATUS.error = DRIVER_STATUS_NO_ERROR; + ARM_FLASH0_STATUS.busy = DRIVER_STATUS_BUSY; + + /* The erase function checks whether the address is aligned with + * the sector or subsector and checks the Flash memory boundaries. + */ + err = mt25ql_erase(ARM_FLASH0_DEV.dev, 0, MT25QL_ERASE_ALL_FLASH); + + ARM_FLASH0_STATUS.busy = DRIVER_STATUS_IDLE; + + if(err != MT25QL_ERR_NONE) { + ARM_FLASH0_STATUS.error = DRIVER_STATUS_ERROR; + + if((err == MT25QL_ERR_ADDR_NOT_ALIGNED) || + (err == MT25QL_ERR_ADDR_TOO_BIG) || + (err == MT25QL_ERR_WRONG_ARGUMENT) ) { + return ARM_DRIVER_ERROR_PARAMETER; + } + return ARM_DRIVER_ERROR; + } + + return ARM_DRIVER_OK; + + } else { + return ARM_DRIVER_ERROR_UNSUPPORTED; + } +} + +static ARM_FLASH_STATUS ARM_Flash_GetStatus(void) +{ + return ARM_FLASH0_STATUS; +} + +static ARM_FLASH_INFO * ARM_Flash_GetInfo(void) +{ + return ARM_FLASH0_DEV.data; +} + +ARM_DRIVER_FLASH Driver_QSPI_FLASH0 = { + ARM_Flash_GetVersion, + ARM_Flash_GetCapabilities, + ARM_Flash_Initialize, + ARM_Flash_Uninitialize, + ARM_Flash_PowerControl, + ARM_Flash_ReadData, + ARM_Flash_ProgramData, + ARM_Flash_EraseSector, + ARM_Flash_EraseChip, + ARM_Flash_GetStatus, + ARM_Flash_GetInfo +}; +#endif /* RTE_QSPI_FLASH0 */ |