Alex, Ulf,
I am not sure about the status of this patch.
Still I would like to give some feedback.
The Jedec specification requires to check the
PRODUCTION_STATE_AWARENESS_ENABLEMENT (ext_csd[17])
register before issuing a PSA command.
Actually in some devices the PSA register might be a
"don't care" random value if the
PRODUCTION_STATE_AWARENESS_ENABLEMENT shows that device
is not supporting MANUAL mode.
Thus we propose some changes to Alex patch
in order to check the ext_csd[17] before actually
taking any action.
Even if the modified lines are few, I was not able to
efficiently merge my proposals with Alex code.
Please forgive me if I post a new patch which
includes both my changes and Alex original
patch.
With these small changes, patch is fine for us.
Cheers,
Luca
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 7466ce0..52c8cc9 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -571,6 +571,29 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8
*ext_csd)
card->ext_csd.ffu_capable =
(ext_csd[EXT_CSD_SUPPORTED_MODE] & 0x1) &&
!(ext_csd[EXT_CSD_FW_CONFIG] & 0x1);
+
+ /*
+ * PSA ext_csd parsing
+ * Note: Only Manual mode needs to be supported
+ */
+ card->ext_csd.psa_enablement =
+ (ext_csd[EXT_CSD_PSA_ENABLEMENT] & 1);
+ if (card->ext_csd.psa_enablement) {
+ card->ext_csd.psa =
+ ext_csd[EXT_CSD_PSA];
+ if (ext_csd[EXT_CSD_PSA_TIMEOUT] > 0) {
+ card->ext_csd.psa_timeout =
+ 100 *
+ (1 << ext_csd[EXT_CSD_PSA_TIMEOUT]);
+ } else {
+ pr_warn("%s: EXT_CSD PSA Timeout is zero\n",
+ mmc_hostname(card->host));
+ }
+ } else {
+ card->ext_csd.psa = EXT_CSD_PSA_NORMAL;
+ card->ext_csd.psa_timeout = 0;
+ }
+
}
out:
return err;
@@ -1358,6 +1381,24 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
}
/*
+ * eMMC v5.0 or later
+ * and Production State Awareness state is
+ * EXT_CSD_PSA_POST_SOLDERING_WRITES (0x02)
+ * The host should set the device to NORMAL mode
+ */
+ if ((card->ext_csd.rev >= 7) && (card->ext_csd.psa_enablement) &&
+ (card->ext_csd.psa == EXT_CSD_PSA_POST_SOLDERING_WRITES)) {
+ unsigned int timeout;
+
+ timeout = DIV_ROUND_UP(card->ext_csd.psa_timeout, 1000);
+ card->ext_csd.psa = EXT_CSD_PSA_NORMAL;
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_PSA, card->ext_csd.psa, timeout);
+ if (err && err != -EBADMSG)
+ goto free_card;
+ }
+
+ /*
* If enhanced_area_en is TRUE, host needs to enable ERASE_GRP_DEF
* bit. This bit will be lost every time after a reset or power off.
*/
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 4d69c00..8dc1148 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -60,9 +60,12 @@ struct mmc_ext_csd {
u8 packed_event_en;
unsigned int part_time; /* Units: ms */
unsigned int sa_timeout; /* Units: 100ns */
- unsigned int generic_cmd6_time; /* Units: 10ms */
+ unsigned int psa_timeout; /* Units: 100us */
+ unsigned int generic_cmd6_time; /* Units: 10ms */
unsigned int power_off_longtime; /* Units: ms */
u8 power_off_notification; /* state */
+ u8 psa_enablement; /* production state awareness
enablement*/
+ u8 psa; /* production state awareness */
unsigned int hs_max_dtr;
unsigned int hs200_max_dtr;
#define MMC_HIGH_26_MAX_DTR 26000000
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 49ad7a9..435e9ef 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -277,6 +277,7 @@ struct _mmc_csd {
* EXT_CSD fields
*/
+#define EXT_CSD_PSA_ENABLEMENT 17 /* RO */
#define EXT_CSD_FLUSH_CACHE 32 /* W */
#define EXT_CSD_CACHE_CTRL 33 /* R/W */
#define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */
@@ -285,6 +286,7 @@ struct _mmc_csd {
#define EXT_CSD_EXP_EVENTS_STATUS 54 /* RO, 2 bytes */
#define EXT_CSD_EXP_EVENTS_CTRL 56 /* R/W, 2 bytes */
#define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */
+#define EXT_CSD_PSA 133 /* R/W/E */
#define EXT_CSD_GP_SIZE_MULT 143 /* R/W */
#define EXT_CSD_PARTITION_SETTING_COMPLETED 155 /* R/W */
#define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */
@@ -315,6 +317,7 @@ struct _mmc_csd {
#define EXT_CSD_PWR_CL_26_360 203 /* RO */
#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
#define EXT_CSD_S_A_TIMEOUT 217 /* RO */
+#define EXT_CSD_PSA_TIMEOUT 218 /* RO */
#define EXT_CSD_REL_WR_SEC_C 222 /* RO */
#define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */
#define EXT_CSD_ERASE_TIMEOUT_MULT 223 /* RO */
@@ -428,6 +431,12 @@ struct _mmc_csd {
#define EXT_CSD_PACKED_INDEXED_ERROR BIT(1)
/*
+ * PRODUCTION STATE AWARENESS fields
+ */
+#define EXT_CSD_PSA_NORMAL 0x00
+#define EXT_CSD_PSA_POST_SOLDERING_WRITES 0x02
+
+/*
* BKOPS status level
*/
#define EXT_CSD_BKOPS_LEVEL_2 0x2
> -----Original Message-----
> From: [email protected] [mailto:linux-mmc-
> [email protected]] On Behalf Of Alex Lemberg
> Sent: mercoledì 26 novembre 2014 17:44
> To: [email protected]
> Cc: [email protected]; [email protected];
> [email protected]; Alex Lemberg
> Subject: [PATCH v3] mmc: Add Production State Awareness Support
>
> In this patch driver should recognize if eMMC device (Rev >=5.0) was left
> in PRE_SOLDERING_POST_WRITES (0x02) state, and switch it to NORMAL (0x00).
> PRE_SOLDERING_POST_WRITES (0x02) state - represents a state where the
> device is in production process and the host (usually programmer)
> completed loading the content to the device.
> The host (usually programmer) sets the device to this state after loading
> the content and just before soldering.
> After soldering the device to the real host (not programmer), the device
> should be switched to NORMAL (0x00) mode.
> The NORMAL (0x00) mode of PSA register represents a state in which the
> device is running in the field and uses regular operations.
> Leaving device in PRE_SOLDERING_POST_WRITES (0x02) might cause unexpected
> behaviour of eMMC device.
>
> More details about PSA feature can be found in eMMC5.0 JEDEC spec (JESD84-
> B50.pdf):
> http://www.jedec.org/standards-documents/technology-focus-areas/flash-
> memory-ssds-ufs-emmc/e-mmc
>
> Signed-off-by: Alex Lemberg <[email protected]>
> ---
> Changes in v2:
> - Remove typo in patch code
> Changes in v3:
> - Move ext_csd revision check
> ---
> drivers/mmc/core/mmc.c | 28 ++++++++++++++++++++++++++++
> include/linux/mmc/card.h | 2 ++
> include/linux/mmc/mmc.h | 8 ++++++++
> 3 files changed, 38 insertions(+)
>
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index
> 02ad792..2c523ca 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -571,6 +571,16 @@ static int mmc_decode_ext_csd(struct mmc_card *card,
> u8 *ext_csd)
> card->ext_csd.ffu_capable =
> (ext_csd[EXT_CSD_SUPPORTED_MODE] & 0x1) &&
> !(ext_csd[EXT_CSD_FW_CONFIG] & 0x1);
> + card->ext_csd.psa =
> + ext_csd[EXT_CSD_PSA];
> + if (ext_csd[EXT_CSD_PSA_TIMEOUT] > 0) {
> + card->ext_csd.psa_timeout =
> + 100 *
> + (1 << ext_csd[EXT_CSD_PSA_TIMEOUT]);
> + } else {
> + pr_warn("%s: EXT_CSD PSA Timeout is zero\n",
> + mmc_hostname(card->host));
> + }
> }
> out:
> return err;
> @@ -1358,6 +1368,24 @@ static int mmc_init_card(struct mmc_host *host, u32
> ocr,
> }
>
> /*
> + * eMMC v5.0 or later
> + * and Production State Awareness state is
> + * EXT_CSD_PSA_POST_SOLDERING_WRITES (0x02)
> + * The host should set the device to NORMAL mode
> + */
> + if ((card->ext_csd.rev >= 7) &&
> + (card->ext_csd.psa == EXT_CSD_PSA_POST_SOLDERING_WRITES)) {
> + unsigned int timeout;
> +
> + timeout = DIV_ROUND_UP(card->ext_csd.psa_timeout, 1000);
> + card->ext_csd.psa = EXT_CSD_PSA_NORMAL;
> + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> + EXT_CSD_PSA, card->ext_csd.psa, timeout);
> + if (err && err != -EBADMSG)
> + goto free_card;
> + }
> +
> + /*
> * If enhanced_area_en is TRUE, host needs to enable ERASE_GRP_DEF
> * bit. This bit will be lost every time after a reset or power
> off.
> */
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index
> 4d69c00..09ac3b0 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -60,9 +60,11 @@ struct mmc_ext_csd {
> u8 packed_event_en;
> unsigned int part_time; /* Units: ms */
> unsigned int sa_timeout; /* Units: 100ns */
> + unsigned int psa_timeout; /* Units: 100us */
> unsigned int generic_cmd6_time; /* Units: 10ms */
> unsigned int power_off_longtime; /* Units: ms */
> u8 power_off_notification; /* state */
> + u8 psa; /* production state awareness */
> unsigned int hs_max_dtr;
> unsigned int hs200_max_dtr;
> #define MMC_HIGH_26_MAX_DTR 26000000
> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index
> 49ad7a9..458814d 100644
> --- a/include/linux/mmc/mmc.h
> +++ b/include/linux/mmc/mmc.h
> @@ -285,6 +285,7 @@ struct _mmc_csd {
> #define EXT_CSD_EXP_EVENTS_STATUS 54 /* RO, 2 bytes */
> #define EXT_CSD_EXP_EVENTS_CTRL 56 /* R/W, 2 bytes */
> #define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */
> +#define EXT_CSD_PSA 133 /* R/W/E */
> #define EXT_CSD_GP_SIZE_MULT 143 /* R/W */
> #define EXT_CSD_PARTITION_SETTING_COMPLETED 155 /* R/W */
> #define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */
> @@ -315,6 +316,7 @@ struct _mmc_csd {
> #define EXT_CSD_PWR_CL_26_360 203 /* RO */
> #define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
> #define EXT_CSD_S_A_TIMEOUT 217 /* RO */
> +#define EXT_CSD_PSA_TIMEOUT 218 /* RO */
> #define EXT_CSD_REL_WR_SEC_C 222 /* RO */
> #define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */
> #define EXT_CSD_ERASE_TIMEOUT_MULT 223 /* RO */
> @@ -433,6 +435,12 @@ struct _mmc_csd {
> #define EXT_CSD_BKOPS_LEVEL_2 0x2
>
> /*
> + * PRODUCTION STATE AWARENESS fields
> + */
> +#define EXT_CSD_PSA_NORMAL 0x00
> +#define EXT_CSD_PSA_POST_SOLDERING_WRITES 0x02
> +
> +/*
> * MMC_SWITCH access modes
> */
>
> --
> 2.1.0
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to [email protected] More majordomo info at
> http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html