常见问题
1.编译执行make时报文件系统权限不够的问题
==================================================
target/allwinner/v851s-lizard/tina_busybox-init-basefiles.mk is called to generate shell scripts
==================================================
(/home/book/workspace/tina-v853/openwrt/target/v851s/v851s-lizard/busybox-init-base-files_generate/rootfs_hook_squash.sh /home/book/workspace/tina-v853/openwrt/target/v851s/v851s-lizard/busybox-init-base-files >/dev/null) || { \
echo "Execute the /home/book/workspace/tina-v853/openwrt/target/v851s/v851s-lizard/busybox-init-base-files_generate/rootfs_hook_squash.sh is failed"; \
exit 1; \
}
/bin/sh: 1: /home/book/workspace/tina-v853/openwrt/target/v851s/v851s-lizard/busybox-init-base-files_generate/rootfs_hook_squash.sh: Permission denied
Execute the /home/book/workspace/tina-v853/openwrt/target/v851s/v851s-lizard/busybox-init-base-files_generate/rootfs_hook_squash.sh is failed
tina_busybox-init-base-files.mk:14: recipe for target 'all' failed
make[4]: *** [all] Error 1
make[4]: Leaving directory '/home/book/workspace/tina-v853/openwrt/target/v851s/v851s-lizard'
Makefile:228: recipe for target '/home/book/workspace/tina-v853/out/v851s/lizard/openwrt/build_dir/target/linux-v851s-lizard/busybox-init-base-files/.built' failed
make[3]: *** [/home/book/workspace/tina-v853/out/v851s/lizard/openwrt/build_dir/target/linux-v851s-lizard/busybox-init-base-files/.built] Error 2
make[3]: Leaving directory '/home/book/workspace/tina-v853/openwrt/package/allwinner/system/busybox-init-base-files'
time: package/subpackage/allwinner/system/busybox-init-base-files/compile#0.32#0.25#0.55
ERROR: package/subpackage/allwinner/system/busybox-init-base-files failed to build.
package/Makefile:114: recipe for target 'package/subpackage/allwinner/system/busybox-init-base-files/compile' failed
make[2]: *** [package/subpackage/allwinner/system/busybox-init-base-files/compile] Error 1
make[2]: Leaving directory '/home/book/workspace/tina-v853/openwrt/openwrt'
package/Makefile:110: recipe for target '/home/book/workspace/tina-v853/openwrt/openwrt/staging_dir/target/stamp/.package_compile' failed
make[1]: *** [/home/book/workspace/tina-v853/openwrt/openwrt/staging_dir/target/stamp/.package_compile] Error 2
make[1]: Leaving directory '/home/book/workspace/tina-v853/openwrt/openwrt'
/home/book/workspace/tina-v853/openwrt/openwrt/include/toplevel.mk:236: recipe for target 'world' failed
make: *** [world] Error 2
make: Leaving directory '/home/book/workspace/tina-v853/openwrt/openwrt'
INFO: build_openwrt_rootfs failed
解决办法是按如下方式增加文件权限
book@100ask:~/workspace/tina-v853$ chmod 755 /home/book/workspace/tina-v853/openwrt/target/v851s/v851s-lizard/busybox-init-base-files_generate/mk_extra_dir.sh
2.打包pack时提示文件系统大小太大
ERROR: dl file rootfs.fex size too large
ERROR: filename = rootfs.fex
ERROR: dl_file_size = 53760 sector
ERROR: part_size = 45360 sector
update_for_part_info -1
ERROR: update mbr file fail
ERROR: update_mbr failed
原本的part_size的值为45360,需要修改成dl_file_size的值53760
3.开发板启动时,启动nand失败
[ 4.087239]
[ 4.087836] device_chose finished 122!
[ 4.133404] Please append a correct "root=" boot option; here are the available partitions:
[ 4.142801] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
[ 4.152057] CPU: 0 PID: 1 Comm: swapper Not tainted 4.9.191 #1
[ 4.158582] Hardware name: sun8iw21
[ 4.162517] [<c010d5a0>] (unwind_backtrace) from [<c010a694>] (show_stack+0x10/0x14)
[ 4.171192] [<c010a694>] (show_stack) from [<c017050c>] (panic+0xac/0x2b8)
[ 4.178899] [<c017050c>] (panic) from [<c09012cc>] (mount_block_root+0x258/0x300)
[ 4.187284] [<c09012cc>] (mount_block_root) from [<c0901500>] (prepare_namespace+0x118/0x178)
[ 4.196834] [<c0901500>] (prepare_namespace) from [<c0900eb4>] (kernel_init_freeable+0x144/0x178)
[ 4.206771] [<c0900eb4>] (kernel_init_freeable) from [<c067464c>] (kernel_init+0x8/0x118)
[ 4.215932] [<c067464c>] (kernel_init) from [<c0106e08>] (ret_from_fork+0x14/0x2c)
[ 4.224410] ---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
[ 4.234532] sunxi dump enabled
[ 4.237944] dump regs done
[ 4.241001] flush cache done
[ 4.244239] crashdump enter
在/tina-v853/kernel/linux-4.9/drivers/mtd/awnand/spinand/physic/目录下,将我们提供的id.c文件替换原本目录中的id.c文件。id.c文件内容为:
// SPDX-License-Identifier: GPL-2.0
#define pr_fmt(fmt) "sunxi-spinand-phy: " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mtd/aw-spinand.h>
#include <linux/of.h>
#include "physic.h"
#define KB (1024)
#define MB (KB * 1024)
#define to_kb(size) (size / KB)
#define to_mb(size) (size / MB)
/* manufacture num */
#define MICRON_MANUFACTURE 0x2c
#define GD_MANUFACTURE 0xc8
#define ATO_MANUFACTURE 0x9b
#define WINBOND_MANUFACTURE 0xef
#define MXIC_MANUFACTURE 0xc2
#define TOSHIBA_MANUFACTURE 0x98
#define ETRON_MANUFACTURE 0xd5
#define XTXTECH_MANUFACTURE 0x0b
#define DSTECH_MANUFACTURE 0xe5
#define FORESEE_MANUFACTURE 0xcd
#define ZETTA_MANUFACTURE 0xba
#define FM_MANUFACTURE 0xa1
struct spinand_manufacture m;
struct aw_spinand_phy_info gigadevice[] = {
{
.Model = "GD5F1GQ4UCYIG",
.NandID = {0xc8, 0xb1, 0x48, 0xff, 0xff, 0xff, 0xff, 0xff},
.DieCntPerChip = 1,
.SectCntPerPage = 4,
.PageCntPerBlk = 64,
.BlkCntPerDie = 1024,
.OobSizePerPage = 64,
.OperationOpt = SPINAND_QUAD_READ | SPINAND_QUAD_PROGRAM |
SPINAND_DUAL_READ | SPINAND_ONEDUMMY_AFTER_RANDOMREAD,
.MaxEraseTimes = 50000,
.EccType = BIT3_LIMIT2_TO_6_ERR7,
.EccProtectedType = SIZE16_OFF0_LEN16,
.BadBlockFlag = BAD_BLK_FLAG_FRIST_1_PAGE,
},
{
.Model = "GD5F1GQ4UBYIG",
.NandID = {0xc8, 0xd1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
.DieCntPerChip = 1,
.SectCntPerPage = 4,
.PageCntPerBlk = 64,
.BlkCntPerDie = 1024,
.OobSizePerPage = 64,
.OperationOpt = SPINAND_QUAD_READ | SPINAND_QUAD_PROGRAM |
SPINAND_DUAL_READ,
.MaxEraseTimes = 50000,
.EccFlag = HAS_EXT_ECC_SE01,
.EccType = BIT4_LIMIT5_TO_7_ERR8_LIMIT_12,
.EccProtectedType = SIZE16_OFF4_LEN8_OFF4,
.BadBlockFlag = BAD_BLK_FLAG_FRIST_1_PAGE,
},
{
/* GD5F2GQ4UB9IG did not check yet */
.Model = "GD5F2GQ4UB9IG",
.NandID = {0xc8, 0xd2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
.DieCntPerChip = 1,
.SectCntPerPage = 4,
.PageCntPerBlk = 64,
.BlkCntPerDie = 2048,
.OobSizePerPage = 64,
.OperationOpt = SPINAND_QUAD_READ | SPINAND_QUAD_PROGRAM |
SPINAND_DUAL_READ,
.MaxEraseTimes = 50000,
.EccFlag = HAS_EXT_ECC_SE01,
.EccType = BIT4_LIMIT5_TO_7_ERR8_LIMIT_12,
.EccProtectedType = SIZE16_OFF4_LEN12,
.BadBlockFlag = BAD_BLK_FLAG_FRIST_1_PAGE,
},
{
.Model = "GD5F1GQ5UEYIG",
.NandID = {0xc8, 0x51, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
.DieCntPerChip = 1,
.SectCntPerPage = 4,
.PageCntPerBlk = 64,
.BlkCntPerDie = 1024,
.OobSizePerPage = 64,
.OperationOpt = SPINAND_QUAD_READ | SPINAND_QUAD_PROGRAM |
SPINAND_DUAL_READ,
.MaxEraseTimes = 50000,
.EccFlag = HAS_EXT_ECC_SE01,
.EccType = BIT4_LIMIT5_TO_7_ERR8_LIMIT_12,
.EccProtectedType = SIZE16_OFF4_LEN12,
.BadBlockFlag = BAD_BLK_FLAG_FRIST_1_PAGE,
},
{
.Model = "F50L1G41LB(2M)",
.NandID = {0xc8, 0x01, 0x7f, 0x7f, 0x7f, 0xff, 0xff, 0xff},
.DieCntPerChip = 1,
.SectCntPerPage = 4,
.PageCntPerBlk = 64,
.BlkCntPerDie = 1024,
.OobSizePerPage = 64,
.OperationOpt = SPINAND_QUAD_READ | SPINAND_QUAD_PROGRAM |
SPINAND_DUAL_READ | SPINAND_QUAD_NO_NEED_ENABLE,
.MaxEraseTimes = 65000,
.EccType = BIT2_LIMIT1_ERR2,
.EccProtectedType = SIZE16_OFF4_LEN4_OFF8,
.BadBlockFlag = BAD_BLK_FLAG_FIRST_2_PAGE,
},
{
.Model = "GD5F2GM7UEYI",
.NandID = {0xc8, 0x92, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
.DieCntPerChip = 1,
.SectCntPerPage = 4,
.PageCntPerBlk = 64,
.BlkCntPerDie = 2048,
.OobSizePerPage = 64,
.OperationOpt = SPINAND_QUAD_READ | SPINAND_QUAD_PROGRAM |
SPINAND_DUAL_READ,
.MaxEraseTimes = 50000,
.EccFlag = HAS_EXT_ECC_SE01,
.EccType = BIT4_LIMIT5_TO_7_ERR8_LIMIT_12,
.EccProtectedType = SIZE16_OFF0_LEN16,
.BadBlockFlag = BAD_BLK_FLAG_FRIST_1_PAGE,
},
};
struct aw_spinand_phy_info micron[] = {
{
.Model = "MT29F1G01ABAGDWB",
.NandID = {0x2c, 0x14, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
.DieCntPerChip = 1,
.SectCntPerPage = 4,
.PageCntPerBlk = 64,
.BlkCntPerDie = 1024,
.OobSizePerPage = 64,
.OperationOpt = SPINAND_QUAD_READ | SPINAND_QUAD_PROGRAM |
SPINAND_DUAL_READ | SPINAND_QUAD_NO_NEED_ENABLE,
.MaxEraseTimes = 65000,
.EccType = BIT3_LIMIT5_ERR2,
.EccProtectedType = SIZE16_OFF32_LEN16,
.BadBlockFlag = BAD_BLK_FLAG_FRIST_1_PAGE,
},
{
.Model = "MT29F2G01ABAGDWB",
.NandID = {0x2c, 0x24, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
.DieCntPerChip = 1,
.SectCntPerPage = 4,
.PageCntPerBlk = 64,
.BlkCntPerDie = 2048,
.OobSizePerPage = 64,
.OperationOpt = SPINAND_QUAD_READ | SPINAND_QUAD_PROGRAM |
SPINAND_DUAL_READ | SPINAND_QUAD_NO_NEED_ENABLE,
.MaxEraseTimes = 65000,
.EccType = BIT3_LIMIT5_ERR2,
.EccProtectedType = SIZE16_OFF32_LEN16,
.BadBlockFlag = BAD_BLK_FLAG_FRIST_1_PAGE,
},
};
struct aw_spinand_phy_info xtx[] = {
{
/* XTX26G02A */
.Model = "XTX26G02A",
.NandID = {0x0B, 0xE2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
.DieCntPerChip = 1,
.SectCntPerPage = 4,
.PageCntPerBlk = 64,
.BlkCntPerDie = 2048,
.OobSizePerPage = 64,
.OperationOpt = SPINAND_QUAD_READ | SPINAND_QUAD_PROGRAM |
SPINAND_DUAL_READ,
.MaxEraseTimes = 50000,
.ecc_status_shift = ECC_STATUS_SHIFT_2,
.EccType = BIT4_LIMIT5_TO_7_ERR8_LIMIT_12,
.EccProtectedType = SIZE16_OFF8_LEN16,
.BadBlockFlag = BAD_BLK_FLAG_FRIST_1_PAGE,
},
{
/* XTX26G02A */
.Model = "XTX26G01A",
.NandID = {0x0B, 0xE1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
.DieCntPerChip = 1,
.SectCntPerPage = 4,
.PageCntPerBlk = 64,
.BlkCntPerDie = 1024,
.OobSizePerPage = 64,
.OperationOpt = SPINAND_QUAD_READ | SPINAND_QUAD_PROGRAM |
SPINAND_DUAL_READ,
.MaxEraseTimes = 50000,
.ecc_status_shift = ECC_STATUS_SHIFT_2,
.EccType = BIT4_LIMIT5_TO_7_ERR8_LIMIT_12,
.EccProtectedType = SIZE16_OFF8_LEN16,
.BadBlockFlag = BAD_BLK_FLAG_FRIST_1_PAGE,
},
{
/* XT26G01C */
.Model = "XT26G01C",
.NandID = {0x0B, 0x11, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
.DieCntPerChip = 1,
.SectCntPerPage = 4,
.PageCntPerBlk = 64,
.BlkCntPerDie = 1024,
.OobSizePerPage = 64,
.OperationOpt = SPINAND_QUAD_READ | SPINAND_QUAD_PROGRAM |
SPINAND_DUAL_READ,
.MaxEraseTimes = 50000,
.ecc_status_shift = ECC_STATUS_SHIFT_4,
.EccType = BIT4_LIMIT5_TO_8_ERR9_TO_15,
.EccProtectedType = SIZE16_OFF0_LEN16,
.BadBlockFlag = BAD_BLK_FLAG_FRIST_1_PAGE,
},
{
/* XT26G02C */
.Model = "XT26G02CWSIG",
.NandID = {0x0B, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
.DieCntPerChip = 1,
.SectCntPerPage = 4,
.PageCntPerBlk = 64,
.BlkCntPerDie = 2048,
.OobSizePerPage = 64,
.OperationOpt = SPINAND_DUAL_READ | SPINAND_QUAD_PROGRAM |
SPINAND_DUAL_READ,
.MaxEraseTimes = 50000,
.ecc_status_shift = ECC_STATUS_SHIFT_2,
.EccType = BIT4_LIMIT5_TO_7_ERR8_LIMIT_12,
.EccProtectedType = SIZE16_OFF8_LEN16,
.BadBlockFlag = BAD_BLK_FLAG_FRIST_1_PAGE,
},
};
struct aw_spinand_phy_info fm[] = {
{
/* only rw stress test */
.Model = "FM25S01",
.NandID = {0xa1, 0xa1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
.DieCntPerChip = 1,
.SectCntPerPage = 4,
.PageCntPerBlk = 64,
.BlkCntPerDie = 1024,
.OobSizePerPage = 64,
.OperationOpt = SPINAND_QUAD_READ | SPINAND_QUAD_PROGRAM |
SPINAND_DUAL_READ | SPINAND_QUAD_NO_NEED_ENABLE,
.MaxEraseTimes = 65000,
.EccType = BIT2_LIMIT1_ERR2,
.EccProtectedType = SIZE16_OFF0_LEN16,
.BadBlockFlag = BAD_BLK_FLAG_FIRST_2_PAGE,
},
};
struct aw_spinand_phy_info etron[] = {
};
struct aw_spinand_phy_info toshiba[] = {
};
struct aw_spinand_phy_info ato[] = {
};
struct aw_spinand_phy_info mxic[] = {
{
.Model = "MX35LF1GE4AB",
.NandID = {0xc2, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
.DieCntPerChip = 1,
.SectCntPerPage = 4,
.PageCntPerBlk = 64,
.BlkCntPerDie = 1024,
.OobSizePerPage = 64,
.OperationOpt = SPINAND_QUAD_READ | SPINAND_QUAD_PROGRAM |
SPINAND_DUAL_READ,
.MaxEraseTimes = 65000,
.EccFlag = HAS_EXT_ECC_STATUS,
.EccType = BIT4_LIMIT3_TO_4_ERR15,
/**
* MX35LF1GE4AB should use SIZE16_OFF4_LEN12, however, in order
* to compatibility with versions already sent to customers,
* which do not use general physical layout, we used
* SIZE16_OFF4_LEN4_OFF8 instead.
*/
.EccProtectedType = SIZE16_OFF4_LEN4_OFF8,
.BadBlockFlag = BAD_BLK_FLAG_FIRST_2_PAGE,
},
{
.Model = "MX35LF2GE4AD",
.NandID = {0xc2, 0x26, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff},
.DieCntPerChip = 1,
.SectCntPerPage = 4,
.PageCntPerBlk = 64,
.BlkCntPerDie = 2048,
.OobSizePerPage = 64,
.OperationOpt = SPINAND_QUAD_READ | SPINAND_QUAD_PROGRAM |
SPINAND_DUAL_READ,
.MaxEraseTimes = 65000,
.EccFlag = HAS_EXT_ECC_STATUS,
.EccType = BIT4_LIMIT5_TO_8_ERR9_TO_15,
.EccProtectedType = SIZE16_OFF4_LEN4_OFF8,
.BadBlockFlag = BAD_BLK_FLAG_FIRST_2_PAGE,
},
};
struct aw_spinand_phy_info winbond[] = {
{
.Model = "W25N01GVZEIG",
.NandID = {0xef, 0xaa, 0x21, 0xff, 0xff, 0xff, 0xff, 0xff},
.DieCntPerChip = 1,
.SectCntPerPage = 4,
.PageCntPerBlk = 64,
.BlkCntPerDie = 1024,
.OobSizePerPage = 64,
.OperationOpt = SPINAND_QUAD_READ | SPINAND_QUAD_PROGRAM |
SPINAND_DUAL_READ,
.MaxEraseTimes = 65000,
.EccType = BIT2_LIMIT1_ERR2,
.EccProtectedType = SIZE16_OFF4_LEN4_OFF8,
.BadBlockFlag = BAD_BLK_FLAG_FRIST_1_PAGE,
},
};
struct aw_spinand_phy_info dosilicon[] = {
{
.Model = "DS35X1GAXXX",
.NandID = {0xe5, 0x71, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
.DieCntPerChip = 1,
.SectCntPerPage = 4,
.PageCntPerBlk = 64,
.BlkCntPerDie = 1024,
.OobSizePerPage = 64,
.OperationOpt = SPINAND_QUAD_READ | SPINAND_QUAD_PROGRAM |
SPINAND_DUAL_READ,
.MaxEraseTimes = 65000,
.EccType = BIT2_LIMIT1_ERR2,
.EccProtectedType = SIZE16_OFF4_LEN4_OFF8,
.BadBlockFlag = BAD_BLK_FLAG_FIRST_2_PAGE,
},
};
struct aw_spinand_phy_info foresee[] = {
{
.Model = "FS35ND01G-S1F1QWFI000",
.NandID = {0xcd, 0xb1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
.DieCntPerChip = 1,
.SectCntPerPage = 4,
.PageCntPerBlk = 64,
.BlkCntPerDie = 1024,
.OobSizePerPage = 64,
.OperationOpt = SPINAND_QUAD_READ | SPINAND_QUAD_PROGRAM |
SPINAND_DUAL_READ,
.MaxEraseTimes = 50000,
.EccType = BIT3_LIMIT3_TO_4_ERR7,
.EccProtectedType = SIZE16_OFF0_LEN16,
.BadBlockFlag = BAD_BLK_FLAG_FRIST_1_PAGE,
},
{
.Model = "FS35ND01G-S1Y2QWFI000",
.NandID = {0xcd, 0xea, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
.DieCntPerChip = 1,
.SectCntPerPage = 4,
.PageCntPerBlk = 64,
.BlkCntPerDie = 1024,
.OobSizePerPage = 64,
.OperationOpt = SPINAND_QUAD_READ | SPINAND_QUAD_PROGRAM |
SPINAND_DUAL_READ,
.MaxEraseTimes = 50000,
.EccType = BIT2_LIMIT1_ERR2,
.EccProtectedType = SIZE16_OFF0_LEN16,
.BadBlockFlag = BAD_BLK_FLAG_FRIST_1_PAGE,
},
{
.Model = "FS35SQA001G",
.NandID = {0xcd, 0x71, 0x71, 0xff, 0xff, 0xff, 0xff, 0xff},
.DieCntPerChip = 1,
.SectCntPerPage = 4,
.PageCntPerBlk = 64,
.BlkCntPerDie = 1024,
.OobSizePerPage = 64,
.OperationOpt = SPINAND_QUAD_READ | SPINAND_QUAD_PROGRAM |
SPINAND_DUAL_READ,
.MaxEraseTimes = 50000,
.EccType = BIT2_LIMIT1_ERR2,
.EccProtectedType = SIZE16_OFF0_LEN16,
.BadBlockFlag = BAD_BLK_FLAG_FRIST_1_PAGE,
}
};
struct aw_spinand_phy_info zetta[] = {
{
.Model = "ZD35Q1GAIB",
.NandID = {0xba, 0x71, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
.DieCntPerChip = 1,
.SectCntPerPage = 4,
.PageCntPerBlk = 64,
.BlkCntPerDie = 1024,
.OobSizePerPage = 64,
.OperationOpt = SPINAND_QUAD_READ | SPINAND_QUAD_PROGRAM |
SPINAND_DUAL_READ,
.MaxEraseTimes = 50000,
.EccType = BIT2_LIMIT1_ERR2,
.EccProtectedType = SIZE16_OFF4_LEN4_OFF8,
.BadBlockFlag = BAD_BLK_FLAG_FIRST_2_PAGE,
},
};
static const char *aw_spinand_info_model(struct aw_spinand_chip *chip)
{
struct aw_spinand_phy_info *pinfo = chip->info->phy_info;
return pinfo->Model;
}
static void aw_spinand_info_nandid(struct aw_spinand_chip *chip,
unsigned char *id, int cnt)
{
int i;
struct aw_spinand_phy_info *pinfo = chip->info->phy_info;
cnt = min(cnt, MAX_ID_LEN);
for (i = 0; i < cnt; i++)
id[i] = pinfo->NandID[i];
}
static unsigned int aw_spinand_info_sector_size(struct aw_spinand_chip *chip)
{
return 1 << SECTOR_SHIFT;
}
static unsigned int aw_spinand_info_phy_page_size(struct aw_spinand_chip *chip)
{
struct aw_spinand_phy_info *pinfo = chip->info->phy_info;
return pinfo->SectCntPerPage * aw_spinand_info_sector_size(chip);
}
static unsigned int aw_spinand_info_page_size(struct aw_spinand_chip *chip)
{
#if IS_ENABLED(CONFIG_AW_SPINAND_SIMULATE_MULTIPLANE)
return aw_spinand_info_phy_page_size(chip) * 2;
#else
return aw_spinand_info_phy_page_size(chip);
#endif
}
static unsigned int aw_spinand_info_phy_block_size(
struct aw_spinand_chip *chip)
{
struct aw_spinand_phy_info *pinfo = chip->info->phy_info;
return pinfo->PageCntPerBlk * aw_spinand_info_phy_page_size(chip);
}
static unsigned int aw_spinand_info_block_size(struct aw_spinand_chip *chip)
{
struct aw_spinand_phy_info *pinfo = chip->info->phy_info;
return pinfo->PageCntPerBlk * aw_spinand_info_page_size(chip);
}
static unsigned int aw_spinand_info_phy_oob_size(struct aw_spinand_chip *chip)
{
struct aw_spinand_phy_info *pinfo = chip->info->phy_info;
return pinfo->OobSizePerPage;
}
static unsigned int aw_spinand_info_oob_size(struct aw_spinand_chip *chip)
{
#if IS_ENABLED(CONFIG_AW_SPINAND_SIMULATE_MULTIPLANE)
return aw_spinand_info_phy_oob_size(chip) * 2;
#else
return aw_spinand_info_phy_oob_size(chip);
#endif
}
static unsigned int aw_spinand_info_die_cnt(struct aw_spinand_chip *chip)
{
struct aw_spinand_phy_info *pinfo = chip->info->phy_info;
return pinfo->DieCntPerChip;
}
static unsigned int aw_spinand_info_total_size(struct aw_spinand_chip *chip)
{
struct aw_spinand_phy_info *pinfo = chip->info->phy_info;
return pinfo->DieCntPerChip * pinfo->BlkCntPerDie *
aw_spinand_info_phy_block_size(chip);
}
static int aw_spinand_info_operation_opt(struct aw_spinand_chip *chip)
{
struct aw_spinand_phy_info *pinfo = chip->info->phy_info;
return pinfo->OperationOpt;
}
static int aw_spinand_info_max_erase_times(struct aw_spinand_chip *chip)
{
struct aw_spinand_phy_info *pinfo = chip->info->phy_info;
return pinfo->MaxEraseTimes;
}
struct spinand_manufacture {
unsigned char id;
const char *name;
struct aw_spinand_phy_info *info;
unsigned int cnt;
};
#define SPINAND_FACTORY_INFO(_id, _name, _info) \
{ \
.id = _id, \
.name = _name, \
.info = _info, \
.cnt = ARRAY_SIZE(_info), \
}
static struct spinand_manufacture spinand_factory[] = {
SPINAND_FACTORY_INFO(MICRON_MANUFACTURE, "Micron", micron),
SPINAND_FACTORY_INFO(GD_MANUFACTURE, "GD", gigadevice),
SPINAND_FACTORY_INFO(ATO_MANUFACTURE, "ATO", ato),
SPINAND_FACTORY_INFO(WINBOND_MANUFACTURE, "Winbond", winbond),
SPINAND_FACTORY_INFO(MXIC_MANUFACTURE, "Mxic", mxic),
SPINAND_FACTORY_INFO(TOSHIBA_MANUFACTURE, "Toshiba", toshiba),
SPINAND_FACTORY_INFO(ETRON_MANUFACTURE, "Etron", etron),
SPINAND_FACTORY_INFO(XTXTECH_MANUFACTURE, "XTX", xtx),
SPINAND_FACTORY_INFO(DSTECH_MANUFACTURE, "Dosilicon", dosilicon),
SPINAND_FACTORY_INFO(FORESEE_MANUFACTURE, "Foresee", foresee),
SPINAND_FACTORY_INFO(ZETTA_MANUFACTURE, "Zetta", zetta),
SPINAND_FACTORY_INFO(FM_MANUFACTURE, "FM", fm),
};
static int spinand_get_chip_munufacture(struct aw_spinand_chip *chip, const char **m)
{
struct aw_spinand_phy_info *info = chip->info->phy_info;
switch (info->NandID[0]) {
case MICRON_MANUFACTURE:
*m = "Micron";
break;
case GD_MANUFACTURE:
*m = "GD";
break;
case ATO_MANUFACTURE:
*m = "ATO";
break;
case WINBOND_MANUFACTURE:
*m = "Winbond";
break;
case MXIC_MANUFACTURE:
*m = "Mxic";
break;
case TOSHIBA_MANUFACTURE:
*m = "Toshiba";
break;
case ETRON_MANUFACTURE:
*m = "Etron";
break;
case XTXTECH_MANUFACTURE:
*m = "XTX";
break;
case DSTECH_MANUFACTURE:
*m = "Dosilicon";
break;
case FORESEE_MANUFACTURE:
*m = "Foresee";
break;
case ZETTA_MANUFACTURE:
*m = "Zetta";
break;
default:
*m = NULL;
break;
}
if (*m == NULL)
return false;
else
return true;
}
static const char *aw_spinand_info_manufacture(struct aw_spinand_chip *chip)
{
int i, j;
struct spinand_manufacture *m;
struct aw_spinand_phy_info *pinfo;
const char *m_name = NULL;
int ret = 0;
for (i = 0; i < ARRAY_SIZE(spinand_factory); i++) {
m = &spinand_factory[i];
pinfo = chip->info->phy_info;
for (j = 0; j < m->cnt; j++)
if (pinfo == &m->info[j])
return m->name;
}
/*for compatible fdt support spi-nand*/
ret = spinand_get_chip_munufacture(chip, &m_name);
if (ret < 0)
return NULL;
else
return m_name;
}
static struct spinand_manufacture *spinand_detect_munufacture(unsigned char id)
{
int index;
struct spinand_manufacture *m;
for (index = 0; index < ARRAY_SIZE(spinand_factory); index++) {
m = &spinand_factory[index];
if (m->id == id) {
pr_info("detect munufacture from id table: %s\n", m->name);
return m;
}
}
pr_err("not detect any munufacture from id table\n");
return NULL;
}
static struct aw_spinand_phy_info *spinand_match_id(
struct spinand_manufacture *m,
unsigned char *id)
{
int i, j, match_max = 1, match_index = 0;
struct aw_spinand_phy_info *pinfo;
for (i = 0; i < m->cnt; i++) {
int match = 1;
pinfo = &m->info[i];
for (j = 1; j < MAX_ID_LEN; j++) {
/* 0xFF matching all ID value */
if (pinfo->NandID[j] != id[j] &&
pinfo->NandID[j] != 0xFF)
break;
if (pinfo->NandID[j] != 0xFF)
match++;
}
if (match > match_max) {
match_max = match;
match_index = i;
}
}
if (match_max > 1)
return &m->info[match_index];
return NULL;
}
struct aw_spinand_phy_info *spinand_get_phy_info_from_fdt(struct aw_spinand_chip *chip)
{
static struct aw_spinand_phy_info info;
static int had_get;
int ret = 0;
const char *bad_blk_mark_pos = NULL;
const char *quad_read_not_need_enable = NULL;
const char *read_seq_need_onedummy = NULL;
int len = 0;
u32 id = 0xffffffff;
struct device_node *node = chip->spi->dev.of_node;
u32 rx_bus_width = 0;
u32 tx_bus_width = 0;
if (had_get == true)
return &info;
#define BAD_BLK_MARK_POS1 "first_1_page"
#define BAD_BLK_MARK_POS2 "first_2_page"
#define BAD_BLK_MARK_POS3 "last_1_page"
#define BAD_BLK_MARK_POS4 "last_2_page"
memset(&info, 0, sizeof(struct aw_spinand_phy_info));
ret = of_property_read_string(node, "model", &(info.Model));
if (ret < 0) {
pr_err("get spi-nand Model from fdt fail\n");
goto err;
}
ret = of_property_read_u32(node, "id-0", &id);
if (ret < 0) {
pr_err("get spi-nand id Low 4 Byte from fdt fail\n");
goto err;
}
len = sizeof(id);
memmove(info.NandID, &id, min(MAX_ID_LEN, len));
id = 0xffffffff;
ret = of_property_read_u32(node, "id-1", &id);
if (ret < 0) {
pr_info("can't get spi-nand id high 4 Byte from fdt, may be not need\n");
}
memmove(info.NandID + min(MAX_ID_LEN, len), &id, max(MAX_ID_LEN, len) - min(MAX_ID_LEN, len));
ret = of_property_read_u32(node, "die_cnt_per_chip", &(info.DieCntPerChip));
if (ret < 0) {
pr_err("get spi-nand DieCntPerChip from fdt fail\n");
goto err;
}
ret = of_property_read_u32(node, "blk_cnt_per_die", &(info.BlkCntPerDie));
if (ret < 0) {
pr_err("get spi-nand BlkCntPerDie from fdt fail\n");
goto err;
}
ret = of_property_read_u32(node, "page_cnt_per_blk", &(info.PageCntPerBlk));
if (ret < 0) {
pr_err("get spi-nand PageCntPerBlk from fdt fail\n");
goto err;
}
ret = of_property_read_u32(node, "sect_cnt_per_page", &(info.SectCntPerPage));
if (ret < 0) {
pr_err("get spi-nand SectCntPerPage from fdt fail\n");
goto err;
}
ret = of_property_read_u32(node, "oob_size_per_page", &(info.OobSizePerPage));
if (ret < 0) {
pr_err("get spi-nand OobSizePerPage from fdt fail\n");
goto err;
}
ret = of_property_read_string(node, "bad_block_mark_pos", &bad_blk_mark_pos);
if (ret < 0 || NULL == bad_blk_mark_pos) {
pr_err("get spi-nand BadBlockFlag from fdt fail\n");
goto err;
} else {
if (!memcmp(bad_blk_mark_pos, BAD_BLK_MARK_POS1, strlen(BAD_BLK_MARK_POS1)))
info.BadBlockFlag = BAD_BLK_FLAG_FRIST_1_PAGE;
else if (!memcmp(bad_blk_mark_pos, BAD_BLK_MARK_POS2, strlen(BAD_BLK_MARK_POS2)))
info.BadBlockFlag = BAD_BLK_FLAG_FRIST_1_PAGE;
else if (!memcmp(bad_blk_mark_pos, BAD_BLK_MARK_POS3, strlen(BAD_BLK_MARK_POS3)))
info.BadBlockFlag = BAD_BLK_FLAG_LAST_1_PAGE;
else if (!memcmp(bad_blk_mark_pos, BAD_BLK_MARK_POS4, strlen(BAD_BLK_MARK_POS4)))
info.BadBlockFlag = BAD_BLK_FLAG_LAST_2_PAGE;
else {
pr_err("get spi-nand BadBlockFlag pattern is not right\n");
goto err;
}
}
ret = of_property_read_s32(node, "max_erase_times", &(info.MaxEraseTimes));
if (ret < 0) {
pr_err("get spi-nand MaxEraseTimes from fdt fail\n");
goto err;
}
ret = of_property_read_u32(node, "ecc_type", &(info.EccType));
if (ret < 0) {
pr_err("get spi-nand EccFlag from fdt fail\n");
goto err;
}
ret = of_property_read_u32(node, "ecc_protected_type", &(info.EccProtectedType));
if (ret < 0) {
pr_err("get spi-nand ecc_protected_type from fdt fail\n");
goto err;
}
ret = of_property_read_u32(node, "spi-rx-bus-width", &rx_bus_width);
if (ret < 0) {
pr_err("get spi-nand spi-rx-bus-width from fdt fail\n");
goto err;
} else {
switch (rx_bus_width) {
case SPI_NBITS_DUAL:
info.OperationOpt |= SPINAND_DUAL_READ;
break;
case SPI_NBITS_QUAD:
info.OperationOpt |= SPINAND_QUAD_READ;
break;
default:
info.OperationOpt |= 0;
break;
}
}
ret = of_property_read_u32(node, "spi-tx-bus-width", &tx_bus_width);
if (ret < 0) {
pr_err("get spi-nand spi-tx-bus-width from fdt fail\n");
goto err;
} else {
switch (tx_bus_width) {
case SPI_NBITS_QUAD:
info.OperationOpt |= SPINAND_QUAD_PROGRAM;
break;
default:
info.OperationOpt |= 0;
break;
}
}
ret = of_property_read_string(node, "read_from_cache_x4_not_need_enable",
&quad_read_not_need_enable);
pr_info("%d quad_read_not_need_enable:%s\n", __LINE__, quad_read_not_need_enable);
if (ret < 0 || NULL == quad_read_not_need_enable) {
pr_info("can't get spi-nand read_from_cache_x4_need_enable or it is null,"
" maybe not need enable quad read before read from cache x4\n");
} else {
if (!memcmp(quad_read_not_need_enable, "yes", strlen("yes")))
info.OperationOpt |= SPINAND_QUAD_NO_NEED_ENABLE;
}
ret = of_property_read_string(node, "read_from_cache_need_onedummy",
&read_seq_need_onedummy);
if (ret < 0 || NULL == read_seq_need_onedummy) {
pr_info("can't get spi-nand read_from_cache_need_onedummy or it is null,"
" maybe read from cache sequence not need one dummy in second Byte\n");
} else {
if (!memcmp(read_seq_need_onedummy, "yes", strlen("yes")))
info.OperationOpt |= SPINAND_ONEDUMMY_AFTER_RANDOMREAD;
}
ret = of_property_read_s32(node, "ecc_flag", &(info.EccFlag));
if (ret < 0) {
pr_err("can't get spi-nand EccFlag from fdt,"
" maybe(default) use 0FH + C0H to get feature,wich obtain ecc status\n");
}
ret = of_property_read_u32(node, "ecc_status_shift", &(info.ecc_status_shift));
if (ret < 0) {
pr_info("can't get spi-nand ecc_status_shift from fdt,"
" use default ecc_status_shift_4 to get ecc status in C0H\n");
}
pr_debug("get spinand phy info from fdt\n");
pr_debug("Model:%s\n", info.Model);
pr_debug("ID:%02x %02x %02x %02x %02x %02x %02x %02x\n",
info.NandID[0], info.NandID[1], info.NandID[2], info.NandID[3],
info.NandID[4], info.NandID[5], info.NandID[6], info.NandID[7]);
pr_debug("DieCntPerChip:%d\n", info.DieCntPerChip);
pr_debug("BlkCntPerDie:%d\n", info.BlkCntPerDie);
pr_debug("PageCntPerBlk:%d\n", info.PageCntPerBlk);
pr_debug("SectCntPerPage:%d\n", info.SectCntPerPage);
pr_debug("OobSizePerPage:%d\n", info.OobSizePerPage);
pr_debug("BadBlockFlag:%d\n", info.BadBlockFlag);
pr_debug("OperationOpt:0x%x\n", info.OperationOpt);
pr_debug("MaxEraseTimes:%d\n", info.MaxEraseTimes);
pr_debug("EccFlag:%x\n", info.EccFlag);
pr_debug("ecc_status_shift:%x\n", info.ecc_status_shift);
pr_debug("EccType:%x\n", info.EccType);
pr_debug("EccProtectedType:%x\n", info.EccProtectedType);
had_get = true;
return &info;
err:
had_get = false;
return NULL;
}
static struct aw_spinand_info aw_spinand_info = {
.model = aw_spinand_info_model,
.manufacture = aw_spinand_info_manufacture,
.nandid = aw_spinand_info_nandid,
.die_cnt = aw_spinand_info_die_cnt,
.oob_size = aw_spinand_info_oob_size,
.page_size = aw_spinand_info_page_size,
.block_size = aw_spinand_info_block_size,
.phy_oob_size = aw_spinand_info_phy_oob_size,
.phy_page_size = aw_spinand_info_phy_page_size,
.phy_block_size = aw_spinand_info_phy_block_size,
.sector_size = aw_spinand_info_sector_size,
.total_size = aw_spinand_info_total_size,
.operation_opt = aw_spinand_info_operation_opt,
.max_erase_times = aw_spinand_info_max_erase_times,
};
static struct spinand_manufacture *spinand_detect_munufacture_from_fdt(struct aw_spinand_chip *chip, unsigned char id)
{
struct aw_spinand_phy_info *info = NULL;
struct spinand_manufacture *pm = &m;
int ret = 0;
info = spinand_get_phy_info_from_fdt(chip);
if (info == NULL) {
pr_err("get phy info from fdt fail\n");
goto err;
}
if (id == info->NandID[0]) {
pm->id = info->NandID[0];
pm->info = info;
chip->info = &aw_spinand_info;
chip->info->phy_info = info;
ret = spinand_get_chip_munufacture(chip, &(pm->name));
if (ret < 0)
goto err;
else
pr_info("detect munufacture from fdt: %s \n", pm->name);
} else {
goto err;
}
return pm;
err:
pr_info("not detect munufacture from fdt\n");
return NULL;
}
static struct aw_spinand_phy_info *spinand_match_id_from_fdt(struct aw_spinand_chip *chip,
struct spinand_manufacture *m,
unsigned char *id)
{
struct aw_spinand_phy_info *info = NULL;
int i = 0;
info = spinand_get_phy_info_from_fdt(chip);
if (info == NULL) {
pr_err("get phy info from fdt fail\n");
goto err;
}
for (i = 0; i < MAX_ID_LEN; i++) {
/*0xff match all id value*/
if (id[i] != info->NandID[i] && info->NandID[i] != 0xff)
goto err;
}
return info;
err:
return NULL;
}
static int aw_spinand_info_init(struct aw_spinand_chip *chip,
struct aw_spinand_phy_info *pinfo)
{
chip->info = &aw_spinand_info;
chip->info->phy_info = pinfo;
pr_info("========== arch info ==========\n");
pr_info("Model: %s\n", pinfo->Model);
pr_info("Munufacture: %s\n", aw_spinand_info_manufacture(chip));
pr_info("DieCntPerChip: %u\n", pinfo->DieCntPerChip);
pr_info("BlkCntPerDie: %u\n", pinfo->BlkCntPerDie);
pr_info("PageCntPerBlk: %u\n", pinfo->PageCntPerBlk);
pr_info("SectCntPerPage: %u\n", pinfo->SectCntPerPage);
pr_info("OobSizePerPage: %u\n", pinfo->OobSizePerPage);
pr_info("BadBlockFlag: 0x%x\n", pinfo->BadBlockFlag);
pr_info("OperationOpt: 0x%x\n", pinfo->OperationOpt);
pr_info("MaxEraseTimes: %d\n", pinfo->MaxEraseTimes);
pr_info("EccFlag: 0x%x\n", pinfo->EccFlag);
pr_info("EccType: %d\n", pinfo->EccType);
pr_info("EccProtectedType: %d\n", pinfo->EccProtectedType);
pr_info("========================================\n");
pr_info("\n");
pr_info("========== physical info ==========\n");
pr_info("TotalSize: %u M\n", to_mb(aw_spinand_info_total_size(chip)));
pr_info("SectorSize: %u B\n", aw_spinand_info_sector_size(chip));
pr_info("PageSize: %u K\n", to_kb(aw_spinand_info_phy_page_size(chip)));
pr_info("BlockSize: %u K\n", to_kb(aw_spinand_info_phy_block_size(chip)));
pr_info("OOBSize: %u B\n", aw_spinand_info_phy_oob_size(chip));
pr_info("========================================\n");
pr_info("\n");
pr_info("========== logical info ==========\n");
pr_info("TotalSize: %u M\n", to_mb(aw_spinand_info_total_size(chip)));
pr_info("SectorSize: %u B\n", aw_spinand_info_sector_size(chip));
pr_info("PageSize: %u K\n", to_kb(aw_spinand_info_page_size(chip)));
pr_info("BlockSize: %u K\n", to_kb(aw_spinand_info_block_size(chip)));
pr_info("OOBSize: %u B\n", aw_spinand_info_oob_size(chip));
pr_info("========================================\n");
return 0;
}
int aw_spinand_chip_detect(struct aw_spinand_chip *chip)
{
struct aw_spinand_phy_info *pinfo;
struct spinand_manufacture *m;
unsigned char id[MAX_ID_LEN] = {0xFF};
struct aw_spinand_chip_ops *ops = chip->ops;
int ret, dummy = 1;
retry:
/*first read with dummy/address@0x00*/
ret = ops->read_id(chip, id, MAX_ID_LEN, dummy);
if (ret) {
pr_err("read id failed : %d\n", ret);
return ret;
}
m = spinand_detect_munufacture(id[0]);
if (!m)
goto detect_from_fdt;
pinfo = spinand_match_id(m, id);
if (pinfo)
goto detect;
detect_from_fdt:
m = spinand_detect_munufacture_from_fdt(chip, id[0]);
if (!m)
goto not_detect;
pinfo = spinand_match_id_from_fdt(chip, m, id);
if (pinfo)
goto detect;
not_detect:
/* retry without dummy/address@0x00 */
if (dummy) {
dummy = 0;
goto retry;
}
pr_info("not match spinand: %x %x\n",
*(__u32 *)id,
*((__u32 *)id + 1));
return -ENODEV;
detect:
pr_info("detect spinand id: %x %x\n",
*((__u32 *)pinfo->NandID),
*((__u32 *)pinfo->NandID + 1));
return aw_spinand_info_init(chip, pinfo);
}
MODULE_AUTHOR("liaoweixiong <liaoweixiong@allwinnertech.com>");
MODULE_DESCRIPTION("Commond physic layer for Allwinner's spinand driver");
重新编译打包