mtd: rawnand: Macronix: Add support for block protection

Macronix AC/AD series support using SET_FEATURES to change block
protection and unprotection. Block protection support can be checked
with GET_FEATURES.

Signed-off-by: Mason Yang <masonccyang@mxic.com.tw>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/1583220084-10890-3-git-send-email-masonccyang@mxic.com.tw
This commit is contained in:
Mason Yang 2020-03-03 15:21:22 +08:00 committed by Miquel Raynal
parent 92270086b7
commit 03a539c7a1

View File

@ -11,6 +11,10 @@
#define MACRONIX_READ_RETRY_BIT BIT(0) #define MACRONIX_READ_RETRY_BIT BIT(0)
#define MACRONIX_NUM_READ_RETRY_MODES 6 #define MACRONIX_NUM_READ_RETRY_MODES 6
#define ONFI_FEATURE_ADDR_MXIC_PROTECTION 0xA0
#define MXIC_BLOCK_PROTECTION_ALL_LOCK 0x38
#define MXIC_BLOCK_PROTECTION_ALL_UNLOCK 0x0
#define ONFI_FEATURE_ADDR_MXIC_RANDOMIZER 0xB0 #define ONFI_FEATURE_ADDR_MXIC_RANDOMIZER 0xB0
#define MACRONIX_RANDOMIZER_BIT BIT(1) #define MACRONIX_RANDOMIZER_BIT BIT(1)
#define MACRONIX_RANDOMIZER_ENPGM BIT(0) #define MACRONIX_RANDOMIZER_ENPGM BIT(0)
@ -172,6 +176,73 @@ static void macronix_nand_fix_broken_get_timings(struct nand_chip *chip)
ONFI_FEATURE_ADDR_TIMING_MODE, 1); ONFI_FEATURE_ADDR_TIMING_MODE, 1);
} }
/*
* Macronix NAND supports Block Protection by Protectoin(PT) pin;
* active high at power-on which protects the entire chip even the #WP is
* disabled. Lock/unlock protection area can be partition according to
* protection bits, i.e. upper 1/2 locked, upper 1/4 locked and so on.
*/
static int mxic_nand_lock(struct nand_chip *chip, loff_t ofs, uint64_t len)
{
u8 feature[ONFI_SUBFEATURE_PARAM_LEN];
int ret;
feature[0] = MXIC_BLOCK_PROTECTION_ALL_LOCK;
nand_select_target(chip, 0);
ret = nand_set_features(chip, ONFI_FEATURE_ADDR_MXIC_PROTECTION,
feature);
nand_deselect_target(chip);
if (ret)
pr_err("%s all blocks failed\n", __func__);
return ret;
}
static int mxic_nand_unlock(struct nand_chip *chip, loff_t ofs, uint64_t len)
{
u8 feature[ONFI_SUBFEATURE_PARAM_LEN];
int ret;
feature[0] = MXIC_BLOCK_PROTECTION_ALL_UNLOCK;
nand_select_target(chip, 0);
ret = nand_set_features(chip, ONFI_FEATURE_ADDR_MXIC_PROTECTION,
feature);
nand_deselect_target(chip);
if (ret)
pr_err("%s all blocks failed\n", __func__);
return ret;
}
static void macronix_nand_block_protection_support(struct nand_chip *chip)
{
u8 feature[ONFI_SUBFEATURE_PARAM_LEN];
int ret;
bitmap_set(chip->parameters.get_feature_list,
ONFI_FEATURE_ADDR_MXIC_PROTECTION, 1);
feature[0] = MXIC_BLOCK_PROTECTION_ALL_UNLOCK;
nand_select_target(chip, 0);
ret = nand_get_features(chip, ONFI_FEATURE_ADDR_MXIC_PROTECTION,
feature);
nand_deselect_target(chip);
if (ret || feature[0] != MXIC_BLOCK_PROTECTION_ALL_LOCK) {
if (ret)
pr_err("Block protection check failed\n");
bitmap_clear(chip->parameters.get_feature_list,
ONFI_FEATURE_ADDR_MXIC_PROTECTION, 1);
return;
}
bitmap_set(chip->parameters.set_feature_list,
ONFI_FEATURE_ADDR_MXIC_PROTECTION, 1);
chip->lock_area = mxic_nand_lock;
chip->unlock_area = mxic_nand_unlock;
}
static int macronix_nand_init(struct nand_chip *chip) static int macronix_nand_init(struct nand_chip *chip)
{ {
if (nand_is_slc(chip)) if (nand_is_slc(chip))
@ -179,6 +250,7 @@ static int macronix_nand_init(struct nand_chip *chip)
macronix_nand_fix_broken_get_timings(chip); macronix_nand_fix_broken_get_timings(chip);
macronix_nand_onfi_init(chip); macronix_nand_onfi_init(chip);
macronix_nand_block_protection_support(chip);
return 0; return 0;
} }