Explorar o código

!449 at91sam9260平台增加mtdnand驱动用于支持uffs文件系统
* update bsp/at91sam9260/drivers/at91_nand.c.
* update bsp/at91sam9260/drivers/at91_nand.c.
* update bsp/at91sam9260/drivers/at91_nand.h.
* update bsp/at91sam9260/drivers/at91_nand.c.
* update bsp/at91sam9260/drivers/at91_nand.c.
* 添加at91sam9260下mtd nand flash驱动

brightsally %!s(int64=3) %!d(string=hai) anos
pai
achega
2282ff3c90

+ 2 - 0
bsp/at91sam9260/drivers/SConscript

@@ -23,6 +23,8 @@ if GetDepend('RT_USING_LWIP'):
 if GetDepend('RT_USING_I2C') and GetDepend('RT_USING_I2C_BITOPS'):
 	src += ['at91_i2c_gpio.c']
 
+if GetDepend('RT_USING_MTD_NAND'):
+    src += ['at91_nand.c']
     
 CPPPATH = [cwd]
 

+ 635 - 0
bsp/at91sam9260/drivers/at91_nand.c

@@ -0,0 +1,635 @@
+/*
+* Copyright (c) 2006-2022, RT-Thread Development Team
+*
+* SPDX-License-Identifier: Apache-2.0
+*
+* Change Logs:
+* Date           Author        Notes
+* 2022-01-08     brightsally   first version
+*/
+
+#include <rtdevice.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <at91sam926x.h>
+#include "at91_nand.h"
+
+static struct nand_chip_id *chip;
+static unsigned int bufsize = 528;
+static unsigned char pages_per_block = 32;
+static unsigned char eccsize = 6;
+static struct rt_mtd_nand_device _partition[2];
+/*****************************************************************************
+nand_calculate_ecc function copy from uboot
+*****************************************************************************/
+#define u_char unsigned char
+/* Define default oob placement schemes for large and small page devices */
+static struct nand_ecclayout nand_oob_16 =
+{
+
+    .eccbytes = 6,
+      .eccpos = {0, 1, 2, 3, 6, 7},
+      .oobfree = {
+            {
+            .offset = 8,
+            . length = 8
+            }
+    }
+};
+
+static struct nand_ecclayout nand_oob_64 =
+{
+    .eccbytes = 24,
+      .eccpos = {
+        40, 41, 42, 43, 44, 45, 46, 47,
+        48, 49, 50, 51, 52, 53, 54, 55,
+        56, 57, 58, 59, 60, 61, 62, 63
+    },
+    .oobfree = {
+        {
+        .offset = 2,
+        .length = 38
+        }
+        }
+};
+/*
+* Pre-calculated 256-way 1 byte column parity
+*/
+
+static const u_char nand_ecc_precalc_table[] =
+{
+    0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
+    0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+    0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+    0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+    0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+    0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+    0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+    0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+    0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+    0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+    0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+    0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+    0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+    0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+    0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+    0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
+};
+
+/**
+* nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256-byte block
+* @mtd:    MTD block structure
+* @dat:    raw data
+* @ecc_code:   buffer for ECC
+*/
+int nand_calculate_ecc(const u_char *dat, u_char *ecc_code)
+{
+    uint8_t idx, reg1, reg2, reg3, tmp1, tmp2;
+    int i;
+
+    /* Initialize variables */
+    reg1 = reg2 = reg3 = 0;
+
+    /* Build up column parity */
+    for (i = 0; i < 256; i++)
+    {
+        /* Get CP0 - CP5 from table */
+        idx = nand_ecc_precalc_table[*dat++];
+        reg1 ^= (idx & 0x3f);
+
+        /* All bit XOR = 1 ? */
+        if (idx & 0x40)
+        {
+            reg3 ^= (uint8_t) i;
+            reg2 ^= ~((uint8_t) i);
+        }
+    }
+
+    /* Create non-inverted ECC code from line parity */
+    tmp1  = (reg3 & 0x80) >> 0; /* B7 -> B7 */
+    tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */
+    tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */
+    tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */
+    tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */
+    tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */
+    tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */
+    tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */
+
+    tmp2  = (reg3 & 0x08) << 4; /* B3 -> B7 */
+    tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */
+    tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */
+    tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */
+    tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */
+    tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */
+    tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */
+    tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */
+
+    /* Calculate final ECC code */
+#ifdef CONFIG_MTD_NAND_ECC_SMC
+    ecc_code[0] = ~tmp2;
+    ecc_code[1] = ~tmp1;
+#else
+    ecc_code[0] = ~tmp1;
+    ecc_code[1] = ~tmp2;
+#endif
+    ecc_code[2] = ((~reg1) << 2) | 0x03;
+
+    return 0;
+}
+/*********nand_calculate_ecc function copy from uboot end*********************/
+static void at91_nand_udelay(rt_uint32_t us)
+{
+    rt_uint32_t len;
+    for (; us > 0; us --)
+        for (len = 0; len < 10; len++);
+}
+static void wait_udelay()
+{
+    if (chip->pagesize == 2048)at91_nand_udelay(2000);
+    else    at91_nand_udelay(1);
+}
+void nand_enable_cs(void)
+{
+    writel(0x00004000, 0xfffff834);
+    readl(0xfffff838);
+    //rt_kprintf("===i=0x%x\r\n",i);
+    wait_udelay();
+}
+void nand_disable_cs(void)
+{
+    writeb(0xff, 0x40400000);
+    writel(0x00004000, 0xfffff830);
+    readl(0xfffff830);
+    wait_udelay();
+}
+
+void nand_write_cmd(unsigned char cmd)
+{
+    writeb(cmd, CMD_REG);
+    wait_udelay();
+}
+void nand_write_addr(unsigned char addr)
+{
+    writeb(addr, ADDR_REG);
+    wait_udelay();
+}
+void nand_write_data_byte(unsigned char data)
+{
+    writeb(data, DATA_REG);
+    wait_udelay();
+}
+
+unsigned char nand_read_data_byte(void)
+{
+    return readb(DATA_REG);
+}
+
+static int  nand_wait_ready(void)
+{
+    unsigned int timeout = 10000;
+
+    nand_write_cmd(CMD_STATUS);
+    while ((!(nand_read_data_byte() & STATUS_READY)) && timeout--);
+    if (!timeout)return -1;
+    return 0;
+}
+
+//----------------------------------------------------------------
+/* read chip id */
+static rt_err_t at9260_nand_read_id(struct rt_mtd_nand_device *device)
+{
+    int manf_id, dev_id;
+    unsigned int chipid;
+    unsigned int i;
+
+    nand_enable_cs();
+
+    nand_write_cmd(CMD_READID);
+    nand_write_addr(CMD_READ_1);
+    manf_id  = nand_read_data_byte();
+    dev_id   = nand_read_data_byte();
+    nand_disable_cs();
+
+    chipid = (manf_id << 8) | dev_id;
+
+    for (i = 0; i < ARRAY_SIZE(nand_ids); i++)
+    {
+        if (chipid == nand_ids[i].chip_id)
+            break;
+    }
+
+    if (i == ARRAY_SIZE(nand_ids))
+    {
+        rt_kprintf("NAND: Not found Manufacturer ID: %x," \
+            "Chip ID: 0x%x\n", manf_id, dev_id);
+        return -1;
+    }
+
+    //find nand chip
+    rt_kprintf("NAND: Manufacturer ID: %x Chip ID: %x Total Block:%d\n", manf_id, dev_id, nand_ids[i].numblocks);
+
+    chip->numblocks = nand_ids[i].numblocks;
+    chip->pagesize  = nand_ids[i].pagesize;
+    chip->blocksize = nand_ids[i].blocksize;
+    chip->oobsize   = nand_ids[i].oobsize;
+    chip->buswidth  = nand_ids[i].buswidth;
+    chip->numblocks = nand_ids[i].numblocks;
+
+    bufsize = chip->pagesize + chip->oobsize;
+    eccsize = (chip->pagesize) * 3 / 256;
+
+    if (chip->pagesize == 512)
+    {
+        pages_per_block = 32;
+        rt_kprintf("===small block pages===== \n");
+    }
+    else if (chip->pagesize == 2048)
+    {
+        pages_per_block = 64;
+        rt_kprintf("===big   block pages===== \n");
+    }
+
+    return i;
+}
+
+int nand_read_page9260(unsigned int block, unsigned int page, unsigned char *data, rt_uint32_t data_len, unsigned char *spare, rt_uint32_t spare_len)
+{
+    int i = 0;
+    unsigned int blockpage;
+    unsigned char buff1[bufsize];
+
+    blockpage = block * (pages_per_block) + page;
+    memset(buff1, 0xff, bufsize);
+
+    nand_enable_cs();
+    nand_write_cmd(CMD_READ_A0);
+    nand_write_addr(0);
+    if (bufsize == 2112)nand_write_addr(0);
+    nand_write_addr(blockpage & 0xff);
+    nand_write_addr((blockpage >> 8) & 0xff);
+    nand_write_addr((blockpage >> 16) & 0xff);
+
+    at91_nand_udelay(2000);
+
+    if (bufsize == 528)nand_write_cmd(CMD_READ_1);
+    else if (bufsize == 2112)nand_write_cmd(CMD_READ_2);
+
+    for (i = 0; i < chip->pagesize; i++)buff1[i] = nand_read_data_byte();
+    for (i = 0; i < chip->oobsize; i++)buff1[i + chip->pagesize] = nand_read_data_byte();
+
+    nand_wait_ready();
+    nand_disable_cs();
+
+    if (data != RT_NULL)
+        rt_memcpy(data, buff1, data_len);
+    if (spare != RT_NULL)
+        rt_memcpy(spare, &buff1[chip->pagesize], spare_len);
+
+    return 0x00;
+}
+//============================================================================
+static rt_err_t at9260_nand_read_page(struct rt_mtd_nand_device *device,
+                                      rt_off_t page,
+                                      rt_uint8_t *data, rt_uint32_t data_len,
+                                      rt_uint8_t *spare, rt_uint32_t spare_len)
+
+{
+    return nand_read_page9260(page / pages_per_block, page % pages_per_block, data, data_len, spare, spare_len);
+}
+
+int nand_write_page9260(unsigned int block, unsigned int page, unsigned char *data, rt_uint32_t data_len, unsigned char *spare, rt_uint32_t spare_len)
+{
+    unsigned int blockpage;
+    unsigned char buff2[chip->pagesize];
+    unsigned char se[chip->oobsize];
+    unsigned char ecc_code[eccsize];
+    int i = 0;
+
+    blockpage = block * (pages_per_block) + page;
+    memset(buff2, 0xff, chip->pagesize);
+    memset(se, 0xff, chip->oobsize);
+    memset(ecc_code, 0xff, eccsize);
+
+    nand_enable_cs();
+    nand_write_cmd(CMD_WRITE_1);
+
+    nand_write_addr(0);
+    if (bufsize == 2112)nand_write_addr(0);
+    nand_write_addr(blockpage & 0xff);
+    nand_write_addr((blockpage >> 8) & 0xff);
+    nand_write_addr((blockpage >> 16) & 0xff);
+
+    at91_nand_udelay(2000);
+
+    for (i = 0; i < data_len; i++)buff2[i] = *(data + i);
+    for (i = 0; i < chip->pagesize; i++)
+    {
+        nand_write_data_byte(buff2[i]);
+    }
+
+#ifndef RT_USING_DFS_UFFS
+    if (bufsize == 528)
+    {
+        //caclu ECC
+        nand_calculate_ecc(buff2, ecc_code);
+        nand_calculate_ecc(&buff2[256], &ecc_code[3]);
+        //use uboot MTD ECC layout
+        for (i = 0; i < 6; i++)
+        {
+            se[nand_oob_16.eccpos[i]] = ecc_code[i];
+        }
+    }
+    else if (bufsize == 2112)
+    {
+        //caclu ECC
+        for (i = 0; i < 8; i++)
+        {
+            nand_calculate_ecc(&buff2[256 * i], &(ecc_code[3 * i]));
+        }
+        //use uboot MTD ECC layout
+        for (i = 0; i < 24; i++)
+        {
+            se[nand_oob_64.eccpos[i]] = ecc_code[i];
+        }
+    }
+#else
+    //UFFS do ECC
+    for (i = 0; i < chip->oobsize; i++)
+    {
+        se[i] = *(spare + i);
+    }
+#endif
+
+    for (i = 0; i < chip->oobsize; i++)
+    {
+        nand_write_data_byte(se[i]);
+    }
+
+    nand_write_cmd(CMD_WRITE_2);
+    nand_wait_ready();
+    nand_disable_cs();
+
+    return RT_EOK;
+}
+//===========================================================================================
+static rt_err_t at9260_nand_write_page(struct rt_mtd_nand_device *device,
+                                       rt_off_t page,
+                                       rt_uint8_t *data, rt_uint32_t data_len,
+                                       rt_uint8_t *oob, rt_uint32_t spare_len)
+{
+
+    return nand_write_page9260(page / pages_per_block, page % pages_per_block, data, data_len, oob, spare_len);
+}
+//===========================================================================================
+static rt_err_t at9260_nand_move_page(struct rt_mtd_nand_device *device, rt_off_t src_page, rt_off_t dst_page)
+{
+    return RT_EOK;
+}
+//===========================================================================================
+static long at9260_nand_isbad(struct rt_mtd_nand_device *nand, uint32_t blk)
+{
+    int i = 0;
+    unsigned char buff2[bufsize];
+    unsigned int blockpage = blk * (chip->blocksize / chip->pagesize) + 0;
+
+    memset(buff2, 0xff, bufsize);
+
+    //read blk page 0
+    nand_enable_cs();
+    nand_write_cmd(CMD_READ_A0);
+    nand_write_addr(0);
+    if (bufsize == 2112)nand_write_addr(0);
+    nand_write_addr(blockpage & 0xff);
+    nand_write_addr((blockpage >> 8) & 0xff);
+    nand_write_addr((blockpage >> 16) & 0xff);
+
+    at91_nand_udelay(2000);
+
+    if (bufsize == 528)nand_write_cmd(CMD_READ_1);
+    else if (bufsize == 2112)nand_write_cmd(CMD_READ_2);
+
+    for (i = 0; i < bufsize; i++)
+    {
+        buff2[i] = nand_read_data_byte();
+    }
+    nand_disable_cs();
+
+    if (bufsize == 528)
+    {
+        if (buff2[5 + 512] != 0xff)
+        {
+            rt_kprintf("\r\n Bad Block=0x%x: Cannot read page #0 of block #%d,addr=0x%x \n\r", buff2[5 + 512], blk, blk * 512 * 32);
+            return buff2[5 + 512];
+        }
+    }
+    else if (bufsize == 2112)
+    {
+        if ((buff2[2048 + 0] != 0xff) && (buff2[2048 + 1] != 0xff))
+        {
+            rt_kprintf("\r\n Bad Block=0x%x: Cannot read page #0 of block #%d,addr=0x%x \n\r", buff2[0 + 2048], blk, blk * 2048 * 64);
+            return buff2[0 + 2048] << 8 | buff2[0 + 2048];
+        }
+    }
+
+    //read blk page 1
+    blockpage = blockpage + 1;
+    memset(buff2, 0xff, bufsize);
+    nand_enable_cs();
+    nand_write_cmd(CMD_READ_A0);
+    nand_write_addr(0);
+    if (bufsize == 2112)nand_write_addr(0);
+    nand_write_addr(blockpage & 0xff);
+    nand_write_addr((blockpage >> 8) & 0xff);
+    nand_write_addr((blockpage >> 16) & 0xff);
+    at91_nand_udelay(2000);
+
+    if (bufsize == 528)nand_write_cmd(CMD_READ_1);
+    else if (bufsize == 2112)nand_write_cmd(CMD_READ_2);
+
+
+    for (i = 0; i < bufsize; i++)
+    {
+        buff2[i] = nand_read_data_byte();
+    }
+
+    nand_disable_cs();
+
+    if (bufsize == 528)
+    {
+        if (buff2[5 + 512] != 0xff)
+        {
+            rt_kprintf("\r\n Bad Block=0x%x: Cannot read page #1 of block #%d,addr=0x%x \n\r", buff2[5 + 512], blk, blk * 512 * 32);
+            return buff2[5 + 512];
+        }
+    }
+    else if (bufsize == 2112)
+    {
+        if ((buff2[2048 + 0] != 0xff) && (buff2[2048 + 1] != 0xff))
+        {
+            rt_kprintf("\r\n Bad Block=0x%x: Cannot read page #1 of block #%d,addr=0x%x \n\r", buff2[0 + 2048], blk, blk * 2048 * 64);
+            return buff2[0 + 2048] << 8 | buff2[0 + 2048];
+        }
+    }
+
+    return GOODBLOCK;
+}
+
+static long at9260_nand_markbad(struct rt_mtd_nand_device *nand, uint32_t blk)
+{
+    unsigned int i = 0;
+    unsigned int blockpage = blk * (chip->blocksize / chip->pagesize) + 0;
+    unsigned char bad_flag = 0xff;
+    long ret_bad;
+
+    ret_bad = at9260_nand_isbad(nand, blk);
+
+    if (bufsize == 528)bad_flag = ret_bad & 0xff;
+    else if (bufsize == 2112)
+    {
+        if (bad_flag == 0xff)bad_flag = (ret_bad >> 8) & 0xff;
+    }
+
+    if (bad_flag != 0xff)
+    {
+        nand_enable_cs();
+        nand_write_cmd(CMD_WRITE_1);
+        nand_write_addr(0);
+        if (bufsize == 2112)nand_write_addr(0);
+        nand_write_addr(blockpage & 0xff);
+        nand_write_addr((blockpage >> 8) & 0xff);
+        nand_write_addr((blockpage >> 16) & 0xff);
+        at91_nand_udelay(2000);
+
+        for (i = 0; i < bufsize; i++)
+        {
+            nand_write_data_byte(0x00);
+        }
+
+        nand_write_cmd(CMD_WRITE_2);
+        nand_wait_ready();
+        nand_disable_cs();
+    }
+    return RT_EOK;
+}
+//---------------------------------------------------------------------------------------------
+/* erase block */
+static rt_err_t at9260_nand_erase_block(struct rt_mtd_nand_device *device, rt_uint32_t block)
+{
+    unsigned int row_address;
+
+
+    //Calculate address used for erase
+    row_address = (block) * (chip->blocksize / chip->pagesize);
+
+    nand_enable_cs();
+    nand_write_cmd(CMD_ERASE_1);
+    nand_write_addr(row_address & 0xff);
+    nand_write_addr((row_address >> 8) & 0xff);
+    nand_write_addr((row_address >> 16) & 0xff);
+    nand_write_cmd(CMD_ERASE_2);
+
+    at91_nand_udelay(2000);
+    nand_wait_ready();
+    nand_disable_cs();
+    return RT_EOK;
+}
+
+const static struct rt_mtd_nand_driver_ops _ops =
+{
+    at9260_nand_read_id,
+    at9260_nand_read_page,
+    at9260_nand_write_page,
+    at9260_nand_move_page,
+    at9260_nand_erase_block,
+#ifndef RT_USING_DFS_UFFS
+    at9260_nand_isbad,
+    at9260_nand_markbad,
+#else
+    RT_NULL,
+    RT_NULL,
+#endif
+};
+
+void nand_eraseall(void);
+
+int rt_hw_mtd_nand_init(void)
+{
+    unsigned int i, reg, index;
+
+    /* Setup Smart Media, first enable the address range of CS3 in HMATRIX user interface  */
+    reg = readl(AT91C_BASE_CCFG + CCFG_EBICSA);
+    reg |= AT91C_EBI_CS3A_SM;
+    writel(reg, AT91C_BASE_CCFG + CCFG_EBICSA);
+    /* Configure SMC CS3 */
+    writel((AT91C_SMC_NWESETUP_(1) | AT91C_SMC_NCS_WRSETUP_(0)   | AT91C_SMC_NRDSETUP_(1) | AT91C_SMC_NCS_RDSETUP_(0)), AT91C_BASE_SMC + SMC_SETUP3);
+    writel((AT91C_SMC_NWEPULSE_(3) | AT91C_SMC_NCS_WRPULSE_(3)   | AT91C_SMC_NRDPULSE_(3) | AT91C_SMC_NCS_RDPULSE_(3)), AT91C_BASE_SMC + SMC_PULSE3);
+    writel((AT91C_SMC_NWECYCLE_(5) | AT91C_SMC_NRDCYCLE_(5)), AT91C_BASE_SMC + SMC_CYCLE3);
+    writel((AT91C_SMC_READMODE  | AT91C_SMC_WRITEMODE   | (0x0 << 5) | AT91C_SMC_DBW_WIDTH_BITS_8 | AT91_SMC_TDF_(2)),    AT91C_BASE_SMC + SMC_CTRL3);
+    /* {"NANDCS", AT91C_PIN_PC(14), 1, PIO_PULLUP, PIO_OUTPUT} */
+    writel((0x01 << 14), 0xfffff800 + 0x0044);
+    writel((0x01 << 14), 0xfffff800 + 0x0060);
+    writel((0x01 << 14), 0xfffff800 + 0x0030);
+    writel((0x01 << 14), 0xfffff800 + 0x0010);
+    writel((0x01 << 14), 0xfffff800 + 0x0000);
+    /* enable PIOC clock  */
+    writel(0x01 << 4, 0x10 + AT91C_BASE_PMC);
+    i = at9260_nand_read_id(RT_NULL);
+    index = i;
+
+    chip->pagesize  = nand_ids[index].pagesize;
+    chip->blocksize = nand_ids[index].blocksize;
+    chip->oobsize   = nand_ids[index].oobsize;
+    chip->buswidth  = nand_ids[index].buswidth;
+    chip->numblocks = nand_ids[index].numblocks;
+
+    _partition[0].page_size = chip->pagesize;
+    _partition[1].page_size = chip->pagesize;
+    _partition[0].pages_per_block = chip->blocksize / chip->pagesize;
+      _partition[1].pages_per_block = chip->blocksize / chip->pagesize;
+    _partition[0].oob_size = _partition[1].oob_size = chip->oobsize;
+    _partition[0].oob_free = _partition[1].oob_free = chip->oobsize - (chip->pagesize / 256 * 3); //oob_free = oob_size - ecc_size
+
+
+    _partition[0].block_total  = DATA_PART_ADDR / (chip->blocksize);
+    _partition[0].block_start  = 0;
+    _partition[0].block_end    = DATA_PART_ADDR / (chip->blocksize) - 1;
+
+    _partition[1].block_total  = chip->numblocks - _partition[0].block_total;
+    _partition[1].block_start  = _partition[0].block_end + 1;
+    _partition[1].block_end    = chip->numblocks - 1;
+
+    _partition[0].ops = &_ops;
+      _partition[1].ops = &_ops;
+
+    rt_mtd_nand_register_device("nand0", &_partition[0]);
+    rt_mtd_nand_register_device("nand1", &_partition[1]);
+
+    return RT_EOK;
+}
+INIT_DEVICE_EXPORT(rt_hw_mtd_nand_init);
+
+#if defined(RT_USING_FINSH)
+#include <finsh.h>
+void nand_eraseall()
+{
+    int tmp=0;
+    int index=0;
+
+
+    if (chip->pagesize == 512)
+        tmp = (DATA_PART_ADDR / 0x4000);            //0X4000=512*32=PAGER_SIZE*PAGES_PER_BLOCK
+    else if (chip->pagesize == 2048)
+        tmp = (DATA_PART_ADDR / 0x20000);                     //0X20000=2048*64
+
+    for (index=tmp; index < chip->numblocks; index ++)
+    {
+        at9260_nand_erase_block(RT_NULL, index);
+    }
+}
+FINSH_FUNCTION_EXPORT(nand_eraseall, erase all of block in the nand flash);
+
+#endif //RT_USING_FINSH
+
+

+ 120 - 0
bsp/at91sam9260/drivers/at91_nand.h

@@ -0,0 +1,120 @@
+/*
+* Copyright (c) 2006-2022, RT-Thread Development Team
+*
+* SPDX-License-Identifier: Apache-2.0
+*
+* Change Logs:
+* Date           Author        Notes
+* 2022-01-08     brightsally   first version
+*/
+
+#ifndef _ATMEL_NAND_H_
+#define _ATMEL_NAND_H_
+
+
+/* NAND flash */
+#define DATA_PART_ADDR                  0x900000                /*nand0=0-9MB;nand1=9MB-END*/
+
+#define AT91C_BASE_CCFG                 0xffffef14
+#define CCFG_EBICSA                     0x08                    /* EBI Chip Select Assignement Register */
+#define AT91C_EBI_CS3A_SM               (0x1UL << 3)
+#define AT91C_BASE_SMC                  0xffffec00
+#define AT91C_BASE_PMC                  0xfffffc00
+#define SMC_SETUP3                      0x30                    /* Setup Register for CS 3 */
+#define SMC_PULSE3                      0x34                    /* Pulse Register for CS 3 */
+#define SMC_CYCLE3                      0x38                    /* Cycle Register for CS 3 */
+#define SMC_CTRL3                       0x3C                    /* Control Register for CS 3 */
+
+#define AT91C_SMC_NWESETUP_(x)          ((x) << 0)
+#define AT91C_SMC_NCS_WRSETUP_(x)       ((x) << 8)
+#define AT91C_SMC_NRDSETUP_(x)          ((x) << 16)
+#define AT91C_SMC_NCS_RDSETUP_(x)       ((x) << 24)
+#define AT91C_SMC_NWEPULSE_(x)          ((x) << 0)
+#define AT91C_SMC_NCS_WRPULSE_(x)       ((x) << 8)
+#define AT91C_SMC_NRDPULSE_(x)          ((x) << 16)
+#define AT91C_SMC_NCS_RDPULSE_(x)       ((x) << 24)
+
+#define AT91C_SMC_NWECYCLE_(x)          ((x) << 0)
+#define AT91C_SMC_NRDCYCLE_(x)          ((x) << 16)
+
+#define AT91C_SMC_READMODE              (0x1UL << 0)
+#define AT91C_SMC_WRITEMODE             (0x1UL << 1)
+#define AT91C_SMC_NWAITM                (0x3UL << 4)
+#define AT91C_SMC_DBW_WIDTH_BITS_8      (0x0UL << 12)
+#define AT91C_SMC_DBW_WIDTH_BITS_16     (0x1UL << 12)
+#define AT91C_SMC_DBW_WIDTH_BITS_32     (0x2UL << 12)
+#define AT91C_SMC_TDF                   (0xFUL << 16)
+#define AT91_SMC_TDF_(x)                ((x) << 16)
+
+#define CMD_STATUS                      0x70
+#define STATUS_READY                    (0x01 << 6)   /* Status code for Ready */
+#define STATUS_ERROR                    (0x01 << 0)   /* Status code for Error */
+
+/* Nand flash commands */
+#define CMD_READID                      0x90
+#define CMD_READ_1                      0x00
+#define CMD_READ_2                      0x30
+
+#define CMD_READ_A0                     0x00
+#define CMD_READ_A1                     0x01
+#define CMD_READ_C                      0x50
+
+#define CMD_WRITE_A                     0x00
+#define CMD_WRITE_C                     0x50
+
+#define CMD_WRITE_1                     0x80
+#define CMD_WRITE_2                     0x10
+
+#define CMD_ERASE_1                     0x60
+#define CMD_ERASE_2                     0xD0
+
+/* read/write/move page */
+#define CMD_REG                         0x40400000
+#define ADDR_REG                        0x40200000
+#define DATA_REG                        0x40000000
+
+/*Values returned by the CheckBlock() function
+GOOD = RT_EOK=0
+BAD = -1
+*/
+#define BADBLOCK        -RT_ERROR       //-1
+#define GOODBLOCK        RT_EOK         //0
+
+struct nand_oobfree
+{
+    unsigned int offset;
+    unsigned int length;
+};
+
+struct nand_ecclayout
+{
+    unsigned int eccbytes;
+    unsigned int eccpos[680];
+    unsigned int oobavail;
+    struct nand_oobfree oobfree[32];
+};
+
+struct nand_chip_id
+{
+    unsigned short  chip_id;            /* Nand Chip ID */
+    unsigned short  numblocks;          //0x1000=4096=4K            //4K*16K=64M
+    unsigned int    blocksize;          //0x4000=16K                //SECTOR
+    unsigned short  pagesize;           //0X200=512                 //1 BLOCK has pages=16K/512=32
+    unsigned char   oobsize;            //0X10=16
+    unsigned char   buswidth;
+};
+static struct nand_chip_id nand_ids[] =
+{
+
+    /* Samsung 32MB 8Bit SMALL BLOCK*/
+    {0xec75, 0x800, 0x4000,  0x200, 0x10, 0x0},    //32M
+    {0xec35, 0x800, 0x4000,  0x200, 0x10, 0x0},    //32M
+    {0xec36, 0x1000, 0x4000,  0x200, 0x10, 0x0},   //4K*16K=64M
+    /* Samsung 128MB 8bit BIG BLOCK*/
+    {0xeca1, 0x400, 0x20000, 0x800, 0x40, 0x0},    //128M
+    {0,}
+};
+
+
+int rt_hw_mtd_nand_init(void);
+#endif