9985e0a43e
Signed-off-by: wangbowen6 <wangbowen6@xiaomi.com>
986 lines
28 KiB
C
986 lines
28 KiB
C
/****************************************************************************
|
|
* arch/arm/src/tlsr82/tlsr82_flash_mtd.c
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership. The
|
|
* ASF licenses this file to you 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.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#include <assert.h>
|
|
#include <debug.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
|
|
#include <nuttx/irq.h>
|
|
#include <nuttx/mm/mm.h>
|
|
#include <nuttx/kmalloc.h>
|
|
|
|
#include "hardware/tlsr82_gpio.h"
|
|
#include "tlsr82_flash.h"
|
|
#include "tlsr82_flash_mtd.h"
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
|
|
#define MIN(a, b) (((a) > (b)) ? (b) : (a))
|
|
|
|
/* Flash size deifnitions */
|
|
|
|
#define TLSR82_SECTOR_SHIFT 12
|
|
#define TLSR82_SECTOR_SIZE (1 << TLSR82_SECTOR_SHIFT)
|
|
#define TLSR82_PAGE_SHIFT 8
|
|
#define TLSR82_PAGE_SIZE (1 << TLSR82_PAGE_SHIFT)
|
|
|
|
/* Flash layout definitions */
|
|
|
|
#define TLSR82_START_ADDR (0)
|
|
#define TLSR82_TOTAL_SIZE (512 * 1024)
|
|
|
|
#define TLSR82_BANKA_ADDR TLSR82_START_ADDR
|
|
#define TLSR82_BANKA_SIZE (240 * 1024)
|
|
|
|
#define TLSR82_USR_ADDR (TLSR82_BANKA_ADDR + TLSR82_BANKA_SIZE)
|
|
#define TLSR82_USR_SIZE (12 * 1024)
|
|
|
|
#define TLSR82_KEY_ADDR (TLSR82_USR_ADDR + TLSR82_USR_SIZE)
|
|
#define TLSR82_KEY_SIZE (4 * 1024)
|
|
|
|
#define TLSR82_BANKB_ADDR (TLSR82_KEY_ADDR + TLSR82_KEY_SIZE)
|
|
#define TLSR82_BANKB_SIZE (240 * 1024)
|
|
|
|
#define TLSR82_SYS_ADDR (TLSR82_BANKB_ADDR + TLSR82_BANKB_SIZE)
|
|
#define TLSR82_SYS_SIZE (16 * 1024)
|
|
|
|
/* Flash write buffer size definitions */
|
|
|
|
#ifdef CONFIG_TLSR82_FLASH_WRITE_BUFFER
|
|
# define FLASH_WRITE_BUF_SIZE CONFIG_TLSR82_FLASH_WRITE_BUFFER_SIZE
|
|
#endif
|
|
|
|
/* Flash test definitions */
|
|
|
|
#ifdef CONFIG_TLSR82_FLASH_TEST
|
|
|
|
/* Flash sector erase trace macro definition */
|
|
|
|
#define FLASH_ERASE_TRACE_START()
|
|
#define FLASH_ERASE_TRACE_END()
|
|
|
|
/* Flash page read/write trace macro definition */
|
|
|
|
#define FLASH_READ_TRACE_START()
|
|
#define FLASH_READ_TRACE_END()
|
|
|
|
#define FLASH_WRITE_TRACE_START()
|
|
#define FLASH_WRITE_TRACE_END()
|
|
|
|
/* Flash protect/unprotect trace marco definition */
|
|
|
|
#define FLASH_PROT_TRACE_START()
|
|
#define FLASH_PROT_TRACE_END()
|
|
|
|
#define FLASH_UNPROT_TRACE_START()
|
|
#define FLASH_UNPROT_TRACE_END()
|
|
|
|
#define FLASH_BUF_LIST16(n) \
|
|
n , n + 1, n + 2, n + 3, n + 4, n + 5, n + 6, n + 7, \
|
|
n + 8, n + 9, n + 10, n + 11, n + 12, n + 13, n + 14, n + 15,
|
|
|
|
#define FLASH_BUF_LIST128(n) \
|
|
FLASH_BUF_LIST16(n) \
|
|
FLASH_BUF_LIST16(n + 0x10) \
|
|
FLASH_BUF_LIST16(n + 0x20) \
|
|
FLASH_BUF_LIST16(n + 0x30) \
|
|
FLASH_BUF_LIST16(n + 0x40) \
|
|
FLASH_BUF_LIST16(n + 0x50) \
|
|
FLASH_BUF_LIST16(n + 0x60) \
|
|
FLASH_BUF_LIST16(n + 0x70) \
|
|
|
|
#endif
|
|
/****************************************************************************
|
|
* Private Types
|
|
****************************************************************************/
|
|
|
|
/* This type represents the state of the MTD device.
|
|
* The struct mtd_dev_s must appear at the beginning of the definition
|
|
* so that you can freely cast between pointers to struct mtd_dev_s and
|
|
* struct tlsr82_flash_dev_s.
|
|
*/
|
|
|
|
struct tlsr82_flash_dev_s
|
|
{
|
|
struct mtd_dev_s mtd; /* MTD interface */
|
|
uint32_t baseaddr; /* mtd flash start address */
|
|
uint32_t size; /* avaliable size for MTD */
|
|
uint16_t nsectors; /* Number of erase sectors */
|
|
uint16_t sectorsize; /* Size of one sector */
|
|
uint16_t pagesize; /* Size of one page */
|
|
};
|
|
|
|
struct tlsr82_partition_s
|
|
{
|
|
char *path;
|
|
off_t firstblock;
|
|
off_t nblocks;
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
/* Flash mtd partition table */
|
|
|
|
#ifdef CONFIG_MTD_PARTITION
|
|
static const struct tlsr82_partition_s tlsr82_part_table[] =
|
|
{
|
|
{
|
|
.path = "dev/banka",
|
|
.firstblock = TLSR82_BANKA_ADDR / TLSR82_PAGE_SIZE,
|
|
.nblocks = TLSR82_BANKA_SIZE / TLSR82_PAGE_SIZE,
|
|
},
|
|
{
|
|
.path = "dev/usr",
|
|
.firstblock = TLSR82_USR_ADDR / TLSR82_PAGE_SIZE,
|
|
.nblocks = TLSR82_USR_SIZE / TLSR82_PAGE_SIZE,
|
|
},
|
|
{
|
|
.path = "dev/key",
|
|
.firstblock = TLSR82_KEY_ADDR / TLSR82_PAGE_SIZE,
|
|
.nblocks = TLSR82_KEY_SIZE / TLSR82_PAGE_SIZE,
|
|
},
|
|
{
|
|
.path = "dev/bankb",
|
|
.firstblock = TLSR82_BANKB_ADDR / TLSR82_PAGE_SIZE,
|
|
.nblocks = TLSR82_BANKB_SIZE / TLSR82_PAGE_SIZE,
|
|
},
|
|
{
|
|
.path = "dev/sys",
|
|
.firstblock = TLSR82_SYS_ADDR / TLSR82_PAGE_SIZE,
|
|
.nblocks = TLSR82_SYS_SIZE / TLSR82_PAGE_SIZE,
|
|
}
|
|
};
|
|
#endif
|
|
|
|
/* Flash manufacture ID and unique ID */
|
|
|
|
static uint32_t g_flash_mid;
|
|
static uint8_t g_flash_uid[16];
|
|
|
|
/* Flash byte write buffer when enable the flash byte write buffer */
|
|
|
|
#ifdef CONFIG_TLSR82_FLASH_WRITE_BUFFER
|
|
static uint8_t flash_write_buffer[FLASH_WRITE_BUF_SIZE];
|
|
#endif
|
|
|
|
/* Flash test buffer when enable the flash test */
|
|
|
|
#ifdef CONFIG_TLSR82_FLASH_TEST
|
|
|
|
static uint8_t flash_buffer[TLSR82_PAGE_SIZE] =
|
|
{
|
|
FLASH_BUF_LIST128(0)
|
|
FLASH_BUF_LIST128(1)
|
|
};
|
|
|
|
static uint8_t flash_read_buffer[TLSR82_PAGE_SIZE];
|
|
static char print_buf[128];
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Public Data
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Private Function Prototypes
|
|
****************************************************************************/
|
|
|
|
/* Flash driver methods */
|
|
|
|
static int tlsr82_flash_chip_erase(struct tlsr82_flash_dev_s *priv);
|
|
|
|
#ifdef CONFIG_TLSR82_FLASH_TEST
|
|
static void tlsr82_flash_print(const char *msg, const uint8_t *buf,
|
|
size_t len);
|
|
|
|
static int tlsr82_flash_test(struct tlsr82_flash_dev_s *priv);
|
|
#endif
|
|
|
|
/* MTD driver methods */
|
|
|
|
static int tlsr82_flash_erase (struct mtd_dev_s *dev, off_t startblock,
|
|
size_t nblocks);
|
|
|
|
static ssize_t tlsr82_flash_bread (struct mtd_dev_s *dev, off_t startblock,
|
|
size_t nblocks, uint8_t *buf);
|
|
|
|
static ssize_t tlsr82_flash_bwrite(struct mtd_dev_s *dev, off_t startblock,
|
|
size_t nblocks, const uint8_t *buf);
|
|
|
|
static ssize_t tlsr82_flash_read (struct mtd_dev_s *dev, off_t offset,
|
|
size_t nbytes, uint8_t *buffer);
|
|
|
|
#ifdef CONFIG_MTD_BYTE_WRITE
|
|
static ssize_t tlsr82_flash_write (struct mtd_dev_s *dev, off_t offset,
|
|
size_t nbytes, const uint8_t *buffer);
|
|
#endif
|
|
|
|
static int tlsr82_flash_ioctl (struct mtd_dev_s *dev, int cmd,
|
|
unsigned long arg);
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: tlsr82_flash_readid
|
|
****************************************************************************/
|
|
|
|
static int tlsr82_flash_chip_erase(struct tlsr82_flash_dev_s *priv)
|
|
{
|
|
int i;
|
|
uint32_t addr;
|
|
|
|
addr = priv->baseaddr;
|
|
for (i = 0; i < priv->nsectors; i++)
|
|
{
|
|
finfo("Erase sector: %d, address: 0x%08lx\n", i, addr);
|
|
tlsr82_flash_erase_sector(addr);
|
|
addr += priv->sectorsize;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: tlsr82_flash_print
|
|
****************************************************************************/
|
|
|
|
#ifdef CONFIG_TLSR82_FLASH_TEST
|
|
static void tlsr82_flash_print(const char *msg, const uint8_t *buf,
|
|
size_t len)
|
|
{
|
|
int i = 0;
|
|
int off = 0;
|
|
|
|
ferr("%s\n", msg);
|
|
while (len--)
|
|
{
|
|
if (i % 16 == 0)
|
|
{
|
|
off += sprintf(&print_buf[off], "0x%08x:", i);
|
|
}
|
|
|
|
off += sprintf(&print_buf[off], "0x%02x ", buf[i]);
|
|
i++;
|
|
|
|
if (i % 16 == 0)
|
|
{
|
|
ferr("%s\n", print_buf);
|
|
off = 0;
|
|
}
|
|
}
|
|
|
|
if (i % 16 != 0)
|
|
{
|
|
ferr("%s\n", print_buf);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: tlsr82_flash_test
|
|
****************************************************************************/
|
|
|
|
#ifdef CONFIG_TLSR82_FLASH_TEST
|
|
static int tlsr82_flash_test(struct tlsr82_flash_dev_s *priv)
|
|
{
|
|
struct mtd_geometry_s geo;
|
|
int ret = OK;
|
|
int npages = 0;
|
|
int i = 0;
|
|
int j = 0;
|
|
|
|
ferr("======== Flash test start ========\n");
|
|
|
|
/* 1. print the manufacture id and unique id */
|
|
|
|
ret = 0;
|
|
ferr("Flash information print:\n");
|
|
ferr(" Flash MID: 0x%08lx\n", g_flash_mid);
|
|
ret += sprintf(&print_buf[ret], " Flash UID: ");
|
|
for (i = 1; i < 16; i++)
|
|
{
|
|
ret += sprintf(&print_buf[ret], "0x%x ", g_flash_uid[i]);
|
|
}
|
|
|
|
ferr("%s\n", print_buf);
|
|
|
|
ret = tlsr82_flash_ioctl(&priv->mtd, MTDIOC_GEOMETRY, (unsigned long)&geo);
|
|
if (ret != OK)
|
|
{
|
|
ferr(" Flash geometry get failed, ret=%d\n", ret);
|
|
goto errout;
|
|
}
|
|
|
|
npages = priv->nsectors * (TLSR82_SECTOR_SIZE / TLSR82_PAGE_SIZE);
|
|
|
|
ferr(" Flash Start Address: 0x%08lx\n", priv->baseaddr);
|
|
ferr(" Flash Size : 0x%08lx\n", priv->size);
|
|
ferr(" Flash Sector Size : %ld\n", geo.erasesize);
|
|
ferr(" Flash Page Size : %ld\n", geo.blocksize);
|
|
ferr(" Flash Sector : %ld\n", geo.neraseblocks);
|
|
ferr(" Flash Page : %d\n", npages);
|
|
|
|
/* 2. erase chip and check all the erased sector, all the bit in erased
|
|
* sector should be 1.
|
|
*/
|
|
|
|
ferr("Flash chip erase test start:\n");
|
|
|
|
FLASH_ERASE_TRACE_START();
|
|
ret = tlsr82_flash_ioctl(&priv->mtd, MTDIOC_BULKERASE, 0);
|
|
if (ret != OK)
|
|
{
|
|
ferr(" Flash erase failed, ret=%d\n", ret);
|
|
goto errout;
|
|
}
|
|
|
|
FLASH_ERASE_TRACE_END();
|
|
|
|
for (i = 0; i < npages; i++)
|
|
{
|
|
FLASH_READ_TRACE_START();
|
|
ret = tlsr82_flash_bread(&priv->mtd, i, 1, flash_read_buffer);
|
|
FLASH_READ_TRACE_END();
|
|
if (ret != 1)
|
|
{
|
|
ferr(" Flash block read failed, ret=%d\n", ret);
|
|
goto errout;
|
|
}
|
|
|
|
for (j = 0; j < TLSR82_PAGE_SIZE; j++)
|
|
{
|
|
if (flash_read_buffer[j] != 0xff)
|
|
{
|
|
ferr(" Flash erased data is not 0xff, page_i=%d, byte_j=%d,"
|
|
"data=0x%x\n", i, j, flash_read_buffer[j]);
|
|
goto errout;
|
|
}
|
|
}
|
|
}
|
|
|
|
ferr("Flach chip erase test Success.\n");
|
|
|
|
/* 3. Write all the flash and check result */
|
|
|
|
ferr("Flash page write/read test start:\n");
|
|
tlsr82_flash_print("Write buffer data:", flash_buffer,
|
|
TLSR82_PAGE_SIZE);
|
|
for (i = 0; i < npages; i++)
|
|
{
|
|
FLASH_WRITE_TRACE_START();
|
|
ret = tlsr82_flash_bwrite(&priv->mtd, i, 1, flash_buffer);
|
|
FLASH_WRITE_TRACE_END();
|
|
if (ret != 1)
|
|
{
|
|
ferr(" Flash block write failed, ret=%d\n", ret);
|
|
goto errout;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < npages; i++)
|
|
{
|
|
memset(flash_read_buffer, 0, TLSR82_PAGE_SIZE);
|
|
ret = tlsr82_flash_bread(&priv->mtd, i, 1, flash_read_buffer);
|
|
if (ret != 1)
|
|
{
|
|
ferr(" Flash block read failed, ret=%d\n", ret);
|
|
goto errout;
|
|
}
|
|
|
|
if (memcmp(flash_read_buffer, flash_buffer, TLSR82_PAGE_SIZE) != 0)
|
|
{
|
|
ferr(" Flash write compre is not equal, page_i=%d\n", i);
|
|
tlsr82_flash_print("Write buffer data:", flash_buffer,
|
|
TLSR82_PAGE_SIZE);
|
|
tlsr82_flash_print("Read buffer data:", flash_read_buffer,
|
|
TLSR82_PAGE_SIZE);
|
|
goto errout;
|
|
}
|
|
}
|
|
|
|
ferr("Flash page write/read test Success.\n");
|
|
|
|
#ifdef CONFIG_MTD_BYTE_WRITE
|
|
|
|
/* 4. Erase chip again for byte write/read test */
|
|
|
|
uint32_t offset = 0;
|
|
int k;
|
|
|
|
ferr("Erase chip for byte write test\n");
|
|
ret = tlsr82_flash_ioctl(&priv->mtd, MTDIOC_BULKERASE, 0);
|
|
if (ret != OK)
|
|
{
|
|
ferr(" Flash erase failed, ret=%d\n", ret);
|
|
goto errout;
|
|
}
|
|
|
|
ferr("Erase chip finished\n");
|
|
|
|
ferr("Flash byte read/write test start\n");
|
|
do
|
|
{
|
|
/* i = the write number, j = the flash_buffer index */
|
|
|
|
i = 40;
|
|
if (i + offset > priv->size)
|
|
{
|
|
i = priv->size - offset;
|
|
}
|
|
|
|
j = offset & 128;
|
|
|
|
FLASH_WRITE_TRACE_START();
|
|
ret = tlsr82_flash_write(&priv->mtd, offset, i, &flash_buffer[j]);
|
|
FLASH_WRITE_TRACE_END();
|
|
|
|
if (ret != i)
|
|
{
|
|
ferr(" Flash byte write failed, offset: 0x%08lx, ret=%d\n",
|
|
offset, ret);
|
|
goto errout;
|
|
}
|
|
|
|
memset(flash_read_buffer, 0, i);
|
|
|
|
FLASH_READ_TRACE_START();
|
|
ret = tlsr82_flash_read(&priv->mtd, offset, i, flash_read_buffer);
|
|
FLASH_READ_TRACE_END();
|
|
|
|
if (ret != i)
|
|
{
|
|
ferr(" Flash byte read failed, offset: 0x%08lx, ret=%d\n",
|
|
offset, ret);
|
|
goto errout;
|
|
}
|
|
|
|
for (k = 0; k < i; k++)
|
|
{
|
|
if (flash_buffer[j + k] != flash_read_buffer[k])
|
|
{
|
|
ferr(" Flash byte write/read compare failed\n");
|
|
ferr(" Flash address: 0x%08lx\n", priv->baseaddr + offset);
|
|
tlsr82_flash_print("Write Data:", &flash_buffer[j], i);
|
|
tlsr82_flash_print("Read Data:", flash_read_buffer, i);
|
|
goto errout;
|
|
}
|
|
}
|
|
|
|
offset += i;
|
|
}
|
|
while (offset < priv->size);
|
|
|
|
ferr("Flash byte read/write test Success\n");
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_TLSR82_FLASH_PROTECT
|
|
/* 5. Flash protect/unprotect test:
|
|
* 1) erase the chip;
|
|
* 2) write data into chip;
|
|
* 3) protect flash;
|
|
* 4) erase the chip with flash protected;
|
|
* 5) read the chip, the data should be same as the data written in 2);
|
|
*/
|
|
|
|
uint8_t status;
|
|
uint32_t addr;
|
|
|
|
/* 1) erase the chip */
|
|
|
|
ferr("Erase chip for protect/unprotect test\n");
|
|
ret = tlsr82_flash_ioctl(&priv->mtd, MTDIOC_BULKERASE, 0);
|
|
if (ret != OK)
|
|
{
|
|
ferr(" Flash erase failed, ret=%d\n", ret);
|
|
goto errout;
|
|
}
|
|
|
|
ferr("Erase chip finished\n");
|
|
|
|
/* 2) write data into chip */
|
|
|
|
tlsr82_flash_print("Write buffer data:", flash_buffer, TLSR82_PAGE_SIZE);
|
|
for (i = 0; i < npages; i++)
|
|
{
|
|
ret = tlsr82_flash_bwrite(&priv->mtd, i, 1, flash_buffer);
|
|
if (ret != 1)
|
|
{
|
|
ferr(" Flash block write failed, ret=%d\n", ret);
|
|
goto errout;
|
|
}
|
|
}
|
|
|
|
/* 3) protect the flash, read the flash status register */
|
|
|
|
FLASH_PROT_TRACE_START();
|
|
ret = tlsr82_flash_ioctl(&priv->mtd, MTDIOC_PROTECT, 0);
|
|
if (ret != OK)
|
|
{
|
|
ferr(" Flash protect failed, ret=%d\n", ret);
|
|
goto errout;
|
|
}
|
|
|
|
FLASH_PROT_TRACE_END();
|
|
|
|
status = tlsr82_flash_read_status(5);
|
|
ferr("Current flash status: 0x%x\n", status);
|
|
|
|
/* 4) erase the chip with flash protected */
|
|
|
|
addr = priv->baseaddr;
|
|
for (i = 0; i < priv->nsectors; i++)
|
|
{
|
|
tlsr82_flash_erase_sector(addr);
|
|
addr += priv->sectorsize;
|
|
}
|
|
|
|
FLASH_UNPROT_TRACE_START();
|
|
ret = tlsr82_flash_ioctl(&priv->mtd, MTDIOC_UNPROTECT, 0);
|
|
if (ret != OK)
|
|
{
|
|
ferr(" Flash unprotect failed, ret=%d\n", ret);
|
|
goto errout;
|
|
}
|
|
|
|
FLASH_UNPROT_TRACE_END();
|
|
|
|
/* 5) read the chip, the data should be same as the data written in 2) */
|
|
|
|
for (i = 0; i < npages; i++)
|
|
{
|
|
memset(flash_read_buffer, 0, TLSR82_PAGE_SIZE);
|
|
ret = tlsr82_flash_bread(&priv->mtd, i, 1, flash_read_buffer);
|
|
if (ret != 1)
|
|
{
|
|
ferr(" Flash block read failed, ret=%d\n", ret);
|
|
goto errout;
|
|
}
|
|
|
|
if (memcmp(flash_read_buffer, flash_buffer, TLSR82_PAGE_SIZE) != 0)
|
|
{
|
|
ferr(" Flash write compre is not equal, page_i=%d\n", i);
|
|
tlsr82_flash_print("Write buffer data:", flash_buffer,
|
|
TLSR82_PAGE_SIZE);
|
|
tlsr82_flash_print("Read buffer data:", flash_read_buffer,
|
|
TLSR82_PAGE_SIZE);
|
|
goto errout;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
ferr("======== Flash test Success ========\n");
|
|
|
|
return OK;
|
|
|
|
errout:
|
|
ferr("Flash test Failed.\n");
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: tlsr82_flash_erase
|
|
****************************************************************************/
|
|
|
|
static int tlsr82_flash_erase(struct mtd_dev_s *dev, off_t startblock,
|
|
size_t nblocks)
|
|
{
|
|
struct tlsr82_flash_dev_s *priv = (struct tlsr82_flash_dev_s *)dev;
|
|
size_t i;
|
|
uint32_t addr;
|
|
|
|
finfo("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
|
|
|
|
addr = priv->baseaddr + startblock * priv->sectorsize;
|
|
for (i = 0; i < nblocks; i++)
|
|
{
|
|
tlsr82_flash_erase_sector(addr);
|
|
addr += priv->sectorsize;
|
|
}
|
|
|
|
return (int)nblocks;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: tlsr82_flash_bread
|
|
****************************************************************************/
|
|
|
|
static ssize_t tlsr82_flash_bread(struct mtd_dev_s *dev, off_t startblock,
|
|
size_t nblocks, uint8_t *buffer)
|
|
{
|
|
struct tlsr82_flash_dev_s *priv = (struct tlsr82_flash_dev_s *)dev;
|
|
uint32_t addr;
|
|
size_t i;
|
|
|
|
finfo("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
|
|
|
|
addr = priv->baseaddr + startblock * priv->pagesize;
|
|
|
|
for (i = 0; i < nblocks; i++)
|
|
{
|
|
tlsr82_flash_read_data(addr, buffer, priv->pagesize);
|
|
addr += priv->pagesize;
|
|
buffer += priv->pagesize;
|
|
}
|
|
|
|
return nblocks;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: tlsr82_flash_bwrite
|
|
****************************************************************************/
|
|
|
|
static ssize_t tlsr82_flash_bwrite(struct mtd_dev_s *dev, off_t startblock,
|
|
size_t nblocks, const uint8_t *buffer)
|
|
{
|
|
struct tlsr82_flash_dev_s *priv = (struct tlsr82_flash_dev_s *)dev;
|
|
uint32_t addr;
|
|
size_t i;
|
|
|
|
finfo("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
|
|
|
|
addr = priv->baseaddr + startblock * priv->pagesize;
|
|
|
|
for (i = 0; i < nblocks; i++)
|
|
{
|
|
tlsr82_flash_write_data(addr, buffer, priv->pagesize);
|
|
addr += priv->pagesize;
|
|
buffer += priv->pagesize;
|
|
}
|
|
|
|
return nblocks;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: tlsr82_flash_read
|
|
****************************************************************************/
|
|
|
|
static ssize_t tlsr82_flash_read(struct mtd_dev_s *dev, off_t offset,
|
|
size_t nbytes, uint8_t *buffer)
|
|
{
|
|
struct tlsr82_flash_dev_s *priv = (struct tlsr82_flash_dev_s *)dev;
|
|
uint32_t addr;
|
|
|
|
finfo("offset: %08lx nbytes: %d\n", (long)offset, (int)nbytes);
|
|
|
|
addr = priv->baseaddr + offset;
|
|
|
|
tlsr82_flash_read_data(addr, buffer, nbytes);
|
|
|
|
finfo("return nbytes: %d\n", (int)nbytes);
|
|
return (ssize_t)nbytes;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: tlsr82_flash_write
|
|
****************************************************************************/
|
|
|
|
#ifdef CONFIG_MTD_BYTE_WRITE
|
|
static ssize_t tlsr82_flash_write (struct mtd_dev_s *dev, off_t offset,
|
|
size_t nbytes, const uint8_t *buffer)
|
|
{
|
|
struct tlsr82_flash_dev_s *priv = (struct tlsr82_flash_dev_s *)dev;
|
|
uint32_t addr;
|
|
size_t allow_len = 0;
|
|
size_t write_len = 0;
|
|
size_t len = nbytes;
|
|
|
|
finfo("offset: %08lx nbytes: %d\n", (long)offset, (int)nbytes);
|
|
|
|
addr = priv->baseaddr + offset;
|
|
|
|
do
|
|
{
|
|
/* The allow length is the max allow write lentgh that not cross page */
|
|
|
|
allow_len = TLSR82_PAGE_SIZE - (addr & (TLSR82_PAGE_SIZE - 1));
|
|
write_len = MIN(nbytes, allow_len);
|
|
|
|
#ifdef CONFIG_TLSR82_FLASH_WRITE_BUFFER
|
|
|
|
/* The write length can not be larger than FLASH_WRITE_BUF_SIZE */
|
|
|
|
write_len = MIN(FLASH_WRITE_BUF_SIZE, write_len);
|
|
|
|
/* Copy the data to the buffer and write, the temporary buffer is used
|
|
* to make sure the argument buffer is not in flash. Telink flash is
|
|
* not allowed read during flash writing.
|
|
*/
|
|
|
|
memcpy(flash_write_buffer, buffer, write_len);
|
|
tlsr82_flash_write_data(addr, flash_write_buffer, write_len);
|
|
#else
|
|
tlsr82_flash_write_data(addr, buffer, write_len);
|
|
#endif
|
|
|
|
addr += write_len;
|
|
buffer += write_len;
|
|
nbytes -= write_len;
|
|
}
|
|
while (nbytes > 0);
|
|
|
|
return (ssize_t)len;
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: tlsr82_flash_ioctl
|
|
****************************************************************************/
|
|
|
|
static int tlsr82_flash_ioctl(struct mtd_dev_s *dev, int cmd,
|
|
unsigned long arg)
|
|
{
|
|
struct tlsr82_flash_dev_s *priv = (struct tlsr82_flash_dev_s *)dev;
|
|
int ret = OK; /* Assume good command with good parameters */
|
|
|
|
finfo("cmd: %d\n", cmd);
|
|
|
|
switch (cmd)
|
|
{
|
|
case MTDIOC_GEOMETRY:
|
|
{
|
|
struct mtd_geometry_s *geo =
|
|
(struct mtd_geometry_s *)((uintptr_t)arg);
|
|
|
|
if (geo)
|
|
{
|
|
/* Populate the geometry structure with information need to
|
|
* know the capacity and how to access the device.
|
|
*
|
|
* NOTE:
|
|
* that the device is treated as though it where just an array
|
|
* of fixed size blocks. That is most likely not true, but
|
|
* the client will expect the device logic to do whatever is
|
|
* necessary to make it appear so.
|
|
*/
|
|
|
|
geo->blocksize = TLSR82_PAGE_SIZE;
|
|
geo->erasesize = TLSR82_SECTOR_SIZE;
|
|
geo->neraseblocks = priv->nsectors;
|
|
ret = OK;
|
|
|
|
finfo("blocksize: %" PRId32 " erasesize: %" PRId32
|
|
" neraseblocks: %" PRId32 "\n",
|
|
geo->blocksize, geo->erasesize, geo->neraseblocks);
|
|
}
|
|
else
|
|
{
|
|
ret = -EINVAL;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MTDIOC_BULKERASE:
|
|
{
|
|
tlsr82_flash_chip_erase(priv);
|
|
}
|
|
break;
|
|
|
|
case MTDIOC_PROTECT:
|
|
{
|
|
/* Ignore arg, direct protect full chip */
|
|
|
|
tlsr82_flash_protect();
|
|
}
|
|
break;
|
|
|
|
case MTDIOC_UNPROTECT:
|
|
{
|
|
/* Ignore arg, direct unprotect full chip */
|
|
|
|
tlsr82_flash_unprotect();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ret = -ENOTTY; /* Bad/unsupported command */
|
|
break;
|
|
}
|
|
|
|
finfo("return %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: tlsr82_flash_initialize
|
|
*
|
|
* Description:
|
|
* Create an initialize MTD device instance for the internal FLASH.
|
|
*
|
|
* MTD devices are not registered in the file system, but are created as
|
|
* instances that can be bound to other functions (such as a block or
|
|
* character driver front end).
|
|
*
|
|
* Parameter:
|
|
* offset - offset from 0 of internal flash
|
|
* size - avaiable size for NVM
|
|
*
|
|
****************************************************************************/
|
|
|
|
struct mtd_dev_s *tlsr82_flash_initialize(uint32_t offset, uint32_t size)
|
|
{
|
|
int ret;
|
|
struct tlsr82_flash_dev_s *priv;
|
|
|
|
/* If the mtd device address exceeded the flash address space, return
|
|
* NULL.
|
|
*/
|
|
|
|
if ((offset + size) > (CONFIG_TLSR82_FLASH_SIZE_KB * 1024))
|
|
{
|
|
goto errout;
|
|
}
|
|
|
|
/* Allocate a state structure (we allocate the structure instead of using
|
|
* a fixed, static allocation so that we can handle multiple FLASH devices.
|
|
* The current implementation would handle only one FLASH part per QuadSPI
|
|
* device (only because of the QSPIDEV_FLASH(0) definition) and so would
|
|
* have to be extended to handle multiple FLASH parts on the same QuadSPI
|
|
* bus.
|
|
*/
|
|
|
|
priv = (struct tlsr82_flash_dev_s *)
|
|
kmm_zalloc(sizeof(struct tlsr82_flash_dev_s));
|
|
if (priv)
|
|
{
|
|
/* Initialize the allocated structure (unsupported methods were
|
|
* nullified by kmm_zalloc).
|
|
*/
|
|
|
|
priv->mtd.erase = tlsr82_flash_erase;
|
|
priv->mtd.bread = tlsr82_flash_bread;
|
|
priv->mtd.bwrite = tlsr82_flash_bwrite;
|
|
priv->mtd.read = tlsr82_flash_read;
|
|
#ifdef CONFIG_MTD_BYTE_WRITE
|
|
priv->mtd.write = tlsr82_flash_write;
|
|
#endif
|
|
priv->mtd.ioctl = tlsr82_flash_ioctl;
|
|
priv->mtd.name = "tlsr82_flash_mtd";
|
|
|
|
priv->baseaddr = offset;
|
|
priv->size = size;
|
|
priv->sectorsize = TLSR82_SECTOR_SIZE;
|
|
priv->pagesize = TLSR82_PAGE_SIZE;
|
|
priv->nsectors = size >> TLSR82_SECTOR_SHIFT;
|
|
|
|
/* Identify the FLASH chip */
|
|
|
|
ret = tlsr82_flash_miduid_check(&g_flash_mid, &g_flash_uid[0]);
|
|
if (ret < 0)
|
|
{
|
|
ferr("Flash mid or uid error\n");
|
|
goto errout_with_priv;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ferr("Flash device malloc failed, size=%lu\n",
|
|
sizeof(struct tlsr82_flash_dev_s));
|
|
goto errout;
|
|
}
|
|
|
|
/* Calibrate the flash */
|
|
|
|
tlsr82_flash_calibrate(g_flash_mid);
|
|
|
|
#ifdef CONFIG_TLSR82_FLASH_TEST
|
|
ret = tlsr82_flash_test(priv);
|
|
if (ret < 0)
|
|
{
|
|
ferr("Flash test failed, ret=%d\n", ret);
|
|
goto errout_with_priv;
|
|
}
|
|
#endif
|
|
|
|
/* Return the implementation-specific state structure as the MTD device */
|
|
|
|
finfo("Return %p\n", priv);
|
|
return (struct mtd_dev_s *)priv;
|
|
|
|
errout_with_priv:
|
|
kmm_free(priv);
|
|
return NULL;
|
|
|
|
errout:
|
|
return NULL;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: tlsr82_partition_init
|
|
*
|
|
* Description:
|
|
* Register partition MTD device on the parent MTD device.
|
|
*
|
|
* Parameter:
|
|
* path - the parent mtd device path.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifdef CONFIG_MTD_PARTITION
|
|
int tlsr82_partition_init(const char *path)
|
|
{
|
|
int ret = OK;
|
|
int num;
|
|
int i;
|
|
|
|
num = sizeof(tlsr82_part_table) / sizeof(struct tlsr82_partition_s);
|
|
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
ret = register_mtdpartition(tlsr82_part_table[i].path, 0, path,
|
|
tlsr82_part_table[i].firstblock,
|
|
tlsr82_part_table[i].nblocks);
|
|
if (ret < 0)
|
|
{
|
|
ferr("Register mtd partition failed, path=%s, ret=%d\n",
|
|
tlsr82_part_table[i].path, ret);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif
|