SmartAudio/lichee/linux-4.9/modules/nand/sun8iw8p1/nandtest/nand_test.c

1308 lines
29 KiB
C
Executable File

/*
**********************************************************************************************************************
* Test
* software test for drivers
* Test Sub-System
*
* (c) Copyright 2007-2010, Grace.Miao China
* All Rights Reserved
*
* Moudle : test driver
* File : nand_test.c
* Purpose : test driver of nand driver in Linux
*
* By : Grace Miao
* Version : v1.0
* Date : 2011-3-16
* history :
* 2011-3-16 build the file Grace Miao
**********************************************************************************************************************
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/stat.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/scatterlist.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/cpufreq.h>
#include <linux/sched.h>
#include "../src/include/nand_type.h"
#include "../src/include/nand_drv_cfg.h"
#include "../src/include/nand_format.h"
#include "../src/include/nand_logic.h"
#include "../src/include/nand_oal.h"
#include "../src/include/nand_physic.h"
#include "../src/include/nand_scan.h"
#include "../src/include/nand_simple.h"
#include "../nfd/nand_blk.h"
#include "../nfd/mbr.h"
#include "nand_test.h"
#ifdef CONFIG_SUN4I_NANDFLASH_TEST /* open nand test module*/
#define NAND_TEST "[nand_test]:"
#define RESULT_OK (0)
#define RESULT_FAIL (1)
#define MAX_SECTORS (100) /* max alloc buffer*/
#define BUFFER_SIZE (512*MAX_SECTORS)
static ssize_t nand_test_store(struct kobject *kobject, struct attribute *attr,
const char *buf, size_t count);
static ssize_t nand_test_show(struct kobject *kobject, struct attribute *attr,
char *buf);
void obj_test_release(struct kobject *kobject);
struct nand_test_card {
u8 *buffer;
u8 *scratch;
unsigned int sector_cnt;
};
struct nand_test_case {
const char *name;
int sectors_cnt;
int (*prepare)(struct nand_test_card *, int sectors_cnt);
int (*run)(struct nand_test_card *);
int (*cleanup)(struct nand_test_card *);
};
struct attribute prompt_attr = {
.name = "nand_test",
.mode = S_IRWXUGO
};
static struct attribute *def_attrs[] = {
&prompt_attr,
NULL
};
struct sysfs_ops obj_test_sysops = {
.show = nand_test_show,
.store = nand_test_store
};
struct kobj_type ktype = {
.release = obj_test_release,
.sysfs_ops = &obj_test_sysops,
.default_attrs = def_attrs
};
void obj_test_release(struct kobject *kobject)
{
printk(NAND_TEST "release .\n");
}
/* prepare buffer data for read and write*/
static int __nand_test_prepare(struct nand_test_card *test, int sector_cnt,
int write)
{
int i;
test->sector_cnt = sector_cnt;
if (write) {
memset(test->buffer, 0xDF, 512 * (sector_cnt) + 4);
} else {
for (i = 0; i < 512 * (sector_cnt) + 4; i++) {
test->buffer[i] = i % 256;
}
}
return 0;
}
static int nand_test_prepare_write(struct nand_test_card *test, int sector_cnt)
{
return __nand_test_prepare(test, sector_cnt, 1);
}
static int nand_test_prepare_read(struct nand_test_card *test, int sector_cnt)
{
return __nand_test_prepare(test, sector_cnt, 0);
}
static int nand_test_prepare_pwm(struct nand_test_card *test, int sector_cnt)
{
test->sector_cnt = sector_cnt;
return 0;
}
/* read /write one sector with out verification*/
static int nand_test_simple_transfer(struct nand_test_card *test,
unsigned dev_addr, unsigned start,
unsigned nsector, int write)
{
int ret;
if (write) {
#ifndef NAND_CACHE_RW
ret = LML_Write(start, nsector, test->buffer + dev_addr);
#else
/*printk("Ws %lu %lu \n",start, nsector);*/
ret = NAND_CacheWrite(start, nsector, test->buffer + dev_addr);
#endif
if (ret) {
return -EIO;
}
return 0;
} else {
#ifndef NAND_CACHE_RW
LML_FlushPageCache();
ret = LML_Read(start, nsector, test->buffer + dev_addr);
#else
/*printk("Rs %lu %lu \n",start, nsector);*/
LML_FlushPageCache();
ret = NAND_CacheRead(start, nsector, test->buffer + dev_addr);
#endif /* read*/
if (ret) {
return -EIO;
}
return 0;
}
}
/* read /write one or more sectors with verification*/
static int nand_test_transfer(struct nand_test_card *test,
unsigned dev_addr, unsigned start,
unsigned nsector, int write)
{
int ret;
int i;
if (!write) {
ret = nand_test_simple_transfer(test, 0, start, nsector, 1); /* write to sectors for read*/
if (ret) {
return ret;
}
memset(test->buffer, 0, nsector * 512 + 4); /* clean mem for read*/
}
ret = nand_test_simple_transfer(test, dev_addr, start, nsector, write); /* read or write*/
if (ret) /* read or write*/
return ret;
if (write) {
memset(test->buffer, 0, nsector * 512 + 4); /* clean mem for read*/
ret = nand_test_simple_transfer(test, 0, start, nsector, 0); /* read*/
if (ret) {
return ret;
}
for (i = 0; i < nsector * 512; i++) { /* verify data*/
if (test->buffer[i] != 0xDF) {
printk(KERN_INFO
"[nand_test] Ttest->buffer[i] = %d, i = %d, dev_addr = %d, nsector = %d\n",
test->buffer[i], i, dev_addr, nsector);
return RESULT_FAIL;
}
}
} else { /*read*/
for (i = 0 + dev_addr; i < nsector * 512 + dev_addr; i++) { /* verify data*/
if (test->buffer[i] != (i - dev_addr) % 256) {
printk(KERN_INFO
"[nand_test] Ttest->buffer[i] = %d, i = %d, dev_addr = %d, nsector = %d\n",
test->buffer[i], i, dev_addr, nsector);
return RESULT_FAIL;
}
}
}
return RESULT_OK;
}
/* write one sector without verification*/
static int nand_test_single_write(struct nand_test_card *test)
{
int ret;
ret = nand_test_simple_transfer(test, 0, 0, test->sector_cnt, 1);
if (ret) {
return ret;
}
return nand_test_simple_transfer(test, 0, DiskSize / 2,
test->sector_cnt, 1);
}
/* read one sector without verification*/
static int nand_test_single_read(struct nand_test_card *test)
{
int ret;
ret = nand_test_simple_transfer(test, 0, 0, test->sector_cnt, 0);
if (ret) {
return ret;
}
return nand_test_simple_transfer(test, 0, DiskSize / 2,
test->sector_cnt, 0);
}
/* write one sector with verification */
static int nand_test_verify_write(struct nand_test_card *test)
{
return nand_test_transfer(test, 0, 1, test->sector_cnt, 1);
}
/* read one sector with verification */
static int nand_test_verify_read(struct nand_test_card *test)
{
return nand_test_transfer(test, 0, 1, test->sector_cnt, 0);
}
/* write multi sector with start sector num 5*/
static int nand_test_multi_write(struct nand_test_card *test)
{
return nand_test_transfer(test, 0, 5, test->sector_cnt, 1);
}
/* write multi sector with start sector num 29*/
static int nand_test_multi_read(struct nand_test_card *test)
{
return nand_test_transfer(test, 0, 29, test->sector_cnt, 0);
}
/* write from buffer+1, buffer+2, and buffer+3, where buffer is 4 bytes algin */
static int nand_test_align_write(struct nand_test_card *test)
{
int ret;
int i;
for (i = 1; i < 4; i++) {
ret = nand_test_transfer(test, i, 1, test->sector_cnt, 1);
}
return ret;
}
/* read to buffer+1, buffer+2, and buffer+3, where buffer is 4 bytes algin */
static int nand_test_align_read(struct nand_test_card *test)
{
int ret;
int i;
for (i = 1; i < 4; i++) {
ret = nand_test_transfer(test, i, 1, test->sector_cnt, 0);
}
if (ret) {
return ret;
}
return 0;
}
/* write to incorrect sector num such as -1, DiskSize, DiskSize +1 */
static int nand_test_negstart_write(struct nand_test_card *test)
{
int ret;
/* start + sectnum > 0, start < 0 */
ret = nand_test_simple_transfer(test, 0, -5, 11, 1);
if (!ret) {
return RESULT_FAIL;
}
printk(NAND_TEST "start + sectnum > 0 pass\n");
/* start + sectnum < 0 , start < 0 */
ret = nand_test_simple_transfer(test, 0, -62, 5, 1);
if (!ret) {
return RESULT_FAIL;
}
return RESULT_OK;
}
/* read from negative sector num start + sectnum > 0, and start + setnum < 0 */
static int nand_test_negstart_read(struct nand_test_card *test)
{
int ret;
/* start + sectnum > 0, start < 0 */
ret = nand_test_simple_transfer(test, 0, -1, 3, 0);
if (!ret) {
return RESULT_FAIL;
}
printk(NAND_TEST "start + sectnum > 0 pass\n");
/* start + sectnum < 0 , start < 0 */
ret = nand_test_simple_transfer(test, 0, -90, 15, 0);
if (!ret) {
return RESULT_FAIL;
}
return RESULT_OK;
}
static int nand_test_beyond(struct nand_test_card *test, int write)
{
int ret;
ret = nand_test_simple_transfer(test, 0, DiskSize - 3, 5, write);
if (!ret) {
return 1;
}
printk(NAND_TEST "DiskSize -3 , 5 pass\n");
ret = nand_test_simple_transfer(test, 0, DiskSize - 1, 2, write);
if (!ret) {
return 1;
}
printk(NAND_TEST "DiskSize -1 , 2 pass\n");
ret = nand_test_simple_transfer(test, 0, DiskSize, 3, write);
if (!ret) {
return 1;
}
printk(NAND_TEST "DiskSize , 3 pass\n");
ret = nand_test_simple_transfer(test, 0, DiskSize + 3, 0, write);
if (!ret) {
return 1;
}
printk(NAND_TEST "DiskSize + 3 , 0 pass\n");
ret = nand_test_simple_transfer(test, 0, DiskSize - 3, -2, write);
if (!ret) {
return 1;
}
printk(NAND_TEST "DiskSize - 3 , -2 pass\n");
return RESULT_OK;
}
static int nand_test_beyond_write(struct nand_test_card *test)
{
return nand_test_beyond(test, 1);
}
/* read from incorrect sector num such as -1, DiskSize(max sector num + 1), DiskSize +1 */
static int nand_test_beyond_read(struct nand_test_card *test)
{
return nand_test_beyond(test, 0);
}
/* write all sectors from sector num 0 to DiskSize - 1(max sector num )*/
static int nand_test_write_all_ascending(struct nand_test_card *test)
{
int ret;
int i = 0;
int j = 0;
printk(KERN_INFO "DiskSize = %x\n", DiskSize);
for (i = 0; i < DiskSize; i++) { /* write all sectors*/
ret =
nand_test_simple_transfer(test, 0, i, test->sector_cnt, 1);
if (ret) {
printk(KERN_INFO
"nand_test_write_all_ascending fail, sector num %d\n",
i);
return ret;
}
}
/* start check */
printk(KERN_INFO "[nand test]:start check\n");
for (i = 0; i < DiskSize; i++) {
memset(test->buffer, 0, test->sector_cnt * 512); /* clear buffer*/
ret = nand_test_simple_transfer(test, 0, i, test->sector_cnt, 0); /* read*/
if (ret) {
return ret;
}
for (j = 0; j < test->sector_cnt * 512; j++) { /* verify*/
if (test->buffer[j] != 0xDF) {
printk(KERN_INFO
"nand_test_write_all_ascending, Ttest->buffer[j] = %d, i = %d\n",
test->buffer[j], i);
return RESULT_FAIL;
}
}
}
return RESULT_OK;
}
/* read all sectors from sector num 0 to DiskSize - 1(max sector num )*/
static int nand_test_read_all_ascending(struct nand_test_card *test)
{
int ret;
int i = 0;
int j = 0;
/* before reading, write */
for (i = 0; i < DiskSize; i++) {
ret = nand_test_simple_transfer(test, 0, i, test->sector_cnt, 1); /* write all sectors*/
if (ret) {
printk(KERN_INFO
"nand_test_read_all_ascending fail, sector num %d\n",
i);
return ret;
}
}
/* finish write, start to read and check */
for (i = 0; i < DiskSize; i++) {
if (i % 100000 == 0) {
printk(KERN_INFO "[nand test]: sector num:%d\n", i);
}
memset(test->buffer, 0, test->sector_cnt * 512); /* clear buffer*/
ret = nand_test_simple_transfer(test, 0, i, test->sector_cnt, 0); /* read*/
if (ret) {
return ret;
}
for (j = 0; j < test->sector_cnt * 512; j++) {
if (test->buffer[j] != (j) % 256) {
printk(KERN_INFO
"nand_test_read_all_ascending fial! Ttest->buffer[j] = %d, i = %d\n",
test->buffer[i], j);
return RESULT_FAIL;
}
}
}
return RESULT_OK;
}
/* write all sectors from sector num DiskSize - 1(max sector num ) to 0 */
static int nand_test_write_all_descending(struct nand_test_card *test)
{
int ret;
int i = 0;
int j = 0;
printk(KERN_INFO "nand_test: DiskSize = %x\n", DiskSize);
for (i = DiskSize - 1; i >= 0; i--) {
memset(test->buffer, i % 256, 512);
if (i % 100000 == 0) {
printk(KERN_INFO "[nand test]: sector num:%d\n", i);
}
ret = nand_test_simple_transfer(test, 0, i, test->sector_cnt, 1); /* write all sectors*/
if (ret) {
printk(KERN_INFO
"[nand_test]: nand_test_write_all_ascending fail, sector num %d\n",
i);
return ret;
}
}
printk(KERN_INFO "[nand test]: check start\n");
for (i = DiskSize - 1; i >= 0; i--) {
if (i % 100000 == 0) {
printk(KERN_INFO "[nand test]: sector num:%d\n", i);
}
memset(test->buffer, 0, test->sector_cnt * 512); /* clear buffer*/
ret = nand_test_simple_transfer(test, 0, i, test->sector_cnt, 0); /* read*/
if (ret) {
return ret;
}
for (j = 0; j < 512; j++) { /* verify*/
if (test->buffer[j] != i % 256) {
printk(KERN_INFO
"[nand_test]: nand_test_write_all_ascending, Ttest->buffer[j] = %d, i = %d\n",
test->buffer[j], i);
return RESULT_FAIL;
}
}
}
return RESULT_OK;
}
/* read all sectors from sector num DiskSize - 1(max sector num ) to 0 */
static int nand_test_read_all_descending(struct nand_test_card *test)
{
int ret;
int i = 0;
int j = 0;
for (i = DiskSize - 1; i >= 0; i--) {
memset(test->buffer, i % 256, 512);
ret = nand_test_simple_transfer(test, 0, i, test->sector_cnt, 1); /* write all sectors*/
if (ret) {
printk(KERN_INFO
"[nand_test]: nand_test_read_all_ascending fail, sector num %d\n",
i);
return ret;
}
}
printk(KERN_INFO "[nand test]: check start\n");
for (i = DiskSize - 1; i >= 0; i--) {
if (i % 100000 == 0) {
printk(KERN_INFO "[nand test]: sector num:%d\n", i);
}
memset(test->buffer, 0, test->sector_cnt * 512); /* clear buffer*/
ret = nand_test_simple_transfer(test, 0, i, test->sector_cnt, 0); /* read*/
if (ret) {
return ret;
}
for (j = 0; j < test->sector_cnt * 512; j++) { /* verify data*/
if (test->buffer[j] != (i) % 256) {
printk(KERN_INFO
"[nand_test]:nand_test_read_all_ascending fial! Ttest->buffer[j] = %d, i = %d\n",
test->buffer[j], i);
return RESULT_FAIL;
}
}
}
return RESULT_OK;
}
/* write a sector for n times without verification to test stability */
static int nand_test_repeat_single_write(struct nand_test_card *test)
{
int ret;
int i = 0;
printk(NAND_TEST "DiskSize = %d\n", DiskSize);
for (i = 0; i < REPEAT_TIMES * 1000; i++) {
ret =
nand_test_simple_transfer(test, 0, DiskSize / 7,
test->sector_cnt, 1);
if (ret) {
return ret;
}
}
return 0;
}
/* read a sector for n times with verification to test stability*/
static int nand_test_repeat_single_read(struct nand_test_card *test)
{
int ret;
int i = 0;
for (i = 0; i < REPEAT_TIMES * 30; i++) {
ret =
nand_test_simple_transfer(test, 0, DiskSize / 4 + 7,
test->sector_cnt, 0);
if (ret) {
return ret;
}
}
return 0;
}
/* write multi sectors for n times without verification to test stability*/
static int nand_test_repeat_multi_write(struct nand_test_card *test)
{
int ret;
int i = 0;
for (i = 0; i < 1100000; i++) {
ret =
nand_test_simple_transfer(test, 0, DiskSize / 2,
test->sector_cnt, 1);
if (ret) {
return ret;
}
}
return 0;
}
/* read multi sectors for n times without verification to test stability*/
static int nand_test_repeat_multi_read(struct nand_test_card *test)
{
int ret;
int i = 0;
for (i = 0; i < 9200000; i++) {
ret =
nand_test_simple_transfer(test, 0, DiskSize / 3,
test->sector_cnt, 0);
if (ret) {
return ret;
}
}
return 0;
}
/* random write one or more sectors*/
static int nand_test_random_write(struct nand_test_card *test)
{
int ret;
ret = nand_test_simple_transfer(test, 0, 0, test->sector_cnt, 1);
if (ret) {
return ret;
}
ret =
nand_test_simple_transfer(test, 0, DiskSize - 1, test->sector_cnt,
1);
if (ret) {
return ret;
}
ret =
nand_test_simple_transfer(test, 0, DiskSize / 2, test->sector_cnt,
1);
if (ret) {
return ret;
}
return 0;
}
/* random read one or more sectors*/
static int nand_test_random_read(struct nand_test_card *test)
{
int ret;
ret = nand_test_simple_transfer(test, 0, 0, test->sector_cnt, 0);
if (ret) {
return ret;
}
ret =
nand_test_simple_transfer(test, 0, DiskSize - 1, test->sector_cnt,
0);
if (ret) {
return ret;
}
ret =
nand_test_simple_transfer(test, 0, DiskSize / 2, test->sector_cnt,
0);
if (ret) {
return ret;
}
return 0;
}
/* clear r/w buffer to 0*/
static int nand_test_cleanup(struct nand_test_card *test)
{
memset(test->buffer, 0, 512 * (test->sector_cnt));
return 0;
}
/* test cases */
static const struct nand_test_case nand_test_cases[] = {
{
.name = "single sector write (no data verification)",
.sectors_cnt = 1,
.prepare = nand_test_prepare_write,
.run = nand_test_single_write,
.cleanup = nand_test_cleanup
},
{
.name = "single sector read (no data verification)",
.sectors_cnt = 1,
.prepare = nand_test_prepare_read,
.run = nand_test_single_read,
.cleanup = nand_test_cleanup
},
{
.name = "single sector write(verify data)",
.sectors_cnt = 1,
.prepare = nand_test_prepare_write,
.run = nand_test_verify_write,
.cleanup = nand_test_cleanup
},
{
.name = "single sector read(verify data)",
.sectors_cnt = 1,
.prepare = nand_test_prepare_read,
.run = nand_test_verify_read,
.cleanup = nand_test_cleanup
},
/* multi read/write */
{
.name = "multi sector read(2 sectors, verify)",
.sectors_cnt = 2,
.prepare = nand_test_prepare_read,
.run = nand_test_multi_read,
.cleanup = nand_test_cleanup
},
{
.name = "multi sector read(3 sectors, verify)",
.sectors_cnt = 3,
.prepare = nand_test_prepare_read,
.run = nand_test_multi_read,
.cleanup = nand_test_cleanup
},
{
.name = "multi sector read(8 sectors, verify)",
.sectors_cnt = 8,
.prepare = nand_test_prepare_read,
.run = nand_test_multi_read,
.cleanup = nand_test_cleanup
},
{
.name = "multi sector read(18 sectors, verify)",
.sectors_cnt = 18,
.prepare = nand_test_prepare_read,
.run = nand_test_multi_read,
.cleanup = nand_test_cleanup
},
{
.name = "multi sector read(53 sectors, verify)",
.sectors_cnt = 53,
.prepare = nand_test_prepare_read,
.run = nand_test_multi_read,
.cleanup = nand_test_cleanup
},
{
.name = "multi sector write(2 sectors ,verify)",
.sectors_cnt = 2,
.prepare = nand_test_prepare_write,
.run = nand_test_multi_write,
.cleanup = nand_test_cleanup
},
{
.name = "multi sector write(5 sectors ,verify)",
.sectors_cnt = 5,
.prepare = nand_test_prepare_write,
.run = nand_test_multi_write,
.cleanup = nand_test_cleanup,
},
{
.name = "multi sector write(12 sectors ,verify)",
.sectors_cnt = 12,
.prepare = nand_test_prepare_write,
.run = nand_test_multi_write,
.cleanup = nand_test_cleanup,
},
{
.name = "multi sector write(15 sectors ,verify)",
.sectors_cnt = 15,
.prepare = nand_test_prepare_write,
.run = nand_test_multi_write,
.cleanup = nand_test_cleanup,
},
{
.name = "multi sector write(26 sectors ,verify)",
.sectors_cnt = 26,
.prepare = nand_test_prepare_write,
.run = nand_test_multi_write,
.cleanup = nand_test_cleanup,
},
{
.name = "multi sector write(93 sectors ,verify)",
.sectors_cnt = 93,
.prepare = nand_test_prepare_write,
.run = nand_test_multi_write,
.cleanup = nand_test_cleanup,
},
/*align test */
{
.name = "align write(1 sector ,verify)",
.sectors_cnt = 1,
.prepare = nand_test_prepare_write,
.run = nand_test_align_write,
.cleanup = nand_test_cleanup,
},
{
.name = "align read(1 sector ,verify)",
.sectors_cnt = 1,
.prepare = nand_test_prepare_read,
.run = nand_test_align_read,
.cleanup = nand_test_cleanup,
},
/* stability test */
{
.name = "weird write(negative start)", /* 18*/
.sectors_cnt = 10,
.prepare = nand_test_prepare_write,
.run = nand_test_negstart_write,
.cleanup = nand_test_cleanup,
},
{
.name = "weid read(nagative satrt)",
.sectors_cnt = 10,
.prepare = nand_test_prepare_read,
.run = nand_test_negstart_read,
.cleanup = nand_test_cleanup,
},
{
.name = "weird write(beyond start)", /* 20*/
.sectors_cnt = 10,
.prepare = nand_test_prepare_write,
.run = nand_test_beyond_write,
.cleanup = nand_test_cleanup,
},
{
.name = "weid read(bayond start)",
.sectors_cnt = 10,
.prepare = nand_test_prepare_read,
.run = nand_test_beyond_read,
.cleanup = nand_test_cleanup,
},
{
/* 22*/
.name = "write all ascending",
.sectors_cnt = 1,
.prepare = nand_test_prepare_write,
.run = nand_test_write_all_ascending,
.cleanup = nand_test_cleanup,
},
{
.name = "read all ascending",
.sectors_cnt = 1,
.prepare = nand_test_prepare_read,
.run = nand_test_read_all_ascending,
.cleanup = nand_test_cleanup,
},
{
.name = "write all descending",
.sectors_cnt = 1,
.prepare = nand_test_prepare_write,
.run = nand_test_write_all_descending,
.cleanup = nand_test_cleanup,
},
{
.name = "read all descending",
.sectors_cnt = 1,
.prepare = nand_test_prepare_read,
.run = nand_test_read_all_descending,
.cleanup = nand_test_cleanup,
},
{
/* 26*/
.name = " repeat write (no data verification) ",
.sectors_cnt = 1,
.prepare = nand_test_prepare_write,
.run = nand_test_repeat_single_write,
.cleanup = nand_test_cleanup,
},
{
/* 27*/
.name = " repeat read (no data verification) ",
.sectors_cnt = 1,
.prepare = nand_test_prepare_read,
.run = nand_test_repeat_single_read,
.cleanup = nand_test_cleanup,
},
{
/* 28*/
.name = " repeat multi write (no data verification)",
.sectors_cnt = 43,
.prepare = nand_test_prepare_write,
.run = nand_test_repeat_multi_write,
.cleanup = nand_test_cleanup,
},
{
/* 29*/
.name = " repeat multi read (no data verification)",
.sectors_cnt = 81,
.prepare = nand_test_prepare_read,
.run = nand_test_repeat_multi_read,
.cleanup = nand_test_cleanup,
},
{
/* 30*/
.name = " random write (no data verification)",
.sectors_cnt = 1,
.prepare = nand_test_prepare_write,
.run = nand_test_random_write,
.cleanup = nand_test_cleanup,
},
{
/* 31*/
.name = " random read (no data verification)",
.sectors_cnt = 1,
.prepare = nand_test_prepare_read,
.run = nand_test_random_read,
.cleanup = nand_test_cleanup,
},
{
/* 32*/
.name = " pwm test (no data verification)",
.sectors_cnt = 1,
.prepare = nand_test_prepare_pwm,
/*.run = nand_test_pwm,*/
.cleanup = nand_test_cleanup,
},
};
static DEFINE_MUTEX(nand_test_lock);
/* run test cases*/
static void nand_test_run(struct nand_test_card *test, int testcase)
{
int i, ret;
printk(KERN_INFO "[nand_test]: Starting tests of nand\n");
for (i = 0; i < ARRAY_SIZE(nand_test_cases); i++) {
if (testcase && ((i + 1) != testcase)) {
continue;
}
printk(KERN_INFO "[nand_test]: Test case %d. %s...\n", i + 1,
nand_test_cases[i].name);
if (nand_test_cases[i].prepare) {
ret =
nand_test_cases[i].prepare(test,
nand_test_cases[i].
sectors_cnt);
if (ret) {
printk(KERN_INFO
"[nand_test]: Result: Prepare stage failed! (%d)\n",
ret);
continue;
}
}
ret = nand_test_cases[i].run(test);
switch (ret) {
case RESULT_OK:
printk(KERN_INFO "[nand_test]: Result: OK\n");
break;
case RESULT_FAIL:
printk(KERN_INFO "[nand_test]:Result: FAILED\n");
break;
/* case RESULT_UNSUP_HOST: */ /*grace del*/
/* printk(KERN_INFO "%s: Result: UNSUPPORTED "*/
/* "(by host)\n",*/
/* mmc_hostname(test->card->host));*/
/* break;*/
/* case RESULT_UNSUP_CARD:*/
/* printk(KERN_INFO "%s: Result: UNSUPPORTED "*/
/* "(by card)\n",*/
/* mmc_hostname(test->card->host));*/
/* break;*/
default:
printk(KERN_INFO "[nand_test]:Result: ERROR (%d)\n",
ret);
}
if (nand_test_cases[i].cleanup) {
ret = nand_test_cases[i].cleanup(test);
if (ret) {
printk(KERN_INFO "[nand_test]:Warning: Cleanup"
"stage failed! (%d)\n", ret);
}
}
}
/*mmc_release_host(test->card->host);*/
printk(KERN_INFO "[nand_test]: Nand tests completed.\n");
}
/* do nothing */
static ssize_t nand_test_show(struct kobject *kobject, struct attribute *attr,
char *buf)
{
return 0;
}
/* receive testcase num from echo command */
static ssize_t nand_test_store(struct kobject *kobject, struct attribute *attr,
const char *buf, size_t count)
{
struct nand_test_card *test;
int testcase;
testcase = simple_strtol(buf, NULL, 10); /* get test case number >> grace*/
test = kzalloc(sizeof(struct nand_test_card), GFP_KERNEL);
if (!test) {
return -ENOMEM;
}
test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL); /* alloc buffer for r/w*/
test->scratch = kzalloc(BUFFER_SIZE, GFP_KERNEL); /* not used now*/
if (test->buffer && test->scratch) {
mutex_lock(&nand_test_lock);
nand_test_run(test, testcase); /* run test cases*/
mutex_unlock(&nand_test_lock);
}
kfree(test->buffer);
kfree(test->scratch);
kfree(test);
return count;
}
struct kobject kobj;
/* if nand driver is not inited , functions below will be used */
#ifdef INIT_NAND_IN_TESTDRIVER
static void set_nand_pio(void)
{
__u32 cfg0;
__u32 cfg1;
__u32 cfg2;
void *gpio_base;
/*modify for f20*/
gpio_base = (void *)SW_VA_PORTC_IO_BASE;
cfg0 = *(volatile __u32 *)(gpio_base + 0x48);
cfg1 = *(volatile __u32 *)(gpio_base + 0x4c);
cfg2 = *(volatile __u32 *)(gpio_base + 0x50);
/*set PIOC for nand */
cfg0 &= 0x0;
cfg0 |= 0x22222222;
cfg1 &= 0x0;
cfg1 |= 0x22222222;
cfg2 &= 0x0;
cfg2 |= 0x22222222;
*(volatile __u32 *)(gpio_base + 0x48) = cfg0;
*(volatile __u32 *)(gpio_base + 0x4c) = cfg1;
*(volatile __u32 *)(gpio_base + 0x50) = cfg2;
/*iounmap(gpio_base);*/
}
static __u32 get_cmu_clk(void)
{
__u32 reg_val;
__u32 div_p, factor_n;
__u32 factor_k, factor_m;
__u32 clock;
reg_val = *(volatile unsigned int *)(0xf1c20000 + 0x20);
div_p = (reg_val >> 16) & 0x3;
factor_n = (reg_val >> 8) & 0x1f;
factor_k = ((reg_val >> 4) & 0x3) + 1;
factor_m = ((reg_val >> 0) & 0x3) + 1;
clock = 24 * factor_n * factor_k / div_p / factor_m;
printk("cmu_clk is %d \n", clock);
return clock;
}
static void set_nand_clock(__u32 nand_max_clock)
{
__u32 edo_clk, cmu_clk;
__u32 cfg;
__u32 nand_clk_divid_ratio;
/*open ahb nand clk */
cfg = *(volatile __u32 *)(0xf1c20000 + 0x60);
cfg |= (0x1 << 13);
*(volatile __u32 *)(0xf1c20000 + 0x60) = cfg;
/*set nand clock */
/*edo_clk = (nand_max_clock > 20)?(nand_max_clock-10):nand_max_clock;*/
edo_clk = nand_max_clock * 2;
cmu_clk = get_cmu_clk();
nand_clk_divid_ratio = cmu_clk / edo_clk;
if (cmu_clk % edo_clk)
nand_clk_divid_ratio++;
if (nand_clk_divid_ratio) {
if (nand_clk_divid_ratio > 16)
nand_clk_divid_ratio = 15;
else
nand_clk_divid_ratio--;
}
/*set nand clock gate on */
cfg = *(volatile __u32 *)(0xf1c20000 + 0x80);
/*gate on nand clock */
cfg |= (1U << 31);
/*take cmu pll as nand src block */
cfg &= ~(0x3 << 24);
cfg |= (0x2 << 24);
/*set divn = 0*/
cfg &= ~(0x03 << 12);
/*set ratio */
cfg &= ~(0x0f << 0);
cfg |= (nand_clk_divid_ratio & 0xf) << 0;
*(volatile __u32 *)(0xf1c20000 + 0x80) = cfg;
printk("nand clk init end \n");
printk("offset 0xc: 0x%x \n", *(volatile __u32 *)(0xf1c20000 + 0x60));
printk("offset 0x14: 0x%x \n", *(volatile __u32 *)(0xf1c20000 + 0x80));
}
#endif
static int __init nand_test_init(void)
{
int ret;
#ifdef INIT_NAND_IN_TESTDRIVER
__u32 cmu_clk;
#endif
printk("[nand_test]:nand_test_init test init.\n");
ret = kobject_init_and_add(&kobj, &ktype, NULL, "nand");
if (ret != 0) {
return ret;
}
#ifdef INIT_NAND_IN_TESTDRIVER
/* init nand resource */
printk("[nand_test]:init nand resource \n");
/*set nand clk*/
set_nand_clock(20);
/*set nand pio*/
set_nand_pio();
clear_NAND_ZI();
printk
("/*********************************************************/ \n");
printk("[nand_test]: init nand block layer start \n");
printk
("/*********************************************************/ \n");
ret = PHY_Init();
if (ret) {
PHY_Exit();
return -1;
}
ret = SCN_AnalyzeNandSystem();
if (ret < 0) {
return ret;
}
ret = PHY_ChangeMode(1);
if (ret < 0) {
return ret;
}
ret = FMT_Init();
if (ret < 0) {
return ret;
}
ret = FMT_FormatNand();
if (ret < 0) {
return ret;
}
FMT_Exit();
/*init logic layer */
ret = LML_Init();
if (ret < 0) {
return ret;
}
#ifdef NAND_CACHE_RW
NAND_CacheOpen();
#endif
#endif
return 0; /* init success*/
}
static void __exit nand_test_exit(void)
{
printk("[nand_test]:nand test exit.\n");
kobject_del(&kobj);
#ifdef INIT_NAND_IN_TESTDRIVER
LML_FlushPageCache();
BMM_WriteBackAllMapTbl();
LML_Exit();
FMT_Exit();
PHY_Exit();
#ifdef NAND_CACHE_RW
NAND_CacheOpen();
#endif
#endif
return;
}
module_init(nand_test_init);
module_exit(nand_test_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Nand test driver");
MODULE_AUTHOR("Grace Miao");
#endif