diff mbox series

[20/32] hw/sd: Add CMD21 tuning sequence

Message ID 20230703132509.2474225-21-clg@kaod.org (mailing list archive)
State New, archived
Headers show
Series hw/sd: eMMC support | expand

Commit Message

Cédric Le Goater July 3, 2023, 1:24 p.m. UTC
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>

MMC cards support different tuning sequence for entering HS200 mode.

Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
[ clg: - ported on QEMU 7.0 ]
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 hw/sd/sd.c | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

Comments

Philippe Mathieu-Daudé June 12, 2024, 10:15 p.m. UTC | #1
On 3/7/23 15:24, Cédric Le Goater wrote:
> From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
> 
> MMC cards support different tuning sequence for entering HS200 mode.
> 
> Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
> [ clg: - ported on QEMU 7.0 ]
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
>   hw/sd/sd.c | 40 ++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 40 insertions(+)
> 
> diff --git a/hw/sd/sd.c b/hw/sd/sd.c
> index 4b4a4cda2e68..7332f7a18435 100644
> --- a/hw/sd/sd.c
> +++ b/hw/sd/sd.c
> @@ -2017,6 +2017,30 @@ static const uint8_t sd_tuning_block_pattern[SD_TUNING_BLOCK_SIZE] = {
>       0xbb, 0xff, 0xf7, 0xff,         0xf7, 0x7f, 0x7b, 0xde,
>   };
>   
> +#define EXCSD_BUS_WIDTH_OFFSET 183
> +#define BUS_WIDTH_8_MASK    0x4
> +#define BUS_WIDTH_4_MASK    0x2
> +#define MMC_TUNING_BLOCK_SIZE   128
> +
> +static const uint8_t mmc_tuning_block_pattern[128] = {
> +       0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
> +       0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
> +       0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
> +       0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
> +       0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
> +       0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
> +       0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
> +       0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
> +       0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
> +       0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
> +       0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
> +       0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
> +       0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
> +       0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
> +       0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
> +       0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
> +};
> +
>   uint8_t sd_read_byte(SDState *sd)
>   {
>       /* TODO: Append CRCs */
> @@ -2103,6 +2127,22 @@ uint8_t sd_read_byte(SDState *sd)
>           ret = sd_tuning_block_pattern[sd->data_offset++];
>           break;
>   
> +    case 21:    /* CMD21: SEND_TUNING_BLOCK (MMC) */

This can be accessed in SPI/SD modes, should we check for eMMC then?

Similarly, other cases previous eMMC introduction only expect SPI/SD
but don't check for it. I need to think a bit more on how to handle
that.

> +        if (sd->data_offset >= MMC_TUNING_BLOCK_SIZE - 1) {
> +            sd->state = sd_transfer_state;
> +        }
> +        if (sd->ext_csd[EXCSD_BUS_WIDTH_OFFSET] & BUS_WIDTH_8_MASK) {
> +            ret = mmc_tuning_block_pattern[sd->data_offset++];
> +        } else {
> +            /*
> +             * Return LSB Nibbles of two byte from the 8bit tuning
> +             * block for 4bit mode
> +             */
> +            ret = mmc_tuning_block_pattern[sd->data_offset++] & 0x0F;
> +            ret |= (mmc_tuning_block_pattern[sd->data_offset++] & 0x0F) << 4;
> +        }
> +        break;
> +
>       case 22:  /* ACMD22: SEND_NUM_WR_BLOCKS */
>           ret = sd->data[sd->data_offset ++];
>
Philippe Mathieu-Daudé June 12, 2024, 10:37 p.m. UTC | #2
On 13/6/24 00:15, Philippe Mathieu-Daudé wrote:
> On 3/7/23 15:24, Cédric Le Goater wrote:
>> From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
>>
>> MMC cards support different tuning sequence for entering HS200 mode.
>>
>> Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
>> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
>> [ clg: - ported on QEMU 7.0 ]
>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
>> ---
>>   hw/sd/sd.c | 40 ++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 40 insertions(+)
>>
>> diff --git a/hw/sd/sd.c b/hw/sd/sd.c
>> index 4b4a4cda2e68..7332f7a18435 100644
>> --- a/hw/sd/sd.c
>> +++ b/hw/sd/sd.c
>> @@ -2017,6 +2017,30 @@ static const uint8_t 
>> sd_tuning_block_pattern[SD_TUNING_BLOCK_SIZE] = {
>>       0xbb, 0xff, 0xf7, 0xff,         0xf7, 0x7f, 0x7b, 0xde,
>>   };
>> +#define EXCSD_BUS_WIDTH_OFFSET 183
>> +#define BUS_WIDTH_8_MASK    0x4
>> +#define BUS_WIDTH_4_MASK    0x2
>> +#define MMC_TUNING_BLOCK_SIZE   128
>> +
>> +static const uint8_t mmc_tuning_block_pattern[128] = {
>> +       0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
>> +       0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
>> +       0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
>> +       0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
>> +       0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
>> +       0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
>> +       0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
>> +       0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
>> +       0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
>> +       0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
>> +       0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
>> +       0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
>> +       0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
>> +       0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
>> +       0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
>> +       0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
>> +};
>> +
>>   uint8_t sd_read_byte(SDState *sd)
>>   {
>>       /* TODO: Append CRCs */
>> @@ -2103,6 +2127,22 @@ uint8_t sd_read_byte(SDState *sd)
>>           ret = sd_tuning_block_pattern[sd->data_offset++];
>>           break;
>> +    case 21:    /* CMD21: SEND_TUNING_BLOCK (MMC) */
> 
> This can be accessed in SPI/SD modes, should we check for eMMC then?

This could do:

-- >8 --
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index 3c12ba2ad3..5bad19c766 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -160,12 +160,18 @@ static const struct SDProto *sd_proto(SDState *sd)
  }

  static const SDProto sd_proto_spi;
+static const SDProto sd_proto_emmc;

  static bool sd_is_spi(SDState *sd)
  {
      return sd_proto(sd) == &sd_proto_spi;
  }

+static bool sd_is_emmc(SDState *sd)
+{
+    return sd_proto(sd) == &sd_proto_emmc;
+}
+
  static const char *sd_version_str(enum SDPhySpecificationVersion version)
  {
      static const char *sdphy_version[] = {
@@ -2389,7 +2395,9 @@ uint8_t sd_read_byte(SDState *sd)
          break;

      case 21:    /* CMD21: SEND_TUNING_BLOCK (MMC) */
+        if (!sd_is_emmc(sd)) {
+            return 0x00;
+        }
          if (sd->data_offset >= MMC_TUNING_BLOCK_SIZE - 1) {
              sd->state = sd_transfer_state;
          }
---

> Similarly, other cases previous eMMC introduction only expect SPI/SD
> but don't check for it. I need to think a bit more on how to handle
> that.
> 
>> +        if (sd->data_offset >= MMC_TUNING_BLOCK_SIZE - 1) {
>> +            sd->state = sd_transfer_state;
>> +        }
>> +        if (sd->ext_csd[EXCSD_BUS_WIDTH_OFFSET] & BUS_WIDTH_8_MASK) {
>> +            ret = mmc_tuning_block_pattern[sd->data_offset++];
>> +        } else {
>> +            /*
>> +             * Return LSB Nibbles of two byte from the 8bit tuning
>> +             * block for 4bit mode
>> +             */
>> +            ret = mmc_tuning_block_pattern[sd->data_offset++] & 0x0F;
>> +            ret |= (mmc_tuning_block_pattern[sd->data_offset++] & 
>> 0x0F) << 4;
>> +        }
>> +        break;
>> +
>>       case 22:  /* ACMD22: SEND_NUM_WR_BLOCKS */
>>           ret = sd->data[sd->data_offset ++];
>
diff mbox series

Patch

diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index 4b4a4cda2e68..7332f7a18435 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -2017,6 +2017,30 @@  static const uint8_t sd_tuning_block_pattern[SD_TUNING_BLOCK_SIZE] = {
     0xbb, 0xff, 0xf7, 0xff,         0xf7, 0x7f, 0x7b, 0xde,
 };
 
+#define EXCSD_BUS_WIDTH_OFFSET 183
+#define BUS_WIDTH_8_MASK    0x4
+#define BUS_WIDTH_4_MASK    0x2
+#define MMC_TUNING_BLOCK_SIZE   128
+
+static const uint8_t mmc_tuning_block_pattern[128] = {
+       0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+       0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
+       0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
+       0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
+       0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
+       0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
+       0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
+       0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
+       0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+       0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
+       0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
+       0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
+       0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
+       0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
+       0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
+       0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
+};
+
 uint8_t sd_read_byte(SDState *sd)
 {
     /* TODO: Append CRCs */
@@ -2103,6 +2127,22 @@  uint8_t sd_read_byte(SDState *sd)
         ret = sd_tuning_block_pattern[sd->data_offset++];
         break;
 
+    case 21:    /* CMD21: SEND_TUNING_BLOCK (MMC) */
+        if (sd->data_offset >= MMC_TUNING_BLOCK_SIZE - 1) {
+            sd->state = sd_transfer_state;
+        }
+        if (sd->ext_csd[EXCSD_BUS_WIDTH_OFFSET] & BUS_WIDTH_8_MASK) {
+            ret = mmc_tuning_block_pattern[sd->data_offset++];
+        } else {
+            /*
+             * Return LSB Nibbles of two byte from the 8bit tuning
+             * block for 4bit mode
+             */
+            ret = mmc_tuning_block_pattern[sd->data_offset++] & 0x0F;
+            ret |= (mmc_tuning_block_pattern[sd->data_offset++] & 0x0F) << 4;
+        }
+        break;
+
     case 22:  /* ACMD22: SEND_NUM_WR_BLOCKS */
         ret = sd->data[sd->data_offset ++];