mbox series

[v2,0/6] mmc: sdhci-acpi: Add some DMI quirks to fix various issues on Bay Trail devices

Message ID 20240408195244.248280-1-hdegoede@redhat.com
Headers show
Series mmc: sdhci-acpi: Add some DMI quirks to fix various issues on Bay Trail devices | expand

Message

Hans de Goede April 8, 2024, 7:52 p.m. UTC
Hi All,

Here is v2 of my series adding DMI quirks to fix various issues on Intel
Bay Trail tablets.

This v2 addresses a few small remarks from Andy and adds Andy's Reviewed-by
to all of the patches.

Regards,

Hans


Hans de Goede (6):
  mmc: core: Add mmc_gpiod_set_cd_config() function
  mmc: sdhci-acpi: Sort DMI quirks alphabetically
  mmc: sdhci-acpi: Fix Lenovo Yoga Tablet 2 Pro 1380 sdcard slot not
    working
  mmc: sdhci-acpi: Disable UHS/1.8V modes on Lenovo Yoga Tablet 2 series
    sdcard slot
  mmc: sdhci-acpi: Disable write protect detection on Toshiba WT10-A
  mmc: sdhci-acpi: Add quirk to enable pull-up on the card-detect GPIO
    on Asus T100TA

 drivers/mmc/core/slot-gpio.c  | 20 +++++++++
 drivers/mmc/host/sdhci-acpi.c | 84 ++++++++++++++++++++++++++++++++---
 include/linux/mmc/slot-gpio.h |  1 +
 3 files changed, 99 insertions(+), 6 deletions(-)

Comments

Adrian Hunter April 9, 2024, 10:37 a.m. UTC | #1
On 8/04/24 22:52, Hans de Goede wrote:
> Unlike all other Bay Trail devices I have (quite a few) the BIOS on
> the Lenovo Yoga Tablet 2 830 / 1050 and Lenovo Yoga Tablet 2 Pro 1380 (8",
> 10" and 13") models sets the SDHCI_SUPPORT_DDR50 bit in the sdcard slots'
> SDHCI controller's Caps_1 register which causes Linux to try and use
> UHS SDR12 / SDR25 and DDR50 modes on UHS cards.
> 
> These tablets do have 1.8V signalling implemented in the hw level through
> the Bay Trail SoC's SD3_1P8EN pin. But trying to use UHS modes leads to
> lots of errors like these:
> 
> [  225.272001] mmc2: Unexpected interrupt 0x04000000.
> [  225.272024] mmc2: sdhci: ============ SDHCI REGISTER DUMP ===========
> [  225.272034] mmc2: sdhci: Sys addr:  0x0712c400 | Version:  0x0000b502
> [  225.272044] mmc2: sdhci: Blk size:  0x00007200 | Blk cnt:  0x00000007
> [  225.272054] mmc2: sdhci: Argument:  0x00000000 | Trn mode: 0x00000023
> [  225.272064] mmc2: sdhci: Present:   0x01e20002 | Host ctl: 0x00000016
> [  225.272073] mmc2: sdhci: Power:     0x0000000f | Blk gap:  0x00000000
> [  225.272082] mmc2: sdhci: Wake-up:   0x00000000 | Clock:    0x00000107
> [  225.272092] mmc2: sdhci: Timeout:   0x0000000e | Int stat: 0x00000001
> [  225.272101] mmc2: sdhci: Int enab:  0x03ff000b | Sig enab: 0x03ff000b
> [  225.272110] mmc2: sdhci: ACmd stat: 0x00000000 | Slot int: 0x00000001
> [  225.272119] mmc2: sdhci: Caps:      0x076864b2 | Caps_1:   0x00000004
> [  225.272129] mmc2: sdhci: Cmd:       0x00000c1b | Max curr: 0x00000000
> [  225.272138] mmc2: sdhci: Resp[0]:   0x00000c00 | Resp[1]:  0x00000000
> [  225.272147] mmc2: sdhci: Resp[2]:   0x00000000 | Resp[3]:  0x00000900
> [  225.272155] mmc2: sdhci: Host ctl2: 0x0000000c
> [  225.272164] mmc2: sdhci: ADMA Err:  0x00000003 | ADMA Ptr: 0x0712c200
> [  225.272172] mmc2: sdhci: ============================================
> 

0x04000000 is so-called "Tuning Error" which oddly the SDHCI driver
does not support / enable.

Could try making the IRQ handler process it and see if that helps:


diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index c79f73459915..746f4cf7ab03 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -3439,12 +3439,18 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
 		host->data->error = -EILSEQ;
 		if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
 			sdhci_err_stats_inc(host, DAT_CRC);
-	} else if ((intmask & SDHCI_INT_DATA_CRC) &&
+	} else if ((intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_TUNING_ERROR)) &&
 		SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))
 			!= MMC_BUS_TEST_R) {
 		host->data->error = -EILSEQ;
 		if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
 			sdhci_err_stats_inc(host, DAT_CRC);
+		if (intmask & SDHCI_INT_TUNING_ERROR) {
+			u16 ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+
+			ctrl2 &= ~SDHCI_CTRL_TUNED_CLK;
+			sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
+		}
 	} else if (intmask & SDHCI_INT_ADMA_ERROR) {
 		pr_err("%s: ADMA error: 0x%08x\n", mmc_hostname(host->mmc),
 		       intmask);
@@ -3979,7 +3985,7 @@ bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error,
 	} else
 		*cmd_error = 0;
 
-	if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC)) {
+	if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC | SDHCI_INT_TUNING_ERROR)) {
 		*data_error = -EILSEQ;
 		if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
 			sdhci_err_stats_inc(host, DAT_CRC);
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index a20864fc0641..957c7a917ffb 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -158,6 +158,7 @@
 #define  SDHCI_INT_BUS_POWER	0x00800000
 #define  SDHCI_INT_AUTO_CMD_ERR	0x01000000
 #define  SDHCI_INT_ADMA_ERROR	0x02000000
+#define  SDHCI_INT_TUNING_ERROR	0x04000000
 
 #define  SDHCI_INT_NORMAL_MASK	0x00007FFF
 #define  SDHCI_INT_ERROR_MASK	0xFFFF8000
@@ -169,7 +170,7 @@
 		SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
 		SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
 		SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR | \
-		SDHCI_INT_BLK_GAP)
+		SDHCI_INT_BLK_GAP | SDHCI_INT_TUNING_ERROR)
 #define SDHCI_INT_ALL_MASK	((unsigned int)-1)
 
 #define SDHCI_CQE_INT_ERR_MASK ( \
Hans de Goede April 9, 2024, 11:39 a.m. UTC | #2
Hi Adrian,

On 4/9/24 12:37 PM, Adrian Hunter wrote:
> On 8/04/24 22:52, Hans de Goede wrote:
>> Unlike all other Bay Trail devices I have (quite a few) the BIOS on
>> the Lenovo Yoga Tablet 2 830 / 1050 and Lenovo Yoga Tablet 2 Pro 1380 (8",
>> 10" and 13") models sets the SDHCI_SUPPORT_DDR50 bit in the sdcard slots'
>> SDHCI controller's Caps_1 register which causes Linux to try and use
>> UHS SDR12 / SDR25 and DDR50 modes on UHS cards.
>>
>> These tablets do have 1.8V signalling implemented in the hw level through
>> the Bay Trail SoC's SD3_1P8EN pin. But trying to use UHS modes leads to
>> lots of errors like these:
>>
>> [  225.272001] mmc2: Unexpected interrupt 0x04000000.
>> [  225.272024] mmc2: sdhci: ============ SDHCI REGISTER DUMP ===========
>> [  225.272034] mmc2: sdhci: Sys addr:  0x0712c400 | Version:  0x0000b502
>> [  225.272044] mmc2: sdhci: Blk size:  0x00007200 | Blk cnt:  0x00000007
>> [  225.272054] mmc2: sdhci: Argument:  0x00000000 | Trn mode: 0x00000023
>> [  225.272064] mmc2: sdhci: Present:   0x01e20002 | Host ctl: 0x00000016
>> [  225.272073] mmc2: sdhci: Power:     0x0000000f | Blk gap:  0x00000000
>> [  225.272082] mmc2: sdhci: Wake-up:   0x00000000 | Clock:    0x00000107
>> [  225.272092] mmc2: sdhci: Timeout:   0x0000000e | Int stat: 0x00000001
>> [  225.272101] mmc2: sdhci: Int enab:  0x03ff000b | Sig enab: 0x03ff000b
>> [  225.272110] mmc2: sdhci: ACmd stat: 0x00000000 | Slot int: 0x00000001
>> [  225.272119] mmc2: sdhci: Caps:      0x076864b2 | Caps_1:   0x00000004
>> [  225.272129] mmc2: sdhci: Cmd:       0x00000c1b | Max curr: 0x00000000
>> [  225.272138] mmc2: sdhci: Resp[0]:   0x00000c00 | Resp[1]:  0x00000000
>> [  225.272147] mmc2: sdhci: Resp[2]:   0x00000000 | Resp[3]:  0x00000900
>> [  225.272155] mmc2: sdhci: Host ctl2: 0x0000000c
>> [  225.272164] mmc2: sdhci: ADMA Err:  0x00000003 | ADMA Ptr: 0x0712c200
>> [  225.272172] mmc2: sdhci: ============================================
>>
> 
> 0x04000000 is so-called "Tuning Error" which oddly the SDHCI driver
> does not support / enable.
> 
> Could try making the IRQ handler process it and see if that helps:

Thank you. I'll give this a try when I've some time.

Note though that the factory Android OS actually also sets
(hardcodes) the SDHCI_QUIRK2_NO_1_8_V quirk2 flag for the external
microsd slot and as I mentioned I've not seen any other Bay Trail
device (and I have quite a few) enable UHS modes on their external
sdcard slot. The datasheet for the Bay Trail SoC claims UHS modes
should work, but it seems that in practice the hw-enablement work
for this was never done.

As I mentioned below the cut-off I have even contemplated to
always set SDHCI_QUIRK2_NO_1_8_V on the external sd slot for
all Bay Trail devices because of this. So I'm wondering if
it would not be safer to just disable UHS modes on Bay Trail
devices and leave things at that ?

Part of my thinking here is that given both that it is only
enabled in the first place on these 3 models as well as how old
these tablets are that it might be better to spend time elsewhere?

Regards,

Hans






> 
> 
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index c79f73459915..746f4cf7ab03 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -3439,12 +3439,18 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
>  		host->data->error = -EILSEQ;
>  		if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
>  			sdhci_err_stats_inc(host, DAT_CRC);
> -	} else if ((intmask & SDHCI_INT_DATA_CRC) &&
> +	} else if ((intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_TUNING_ERROR)) &&
>  		SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))
>  			!= MMC_BUS_TEST_R) {
>  		host->data->error = -EILSEQ;
>  		if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
>  			sdhci_err_stats_inc(host, DAT_CRC);
> +		if (intmask & SDHCI_INT_TUNING_ERROR) {
> +			u16 ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
> +
> +			ctrl2 &= ~SDHCI_CTRL_TUNED_CLK;
> +			sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
> +		}
>  	} else if (intmask & SDHCI_INT_ADMA_ERROR) {
>  		pr_err("%s: ADMA error: 0x%08x\n", mmc_hostname(host->mmc),
>  		       intmask);
> @@ -3979,7 +3985,7 @@ bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error,
>  	} else
>  		*cmd_error = 0;
>  
> -	if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC)) {
> +	if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC | SDHCI_INT_TUNING_ERROR)) {
>  		*data_error = -EILSEQ;
>  		if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
>  			sdhci_err_stats_inc(host, DAT_CRC);
> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> index a20864fc0641..957c7a917ffb 100644
> --- a/drivers/mmc/host/sdhci.h
> +++ b/drivers/mmc/host/sdhci.h
> @@ -158,6 +158,7 @@
>  #define  SDHCI_INT_BUS_POWER	0x00800000
>  #define  SDHCI_INT_AUTO_CMD_ERR	0x01000000
>  #define  SDHCI_INT_ADMA_ERROR	0x02000000
> +#define  SDHCI_INT_TUNING_ERROR	0x04000000
>  
>  #define  SDHCI_INT_NORMAL_MASK	0x00007FFF
>  #define  SDHCI_INT_ERROR_MASK	0xFFFF8000
> @@ -169,7 +170,7 @@
>  		SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
>  		SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
>  		SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR | \
> -		SDHCI_INT_BLK_GAP)
> +		SDHCI_INT_BLK_GAP | SDHCI_INT_TUNING_ERROR)
>  #define SDHCI_INT_ALL_MASK	((unsigned int)-1)
>  
>  #define SDHCI_CQE_INT_ERR_MASK ( \
> 
>
Hans de Goede April 10, 2024, 5:11 p.m. UTC | #3
Hi Adrian,

On 4/9/24 12:37 PM, Adrian Hunter wrote:
> On 8/04/24 22:52, Hans de Goede wrote:
>> Unlike all other Bay Trail devices I have (quite a few) the BIOS on
>> the Lenovo Yoga Tablet 2 830 / 1050 and Lenovo Yoga Tablet 2 Pro 1380 (8",
>> 10" and 13") models sets the SDHCI_SUPPORT_DDR50 bit in the sdcard slots'
>> SDHCI controller's Caps_1 register which causes Linux to try and use
>> UHS SDR12 / SDR25 and DDR50 modes on UHS cards.
>>
>> These tablets do have 1.8V signalling implemented in the hw level through
>> the Bay Trail SoC's SD3_1P8EN pin. But trying to use UHS modes leads to
>> lots of errors like these:
>>
>> [  225.272001] mmc2: Unexpected interrupt 0x04000000.
>> [  225.272024] mmc2: sdhci: ============ SDHCI REGISTER DUMP ===========
>> [  225.272034] mmc2: sdhci: Sys addr:  0x0712c400 | Version:  0x0000b502
>> [  225.272044] mmc2: sdhci: Blk size:  0x00007200 | Blk cnt:  0x00000007
>> [  225.272054] mmc2: sdhci: Argument:  0x00000000 | Trn mode: 0x00000023
>> [  225.272064] mmc2: sdhci: Present:   0x01e20002 | Host ctl: 0x00000016
>> [  225.272073] mmc2: sdhci: Power:     0x0000000f | Blk gap:  0x00000000
>> [  225.272082] mmc2: sdhci: Wake-up:   0x00000000 | Clock:    0x00000107
>> [  225.272092] mmc2: sdhci: Timeout:   0x0000000e | Int stat: 0x00000001
>> [  225.272101] mmc2: sdhci: Int enab:  0x03ff000b | Sig enab: 0x03ff000b
>> [  225.272110] mmc2: sdhci: ACmd stat: 0x00000000 | Slot int: 0x00000001
>> [  225.272119] mmc2: sdhci: Caps:      0x076864b2 | Caps_1:   0x00000004
>> [  225.272129] mmc2: sdhci: Cmd:       0x00000c1b | Max curr: 0x00000000
>> [  225.272138] mmc2: sdhci: Resp[0]:   0x00000c00 | Resp[1]:  0x00000000
>> [  225.272147] mmc2: sdhci: Resp[2]:   0x00000000 | Resp[3]:  0x00000900
>> [  225.272155] mmc2: sdhci: Host ctl2: 0x0000000c
>> [  225.272164] mmc2: sdhci: ADMA Err:  0x00000003 | ADMA Ptr: 0x0712c200
>> [  225.272172] mmc2: sdhci: ============================================
>>
> 
> 0x04000000 is so-called "Tuning Error" which oddly the SDHCI driver
> does not support / enable.
> 
> Could try making the IRQ handler process it and see if that helps:

Good news I have applied this diff and with that everything seems
to just work. No need to add the SDHCI_QUIRK2_PRESET_VALUE_BROKEN, just
this patch from you and then things work.

I'll prepare a v3 patch-set replacing this patch with your "Tuning Error"
handling patch with you as the author.

Regards,

Hans




> 
> 
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index c79f73459915..746f4cf7ab03 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -3439,12 +3439,18 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
>  		host->data->error = -EILSEQ;
>  		if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
>  			sdhci_err_stats_inc(host, DAT_CRC);
> -	} else if ((intmask & SDHCI_INT_DATA_CRC) &&
> +	} else if ((intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_TUNING_ERROR)) &&
>  		SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))
>  			!= MMC_BUS_TEST_R) {
>  		host->data->error = -EILSEQ;
>  		if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
>  			sdhci_err_stats_inc(host, DAT_CRC);
> +		if (intmask & SDHCI_INT_TUNING_ERROR) {
> +			u16 ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
> +
> +			ctrl2 &= ~SDHCI_CTRL_TUNED_CLK;
> +			sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
> +		}
>  	} else if (intmask & SDHCI_INT_ADMA_ERROR) {
>  		pr_err("%s: ADMA error: 0x%08x\n", mmc_hostname(host->mmc),
>  		       intmask);
> @@ -3979,7 +3985,7 @@ bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error,
>  	} else
>  		*cmd_error = 0;
>  
> -	if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC)) {
> +	if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC | SDHCI_INT_TUNING_ERROR)) {
>  		*data_error = -EILSEQ;
>  		if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
>  			sdhci_err_stats_inc(host, DAT_CRC);
> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> index a20864fc0641..957c7a917ffb 100644
> --- a/drivers/mmc/host/sdhci.h
> +++ b/drivers/mmc/host/sdhci.h
> @@ -158,6 +158,7 @@
>  #define  SDHCI_INT_BUS_POWER	0x00800000
>  #define  SDHCI_INT_AUTO_CMD_ERR	0x01000000
>  #define  SDHCI_INT_ADMA_ERROR	0x02000000
> +#define  SDHCI_INT_TUNING_ERROR	0x04000000
>  
>  #define  SDHCI_INT_NORMAL_MASK	0x00007FFF
>  #define  SDHCI_INT_ERROR_MASK	0xFFFF8000
> @@ -169,7 +170,7 @@
>  		SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
>  		SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
>  		SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR | \
> -		SDHCI_INT_BLK_GAP)
> +		SDHCI_INT_BLK_GAP | SDHCI_INT_TUNING_ERROR)
>  #define SDHCI_INT_ALL_MASK	((unsigned int)-1)
>  
>  #define SDHCI_CQE_INT_ERR_MASK ( \
> 
>