/** * \file * * \brief N25Q256A component implement * * Copyright (c) 2018 Microchip Technology Inc. and its subsidiaries. * * \asf_license_start * * \page License * * Subject to your compliance with these terms, you may use Microchip * software and any derivatives exclusively with Microchip products. * It is your responsibility to comply with third party license terms applicable * to your use of third party software (including open source software) that * may accompany Microchip software. * * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. * * \asf_license_stop * */ /* * Support and FAQ: visit Microchip Support */ #include #include #include "spi_nor_flash.h" #include "n25q256a.h" #include "driver_init.h" /** Register addresses of n25q256a */ /** Resume from deep power-down command code. */ #define N25Q_SOFT_RESET_ENABLE 0x66 /** Resume from deep power-down command code. */ #define N25Q_SOFT_RESET 0x99 /** Read status register command code. */ #define N25Q_READ_STATUS_REGISTER 0x05 /** Write status register command code. */ #define N25Q_WRITE_STATUS_REGISTER 0x01 /** Read status register command code. */ #define N25Q_READ_FLAG_STATUS_REGISTER 0x70 /** Write volatile config register command code. */ #define N25Q_WRITE_VOLATILE_CONFIG_REGISTER 0x81 /** Read volatile config register command code. */ #define N25Q_READ_VOLATILE_CONFIG_REGISTER 0x85 /** Write enhanced volatile config register command code. */ #define N25Q_WRITE_ENHANCED_VOLATILE_CONFIG_REGISTER 0x61 /** Read enhanced volatile config register command code. */ #define N25Q_READ_ENHANCED_VOLATILE_CONFIG_REGISTER 0x65 /** Write enable command code. */ #define N25Q_WRITE_ENABLE 0x06 /** Write disable command code. */ #define N25Q_WRITE_DISABLE 0x04 /** Byte/page program command code. */ #define N25Q_BYTE_PAGE_PROGRAM 0x02 /** Byte/page program command code. */ #define N25Q_QUAD_INPUT_PROGRAM 0x32 /** Block erase command code (4K block). */ #define N25Q_BLOCK_ERASE_4K 0x20 /** Block erase command code (64K block). */ #define N25Q_BLOCK_ERASE_64K 0xD8 /** Chip erase command code 2. */ #define N25Q_BULK_ERASE 0xC7 /** Read array (low frequency) command code. */ #define N25Q_READ_ARRAY_LF 0x03 /** Read array command code. */ #define N25Q_FAST_READ 0x0B /** Fast Read array command code. */ #define N25Q_DUAL_OUTPUT_READ 0x3B /** Fast Read array command code. */ #define N25Q_QUAD_OUTPUT_READ 0x6B /** Fast Read array command code. */ #define N25Q_DUAL_IO_FAST_READ 0xBB /** Fast Read array command code. */ #define N25Q_QUAD_I0_FAST_READ 0xEB /** Read manufacturer and device ID command code. */ #define N25Q_READ_JEDEC_ID 0x9F /** Size of n25q256a reg */ #define N25Q_RD_REG_SIZE(op) (1) #define N25Q_WR_REG_SIZE(op) (1) /** Size of n25q256a */ #define N25Q_PAGE_SIZE 256 #define N25Q_SECTOR_SIZE 4096 #define N25Q_BLOCK_SIZE 65536 #define N25Q_FLASH_SIZE 0x200000 /** wait here for CS to go high */ void wait_cs_is_low() { while (!gpio_get_pin_level(FLASH_CS)) ; } /** N25Q256A spi nor flash's interface */ static const struct spi_nor_flash_interface n25q256a_interface = { n25q256a_read, n25q256a_write, n25q256a_erase, n25q256a_enable_xip, n25q256a_disable_xip, }; int32_t n25q256a_xip_confirm(const struct spi_nor_flash *const me, const bool on_off) { uint8_t dummy; struct n25q256a * n25q = (struct n25q256a *)me; struct qspi_dma_descriptor *descr = (struct qspi_dma_descriptor *)(me->io); struct _qspi_command cmd = {.inst_frame.bits.width = n25q->quad_mode ? QSPI_INST4_ADDR4_DATA4 : QSPI_INST1_ADDR1_DATA1, .inst_frame.bits.inst_en = 1, .inst_frame.bits.data_en = 1, .inst_frame.bits.addr_en = 1, .inst_frame.bits.opt_en = 1, .inst_frame.bits.opt_len = QSPI_OPT_8BIT, .inst_frame.bits.dummy_cycles = n25q->quad_mode ? 8 : 0, .inst_frame.bits.tfr_type = QSPI_READMEM_ACCESS, .instruction = N25Q_FAST_READ, .option = on_off ? 0x00 : 0xFF, .address = 0, .buf_len = 1, .rx_buf = &dummy}; qspi_dma_serial_run_command(descr, &cmd); n25q->xip_mode = on_off ? 2 : 1; return ERR_NONE; } uint32_t n25q256a_read_reg(const struct spi_nor_flash *const me, uint8_t width, uint8_t inst) { uint32_t status = 0; struct n25q256a * n25q = (struct n25q256a *)me; struct qspi_dma_descriptor *descr = (struct qspi_dma_descriptor *)(me->io); struct _qspi_command cmd = {.inst_frame.bits.width = width, .inst_frame.bits.inst_en = 1, .inst_frame.bits.data_en = 1, .inst_frame.bits.tfr_type = QSPI_READ_ACCESS, .instruction = inst, .buf_len = N25Q_RD_REG_SIZE(inst), .rx_buf = &status}; if (n25q->xip_mode) { n25q256a_xip_confirm(me, false); } qspi_dma_serial_run_command(descr, &cmd); if (n25q->xip_mode) { n25q256a_xip_confirm(me, true); } return status; } void n25q256a_write_reg(const struct spi_nor_flash *const me, uint8_t width, uint8_t inst, uint32_t data) { struct n25q256a * n25q = (struct n25q256a *)me; struct qspi_dma_descriptor *descr = (struct qspi_dma_descriptor *)(me->io); struct _qspi_command cmd = {.inst_frame.bits.width = width, .inst_frame.bits.inst_en = 1, .inst_frame.bits.data_en = 1, .inst_frame.bits.tfr_type = QSPI_WRITE_ACCESS, .instruction = inst, .buf_len = N25Q_WR_REG_SIZE(inst), .tx_buf = &data}; if (n25q->xip_mode) { n25q256a_xip_confirm(me, false); } qspi_dma_serial_run_command(descr, &cmd); if (n25q->xip_mode) { n25q256a_xip_confirm(me, true); } } void n25q256a_write_enable(const struct spi_nor_flash *const me, uint8_t width, bool en) { uint8_t status; struct qspi_dma_descriptor *descr = (struct qspi_dma_descriptor *)(me->io); uint8_t inst = (en == true ? N25Q_WRITE_ENABLE : N25Q_WRITE_DISABLE); struct _qspi_command cmd_en = {.inst_frame.bits.width = width, .inst_frame.bits.inst_en = 1, .instruction = inst}; struct _qspi_command cmd_st = {.inst_frame.bits.width = width, .inst_frame.bits.inst_en = 1, .inst_frame.bits.data_en = 1, .inst_frame.bits.tfr_type = QSPI_READ_ACCESS, .instruction = N25Q_READ_STATUS_REGISTER, .buf_len = 1, .rx_buf = &status}; do { qspi_dma_serial_run_command(descr, &cmd_en); qspi_dma_serial_run_command(descr, &cmd_st); } while ((status & (1 << 1)) == 0); } void n25q256a_switch_mode(const struct spi_nor_flash *const me, uint8_t mode) { struct n25q256a *n25q = (struct n25q256a *)me; uint8_t width = n25q->quad_mode ? QSPI_INST4_ADDR4_DATA4 : QSPI_INST1_ADDR1_DATA1; uint32_t evcfg = n25q256a_read_reg(me, width, N25Q_READ_ENHANCED_VOLATILE_CONFIG_REGISTER); uint8_t modify = 0; if (n25q->quad_mode == mode) { return; } if (mode) { if (evcfg & 0x80) { evcfg &= 0x1F; modify = 1; } } else { if (!(evcfg & 0x80)) { evcfg |= 0xC0; modify = 1; } } if (modify) { n25q->quad_mode = mode; n25q256a_write_enable(me, width, true); n25q256a_write_reg(me, width, N25Q_WRITE_ENHANCED_VOLATILE_CONFIG_REGISTER, evcfg); width = mode ? QSPI_INST4_ADDR4_DATA4 : QSPI_INST1_ADDR1_DATA1; evcfg = n25q256a_read_reg(me, width, N25Q_READ_ENHANCED_VOLATILE_CONFIG_REGISTER); n25q->quad_mode = mode; } } /** * \brief Construct n25q256a spi nor flash */ struct spi_nor_flash *n25q256a_construct(struct spi_nor_flash *const me, void *const io, func pin_exit_xip, const uint8_t quad_mode) { struct n25q256a *n25q = (struct n25q256a *)me; spi_nor_flash_construct(me, io, &n25q256a_interface); n25q->quad_mode = 0; n25q->xip_mode = false; n25q->pin_exit_xip = pin_exit_xip; n25q256a_switch_mode(me, quad_mode); return me; } int32_t n25q256a_read(const struct spi_nor_flash *const me, uint8_t *buf, uint32_t address, uint32_t length) { struct n25q256a * n25q = (struct n25q256a *)me; struct qspi_dma_descriptor *descr = (struct qspi_dma_descriptor *)(me->io); struct _qspi_command cmd = { .inst_frame.bits.width = n25q->quad_mode ? QSPI_INST4_ADDR4_DATA4 : QSPI_INST1_ADDR1_DATA1, .inst_frame.bits.inst_en = 1, .inst_frame.bits.data_en = 1, .inst_frame.bits.addr_en = 1, .inst_frame.bits.dummy_cycles = n25q->quad_mode ? 10 : 8, .inst_frame.bits.tfr_type = QSPI_READMEM_ACCESS, .instruction = N25Q_FAST_READ, .address = address, .buf_len = length, .rx_buf = buf, }; qspi_dma_serial_run_command(descr, &cmd); return ERR_NONE; } int32_t n25q256a_write(const struct spi_nor_flash *const me, uint8_t *buf, uint32_t address, uint32_t length) { struct n25q256a * n25q = (struct n25q256a *)me; struct qspi_dma_descriptor *descr = (struct qspi_dma_descriptor *)(me->io); struct _qspi_command cmd = { .inst_frame.bits.inst_en = 1, .inst_frame.bits.data_en = 1, .inst_frame.bits.addr_en = 1, .inst_frame.bits.tfr_type = QSPI_WRITEMEM_ACCESS, .instruction = N25Q_BYTE_PAGE_PROGRAM, /* Command is for all modes */ .address = address, .buf_len = length, .tx_buf = buf, }; /* Command, address, data width are different for different modes */ cmd.inst_frame.bits.width = n25q->quad_mode ? QSPI_INST4_ADDR4_DATA4 : QSPI_INST1_ADDR1_DATA1; while (length) { cmd.address = address; if (length <= N25Q_PAGE_SIZE) { cmd.buf_len = length; } else { cmd.buf_len = N25Q_PAGE_SIZE; } /* PROGRAM commands are initiated by first executing the * WRITE ENABLE command to set the write enable latch bit to 1. */ n25q256a_write_enable(me, cmd.inst_frame.bits.width, true); /* Send PROGRAM command */ qspi_dma_serial_run_command(descr, &cmd); /* wait here to complete the page write. * check the CS line status. if CS is low then wait for CS go to high */ wait_cs_is_low(); while (!(n25q256a_read_reg(me, cmd.inst_frame.bits.width, N25Q_READ_FLAG_STATUS_REGISTER) & (1 << 7))) ; cmd.tx_buf += cmd.buf_len; length -= cmd.buf_len; address += cmd.buf_len; } if (n25q->xip_mode) { n25q256a_xip_confirm(me, true); } return ERR_NONE; } int32_t n25q256a_erase(const struct spi_nor_flash *const me, uint32_t address, uint32_t length) { struct n25q256a * n25q = (struct n25q256a *)me; struct qspi_dma_descriptor *descr = (struct qspi_dma_descriptor *)(me->io); struct _qspi_command cmd = { .inst_frame.bits.width = n25q->quad_mode ? QSPI_INST4_ADDR4_DATA4 : QSPI_INST1_ADDR1_DATA1, .inst_frame.bits.inst_en = 1, .inst_frame.bits.addr_en = (length < N25Q_FLASH_SIZE) ? 1 : 0, .inst_frame.bits.tfr_type = QSPI_WRITE_ACCESS, }; uint32_t temp_addr = address; uint32_t temp_len = length; int32_t rc = ERR_NONE; if ((length % N25Q_SECTOR_SIZE) || (address % N25Q_SECTOR_SIZE)) { return ERR_INVALID_ARG; } if (length >= N25Q_FLASH_SIZE) { cmd.instruction = N25Q_BULK_ERASE; /* WRITE ENABLE command must be issued to * set the write enable latch bit to 1 */ n25q256a_write_enable(me, cmd.inst_frame.bits.width, true); /* Send specific erase command */ qspi_dma_serial_run_command(descr, &cmd); } else { while (temp_len > 0) { if (((temp_addr % N25Q_BLOCK_SIZE) == 0) && (temp_len >= N25Q_BLOCK_SIZE)) { cmd.address = temp_addr; cmd.instruction = N25Q_BLOCK_ERASE_64K; /* WRITE ENABLE command must be issued to * set the write enable latch bit to 1 */ n25q256a_write_enable(me, cmd.inst_frame.bits.width, true); /* Send specific erase command */ qspi_dma_serial_run_command(descr, &cmd); temp_addr += N25Q_BLOCK_SIZE; temp_len -= N25Q_BLOCK_SIZE; } else if (temp_len >= N25Q_SECTOR_SIZE) { cmd.address = temp_addr; cmd.instruction = N25Q_BLOCK_ERASE_4K; /* WRITE ENABLE command must be issued to * set the write enable latch bit to 1 */ n25q256a_write_enable(me, cmd.inst_frame.bits.width, true); /* Send specific erase command */ qspi_dma_serial_run_command(descr, &cmd); temp_addr += N25Q_SECTOR_SIZE; temp_len -= N25Q_SECTOR_SIZE; } else { rc = ERR_INVALID_ARG; break; } /* When the operation is in progress, * the write in progress bit is set. * The write enable latch bit is cleared. * The flag status register is polled for the operation status. */ while (!(n25q256a_read_reg(me, cmd.inst_frame.bits.width, N25Q_READ_FLAG_STATUS_REGISTER) & (1 << 7))) ; } } /* The flag status register is polled for the final operation status. */ while (!(n25q256a_read_reg(me, cmd.inst_frame.bits.width, N25Q_READ_FLAG_STATUS_REGISTER) & (1 << 7))) ; if (n25q->xip_mode) { n25q256a_xip_confirm(me, true); } return rc; } int32_t n25q256a_enable_xip(const struct spi_nor_flash *const me) { struct n25q256a *n25q = (struct n25q256a *)me; uint8_t width = n25q->quad_mode ? QSPI_INST4_ADDR4_DATA4 : QSPI_INST1_ADDR1_DATA1; if (!n25q->xip_mode) { uint8_t vcfg = n25q256a_read_reg(me, width, N25Q_READ_VOLATILE_CONFIG_REGISTER); if (vcfg & (1u << 3)) { vcfg &= ~(1u << 3); n25q256a_write_reg(me, width, N25Q_WRITE_VOLATILE_CONFIG_REGISTER, vcfg); while (!(n25q256a_read_reg(me, width, N25Q_READ_FLAG_STATUS_REGISTER) & (1 << 7))) ; } n25q->xip_mode = 1; n25q256a_xip_confirm(me, true); } return ERR_NONE; } int32_t n25q256a_disable_xip(const struct spi_nor_flash *const me) { struct n25q256a * n25q = (struct n25q256a *)me; struct qspi_dma_descriptor *descr = (struct qspi_dma_descriptor *)(me->io); uint8_t width = n25q->quad_mode ? QSPI_INST4_ADDR4_DATA4 : QSPI_INST1_ADDR1_DATA1; uint8_t vcfg; /* XIP is terminated by driving the XIP confirmation bit to 1. * The device automatically resets volatile configuration register bit 3 to 1. */ n25q256a_xip_confirm(me, false); vcfg = n25q256a_read_reg(me, width, N25Q_READ_VOLATILE_CONFIG_REGISTER); if (!(vcfg & (1u << 3))) { if (n25q->pin_exit_xip) { /* Quad : drive DQ0 = 1 with S# held LOW for 7 clock cycles * Dual : drive DQ0 = 1 with S# held LOW for 13 clock cycles * Extended: drive DQ0 = 1 with S# held LOW for 25 clock cycles */ void *hw = descr->dev.prvt; qspi_dma_disable(descr); n25q->pin_exit_xip(); qspi_dma_init(descr, hw); qspi_dma_enable(descr); } } n25q->xip_mode = 0; return ERR_NONE; }