Skip to content

Commit

Permalink
mtd: rawnand: Macronix: Add support for block protection
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Mason Yang authored and Miquel Raynal committed Mar 11, 2020
1 parent 9227008 commit 03a539c
Showing 1 changed file with 72 additions and 0 deletions.
72 changes: 72 additions & 0 deletions drivers/mtd/nand/raw/nand_macronix.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
#define MACRONIX_READ_RETRY_BIT BIT(0)
#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 MACRONIX_RANDOMIZER_BIT BIT(1)
#define MACRONIX_RANDOMIZER_ENPGM BIT(0)
Expand Down Expand Up @@ -172,13 +176,81 @@ static void macronix_nand_fix_broken_get_timings(struct nand_chip *chip)
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)
{
if (nand_is_slc(chip))
chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE;

macronix_nand_fix_broken_get_timings(chip);
macronix_nand_onfi_init(chip);
macronix_nand_block_protection_support(chip);

return 0;
}
Expand Down

0 comments on commit 03a539c

Please sign in to comment.