From dc7ae21c744272f7796386c4a8ad68cb41278359 Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Sun, 7 Oct 2018 11:59:35 +0000 Subject: Renamed for consistency. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@12346 110e8d01-0319-4d1e-a829-52ad28d1bb01 --- .../serial_nor/devices/micron_n25q/flash_device.c | 593 -------------- .../serial_nor/devices/micron_n25q/flash_device.h | 207 ----- .../serial_nor/devices/micron_n25q/flash_device.mk | 13 - .../devices/micron_n25q/hal_flash_device.c | 593 ++++++++++++++ .../devices/micron_n25q/hal_flash_device.h | 207 +++++ .../devices/micron_n25q/hal_flash_device.mk | 13 + os/hal/lib/complex/serial_nor/hal_serial_nor.c | 867 +++++++++++++++++++++ os/hal/lib/complex/serial_nor/hal_serial_nor.h | 200 +++++ os/hal/lib/complex/serial_nor/serial_nor.c | 867 --------------------- os/hal/lib/complex/serial_nor/serial_nor.h | 200 ----- os/lib/include/chlib.h | 14 +- os/license/chcustomer.h | 2 +- testhal/STM32/multi/WSPI-MFS/.cproject | 1 + testhal/STM32/multi/WSPI-MFS/main.c | 2 +- .../multi/WSPI-MFS/make/stm32l476_discovery.make | 2 +- 15 files changed, 1891 insertions(+), 1890 deletions(-) delete mode 100644 os/hal/lib/complex/serial_nor/devices/micron_n25q/flash_device.c delete mode 100644 os/hal/lib/complex/serial_nor/devices/micron_n25q/flash_device.h delete mode 100644 os/hal/lib/complex/serial_nor/devices/micron_n25q/flash_device.mk create mode 100644 os/hal/lib/complex/serial_nor/devices/micron_n25q/hal_flash_device.c create mode 100644 os/hal/lib/complex/serial_nor/devices/micron_n25q/hal_flash_device.h create mode 100644 os/hal/lib/complex/serial_nor/devices/micron_n25q/hal_flash_device.mk create mode 100644 os/hal/lib/complex/serial_nor/hal_serial_nor.c create mode 100644 os/hal/lib/complex/serial_nor/hal_serial_nor.h delete mode 100644 os/hal/lib/complex/serial_nor/serial_nor.c delete mode 100644 os/hal/lib/complex/serial_nor/serial_nor.h diff --git a/os/hal/lib/complex/serial_nor/devices/micron_n25q/flash_device.c b/os/hal/lib/complex/serial_nor/devices/micron_n25q/flash_device.c deleted file mode 100644 index 5f320ebc8..000000000 --- a/os/hal/lib/complex/serial_nor/devices/micron_n25q/flash_device.c +++ /dev/null @@ -1,593 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio - - 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 flash_device.c - * @brief Micron N25Q serial flash driver code. - * - * @addtogroup MICRON_N25Q - * @ingroup MICRON_N25Q - * @{ - */ - -#include - -#include "hal.h" -#include "serial_nor.h" - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -#define PAGE_SIZE 256U -#define PAGE_MASK (PAGE_SIZE - 1U) - -#if N25Q_USE_SUB_SECTORS == TRUE -#define SECTOR_SIZE 0x00001000U -#define CMD_SECTOR_ERASE N25Q_CMD_SUBSECTOR_ERASE -#else -#define SECTOR_SIZE 0x00010000U -#define CMD_SECTOR_ERASE N25Q_CMD_SECTOR_ERASE -#endif - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/** - * @brief N25Q128 descriptor. - */ -flash_descriptor_t snor_descriptor = { - .attributes = FLASH_ATTR_ERASED_IS_ONE | FLASH_ATTR_REWRITABLE | - FLASH_ATTR_SUSPEND_ERASE_CAPABLE, - .page_size = 256U, - .sectors_count = 0U, /* It is overwritten.*/ - .sectors = NULL, - .sectors_size = SECTOR_SIZE, - .address = 0U -}; - -#if (SNOR_BUS_MODE != SNOR_BUS_MODE_SPI) || defined(__DOXYGEN__) -#if (WSPI_SUPPORTS_MEMMAP == TRUE) || defined(__DOXYGEN__) -/** - * @brief Fast read command for memory mapped mode. - */ -const wspi_command_t snor_memmap_read = { - .cmd = N25Q_CMD_FAST_READ, - .addr = 0, - .dummy = N25Q_READ_DUMMY_CYCLES - 2, - .cfg = WSPI_CFG_ADDR_SIZE_24 | -#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L - WSPI_CFG_CMD_MODE_ONE_LINE | - WSPI_CFG_ADDR_MODE_ONE_LINE | - WSPI_CFG_DATA_MODE_ONE_LINE | -#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L - WSPI_CFG_CMD_MODE_TWO_LINES | - WSPI_CFG_ADDR_MODE_TWO_LINES | - WSPI_CFG_DATA_MODE_TWO_LINES | -#else - WSPI_CFG_CMD_MODE_FOUR_LINES | - WSPI_CFG_ADDR_MODE_FOUR_LINES | - WSPI_CFG_DATA_MODE_FOUR_LINES | -#endif - WSPI_CFG_ALT_MODE_FOUR_LINES | /* Always 4 lines, note.*/ - WSPI_CFG_ALT_SIZE_8 | - WSPI_CFG_SIOO -}; -#endif -#endif - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -#if SNOR_BUS_MODE != SNOR_BUS_MODE_SPI -/* Initial N25Q_CMD_READ_ID command.*/ -static const wspi_command_t n25q_cmd_read_id = { - .cmd = N25Q_CMD_READ_ID, - .cfg = 0U | -#if N25Q_SWITCH_WIDTH == TRUE - WSPI_CFG_CMD_MODE_ONE_LINE | - WSPI_CFG_DATA_MODE_ONE_LINE, -#else -#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L - WSPI_CFG_CMD_MODE_ONE_LINE | - WSPI_CFG_DATA_MODE_ONE_LINE, -#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L - WSPI_CFG_CMD_MODE_TWO_LINES | - WSPI_CFG_DATA_MODE_TWO_LINES, -#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI4L - WSPI_CFG_CMD_MODE_FOUR_LINES | - WSPI_CFG_DATA_MODE_FOUR_LINES, -#else - WSPI_CFG_CMD_MODE_EIGHT_LINES | - WSPI_CFG_DATA_MODE_EIGHT_LINES, -#endif -#endif - .addr = 0, - .alt = 0, - .dummy = 0 -}; - -/* Initial N25Q_CMD_WRITE_ENHANCED_V_CONF_REGISTER command.*/ -static const wspi_command_t n25q_cmd_write_evconf = { - .cmd = N25Q_CMD_WRITE_ENHANCED_V_CONF_REGISTER, - .cfg = 0U | -#if N25Q_SWITCH_WIDTH == TRUE - WSPI_CFG_CMD_MODE_ONE_LINE | - WSPI_CFG_DATA_MODE_ONE_LINE, -#else -#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L - WSPI_CFG_CMD_MODE_ONE_LINE | - WSPI_CFG_DATA_MODE_ONE_LINE, -#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L - WSPI_CFG_CMD_MODE_TWO_LINES | - WSPI_CFG_DATA_MODE_TWO_LINES, -#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI4L - WSPI_CFG_CMD_MODE_FOUR_LINES | - WSPI_CFG_DATA_MODE_FOUR_LINES, -#else - WSPI_CFG_CMD_MODE_EIGHT_LINES | - WSPI_CFG_DATA_MODE_EIGHT_LINES, -#endif -#endif - .addr = 0, - .alt = 0, - .dummy = 0 -}; - -/* Initial N25Q_CMD_WRITE_ENABLE command.*/ -static const wspi_command_t n25q_cmd_write_enable = { - .cmd = N25Q_CMD_WRITE_ENABLE, - .cfg = 0U | -#if N25Q_SWITCH_WIDTH == TRUE - WSPI_CFG_CMD_MODE_ONE_LINE, -#else -#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L - WSPI_CFG_CMD_MODE_ONE_LINE, -#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L - WSPI_CFG_CMD_MODE_TWO_LINES, -#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI4L - WSPI_CFG_CMD_MODE_FOUR_LINES, -#else - WSPI_CFG_CMD_MODE_EIGHT_LINES, -#endif -#endif - .addr = 0, - .alt = 0, - .dummy = 0 -}; - -/* Bus width initialization.*/ -#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L -static const uint8_t n25q_evconf_value[1] = {0xCF}; -#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L -static const uint8_t n25q_evconf_value[1] = {0x8F}; -#else -static const uint8_t n25q_evconf_value[1] = {0x4F}; -#endif -#endif /* SNOR_BUS_MODE != SNOR_BUS_MODE_SPI */ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -static bool n25q_find_id(const uint8_t *set, size_t size, uint8_t element) { - size_t i; - - for (i = 0; i < size; i++) { - if (set[i] == element) { - return true; - } - } - return false; -} - -static flash_error_t n25q_poll_status(SNORDriver *devp) { - uint8_t sts; - - do { -#if N25Q_NICE_WAITING == TRUE - osalThreadSleepMilliseconds(1); -#endif - /* Read status command.*/ - bus_cmd_receive(devp->config->busp, N25Q_CMD_READ_FLAG_STATUS_REGISTER, - 1, &sts); - } while ((sts & N25Q_FLAGS_PROGRAM_ERASE) == 0U); - - /* Checking for errors.*/ - if ((sts & N25Q_FLAGS_ALL_ERRORS) != 0U) { - /* Clearing status register.*/ - bus_cmd(devp->config->busp, N25Q_CMD_CLEAR_FLAG_STATUS_REGISTER); - - /* Program operation failed.*/ - return FLASH_ERROR_PROGRAM; - } - - return FLASH_NO_ERROR; -} - -#if (SNOR_BUS_MODE != SNOR_BUS_MODE_SPI) || defined(__DOXYGEN__) -static void n25q_reset_memory(SNORDriver *devp) { - - /* 1x N25Q_CMD_RESET_ENABLE command.*/ - static const wspi_command_t cmd_reset_enable_1 = { - .cmd = N25Q_CMD_RESET_ENABLE, - .cfg = WSPI_CFG_CMD_MODE_ONE_LINE, - .addr = 0, - .alt = 0, - .dummy = 0 - }; - - /* 1x N25Q_CMD_RESET_MEMORY command.*/ - static const wspi_command_t cmd_reset_memory_1 = { - .cmd = N25Q_CMD_RESET_MEMORY, - .cfg = WSPI_CFG_CMD_MODE_ONE_LINE, - .addr = 0, - .alt = 0, - .dummy = 0 - }; - - /* If the device is in one bit mode then the following commands are - rejected because shorter than 8 bits. If the device is in multiple - bits mode then the commands are accepted and the device is reset to - one bit mode.*/ -#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI4L - /* 4x N25Q_CMD_RESET_ENABLE command.*/ - static const wspi_command_t cmd_reset_enable_4 = { - .cmd = N25Q_CMD_RESET_ENABLE, - .cfg = WSPI_CFG_CMD_MODE_FOUR_LINES, - .addr = 0, - .alt = 0, - .dummy = 0 - }; - - /* 4x N25Q_CMD_RESET_MEMORY command.*/ - static const wspi_command_t cmd_reset_memory_4 = { - .cmd = N25Q_CMD_RESET_MEMORY, - .cfg = WSPI_CFG_CMD_MODE_FOUR_LINES, - .addr = 0, - .alt = 0, - .dummy = 0 - }; - - wspiCommand(devp->config->busp, &cmd_reset_enable_4); - wspiCommand(devp->config->busp, &cmd_reset_memory_4); -#else - /* 2x N25Q_CMD_RESET_ENABLE command.*/ - static const wspi_command_t cmd_reset_enable_2 = { - .cfg = WSPI_CFG_CMD(N25Q_CMD_RESET_ENABLE) | - WSPI_CFG_CMD_MODE_TWO_LINES, - .addr = 0, - .alt = 0, - .dummy = 0 - }; - - /* 2x N25Q_CMD_RESET_MEMORY command.*/ - static const wspi_command_t cmd_reset_memory_2 = { - .cfg = WSPI_CFG_CMD(N25Q_CMD_RESET_MEMORY) | - WSPI_CFG_CMD_MODE_TWO_LINES, - .addr = 0, - .alt = 0, - .dummy = 0 - }; - - wspiCommand(devp->config->busp, &cmd_reset_enable_2); - wspiCommand(devp->config->busp, &cmd_reset_memory_2); -#endif - - /* Now the device should be in one bit mode for sure and we perform a - device reset.*/ - wspiCommand(devp->config->busp, &cmd_reset_enable_1); - wspiCommand(devp->config->busp, &cmd_reset_memory_1); -} -#endif /* #if SNOR_BUS_MODE != SNOR_BUS_MODE_SPI */ - -static const uint8_t n25q_manufacturer_ids[] = N25Q_SUPPORTED_MANUFACTURE_IDS; -static const uint8_t n25q_memory_type_ids[] = N25Q_SUPPORTED_MEMORY_TYPE_IDS; - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -void snor_device_init(SNORDriver *devp) { - -#if SNOR_BUS_MODE == SNOR_BUS_MODE_SPI - /* Reading device ID.*/ - bus_cmd_receive(devp->config->busp, N25Q_CMD_READ_ID, - sizeof devp->device_id, devp->device_id); - -#else /* SNOR_BUS_MODE != SNOR_BUS_MODE_SPI */ - /* Attempting a reset of the XIP mode, it could be in an unexpected state - because a CPU reset does not reset the memory too.*/ - snor_reset_xip(devp); - - /* Attempting a reset of the device, it could be in an unexpected state - because a CPU reset does not reset the memory too.*/ - n25q_reset_memory(devp); - - /* Reading device ID and unique ID.*/ - wspiReceive(devp->config->busp, &n25q_cmd_read_id, - sizeof devp->device_id, devp->device_id); -#endif /* SNOR_BUS_MODE != SNOR_BUS_MODE_SPI */ - - /* Checking if the device is white listed.*/ - osalDbgAssert(n25q_find_id(n25q_manufacturer_ids, - sizeof n25q_manufacturer_ids, - devp->device_id[0]), - "invalid manufacturer id"); - osalDbgAssert(n25q_find_id(n25q_memory_type_ids, - sizeof n25q_memory_type_ids, - devp->device_id[1]), - "invalid memory type id"); - -#if (SNOR_BUS_MODE != SNOR_BUS_MODE_SPI) && (N25Q_SWITCH_WIDTH == TRUE) - /* Setting up final bus width.*/ - wspiCommand(devp->config->busp, &n25q_cmd_write_enable); - wspiSend(devp->config->busp, &n25q_cmd_write_evconf, 1, n25q_evconf_value); - - { - uint8_t id[3]; - - /* Reading ID again for confirmation.*/ - bus_cmd_receive(devp->config->busp, N25Q_CMD_MULTIPLE_IO_READ_ID, 3, id); - - /* Checking if the device is white listed.*/ - osalDbgAssert(memcmp(id, devp->device_id, 3) == 0, - "id confirmation failed"); - } -#endif - - /* Setting up the device size.*/ - snor_descriptor.sectors_count = (1U << (size_t)devp->device_id[2]) / - SECTOR_SIZE; - -#if (SNOR_BUS_MODE != SNOR_BUS_MODE_SPI) - { - static const uint8_t flash_conf[1] = { - (N25Q_READ_DUMMY_CYCLES << 4U) | 0x0FU - }; - - /* Setting up the dummy cycles to be used for fast read operations.*/ - bus_cmd(devp->config->busp, N25Q_CMD_WRITE_ENABLE); - bus_cmd_send(devp->config->busp, N25Q_CMD_WRITE_V_CONF_REGISTER, - 1, flash_conf); - } -#endif -} - -const flash_descriptor_t *snor_get_descriptor(void *instance) { - SNORDriver *devp = (SNORDriver *)instance; - - osalDbgCheck(instance != NULL); - osalDbgAssert((devp->state != FLASH_UNINIT) && (devp->state != FLASH_STOP), - "invalid state"); - - return &snor_descriptor; -} - -flash_error_t snor_device_read(SNORDriver *devp, flash_offset_t offset, - size_t n, uint8_t *rp) { - -#if SNOR_BUS_MODE != SNOR_BUS_MODE_SPI - /* Fast read command in WSPI mode.*/ - bus_cmd_addr_dummy_receive(devp->config->busp, N25Q_CMD_FAST_READ, - offset, N25Q_READ_DUMMY_CYCLES, n, rp); -#else - /* Normal read command in SPI mode.*/ - bus_cmd_addr_receive(devp->config->busp, N25Q_CMD_READ, - offset, n, rp); -#endif - - return FLASH_NO_ERROR; -} - -flash_error_t snor_device_program(SNORDriver *devp, flash_offset_t offset, - size_t n, const uint8_t *pp) { - - /* Data is programmed page by page.*/ - while (n > 0U) { - flash_error_t err; - - /* Data size that can be written in a single program page operation.*/ - size_t chunk = (size_t)(((offset | PAGE_MASK) + 1U) - offset); - if (chunk > n) { - chunk = n; - } - - /* Enabling write operation.*/ - bus_cmd(devp->config->busp, N25Q_CMD_WRITE_ENABLE); - - /* Page program command.*/ - bus_cmd_addr_send(devp->config->busp, N25Q_CMD_PAGE_PROGRAM, offset, - chunk, pp); - - /* Wait for status and check errors.*/ - err = n25q_poll_status(devp); - if (err != FLASH_NO_ERROR) { - - return err; - } - - /* Next page.*/ - offset += chunk; - pp += chunk; - n -= chunk; - } - - return FLASH_NO_ERROR; -} - -flash_error_t snor_device_start_erase_all(SNORDriver *devp) { - - /* Enabling write operation.*/ - bus_cmd(devp->config->busp, N25Q_CMD_WRITE_ENABLE); - - /* Bulk erase command.*/ - bus_cmd(devp->config->busp, N25Q_CMD_BULK_ERASE); - - return FLASH_NO_ERROR; -} - -flash_error_t snor_device_start_erase_sector(SNORDriver *devp, - flash_sector_t sector) { - flash_offset_t offset = (flash_offset_t)(sector * SECTOR_SIZE); - - /* Enabling write operation.*/ - bus_cmd(devp->config->busp, N25Q_CMD_WRITE_ENABLE); - - /* Sector erase command.*/ - bus_cmd_addr(devp->config->busp, N25Q_CMD_SECTOR_ERASE, offset); - - return FLASH_NO_ERROR; -} - -flash_error_t snor_device_verify_erase(SNORDriver *devp, - flash_sector_t sector) { - uint8_t cmpbuf[N25Q_COMPARE_BUFFER_SIZE]; - flash_offset_t offset; - size_t n; - - /* Read command.*/ - offset = (flash_offset_t)(sector * SECTOR_SIZE); - n = SECTOR_SIZE; - while (n > 0U) { - uint8_t *p; - -#if SNOR_BUS_MODE != SNOR_BUS_MODE_SPI - bus_cmd_addr_dummy_receive(devp->config->busp, N25Q_CMD_FAST_READ, - offset, N25Q_READ_DUMMY_CYCLES, - sizeof cmpbuf, cmpbuf); -#else - /* Normal read command in SPI mode.*/ - bus_cmd_addr_receive(devp->config->busp, N25Q_CMD_READ, - offset, sizeof cmpbuf, cmpbuf); -#endif - - /* Checking for erased state of current buffer.*/ - for (p = cmpbuf; p < &cmpbuf[N25Q_COMPARE_BUFFER_SIZE]; p++) { - if (*p != 0xFFU) { - /* Ready state again.*/ - devp->state = FLASH_READY; - - return FLASH_ERROR_VERIFY; - } - } - - offset += sizeof cmpbuf; - n -= sizeof cmpbuf; - } - - return FLASH_NO_ERROR; -} - -flash_error_t snor_device_query_erase(SNORDriver *devp, uint32_t *msec) { - uint8_t sts; - - /* Read status command.*/ - bus_cmd_receive(devp->config->busp, N25Q_CMD_READ_FLAG_STATUS_REGISTER, - 1, &sts); - - /* If the P/E bit is zero (busy) or the flash in a suspended state then - report that the operation is still in progress.*/ - if (((sts & N25Q_FLAGS_PROGRAM_ERASE) == 0U) || - ((sts & N25Q_FLAGS_ERASE_SUSPEND) != 0U)) { - - /* Recommended time before polling again, this is a simplified - implementation.*/ - if (msec != NULL) { - *msec = 1U; - } - - return FLASH_BUSY_ERASING; - } - - /* Checking for errors.*/ - if ((sts & N25Q_FLAGS_ALL_ERRORS) != 0U) { - - /* Clearing status register.*/ - bus_cmd(devp->config->busp, N25Q_CMD_CLEAR_FLAG_STATUS_REGISTER); - - /* Erase operation failed.*/ - return FLASH_ERROR_ERASE; - } - - return FLASH_NO_ERROR; -} - -flash_error_t snor_device_read_sfdp(SNORDriver *devp, flash_offset_t offset, - size_t n, uint8_t *rp) { - - (void)devp; - (void)rp; - (void)offset; - (void)n; - - return FLASH_NO_ERROR; -} - -#if (SNOR_BUS_MODE != SNOR_BUS_MODE_SPI) || defined(__DOXYGEN__) -void snor_activate_xip(SNORDriver *devp) { - static const uint8_t flash_status_xip[1] = { - (N25Q_READ_DUMMY_CYCLES << 4U) | 0x07U - }; - - /* Activating XIP mode in the device.*/ - bus_cmd(devp->config->busp, N25Q_CMD_WRITE_ENABLE); - bus_cmd_send(devp->config->busp, N25Q_CMD_WRITE_V_CONF_REGISTER, - 1, flash_status_xip); -} - -void snor_reset_xip(SNORDriver *devp) { - static const uint8_t flash_conf[1] = { - (N25Q_READ_DUMMY_CYCLES << 4U) | 0x0FU - }; - wspi_command_t cmd; - uint8_t buf[1]; - - /* Resetting XIP mode by reading one byte without XIP confirmation bit.*/ - cmd.alt = 0xFF; - cmd.addr = 0; - cmd.dummy = N25Q_READ_DUMMY_CYCLES - 2; - cmd.cfg = WSPI_CFG_CMD_MODE_NONE | - WSPI_CFG_ADDR_SIZE_24 | -#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L - WSPI_CFG_ADDR_MODE_ONE_LINE | - WSPI_CFG_DATA_MODE_ONE_LINE | -#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L - WSPI_CFG_ADDR_MODE_TWO_LINES | - WSPI_CFG_DATA_MODE_TWO_LINES | -#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI4L - WSPI_CFG_ADDR_MODE_FOUR_LINES | - WSPI_CFG_DATA_MODE_FOUR_LINES | -#else - WSPI_CFG_ADDR_MODE_EIGHT_LINES | - WSPI_CFG_DATA_MODE_EIGHT_LINES | -#endif - WSPI_CFG_ALT_MODE_FOUR_LINES | /* Always 4 lines, note.*/ - WSPI_CFG_ALT_SIZE_8; - wspiReceive(devp->config->busp, &cmd, 1, buf); - - /* Enabling write operation.*/ - bus_cmd(devp->config->busp, N25Q_CMD_WRITE_ENABLE); - - /* Rewriting volatile configuration register.*/ - bus_cmd_send(devp->config->busp, N25Q_CMD_WRITE_V_CONF_REGISTER, - 1, flash_conf); -} -#endif /* SNOR_BUS_MODE != SNOR_BUS_MODE_SPI */ - -/** @} */ diff --git a/os/hal/lib/complex/serial_nor/devices/micron_n25q/flash_device.h b/os/hal/lib/complex/serial_nor/devices/micron_n25q/flash_device.h deleted file mode 100644 index 8ae3bae13..000000000 --- a/os/hal/lib/complex/serial_nor/devices/micron_n25q/flash_device.h +++ /dev/null @@ -1,207 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio - - 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 flash_device.h - * @brief Micron N25Q serial flash driver header. - * - * @addtogroup MICRON_N25Q - * @ingroup MICRON_N25Q - * @{ - */ - -#ifndef FLASH_DEVICE_H -#define FLASH_DEVICE_H - -/*===========================================================================*/ -/* Driver constants. */ -/*===========================================================================*/ - -/** - * @name Device identification - * @{ - */ -#define N25Q_SUPPORTED_MANUFACTURE_IDS {0x20} -#define N25Q_SUPPORTED_MEMORY_TYPE_IDS {0xBA, 0xBB} -/** @} */ - -/** - * @name Command codes - * @{ - */ -#define N25Q_CMD_RESET_ENABLE 0x66 -#define N25Q_CMD_RESET_MEMORY 0x99 -#define N25Q_CMD_READ_ID 0x9F -#define N25Q_CMD_MULTIPLE_IO_READ_ID 0xAF -#define N25Q_CMD_READ_DISCOVERY_PARAMETER 0x5A -#define N25Q_CMD_READ 0x03 -#define N25Q_CMD_FAST_READ 0x0B -#define N25Q_CMD_WRITE_ENABLE 0x06 -#define N25Q_CMD_WRITE_DISABLE 0x04 -#define N25Q_CMD_READ_STATUS_REGISTER 0x05 -#define N25Q_CMD_WRITE_STATUS_REGISTER 0x01 -#define N25Q_CMD_READ_LOCK_REGISTER 0xE8 -#define N25Q_CMD_WRITE_LOCK_REGISTER 0xE5 -#define N25Q_CMD_READ_FLAG_STATUS_REGISTER 0x70 -#define N25Q_CMD_CLEAR_FLAG_STATUS_REGISTER 0x50 -#define N25Q_CMD_READ_NV_CONFIGURATION_REGISTER 0xB5 -#define N25Q_CMD_WRITE_NV_CONFIGURATION_REGISTER 0xB1 -#define N25Q_CMD_READ_V_CONF_REGISTER 0x85 -#define N25Q_CMD_WRITE_V_CONF_REGISTER 0x81 -#define N25Q_CMD_READ_ENHANCED_V_CONF_REGISTER 0x65 -#define N25Q_CMD_WRITE_ENHANCED_V_CONF_REGISTER 0x61 -#define N25Q_CMD_PAGE_PROGRAM 0x02 -#define N25Q_CMD_SUBSECTOR_ERASE 0x20 -#define N25Q_CMD_SECTOR_ERASE 0xD8 -#define N25Q_CMD_BULK_ERASE 0xC7 -#define N25Q_CMD_PROGRAM_ERASE_RESUME 0x7A -#define N25Q_CMD_PROGRAM_ERASE_SUSPEND 0x75 -#define N25Q_CMD_READ_OTP_ARRAY 0x4B -#define N25Q_CMD_PROGRAM_OTP_ARRAY 0x42 -/** @} */ - -/** - * @name Flags status register bits - * @{ - */ -#define N25Q_FLAGS_PROGRAM_ERASE 0x80U -#define N25Q_FLAGS_ERASE_SUSPEND 0x40U -#define N25Q_FLAGS_ERASE_ERROR 0x20U -#define N25Q_FLAGS_PROGRAM_ERROR 0x10U -#define N25Q_FLAGS_VPP_ERROR 0x08U -#define N25Q_FLAGS_PROGRAM_SUSPEND 0x04U -#define N25Q_FLAGS_PROTECTION_ERROR 0x02U -#define N25Q_FLAGS_RESERVED 0x01U -#define N25Q_FLAGS_ALL_ERRORS (N25Q_FLAGS_ERASE_ERROR | \ - N25Q_FLAGS_PROGRAM_ERROR | \ - N25Q_FLAGS_VPP_ERROR | \ - N25Q_FLAGS_PROTECTION_ERROR) -/** @} */ - -/*===========================================================================*/ -/* Driver pre-compile time settings. */ -/*===========================================================================*/ - -/** - * @brief Switch WSPI bus width on initialization. - * @details A bus width initialization is performed by writing the - * Enhanced Volatile Configuration Register. If the flash - * device is configured using the Non Volatile Configuration - * Register then this option is not required. - * @note This option is only valid in QSPI bus modes. - */ -#if !defined(N25Q_SWITCH_WIDTH) || defined(__DOXYGEN__) -#define N25Q_SWITCH_WIDTH TRUE -#endif - -/** - * @brief Delays insertions. - * @details If enabled this options inserts delays into the flash waiting - * routines releasing some extra CPU time for threads with lower - * priority, this may slow down the driver a bit however. - */ -#if !defined(N25Q_NICE_WAITING) || defined(__DOXYGEN__) -#define N25Q_NICE_WAITING TRUE -#endif - -/** - * @brief Uses 4kB sub-sectors rather than 64kB sectors. - */ -#if !defined(N25Q_USE_SUB_SECTORS) || defined(__DOXYGEN__) -#define N25Q_USE_SUB_SECTORS FALSE -#endif - -/** - * @brief Size of the compare buffer. - * @details This buffer is allocated in the stack frame of the function - * @p flashVerifyErase() and its size must be a power of two. - * Larger buffers lead to better verify performance but increase - * stack usage for that function. - */ -#if !defined(N25Q_COMPARE_BUFFER_SIZE) || defined(__DOXYGEN__) -#define N25Q_COMPARE_BUFFER_SIZE 32 -#endif - -/** - * @brief Number of dummy cycles for fast read (1..15). - * @details This is the number of dummy cycles to be used for fast read - * operations. - */ -#if !defined(N25Q_READ_DUMMY_CYCLES) || defined(__DOXYGEN__) -#define N25Q_READ_DUMMY_CYCLES 8 -#endif - -/*===========================================================================*/ -/* Derived constants and error checks. */ -/*===========================================================================*/ - -#if (N25Q_COMPARE_BUFFER_SIZE & (N25Q_COMPARE_BUFFER_SIZE - 1)) != 0 -#error "invalid N25Q_COMPARE_BUFFER_SIZE value" -#endif - -#if (N25Q_READ_DUMMY_CYCLES < 1) || (N25Q_READ_DUMMY_CYCLES > 15) -#error "invalid N25Q_READ_DUMMY_CYCLES value (1..15)" -#endif - -/*===========================================================================*/ -/* Driver data structures and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver macros. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -#if !defined(__DOXYGEN__) -extern flash_descriptor_t snor_descriptor; -#endif - -#if (SNOR_BUS_MODE != SNOR_BUS_MODE_SPI) && (WSPI_SUPPORTS_MEMMAP == TRUE) -extern const wspi_command_t snor_memmap_read; -#endif - -#ifdef __cplusplus -extern "C" { -#endif - void snor_device_init(SNORDriver *devp); - const flash_descriptor_t *snor_get_descriptor(void *instance); - flash_error_t snor_device_read(SNORDriver *devp, flash_offset_t offset, - size_t n, uint8_t *rp); - flash_error_t snor_device_program(SNORDriver *devp, flash_offset_t offset, - size_t n, const uint8_t *pp); - flash_error_t snor_device_start_erase_all(SNORDriver *devp); - flash_error_t snor_device_start_erase_sector(SNORDriver *devp, - flash_sector_t sector); - flash_error_t snor_device_verify_erase(SNORDriver *devp, - flash_sector_t sector); - flash_error_t snor_device_query_erase(SNORDriver *devp, uint32_t *msec); - flash_error_t snor_device_read_sfdp(SNORDriver *devp, flash_offset_t offset, - size_t n, uint8_t *rp); -#if SNOR_BUS_MODE != SNOR_BUS_MODE_SPI - void snor_activate_xip(SNORDriver *devp); - void snor_reset_xip(SNORDriver *devp); -#endif -#ifdef __cplusplus -} -#endif - -#endif /* FLASH_DEVICE_H */ - -/** @} */ - diff --git a/os/hal/lib/complex/serial_nor/devices/micron_n25q/flash_device.mk b/os/hal/lib/complex/serial_nor/devices/micron_n25q/flash_device.mk deleted file mode 100644 index 07103fe29..000000000 --- a/os/hal/lib/complex/serial_nor/devices/micron_n25q/flash_device.mk +++ /dev/null @@ -1,13 +0,0 @@ -# List of all the Micron N25Q device files. -N25QSRC := $(CHIBIOS)/os/hal/lib/peripherals/flash/hal_flash.c \ - $(CHIBIOS)/os/hal/lib/complex/serial_nor/serial_nor.c \ - $(CHIBIOS)/os/hal/lib/complex/serial_nor/devices/micron_n25q/flash_device.c - -# Required include directories -N25QINC := $(CHIBIOS)/os/hal/lib/peripherals/flash \ - $(CHIBIOS)/os/hal/lib/complex/serial_nor \ - $(CHIBIOS)/os/hal/lib/complex/serial_nor/devices/micron_n25q - -# Shared variables -ALLCSRC += $(N25QSRC) -ALLINC += $(N25QINC) diff --git a/os/hal/lib/complex/serial_nor/devices/micron_n25q/hal_flash_device.c b/os/hal/lib/complex/serial_nor/devices/micron_n25q/hal_flash_device.c new file mode 100644 index 000000000..1bba8f99a --- /dev/null +++ b/os/hal/lib/complex/serial_nor/devices/micron_n25q/hal_flash_device.c @@ -0,0 +1,593 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 flash_device.c + * @brief Micron N25Q serial flash driver code. + * + * @addtogroup MICRON_N25Q + * @ingroup MICRON_N25Q + * @{ + */ + +#include + +#include "hal.h" +#include "hal_serial_nor.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define PAGE_SIZE 256U +#define PAGE_MASK (PAGE_SIZE - 1U) + +#if N25Q_USE_SUB_SECTORS == TRUE +#define SECTOR_SIZE 0x00001000U +#define CMD_SECTOR_ERASE N25Q_CMD_SUBSECTOR_ERASE +#else +#define SECTOR_SIZE 0x00010000U +#define CMD_SECTOR_ERASE N25Q_CMD_SECTOR_ERASE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief N25Q128 descriptor. + */ +flash_descriptor_t snor_descriptor = { + .attributes = FLASH_ATTR_ERASED_IS_ONE | FLASH_ATTR_REWRITABLE | + FLASH_ATTR_SUSPEND_ERASE_CAPABLE, + .page_size = 256U, + .sectors_count = 0U, /* It is overwritten.*/ + .sectors = NULL, + .sectors_size = SECTOR_SIZE, + .address = 0U +}; + +#if (SNOR_BUS_MODE != SNOR_BUS_MODE_SPI) || defined(__DOXYGEN__) +#if (WSPI_SUPPORTS_MEMMAP == TRUE) || defined(__DOXYGEN__) +/** + * @brief Fast read command for memory mapped mode. + */ +const wspi_command_t snor_memmap_read = { + .cmd = N25Q_CMD_FAST_READ, + .addr = 0, + .dummy = N25Q_READ_DUMMY_CYCLES - 2, + .cfg = WSPI_CFG_ADDR_SIZE_24 | +#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L + WSPI_CFG_CMD_MODE_ONE_LINE | + WSPI_CFG_ADDR_MODE_ONE_LINE | + WSPI_CFG_DATA_MODE_ONE_LINE | +#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L + WSPI_CFG_CMD_MODE_TWO_LINES | + WSPI_CFG_ADDR_MODE_TWO_LINES | + WSPI_CFG_DATA_MODE_TWO_LINES | +#else + WSPI_CFG_CMD_MODE_FOUR_LINES | + WSPI_CFG_ADDR_MODE_FOUR_LINES | + WSPI_CFG_DATA_MODE_FOUR_LINES | +#endif + WSPI_CFG_ALT_MODE_FOUR_LINES | /* Always 4 lines, note.*/ + WSPI_CFG_ALT_SIZE_8 | + WSPI_CFG_SIOO +}; +#endif +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +#if SNOR_BUS_MODE != SNOR_BUS_MODE_SPI +/* Initial N25Q_CMD_READ_ID command.*/ +static const wspi_command_t n25q_cmd_read_id = { + .cmd = N25Q_CMD_READ_ID, + .cfg = 0U | +#if N25Q_SWITCH_WIDTH == TRUE + WSPI_CFG_CMD_MODE_ONE_LINE | + WSPI_CFG_DATA_MODE_ONE_LINE, +#else +#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L + WSPI_CFG_CMD_MODE_ONE_LINE | + WSPI_CFG_DATA_MODE_ONE_LINE, +#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L + WSPI_CFG_CMD_MODE_TWO_LINES | + WSPI_CFG_DATA_MODE_TWO_LINES, +#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI4L + WSPI_CFG_CMD_MODE_FOUR_LINES | + WSPI_CFG_DATA_MODE_FOUR_LINES, +#else + WSPI_CFG_CMD_MODE_EIGHT_LINES | + WSPI_CFG_DATA_MODE_EIGHT_LINES, +#endif +#endif + .addr = 0, + .alt = 0, + .dummy = 0 +}; + +/* Initial N25Q_CMD_WRITE_ENHANCED_V_CONF_REGISTER command.*/ +static const wspi_command_t n25q_cmd_write_evconf = { + .cmd = N25Q_CMD_WRITE_ENHANCED_V_CONF_REGISTER, + .cfg = 0U | +#if N25Q_SWITCH_WIDTH == TRUE + WSPI_CFG_CMD_MODE_ONE_LINE | + WSPI_CFG_DATA_MODE_ONE_LINE, +#else +#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L + WSPI_CFG_CMD_MODE_ONE_LINE | + WSPI_CFG_DATA_MODE_ONE_LINE, +#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L + WSPI_CFG_CMD_MODE_TWO_LINES | + WSPI_CFG_DATA_MODE_TWO_LINES, +#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI4L + WSPI_CFG_CMD_MODE_FOUR_LINES | + WSPI_CFG_DATA_MODE_FOUR_LINES, +#else + WSPI_CFG_CMD_MODE_EIGHT_LINES | + WSPI_CFG_DATA_MODE_EIGHT_LINES, +#endif +#endif + .addr = 0, + .alt = 0, + .dummy = 0 +}; + +/* Initial N25Q_CMD_WRITE_ENABLE command.*/ +static const wspi_command_t n25q_cmd_write_enable = { + .cmd = N25Q_CMD_WRITE_ENABLE, + .cfg = 0U | +#if N25Q_SWITCH_WIDTH == TRUE + WSPI_CFG_CMD_MODE_ONE_LINE, +#else +#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L + WSPI_CFG_CMD_MODE_ONE_LINE, +#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L + WSPI_CFG_CMD_MODE_TWO_LINES, +#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI4L + WSPI_CFG_CMD_MODE_FOUR_LINES, +#else + WSPI_CFG_CMD_MODE_EIGHT_LINES, +#endif +#endif + .addr = 0, + .alt = 0, + .dummy = 0 +}; + +/* Bus width initialization.*/ +#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L +static const uint8_t n25q_evconf_value[1] = {0xCF}; +#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L +static const uint8_t n25q_evconf_value[1] = {0x8F}; +#else +static const uint8_t n25q_evconf_value[1] = {0x4F}; +#endif +#endif /* SNOR_BUS_MODE != SNOR_BUS_MODE_SPI */ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static bool n25q_find_id(const uint8_t *set, size_t size, uint8_t element) { + size_t i; + + for (i = 0; i < size; i++) { + if (set[i] == element) { + return true; + } + } + return false; +} + +static flash_error_t n25q_poll_status(SNORDriver *devp) { + uint8_t sts; + + do { +#if N25Q_NICE_WAITING == TRUE + osalThreadSleepMilliseconds(1); +#endif + /* Read status command.*/ + bus_cmd_receive(devp->config->busp, N25Q_CMD_READ_FLAG_STATUS_REGISTER, + 1, &sts); + } while ((sts & N25Q_FLAGS_PROGRAM_ERASE) == 0U); + + /* Checking for errors.*/ + if ((sts & N25Q_FLAGS_ALL_ERRORS) != 0U) { + /* Clearing status register.*/ + bus_cmd(devp->config->busp, N25Q_CMD_CLEAR_FLAG_STATUS_REGISTER); + + /* Program operation failed.*/ + return FLASH_ERROR_PROGRAM; + } + + return FLASH_NO_ERROR; +} + +#if (SNOR_BUS_MODE != SNOR_BUS_MODE_SPI) || defined(__DOXYGEN__) +static void n25q_reset_memory(SNORDriver *devp) { + + /* 1x N25Q_CMD_RESET_ENABLE command.*/ + static const wspi_command_t cmd_reset_enable_1 = { + .cmd = N25Q_CMD_RESET_ENABLE, + .cfg = WSPI_CFG_CMD_MODE_ONE_LINE, + .addr = 0, + .alt = 0, + .dummy = 0 + }; + + /* 1x N25Q_CMD_RESET_MEMORY command.*/ + static const wspi_command_t cmd_reset_memory_1 = { + .cmd = N25Q_CMD_RESET_MEMORY, + .cfg = WSPI_CFG_CMD_MODE_ONE_LINE, + .addr = 0, + .alt = 0, + .dummy = 0 + }; + + /* If the device is in one bit mode then the following commands are + rejected because shorter than 8 bits. If the device is in multiple + bits mode then the commands are accepted and the device is reset to + one bit mode.*/ +#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI4L + /* 4x N25Q_CMD_RESET_ENABLE command.*/ + static const wspi_command_t cmd_reset_enable_4 = { + .cmd = N25Q_CMD_RESET_ENABLE, + .cfg = WSPI_CFG_CMD_MODE_FOUR_LINES, + .addr = 0, + .alt = 0, + .dummy = 0 + }; + + /* 4x N25Q_CMD_RESET_MEMORY command.*/ + static const wspi_command_t cmd_reset_memory_4 = { + .cmd = N25Q_CMD_RESET_MEMORY, + .cfg = WSPI_CFG_CMD_MODE_FOUR_LINES, + .addr = 0, + .alt = 0, + .dummy = 0 + }; + + wspiCommand(devp->config->busp, &cmd_reset_enable_4); + wspiCommand(devp->config->busp, &cmd_reset_memory_4); +#else + /* 2x N25Q_CMD_RESET_ENABLE command.*/ + static const wspi_command_t cmd_reset_enable_2 = { + .cfg = WSPI_CFG_CMD(N25Q_CMD_RESET_ENABLE) | + WSPI_CFG_CMD_MODE_TWO_LINES, + .addr = 0, + .alt = 0, + .dummy = 0 + }; + + /* 2x N25Q_CMD_RESET_MEMORY command.*/ + static const wspi_command_t cmd_reset_memory_2 = { + .cfg = WSPI_CFG_CMD(N25Q_CMD_RESET_MEMORY) | + WSPI_CFG_CMD_MODE_TWO_LINES, + .addr = 0, + .alt = 0, + .dummy = 0 + }; + + wspiCommand(devp->config->busp, &cmd_reset_enable_2); + wspiCommand(devp->config->busp, &cmd_reset_memory_2); +#endif + + /* Now the device should be in one bit mode for sure and we perform a + device reset.*/ + wspiCommand(devp->config->busp, &cmd_reset_enable_1); + wspiCommand(devp->config->busp, &cmd_reset_memory_1); +} +#endif /* #if SNOR_BUS_MODE != SNOR_BUS_MODE_SPI */ + +static const uint8_t n25q_manufacturer_ids[] = N25Q_SUPPORTED_MANUFACTURE_IDS; +static const uint8_t n25q_memory_type_ids[] = N25Q_SUPPORTED_MEMORY_TYPE_IDS; + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +void snor_device_init(SNORDriver *devp) { + +#if SNOR_BUS_MODE == SNOR_BUS_MODE_SPI + /* Reading device ID.*/ + bus_cmd_receive(devp->config->busp, N25Q_CMD_READ_ID, + sizeof devp->device_id, devp->device_id); + +#else /* SNOR_BUS_MODE != SNOR_BUS_MODE_SPI */ + /* Attempting a reset of the XIP mode, it could be in an unexpected state + because a CPU reset does not reset the memory too.*/ + snor_reset_xip(devp); + + /* Attempting a reset of the device, it could be in an unexpected state + because a CPU reset does not reset the memory too.*/ + n25q_reset_memory(devp); + + /* Reading device ID and unique ID.*/ + wspiReceive(devp->config->busp, &n25q_cmd_read_id, + sizeof devp->device_id, devp->device_id); +#endif /* SNOR_BUS_MODE != SNOR_BUS_MODE_SPI */ + + /* Checking if the device is white listed.*/ + osalDbgAssert(n25q_find_id(n25q_manufacturer_ids, + sizeof n25q_manufacturer_ids, + devp->device_id[0]), + "invalid manufacturer id"); + osalDbgAssert(n25q_find_id(n25q_memory_type_ids, + sizeof n25q_memory_type_ids, + devp->device_id[1]), + "invalid memory type id"); + +#if (SNOR_BUS_MODE != SNOR_BUS_MODE_SPI) && (N25Q_SWITCH_WIDTH == TRUE) + /* Setting up final bus width.*/ + wspiCommand(devp->config->busp, &n25q_cmd_write_enable); + wspiSend(devp->config->busp, &n25q_cmd_write_evconf, 1, n25q_evconf_value); + + { + uint8_t id[3]; + + /* Reading ID again for confirmation.*/ + bus_cmd_receive(devp->config->busp, N25Q_CMD_MULTIPLE_IO_READ_ID, 3, id); + + /* Checking if the device is white listed.*/ + osalDbgAssert(memcmp(id, devp->device_id, 3) == 0, + "id confirmation failed"); + } +#endif + + /* Setting up the device size.*/ + snor_descriptor.sectors_count = (1U << (size_t)devp->device_id[2]) / + SECTOR_SIZE; + +#if (SNOR_BUS_MODE != SNOR_BUS_MODE_SPI) + { + static const uint8_t flash_conf[1] = { + (N25Q_READ_DUMMY_CYCLES << 4U) | 0x0FU + }; + + /* Setting up the dummy cycles to be used for fast read operations.*/ + bus_cmd(devp->config->busp, N25Q_CMD_WRITE_ENABLE); + bus_cmd_send(devp->config->busp, N25Q_CMD_WRITE_V_CONF_REGISTER, + 1, flash_conf); + } +#endif +} + +const flash_descriptor_t *snor_get_descriptor(void *instance) { + SNORDriver *devp = (SNORDriver *)instance; + + osalDbgCheck(instance != NULL); + osalDbgAssert((devp->state != FLASH_UNINIT) && (devp->state != FLASH_STOP), + "invalid state"); + + return &snor_descriptor; +} + +flash_error_t snor_device_read(SNORDriver *devp, flash_offset_t offset, + size_t n, uint8_t *rp) { + +#if SNOR_BUS_MODE != SNOR_BUS_MODE_SPI + /* Fast read command in WSPI mode.*/ + bus_cmd_addr_dummy_receive(devp->config->busp, N25Q_CMD_FAST_READ, + offset, N25Q_READ_DUMMY_CYCLES, n, rp); +#else + /* Normal read command in SPI mode.*/ + bus_cmd_addr_receive(devp->config->busp, N25Q_CMD_READ, + offset, n, rp); +#endif + + return FLASH_NO_ERROR; +} + +flash_error_t snor_device_program(SNORDriver *devp, flash_offset_t offset, + size_t n, const uint8_t *pp) { + + /* Data is programmed page by page.*/ + while (n > 0U) { + flash_error_t err; + + /* Data size that can be written in a single program page operation.*/ + size_t chunk = (size_t)(((offset | PAGE_MASK) + 1U) - offset); + if (chunk > n) { + chunk = n; + } + + /* Enabling write operation.*/ + bus_cmd(devp->config->busp, N25Q_CMD_WRITE_ENABLE); + + /* Page program command.*/ + bus_cmd_addr_send(devp->config->busp, N25Q_CMD_PAGE_PROGRAM, offset, + chunk, pp); + + /* Wait for status and check errors.*/ + err = n25q_poll_status(devp); + if (err != FLASH_NO_ERROR) { + + return err; + } + + /* Next page.*/ + offset += chunk; + pp += chunk; + n -= chunk; + } + + return FLASH_NO_ERROR; +} + +flash_error_t snor_device_start_erase_all(SNORDriver *devp) { + + /* Enabling write operation.*/ + bus_cmd(devp->config->busp, N25Q_CMD_WRITE_ENABLE); + + /* Bulk erase command.*/ + bus_cmd(devp->config->busp, N25Q_CMD_BULK_ERASE); + + return FLASH_NO_ERROR; +} + +flash_error_t snor_device_start_erase_sector(SNORDriver *devp, + flash_sector_t sector) { + flash_offset_t offset = (flash_offset_t)(sector * SECTOR_SIZE); + + /* Enabling write operation.*/ + bus_cmd(devp->config->busp, N25Q_CMD_WRITE_ENABLE); + + /* Sector erase command.*/ + bus_cmd_addr(devp->config->busp, N25Q_CMD_SECTOR_ERASE, offset); + + return FLASH_NO_ERROR; +} + +flash_error_t snor_device_verify_erase(SNORDriver *devp, + flash_sector_t sector) { + uint8_t cmpbuf[N25Q_COMPARE_BUFFER_SIZE]; + flash_offset_t offset; + size_t n; + + /* Read command.*/ + offset = (flash_offset_t)(sector * SECTOR_SIZE); + n = SECTOR_SIZE; + while (n > 0U) { + uint8_t *p; + +#if SNOR_BUS_MODE != SNOR_BUS_MODE_SPI + bus_cmd_addr_dummy_receive(devp->config->busp, N25Q_CMD_FAST_READ, + offset, N25Q_READ_DUMMY_CYCLES, + sizeof cmpbuf, cmpbuf); +#else + /* Normal read command in SPI mode.*/ + bus_cmd_addr_receive(devp->config->busp, N25Q_CMD_READ, + offset, sizeof cmpbuf, cmpbuf); +#endif + + /* Checking for erased state of current buffer.*/ + for (p = cmpbuf; p < &cmpbuf[N25Q_COMPARE_BUFFER_SIZE]; p++) { + if (*p != 0xFFU) { + /* Ready state again.*/ + devp->state = FLASH_READY; + + return FLASH_ERROR_VERIFY; + } + } + + offset += sizeof cmpbuf; + n -= sizeof cmpbuf; + } + + return FLASH_NO_ERROR; +} + +flash_error_t snor_device_query_erase(SNORDriver *devp, uint32_t *msec) { + uint8_t sts; + + /* Read status command.*/ + bus_cmd_receive(devp->config->busp, N25Q_CMD_READ_FLAG_STATUS_REGISTER, + 1, &sts); + + /* If the P/E bit is zero (busy) or the flash in a suspended state then + report that the operation is still in progress.*/ + if (((sts & N25Q_FLAGS_PROGRAM_ERASE) == 0U) || + ((sts & N25Q_FLAGS_ERASE_SUSPEND) != 0U)) { + + /* Recommended time before polling again, this is a simplified + implementation.*/ + if (msec != NULL) { + *msec = 1U; + } + + return FLASH_BUSY_ERASING; + } + + /* Checking for errors.*/ + if ((sts & N25Q_FLAGS_ALL_ERRORS) != 0U) { + + /* Clearing status register.*/ + bus_cmd(devp->config->busp, N25Q_CMD_CLEAR_FLAG_STATUS_REGISTER); + + /* Erase operation failed.*/ + return FLASH_ERROR_ERASE; + } + + return FLASH_NO_ERROR; +} + +flash_error_t snor_device_read_sfdp(SNORDriver *devp, flash_offset_t offset, + size_t n, uint8_t *rp) { + + (void)devp; + (void)rp; + (void)offset; + (void)n; + + return FLASH_NO_ERROR; +} + +#if (SNOR_BUS_MODE != SNOR_BUS_MODE_SPI) || defined(__DOXYGEN__) +void snor_activate_xip(SNORDriver *devp) { + static const uint8_t flash_status_xip[1] = { + (N25Q_READ_DUMMY_CYCLES << 4U) | 0x07U + }; + + /* Activating XIP mode in the device.*/ + bus_cmd(devp->config->busp, N25Q_CMD_WRITE_ENABLE); + bus_cmd_send(devp->config->busp, N25Q_CMD_WRITE_V_CONF_REGISTER, + 1, flash_status_xip); +} + +void snor_reset_xip(SNORDriver *devp) { + static const uint8_t flash_conf[1] = { + (N25Q_READ_DUMMY_CYCLES << 4U) | 0x0FU + }; + wspi_command_t cmd; + uint8_t buf[1]; + + /* Resetting XIP mode by reading one byte without XIP confirmation bit.*/ + cmd.alt = 0xFF; + cmd.addr = 0; + cmd.dummy = N25Q_READ_DUMMY_CYCLES - 2; + cmd.cfg = WSPI_CFG_CMD_MODE_NONE | + WSPI_CFG_ADDR_SIZE_24 | +#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L + WSPI_CFG_ADDR_MODE_ONE_LINE | + WSPI_CFG_DATA_MODE_ONE_LINE | +#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L + WSPI_CFG_ADDR_MODE_TWO_LINES | + WSPI_CFG_DATA_MODE_TWO_LINES | +#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI4L + WSPI_CFG_ADDR_MODE_FOUR_LINES | + WSPI_CFG_DATA_MODE_FOUR_LINES | +#else + WSPI_CFG_ADDR_MODE_EIGHT_LINES | + WSPI_CFG_DATA_MODE_EIGHT_LINES | +#endif + WSPI_CFG_ALT_MODE_FOUR_LINES | /* Always 4 lines, note.*/ + WSPI_CFG_ALT_SIZE_8; + wspiReceive(devp->config->busp, &cmd, 1, buf); + + /* Enabling write operation.*/ + bus_cmd(devp->config->busp, N25Q_CMD_WRITE_ENABLE); + + /* Rewriting volatile configuration register.*/ + bus_cmd_send(devp->config->busp, N25Q_CMD_WRITE_V_CONF_REGISTER, + 1, flash_conf); +} +#endif /* SNOR_BUS_MODE != SNOR_BUS_MODE_SPI */ + +/** @} */ diff --git a/os/hal/lib/complex/serial_nor/devices/micron_n25q/hal_flash_device.h b/os/hal/lib/complex/serial_nor/devices/micron_n25q/hal_flash_device.h new file mode 100644 index 000000000..22b024b95 --- /dev/null +++ b/os/hal/lib/complex/serial_nor/devices/micron_n25q/hal_flash_device.h @@ -0,0 +1,207 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 flash_device.h + * @brief Micron N25Q serial flash driver header. + * + * @addtogroup MICRON_N25Q + * @ingroup MICRON_N25Q + * @{ + */ + +#ifndef HAL_FLASH_DEVICE_H +#define HAL_FLASH_DEVICE_H + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Device identification + * @{ + */ +#define N25Q_SUPPORTED_MANUFACTURE_IDS {0x20} +#define N25Q_SUPPORTED_MEMORY_TYPE_IDS {0xBA, 0xBB} +/** @} */ + +/** + * @name Command codes + * @{ + */ +#define N25Q_CMD_RESET_ENABLE 0x66 +#define N25Q_CMD_RESET_MEMORY 0x99 +#define N25Q_CMD_READ_ID 0x9F +#define N25Q_CMD_MULTIPLE_IO_READ_ID 0xAF +#define N25Q_CMD_READ_DISCOVERY_PARAMETER 0x5A +#define N25Q_CMD_READ 0x03 +#define N25Q_CMD_FAST_READ 0x0B +#define N25Q_CMD_WRITE_ENABLE 0x06 +#define N25Q_CMD_WRITE_DISABLE 0x04 +#define N25Q_CMD_READ_STATUS_REGISTER 0x05 +#define N25Q_CMD_WRITE_STATUS_REGISTER 0x01 +#define N25Q_CMD_READ_LOCK_REGISTER 0xE8 +#define N25Q_CMD_WRITE_LOCK_REGISTER 0xE5 +#define N25Q_CMD_READ_FLAG_STATUS_REGISTER 0x70 +#define N25Q_CMD_CLEAR_FLAG_STATUS_REGISTER 0x50 +#define N25Q_CMD_READ_NV_CONFIGURATION_REGISTER 0xB5 +#define N25Q_CMD_WRITE_NV_CONFIGURATION_REGISTER 0xB1 +#define N25Q_CMD_READ_V_CONF_REGISTER 0x85 +#define N25Q_CMD_WRITE_V_CONF_REGISTER 0x81 +#define N25Q_CMD_READ_ENHANCED_V_CONF_REGISTER 0x65 +#define N25Q_CMD_WRITE_ENHANCED_V_CONF_REGISTER 0x61 +#define N25Q_CMD_PAGE_PROGRAM 0x02 +#define N25Q_CMD_SUBSECTOR_ERASE 0x20 +#define N25Q_CMD_SECTOR_ERASE 0xD8 +#define N25Q_CMD_BULK_ERASE 0xC7 +#define N25Q_CMD_PROGRAM_ERASE_RESUME 0x7A +#define N25Q_CMD_PROGRAM_ERASE_SUSPEND 0x75 +#define N25Q_CMD_READ_OTP_ARRAY 0x4B +#define N25Q_CMD_PROGRAM_OTP_ARRAY 0x42 +/** @} */ + +/** + * @name Flags status register bits + * @{ + */ +#define N25Q_FLAGS_PROGRAM_ERASE 0x80U +#define N25Q_FLAGS_ERASE_SUSPEND 0x40U +#define N25Q_FLAGS_ERASE_ERROR 0x20U +#define N25Q_FLAGS_PROGRAM_ERROR 0x10U +#define N25Q_FLAGS_VPP_ERROR 0x08U +#define N25Q_FLAGS_PROGRAM_SUSPEND 0x04U +#define N25Q_FLAGS_PROTECTION_ERROR 0x02U +#define N25Q_FLAGS_RESERVED 0x01U +#define N25Q_FLAGS_ALL_ERRORS (N25Q_FLAGS_ERASE_ERROR | \ + N25Q_FLAGS_PROGRAM_ERROR | \ + N25Q_FLAGS_VPP_ERROR | \ + N25Q_FLAGS_PROTECTION_ERROR) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @brief Switch WSPI bus width on initialization. + * @details A bus width initialization is performed by writing the + * Enhanced Volatile Configuration Register. If the flash + * device is configured using the Non Volatile Configuration + * Register then this option is not required. + * @note This option is only valid in QSPI bus modes. + */ +#if !defined(N25Q_SWITCH_WIDTH) || defined(__DOXYGEN__) +#define N25Q_SWITCH_WIDTH TRUE +#endif + +/** + * @brief Delays insertions. + * @details If enabled this options inserts delays into the flash waiting + * routines releasing some extra CPU time for threads with lower + * priority, this may slow down the driver a bit however. + */ +#if !defined(N25Q_NICE_WAITING) || defined(__DOXYGEN__) +#define N25Q_NICE_WAITING TRUE +#endif + +/** + * @brief Uses 4kB sub-sectors rather than 64kB sectors. + */ +#if !defined(N25Q_USE_SUB_SECTORS) || defined(__DOXYGEN__) +#define N25Q_USE_SUB_SECTORS FALSE +#endif + +/** + * @brief Size of the compare buffer. + * @details This buffer is allocated in the stack frame of the function + * @p flashVerifyErase() and its size must be a power of two. + * Larger buffers lead to better verify performance but increase + * stack usage for that function. + */ +#if !defined(N25Q_COMPARE_BUFFER_SIZE) || defined(__DOXYGEN__) +#define N25Q_COMPARE_BUFFER_SIZE 32 +#endif + +/** + * @brief Number of dummy cycles for fast read (1..15). + * @details This is the number of dummy cycles to be used for fast read + * operations. + */ +#if !defined(N25Q_READ_DUMMY_CYCLES) || defined(__DOXYGEN__) +#define N25Q_READ_DUMMY_CYCLES 8 +#endif + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if (N25Q_COMPARE_BUFFER_SIZE & (N25Q_COMPARE_BUFFER_SIZE - 1)) != 0 +#error "invalid N25Q_COMPARE_BUFFER_SIZE value" +#endif + +#if (N25Q_READ_DUMMY_CYCLES < 1) || (N25Q_READ_DUMMY_CYCLES > 15) +#error "invalid N25Q_READ_DUMMY_CYCLES value (1..15)" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) +extern flash_descriptor_t snor_descriptor; +#endif + +#if (SNOR_BUS_MODE != SNOR_BUS_MODE_SPI) && (WSPI_SUPPORTS_MEMMAP == TRUE) +extern const wspi_command_t snor_memmap_read; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void snor_device_init(SNORDriver *devp); + const flash_descriptor_t *snor_get_descriptor(void *instance); + flash_error_t snor_device_read(SNORDriver *devp, flash_offset_t offset, + size_t n, uint8_t *rp); + flash_error_t snor_device_program(SNORDriver *devp, flash_offset_t offset, + size_t n, const uint8_t *pp); + flash_error_t snor_device_start_erase_all(SNORDriver *devp); + flash_error_t snor_device_start_erase_sector(SNORDriver *devp, + flash_sector_t sector); + flash_error_t snor_device_verify_erase(SNORDriver *devp, + flash_sector_t sector); + flash_error_t snor_device_query_erase(SNORDriver *devp, uint32_t *msec); + flash_error_t snor_device_read_sfdp(SNORDriver *devp, flash_offset_t offset, + size_t n, uint8_t *rp); +#if SNOR_BUS_MODE != SNOR_BUS_MODE_SPI + void snor_activate_xip(SNORDriver *devp); + void snor_reset_xip(SNORDriver *devp); +#endif +#ifdef __cplusplus +} +#endif + +#endif /* HAL_FLASH_DEVICE_H */ + +/** @} */ + diff --git a/os/hal/lib/complex/serial_nor/devices/micron_n25q/hal_flash_device.mk b/os/hal/lib/complex/serial_nor/devices/micron_n25q/hal_flash_device.mk new file mode 100644 index 000000000..c333513dd --- /dev/null +++ b/os/hal/lib/complex/serial_nor/devices/micron_n25q/hal_flash_device.mk @@ -0,0 +1,13 @@ +# List of all the Micron N25Q device files. +N25QSRC := $(CHIBIOS)/os/hal/lib/peripherals/flash/hal_flash.c \ + $(CHIBIOS)/os/hal/lib/complex/serial_nor/hal_serial_nor.c \ + $(CHIBIOS)/os/hal/lib/complex/serial_nor/devices/micron_n25q/hal_flash_device.c + +# Required include directories +N25QINC := $(CHIBIOS)/os/hal/lib/peripherals/flash \ + $(CHIBIOS)/os/hal/lib/complex/serial_nor \ + $(CHIBIOS)/os/hal/lib/complex/serial_nor/devices/micron_n25q + +# Shared variables +ALLCSRC += $(N25QSRC) +ALLINC += $(N25QINC) diff --git a/os/hal/lib/complex/serial_nor/hal_serial_nor.c b/os/hal/lib/complex/serial_nor/hal_serial_nor.c new file mode 100644 index 000000000..b21d09694 --- /dev/null +++ b/os/hal/lib/complex/serial_nor/hal_serial_nor.c @@ -0,0 +1,867 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 m25q.c + * @brief M25Q serial flash driver code. + * + * @addtogroup M25Q + * @ingroup M25Q + * @{ + */ + +#include "hal.h" +#include "hal_serial_nor.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +static flash_error_t snor_read(void *instance, flash_offset_t offset, + size_t n, uint8_t *rp); +static flash_error_t snor_program(void *instance, flash_offset_t offset, + size_t n, const uint8_t *pp); +static flash_error_t snor_start_erase_all(void *instance); +static flash_error_t snor_start_erase_sector(void *instance, + flash_sector_t sector); +static flash_error_t snor_verify_erase(void *instance, + flash_sector_t sector); +static flash_error_t snor_query_erase(void *instance, uint32_t *msec); +static flash_error_t snor_read_sfdp(void *instance, flash_offset_t offset, + size_t n, uint8_t *rp); + +/** + * @brief Virtual methods table. + */ +static const struct SNORDriverVMT snor_vmt = { + (size_t)0, + snor_get_descriptor, snor_read, snor_program, + snor_start_erase_all, snor_start_erase_sector, + snor_query_erase, snor_verify_erase, + snor_read_sfdp +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#if ((SNOR_BUS_MODE != SNOR_BUS_MODE_SPI) && \ + (SNOR_SHARED_BUS == TRUE)) || defined(__DOXYGEN__) +/** + * @brief Bus acquisition and lock. + * + * @param[in] busp pointer to the bus driver + * @param[in] config bus configuration + * + * @notapi + */ +static void bus_acquire(BUSDriver *busp, const BUSConfig *config) { + + (void)config; + + wspiAcquireBus(busp); + if (busp->config != config) { + wspiStart(busp, config); + } +} + +/** + * @brief Bus release. + * + * @param[in] busp pointer to the bus driver + * + * @notapi + */ +static void bus_release(BUSDriver *busp) { + + wspiReleaseBus(busp); +} +#elif (SNOR_BUS_MODE == SNOR_BUS_MODE_SPI) && \ + (SNOR_SHARED_BUS == TRUE) +void bus_acquire(BUSDriver *busp, const BUSConfig *config) { + + spiAcquireBus(busp); + if (busp->config != config) { + spiStart(busp, config); + } +} + +void bus_release(BUSDriver *busp) { + + spiReleaseBus(busp); +} +#else +#define bus_acquire(busp) +#define bus_release(busp) +#endif + +static flash_error_t snor_read(void *instance, flash_offset_t offset, + size_t n, uint8_t *rp) { + SNORDriver *devp = (SNORDriver *)instance; + flash_error_t err; + + osalDbgCheck((instance != NULL) && (rp != NULL) && (n > 0U)); + osalDbgCheck((size_t)offset + n <= (size_t)snor_descriptor.sectors_count * + (size_t)snor_descriptor.sectors_size); + osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE), + "invalid state"); + + if (devp->state == FLASH_ERASE) { + return FLASH_BUSY_ERASING; + } + + /* Bus acquired.*/ + bus_acquire(devp->config->busp, devp->config->buscfg); + + /* FLASH_READY state while the operation is performed.*/ + devp->state = FLASH_READ; + + /* Actual read implementation.*/ + err = snor_device_read(devp, offset, n, rp); + + /* Ready state again.*/ + devp->state = FLASH_READY; + + /* Bus released.*/ + bus_release(devp->config->busp); + + return err; +} + +static flash_error_t snor_program(void *instance, flash_offset_t offset, + size_t n, const uint8_t *pp) { + SNORDriver *devp = (SNORDriver *)instance; + flash_error_t err; + + osalDbgCheck((instance != NULL) && (pp != NULL) && (n > 0U)); + osalDbgCheck((size_t)offset + n <= (size_t)snor_descriptor.sectors_count * + (size_t)snor_descriptor.sectors_size); + osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE), + "invalid state"); + + if (devp->state == FLASH_ERASE) { + return FLASH_BUSY_ERASING; + } + + /* Bus acquired.*/ + bus_acquire(devp->config->busp, devp->config->buscfg); + + /* FLASH_PGM state while the operation is performed.*/ + devp->state = FLASH_PGM; + + /* Actual program implementation.*/ + err = snor_device_program(devp, offset, n, pp); + + /* Ready state again.*/ + devp->state = FLASH_READY; + + /* Bus released.*/ + bus_release(devp->config->busp); + + return err; +} + +static flash_error_t snor_start_erase_all(void *instance) { + SNORDriver *devp = (SNORDriver *)instance; + flash_error_t err; + + osalDbgCheck(instance != NULL); + osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE), + "invalid state"); + + if (devp->state == FLASH_ERASE) { + return FLASH_BUSY_ERASING; + } + + /* Bus acquired.*/ + bus_acquire(devp->config->busp, devp->config->buscfg); + + /* FLASH_ERASE state while the operation is performed.*/ + devp->state = FLASH_ERASE; + + /* Actual erase implementation.*/ + err = snor_device_start_erase_all(devp); + + /* Ready state again.*/ + devp->state = FLASH_READY; + + /* Bus released.*/ + bus_release(devp->config->busp); + + return err; +} + +static flash_error_t snor_start_erase_sector(void *instance, + flash_sector_t sector) { + SNORDriver *devp = (SNORDriver *)instance; + flash_error_t err; + + osalDbgCheck(instance != NULL); + osalDbgCheck(sector < snor_descriptor.sectors_count); + osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE), + "invalid state"); + + if (devp->state == FLASH_ERASE) { + return FLASH_BUSY_ERASING; + } + + /* Bus acquired.*/ + bus_acquire(devp->config->busp, devp->config->buscfg); + + /* FLASH_ERASE state while the operation is performed.*/ + devp->state = FLASH_ERASE; + + /* Actual erase implementation.*/ + err = snor_device_start_erase_sector(devp, sector); + + /* Bus released.*/ + bus_release(devp->config->busp); + + return err; +} + +static flash_error_t snor_verify_erase(void *instance, + flash_sector_t sector) { + SNORDriver *devp = (SNORDriver *)instance; + flash_error_t err; + + osalDbgCheck(instance != NULL); + osalDbgCheck(sector < snor_descriptor.sectors_count); + osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE), + "invalid state"); + + if (devp->state == FLASH_ERASE) { + return FLASH_BUSY_ERASING; + } + + /* Bus acquired.*/ + bus_acquire(devp->config->busp, devp->config->buscfg); + + /* FLASH_READY state while the operation is performed.*/ + devp->state = FLASH_READ; + + /* Actual verify erase implementation.*/ + err = snor_device_verify_erase(devp, sector); + + /* Ready state again.*/ + devp->state = FLASH_READY; + + /* Bus released.*/ + bus_release(devp->config->busp); + + return err; +} + +static flash_error_t snor_query_erase(void *instance, uint32_t *msec) { + SNORDriver *devp = (SNORDriver *)instance; + flash_error_t err; + + osalDbgCheck(instance != NULL); + osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE), + "invalid state"); + + /* If there is an erase in progress then the device must be checked.*/ + if (devp->state == FLASH_ERASE) { + + /* Bus acquired.*/ + bus_acquire(devp->config->busp, devp->config->buscfg); + + /* Actual query erase implementation.*/ + err = snor_device_query_erase(devp, msec); + + /* The device is ready to accept commands.*/ + if (err == FLASH_NO_ERROR) { + devp->state = FLASH_READY; + } + + /* Bus released.*/ + bus_release(devp->config->busp); + } + else { + err = FLASH_NO_ERROR; + } + + return err; +} + +static flash_error_t snor_read_sfdp(void *instance, flash_offset_t offset, + size_t n, uint8_t *rp) { + SNORDriver *devp = (SNORDriver *)instance; + flash_error_t err; + + osalDbgCheck((instance != NULL) && (rp != NULL) && (n > 0U)); + osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE), + "invalid state"); + + if (devp->state == FLASH_ERASE) { + return FLASH_BUSY_ERASING; + } + + /* Bus acquired.*/ + bus_acquire(devp->config->busp, devp->config->buscfg); + + /* Actual read SFDP implementation.*/ + err = snor_device_read_sfdp(devp, offset, n, rp); + + /* The device is ready to accept commands.*/ + if (err == FLASH_NO_ERROR) { + devp->state = FLASH_READY; + } + + /* Bus released.*/ + bus_release(devp->config->busp); + + return err; +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Stops the underlying bus driver. + * + * @param[in] busp pointer to the bus driver + * + * @notapi + */ +void bus_stop(BUSDriver *busp) { + +#if SNOR_BUS_MODE == SNOR_BUS_MODE_SPI + spiStop(busp); +#else + wspiStop(busp); +#endif +} + +/** + * @brief Sends a naked command. + * + * @param[in] busp pointer to the bus driver + * @param[in] cmd instruction code + * + * @notapi + */ +void bus_cmd(BUSDriver *busp, uint32_t cmd) { +#if SNOR_BUS_MODE != SNOR_BUS_MODE_SPI + wspi_command_t mode; + + mode.cmd = cmd; + mode.dummy = 0U; + mode.cfg = 0U | +#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L + WSPI_CFG_CMD_MODE_ONE_LINE; +#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L + WSPI_CFG_CMD_MODE_TWO_LINES; +#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI4L + WSPI_CFG_CMD_MODE_FOUR_LINES; +#else + WSPI_CFG_CMD_MODE_EIGHT_LINES; +#endif + mode.addr = 0U; + mode.alt = 0U; + wspiCommand(busp, &mode); +#else + uint8_t buf[1]; + + spiSelect(busp); + buf[0] = cmd; + spiSend(busp, 1, buf); + spiUnselect(busp); +#endif +} + +/** + * @brief Sends a command followed by a data transmit phase. + * + * @param[in] busp pointer to the bus driver + * @param[in] cmd instruction code + * @param[in] n number of bytes to receive + * @param[in] p data buffer + * + * @notapi + */ +void bus_cmd_send(BUSDriver *busp, uint32_t cmd, size_t n, const uint8_t *p) { +#if SNOR_BUS_MODE != SNOR_BUS_MODE_SPI + wspi_command_t mode; + + mode.cmd = cmd; + mode.dummy = 0U; + mode.cfg = 0U | +#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L + WSPI_CFG_CMD_MODE_ONE_LINE | + WSPI_CFG_DATA_MODE_ONE_LINE; +#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L + WSPI_CFG_CMD_MODE_TWO_LINES | + WSPI_CFG_DATA_MODE_TWO_LINES; +#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI4L + WSPI_CFG_CMD_MODE_FOUR_LINES | + WSPI_CFG_DATA_MODE_FOUR_LINES; +#else + WSPI_CFG_CMD_MODE_EIGHT_LINES | + WSPI_CFG_DATA_MODE_EIGHT_LINES; +#endif + mode.addr = 0U; + mode.alt = 0U; + wspiSend(busp, &mode, n, p); +#else + uint8_t buf[1]; + + spiSelect(busp); + buf[0] = cmd; + spiSend(busp, 1, buf); + spiSend(busp, n, p); + spiUnselect(busp); +#endif +} + +/** + * @brief Sends a command followed by a data receive phase. + * + * @param[in] busp pointer to the bus driver + * @param[in] cmd instruction code + * @param[in] n number of bytes to receive + * @param[out] p data buffer + * + * @notapi + */ +void bus_cmd_receive(BUSDriver *busp, + uint32_t cmd, + size_t n, + uint8_t *p) { +#if SNOR_BUS_MODE != SNOR_BUS_MODE_SPI + wspi_command_t mode; + + mode.cmd = cmd; + mode.dummy = 0U; + mode.cfg = 0U | +#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L + WSPI_CFG_CMD_MODE_ONE_LINE | + WSPI_CFG_DATA_MODE_ONE_LINE; +#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L + WSPI_CFG_CMD_MODE_TWO_LINES | + WSPI_CFG_DATA_MODE_TWO_LINES; +#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI4L + WSPI_CFG_CMD_MODE_FOUR_LINES | + WSPI_CFG_DATA_MODE_FOUR_LINES; +#else + WSPI_CFG_CMD_MODE_EIGHT_LINES | + WSPI_CFG_DATA_MODE_EIGHT_LINES; +#endif + mode.addr = 0U; + mode.alt = 0U; + wspiReceive(busp, &mode, n, p); +#else + uint8_t buf[1]; + + spiSelect(busp); + buf[0] = cmd; + spiSend(busp, 1, buf); + spiReceive(busp, n, p); + spiUnselect(busp); +#endif +} + +/** + * @brief Sends a command followed by a flash address. + * + * @param[in] busp pointer to the bus driver + * @param[in] cmd instruction code + * @param[in] offset flash offset + * + * @notapi + */ +void bus_cmd_addr(BUSDriver *busp, uint32_t cmd, flash_offset_t offset) { +#if SNOR_BUS_MODE != SNOR_BUS_MODE_SPI + wspi_command_t mode; + + mode.cmd = cmd; + mode.dummy = 0U; + mode.cfg = 0U | +#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L + WSPI_CFG_CMD_MODE_ONE_LINE | + WSPI_CFG_ADDR_MODE_ONE_LINE | + WSPI_CFG_ADDR_SIZE_24; +#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L + WSPI_CFG_CMD_MODE_TWO_LINES | + WSPI_CFG_ADDR_MODE_TWO_LINES | + WSPI_CFG_ADDR_SIZE_24; +#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI4L + WSPI_CFG_CMD_MODE_FOUR_LINES | + WSPI_CFG_ADDR_MODE_FOUR_LINES | + WSPI_CFG_ADDR_SIZE_24; +#else + WSPI_CFG_CMD_MODE_EIGHT_LINES | + WSPI_CFG_ADDR_MODE_EIGHT_LINES | + WSPI_CFG_ADDR_SIZE_24; +#endif + + /* Handling 32 bits addressing. + TODO: Address size should come from upper levels.*/ + if ((cmd & SNOR_BUS_CMD_EXTENDED_ADDRESSING) == 0) { + mode.cfg |= WSPI_CFG_ADDR_SIZE_24; + } + else { + mode.cfg |= WSPI_CFG_ADDR_SIZE_32; + } + + mode.addr = offset; + mode.alt = 0U; + wspiCommand(busp, &mode); +#else + uint8_t buf[4]; + + spiSelect(busp); + buf[0] = cmd; + buf[1] = (uint8_t)(offset >> 16); + buf[2] = (uint8_t)(offset >> 8); + buf[3] = (uint8_t)(offset >> 0); + spiSend(busp, 4, buf); + spiUnselect(busp); +#endif +} + +/** + * @brief Sends a command followed by a flash address and a data transmit + * phase. + * + * @param[in] busp pointer to the bus driver + * @param[in] cmd instruction code + * @param[in] offset flash offset + * @param[in] n number of bytes to receive + * @param[in] p data buffer + * + * @notapi + */ +void bus_cmd_addr_send(BUSDriver *busp, + uint32_t cmd, + flash_offset_t offset, + size_t n, + const uint8_t *p) { +#if SNOR_BUS_MODE != SNOR_BUS_MODE_SPI + wspi_command_t mode; + + mode.cmd = cmd; + mode.dummy = 0U; + mode.cfg = 0U | +#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L + WSPI_CFG_CMD_MODE_ONE_LINE | + WSPI_CFG_ADDR_MODE_ONE_LINE | + WSPI_CFG_DATA_MODE_ONE_LINE; +#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L + WSPI_CFG_CMD_MODE_TWO_LINES | + WSPI_CFG_ADDR_MODE_TWO_LINES | + WSPI_CFG_DATA_MODE_TWO_LINES; +#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI4L + WSPI_CFG_CMD_MODE_FOUR_LINES | + WSPI_CFG_ADDR_MODE_FOUR_LINES | + WSPI_CFG_DATA_MODE_FOUR_LINES; +#else + WSPI_CFG_CMD_MODE_EIGHT_LINES | + WSPI_CFG_ADDR_MODE_EIGHT_LINES | + WSPI_CFG_DATA_MODE_EIGHT_LINES; +#endif + + /* Handling 32 bits addressing. + TODO: Address size should come from upper levels.*/ + if ((cmd & SNOR_BUS_CMD_EXTENDED_ADDRESSING) == 0) { + mode.cfg |= WSPI_CFG_ADDR_SIZE_24; + } + else { + mode.cfg |= WSPI_CFG_ADDR_SIZE_32; + } + + mode.addr = offset; + mode.alt = 0U; + wspiSend(busp, &mode, n, p); +#else + uint8_t buf[4]; + + spiSelect(busp); + buf[0] = cmd; + buf[1] = (uint8_t)(offset >> 16); + buf[2] = (uint8_t)(offset >> 8); + buf[3] = (uint8_t)(offset >> 0); + spiSend(busp, 4, buf); + spiSend(busp, n, p); + spiUnselect(busp); +#endif +} + +/** + * @brief Sends a command followed by a flash address and a data receive + * phase. + * + * @param[in] busp pointer to the bus driver + * @param[in] cmd instruction code + * @param[in] offset flash offset + * @param[in] n number of bytes to receive + * @param[out] p data buffer + * + * @notapi + */ +void bus_cmd_addr_receive(BUSDriver *busp, + uint32_t cmd, + flash_offset_t offset, + size_t n, + uint8_t *p) { +#if SNOR_BUS_MODE != SNOR_BUS_MODE_SPI + wspi_command_t mode; + + mode.cmd = cmd; + mode.dummy = 0U; + mode.cfg = 0U | +#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L + WSPI_CFG_CMD_MODE_ONE_LINE | + WSPI_CFG_ADDR_MODE_ONE_LINE | + WSPI_CFG_DATA_MODE_ONE_LINE; +#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L + WSPI_CFG_CMD_MODE_TWO_LINES | + WSPI_CFG_ADDR_MODE_TWO_LINES | + WSPI_CFG_DATA_MODE_TWO_LINES; +#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI4L + WSPI_CFG_CMD_MODE_TWO_LINES | + WSPI_CFG_ADDR_MODE_TWO_LINES | + WSPI_CFG_DATA_MODE_TWO_LINES; +#else + WSPI_CFG_CMD_MODE_EIGHT_LINES | + WSPI_CFG_ADDR_MODE_EIGHT_LINES | + WSPI_CFG_DATA_MODE_EIGHT_LINES; +#endif + + /* Handling 32 bits addressing. + TODO: Address size should come from upper levels.*/ + if ((cmd & SNOR_BUS_CMD_EXTENDED_ADDRESSING) == 0) { + mode .cfg |= WSPI_CFG_ADDR_SIZE_24; + } + else { + mode .cfg |= WSPI_CFG_ADDR_SIZE_32; + } + + mode.addr = offset; + mode.alt = 0U; + wspiReceive(busp, &mode, n, p); +#else + uint8_t buf[4]; + + spiSelect(busp); + buf[0] = cmd; + buf[1] = (uint8_t)(offset >> 16); + buf[2] = (uint8_t)(offset >> 8); + buf[3] = (uint8_t)(offset >> 0); + spiSend(busp, 4, buf); + spiReceive(busp, n, p); + spiUnselect(busp); +#endif +} + +#if (SNOR_BUS_MODE != SNOR_BUS_MODE_SPI) || defined(__DOXYGEN__) +/** + * @brief Sends a command followed by a flash address, dummy cycles and a + * data receive phase. + * + * @param[in] busp pointer to the bus driver + * @param[in] cmd instruction code + * @param[in] offset flash offset + * @param[in] dummy number of dummy cycles + * @param[in] n number of bytes to receive + * @param[out] p data buffer + * + * @notapi + */ +void bus_cmd_addr_dummy_receive(BUSDriver *busp, + uint32_t cmd, + flash_offset_t offset, + uint32_t dummy, + size_t n, + uint8_t *p) { + wspi_command_t mode; + + mode.cmd = cmd; + mode.dummy = dummy; + mode.cfg = 0U | +#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L + WSPI_CFG_CMD_MODE_ONE_LINE | + WSPI_CFG_ADDR_MODE_ONE_LINE | + WSPI_CFG_DATA_MODE_ONE_LINE; +#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L + WSPI_CFG_CMD_MODE_TWO_LINES | + WSPI_CFG_ADDR_MODE_TWO_LINES | + WSPI_CFG_DATA_MODE_TWO_LINES; +#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI4L + WSPI_CFG_CMD_MODE_FOUR_LINES | + WSPI_CFG_ADDR_MODE_FOUR_LINES | + WSPI_CFG_DATA_MODE_FOUR_LINES; +#else + WSPI_CFG_CMD_MODE_EIGHT_LINES | + WSPI_CFG_ADDR_MODE_EIGHT_LINES | + WSPI_CFG_DATA_MODE_EIGHT_LINES; +#endif + + /* Handling 32 bits addressing. + TODO: Address size should come from upper levels.*/ + if ((cmd & SNOR_BUS_CMD_EXTENDED_ADDRESSING) == 0) { + mode .cfg |= WSPI_CFG_ADDR_SIZE_24; + } + else { + mode .cfg |= WSPI_CFG_ADDR_SIZE_32; + } + + mode.addr = offset; + mode.alt = 0U; + wspiReceive(busp, &mode, n, p); +} +#endif /* SNOR_BUS_MODE != SNOR_BUS_MODE_SPI */ + +/** + * @brief Initializes an instance. + * + * @param[out] devp pointer to the @p SNORDriver object + * + * @init + */ +void snorObjectInit(SNORDriver *devp) { + + osalDbgCheck(devp != NULL); + + devp->vmt = &snor_vmt; + devp->state = FLASH_STOP; + devp->config = NULL; +} + +/** + * @brief Configures and activates SNOR driver. + * + * @param[in] devp pointer to the @p SNORDriver object + * @param[in] config pointer to the configuration + * + * @api + */ +void snorStart(SNORDriver *devp, const SNORConfig *config) { + + osalDbgCheck((devp != NULL) && (config != NULL)); + osalDbgAssert(devp->state != FLASH_UNINIT, "invalid state"); + + devp->config = config; + + if (devp->state == FLASH_STOP) { + + /* Bus acquisition.*/ + bus_acquire(devp->config->busp, devp->config->buscfg); + + /* Device identification and initialization.*/ + snor_device_init(devp); + + /* Driver in ready state.*/ + devp->state = FLASH_READY; + + /* Bus release.*/ + bus_release(devp->config->busp); + } +} + +/** + * @brief Deactivates the SNOR driver. + * + * @param[in] devp pointer to the @p SNORDriver object + * + * @api + */ +void snorStop(SNORDriver *devp) { + + osalDbgCheck(devp != NULL); + osalDbgAssert(devp->state != FLASH_UNINIT, "invalid state"); + + if (devp->state != FLASH_STOP) { + + /* Bus acquisition.*/ + bus_acquire(devp->config->busp, devp->config->buscfg); + + /* Stopping bus device.*/ + bus_stop(devp->config->busp); + + /* Driver stopped.*/ + devp->state = FLASH_STOP; + + /* Bus release.*/ + bus_release(devp->config->busp); + + /* Deleting current configuration.*/ + devp->config = NULL; + } +} + +#if (SNOR_BUS_MODE != SNOR_BUS_MODE_SPI) || defined(__DOXYGEN__) +#if (WSPI_SUPPORTS_MEMMAP == TRUE) || defined(__DOXYGEN__) +/** + * @brief Enters the memory Mapping mode. + * @details The memory mapping mode is only available when the WSPI mode + * is selected and the underlying WSPI controller supports the + * feature. + * + * @param[in] devp pointer to the @p SNORDriver object + * @param[out] addrp pointer to the memory start address of the mapped + * flash or @p NULL + * + * @api + */ +void snorMemoryMap(SNORDriver *devp, uint8_t **addrp) { + + /* Bus acquisition.*/ + bus_acquire(devp->config->busp, devp->config->buscfg); + + /* Activating XIP mode in the device.*/ + snor_activate_xip(devp); + + /* Starting WSPI memory mapped mode.*/ + wspiMapFlash(devp->config->busp, &snor_memmap_read, addrp); + + /* Bus release.*/ + bus_release(devp->config->busp); +} + +/** + * @brief Leaves the memory Mapping mode. + * + * @param[in] devp pointer to the @p SNORDriver object + * + * @api + */ +void snorMemoryUnmap(SNORDriver *devp) { + + /* Bus acquisition.*/ + bus_acquire(devp->config->busp, devp->config->buscfg); + + /* Stopping WSPI memory mapped mode.*/ + wspiUnmapFlash(devp->config->busp); + + snor_reset_xip(devp); + + /* Bus release.*/ + bus_release(devp->config->busp); +} +#endif /* WSPI_SUPPORTS_MEMMAP == TRUE */ +#endif /* SNOR_BUS_MODE != SNOR_BUS_MODE_SPI */ + +/** @} */ diff --git a/os/hal/lib/complex/serial_nor/hal_serial_nor.h b/os/hal/lib/complex/serial_nor/hal_serial_nor.h new file mode 100644 index 000000000..6be8e8e0c --- /dev/null +++ b/os/hal/lib/complex/serial_nor/hal_serial_nor.h @@ -0,0 +1,200 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 serial_nor.h + * @brief Serial NOR driver header. + * + * @addtogroup SERIAL_NOR + * @ingroup SERIAL_NOR + * @{ + */ + +#ifndef HAL_SERIAL_NOR_H +#define HAL_SERIAL_NOR_H + +#include "hal_flash.h" + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Bus interface modes. + * @{ + */ +#define SNOR_BUS_MODE_SPI 0U +#define SNOR_BUS_MODE_WSPI1L 1U +#define SNOR_BUS_MODE_WSPI2L 2U +#define SNOR_BUS_MODE_WSPI4L 4U +#define SNOR_BUS_MODE_WSPI8L 8U +/** @} */ + +#define SNOR_BUS_CMD_EXTENDED_ADDRESSING 0x80000000U + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief Physical transport interface. + */ +#if !defined(SNOR_BUS_MODE) || defined(__DOXYGEN__) +#define SNOR_BUS_MODE SNOR_BUS_MODE_WSPI4L +#endif + +/** + * @brief Shared bus switch. + * @details If set to @p TRUE the device acquires bus ownership + * on each transaction. + * @note Requires @p SPI_USE_MUTUAL_EXCLUSION or + * @p WSPI_USE_MUTUAL_EXCLUSION depending on mode selected + * with @p SNOR_BUS_MODE. + */ +#if !defined(SNOR_SHARED_BUS) || defined(__DOXYGEN__) +#define SNOR_SHARED_BUS TRUE +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if (SNOR_BUS_MODE != SNOR_BUS_MODE_SPI) || defined(__DOXYGEN__) +#define BUSConfig WSPIConfig +#define BUSDriver WSPIDriver +#else +#define BUSConfig SPIConfig +#define BUSDriver SPIDriver +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of a SNOR configuration structure. + */ +typedef struct { + BUSDriver *busp; + const BUSConfig *buscfg; +} SNORConfig; + +/** + * @brief @p SNORDriver specific methods. + */ +#define _snor_flash_methods_alone \ + /* Read SFDP.*/ \ + flash_error_t (*read_sfdp)(void *instance, \ + flash_offset_t offset, \ + size_t n, \ + uint8_t *rp); + +/** + * @brief @p SNORDriver specific methods with inherited ones. + */ +#define _snor_flash_methods \ + _base_flash_methods \ + _snor_flash_methods_alone + +/** + * @extends BaseFlashVMT + * + * @brief @p SNOR virtual methods table. + */ +struct SNORDriverVMT { + _snor_flash_methods +}; + +/** + * @extends BaseFlash + * + * @brief Type of SNOR flash class. + */ +typedef struct { + /** + * @brief SNORDriver Virtual Methods Table. + */ + const struct SNORDriverVMT *vmt; + _base_flash_data + /** + * @brief Current configuration data. + */ + const SNORConfig *config; + /** + * @brief Device ID and unique ID. + */ + uint8_t device_id[20]; +} SNORDriver; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void bus_cmd(BUSDriver *busp, uint32_t cmd); + void bus_cmd_send(BUSDriver *busp, uint32_t cmd, size_t n, const uint8_t *p); + void bus_cmd_receive(BUSDriver *busp, + uint32_t cmd, + size_t n, + uint8_t *p); + void bus_cmd_addr(BUSDriver *busp, uint32_t cmd, flash_offset_t offset); + void bus_cmd_addr_send(BUSDriver *busp, + uint32_t cmd, + flash_offset_t offset, + size_t n, + const uint8_t *p); + void bus_cmd_addr_receive(BUSDriver *busp, + uint32_t cmd, + flash_offset_t offset, + size_t n, + uint8_t *p); + void bus_cmd_addr_dummy_receive(BUSDriver *busp, + uint32_t cmd, + flash_offset_t offset, + uint32_t dummy, + size_t n, + uint8_t *p); + void snorObjectInit(SNORDriver *devp); + void snorStart(SNORDriver *devp, const SNORConfig *config); + void snorStop(SNORDriver *devp); +#if (SNOR_BUS_MODE != SNOR_BUS_MODE_SPI) || defined(__DOXYGEN__) +#if (WSPI_SUPPORTS_MEMMAP == TRUE) || defined(__DOXYGEN__) + void snorMemoryMap(SNORDriver *devp, uint8_t ** addrp); + void snorMemoryUnmap(SNORDriver *devp); +#endif /* QSPI_SUPPORTS_MEMMAP == TRUE */ +#endif /* SNOR_BUS_MODE != SNOR_BUS_MODE_SPI */ +#ifdef __cplusplus +} +#endif + +/* Device-specific implementations.*/ +#include "hal_flash_device.h" + +#endif /* HAL_SERIAL_NOR_H */ + +/** @} */ + diff --git a/os/hal/lib/complex/serial_nor/serial_nor.c b/os/hal/lib/complex/serial_nor/serial_nor.c deleted file mode 100644 index 6e512fcc3..000000000 --- a/os/hal/lib/complex/serial_nor/serial_nor.c +++ /dev/null @@ -1,867 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio - - 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 m25q.c - * @brief M25Q serial flash driver code. - * - * @addtogroup M25Q - * @ingroup M25Q - * @{ - */ - -#include "hal.h" -#include "serial_nor.h" - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -static flash_error_t snor_read(void *instance, flash_offset_t offset, - size_t n, uint8_t *rp); -static flash_error_t snor_program(void *instance, flash_offset_t offset, - size_t n, const uint8_t *pp); -static flash_error_t snor_start_erase_all(void *instance); -static flash_error_t snor_start_erase_sector(void *instance, - flash_sector_t sector); -static flash_error_t snor_verify_erase(void *instance, - flash_sector_t sector); -static flash_error_t snor_query_erase(void *instance, uint32_t *msec); -static flash_error_t snor_read_sfdp(void *instance, flash_offset_t offset, - size_t n, uint8_t *rp); - -/** - * @brief Virtual methods table. - */ -static const struct SNORDriverVMT snor_vmt = { - (size_t)0, - snor_get_descriptor, snor_read, snor_program, - snor_start_erase_all, snor_start_erase_sector, - snor_query_erase, snor_verify_erase, - snor_read_sfdp -}; - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -#if ((SNOR_BUS_MODE != SNOR_BUS_MODE_SPI) && \ - (SNOR_SHARED_BUS == TRUE)) || defined(__DOXYGEN__) -/** - * @brief Bus acquisition and lock. - * - * @param[in] busp pointer to the bus driver - * @param[in] config bus configuration - * - * @notapi - */ -static void bus_acquire(BUSDriver *busp, const BUSConfig *config) { - - (void)config; - - wspiAcquireBus(busp); - if (busp->config != config) { - wspiStart(busp, config); - } -} - -/** - * @brief Bus release. - * - * @param[in] busp pointer to the bus driver - * - * @notapi - */ -static void bus_release(BUSDriver *busp) { - - wspiReleaseBus(busp); -} -#elif (SNOR_BUS_MODE == SNOR_BUS_MODE_SPI) && \ - (SNOR_SHARED_BUS == TRUE) -void bus_acquire(BUSDriver *busp, const BUSConfig *config) { - - spiAcquireBus(busp); - if (busp->config != config) { - spiStart(busp, config); - } -} - -void bus_release(BUSDriver *busp) { - - spiReleaseBus(busp); -} -#else -#define bus_acquire(busp) -#define bus_release(busp) -#endif - -static flash_error_t snor_read(void *instance, flash_offset_t offset, - size_t n, uint8_t *rp) { - SNORDriver *devp = (SNORDriver *)instance; - flash_error_t err; - - osalDbgCheck((instance != NULL) && (rp != NULL) && (n > 0U)); - osalDbgCheck((size_t)offset + n <= (size_t)snor_descriptor.sectors_count * - (size_t)snor_descriptor.sectors_size); - osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE), - "invalid state"); - - if (devp->state == FLASH_ERASE) { - return FLASH_BUSY_ERASING; - } - - /* Bus acquired.*/ - bus_acquire(devp->config->busp, devp->config->buscfg); - - /* FLASH_READY state while the operation is performed.*/ - devp->state = FLASH_READ; - - /* Actual read implementation.*/ - err = snor_device_read(devp, offset, n, rp); - - /* Ready state again.*/ - devp->state = FLASH_READY; - - /* Bus released.*/ - bus_release(devp->config->busp); - - return err; -} - -static flash_error_t snor_program(void *instance, flash_offset_t offset, - size_t n, const uint8_t *pp) { - SNORDriver *devp = (SNORDriver *)instance; - flash_error_t err; - - osalDbgCheck((instance != NULL) && (pp != NULL) && (n > 0U)); - osalDbgCheck((size_t)offset + n <= (size_t)snor_descriptor.sectors_count * - (size_t)snor_descriptor.sectors_size); - osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE), - "invalid state"); - - if (devp->state == FLASH_ERASE) { - return FLASH_BUSY_ERASING; - } - - /* Bus acquired.*/ - bus_acquire(devp->config->busp, devp->config->buscfg); - - /* FLASH_PGM state while the operation is performed.*/ - devp->state = FLASH_PGM; - - /* Actual program implementation.*/ - err = snor_device_program(devp, offset, n, pp); - - /* Ready state again.*/ - devp->state = FLASH_READY; - - /* Bus released.*/ - bus_release(devp->config->busp); - - return err; -} - -static flash_error_t snor_start_erase_all(void *instance) { - SNORDriver *devp = (SNORDriver *)instance; - flash_error_t err; - - osalDbgCheck(instance != NULL); - osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE), - "invalid state"); - - if (devp->state == FLASH_ERASE) { - return FLASH_BUSY_ERASING; - } - - /* Bus acquired.*/ - bus_acquire(devp->config->busp, devp->config->buscfg); - - /* FLASH_ERASE state while the operation is performed.*/ - devp->state = FLASH_ERASE; - - /* Actual erase implementation.*/ - err = snor_device_start_erase_all(devp); - - /* Ready state again.*/ - devp->state = FLASH_READY; - - /* Bus released.*/ - bus_release(devp->config->busp); - - return err; -} - -static flash_error_t snor_start_erase_sector(void *instance, - flash_sector_t sector) { - SNORDriver *devp = (SNORDriver *)instance; - flash_error_t err; - - osalDbgCheck(instance != NULL); - osalDbgCheck(sector < snor_descriptor.sectors_count); - osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE), - "invalid state"); - - if (devp->state == FLASH_ERASE) { - return FLASH_BUSY_ERASING; - } - - /* Bus acquired.*/ - bus_acquire(devp->config->busp, devp->config->buscfg); - - /* FLASH_ERASE state while the operation is performed.*/ - devp->state = FLASH_ERASE; - - /* Actual erase implementation.*/ - err = snor_device_start_erase_sector(devp, sector); - - /* Bus released.*/ - bus_release(devp->config->busp); - - return err; -} - -static flash_error_t snor_verify_erase(void *instance, - flash_sector_t sector) { - SNORDriver *devp = (SNORDriver *)instance; - flash_error_t err; - - osalDbgCheck(instance != NULL); - osalDbgCheck(sector < snor_descriptor.sectors_count); - osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE), - "invalid state"); - - if (devp->state == FLASH_ERASE) { - return FLASH_BUSY_ERASING; - } - - /* Bus acquired.*/ - bus_acquire(devp->config->busp, devp->config->buscfg); - - /* FLASH_READY state while the operation is performed.*/ - devp->state = FLASH_READ; - - /* Actual verify erase implementation.*/ - err = snor_device_verify_erase(devp, sector); - - /* Ready state again.*/ - devp->state = FLASH_READY; - - /* Bus released.*/ - bus_release(devp->config->busp); - - return err; -} - -static flash_error_t snor_query_erase(void *instance, uint32_t *msec) { - SNORDriver *devp = (SNORDriver *)instance; - flash_error_t err; - - osalDbgCheck(instance != NULL); - osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE), - "invalid state"); - - /* If there is an erase in progress then the device must be checked.*/ - if (devp->state == FLASH_ERASE) { - - /* Bus acquired.*/ - bus_acquire(devp->config->busp, devp->config->buscfg); - - /* Actual query erase implementation.*/ - err = snor_device_query_erase(devp, msec); - - /* The device is ready to accept commands.*/ - if (err == FLASH_NO_ERROR) { - devp->state = FLASH_READY; - } - - /* Bus released.*/ - bus_release(devp->config->busp); - } - else { - err = FLASH_NO_ERROR; - } - - return err; -} - -static flash_error_t snor_read_sfdp(void *instance, flash_offset_t offset, - size_t n, uint8_t *rp) { - SNORDriver *devp = (SNORDriver *)instance; - flash_error_t err; - - osalDbgCheck((instance != NULL) && (rp != NULL) && (n > 0U)); - osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE), - "invalid state"); - - if (devp->state == FLASH_ERASE) { - return FLASH_BUSY_ERASING; - } - - /* Bus acquired.*/ - bus_acquire(devp->config->busp, devp->config->buscfg); - - /* Actual read SFDP implementation.*/ - err = snor_device_read_sfdp(devp, offset, n, rp); - - /* The device is ready to accept commands.*/ - if (err == FLASH_NO_ERROR) { - devp->state = FLASH_READY; - } - - /* Bus released.*/ - bus_release(devp->config->busp); - - return err; -} - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief Stops the underlying bus driver. - * - * @param[in] busp pointer to the bus driver - * - * @notapi - */ -void bus_stop(BUSDriver *busp) { - -#if SNOR_BUS_MODE == SNOR_BUS_MODE_SPI - spiStop(busp); -#else - wspiStop(busp); -#endif -} - -/** - * @brief Sends a naked command. - * - * @param[in] busp pointer to the bus driver - * @param[in] cmd instruction code - * - * @notapi - */ -void bus_cmd(BUSDriver *busp, uint32_t cmd) { -#if SNOR_BUS_MODE != SNOR_BUS_MODE_SPI - wspi_command_t mode; - - mode.cmd = cmd; - mode.dummy = 0U; - mode.cfg = 0U | -#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L - WSPI_CFG_CMD_MODE_ONE_LINE; -#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L - WSPI_CFG_CMD_MODE_TWO_LINES; -#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI4L - WSPI_CFG_CMD_MODE_FOUR_LINES; -#else - WSPI_CFG_CMD_MODE_EIGHT_LINES; -#endif - mode.addr = 0U; - mode.alt = 0U; - wspiCommand(busp, &mode); -#else - uint8_t buf[1]; - - spiSelect(busp); - buf[0] = cmd; - spiSend(busp, 1, buf); - spiUnselect(busp); -#endif -} - -/** - * @brief Sends a command followed by a data transmit phase. - * - * @param[in] busp pointer to the bus driver - * @param[in] cmd instruction code - * @param[in] n number of bytes to receive - * @param[in] p data buffer - * - * @notapi - */ -void bus_cmd_send(BUSDriver *busp, uint32_t cmd, size_t n, const uint8_t *p) { -#if SNOR_BUS_MODE != SNOR_BUS_MODE_SPI - wspi_command_t mode; - - mode.cmd = cmd; - mode.dummy = 0U; - mode.cfg = 0U | -#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L - WSPI_CFG_CMD_MODE_ONE_LINE | - WSPI_CFG_DATA_MODE_ONE_LINE; -#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L - WSPI_CFG_CMD_MODE_TWO_LINES | - WSPI_CFG_DATA_MODE_TWO_LINES; -#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI4L - WSPI_CFG_CMD_MODE_FOUR_LINES | - WSPI_CFG_DATA_MODE_FOUR_LINES; -#else - WSPI_CFG_CMD_MODE_EIGHT_LINES | - WSPI_CFG_DATA_MODE_EIGHT_LINES; -#endif - mode.addr = 0U; - mode.alt = 0U; - wspiSend(busp, &mode, n, p); -#else - uint8_t buf[1]; - - spiSelect(busp); - buf[0] = cmd; - spiSend(busp, 1, buf); - spiSend(busp, n, p); - spiUnselect(busp); -#endif -} - -/** - * @brief Sends a command followed by a data receive phase. - * - * @param[in] busp pointer to the bus driver - * @param[in] cmd instruction code - * @param[in] n number of bytes to receive - * @param[out] p data buffer - * - * @notapi - */ -void bus_cmd_receive(BUSDriver *busp, - uint32_t cmd, - size_t n, - uint8_t *p) { -#if SNOR_BUS_MODE != SNOR_BUS_MODE_SPI - wspi_command_t mode; - - mode.cmd = cmd; - mode.dummy = 0U; - mode.cfg = 0U | -#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L - WSPI_CFG_CMD_MODE_ONE_LINE | - WSPI_CFG_DATA_MODE_ONE_LINE; -#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L - WSPI_CFG_CMD_MODE_TWO_LINES | - WSPI_CFG_DATA_MODE_TWO_LINES; -#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI4L - WSPI_CFG_CMD_MODE_FOUR_LINES | - WSPI_CFG_DATA_MODE_FOUR_LINES; -#else - WSPI_CFG_CMD_MODE_EIGHT_LINES | - WSPI_CFG_DATA_MODE_EIGHT_LINES; -#endif - mode.addr = 0U; - mode.alt = 0U; - wspiReceive(busp, &mode, n, p); -#else - uint8_t buf[1]; - - spiSelect(busp); - buf[0] = cmd; - spiSend(busp, 1, buf); - spiReceive(busp, n, p); - spiUnselect(busp); -#endif -} - -/** - * @brief Sends a command followed by a flash address. - * - * @param[in] busp pointer to the bus driver - * @param[in] cmd instruction code - * @param[in] offset flash offset - * - * @notapi - */ -void bus_cmd_addr(BUSDriver *busp, uint32_t cmd, flash_offset_t offset) { -#if SNOR_BUS_MODE != SNOR_BUS_MODE_SPI - wspi_command_t mode; - - mode.cmd = cmd; - mode.dummy = 0U; - mode.cfg = 0U | -#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L - WSPI_CFG_CMD_MODE_ONE_LINE | - WSPI_CFG_ADDR_MODE_ONE_LINE | - WSPI_CFG_ADDR_SIZE_24; -#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L - WSPI_CFG_CMD_MODE_TWO_LINES | - WSPI_CFG_ADDR_MODE_TWO_LINES | - WSPI_CFG_ADDR_SIZE_24; -#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI4L - WSPI_CFG_CMD_MODE_FOUR_LINES | - WSPI_CFG_ADDR_MODE_FOUR_LINES | - WSPI_CFG_ADDR_SIZE_24; -#else - WSPI_CFG_CMD_MODE_EIGHT_LINES | - WSPI_CFG_ADDR_MODE_EIGHT_LINES | - WSPI_CFG_ADDR_SIZE_24; -#endif - - /* Handling 32 bits addressing. - TODO: Address size should come from upper levels.*/ - if ((cmd & SNOR_BUS_CMD_EXTENDED_ADDRESSING) == 0) { - mode.cfg |= WSPI_CFG_ADDR_SIZE_24; - } - else { - mode.cfg |= WSPI_CFG_ADDR_SIZE_32; - } - - mode.addr = offset; - mode.alt = 0U; - wspiCommand(busp, &mode); -#else - uint8_t buf[4]; - - spiSelect(busp); - buf[0] = cmd; - buf[1] = (uint8_t)(offset >> 16); - buf[2] = (uint8_t)(offset >> 8); - buf[3] = (uint8_t)(offset >> 0); - spiSend(busp, 4, buf); - spiUnselect(busp); -#endif -} - -/** - * @brief Sends a command followed by a flash address and a data transmit - * phase. - * - * @param[in] busp pointer to the bus driver - * @param[in] cmd instruction code - * @param[in] offset flash offset - * @param[in] n number of bytes to receive - * @param[in] p data buffer - * - * @notapi - */ -void bus_cmd_addr_send(BUSDriver *busp, - uint32_t cmd, - flash_offset_t offset, - size_t n, - const uint8_t *p) { -#if SNOR_BUS_MODE != SNOR_BUS_MODE_SPI - wspi_command_t mode; - - mode.cmd = cmd; - mode.dummy = 0U; - mode.cfg = 0U | -#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L - WSPI_CFG_CMD_MODE_ONE_LINE | - WSPI_CFG_ADDR_MODE_ONE_LINE | - WSPI_CFG_DATA_MODE_ONE_LINE; -#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L - WSPI_CFG_CMD_MODE_TWO_LINES | - WSPI_CFG_ADDR_MODE_TWO_LINES | - WSPI_CFG_DATA_MODE_TWO_LINES; -#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI4L - WSPI_CFG_CMD_MODE_FOUR_LINES | - WSPI_CFG_ADDR_MODE_FOUR_LINES | - WSPI_CFG_DATA_MODE_FOUR_LINES; -#else - WSPI_CFG_CMD_MODE_EIGHT_LINES | - WSPI_CFG_ADDR_MODE_EIGHT_LINES | - WSPI_CFG_DATA_MODE_EIGHT_LINES; -#endif - - /* Handling 32 bits addressing. - TODO: Address size should come from upper levels.*/ - if ((cmd & SNOR_BUS_CMD_EXTENDED_ADDRESSING) == 0) { - mode.cfg |= WSPI_CFG_ADDR_SIZE_24; - } - else { - mode.cfg |= WSPI_CFG_ADDR_SIZE_32; - } - - mode.addr = offset; - mode.alt = 0U; - wspiSend(busp, &mode, n, p); -#else - uint8_t buf[4]; - - spiSelect(busp); - buf[0] = cmd; - buf[1] = (uint8_t)(offset >> 16); - buf[2] = (uint8_t)(offset >> 8); - buf[3] = (uint8_t)(offset >> 0); - spiSend(busp, 4, buf); - spiSend(busp, n, p); - spiUnselect(busp); -#endif -} - -/** - * @brief Sends a command followed by a flash address and a data receive - * phase. - * - * @param[in] busp pointer to the bus driver - * @param[in] cmd instruction code - * @param[in] offset flash offset - * @param[in] n number of bytes to receive - * @param[out] p data buffer - * - * @notapi - */ -void bus_cmd_addr_receive(BUSDriver *busp, - uint32_t cmd, - flash_offset_t offset, - size_t n, - uint8_t *p) { -#if SNOR_BUS_MODE != SNOR_BUS_MODE_SPI - wspi_command_t mode; - - mode.cmd = cmd; - mode.dummy = 0U; - mode.cfg = 0U | -#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L - WSPI_CFG_CMD_MODE_ONE_LINE | - WSPI_CFG_ADDR_MODE_ONE_LINE | - WSPI_CFG_DATA_MODE_ONE_LINE; -#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L - WSPI_CFG_CMD_MODE_TWO_LINES | - WSPI_CFG_ADDR_MODE_TWO_LINES | - WSPI_CFG_DATA_MODE_TWO_LINES; -#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI4L - WSPI_CFG_CMD_MODE_TWO_LINES | - WSPI_CFG_ADDR_MODE_TWO_LINES | - WSPI_CFG_DATA_MODE_TWO_LINES; -#else - WSPI_CFG_CMD_MODE_EIGHT_LINES | - WSPI_CFG_ADDR_MODE_EIGHT_LINES | - WSPI_CFG_DATA_MODE_EIGHT_LINES; -#endif - - /* Handling 32 bits addressing. - TODO: Address size should come from upper levels.*/ - if ((cmd & SNOR_BUS_CMD_EXTENDED_ADDRESSING) == 0) { - mode .cfg |= WSPI_CFG_ADDR_SIZE_24; - } - else { - mode .cfg |= WSPI_CFG_ADDR_SIZE_32; - } - - mode.addr = offset; - mode.alt = 0U; - wspiReceive(busp, &mode, n, p); -#else - uint8_t buf[4]; - - spiSelect(busp); - buf[0] = cmd; - buf[1] = (uint8_t)(offset >> 16); - buf[2] = (uint8_t)(offset >> 8); - buf[3] = (uint8_t)(offset >> 0); - spiSend(busp, 4, buf); - spiReceive(busp, n, p); - spiUnselect(busp); -#endif -} - -#if (SNOR_BUS_MODE != SNOR_BUS_MODE_SPI) || defined(__DOXYGEN__) -/** - * @brief Sends a command followed by a flash address, dummy cycles and a - * data receive phase. - * - * @param[in] busp pointer to the bus driver - * @param[in] cmd instruction code - * @param[in] offset flash offset - * @param[in] dummy number of dummy cycles - * @param[in] n number of bytes to receive - * @param[out] p data buffer - * - * @notapi - */ -void bus_cmd_addr_dummy_receive(BUSDriver *busp, - uint32_t cmd, - flash_offset_t offset, - uint32_t dummy, - size_t n, - uint8_t *p) { - wspi_command_t mode; - - mode.cmd = cmd; - mode.dummy = dummy; - mode.cfg = 0U | -#if SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI1L - WSPI_CFG_CMD_MODE_ONE_LINE | - WSPI_CFG_ADDR_MODE_ONE_LINE | - WSPI_CFG_DATA_MODE_ONE_LINE; -#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI2L - WSPI_CFG_CMD_MODE_TWO_LINES | - WSPI_CFG_ADDR_MODE_TWO_LINES | - WSPI_CFG_DATA_MODE_TWO_LINES; -#elif SNOR_BUS_MODE == SNOR_BUS_MODE_WSPI4L - WSPI_CFG_CMD_MODE_FOUR_LINES | - WSPI_CFG_ADDR_MODE_FOUR_LINES | - WSPI_CFG_DATA_MODE_FOUR_LINES; -#else - WSPI_CFG_CMD_MODE_EIGHT_LINES | - WSPI_CFG_ADDR_MODE_EIGHT_LINES | - WSPI_CFG_DATA_MODE_EIGHT_LINES; -#endif - - /* Handling 32 bits addressing. - TODO: Address size should come from upper levels.*/ - if ((cmd & SNOR_BUS_CMD_EXTENDED_ADDRESSING) == 0) { - mode .cfg |= WSPI_CFG_ADDR_SIZE_24; - } - else { - mode .cfg |= WSPI_CFG_ADDR_SIZE_32; - } - - mode.addr = offset; - mode.alt = 0U; - wspiReceive(busp, &mode, n, p); -} -#endif /* SNOR_BUS_MODE != SNOR_BUS_MODE_SPI */ - -/** - * @brief Initializes an instance. - * - * @param[out] devp pointer to the @p SNORDriver object - * - * @init - */ -void snorObjectInit(SNORDriver *devp) { - - osalDbgCheck(devp != NULL); - - devp->vmt = &snor_vmt; - devp->state = FLASH_STOP; - devp->config = NULL; -} - -/** - * @brief Configures and activates SNOR driver. - * - * @param[in] devp pointer to the @p SNORDriver object - * @param[in] config pointer to the configuration - * - * @api - */ -void snorStart(SNORDriver *devp, const SNORConfig *config) { - - osalDbgCheck((devp != NULL) && (config != NULL)); - osalDbgAssert(devp->state != FLASH_UNINIT, "invalid state"); - - devp->config = config; - - if (devp->state == FLASH_STOP) { - - /* Bus acquisition.*/ - bus_acquire(devp->config->busp, devp->config->buscfg); - - /* Device identification and initialization.*/ - snor_device_init(devp); - - /* Driver in ready state.*/ - devp->state = FLASH_READY; - - /* Bus release.*/ - bus_release(devp->config->busp); - } -} - -/** - * @brief Deactivates the SNOR driver. - * - * @param[in] devp pointer to the @p SNORDriver object - * - * @api - */ -void snorStop(SNORDriver *devp) { - - osalDbgCheck(devp != NULL); - osalDbgAssert(devp->state != FLASH_UNINIT, "invalid state"); - - if (devp->state != FLASH_STOP) { - - /* Bus acquisition.*/ - bus_acquire(devp->config->busp, devp->config->buscfg); - - /* Stopping bus device.*/ - bus_stop(devp->config->busp); - - /* Driver stopped.*/ - devp->state = FLASH_STOP; - - /* Bus release.*/ - bus_release(devp->config->busp); - - /* Deleting current configuration.*/ - devp->config = NULL; - } -} - -#if (SNOR_BUS_MODE != SNOR_BUS_MODE_SPI) || defined(__DOXYGEN__) -#if (WSPI_SUPPORTS_MEMMAP == TRUE) || defined(__DOXYGEN__) -/** - * @brief Enters the memory Mapping mode. - * @details The memory mapping mode is only available when the WSPI mode - * is selected and the underlying WSPI controller supports the - * feature. - * - * @param[in] devp pointer to the @p SNORDriver object - * @param[out] addrp pointer to the memory start address of the mapped - * flash or @p NULL - * - * @api - */ -void snorMemoryMap(SNORDriver *devp, uint8_t **addrp) { - - /* Bus acquisition.*/ - bus_acquire(devp->config->busp, devp->config->buscfg); - - /* Activating XIP mode in the device.*/ - snor_activate_xip(devp); - - /* Starting WSPI memory mapped mode.*/ - wspiMapFlash(devp->config->busp, &snor_memmap_read, addrp); - - /* Bus release.*/ - bus_release(devp->config->busp); -} - -/** - * @brief Leaves the memory Mapping mode. - * - * @param[in] devp pointer to the @p SNORDriver object - * - * @api - */ -void snorMemoryUnmap(SNORDriver *devp) { - - /* Bus acquisition.*/ - bus_acquire(devp->config->busp, devp->config->buscfg); - - /* Stopping WSPI memory mapped mode.*/ - wspiUnmapFlash(devp->config->busp); - - snor_reset_xip(devp); - - /* Bus release.*/ - bus_release(devp->config->busp); -} -#endif /* WSPI_SUPPORTS_MEMMAP == TRUE */ -#endif /* SNOR_BUS_MODE != SNOR_BUS_MODE_SPI */ - -/** @} */ diff --git a/os/hal/lib/complex/serial_nor/serial_nor.h b/os/hal/lib/complex/serial_nor/serial_nor.h deleted file mode 100644 index 62c25a1ba..000000000 --- a/os/hal/lib/complex/serial_nor/serial_nor.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio - - 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 serial_nor.h - * @brief Serial NOR driver header. - * - * @addtogroup SERIAL_NOR - * @ingroup SERIAL_NOR - * @{ - */ - -#ifndef SERIAL_NOR_H -#define SERIAL_NOR_H - -#include "hal_flash.h" - -/*===========================================================================*/ -/* Driver constants. */ -/*===========================================================================*/ - -/** - * @name Bus interface modes. - * @{ - */ -#define SNOR_BUS_MODE_SPI 0U -#define SNOR_BUS_MODE_WSPI1L 1U -#define SNOR_BUS_MODE_WSPI2L 2U -#define SNOR_BUS_MODE_WSPI4L 4U -#define SNOR_BUS_MODE_WSPI8L 8U -/** @} */ - -#define SNOR_BUS_CMD_EXTENDED_ADDRESSING 0x80000000U - -/*===========================================================================*/ -/* Driver pre-compile time settings. */ -/*===========================================================================*/ - -/** - * @name Configuration options - * @{ - */ -/** - * @brief Physical transport interface. - */ -#if !defined(SNOR_BUS_MODE) || defined(__DOXYGEN__) -#define SNOR_BUS_MODE SNOR_BUS_MODE_WSPI4L -#endif - -/** - * @brief Shared bus switch. - * @details If set to @p TRUE the device acquires bus ownership - * on each transaction. - * @note Requires @p SPI_USE_MUTUAL_EXCLUSION or - * @p WSPI_USE_MUTUAL_EXCLUSION depending on mode selected - * with @p SNOR_BUS_MODE. - */ -#if !defined(SNOR_SHARED_BUS) || defined(__DOXYGEN__) -#define SNOR_SHARED_BUS TRUE -#endif -/** @} */ - -/*===========================================================================*/ -/* Derived constants and error checks. */ -/*===========================================================================*/ - -#if (SNOR_BUS_MODE != SNOR_BUS_MODE_SPI) || defined(__DOXYGEN__) -#define BUSConfig WSPIConfig -#define BUSDriver WSPIDriver -#else -#define BUSConfig SPIConfig -#define BUSDriver SPIDriver -#endif - -/*===========================================================================*/ -/* Driver data structures and types. */ -/*===========================================================================*/ - -/** - * @brief Type of a SNOR configuration structure. - */ -typedef struct { - BUSDriver *busp; - const BUSConfig *buscfg; -} SNORConfig; - -/** - * @brief @p SNORDriver specific methods. - */ -#define _snor_flash_methods_alone \ - /* Read SFDP.*/ \ - flash_error_t (*read_sfdp)(void *instance, \ - flash_offset_t offset, \ - size_t n, \ - uint8_t *rp); - -/** - * @brief @p SNORDriver specific methods with inherited ones. - */ -#define _snor_flash_methods \ - _base_flash_methods \ - _snor_flash_methods_alone - -/** - * @extends BaseFlashVMT - * - * @brief @p SNOR virtual methods table. - */ -struct SNORDriverVMT { - _snor_flash_methods -}; - -/** - * @extends BaseFlash - * - * @brief Type of SNOR flash class. - */ -typedef struct { - /** - * @brief SNORDriver Virtual Methods Table. - */ - const struct SNORDriverVMT *vmt; - _base_flash_data - /** - * @brief Current configuration data. - */ - const SNORConfig *config; - /** - * @brief Device ID and unique ID. - */ - uint8_t device_id[20]; -} SNORDriver; - -/*===========================================================================*/ -/* Driver macros. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -#ifdef __cplusplus -extern "C" { -#endif - void bus_cmd(BUSDriver *busp, uint32_t cmd); - void bus_cmd_send(BUSDriver *busp, uint32_t cmd, size_t n, const uint8_t *p); - void bus_cmd_receive(BUSDriver *busp, - uint32_t cmd, - size_t n, - uint8_t *p); - void bus_cmd_addr(BUSDriver *busp, uint32_t cmd, flash_offset_t offset); - void bus_cmd_addr_send(BUSDriver *busp, - uint32_t cmd, - flash_offset_t offset, - size_t n, - const uint8_t *p); - void bus_cmd_addr_receive(BUSDriver *busp, - uint32_t cmd, - flash_offset_t offset, - size_t n, - uint8_t *p); - void bus_cmd_addr_dummy_receive(BUSDriver *busp, - uint32_t cmd, - flash_offset_t offset, - uint32_t dummy, - size_t n, - uint8_t *p); - void snorObjectInit(SNORDriver *devp); - void snorStart(SNORDriver *devp, const SNORConfig *config); - void snorStop(SNORDriver *devp); -#if (SNOR_BUS_MODE != SNOR_BUS_MODE_SPI) || defined(__DOXYGEN__) -#if (WSPI_SUPPORTS_MEMMAP == TRUE) || defined(__DOXYGEN__) - void snorMemoryMap(SNORDriver *devp, uint8_t ** addrp); - void snorMemoryUnmap(SNORDriver *devp); -#endif /* QSPI_SUPPORTS_MEMMAP == TRUE */ -#endif /* SNOR_BUS_MODE != SNOR_BUS_MODE_SPI */ -#ifdef __cplusplus -} -#endif - -/* Device-specific implementations.*/ -#include "flash_device.h" - -#endif /* SERIAL_NOR_H */ - -/** @} */ - diff --git a/os/lib/include/chlib.h b/os/lib/include/chlib.h index 1097c8e15..495d03643 100644 --- a/os/lib/include/chlib.h +++ b/os/lib/include/chlib.h @@ -38,7 +38,7 @@ /** * @brief ChibiOS/LIB identification macro. */ -#define _CHIBIOS_LIB_ +#define _CHIBIOS_OSLIB_ /** * @brief Stable release flag. @@ -138,11 +138,11 @@ #endif /* License checks.*/ -#if !defined(CH_CUSTOMER_LIC_LIB) || !defined(CH_LICENSE_FEATURES) +#if !defined(CH_CUSTOMER_LIC_OSLIB) || !defined(CH_LICENSE_FEATURES) #error "malformed chlicense.h" #endif -#if CH_CUSTOMER_LIC_LIB== FALSE +#if CH_CUSTOMER_LIC_OSLIB== FALSE #error "ChibiOS/LIB not licensed" #endif @@ -153,7 +153,7 @@ #endif /* Restrictions in basic and intermediate modes.*/ -#if (CH_CUSTOMER_LIC_LIB == FALSE) || \ +#if (CH_CUSTOMER_LIC_OSLIB == FALSE) || \ (CH_LICENSE_FEATURES == CH_FEATURES_INTERMEDIATE) || \ (CH_LICENSE_FEATURES == CH_FEATURES_BASIC) @@ -162,12 +162,12 @@ #define CH_CFG_USE_FACTORY FALSE -#endif /* (CH_CUSTOMER_LIC_LIB == FALSE) || +#endif /* (CH_CUSTOMER_LIC_OSLIB == FALSE) || (CH_LICENSE_FEATURES == CH_FEATURES_INTERMEDIATE) || (CH_LICENSE_FEATURES == CH_FEATURES_BASIC) */ /* Restrictions in basic mode.*/ -#if (CH_CUSTOMER_LIC_LIB == FALSE) || \ +#if (CH_CUSTOMER_LIC_OSLIB == FALSE) || \ (CH_LICENSE_FEATURES == CH_FEATURES_BASIC) /* Restricted subsystems.*/ @@ -183,7 +183,7 @@ #define CH_CFG_USE_OBJ_FIFOS FALSE #define CH_CFG_USE_PIPES FALSE -#endif /* (CH_CUSTOMER_LIC_LIB == FALSE) || +#endif /* (CH_CUSTOMER_LIC_OSLIB == FALSE) || (CH_LICENSE_FEATURES == CH_FEATURES_BASIC) */ /*===========================================================================*/ diff --git a/os/license/chcustomer.h b/os/license/chcustomer.h index 61aed864e..0c0f8cb16 100644 --- a/os/license/chcustomer.h +++ b/os/license/chcustomer.h @@ -60,7 +60,7 @@ */ #define CH_CUSTOMER_LIC_RT TRUE #define CH_CUSTOMER_LIC_NIL TRUE -#define CH_CUSTOMER_LIC_LIB TRUE +#define CH_CUSTOMER_LIC_OSLIB TRUE #define CH_CUSTOMER_LIC_EX TRUE #define CH_CUSTOMER_LIC_PORT_CM0 TRUE #define CH_CUSTOMER_LIC_PORT_CM3 TRUE diff --git a/testhal/STM32/multi/WSPI-MFS/.cproject b/testhal/STM32/multi/WSPI-MFS/.cproject index a950bac3f..5052dd0dd 100644 --- a/testhal/STM32/multi/WSPI-MFS/.cproject +++ b/testhal/STM32/multi/WSPI-MFS/.cproject @@ -78,6 +78,7 @@ + diff --git a/testhal/STM32/multi/WSPI-MFS/main.c b/testhal/STM32/multi/WSPI-MFS/main.c index 3de5be345..eb964184b 100644 --- a/testhal/STM32/multi/WSPI-MFS/main.c +++ b/testhal/STM32/multi/WSPI-MFS/main.c @@ -19,7 +19,7 @@ #include "ch.h" #include "hal.h" -#include "serial_nor.h" +#include "hal_serial_nor.h" #include "mfs.h" #include "mfs_test_root.h" diff --git a/testhal/STM32/multi/WSPI-MFS/make/stm32l476_discovery.make b/testhal/STM32/multi/WSPI-MFS/make/stm32l476_discovery.make index 067ab9f04..ad212eca6 100644 --- a/testhal/STM32/multi/WSPI-MFS/make/stm32l476_discovery.make +++ b/testhal/STM32/multi/WSPI-MFS/make/stm32l476_discovery.make @@ -113,7 +113,7 @@ include $(CHIBIOS)/tools/mk/autobuild.mk # Other files (optional). include $(CHIBIOS)/test/lib/test.mk include $(CHIBIOS)/test/mfs/mfs_test.mk -include $(CHIBIOS)/os/hal/lib/complex/serial_nor/devices/micron_n25q/flash_device.mk +include $(CHIBIOS)/os/hal/lib/complex/serial_nor/devices/micron_n25q/hal_flash_device.mk include $(CHIBIOS)/os/hal/lib/complex/mfs/mfs.mk include $(CHIBIOS)/os/hal/lib/streams/streams.mk -- cgit v1.2.3