123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776 |
- /**************************************************************************//**
- *
- * @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2021-1-13 Wayne First version
- *
- ******************************************************************************/
- #include <rtthread.h>
- #if defined(NU_PKG_USING_SPINAND)
- #define LOG_TAG "spinand_flash"
- #define DBG_ENABLE
- #define DBG_SECTION_NAME LOG_TAG
- #define DBG_LEVEL DBG_INFO
- #define DBG_COLOR
- #include <rtdbg.h>
- #include "spinand.h"
- const struct nu_spinand_info g_spinandflash_list[] =
- {
- /* Winbond */
- /* Only tested */
- {
- 0xEFAA21, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 1024, 64, 0, "Winbond 128MB: 2048+64@64@1024",
- #if defined(RT_USING_DFS_UFFS)
- {
- /* For storing Seal-byte at 0x37. Need 15-Bytes */
- 0x04, 0x04, 0x14, 0x04, 0x24, 0x04, 0x34, 0x03, 0xFF, 0x00
- },
- {
- /* For storing Seal-byte at 0x37 and not report latest ECC part in Spare-3 */
- 0x08, 0x08, 0x18, 0x08, 0x28, 0x08, /*0x38, 0x08,*/ 0xFF, 0x00
- }
- #else
- {
- 0x04, 0x04, 0x14, 0x04, 0x24, 0x04, 0x34, 0x04, 0xFF, 0x00
- },
- {
- 0x08, 0x08, 0x18, 0x08, 0x28, 0x08, 0x38, 0x08, 0xFF, 0x00
- }
- #endif
- },
- {
- 0xEFBF22, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 2048, 64, 0, "Winbond 256MB: 2048+64@64@2048",
- #if defined(RT_USING_DFS_UFFS)
- {
- /* For storing Seal-byte at 0x39. Need 15-Bytes */
- 0x08, 0x04, 0x18, 0x04, 0x28, 0x04, 0x38, 0x03, 0xFF, 0x00
- },
- {
- /* For storing Seal-byte at 0x39 and not report latest ECC part in Spare-3 */
- 0x0C, 0x04, 0x1C, 0x04, 0x2C, 0x04, /*0x3C, 0x04,*/ 0xFF, 0x00
- }
- #else
- {
- 0x08, 0x04, 0x18, 0x04, 0x28, 0x04, 0x38, 0x04, 0xFF, 0x00
- },
- {
- 0x0C, 0x04, 0x1C, 0x04, 0x2C, 0x04, 0x3C, 0x04, 0xFF, 0x00
- }
- #endif
- },
- #if 0
- { 0xEFAA22, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 2048, 64, 0, "Winbond 256MB: 2048+64@64@1024" },
- { 0xEFAB21, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 1024, 64, 1, "Winbond 256MB: 2048+64@64@1024, MCP" },
- /* Not test and supporting yet. */
- /* MXIC */
- { 0x00C212, 2048, 64, 0x6b, 0x05, 0x01, 0x40, 0x1, 1024, 64, 0, "MXIC 128MB: 2048+64@64@1024" },
- /* XTX */
- { 0x0BE20B, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 2048, 64, 0, "XTX 256MB: 2048+64@64@2048" },
- { 0x0BF20B, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 2048, 64, 0, "XTX 256MB: 2048+64@64@2048" },
- { 0x0BE10B, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 1024, 64, 0, "XTX 256MB: 2048+64@64@1024" },
- { 0x0BF10B, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 1024, 64, 0, "XTX 256MB: 2048+64@64@1024" },
- /* ATO */
- { 0x9B129B, 2048, 64, 0x6b, 0x0f, 0x1f, 0x01, 0x1, 1024, 64, 0, "ATO 128MB: 2048+64@64@1024" },
- /* Micro */
- { 0x2C242C, 2048, 128, 0x6b, 0x0f, 0x1f, 0x01, 0x1, 2048, 64, 0, "Micro 256MB: 2048+128@64@2048" },
- /* GigaDevice */
- { 0xB148C8, 2048, 128, 0x6b, 0x0f, 0x1f, 0x01, 0x1, 1024, 64, 0, "GD 128MB: 2048+128@64@1024" },
- /* Unknown */
- { 0x00C8D1, 2048, 128, 0x6b, 0x0f, 0x1f, 0x01, 0x1, 1024, 64, 0, "Unknown 128MB: 2048+128@64@1024" },
- { 0x00C851, 2048, 128, 0x6b, 0x0f, 0x1f, 0x01, 0x1, 1024, 64, 0, "Unknown 128MB: 2048+128@64@1024" },
- { 0x98E240, 2048, 128, 0x6b, 0x0f, 0x1f, 0x01, 0x1, 1024, 64, 0, "Unknown 128MB: 2048+128@64@1024" }
- #endif
- };
- #define SPINAND_LIST_ELEMENT_NUM ( sizeof(g_spinandflash_list)/sizeof(struct nu_spinand_info) )
- /*
- ========================================================
- For 0xEFAA21 description:
- Data Area(2048-Byte)
- -----------------------------
- |Sect-0|Sect-1|Sect-2|Sect-3|
- |(512B)|(512B)|(512B)|(512B)|
- -----------------------------
- Spare Area(64-Byte)
- ---------------------------------
- |Spare-0|Spare-1|Spare-2|Spare-3|
- | (16B) | (16B) | (16B) | (16B) |
- ---------------------------------
- ----------------- Spare-0 -------------------
- / \
- -------------------------------------------------
- | BBM | UD2 | UD1 | ECC Sect-0 | ECC Spare |
- | 0 1 | 2 3 | 4 5 6 7 | 8 9 A B C D | E F |
- -------------------------------------------------
- | NO ECC | ECC PROTECTED | ECC 4-D |
- BBM: Bad block marker.
- UD1: User Data 1.
- UD2: User Data 2.
- ECC Sect-n: ECC for sector-n.
- ECC Spare: ECC for spare 4-D.
- ---------------- Spare-1 -------------------
- / \
- -----------------------------------------------
- | UD2 | UD1 | ECC Sect-1 | ECC Spare |
- | 0 1 2 3 | 4 5 6 7 | 8 9 A B C D | E F |
- -----------------------------------------------
- | NO ECC | ECC PROTECTED | ECC 14-1D |
- ---------------- Spare-2 -------------------
- / \
- -----------------------------------------------
- | UD2 | UD1 | ECC Sect-2 | ECC Spare |
- | 0 1 2 3 | 4 5 6 7 | 8 9 A B C D | E F |
- -----------------------------------------------
- | NO ECC | ECC PROTECTED | ECC 24-2D |
- ---------------- Spare-3 -------------------
- / \
- -----------------------------------------------
- | UD2 | UD1 | ECC Sect-3 | ECC Spare |
- | 0 1 2 3 | 4 5 6 7 | 8 9 A B C D | E F |
- -----------------------------------------------
- | NO ECC | ECC PROTECTED | ECC 34-3D |
- ========================================================
- ========================================================
- For 0xEFBF22 description:
- Data Area(2048-Byte)
- -----------------------------
- |Sect-0|Sect-1|Sect-2|Sect-3|
- |(512B)|(512B)|(512B)|(512B)|
- -----------------------------
- Spare Area(64-Byte)
- ---------------------------------
- |Spare-0|Spare-1|Spare-2|Spare-3|
- | (16B) | (16B) | (16B) | (16B) |
- ---------------------------------
- ----------------- Spare-0 -------------------
- / \
- -----------------------------------------
- | BBM | UD2 | UD1 | ECC UD1 |
- | 0 1 | 2 3 4 5 6 7 | 8 9 A B | C D E F |
- -----------------------------------------
- | NO ECC | ECC PROTECTED |
- BBM: Bad block marker.
- UD1: User Data 1.
- UD2: User Data 2.
- ECC UD1: ECC for UD1.
- ---------------- Spare-1 -------------------
- / \
- ---------------------------------------
- | UD2 | UD1 | ECC UD1 |
- | 0 1 2 3 4 5 6 7 | 8 9 A B | C D E F |
- ---------------------------------------
- | NO ECC | ECC PROTECTED |
- ---------------- Spare-2 -------------------
- / \
- ---------------------------------------
- | UD2 | UD1 | ECC UD1 |
- | 0 1 2 3 4 5 6 7 | 8 9 A B | C D E F |
- ---------------------------------------
- | NO ECC | ECC PROTECTED |
- ---------------- Spare-3 -------------------
- / \
- ---------------------------------------
- | UD2 | UD1 | ECC UD1 |
- | 0 1 2 3 4 5 6 7 | 8 9 A B | C D E F |
- ---------------------------------------
- | NO ECC | ECC PROTECTED |
- ========================================================
- */
- rt_uint8_t spinand_flash_data_layout[SPINAND_SPARE_LAYOUT_SIZE];
- rt_uint8_t spinand_flash_ecc_layout[SPINAND_SPARE_LAYOUT_SIZE];
- static rt_err_t spinand_info_read(struct rt_qspi_device *qspi);
- static rt_err_t spinand_die_select(struct rt_qspi_device *qspi, uint8_t select_die)
- {
- uint8_t au8Cmd[2] = { 0xC2, 0x0 };
- au8Cmd[1] = select_die;
- return nu_qspi_send(qspi, &au8Cmd[0], sizeof(au8Cmd));
- }
- static uint8_t spinand_isbusy(struct rt_qspi_device *qspi)
- {
- #define BUSY_CKECKING_TIMEOUT_MS 3000
- volatile uint8_t SR = 0xFF;
- rt_err_t result;
- uint8_t au8Cmd[2] = { 0x0F, 0xC0 };
- uint32_t u32CheckingDuration = rt_tick_from_millisecond(BUSY_CKECKING_TIMEOUT_MS);
- uint32_t u32Start = rt_tick_get();
- do
- {
- result = nu_qspi_send_then_recv(qspi, &au8Cmd[0], sizeof(au8Cmd), (void *)&SR, 1);
- if (result != RT_EOK)
- goto timeout_spinand_isbusy;
- if ((rt_tick_get() - u32Start) >= u32CheckingDuration)
- {
- goto timeout_spinand_isbusy;
- }
- }
- while ((SR & 0x1) != 0x00);
- return 0;
- timeout_spinand_isbusy:
- LOG_E("Error: spinand timeout.");
- return 1;
- }
- static rt_err_t spinand_program_dataload(
- struct rt_qspi_device *qspi,
- uint8_t u8AddrH,
- uint8_t u8AddrL,
- uint8_t *pu8DataBuff,
- uint32_t u32DataCount,
- uint8_t *pu8SpareBuff,
- uint32_t u32SpareCount)
- {
- uint8_t u8WECmd = 0x06;
- rt_err_t result = RT_EOK;
- struct rt_qspi_message qspi_messages[2] = {0};
- /* 1-bit mode */
- qspi_messages[0].instruction.content = 0x32;
- qspi_messages[0].instruction.qspi_lines = 1;
- qspi_messages[0].address.content = (u8AddrH << 8) | (u8AddrL);
- qspi_messages[0].address.size = 2 * 8;
- qspi_messages[0].address.qspi_lines = 1;
- /* 4-bit mode */
- qspi_messages[0].qspi_data_lines = 4;
- qspi_messages[0].parent.cs_take = 1;
- qspi_messages[0].parent.cs_release = 0;
- qspi_messages[0].parent.send_buf = pu8DataBuff;
- qspi_messages[0].parent.length = u32DataCount;
- qspi_messages[0].parent.next = &qspi_messages[1].parent;
- qspi_messages[1].qspi_data_lines = 4;
- qspi_messages[1].parent.cs_take = 0;
- qspi_messages[1].parent.cs_release = 1;
- qspi_messages[1].parent.send_buf = pu8SpareBuff;
- qspi_messages[1].parent.length = u32SpareCount;
- if ((result = nu_qspi_send(qspi, &u8WECmd, sizeof(u8WECmd))) != RT_EOK)
- goto exit_spinand_program_dataload;
- result = nu_qspi_transfer_message(qspi, (struct rt_qspi_message *)&qspi_messages[0]);
- exit_spinand_program_dataload:
- return result;
- }
- static uint8_t spinand_status_register_read(struct rt_qspi_device *qspi, uint8_t u8SRSel)
- {
- uint8_t u8SR = 0;
- uint8_t au8Cmd[2];
- switch (u8SRSel)
- {
- case 0x01:
- au8Cmd[0] = 0x05;
- au8Cmd[1] = 0xA0;
- break;
- case 0x02:
- au8Cmd[0] = 0x0F;
- au8Cmd[1] = 0xB0;
- break;
- case 0x03:
- au8Cmd[0] = 0x05;
- au8Cmd[1] = 0xC0;
- break;
- default:
- RT_ASSERT(0);
- break;
- }
- if (nu_qspi_send_then_recv(qspi, &au8Cmd[0], sizeof(au8Cmd), &u8SR, 1) != RT_EOK)
- RT_ASSERT(0);
- return u8SR;
- }
- static rt_err_t spinand_status_register_write(struct rt_qspi_device *qspi, uint8_t u8SRSel, uint8_t u8Value)
- {
- rt_err_t result = RT_EOK;
- uint8_t au8Cmd[3];
- switch (u8SRSel)
- {
- case 0x01:
- au8Cmd[0] = 0x01;
- au8Cmd[1] = 0xA0;
- break;
- case 0x02:
- au8Cmd[0] = 0x01;
- au8Cmd[1] = 0xB0;
- break;
- case 0x03:
- au8Cmd[0] = 0x01;
- au8Cmd[1] = 0xC0;
- break;
- default:
- result = RT_EINVAL;
- goto exit_spinand_status_register_write;
- }
- au8Cmd[2] = u8Value;
- if ((result = nu_qspi_send(qspi, &au8Cmd[0], sizeof(au8Cmd))) != RT_EOK)
- goto exit_spinand_status_register_write;
- if (spinand_isbusy(qspi))
- {
- result = RT_EIO;
- goto exit_spinand_status_register_write;
- }
- exit_spinand_status_register_write:
- return result;
- }
- static rt_err_t spinand_program_execute(struct rt_qspi_device *qspi, uint8_t u8Addr2, uint8_t u8Addr1, uint8_t u8Addr0)
- {
- rt_err_t result;
- uint8_t au8Cmd[4], u8SR;
- au8Cmd[0] = 0x10 ;
- au8Cmd[1] = u8Addr2;
- au8Cmd[2] = u8Addr1;
- au8Cmd[3] = u8Addr0;
- if ((result = nu_qspi_send(qspi, &au8Cmd, sizeof(au8Cmd))) != RT_EOK)
- goto exit_spinand_program_execute;
- if (spinand_isbusy(qspi))
- {
- result = -RT_MTD_EIO;
- goto exit_spinand_program_execute;
- }
- u8SR = (spinand_status_register_read(SPINAND_FLASH_QSPI, 3) & 0x0C) >> 2;
- if (u8SR == 1)
- {
- result = -RT_MTD_EIO;
- LOG_E("Error write status!");
- }
- exit_spinand_program_execute:
- return result;
- }
- static rt_err_t spinand_normal_read(struct rt_qspi_device *qspi, uint8_t u8AddrH, uint8_t u8AddrL, uint8_t *pu8Buff, uint32_t u32Count)
- {
- uint8_t au8Cmd[4];
- au8Cmd[0] = 0x03;
- au8Cmd[1] = u8AddrH;
- au8Cmd[2] = u8AddrL;
- au8Cmd[3] = 0x00;
- return nu_qspi_send_then_recv(qspi, &au8Cmd[0], sizeof(au8Cmd), pu8Buff, u32Count);
- }
- static rt_err_t spinand_protect_set(struct rt_qspi_device *qspi, uint8_t u8Protect)
- {
- /* Read status register 1 */
- uint8_t u8SR = spinand_status_register_read(qspi, 1);
- if (u8Protect)
- {
- /* protect */
- u8SR |= 0x7C;
- }
- else
- {
- /* unprotect */
- u8SR &= 0x83;
- }
- return spinand_status_register_write(qspi, 1, u8SR);
- }
- static uint8_t spinand_program_erase_isfail(struct rt_qspi_device *qspi)
- {
- /* Read status register 3 */
- uint8_t u8SR = spinand_status_register_read(qspi, 3);
- return (u8SR & 0x0C) >> 2; /* Check P-Fail, E-Fail bit */
- }
- static uint8_t spinand_hwecc_status_get(struct rt_qspi_device *qspi)
- {
- /* Read status register 3 */
- uint8_t u8SR = spinand_status_register_read(qspi, 3);
- return (u8SR & 0x30) >> 4; /* ECC-1, ECC0 bit */
- }
- static rt_err_t spinand_hwecc_set(struct rt_qspi_device *qspi, uint8_t u8Enable)
- {
- uint8_t u8SR = spinand_status_register_read(qspi, 2); // Read status register 2
- if (u8Enable)
- {
- u8SR |= 0x10; // Enable ECC-E bit
- }
- else
- {
- u8SR &= 0xEF; // Disable ECC-E bit
- }
- return spinand_status_register_write(qspi, 2, u8SR);
- }
- static uint8_t spinand_hwecc_get(struct rt_qspi_device *qspi)
- {
- /* Read status register 2 */
- uint8_t u8SR = spinand_status_register_read(qspi, 2);
- return (u8SR & 0x10) >> 4;
- }
- static rt_err_t spinand_read_dataload(struct rt_qspi_device *qspi, uint8_t u8Addr2, uint8_t u8Addr1, uint8_t u8Addr0)
- {
- rt_err_t result = RT_EOK;
- uint8_t au8Cmd[4];
- uint8_t u8SR;
- au8Cmd[0] = 0x13 ;
- au8Cmd[1] = u8Addr2;
- au8Cmd[2] = u8Addr1;
- au8Cmd[3] = u8Addr0;
- if ((result = nu_qspi_send(qspi, &au8Cmd[0], sizeof(au8Cmd))) != RT_EOK)
- goto exit_spinand_read_dataload;
- if (spinand_isbusy(qspi))
- {
- result = -RT_EIO;
- goto exit_spinand_read_dataload;
- }
- u8SR = spinand_hwecc_status_get(SPINAND_FLASH_QSPI);
- if ((u8SR != 0x00) && (u8SR != 0x01))
- {
- result = -RT_MTD_EECC;
- LOG_E("Error ECC status error[0x%x].", u8SR);
- }
- exit_spinand_read_dataload:
- return result;
- }
- static uint8_t spinand_block_isbad(struct rt_qspi_device *qspi, uint32_t u32PageAddr)
- {
- rt_err_t result;
- uint8_t read_buf;
- again_spinand_block_isbad:
- result = spinand_read_dataload(qspi, (u32PageAddr >> 16) & 0xFF, (u32PageAddr >> 8) & 0xFF, u32PageAddr & 0xFF); // Read the first page of a block
- RT_ASSERT(result == RT_EOK);
- result = spinand_normal_read(qspi, (SPINAND_FLASH_PAGE_SIZE >> 8) & 0xff, SPINAND_FLASH_PAGE_SIZE & 0xff, &read_buf, 1); // Read bad block mark at 0x800 update at v.1.0.8
- RT_ASSERT(result == RT_EOK);
- if (read_buf != 0xFF)
- {
- // update at v.1.0.7
- return 1;
- }
- if (((u32PageAddr % (SPINAND_FLASH_PAGE_PER_BLOCK_NUM * SPINAND_FLASH_PAGE_SIZE)) == 0))
- {
- /* Need check second page again. */
- u32PageAddr++;
- goto again_spinand_block_isbad;
- }
- return 0;
- }
- static rt_err_t spinand_buffermode_set(struct rt_qspi_device *qspi, uint8_t u8Enable)
- {
- uint8_t u8SR = spinand_status_register_read(qspi, 2); // Read status register 2
- if (u8Enable)
- {
- u8SR |= 0x08; // Enable BUF bit
- }
- else
- {
- u8SR &= 0xF7; // Disable BUF bit
- }
- return spinand_status_register_write(qspi, 2, u8SR);
- }
- static rt_err_t spinand_block_erase(struct rt_qspi_device *qspi, uint8_t u8Addr2, uint8_t u8Addr1, uint8_t u8Addr0)
- {
- rt_err_t result;
- uint8_t u8WECmd = 0x06;
- uint8_t au8EraseCmd[4], u8SR;
- au8EraseCmd[0] = 0xD8;
- au8EraseCmd[1] = u8Addr2;
- au8EraseCmd[2] = u8Addr1;
- au8EraseCmd[3] = u8Addr0;
- if ((result = nu_qspi_send(qspi, &u8WECmd, sizeof(u8WECmd))) != RT_EOK)
- goto exit_spinand_block_erase;
- if ((result = nu_qspi_send(qspi, &au8EraseCmd[0], sizeof(au8EraseCmd))) != RT_EOK)
- goto exit_spinand_block_erase;
- if (spinand_isbusy(qspi))
- return -RT_EIO;
- u8SR = spinand_program_erase_isfail(SPINAND_FLASH_QSPI);
- if (u8SR != 0)
- {
- /* Fail to erase */
- LOG_E("Fail to erase. Will mark it bad.");
- result = -RT_ERROR;
- goto exit_spinand_block_erase;
- }
- exit_spinand_block_erase:
- return result;
- }
- static rt_err_t spinand_block_markbad(struct rt_qspi_device *qspi, uint32_t u32PageAddr)
- {
- rt_err_t result = RT_EOK;
- uint8_t u8BadBlockMarker = 0xF0;
- result = spinand_block_erase(qspi, (u32PageAddr >> 16) & 0xFF, (u32PageAddr >> 8) & 0xFF, u32PageAddr & 0xFF);
- if (result != RT_EOK)
- return result;
- result = spinand_program_dataload(qspi, (SPINAND_FLASH_PAGE_SIZE >> 8) & 0xff, SPINAND_FLASH_PAGE_SIZE & 0xff, &u8BadBlockMarker, 1, 0, 0);
- if (result != RT_EOK)
- return result;
- return spinand_program_execute(qspi, (u32PageAddr >> 16) & 0xFF, (u32PageAddr >> 8) & 0xFF, u32PageAddr & 0xFF);
- }
- static rt_err_t spinand_read_quadoutput(
- struct rt_qspi_device *qspi,
- uint8_t u8AddrH,
- uint8_t u8AddrL,
- uint8_t *pu8DataBuff,
- uint32_t u32DataCount
- )
- {
- struct rt_qspi_message qspi_messages = {0};
- /* 1-bit mode */
- qspi_messages.instruction.content = SPINAND_FLASH_QUADREAD_CMDID;
- qspi_messages.instruction.qspi_lines = 1;
- qspi_messages.address.content = (u8AddrH << 8) | (u8AddrL);
- qspi_messages.address.size = 2 * 8;
- qspi_messages.address.qspi_lines = 1;
- qspi_messages.dummy_cycles = SPINAND_FLASH_DUMMYBYTE * 8; //In bit
- /* 4-bit mode */
- qspi_messages.qspi_data_lines = 4;
- qspi_messages.parent.cs_take = 1;
- qspi_messages.parent.cs_release = 1;
- qspi_messages.parent.recv_buf = pu8DataBuff;
- qspi_messages.parent.length = u32DataCount;
- qspi_messages.parent.next = RT_NULL;
- return nu_qspi_transfer_message(qspi, (struct rt_qspi_message *) &qspi_messages);
- }
- static rt_err_t spinand_jedecid_get(struct rt_qspi_device *qspi, uint32_t *pu32ID)
- {
- uint32_t u32JedecId = 0;
- uint32_t u32JedecId_real = 0;
- uint8_t u8Cmd = 0x9F;
- if (nu_qspi_send_then_recv(qspi, &u8Cmd, 1, &u32JedecId, 4) != RT_EOK)
- {
- return -RT_ERROR;
- }
- /* Reverse order. */
- nu_set32_be((uint8_t *)&u32JedecId_real, u32JedecId);
- /* Only keep 3-bytes. */
- u32JedecId_real &= 0x00ffffff;
- *pu32ID = u32JedecId_real;
- return RT_EOK;
- }
- static rt_err_t spinand_reset(struct rt_qspi_device *qspi)
- {
- rt_err_t result;
- uint8_t u8Cmd = 0xFF;
- if ((result = nu_qspi_send(qspi, &u8Cmd, 1)) != RT_EOK)
- goto exit_spinand_reset;
- if (spinand_isbusy(qspi))
- {
- result = RT_EIO;
- goto exit_spinand_reset;
- }
- exit_spinand_reset:
- return result;
- }
- rt_err_t spinand_flash_init(struct rt_qspi_device *qspi)
- {
- rt_err_t result;
- if ((result = spinand_reset(qspi)) != RT_EOK)
- goto exit_spinand_init;
- if ((result = spinand_info_read(qspi)) != RT_EOK)
- goto exit_spinand_init;
- /* Un-protect */
- if ((result = spinand_protect_set(qspi, 0)) != RT_EOK)
- goto exit_spinand_init;
- /* Enable BUF mode */
- if ((result = spinand_buffermode_set(qspi, 1)) != RT_EOK)
- goto exit_spinand_init;
- /* Enable HWECC */
- if ((result = spinand_hwecc_set(qspi, 1)) != RT_EOK)
- goto exit_spinand_init;
- /* Check HWECC */
- if (!(spinand_hwecc_get(qspi)))
- goto exit_spinand_init;
- if (SPINAND_FLASH_MCP == 1)
- {
- /* Select die. */
- if ((result = spinand_die_select(qspi, SPINAND_DIE_ID1)) != RT_EOK)
- goto exit_spinand_init;
- /* Unprotect */
- if ((result = spinand_protect_set(qspi, 0)) != RT_EOK)
- goto exit_spinand_init;
- }
- LOG_I("Enabled BUF, HWECC. Unprotected.");
- exit_spinand_init:
- return -result;
- }
- struct spinand_ops spinand_ops_wb =
- {
- .block_erase = spinand_block_erase,
- .block_isbad = spinand_block_isbad,
- .block_markbad = spinand_block_markbad,
- .die_select = spinand_die_select,
- .jedecid_get = spinand_jedecid_get,
- .program_dataload = spinand_program_dataload,
- .program_execute = spinand_program_execute,
- .read_dataload = spinand_read_dataload,
- .read_quadoutput = spinand_read_quadoutput
- };
- static rt_err_t spinand_info_read(struct rt_qspi_device *qspi)
- {
- int i;
- uint32_t u32JedecId = 0;
- if (spinand_jedecid_get(qspi, &u32JedecId) != RT_EOK)
- goto exit_spinand_info_read;
- for (i = 0 ; i < SPINAND_LIST_ELEMENT_NUM; i++)
- {
- if (u32JedecId == g_spinandflash_list[i].u32JEDECID) /* Match JEDECID? */
- {
- rt_memcpy((void *)&spinand_flash_data_layout[0], (void *)&g_spinandflash_list[i].au8DataLayout[0], SPINAND_SPARE_LAYOUT_SIZE);
- rt_memcpy((void *)&spinand_flash_ecc_layout[0], (void *)&g_spinandflash_list[i].au8EccLayout[0], SPINAND_SPARE_LAYOUT_SIZE);
- rt_memcpy(SPINAND_FLASH_INFO, &g_spinandflash_list[i], sizeof(struct nu_spinand_info));
- LOG_I("Found: [%08X] %s.", u32JedecId, SPINAND_FLASH_DESCRIPTION);
- switch (u32JedecId & 0xff0000)
- {
- case 0xEF0000: /* Winbond */
- SPINAND_FLASH_OPS = &spinand_ops_wb;
- break;
- default:
- goto exit_spinand_info_read;
- }
- return RT_EOK;
- }
- }
- exit_spinand_info_read:
- LOG_E("Can't find the flash[%08X] in supported list.", u32JedecId);
- return -RT_ERROR;
- }
- #endif
|