sdk-hwV1.3/lichee/linux-4.9/drivers/mtd/awnand/spinand/physic/bbt.c

85 lines
2.2 KiB
C
Raw Normal View History

2024-05-07 10:09:20 +00:00
// SPDX-License-Identifier: GPL-2.0
/* bad block table */
#define pr_fmt(fmt) "sunxi-spinand-phy: " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mtd/aw-spinand.h>
#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include "physic.h"
static int aw_spinand_bbt_mark_badblock(struct aw_spinand_chip *chip,
unsigned int blknum, bool badblk)
{
struct aw_spinand_bbt *bbt = chip->bbt;
struct aw_spinand_phy_info *pinfo = chip->info->phy_info;
unsigned int blkcnt = pinfo->DieCntPerChip * pinfo->BlkCntPerDie;
if (blknum > blkcnt)
return -EOVERFLOW;
if (badblk == true)
set_bit(blknum, bbt->bitmap);
set_bit(blknum, bbt->en_bitmap);
pr_debug("bbt: mark blk %u as %s\n", blknum, badblk ? "bad" : "good");
return 0;
}
static int aw_spinand_bbt_is_badblock(struct aw_spinand_chip *chip,
unsigned int blknum)
{
struct aw_spinand_bbt *bbt = chip->bbt;
struct aw_spinand_phy_info *pinfo = chip->info->phy_info;
unsigned int blkcnt = pinfo->DieCntPerChip * pinfo->BlkCntPerDie;
if (blknum > blkcnt)
return -EOVERFLOW;
if (!test_bit(blknum, bbt->en_bitmap))
return NOT_MARKED;
pr_debug("bbt: blk %u is %s\n", blknum,
test_bit(blknum, bbt->bitmap) ? "bad" : "good");
if (test_bit(blknum, bbt->bitmap))
return BADBLOCK;
else
return NON_BADBLOCK;
}
struct aw_spinand_bbt aw_spinand_bbt = {
.mark_badblock = aw_spinand_bbt_mark_badblock,
.is_badblock = aw_spinand_bbt_is_badblock,
};
int aw_spinand_chip_bbt_init(struct aw_spinand_chip *chip)
{
struct aw_spinand_phy_info *pinfo = chip->info->phy_info;
unsigned int blkcnt = pinfo->DieCntPerChip * pinfo->BlkCntPerDie;
unsigned long longcnt = BITS_TO_LONGS(blkcnt);
struct aw_spinand_bbt *bbt = &aw_spinand_bbt;
bbt->bitmap = kzalloc(longcnt * sizeof(long) * 2, GFP_KERNEL);
if (!bbt->bitmap)
return -ENOMEM;
bbt->en_bitmap = bbt->bitmap + longcnt;
chip->bbt = bbt;
return 0;
}
void aw_spinand_chip_bbt_exit(struct aw_spinand_chip *chip)
{
struct aw_spinand_bbt *bbt = chip->bbt;
if (bbt && bbt->bitmap)
kfree(bbt->bitmap);
bbt->bitmap = NULL;
}
MODULE_AUTHOR("liaoweixiong <liaoweixiong@allwinnertech.com>");
MODULE_DESCRIPTION("Commond physic layer for Allwinner's spinand driver");