[v2,2/4] mtd: rawnand: Add support Macronix Block Protection function
diff mbox series

Message ID 1572256527-5074-3-git-send-email-masonccyang@mxic.com.tw
State New
Headers show
Series
  • mtd: rawnand: Add support Macronix Block Protection & deep power down mode
Related show

Commit Message

Mason Yang Oct. 28, 2019, 9:55 a.m. UTC
Macronix AC series support using SET_FEATURES to change
Block Protection and Unprotection.

Signed-off-by: Mason Yang <masonccyang@mxic.com.tw>
---
 drivers/mtd/nand/raw/nand_macronix.c | 69 +++++++++++++++++++++++++++++++++---
 1 file changed, 65 insertions(+), 4 deletions(-)

Comments

Miquel Raynal Jan. 9, 2020, 4:47 p.m. UTC | #1
Hi Mason,

Mason Yang <masonccyang@mxic.com.tw> wrote on Mon, 28 Oct 2019 17:55:25
+0800:

> Macronix AC series support using SET_FEATURES to change
> Block Protection and Unprotection.
> 
> Signed-off-by: Mason Yang <masonccyang@mxic.com.tw>
> ---
>  drivers/mtd/nand/raw/nand_macronix.c | 69 +++++++++++++++++++++++++++++++++---
>  1 file changed, 65 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/mtd/nand/raw/nand_macronix.c b/drivers/mtd/nand/raw/nand_macronix.c
> index 58511ae..13929bf 100644
> --- a/drivers/mtd/nand/raw/nand_macronix.c
> +++ b/drivers/mtd/nand/raw/nand_macronix.c
> @@ -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
> +
>  struct nand_onfi_vendor_macronix {
>  	u8 reserved;
>  	u8 reliability_func;
> @@ -57,7 +61,7 @@ static void macronix_nand_onfi_init(struct nand_chip *chip)
>   * the timings unlike what is declared in the parameter page. Unflag
>   * this feature to avoid unnecessary downturns.
>   */
> -static void macronix_nand_fix_broken_get_timings(struct nand_chip *chip)
> +static int macronix_nand_fix_broken_get_timings(struct nand_chip *chip)
>  {
>  	unsigned int i;
>  	static const char * const broken_get_timings[] = {
> @@ -78,7 +82,7 @@ static void macronix_nand_fix_broken_get_timings(struct nand_chip *chip)
>  	};
>  
>  	if (!chip->parameters.supports_set_get_features)
> -		return;
> +		return 0;
>  
>  	for (i = 0; i < ARRAY_SIZE(broken_get_timings); i++) {
>  		if (!strcmp(broken_get_timings[i], chip->parameters.model))
> @@ -86,22 +90,79 @@ static void macronix_nand_fix_broken_get_timings(struct nand_chip *chip)
>  	}
>  
>  	if (i == ARRAY_SIZE(broken_get_timings))
> -		return;
> +		return 0;
>  
>  	bitmap_clear(chip->parameters.get_feature_list,
>  		     ONFI_FEATURE_ADDR_TIMING_MODE, 1);
>  	bitmap_clear(chip->parameters.set_feature_list,
>  		     ONFI_FEATURE_ADDR_TIMING_MODE, 1);
> +	return 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;
>  }
>  
> +/*
> + * Macronix NAND AC series support Block Protection by SET_FEATURES
> + * to lock/unlock blocks.
> + */
>  static int macronix_nand_init(struct nand_chip *chip)
>  {
> +	bool blockprotected = false;
> +
>  	if (nand_is_slc(chip))
>  		chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE;
>  
> -	macronix_nand_fix_broken_get_timings(chip);
> +	if (macronix_nand_fix_broken_get_timings(chip))
> +		blockprotected = true;

I don't like this at all :)

Please create a helper which detects which part is broken/protected
then create helpers to act in this case.

If the list is absolutely identical, you can share the detection
helper. Otherwise, if you think the list can diverge, please only share
the list for now and create two detection helpers.

> +
>  	macronix_nand_onfi_init(chip);
>  
> +	if (blockprotected) {
> +		bitmap_set(chip->parameters.set_feature_list,
> +			   ONFI_FEATURE_ADDR_MXIC_PROTECTION, 1);
> +		bitmap_set(chip->parameters.get_feature_list,
> +			   ONFI_FEATURE_ADDR_MXIC_PROTECTION, 1);
> +
> +		chip->_lock = mxic_nand_lock;
> +		chip->_unlock = mxic_nand_unlock;
> +	}
> +
>  	return 0;
>  }
>  


Thanks,
Miquèl
Mason Yang Feb. 17, 2020, 8:24 a.m. UTC | #2
Hi Miquel,

> > +/*
> > + * 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;
> >  }
> > 
> > +/*
> > + * Macronix NAND AC series support Block Protection by SET_FEATURES
> > + * to lock/unlock blocks.
> > + */
> >  static int macronix_nand_init(struct nand_chip *chip)
> >  {
> > +   bool blockprotected = false;
> > +
> >     if (nand_is_slc(chip))
> >        chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE;
> > 
> > -   macronix_nand_fix_broken_get_timings(chip);
> > +   if (macronix_nand_fix_broken_get_timings(chip))
> > +      blockprotected = true;
> 
> I don't like this at all :)
> 
> Please create a helper which detects which part is broken/protected
> then create helpers to act in this case.

okay, will patch it to read default protected value (after power-on)
for protection function detection.

> 
> If the list is absolutely identical, you can share the detection
> helper. Otherwise, if you think the list can diverge, please only share
> the list for now and create two detection helpers.
> 
> > +
> >     macronix_nand_onfi_init(chip);
> > 
> > +   if (blockprotected) {
> > +      bitmap_set(chip->parameters.set_feature_list,
> > +            ONFI_FEATURE_ADDR_MXIC_PROTECTION, 1);
> > +      bitmap_set(chip->parameters.get_feature_list,
> > +            ONFI_FEATURE_ADDR_MXIC_PROTECTION, 1);
> > +
> > +      chip->_lock = mxic_nand_lock;
> > +      chip->_unlock = mxic_nand_unlock;
> > +   }
> > +
> >     return 0;
> >  }
> > 

thanks for your time & comments.
Mason 


CONFIDENTIALITY NOTE:

This e-mail and any attachments may contain confidential information 
and/or personal data, which is protected by applicable laws. Please be 
reminded that duplication, disclosure, distribution, or use of this e-mail 
(and/or its attachments) or any part thereof is prohibited. If you receive 
this e-mail in error, please notify us immediately and delete this mail as 
well as its attachment(s) from your system. In addition, please be 
informed that collection, processing, and/or use of personal data is 
prohibited unless expressly permitted by personal data protection laws. 
Thank you for your attention and cooperation.

Macronix International Co., Ltd.

=====================================================================



============================================================================

CONFIDENTIALITY NOTE:

This e-mail and any attachments may contain confidential information and/or personal data, which is protected by applicable laws. Please be reminded that duplication, disclosure, distribution, or use of this e-mail (and/or its attachments) or any part thereof is prohibited. If you receive this e-mail in error, please notify us immediately and delete this mail as well as its attachment(s) from your system. In addition, please be informed that collection, processing, and/or use of personal data is prohibited unless expressly permitted by personal data protection laws. Thank you for your attention and cooperation.

Macronix International Co., Ltd.

=====================================================================

Patch
diff mbox series

diff --git a/drivers/mtd/nand/raw/nand_macronix.c b/drivers/mtd/nand/raw/nand_macronix.c
index 58511ae..13929bf 100644
--- a/drivers/mtd/nand/raw/nand_macronix.c
+++ b/drivers/mtd/nand/raw/nand_macronix.c
@@ -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
+
 struct nand_onfi_vendor_macronix {
 	u8 reserved;
 	u8 reliability_func;
@@ -57,7 +61,7 @@  static void macronix_nand_onfi_init(struct nand_chip *chip)
  * the timings unlike what is declared in the parameter page. Unflag
  * this feature to avoid unnecessary downturns.
  */
-static void macronix_nand_fix_broken_get_timings(struct nand_chip *chip)
+static int macronix_nand_fix_broken_get_timings(struct nand_chip *chip)
 {
 	unsigned int i;
 	static const char * const broken_get_timings[] = {
@@ -78,7 +82,7 @@  static void macronix_nand_fix_broken_get_timings(struct nand_chip *chip)
 	};
 
 	if (!chip->parameters.supports_set_get_features)
-		return;
+		return 0;
 
 	for (i = 0; i < ARRAY_SIZE(broken_get_timings); i++) {
 		if (!strcmp(broken_get_timings[i], chip->parameters.model))
@@ -86,22 +90,79 @@  static void macronix_nand_fix_broken_get_timings(struct nand_chip *chip)
 	}
 
 	if (i == ARRAY_SIZE(broken_get_timings))
-		return;
+		return 0;
 
 	bitmap_clear(chip->parameters.get_feature_list,
 		     ONFI_FEATURE_ADDR_TIMING_MODE, 1);
 	bitmap_clear(chip->parameters.set_feature_list,
 		     ONFI_FEATURE_ADDR_TIMING_MODE, 1);
+	return 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;
 }
 
+/*
+ * Macronix NAND AC series support Block Protection by SET_FEATURES
+ * to lock/unlock blocks.
+ */
 static int macronix_nand_init(struct nand_chip *chip)
 {
+	bool blockprotected = false;
+
 	if (nand_is_slc(chip))
 		chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE;
 
-	macronix_nand_fix_broken_get_timings(chip);
+	if (macronix_nand_fix_broken_get_timings(chip))
+		blockprotected = true;
+
 	macronix_nand_onfi_init(chip);
 
+	if (blockprotected) {
+		bitmap_set(chip->parameters.set_feature_list,
+			   ONFI_FEATURE_ADDR_MXIC_PROTECTION, 1);
+		bitmap_set(chip->parameters.get_feature_list,
+			   ONFI_FEATURE_ADDR_MXIC_PROTECTION, 1);
+
+		chip->_lock = mxic_nand_lock;
+		chip->_unlock = mxic_nand_unlock;
+	}
+
 	return 0;
 }