From da54384531630ae204b1b925537a2ec0bb136980 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Fri, 2 Nov 2018 08:43:34 +0000 Subject: Tentative driver for macronix MX25LM51245G, untested. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@12400 110e8d01-0319-4d1e-a829-52ad28d1bb01 --- .../devices/macronix_mx25/hal_flash_device.c | 645 +++++++++++++++++++++ .../devices/macronix_mx25/hal_flash_device.h | 416 +++++++++++++ .../devices/macronix_mx25/hal_flash_device.mk | 13 + .../devices/micron_n25q/hal_flash_device.c | 1 - .../devices/micron_n25q/hal_flash_device.h | 167 +++--- os/hal/lib/complex/serial_nor/hal_serial_nor.c | 32 +- os/hal/lib/complex/serial_nor/hal_serial_nor.h | 8 +- 7 files changed, 1199 insertions(+), 83 deletions(-) create mode 100644 os/hal/lib/complex/serial_nor/devices/macronix_mx25/hal_flash_device.c create mode 100644 os/hal/lib/complex/serial_nor/devices/macronix_mx25/hal_flash_device.h create mode 100644 os/hal/lib/complex/serial_nor/devices/macronix_mx25/hal_flash_device.mk (limited to 'os') diff --git a/os/hal/lib/complex/serial_nor/devices/macronix_mx25/hal_flash_device.c b/os/hal/lib/complex/serial_nor/devices/macronix_mx25/hal_flash_device.c new file mode 100644 index 000000000..c9058199d --- /dev/null +++ b/os/hal/lib/complex/serial_nor/devices/macronix_mx25/hal_flash_device.c @@ -0,0 +1,645 @@ +/* + 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 hal_flash_device.c + * @brief Macronix MX25 serial flash driver code. + * + * @addtogroup MACRONIX_MX25 + * @{ + */ + +#include + +#include "hal.h" +#include "hal_serial_nor.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define PAGE_SIZE 256U +#define PAGE_MASK (PAGE_SIZE - 1U) + +#if MX25_USE_SUB_SECTORS == TRUE +#define SECTOR_SIZE 0x00001000U +#define CMD_SECTOR_ERASE MX25_CMD_SUBSECTOR_ERASE +#else +#define SECTOR_SIZE 0x00010000U +#define CMD_SECTOR_ERASE MX25_CMD_SECTOR_ERASE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief MX25LM51245G 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_DRIVER == SNOR_BUS_DRIVER_WSPI) || defined(__DOXYGEN__) +#if (WSPI_SUPPORTS_MEMMAP == TRUE) || defined(__DOXYGEN__) +/** + * @brief Fast read command for memory mapped mode. + */ +const wspi_command_t snor_memmap_read = { + .addr = 0U, +#if MX25_BUS_MODE == MX25_BUS_MODE_SPI + .cmd = MX25_CMD_SPI_FAST_READ4B, + .dummy = 8, /* Note, always 8 for this command. */ + .cfg = WSPI_CFG_CMD_MODE_ONE_LINE | + WSPI_CFG_ADDR_MODE_ONE_LINE | + WSPI_CFG_DATA_MODE_ONE_LINE | + WSPI_CFG_CMD_SIZE_8 | + WSPI_CFG_ADDR_SIZE_32 +#elif MX25_BUS_MODE == MX25_BUS_MODE_OPI_STR + .cmd = MX25_CMD_OPI_8READ, + .dummy = MX25_READ_DUMMY_CYCLES, + .cfg = WSPI_CFG_CMD_MODE_TWO_LINES | + WSPI_CFG_ADDR_MODE_TWO_LINES | + WSPI_CFG_DATA_MODE_TWO_LINES | + WSPI_CFG_CMD_SIZE_16 | + WSPI_CFG_ADDR_SIZE_32 +#elif MX25_BUS_MODE == MX25_BUS_MODE_OPI_DTR + .cmd = MX25_CMD_OPI_8DTRD, + .dummy = MX25_READ_DUMMY_CYCLES, + .cfg = WSPI_CFG_CMD_MODE_FOUR_LINES | + WSPI_CFG_ADDR_MODE_FOUR_LINES | + WSPI_CFG_DATA_MODE_FOUR_LINES | + WSPI_CFG_CMD_SIZE_16 | + WSPI_CFG_ADDR_SIZE_32 | + WSPI_CFG_CMD_DDR | + WSPI_CFG_ADDR_DDR | + WSPI_CFG_DATA_DDR +#endif +}; +#endif +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +#if SNOR_BUS_DRIVER == SNOR_BUS_DRIVER_WSPI +/* Initial MX25_CMD_READ_ID command.*/ +static const wspi_command_t mx25_cmd_read_id = { + +#if MX25_SWITCH_WIDTH == TRUE + .cmd = MX25_CMD_SPI_RDID, + .cfg = WSPI_CFG_CMD_MODE_ONE_LINE | + WSPI_CFG_DATA_MODE_ONE_LINE | + WSPI_CFG_CMD_SIZE_8, + .dummy = 0, +#else +#if MX25_BUS_MODE == MX25_BUS_MODE_SPI + .cmd = MX25_CMD_SPI_RDID, + .cfg = WSPI_CFG_CMD_MODE_ONE_LINE | + WSPI_CFG_DATA_MODE_ONE_LINE | + WSPI_CFG_CMD_SIZE_8, + .dummy = 0, +#elif MX25_BUS_MODE == MX25_BUS_MODE_OPI_STR + .cmd = MX25_CMD_OPI_RDID, + .cfg = WSPI_CFG_CMD_MODE_EIGHT_LINES | + WSPI_CFG_DATA_MODE_EIGHT_LINES | + WSPI_CFG_CMD_SIZE_16, + .dummy = MX25_READ_DUMMY_CYCLES, +#elif MX25_BUS_MODE == MX25_BUS_MODE_OPI_DTR + .cmd = MX25_CMD_OPI_RDID, + .cfg = WSPI_CFG_CMD_MODE_EIGHT_LINES | + WSPI_CFG_DATA_MODE_EIGHT_LINES | + WSPI_CFG_CMD_SIZE_16 | + WSPI_CFG_CMD_DDR, + .dummy = MX25_READ_DUMMY_CYCLES, +#endif +#endif + .addr = 0, + .alt = 0 +}; + +static const uint8_t n25q_manufacturer_ids[] = MX25_SUPPORTED_MANUFACTURE_IDS; +static const uint8_t n25q_memory_type_ids[] = MX25_SUPPORTED_MEMORY_TYPE_IDS; +#endif /* SNOR_BUS_DRIVER == SNOR_BUS_DRIVER_WSPI */ + +/*===========================================================================*/ +/* 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 MX25_NICE_WAITING == TRUE + osalThreadSleepMilliseconds(1); +#endif + /* Read status command.*/ +#if MX25_BUS_MODE == MX25_BUS_MODE_SPI + bus_cmd_receive(devp->config->busp, MX25_CMD_SPI_RDSR, 1, &sts); +#else + bus_cmd_dummy_receive(devp->config->busp, MX25_CMD_OPI_RDSR, 1, &sts); +#endif + } while ((sts & 1U) != 0U); + + /* Reading security register and checking for errors.*/ +#if MX25_BUS_MODE == MX25_BUS_MODE_SPI + bus_cmd_receive(devp->config->busp, MX25_CMD_SPI_RDSCUR, 1, &sts); +#else + bus_cmd_dummy_receive(devp->config->busp, MX25_CMD_OPI_RDSCUR, 1, &sts); +#endif + if ((sts & MX25_FLAGS_ALL_ERRORS) != 0U) { + + return FLASH_ERROR_PROGRAM; + } + + return FLASH_NO_ERROR; +} + +#if (SNOR_BUS_DRIVER == SNOR_BUS_DRIVER_WSPI) || defined(__DOXYGEN__) +static void n25q_reset_memory(SNORDriver *devp) { + + /* 1x MX25_CMD_SPI_RSTEN command.*/ + static const wspi_command_t cmd_reset_enable_1 = { + .cmd = MX25_CMD_SPI_RSTEN, + .cfg = WSPI_CFG_CMD_MODE_ONE_LINE | WSPI_CFG_CMD_SIZE_8, + .addr = 0, + .alt = 0, + .dummy = 0 + }; + + /* 1x MX25_CMD_SPI_RST command.*/ + static const wspi_command_t cmd_reset_memory_1 = { + .cmd = MX25_CMD_SPI_RST, + .cfg = WSPI_CFG_CMD_MODE_ONE_LINE | WSPI_CFG_CMD_SIZE_8, + .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 MX25_BUS_MODE == MX25_BUS_MODE_OPI_DTR + /* 8xDTR MX25_CMD_OPI_RSTEN command.*/ + static const wspi_command_t cmd_reset_enable_8dtr = { + .cmd = MX25_CMD_OPI_RSTEN, + .cfg = WSPI_CFG_CMD_MODE_EIGHT_LINES | + WSPI_CFG_CMD_SIZE_16 | + WSPI_CFG_CMD_DDR, + .addr = 0, + .alt = 0, + .dummy = 0 + }; + + /* 8xDTR MX25_CMD_OPI_RST command.*/ + static const wspi_command_t cmd_reset_memory_8dtr = { + .cmd = MX25_CMD_OPI_RST, + .cfg = WSPI_CFG_CMD_MODE_EIGHT_LINES | + WSPI_CFG_CMD_SIZE_16 | + WSPI_CFG_CMD_DDR, + .addr = 0, + .alt = 0, + .dummy = 0 + }; + + wspiCommand(devp->config->busp, &cmd_reset_enable_8dtr); + wspiCommand(devp->config->busp, &cmd_reset_memory_8dtr); +#else + /* 8xSTR MX25_CMD_OPI_RSTEN command.*/ + static const wspi_command_t cmd_reset_enable_8str = { + .cmd = MX25_CMD_OPI_RSTEN, + .cfg = WSPI_CFG_CMD_MODE_EIGHT_LINES | + WSPI_CFG_CMD_SIZE_16, + .addr = 0, + .alt = 0, + .dummy = 0 + }; + + /* 8xSTR MX25_CMD_OPI_RST command.*/ + static const wspi_command_t cmd_reset_memory_8str = { + .cmd = MX25_CMD_OPI_RST, + .cfg = WSPI_CFG_CMD_MODE_EIGHT_LINES | + WSPI_CFG_CMD_SIZE_16, + .addr = 0, + .alt = 0, + .dummy = 0 + }; + + wspiCommand(devp->config->busp, &cmd_reset_enable_8str); + wspiCommand(devp->config->busp, &cmd_reset_memory_8str); +#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); +} + +static void mx25_write_cr2(SNORDriver *devp, uint32_t addr, const uint8_t *value) { + + const wspi_command_t cmd_write_cr2 = { + +#if MX25_SWITCH_WIDTH == TRUE + .cmd = MX25_CMD_SPI_RDID, + .cfg = WSPI_CFG_CMD_MODE_ONE_LINE | + WSPI_CFG_ADDR_MODE_ONE_LINE | + WSPI_CFG_DATA_MODE_ONE_LINE | + WSPI_CFG_CMD_SIZE_8 | + WSPI_CFG_ADDR_SIZE_32, +#else +#if MX25_BUS_MODE == MX25_BUS_MODE_SPI + .cmd = MX25_CMD_SPI_RDID, + .cfg = WSPI_CFG_CMD_MODE_ONE_LINE | + WSPI_CFG_ADDR_MODE_ONE_LINE | + WSPI_CFG_DATA_MODE_ONE_LINE | + WSPI_CFG_CMD_SIZE_8 | + WSPI_CFG_ADDR_SIZE_32, +#elif MX25_BUS_MODE == MX25_BUS_MODE_OPI_STR + .cmd = MX25_CMD_OPI_RDID, + .cfg = WSPI_CFG_CMD_MODE_EIGHT_LINES | + WSPI_CFG_ADDR_MODE_EIGHT_LINES | + WSPI_CFG_DATA_MODE_EIGHT_LINES | + WSPI_CFG_CMD_SIZE_16 | + WSPI_CFG_ADDR_SIZE_32, +#elif MX25_BUS_MODE == MX25_BUS_MODE_OPI_DTR + .cmd = MX25_CMD_OPI_RDID, + .cfg = WSPI_CFG_CMD_MODE_EIGHT_LINES | + WSPI_CFG_ADDR_MODE_EIGHT_LINES | + WSPI_CFG_DATA_MODE_EIGHT_LINES | + WSPI_CFG_CMD_SIZE_16 | + WSPI_CFG_ADDR_SIZE_32 | + WSPI_CFG_CMD_DDR, +#endif +#endif + .addr = addr, + .alt = 0, + .dummy = 0 + }; + + static const wspi_command_t cmd_write_enable = { +#if MX25_SWITCH_WIDTH == TRUE + .cmd = MX25_CMD_SPI_WREN, + .cfg = WSPI_CFG_CMD_MODE_ONE_LINE, +#else +#if MX25_BUS_MODE == MX25_BUS_MODE_SPI + .cfg = WSPI_CFG_CMD_MODE_ONE_LINE, +#elif MX25_BUS_MODE == MX25_BUS_MODE_OPI_STR + .cfg = WSPI_CFG_CMD_MODE_EIGHT_LINES | + WSPI_CFG_CMD_SIZE_16, +#elif MX25_BUS_MODE == MX25_BUS_MODE_OPI_DTR + .cfg = WSPI_CFG_CMD_MODE_EIGHT_LINES | + WSPI_CFG_CMD_SIZE_16 | + WSPI_CFG_CMD_DDR, +#endif +#endif + .addr = 0, + .alt = 0, + .dummy = 0 + }; + + wspiCommand(devp->config->busp, &cmd_write_enable); + wspiSend(devp->config->busp, &cmd_write_cr2, 1, value); +} +#endif /* SNOR_BUS_DRIVER == SNOR_BUS_DRIVER_WSPI */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +void snor_device_init(SNORDriver *devp) { + +#if SNOR_BUS_DRIVER == SNOR_BUS_DRIVER_SPI + /* Reading device ID.*/ + bus_cmd_receive(devp->config->busp, MX25_CMD_READ_ID, + sizeof devp->device_id, devp->device_id); + +#else /* SNOR_BUS_DRIVER == SNOR_BUS_DRIVER_WSPI */ + + /* 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, &mx25_cmd_read_id, + sizeof devp->device_id, devp->device_id); +#endif /* SNOR_BUS_DRIVER == SNOR_BUS_DRIVER_WSPI */ + + /* 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_DRIVER == SNOR_BUS_DRIVER_WSPI) && (MX25_SWITCH_WIDTH == TRUE) + { + /* Bus width initialization.*/ +#if MX25_BUS_MODE == MX25_BUS_MODE_OPI_STR + static const uint8_t regval[1] = {0x01}; +#else + static const uint8_t regval[1] = {0x02}; +#endif + uint8_t id[8]; + + /* Setting up final bus width.*/ + mx25_write_cr2(devp, 0x00000000U, regval); + + /* Reading ID again for confirmation, in DTR mode bytes are read twice, + it needs adjusting.*/ +#if MX25_BUS_MODE == MX25_BUS_MODE_OPI_DTR + bus_cmd_dummy_receive(devp->config->busp, MX25_CMD_OPI_RDID, 6, id); + id[1] = id[2]; + id[2] = id[4]; +#else + bus_cmd_dummy_receive(devp->config->busp, MX25_CMD_OPI_RDID, + MX25_READ_DUMMY_CYCLES, 3, id); +#endif + + /* 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]) & 0x1FU) / + SECTOR_SIZE; + +#if SNOR_BUS_DRIVER == SNOR_BUS_DRIVER_WSPI + { + static const uint8_t regval[1] = { + ~((MX25_READ_DUMMY_CYCLES - 6U) / 2U) & 7U + }; + + /* Setting up the dummy cycles to be used for fast read operations.*/ + mx25_write_cr2(devp, 0x00000300U, regval); + } +#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_DRIVER == SNOR_BUS_DRIVER_WSPI + /* Fast read command in WSPI mode.*/ +#if MX25_BUS_MODE == MX25_BUS_MODE_SPI + bus_cmd_addr_dummy_receive(devp->config->busp, MX25_CMD_SPI_FAST_READ4B, + offset, 8, /* Note, always 8 dummy cycles. */ + n, rp); +#elif MX25_BUS_MODE == MX25_BUS_MODE_OPI_DTR + bus_cmd_addr_dummy_receive(devp->config->busp, MX25_CMD_OPI_8DTRD, + offset, MX25_READ_DUMMY_CYCLES, n, rp); +#elif MX25_BUS_MODE == MX25_BUS_MODE_OPI_STR + bus_cmd_addr_dummy_receive(devp->config->busp, MX25_CMD_OPI_8READ, + offset, MX25_READ_DUMMY_CYCLES, n, rp); +#endif +#else + /* Normal read command in SPI mode.*/ + bus_cmd_addr_receive(devp->config->busp, MX25_CMD_SPI_READ4B, + 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; + } + +#if MX25_BUS_MODE == MX25_BUS_MODE_SPI + /* Enabling write operation.*/ + bus_cmd(devp->config->busp, MX25_CMD_SPI_WREN); + + /* Page program command.*/ + bus_cmd_addr_send(devp->config->busp, MX25_CMD_SPI_PP4B, offset, + chunk, pp); +#else + /* Enabling write operation.*/ + bus_cmd(devp->config->busp, MX25_CMD_OPI_WREN); + + /* Page program command.*/ + bus_cmd_addr_send(devp->config->busp, MX25_CMD_OPI_PP4B, offset, + chunk, pp); +#endif + + /* 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) { + +#if MX25_BUS_MODE == MX25_BUS_MODE_SPI + /* Enabling write operation.*/ + bus_cmd(devp->config->busp, MX25_CMD_SPI_WREN); + + /* Bulk erase command.*/ + bus_cmd(devp->config->busp, MX25_CMD_SPI_CE); +#else + /* Enabling write operation.*/ + bus_cmd(devp->config->busp, MX25_CMD_OPI_WREN); + + /* Bulk erase command.*/ + bus_cmd(devp->config->busp, MX25_CMD_OPI_CE); +#endif + + 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); + +#if MX25_BUS_MODE == MX25_BUS_MODE_SPI + /* Enabling write operation.*/ + bus_cmd(devp->config->busp, MX25_CMD_SPI_WREN); + +#if MX25_USE_SUB_SECTORS == FALSE + /* Block erase command.*/ + bus_cmd_addr(devp->config->busp, MX25_CMD_SPI_BE4B, offset); +#else + /* Sector erase command.*/ + bus_cmd_addr(devp->config->busp, MX25_CMD_SPI_SE4B, offset); +#endif +#else + /* Enabling write operation.*/ + bus_cmd(devp->config->busp, MX25_CMD_OPI_WREN); + +#if MX25_USE_SUB_SECTORS == FALSE + /* Block erase command.*/ + bus_cmd_addr(devp->config->busp, MX25_CMD_OPI_BE4B, offset); +#else + /* Sector erase command.*/ + bus_cmd_addr(devp->config->busp, MX25_CMD_OPI_SE4B, offset); +#endif +#endif + + return FLASH_NO_ERROR; +} + +flash_error_t snor_device_verify_erase(SNORDriver *devp, + flash_sector_t sector) { + uint8_t cmpbuf[MX25_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_DRIVER == SNOR_BUS_DRIVER_WSPI +#if MX25_BUS_MODE == MX25_BUS_MODE_SPI + bus_cmd_addr_dummy_receive(devp->config->busp, MX25_CMD_SPI_FAST_READ4B, + offset, 8, /* Note, always 8 dummy cycles. */ + sizeof cmpbuf, cmpbuf); +#elif MX25_BUS_MODE == MX25_BUS_MODE_OPI_STR + bus_cmd_addr_dummy_receive(devp->config->busp, MX25_CMD_OPI_8READ, + offset, MX25_READ_DUMMY_CYCLES, + sizeof cmpbuf, cmpbuf); +#elif MX25_BUS_MODE == MX25_BUS_MODE_OPI_DTR + bus_cmd_addr_dummy_receive(devp->config->busp, MX25_CMD_OPI_8DTRD, + offset, MX25_READ_DUMMY_CYCLES, + sizeof cmpbuf, cmpbuf); +#endif +#else + /* Normal read command in SPI mode.*/ + bus_cmd_addr_receive(devp->config->busp, MX25_CMD_SPI_READ4B, + offset, sizeof cmpbuf, cmpbuf); +#endif + + /* Checking for erased state of current buffer.*/ + for (p = cmpbuf; p < &cmpbuf[MX25_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, sec; + + /* Read status register.*/ +#if MX25_BUS_MODE == MX25_BUS_MODE_SPI + bus_cmd_receive(devp->config->busp, MX25_CMD_SPI_RDSR, 1, &sts); +#else + bus_cmd_dummy_receive(devp->config->busp, MX25_CMD_OPI_RDSR, 1, &sts); +#endif + + /* Read security register.*/ +#if MX25_BUS_MODE == MX25_BUS_MODE_SPI + bus_cmd_receive(devp->config->busp, MX25_CMD_SPI_RDSCUR, 1, &sec); +#else + bus_cmd_dummy_receive(devp->config->busp, MX25_CMD_OPI_RDSCUR, 1, &sec); +#endif + + /* If the WIP bit is one (busy) or the flash in a suspended state then + report that the operation is still in progress.*/ + if (((sts & 1) != 0U) || ((sec & 8) != 0U)) { + + /* Recommended time before polling again, this is a simplified + implementation.*/ + if (msec != NULL) { + *msec = 1U; + } + + return FLASH_BUSY_ERASING; + } + + /* Checking for errors.*/ + if ((sec & MX25_FLAGS_ALL_ERRORS) != 0U) { + + /* 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; +} + +/** @} */ diff --git a/os/hal/lib/complex/serial_nor/devices/macronix_mx25/hal_flash_device.h b/os/hal/lib/complex/serial_nor/devices/macronix_mx25/hal_flash_device.h new file mode 100644 index 000000000..f4c8bece7 --- /dev/null +++ b/os/hal/lib/complex/serial_nor/devices/macronix_mx25/hal_flash_device.h @@ -0,0 +1,416 @@ +/* + 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 hal_flash_device.h + * @brief Macronix MX25 serial flash driver header. + * + * @addtogroup MACRONIX_MX25 + * @{ + */ + +#ifndef HAL_FLASH_DEVICE_H +#define HAL_FLASH_DEVICE_H + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Device capabilities + * @{ + */ +#define SNOR_DEVICE_SUPPORTS_XIP FALSE +/** @} */ + +/** + * @name Device identification + * @{ + */ +#define MX25_SUPPORTED_MANUFACTURE_IDS {0xC2} +#define MX25_SUPPORTED_MEMORY_TYPE_IDS {0x85} +/** @} */ + +/** + * @name Command codes, SPI mode + * @{ + */ +#define MX25_CMD_SPI_READ3B 0x03U +#define MX25_CMD_SPI_FAST_READ3B 0x0BU +#define MX25_CMD_SPI_PP3B 0x02U +#define MX25_CMD_SPI_SE3B 0x20U +#define MX25_CMD_SPI_BE3B 0xD8U +#define MX25_CMD_SPI_CE 0xC7U +#define MX25_CMD_SPI_READ4B 0x13U +#define MX25_CMD_SPI_FAST_READ4B 0x0CU +#define MX25_CMD_SPI_PP4B 0x12U +#define MX25_CMD_SPI_SE4B 0x21U +#define MX25_CMD_SPI_BE4B 0xDCU +#define MX25_CMD_SPI_WREN 0x06U +#define MX25_CMD_SPI_WRDI 0x04U +#define MX25_CMD_SPI_PE_SUSPEND 0xB0U +#define MX25_CMD_SPI_PE_RESUME 0x30U +#define MX25_CMD_SPI_DP 0xB9U +#define MX25_CMD_SPI_SBL 0xC0U +#define MX25_CMD_SPI_ENSO 0xB1U +#define MX25_CMD_SPI_EXSO 0xC1U +#define MX25_CMD_SPI_NOP 0x00U +#define MX25_CMD_SPI_RSTEN 0x66U +#define MX25_CMD_SPI_RST 0x99U +#define MX25_CMD_SPI_RDID 0x9FU +#define MX25_CMD_SPI_RDSFDP 0x5AU +#define MX25_CMD_SPI_RDSR 0x05U +#define MX25_CMD_SPI_RDCR 0x15U +#define MX25_CMD_SPI_WRSR 0x01U +#define MX25_CMD_SPI_RDCR2 0x71U +#define MX25_CMD_SPI_WRCR2 0x72U +#define MX25_CMD_SPI_RDFBR 0x16U +#define MX25_CMD_SPI_WRFBR 0x17U +#define MX25_CMD_SPI_ESFBR 0x18U +#define MX25_CMD_SPI_RDSCUR 0x2BU +#define MX25_CMD_SPI_WRSCUR 0x2FU +#define MX25_CMD_SPI_WRLR 0x2CU +#define MX25_CMD_SPI_RDLR 0x2DU +#define MX25_CMD_SPI_WRSPB 0xE3U +#define MX25_CMD_SPI_ESSPB 0xE4U +#define MX25_CMD_SPI_RDSPB 0xE2U +#define MX25_CMD_SPI_WRDPB 0xE1U +#define MX25_CMD_SPI_RDDPB 0xE0U +#define MX25_CMD_SPI_WPSEL 0x68U +#define MX25_CMD_SPI_GBLK 0x7EU +#define MX25_CMD_SPI_GBULK 0x98U +#define MX25_CMD_SPI_RDPASS 0x27U +#define MX25_CMD_SPI_WRPASS 0x28U +#define MX25_CMD_SPI_PASSULK 0x29U +/** @} */ + +/** + * @name Command codes, OPI mode + * @{ + */ +#define MX25_CMD_OPI_8READ 0xEC13U +#define MX25_CMD_OPI_8DTRD 0xEE11U +#define MX25_CMD_OPI_RDID 0x9F60U +#define MX25_CMD_OPI_RDSFDP 0x5AA5U +#define MX25_CMD_OPI_PP 0x12EDU +#define MX25_CMD_OPI_SE 0x21DEU +#define MX25_CMD_OPI_BE 0xDC23U +#define MX25_CMD_OPI_CE 0xC738U +#define MX25_CMD_OPI_WREN 0x06F9U +#define MX25_CMD_OPI_WRDI 0x04FBU +#define MX25_CMD_OPI_PE_SUSPEND 0xB04FU +#define MX25_CMD_OPI_PE_RESUME 0x30CFU +#define MX25_CMD_OPI_DP 0xB946U +#define MX25_CMD_OPI_SBL 0xC03FU +#define MX25_CMD_OPI_ENSO 0xB14EU +#define MX25_CMD_OPI_EXSO 0xC13EU +#define MX25_CMD_OPI_NOP 0x00FFU +#define MX25_CMD_OPI_RSTEN 0x6699U +#define MX25_CMD_OPI_RST 0x9966U +#define MX25_CMD_OPI_RDSR 0x05FAU +#define MX25_CMD_OPI_RDCR 0x15EAU +#define MX25_CMD_OPI_WRSR 0x01FEU +#define MX25_CMD_OPI_WRCR 0x01FEU +#define MX25_CMD_OPI_RDCR2 0x718EU +#define MX25_CMD_OPI_WRCR2 0x728DU +#define MX25_CMD_OPI_RDFBR 0x16E9U +#define MX25_CMD_OPI_WRFBR 0x17E8U +#define MX25_CMD_OPI_ESFBR 0x18E7U +#define MX25_CMD_OPI_RDSCUR 0x2BD4U +#define MX25_CMD_OPI_WRSCUR 0x2FD0U +#define MX25_CMD_OPI_WRLR 0x2CD3U +#define MX25_CMD_OPI_RDLR 0x2DD2U +#define MX25_CMD_OPI_WRSPB 0xE31CU +#define MX25_CMD_OPI_ESSPB 0xE41BU +#define MX25_CMD_OPI_RDSPB 0xE21DU +#define MX25_CMD_OPI_WRDPB 0xE11EU +#define MX25_CMD_OPI_RDDPB 0xE01FU +#define MX25_CMD_OPI_WPSEL 0x6897U +#define MX25_CMD_OPI_GBLK 0x7E81U +#define MX25_CMD_OPI_GBULK 0x9867U +#define MX25_CMD_OPI_RDPASS 0x27D8U +#define MX25_CMD_OPI_WRPASS 0x28D7U +#define MX25_CMD_OPI_PASSULK 0x29D6U +/** @} */ + +/** + * @name Flags status register bits + * @{ + */ +#define MX25_FLAGS_WPSEL 0x80U +#define MX25_FLAGS_E_FAIL 0x40U +#define MX25_FLAGS_P_FAIL 0x20U +#define MX25_FLAGS_ESB 0x08U +#define MX25_FLAGS_PSB 0x04U +#define MX25_FLAGS_LDSO 0x02U +#define MX25_FLAGS_SECURED_OTP 0x01U +#define MX25_FLAGS_ALL_ERRORS (MX25_FLAGS_E_FAIL | \ + MX25_FLAGS_P_FAIL) +/** @} */ + +/** + * @name Bus interface modes. + * @{ + */ +#define MX25_BUS_MODE_SPI 0U +#define MX25_BUS_MODE_OPI_STR 1U +#define MX25_BUS_MODE_OPI_DTR 2U +/** @} */ + +/*===========================================================================*/ +/* 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(MX25_SWITCH_WIDTH) || defined(__DOXYGEN__) +#define MX25_SWITCH_WIDTH TRUE +#endif + +/** + * @brief Device bus mode to be used. + * #note if @p MX25_SWITCH_WIDTH is @p FALSE then this is the bus mode + * that the device is expected to be using. + * #note if @p MX25_SWITCH_WIDTH is @p TRUE then this is the bus mode + * that the device will be switched in. + * @note This option is only valid in WSPI bus mode. + */ +#if !defined(MX25_BUS_MODE) || defined(__DOXYGEN__) +#define MX25_BUS_MODE MX25_BUS_MODE_SPI +#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(MX25_NICE_WAITING) || defined(__DOXYGEN__) +#define MX25_NICE_WAITING TRUE +#endif + +/** + * @brief Uses 4kB sub-sectors rather than 64kB sectors. + */ +#if !defined(MX25_USE_SUB_SECTORS) || defined(__DOXYGEN__) +#define MX25_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(MX25_COMPARE_BUFFER_SIZE) || defined(__DOXYGEN__) +#define MX25_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(MX25_READ_DUMMY_CYCLES) || defined(__DOXYGEN__) +#define MX25_READ_DUMMY_CYCLES 6 +#endif + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if (MX25_COMPARE_BUFFER_SIZE & (MX25_COMPARE_BUFFER_SIZE - 1)) != 0 +#error "invalid MX25_COMPARE_BUFFER_SIZE value" +#endif + +#if (MX25_READ_DUMMY_CYCLES < 6) || (MX25_READ_DUMMY_CYCLES > 20) || \ + ((MX25_READ_DUMMY_CYCLES & 1) != 0) +#error "invalid MX25_READ_DUMMY_CYCLES value (6, 8, 10, 12, 14, 16, 18, 20)" +#endif + +#if (SNOR_BUS_DRIVER == SNOR_BUS_DRIVER_SPI) && \ + (MX25_BUS_MODE != MX25_BUS_MODE_SPI) +#error "only MX25_BUS_MODE_SPI is allowed when using SPI driver" +#endif + +#if (MX25_BUS_MODE == MX25_BUS_MODE_OPI_DTR) || defined(__DOXYGEN__) +/** + * @brief WSPI settings for command only. + */ +#define SNOR_WSPI_CFG_CMD (WSPI_CFG_CMD_MODE_EIGHT_LINES | \ + WSPI_CFG_ADDR_MODE_NONE | \ + WSPI_CFG_ALT_MODE_NONE | \ + WSPI_CFG_DATA_MODE_NONE | \ + WSPI_CFG_CMD_SIZE_16 | \ + WSPI_CFG_ADDR_SIZE_32 | \ + WSPI_CFG_CMD_DDR) + +/** + * @brief WSPI settings for command and address. + */ +#define SNOR_WSPI_CFG_CMD_ADDR (WSPI_CFG_CMD_MODE_EIGHT_LINES | \ + WSPI_CFG_ADDR_MODE_EIGHT_LINES | \ + WSPI_CFG_ALT_MODE_NONE | \ + WSPI_CFG_DATA_MODE_NONE | \ + WSPI_CFG_CMD_SIZE_16 | \ + WSPI_CFG_ADDR_SIZE_32 | \ + WSPI_CFG_CMD_DDR | \ + WSPI_CFG_ADDR_DDR) + +/** + * @brief WSPI settings for command and data. + */ +#define SNOR_WSPI_CFG_CMD_DATA (WSPI_CFG_CMD_MODE_EIGHT_LINES | \ + WSPI_CFG_ADDR_MODE_NONE | \ + WSPI_CFG_ALT_MODE_NONE | \ + WSPI_CFG_DATA_MODE_EIGHT_LINES | \ + WSPI_CFG_CMD_SIZE_16 | \ + WSPI_CFG_ADDR_SIZE_32 | \ + WSPI_CFG_CMD_DDR | \ + WSPI_CFG_DATA_DDR) + +/** + * @brief WSPI settings for command, address and data. + */ +#define SNOR_WSPI_CFG_CMD_ADDR_DATA (WSPI_CFG_CMD_MODE_EIGHT_LINES | \ + WSPI_CFG_ADDR_MODE_EIGHT_LINES | \ + WSPI_CFG_ALT_MODE_NONE | \ + WSPI_CFG_DATA_MODE_EIGHT_LINES | \ + WSPI_CFG_CMD_SIZE_16 | \ + WSPI_CFG_ADDR_SIZE_32 | \ + WSPI_CFG_CMD_DDR | \ + WSPI_CFG_ADDR_DDR | \ + WSPI_CFG_DATA_DDR) + +#elif MX25_BUS_MODE == MX25_BUS_MODE_OPI_STR +#define SNOR_WSPI_CFG_CMD (WSPI_CFG_CMD_MODE_EIGHT_LINES | \ + WSPI_CFG_ADDR_MODE_NONE | \ + WSPI_CFG_ALT_MODE_NONE | \ + WSPI_CFG_DATA_MODE_NONE | \ + WSPI_CFG_CMD_SIZE_16 | \ + WSPI_CFG_ADDR_SIZE_32) + +#define SNOR_WSPI_CFG_CMD_ADDR (WSPI_CFG_CMD_MODE_EIGHT_LINES | \ + WSPI_CFG_ADDR_MODE_EIGHT_LINES | \ + WSPI_CFG_ALT_MODE_NONE | \ + WSPI_CFG_DATA_MODE_NONE | \ + WSPI_CFG_CMD_SIZE_16 | \ + WSPI_CFG_ADDR_SIZE_32) + +#define SNOR_WSPI_CFG_CMD_DATA (WSPI_CFG_CMD_MODE_EIGHT_LINES | \ + WSPI_CFG_ADDR_MODE_NONE | \ + WSPI_CFG_ALT_MODE_NONE | \ + WSPI_CFG_DATA_MODE_EIGHT_LINES | \ + WSPI_CFG_CMD_SIZE_16 | \ + WSPI_CFG_ADDR_SIZE_32) + +#define SNOR_WSPI_CFG_CMD_ADDR_DATA (WSPI_CFG_CMD_MODE_EIGHT_LINES | \ + WSPI_CFG_ADDR_MODE_EIGHT_LINES | \ + WSPI_CFG_ALT_MODE_NONE | \ + WSPI_CFG_DATA_MODE_EIGHT_LINES | \ + WSPI_CFG_CMD_SIZE_16 | \ + WSPI_CFG_ADDR_SIZE_32) + +#elif MX25_BUS_MODE == MX25_BUS_MODE_SPI +#define SNOR_WSPI_CFG_CMD (WSPI_CFG_CMD_MODE_ONE_LINE | \ + WSPI_CFG_ADDR_MODE_NONE | \ + WSPI_CFG_ALT_MODE_NONE | \ + WSPI_CFG_DATA_MODE_NONE | \ + WSPI_CFG_CMD_SIZE_8 | \ + WSPI_CFG_ADDR_SIZE_32) + +#define SNOR_WSPI_CFG_CMD_ADDR (WSPI_CFG_CMD_MODE_ONE_LINE | \ + WSPI_CFG_ADDR_MODE_ONE_LINE | \ + WSPI_CFG_ALT_MODE_NONE | \ + WSPI_CFG_DATA_MODE_NONE | \ + WSPI_CFG_CMD_SIZE_8 | \ + WSPI_CFG_ADDR_SIZE_32) + +#define SNOR_WSPI_CFG_CMD_DATA (WSPI_CFG_CMD_MODE_ONE_LINE | \ + WSPI_CFG_ADDR_MODE_NONE | \ + WSPI_CFG_ALT_MODE_NONE | \ + WSPI_CFG_DATA_MODE_ONE_LINE | \ + WSPI_CFG_CMD_SIZE_8 | \ + WSPI_CFG_ADDR_SIZE_32) + +#define SNOR_WSPI_CFG_CMD_ADDR_DATA (WSPI_CFG_CMD_MODE_ONE_LINE | \ + WSPI_CFG_ADDR_MODE_ONE_LINE | \ + WSPI_CFG_ALT_MODE_NONE | \ + WSPI_CFG_DATA_MODE_ONE_LINE | \ + WSPI_CFG_CMD_SIZE_8 | \ + WSPI_CFG_ADDR_SIZE_32) + +#else +#error "invalid MX25_BUS_MODE setting" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) +extern flash_descriptor_t snor_descriptor; +#endif + +#if (SNOR_BUS_DRIVER == SNOR_BUS_DRIVER_WSPI) && (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_DRIVER == SNOR_BUS_DRIVER_WSPI) && \ + (SNOR_DEVICE_SUPPORTS_XIP == TRUE) + 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/macronix_mx25/hal_flash_device.mk b/os/hal/lib/complex/serial_nor/devices/macronix_mx25/hal_flash_device.mk new file mode 100644 index 000000000..94b565921 --- /dev/null +++ b/os/hal/lib/complex/serial_nor/devices/macronix_mx25/hal_flash_device.mk @@ -0,0 +1,13 @@ +# List of all the Micron N25Q device files. +SERNORSRC := $(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/macronix_mx25/hal_flash_device.c + +# Required include directories +SERNORINC := $(CHIBIOS)/os/hal/lib/peripherals/flash \ + $(CHIBIOS)/os/hal/lib/complex/serial_nor \ + $(CHIBIOS)/os/hal/lib/complex/serial_nor/devices/macronix_mx25 + +# Shared variables +ALLCSRC += $(SERNORSRC) +ALLINC += $(SERNORINC) 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 index 6242a91ba..0754d6e51 100644 --- 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 @@ -19,7 +19,6 @@ * @brief Micron N25Q serial flash driver code. * * @addtogroup MICRON_N25Q - * @ingroup MICRON_N25Q * @{ */ 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 index 1cb77f932..dfe4a351f 100644 --- 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 @@ -19,7 +19,6 @@ * @brief Micron N25Q serial flash driver header. * * @addtogroup MICRON_N25Q - * @ingroup MICRON_N25Q * @{ */ @@ -30,6 +29,13 @@ /* Driver constants. */ /*===========================================================================*/ +/** + * @name Device capabilities + * @{ + */ +#define SNOR_DEVICE_SUPPORTS_XIP TRUE +/** @} */ + /** * @name Device identification * @{ @@ -181,100 +187,100 @@ /** * @brief WSPI settings for command only. */ -#define SNOR_WSPI_CFG_CMD (WSPI_CFG_CMD_MODE_FOUR_LINES | \ - WSPI_CFG_ADDR_MODE_NONE | \ - WSPI_CFG_ALT_MODE_NONE | \ - WSPI_CFG_DATA_MODE_NONE | \ - WSPI_CFG_CMD_SIZE_8 | \ - WSPI_CFG_ADDR_SIZE_24) +#define SNOR_WSPI_CFG_CMD (WSPI_CFG_CMD_MODE_FOUR_LINES | \ + WSPI_CFG_ADDR_MODE_NONE | \ + WSPI_CFG_ALT_MODE_NONE | \ + WSPI_CFG_DATA_MODE_NONE | \ + WSPI_CFG_CMD_SIZE_8 | \ + WSPI_CFG_ADDR_SIZE_24) /** * @brief WSPI settings for command and address. */ -#define SNOR_WSPI_CFG_CMD_ADDR (WSPI_CFG_CMD_MODE_FOUR_LINES | \ - WSPI_CFG_ADDR_MODE_FOUR_LINES| \ - WSPI_CFG_ALT_MODE_NONE | \ - WSPI_CFG_DATA_MODE_NONE | \ - WSPI_CFG_CMD_SIZE_8 | \ - WSPI_CFG_ADDR_SIZE_24) +#define SNOR_WSPI_CFG_CMD_ADDR (WSPI_CFG_CMD_MODE_FOUR_LINES | \ + WSPI_CFG_ADDR_MODE_FOUR_LINES | \ + WSPI_CFG_ALT_MODE_NONE | \ + WSPI_CFG_DATA_MODE_NONE | \ + WSPI_CFG_CMD_SIZE_8 | \ + WSPI_CFG_ADDR_SIZE_24) /** * @brief WSPI settings for command and data. */ -#define SNOR_WSPI_CFG_CMD_DATA (WSPI_CFG_CMD_MODE_FOUR_LINES | \ - WSPI_CFG_ADDR_MODE_NONE | \ - WSPI_CFG_ALT_MODE_NONE | \ - WSPI_CFG_DATA_MODE_FOUR_LINES| \ - WSPI_CFG_CMD_SIZE_8 | \ - WSPI_CFG_ADDR_SIZE_24) +#define SNOR_WSPI_CFG_CMD_DATA (WSPI_CFG_CMD_MODE_FOUR_LINES | \ + WSPI_CFG_ADDR_MODE_NONE | \ + WSPI_CFG_ALT_MODE_NONE | \ + WSPI_CFG_DATA_MODE_FOUR_LINES | \ + WSPI_CFG_CMD_SIZE_8 | \ + WSPI_CFG_ADDR_SIZE_24) /** * @brief WSPI settings for command, address and data. */ -#define SNOR_WSPI_CFG_CMD_ADDR_DATA (WSPI_CFG_CMD_MODE_FOUR_LINES | \ - WSPI_CFG_ADDR_MODE_FOUR_LINES| \ - WSPI_CFG_ALT_MODE_NONE | \ - WSPI_CFG_DATA_MODE_FOUR_LINES| \ - WSPI_CFG_CMD_SIZE_8 | \ - WSPI_CFG_ADDR_SIZE_24) +#define SNOR_WSPI_CFG_CMD_ADDR_DATA (WSPI_CFG_CMD_MODE_FOUR_LINES | \ + WSPI_CFG_ADDR_MODE_FOUR_LINES | \ + WSPI_CFG_ALT_MODE_NONE | \ + WSPI_CFG_DATA_MODE_FOUR_LINES | \ + WSPI_CFG_CMD_SIZE_8 | \ + WSPI_CFG_ADDR_SIZE_24) #elif N25Q_BUS_MODE == N25Q_BUS_MODE_WSPI2L -#define SNOR_WSPI_CFG_CMD (WSPI_CFG_CMD_MODE_TWO_LINES | \ - WSPI_CFG_ADDR_MODE_NONE | \ - WSPI_CFG_ALT_MODE_NONE | \ - WSPI_CFG_DATA_MODE_NONE | \ - WSPI_CFG_CMD_SIZE_8 | \ - WSPI_CFG_ADDR_SIZE_24) - -#define SNOR_WSPI_CFG_CMD_ADDR (WSPI_CFG_CMD_MODE_TWO_LINES | \ - WSPI_CFG_ADDR_MODE_TWO_LINES | \ - WSPI_CFG_ALT_MODE_NONE | \ - WSPI_CFG_DATA_MODE_NONE | \ - WSPI_CFG_CMD_SIZE_8 | \ - WSPI_CFG_ADDR_SIZE_24) - -#define SNOR_WSPI_CFG_CMD_DATA (WSPI_CFG_CMD_MODE_TWO_LINES | \ - WSPI_CFG_ADDR_MODE_NONE | \ - WSPI_CFG_ALT_MODE_NONE | \ - WSPI_CFG_DATA_MODE_TWO_LINES | \ - WSPI_CFG_CMD_SIZE_8 | \ - WSPI_CFG_ADDR_SIZE_24) - -#define SNOR_WSPI_CFG_CMD_ADDR_DATA (WSPI_CFG_CMD_MODE_ONE_LINE | \ - WSPI_CFG_ADDR_MODE_ONE_LINE | \ - WSPI_CFG_ALT_MODE_NONE | \ - WSPI_CFG_DATA_MODE_ONE_LINE | \ - WSPI_CFG_CMD_SIZE_8 | \ - WSPI_CFG_ADDR_SIZE_24) +#define SNOR_WSPI_CFG_CMD (WSPI_CFG_CMD_MODE_TWO_LINES | \ + WSPI_CFG_ADDR_MODE_NONE | \ + WSPI_CFG_ALT_MODE_NONE | \ + WSPI_CFG_DATA_MODE_NONE | \ + WSPI_CFG_CMD_SIZE_8 | \ + WSPI_CFG_ADDR_SIZE_24) + +#define SNOR_WSPI_CFG_CMD_ADDR (WSPI_CFG_CMD_MODE_TWO_LINES | \ + WSPI_CFG_ADDR_MODE_TWO_LINES | \ + WSPI_CFG_ALT_MODE_NONE | \ + WSPI_CFG_DATA_MODE_NONE | \ + WSPI_CFG_CMD_SIZE_8 | \ + WSPI_CFG_ADDR_SIZE_24) + +#define SNOR_WSPI_CFG_CMD_DATA (WSPI_CFG_CMD_MODE_TWO_LINES | \ + WSPI_CFG_ADDR_MODE_NONE | \ + WSPI_CFG_ALT_MODE_NONE | \ + WSPI_CFG_DATA_MODE_TWO_LINES | \ + WSPI_CFG_CMD_SIZE_8 | \ + WSPI_CFG_ADDR_SIZE_24) + +#define SNOR_WSPI_CFG_CMD_ADDR_DATA (WSPI_CFG_CMD_MODE_ONE_LINE | \ + WSPI_CFG_ADDR_MODE_ONE_LINE | \ + WSPI_CFG_ALT_MODE_NONE | \ + WSPI_CFG_DATA_MODE_ONE_LINE | \ + WSPI_CFG_CMD_SIZE_8 | \ + WSPI_CFG_ADDR_SIZE_24) #elif N25Q_BUS_MODE == N25Q_BUS_MODE_WSPI1L -#define SNOR_WSPI_CFG_CMD (WSPI_CFG_CMD_MODE_ONE_LINE | \ - WSPI_CFG_ADDR_MODE_NONE | \ - WSPI_CFG_ALT_MODE_NONE | \ - WSPI_CFG_DATA_MODE_NONE | \ - WSPI_CFG_CMD_SIZE_8 | \ - WSPI_CFG_ADDR_SIZE_24) - -#define SNOR_WSPI_CFG_CMD_ADDR (WSPI_CFG_CMD_MODE_ONE_LINE | \ - WSPI_CFG_ADDR_MODE_ONE_LINE | \ - WSPI_CFG_ALT_MODE_NONE | \ - WSPI_CFG_DATA_MODE_NONE | \ - WSPI_CFG_CMD_SIZE_8 | \ - WSPI_CFG_ADDR_SIZE_24) - -#define SNOR_WSPI_CFG_CMD_DATA (WSPI_CFG_CMD_MODE_ONE_LINE | \ - WSPI_CFG_ADDR_MODE_NONE | \ - WSPI_CFG_ALT_MODE_NONE | \ - WSPI_CFG_DATA_MODE_ONE_LINE | \ - WSPI_CFG_CMD_SIZE_8 | \ - WSPI_CFG_ADDR_SIZE_24) - -#define SNOR_WSPI_CFG_CMD_ADDR_DATA (WSPI_CFG_CMD_MODE_ONE_LINE | \ - WSPI_CFG_ADDR_MODE_ONE_LINE | \ - WSPI_CFG_ALT_MODE_NONE | \ - WSPI_CFG_DATA_MODE_ONE_LINE | \ - WSPI_CFG_CMD_SIZE_8 | \ - WSPI_CFG_ADDR_SIZE_24) +#define SNOR_WSPI_CFG_CMD (WSPI_CFG_CMD_MODE_ONE_LINE | \ + WSPI_CFG_ADDR_MODE_NONE | \ + WSPI_CFG_ALT_MODE_NONE | \ + WSPI_CFG_DATA_MODE_NONE | \ + WSPI_CFG_CMD_SIZE_8 | \ + WSPI_CFG_ADDR_SIZE_24) + +#define SNOR_WSPI_CFG_CMD_ADDR (WSPI_CFG_CMD_MODE_ONE_LINE | \ + WSPI_CFG_ADDR_MODE_ONE_LINE | \ + WSPI_CFG_ALT_MODE_NONE | \ + WSPI_CFG_DATA_MODE_NONE | \ + WSPI_CFG_CMD_SIZE_8 | \ + WSPI_CFG_ADDR_SIZE_24) + +#define SNOR_WSPI_CFG_CMD_DATA (WSPI_CFG_CMD_MODE_ONE_LINE | \ + WSPI_CFG_ADDR_MODE_NONE | \ + WSPI_CFG_ALT_MODE_NONE | \ + WSPI_CFG_DATA_MODE_ONE_LINE | \ + WSPI_CFG_CMD_SIZE_8 | \ + WSPI_CFG_ADDR_SIZE_24) + +#define SNOR_WSPI_CFG_CMD_ADDR_DATA (WSPI_CFG_CMD_MODE_ONE_LINE | \ + WSPI_CFG_ADDR_MODE_ONE_LINE | \ + WSPI_CFG_ALT_MODE_NONE | \ + WSPI_CFG_DATA_MODE_ONE_LINE | \ + WSPI_CFG_CMD_SIZE_8 | \ + WSPI_CFG_ADDR_SIZE_24) #else #error "invalid N25Q_BUS_MODE setting" @@ -317,7 +323,8 @@ extern "C" { 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_DRIVER == SNOR_BUS_DRIVER_WSPI +#if (SNOR_BUS_DRIVER == SNOR_BUS_DRIVER_WSPI) && \ + (SNOR_DEVICE_SUPPORTS_XIP == TRUE) void snor_activate_xip(SNORDriver *devp); void snor_reset_xip(SNORDriver *devp); #endif diff --git a/os/hal/lib/complex/serial_nor/hal_serial_nor.c b/os/hal/lib/complex/serial_nor/hal_serial_nor.c index 417b52614..8ab1e3574 100644 --- a/os/hal/lib/complex/serial_nor/hal_serial_nor.c +++ b/os/hal/lib/complex/serial_nor/hal_serial_nor.c @@ -19,7 +19,6 @@ * @brief Serial NOR serial flash driver code. * * @addtogroup HAL_SERIAL_NOR - * @ingroup HAL_SERIAL_NOR * @{ */ @@ -564,6 +563,33 @@ void bus_cmd_addr_receive(BUSDriver *busp, } #if (SNOR_BUS_DRIVER == SNOR_BUS_DRIVER_WSPI) || defined(__DOXYGEN__) +/** + * @brief Sends a command followed by dummy cycles and a + * data receive phase. + * + * @param[in] busp pointer to the bus driver + * @param[in] cmd instruction code + * @param[in] dummy number of dummy cycles + * @param[in] n number of bytes to receive + * @param[out] p data buffer + * + * @notapi + */ +void bus_cmd_dummy_receive(BUSDriver *busp, + uint32_t cmd, + uint32_t dummy, + size_t n, + uint8_t *p) { + wspi_command_t mode; + + mode.cmd = cmd; + mode.cfg = SNOR_WSPI_CFG_CMD_ADDR_DATA; + mode.addr = 0U; + mode.alt = 0U; + mode.dummy = dummy; + wspiReceive(busp, &mode, n, p); +} + /** * @brief Sends a command followed by a flash address, dummy cycles and a * data receive phase. @@ -691,8 +717,10 @@ void snorMemoryMap(SNORDriver *devp, uint8_t **addrp) { /* Bus acquisition.*/ bus_acquire(devp->config->busp, devp->config->buscfg); +#if SNOR_DEVICE_SUPPORTS_XIP == TRUE /* Activating XIP mode in the device.*/ snor_activate_xip(devp); +#endif /* Starting WSPI memory mapped mode.*/ wspiMapFlash(devp->config->busp, &snor_memmap_read, addrp); @@ -716,7 +744,9 @@ void snorMemoryUnmap(SNORDriver *devp) { /* Stopping WSPI memory mapped mode.*/ wspiUnmapFlash(devp->config->busp); +#if SNOR_DEVICE_SUPPORTS_XIP == TRUE snor_reset_xip(devp); +#endif /* Bus release.*/ bus_release(devp->config->busp); diff --git a/os/hal/lib/complex/serial_nor/hal_serial_nor.h b/os/hal/lib/complex/serial_nor/hal_serial_nor.h index cb2451a6b..81c66f0c9 100644 --- a/os/hal/lib/complex/serial_nor/hal_serial_nor.h +++ b/os/hal/lib/complex/serial_nor/hal_serial_nor.h @@ -19,7 +19,6 @@ * @brief Serial NOR driver header. * * @addtogroup SERIAL_NOR - * @ingroup SERIAL_NOR * @{ */ @@ -169,12 +168,19 @@ extern "C" { flash_offset_t offset, size_t n, uint8_t *p); +#if (SNOR_BUS_DRIVER == SNOR_BUS_DRIVER_WSPI) || defined(__DOXYGEN__) + void bus_cmd_dummy_receive(BUSDriver *busp, + uint32_t cmd, + uint32_t dummy, + 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); +#endif void snorObjectInit(SNORDriver *devp); void snorStart(SNORDriver *devp, const SNORConfig *config); void snorStop(SNORDriver *devp); -- cgit v1.2.3