summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGUI <[email protected]>2026-08-14 12:39:11 +0800
committerGitHub <[email protected]>2026-08-14 12:39:11 +0800
commit4cf70e176c10548d929c1e4b2124cdfb0899c384 (patch)
treed31f302395ea87bc58975a70e4bc10fd29adfafa
parent76b0267361973953b4b8a05a11208379f81f7a8d (diff)
[dm][sdio] Update for SDHCI- #11684 #11684
-rwxr-xr-xcomponents/drivers/include/drivers/dev_sdhci.h649
-rwxr-xr-xcomponents/drivers/sdio/dev_regulator.c56
-rwxr-xr-xcomponents/drivers/sdio/dev_sdhci.c494
-rwxr-xr-xcomponents/drivers/sdio/dev_sdio_dm.h6
-rwxr-xr-xcomponents/drivers/sdio/host/Kconfig6
-rwxr-xr-xcomponents/drivers/sdio/host/SConscript3
-rw-r--r--components/drivers/sdio/host/sdhci-dwcmshc-platform.c56
-rw-r--r--components/drivers/sdio/host/sdhci-dwcmshc-platform.h19
-rw-r--r--components/drivers/sdio/host/sdhci-dwcmshc.c359
-rw-r--r--components/drivers/sdio/host/sdhci-dwcmshc.h66
10 files changed, 1257 insertions, 457 deletions
diff --git a/components/drivers/include/drivers/dev_sdhci.h b/components/drivers/include/drivers/dev_sdhci.h
index be6e427907..62a6153f1c 100755
--- a/components/drivers/include/drivers/dev_sdhci.h
+++ b/components/drivers/include/drivers/dev_sdhci.h
@@ -17,292 +17,292 @@
#include <drivers/dev_sdhci_host.h>
#include <drivers/dev_mmcsd_core.h>
-#define RT_SDHCI_MAX_TUNING_LOOP 40
+#define RT_SDHCI_MAX_TUNING_LOOP 40
/*
* Controller registers
*/
-#define RT_SDHCI_DMA_ADDRESS 0x00
-#define RT_SDHCI_ARGUMENT2 RT_SDHCI_DMA_ADDRESS
-#define RT_SDHCI_32BIT_BLK_CNT RT_SDHCI_DMA_ADDRESS
+#define RT_SDHCI_DMA_ADDRESS 0x00
+#define RT_SDHCI_ARGUMENT2 RT_SDHCI_DMA_ADDRESS
+#define RT_SDHCI_32BIT_BLK_CNT RT_SDHCI_DMA_ADDRESS
-#define RT_SDHCI_BLOCK_SIZE 0x04
-#define RT_SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))
+#define RT_SDHCI_BLOCK_SIZE 0x04
+#define RT_SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))
-#define RT_SDHCI_BLOCK_COUNT 0x06
+#define RT_SDHCI_BLOCK_COUNT 0x06
-#define RT_SDHCI_ARGUMENT 0x08
+#define RT_SDHCI_ARGUMENT 0x08
-#define RT_SDHCI_TRANSFER_MODE 0x0c
-#define RT_SDHCI_TRNS_DMA 0x01
-#define RT_SDHCI_TRNS_BLK_CNT_EN 0x02
-#define RT_SDHCI_TRNS_AUTO_CMD12 0x04
-#define RT_SDHCI_TRNS_AUTO_CMD23 0x08
-#define RT_SDHCI_TRNS_AUTO_SEL 0x0c
-#define RT_SDHCI_TRNS_READ 0x10
-#define RT_SDHCI_TRNS_MULTI 0x20
+#define RT_SDHCI_TRANSFER_MODE 0x0c
+#define RT_SDHCI_TRNS_DMA 0x01
+#define RT_SDHCI_TRNS_BLK_CNT_EN 0x02
+#define RT_SDHCI_TRNS_AUTO_CMD12 0x04
+#define RT_SDHCI_TRNS_AUTO_CMD23 0x08
+#define RT_SDHCI_TRNS_AUTO_SEL 0x0c
+#define RT_SDHCI_TRNS_READ 0x10
+#define RT_SDHCI_TRNS_MULTI 0x20
-#define RT_SDHCI_COMMAND 0x0e
-#define RT_SDHCI_CMD_RESP_MASK 0x03
-#define RT_SDHCI_CMD_CRC 0x08
-#define RT_SDHCI_CMD_INDEX 0x10
-#define RT_SDHCI_CMD_DATA 0x20
-#define RT_SDHCI_CMD_ABORTCMD 0xc0
+#define RT_SDHCI_COMMAND 0x0e
+#define RT_SDHCI_CMD_RESP_MASK 0x03
+#define RT_SDHCI_CMD_CRC 0x08
+#define RT_SDHCI_CMD_INDEX 0x10
+#define RT_SDHCI_CMD_DATA 0x20
+#define RT_SDHCI_CMD_ABORTCMD 0xc0
-#define RT_SDHCI_CMD_RESP_NONE 0x00
-#define RT_SDHCI_CMD_RESP_LONG 0x01
-#define RT_SDHCI_CMD_RESP_SHORT 0x02
-#define RT_SDHCI_CMD_RESP_SHORT_BUSY 0x03
+#define RT_SDHCI_CMD_RESP_NONE 0x00
+#define RT_SDHCI_CMD_RESP_LONG 0x01
+#define RT_SDHCI_CMD_RESP_SHORT 0x02
+#define RT_SDHCI_CMD_RESP_SHORT_BUSY 0x03
-#define RT_SDHCI_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff))
-#define RT_SDHCI_GET_CMD(c) ((c >> 8) & 0x3f)
+#define RT_SDHCI_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff))
+#define RT_SDHCI_GET_CMD(c) ((c >> 8) & 0x3f)
-#define RT_SDHCI_RESPONSE 0x10
+#define RT_SDHCI_RESPONSE 0x10
-#define RT_SDHCI_BUFFER 0x20
+#define RT_SDHCI_BUFFER 0x20
-#define RT_SDHCI_PRESENT_STATE 0x24
-#define RT_SDHCI_CMD_INHIBIT 0x00000001
-#define RT_SDHCI_DATA_INHIBIT 0x00000002
-#define RT_SDHCI_DOING_WRITE 0x00000100
-#define RT_SDHCI_DOING_READ 0x00000200
-#define RT_SDHCI_SPACE_AVAILABLE 0x00000400
-#define RT_SDHCI_DATA_AVAILABLE 0x00000800
-#define RT_SDHCI_CARD_PRESENT 0x00010000
-#define RT_SDHCI_CARD_PRES_SHIFT 16
-#define RT_SDHCI_CD_STABLE 0x00020000
-#define RT_SDHCI_CD_LVL 0x00040000
-#define RT_SDHCI_CD_LVL_SHIFT 18
-#define RT_SDHCI_WRITE_PROTECT 0x00080000
-#define RT_SDHCI_DATA_LVL_MASK 0x00f00000
-#define RT_SDHCI_DATA_LVL_SHIFT 20
-#define RT_SDHCI_DATA_0_LVL_MASK 0x00100000
-#define RT_SDHCI_CMD_LVL 0x01000000
+#define RT_SDHCI_PRESENT_STATE 0x24
+#define RT_SDHCI_CMD_INHIBIT 0x00000001
+#define RT_SDHCI_DATA_INHIBIT 0x00000002
+#define RT_SDHCI_DOING_WRITE 0x00000100
+#define RT_SDHCI_DOING_READ 0x00000200
+#define RT_SDHCI_SPACE_AVAILABLE 0x00000400
+#define RT_SDHCI_DATA_AVAILABLE 0x00000800
+#define RT_SDHCI_CARD_PRESENT 0x00010000
+#define RT_SDHCI_CARD_PRES_SHIFT 16
+#define RT_SDHCI_CD_STABLE 0x00020000
+#define RT_SDHCI_CD_LVL 0x00040000
+#define RT_SDHCI_CD_LVL_SHIFT 18
+#define RT_SDHCI_WRITE_PROTECT 0x00080000
+#define RT_SDHCI_DATA_LVL_MASK 0x00f00000
+#define RT_SDHCI_DATA_LVL_SHIFT 20
+#define RT_SDHCI_DATA_0_LVL_MASK 0x00100000
+#define RT_SDHCI_CMD_LVL 0x01000000
-#define RT_SDHCI_HOST_CONTROL 0x28
-#define RT_SDHCI_CTRL_LED 0x01
-#define RT_SDHCI_CTRL_4BITBUS 0x02
-#define RT_SDHCI_CTRL_HISPD 0x04
-#define RT_SDHCI_CTRL_DMA_MASK 0x18
-#define RT_SDHCI_CTRL_SDMA 0x00
-#define RT_SDHCI_CTRL_ADMA1 0x08
-#define RT_SDHCI_CTRL_ADMA32 0x10
-#define RT_SDHCI_CTRL_ADMA64 0x18
-#define RT_SDHCI_CTRL_ADMA3 0x18
-#define RT_SDHCI_CTRL_8BITBUS 0x20
-#define RT_SDHCI_CTRL_CDTEST_INS 0x40
-#define RT_SDHCI_CTRL_CDTEST_EN 0x80
+#define RT_SDHCI_HOST_CONTROL 0x28
+#define RT_SDHCI_CTRL_LED 0x01
+#define RT_SDHCI_CTRL_4BITBUS 0x02
+#define RT_SDHCI_CTRL_HISPD 0x04
+#define RT_SDHCI_CTRL_DMA_MASK 0x18
+#define RT_SDHCI_CTRL_SDMA 0x00
+#define RT_SDHCI_CTRL_ADMA1 0x08
+#define RT_SDHCI_CTRL_ADMA32 0x10
+#define RT_SDHCI_CTRL_ADMA64 0x18
+#define RT_SDHCI_CTRL_ADMA3 0x18
+#define RT_SDHCI_CTRL_8BITBUS 0x20
+#define RT_SDHCI_CTRL_CDTEST_INS 0x40
+#define RT_SDHCI_CTRL_CDTEST_EN 0x80
-#define RT_SDHCI_POWER_CONTROL 0x29
-#define RT_SDHCI_POWER_ON 0x01
-#define RT_SDHCI_POWER_180 0x0a
-#define RT_SDHCI_POWER_300 0x0c
-#define RT_SDHCI_POWER_330 0x0e
+#define RT_SDHCI_POWER_CONTROL 0x29
+#define RT_SDHCI_POWER_ON 0x01
+#define RT_SDHCI_POWER_180 0x0a
+#define RT_SDHCI_POWER_300 0x0c
+#define RT_SDHCI_POWER_330 0x0e
/*
* VDD2 - UHS2 or PCIe/NVMe
* VDD2 power on/off and voltage select
*/
-#define RT_SDHCI_VDD2_POWER_ON 0x10
-#define RT_SDHCI_VDD2_POWER_120 0x80
-#define RT_SDHCI_VDD2_POWER_180 0xa0
+#define RT_SDHCI_VDD2_POWER_ON 0x10
+#define RT_SDHCI_VDD2_POWER_120 0x80
+#define RT_SDHCI_VDD2_POWER_180 0xa0
-#define RT_SDHCI_BLOCK_GAP_CONTROL 0x2a
+#define RT_SDHCI_BLOCK_GAP_CONTROL 0x2a
-#define RT_SDHCI_WAKE_UP_CONTROL 0x2b
-#define RT_SDHCI_WAKE_ON_INT 0x01
-#define RT_SDHCI_WAKE_ON_INSERT 0x02
-#define RT_SDHCI_WAKE_ON_REMOVE 0x04
+#define RT_SDHCI_WAKE_UP_CONTROL 0x2b
+#define RT_SDHCI_WAKE_ON_INT 0x01
+#define RT_SDHCI_WAKE_ON_INSERT 0x02
+#define RT_SDHCI_WAKE_ON_REMOVE 0x04
-#define RT_SDHCI_CLOCK_CONTROL 0x2c
-#define RT_SDHCI_DIVIDER_SHIFT 8
-#define RT_SDHCI_DIVIDER_HI_SHIFT 6
-#define RT_SDHCI_DIV_MASK 0xff
-#define RT_SDHCI_DIV_MASK_LEN 8
-#define RT_SDHCI_DIV_HI_MASK 0x300
-#define RT_SDHCI_PROG_CLOCK_MODE 0x0020
-#define RT_SDHCI_CLOCK_CARD_EN 0x0004
-#define RT_SDHCI_CLOCK_PLL_EN 0x0008
-#define RT_SDHCI_CLOCK_INT_STABLE 0x0002
-#define RT_SDHCI_CLOCK_INT_EN 0x0001
+#define RT_SDHCI_CLOCK_CONTROL 0x2c
+#define RT_SDHCI_DIVIDER_SHIFT 8
+#define RT_SDHCI_DIVIDER_HI_SHIFT 6
+#define RT_SDHCI_DIV_MASK 0xff
+#define RT_SDHCI_DIV_MASK_LEN 8
+#define RT_SDHCI_DIV_HI_MASK 0x300
+#define RT_SDHCI_PROG_CLOCK_MODE 0x0020
+#define RT_SDHCI_CLOCK_CARD_EN 0x0004
+#define RT_SDHCI_CLOCK_PLL_EN 0x0008
+#define RT_SDHCI_CLOCK_INT_STABLE 0x0002
+#define RT_SDHCI_CLOCK_INT_EN 0x0001
-#define RT_SDHCI_TIMEOUT_CONTROL 0x2e
+#define RT_SDHCI_TIMEOUT_CONTROL 0x2e
-#define RT_SDHCI_SOFTWARE_RESET 0x2f
-#define RT_SDHCI_RESET_ALL 0x01
-#define RT_SDHCI_RESET_CMD 0x02
-#define RT_SDHCI_RESET_DATA 0x04
+#define RT_SDHCI_SOFTWARE_RESET 0x2f
+#define RT_SDHCI_RESET_ALL 0x01
+#define RT_SDHCI_RESET_CMD 0x02
+#define RT_SDHCI_RESET_DATA 0x04
-#define RT_SDHCI_INT_STATUS 0x30
-#define RT_SDHCI_INT_ENABLE 0x34
-#define RT_SDHCI_SIGNAL_ENABLE 0x38
-#define RT_SDHCI_INT_RESPONSE 0x00000001
-#define RT_SDHCI_INT_DATA_END 0x00000002
-#define RT_SDHCI_INT_BLK_GAP 0x00000004
-#define RT_SDHCI_INT_DMA_END 0x00000008
-#define RT_SDHCI_INT_SPACE_AVAIL 0x00000010
-#define RT_SDHCI_INT_DATA_AVAIL 0x00000020
-#define RT_SDHCI_INT_CARD_INSERT 0x00000040
-#define RT_SDHCI_INT_CARD_REMOVE 0x00000080
-#define RT_SDHCI_INT_CARD_INT 0x00000100
-#define RT_SDHCI_INT_RETUNE 0x00001000
-#define RT_SDHCI_INT_CQE 0x00004000
-#define RT_SDHCI_INT_ERROR 0x00008000
-#define RT_SDHCI_INT_TIMEOUT 0x00010000
-#define RT_SDHCI_INT_CRC 0x00020000
-#define RT_SDHCI_INT_END_BIT 0x00040000
-#define RT_SDHCI_INT_INDEX 0x00080000
-#define RT_SDHCI_INT_DATA_TIMEOUT 0x00100000
-#define RT_SDHCI_INT_DATA_CRC 0x00200000
-#define RT_SDHCI_INT_DATA_END_BIT 0x00400000
-#define RT_SDHCI_INT_BUS_POWER 0x00800000
-#define RT_SDHCI_INT_AUTO_CMD_ERR 0x01000000
-#define RT_SDHCI_INT_ADMA_ERROR 0x02000000
+#define RT_SDHCI_INT_STATUS 0x30
+#define RT_SDHCI_INT_ENABLE 0x34
+#define RT_SDHCI_SIGNAL_ENABLE 0x38
+#define RT_SDHCI_INT_RESPONSE 0x00000001
+#define RT_SDHCI_INT_DATA_END 0x00000002
+#define RT_SDHCI_INT_BLK_GAP 0x00000004
+#define RT_SDHCI_INT_DMA_END 0x00000008
+#define RT_SDHCI_INT_SPACE_AVAIL 0x00000010
+#define RT_SDHCI_INT_DATA_AVAIL 0x00000020
+#define RT_SDHCI_INT_CARD_INSERT 0x00000040
+#define RT_SDHCI_INT_CARD_REMOVE 0x00000080
+#define RT_SDHCI_INT_CARD_INT 0x00000100
+#define RT_SDHCI_INT_RETUNE 0x00001000
+#define RT_SDHCI_INT_CQE 0x00004000
+#define RT_SDHCI_INT_ERROR 0x00008000
+#define RT_SDHCI_INT_TIMEOUT 0x00010000
+#define RT_SDHCI_INT_CRC 0x00020000
+#define RT_SDHCI_INT_END_BIT 0x00040000
+#define RT_SDHCI_INT_INDEX 0x00080000
+#define RT_SDHCI_INT_DATA_TIMEOUT 0x00100000
+#define RT_SDHCI_INT_DATA_CRC 0x00200000
+#define RT_SDHCI_INT_DATA_END_BIT 0x00400000
+#define RT_SDHCI_INT_BUS_POWER 0x00800000
+#define RT_SDHCI_INT_AUTO_CMD_ERR 0x01000000
+#define RT_SDHCI_INT_ADMA_ERROR 0x02000000
-#define RT_SDHCI_INT_NORMAL_MASK 0x00007fff
-#define RT_SDHCI_INT_ERROR_MASK 0xffff8000
+#define RT_SDHCI_INT_NORMAL_MASK 0x00007fff
+#define RT_SDHCI_INT_ERROR_MASK 0xffff8000
-#define RT_SDHCI_INT_CMD_MASK (RT_SDHCI_INT_RESPONSE | RT_SDHCI_INT_TIMEOUT | \
- RT_SDHCI_INT_CRC | RT_SDHCI_INT_END_BIT | \
- RT_SDHCI_INT_INDEX | RT_SDHCI_INT_AUTO_CMD_ERR)
-#define RT_SDHCI_INT_DATA_MASK (RT_SDHCI_INT_DATA_END | RT_SDHCI_INT_DMA_END | \
- RT_SDHCI_INT_DATA_AVAIL | RT_SDHCI_INT_SPACE_AVAIL | \
- RT_SDHCI_INT_DATA_TIMEOUT | RT_SDHCI_INT_DATA_CRC | \
- RT_SDHCI_INT_DATA_END_BIT | RT_SDHCI_INT_ADMA_ERROR | \
- RT_SDHCI_INT_BLK_GAP)
-#define RT_SDHCI_INT_ALL_MASK ((rt_uint32_t)-1)
+#define RT_SDHCI_INT_CMD_MASK (RT_SDHCI_INT_RESPONSE | RT_SDHCI_INT_TIMEOUT | \
+ RT_SDHCI_INT_CRC | RT_SDHCI_INT_END_BIT | \
+ RT_SDHCI_INT_INDEX | RT_SDHCI_INT_AUTO_CMD_ERR)
+#define RT_SDHCI_INT_DATA_MASK (RT_SDHCI_INT_DATA_END | RT_SDHCI_INT_DMA_END | \
+ RT_SDHCI_INT_DATA_AVAIL | RT_SDHCI_INT_SPACE_AVAIL | \
+ RT_SDHCI_INT_DATA_TIMEOUT | RT_SDHCI_INT_DATA_CRC | \
+ RT_SDHCI_INT_DATA_END_BIT | RT_SDHCI_INT_ADMA_ERROR | \
+ RT_SDHCI_INT_BLK_GAP)
+#define RT_SDHCI_INT_ALL_MASK ((rt_uint32_t) - 1)
-#define RT_SDHCI_CQE_INT_ERR_MASK (RT_SDHCI_INT_ADMA_ERROR | RT_SDHCI_INT_BUS_POWER | \
- RT_SDHCI_INT_DATA_END_BIT | RT_SDHCI_INT_DATA_CRC | \
- RT_SDHCI_INT_DATA_TIMEOUT | RT_SDHCI_INT_INDEX | \
- RT_SDHCI_INT_END_BIT | RT_SDHCI_INT_CRC | RT_SDHCI_INT_TIMEOUT)
+#define RT_SDHCI_CQE_INT_ERR_MASK (RT_SDHCI_INT_ADMA_ERROR | RT_SDHCI_INT_BUS_POWER | \
+ RT_SDHCI_INT_DATA_END_BIT | RT_SDHCI_INT_DATA_CRC | \
+ RT_SDHCI_INT_DATA_TIMEOUT | RT_SDHCI_INT_INDEX | \
+ RT_SDHCI_INT_END_BIT | RT_SDHCI_INT_CRC | RT_SDHCI_INT_TIMEOUT)
-#define RT_SDHCI_CQE_INT_MASK (RT_SDHCI_CQE_INT_ERR_MASK | RT_SDHCI_INT_CQE)
+#define RT_SDHCI_CQE_INT_MASK (RT_SDHCI_CQE_INT_ERR_MASK | RT_SDHCI_INT_CQE)
-#define RT_SDHCI_AUTO_CMD_STATUS 0x3c
-#define RT_SDHCI_AUTO_CMD_TIMEOUT 0x00000002
-#define RT_SDHCI_AUTO_CMD_CRC 0x00000004
-#define RT_SDHCI_AUTO_CMD_END_BIT 0x00000008
-#define RT_SDHCI_AUTO_CMD_INDEX 0x00000010
+#define RT_SDHCI_AUTO_CMD_STATUS 0x3c
+#define RT_SDHCI_AUTO_CMD_TIMEOUT 0x00000002
+#define RT_SDHCI_AUTO_CMD_CRC 0x00000004
+#define RT_SDHCI_AUTO_CMD_END_BIT 0x00000008
+#define RT_SDHCI_AUTO_CMD_INDEX 0x00000010
-#define RT_SDHCI_HOST_CONTROL2 0x3e
-#define RT_SDHCI_CTRL_UHS_MASK 0x0007
-#define RT_SDHCI_CTRL_UHS_SDR12 0x0000
-#define RT_SDHCI_CTRL_UHS_SDR25 0x0001
-#define RT_SDHCI_CTRL_UHS_SDR50 0x0002
-#define RT_SDHCI_CTRL_UHS_SDR104 0x0003
-#define RT_SDHCI_CTRL_UHS_DDR50 0x0004
-#define RT_SDHCI_CTRL_HS400 0x0005 /* Non-standard */
-#define RT_SDHCI_CTRL_VDD_180 0x0008
-#define RT_SDHCI_CTRL_DRV_TYPE_MASK 0x0030
-#define RT_SDHCI_CTRL_DRV_TYPE_B 0x0000
-#define RT_SDHCI_CTRL_DRV_TYPE_A 0x0010
-#define RT_SDHCI_CTRL_DRV_TYPE_C 0x0020
-#define RT_SDHCI_CTRL_DRV_TYPE_D 0x0030
-#define RT_SDHCI_CTRL_EXEC_TUNING 0x0040
-#define RT_SDHCI_CTRL_TUNED_CLK 0x0080
-#define RT_SDHCI_CMD23_ENABLE 0x0800
-#define RT_SDHCI_CTRL_V4_MODE 0x1000
-#define RT_SDHCI_CTRL_64BIT_ADDR 0x2000
-#define RT_SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000
+#define RT_SDHCI_HOST_CONTROL2 0x3e
+#define RT_SDHCI_CTRL_UHS_MASK 0x0007
+#define RT_SDHCI_CTRL_UHS_SDR12 0x0000
+#define RT_SDHCI_CTRL_UHS_SDR25 0x0001
+#define RT_SDHCI_CTRL_UHS_SDR50 0x0002
+#define RT_SDHCI_CTRL_UHS_SDR104 0x0003
+#define RT_SDHCI_CTRL_UHS_DDR50 0x0004
+#define RT_SDHCI_CTRL_HS400 0x0005 /* Non-standard */
+#define RT_SDHCI_CTRL_VDD_180 0x0008
+#define RT_SDHCI_CTRL_DRV_TYPE_MASK 0x0030
+#define RT_SDHCI_CTRL_DRV_TYPE_B 0x0000
+#define RT_SDHCI_CTRL_DRV_TYPE_A 0x0010
+#define RT_SDHCI_CTRL_DRV_TYPE_C 0x0020
+#define RT_SDHCI_CTRL_DRV_TYPE_D 0x0030
+#define RT_SDHCI_CTRL_EXEC_TUNING 0x0040
+#define RT_SDHCI_CTRL_TUNED_CLK 0x0080
+#define RT_SDHCI_CMD23_ENABLE 0x0800
+#define RT_SDHCI_CTRL_V4_MODE 0x1000
+#define RT_SDHCI_CTRL_64BIT_ADDR 0x2000
+#define RT_SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000
-#define RT_SDHCI_CAPABILITIES 0x40
-#define RT_SDHCI_TIMEOUT_CLK_MASK RT_GENMASK(5, 0)
-#define RT_SDHCI_TIMEOUT_CLK_SHIFT 0
-#define RT_SDHCI_TIMEOUT_CLK_UNIT 0x00000080
-#define RT_SDHCI_CLOCK_BASE_MASK RT_GENMASK(13, 8)
-#define RT_SDHCI_CLOCK_BASE_SHIFT 8
-#define RT_SDHCI_CLOCK_V3_BASE_MASK RT_GENMASK(15, 8)
-#define RT_SDHCI_MAX_BLOCK_MASK 0x00030000
-#define RT_SDHCI_MAX_BLOCK_SHIFT 16
-#define RT_SDHCI_CAN_DO_8BIT 0x00040000
-#define RT_SDHCI_CAN_DO_ADMA2 0x00080000
-#define RT_SDHCI_CAN_DO_ADMA1 0x00100000
-#define RT_SDHCI_CAN_DO_HISPD 0x00200000
-#define RT_SDHCI_CAN_DO_SDMA 0x00400000
-#define RT_SDHCI_CAN_DO_SUSPEND 0x00800000
-#define RT_SDHCI_CAN_VDD_330 0x01000000
-#define RT_SDHCI_CAN_VDD_300 0x02000000
-#define RT_SDHCI_CAN_VDD_180 0x04000000
-#define RT_SDHCI_CAN_64BIT_V4 0x08000000
-#define RT_SDHCI_CAN_64BIT 0x10000000
+#define RT_SDHCI_CAPABILITIES 0x40
+#define RT_SDHCI_TIMEOUT_CLK_MASK RT_GENMASK(5, 0)
+#define RT_SDHCI_TIMEOUT_CLK_SHIFT 0
+#define RT_SDHCI_TIMEOUT_CLK_UNIT 0x00000080
+#define RT_SDHCI_CLOCK_BASE_MASK RT_GENMASK(13, 8)
+#define RT_SDHCI_CLOCK_BASE_SHIFT 8
+#define RT_SDHCI_CLOCK_V3_BASE_MASK RT_GENMASK(15, 8)
+#define RT_SDHCI_MAX_BLOCK_MASK 0x00030000
+#define RT_SDHCI_MAX_BLOCK_SHIFT 16
+#define RT_SDHCI_CAN_DO_8BIT 0x00040000
+#define RT_SDHCI_CAN_DO_ADMA2 0x00080000
+#define RT_SDHCI_CAN_DO_ADMA1 0x00100000
+#define RT_SDHCI_CAN_DO_HISPD 0x00200000
+#define RT_SDHCI_CAN_DO_SDMA 0x00400000
+#define RT_SDHCI_CAN_DO_SUSPEND 0x00800000
+#define RT_SDHCI_CAN_VDD_330 0x01000000
+#define RT_SDHCI_CAN_VDD_300 0x02000000
+#define RT_SDHCI_CAN_VDD_180 0x04000000
+#define RT_SDHCI_CAN_64BIT_V4 0x08000000
+#define RT_SDHCI_CAN_64BIT 0x10000000
-#define RT_SDHCI_CAPABILITIES_1 0x44
-#define RT_SDHCI_SUPPORT_SDR50 0x00000001
-#define RT_SDHCI_SUPPORT_SDR104 0x00000002
-#define RT_SDHCI_SUPPORT_DDR50 0x00000004
-#define RT_SDHCI_DRIVER_TYPE_A 0x00000010
-#define RT_SDHCI_DRIVER_TYPE_C 0x00000020
-#define RT_SDHCI_DRIVER_TYPE_D 0x00000040
-#define RT_SDHCI_RETUNING_TIMER_COUNT_MASK RT_GENMASK(11, 8)
-#define RT_SDHCI_USE_SDR50_TUNING 0x00002000
-#define RT_SDHCI_RETUNING_MODE_MASK RT_GENMASK(15, 14)
-#define RT_SDHCI_CLOCK_MUL_MASK RT_GENMASK(23, 16)
-#define RT_SDHCI_CAN_DO_ADMA3 0x08000000
-#define RT_SDHCI_SUPPORT_HS400 0x80000000 /* Non-standard */
+#define RT_SDHCI_CAPABILITIES_1 0x44
+#define RT_SDHCI_SUPPORT_SDR50 0x00000001
+#define RT_SDHCI_SUPPORT_SDR104 0x00000002
+#define RT_SDHCI_SUPPORT_DDR50 0x00000004
+#define RT_SDHCI_DRIVER_TYPE_A 0x00000010
+#define RT_SDHCI_DRIVER_TYPE_C 0x00000020
+#define RT_SDHCI_DRIVER_TYPE_D 0x00000040
+#define RT_SDHCI_RETUNING_TIMER_COUNT_MASK RT_GENMASK(11, 8)
+#define RT_SDHCI_USE_SDR50_TUNING 0x00002000
+#define RT_SDHCI_RETUNING_MODE_MASK RT_GENMASK(15, 14)
+#define RT_SDHCI_CLOCK_MUL_MASK RT_GENMASK(23, 16)
+#define RT_SDHCI_CAN_DO_ADMA3 0x08000000
+#define RT_SDHCI_SUPPORT_HS400 0x80000000 /* Non-standard */
-#define RT_SDHCI_MAX_CURRENT 0x48
-#define RT_SDHCI_MAX_CURRENT_LIMIT RT_GENMASK(7, 0)
-#define RT_SDHCI_MAX_CURRENT_330_MASK RT_GENMASK(7, 0)
-#define RT_SDHCI_MAX_CURRENT_300_MASK RT_GENMASK(15, 8)
-#define RT_SDHCI_MAX_CURRENT_180_MASK RT_GENMASK(23, 16)
-#define RT_SDHCI_MAX_CURRENT_MULTIPLIER 4
+#define RT_SDHCI_MAX_CURRENT 0x48
+#define RT_SDHCI_MAX_CURRENT_LIMIT RT_GENMASK(7, 0)
+#define RT_SDHCI_MAX_CURRENT_330_MASK RT_GENMASK(7, 0)
+#define RT_SDHCI_MAX_CURRENT_300_MASK RT_GENMASK(15, 8)
+#define RT_SDHCI_MAX_CURRENT_180_MASK RT_GENMASK(23, 16)
+#define RT_SDHCI_MAX_CURRENT_MULTIPLIER 4
/* 4C-4F reserved for more max current */
-#define RT_SDHCI_SET_ACMD12_ERROR 0x50
-#define RT_SDHCI_SET_INT_ERROR 0x52
+#define RT_SDHCI_SET_ACMD12_ERROR 0x50
+#define RT_SDHCI_SET_INT_ERROR 0x52
-#define RT_SDHCI_ADMA_ERROR 0x54
+#define RT_SDHCI_ADMA_ERROR 0x54
/* 55-57 reserved */
-#define RT_SDHCI_ADMA_ADDRESS 0x58
-#define RT_SDHCI_ADMA_ADDRESS_HI 0x5c
+#define RT_SDHCI_ADMA_ADDRESS 0x58
+#define RT_SDHCI_ADMA_ADDRESS_HI 0x5c
/* 60-FB reserved */
-#define RT_SDHCI_PRESET_FOR_HIGH_SPEED 0x64
-#define RT_SDHCI_PRESET_FOR_SDR12 0x66
-#define RT_SDHCI_PRESET_FOR_SDR25 0x68
-#define RT_SDHCI_PRESET_FOR_SDR50 0x6a
-#define RT_SDHCI_PRESET_FOR_SDR104 0x6c
-#define RT_SDHCI_PRESET_FOR_DDR50 0x6e
-#define RT_SDHCI_PRESET_FOR_HS400 0x74 /* Non-standard */
-#define RT_SDHCI_PRESET_DRV_MASK RT_GENMASK(15, 14)
+#define RT_SDHCI_PRESET_FOR_HIGH_SPEED 0x64
+#define RT_SDHCI_PRESET_FOR_SDR12 0x66
+#define RT_SDHCI_PRESET_FOR_SDR25 0x68
+#define RT_SDHCI_PRESET_FOR_SDR50 0x6a
+#define RT_SDHCI_PRESET_FOR_SDR104 0x6c
+#define RT_SDHCI_PRESET_FOR_DDR50 0x6e
+#define RT_SDHCI_PRESET_FOR_HS400 0x74 /* Non-standard */
+#define RT_SDHCI_PRESET_DRV_MASK RT_GENMASK(15, 14)
-#define RT_SDHCI_PRESET_CLKGEN_SEL RT_BIT(10)
-#define RT_SDHCI_PRESET_SDCLK_FREQ_MASK RT_GENMASK(9, 0)
+#define RT_SDHCI_PRESET_CLKGEN_SEL RT_BIT(10)
+#define RT_SDHCI_PRESET_SDCLK_FREQ_MASK RT_GENMASK(9, 0)
-#define RT_SDHCI_SLOT_INT_STATUS 0xfc
+#define RT_SDHCI_SLOT_INT_STATUS 0xfc
-#define RT_SDHCI_HOST_VERSION 0xfe
-#define RT_SDHCI_VENDOR_VER_MASK 0xff00
-#define RT_SDHCI_VENDOR_VER_SHIFT 8
-#define RT_SDHCI_SPEC_VER_MASK 0x00ff
-#define RT_SDHCI_SPEC_VER_SHIFT 0
-#define RT_SDHCI_SPEC_100 0
-#define RT_SDHCI_SPEC_200 1
-#define RT_SDHCI_SPEC_300 2
-#define RT_SDHCI_SPEC_400 3
-#define RT_SDHCI_SPEC_410 4
-#define RT_SDHCI_SPEC_420 5
+#define RT_SDHCI_HOST_VERSION 0xfe
+#define RT_SDHCI_VENDOR_VER_MASK 0xff00
+#define RT_SDHCI_VENDOR_VER_SHIFT 8
+#define RT_SDHCI_SPEC_VER_MASK 0x00ff
+#define RT_SDHCI_SPEC_VER_SHIFT 0
+#define RT_SDHCI_SPEC_100 0
+#define RT_SDHCI_SPEC_200 1
+#define RT_SDHCI_SPEC_300 2
+#define RT_SDHCI_SPEC_400 3
+#define RT_SDHCI_SPEC_410 4
+#define RT_SDHCI_SPEC_420 5
/*
* End of controller registers.
*/
-#define RT_SDHCI_MAX_DIV_SPEC_200 256
-#define RT_SDHCI_MAX_DIV_SPEC_300 2046
+#define RT_SDHCI_MAX_DIV_SPEC_200 256
+#define RT_SDHCI_MAX_DIV_SPEC_300 2046
/*
* Host SDMA buffer boundary. Valid values from 4K to 512K in powers of 2.
*/
-#define RT_SDHCI_DEFAULT_BOUNDARY_SIZE (512 * 1024)
-#define RT_SDHCI_DEFAULT_BOUNDARY_ARG (rt_ilog2(RT_SDHCI_DEFAULT_BOUNDARY_SIZE) - 12)
-#define RT_SDHCI_MAX_SEGS 128
+#define RT_SDHCI_DEFAULT_BOUNDARY_SIZE (512 * 1024)
+#define RT_SDHCI_DEFAULT_BOUNDARY_ARG (rt_ilog2(RT_SDHCI_DEFAULT_BOUNDARY_SIZE) - 12)
+#define RT_SDHCI_MAX_SEGS 128
/* Allow for a command request and a data request at the same time */
-#define RT_SDHCI_MAX_MRQS 2
-#define MMC_CMD_TRANSFER_TIME (10 * 1000000L) /* max 10 ms */
+#define RT_SDHCI_MAX_MRQS 2
+#define MMC_CMD_TRANSFER_TIME (10 * 1000000L) /* max 10 ms */
enum rt_sdhci_cookie
{
@@ -318,119 +318,121 @@ struct rt_sdhci_host
unsigned int quirks; /* Deviations from spec. */
/* Controller doesn't honor resets unless we touch the clock register */
-#define RT_SDHCI_QUIRK_CLOCK_BEFORE_RESET (1 << 0)
+#define RT_SDHCI_QUIRK_CLOCK_BEFORE_RESET (1 << 0)
/* Controller has bad caps bits, but really supports DMA */
-#define RT_SDHCI_QUIRK_FORCE_DMA (1 << 1)
+#define RT_SDHCI_QUIRK_FORCE_DMA (1 << 1)
/* Controller doesn't like to be reset when there is no card inserted. */
-#define RT_SDHCI_QUIRK_NO_CARD_NO_RESET (1 << 2)
+#define RT_SDHCI_QUIRK_NO_CARD_NO_RESET (1 << 2)
/* Controller doesn't like clearing the power reg before a change */
-#define RT_SDHCI_QUIRK_SINGLE_POWER_WRITE (1 << 3)
+#define RT_SDHCI_QUIRK_SINGLE_POWER_WRITE (1 << 3)
/* Controller has an unusable DMA engine */
-#define RT_SDHCI_QUIRK_BROKEN_DMA (1 << 5)
+#define RT_SDHCI_QUIRK_BROKEN_DMA (1 << 5)
/* Controller has an unusable ADMA engine */
-#define RT_SDHCI_QUIRK_BROKEN_ADMA (1 << 6)
+#define RT_SDHCI_QUIRK_BROKEN_ADMA (1 << 6)
/* Controller can only DMA from 32-bit aligned addresses */
-#define RT_SDHCI_QUIRK_32BIT_DMA_ADDR (1 << 7)
+#define RT_SDHCI_QUIRK_32BIT_DMA_ADDR (1 << 7)
/* Controller can only DMA chunk sizes that are a multiple of 32 bits */
-#define RT_SDHCI_QUIRK_32BIT_DMA_SIZE (1 << 8)
+#define RT_SDHCI_QUIRK_32BIT_DMA_SIZE (1 << 8)
/* Controller can only ADMA chunks that are a multiple of 32 bits */
-#define RT_SDHCI_QUIRK_32BIT_ADMA_SIZE (1 << 9)
+#define RT_SDHCI_QUIRK_32BIT_ADMA_SIZE (1 << 9)
/* Controller needs to be reset after each request to stay stable */
-#define RT_SDHCI_QUIRK_RESET_AFTER_REQUEST (1 << 10)
+#define RT_SDHCI_QUIRK_RESET_AFTER_REQUEST (1 << 10)
/* Controller needs voltage and power writes to happen separately */
-#define RT_SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1 << 11)
+#define RT_SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1 << 11)
/* Controller provides an incorrect timeout value for transfers */
-#define RT_SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1 << 12)
+#define RT_SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1 << 12)
/* Controller has an issue with buffer bits for small transfers */
-#define RT_SDHCI_QUIRK_BROKEN_SMALL_PIO (1 << 13)
+#define RT_SDHCI_QUIRK_BROKEN_SMALL_PIO (1 << 13)
/* Controller does not provide transfer-complete interrupt when not busy */
-#define RT_SDHCI_QUIRK_NO_BUSY_IRQ (1 << 14)
+#define RT_SDHCI_QUIRK_NO_BUSY_IRQ (1 << 14)
/* Controller has unreliable card detection */
-#define RT_SDHCI_QUIRK_BROKEN_CARD_DETECTION (1 << 15)
+#define RT_SDHCI_QUIRK_BROKEN_CARD_DETECTION (1 << 15)
/* Controller reports inverted write-protect state */
-#define RT_SDHCI_QUIRK_INVERTED_WRITE_PROTECT (1 << 16)
+#define RT_SDHCI_QUIRK_INVERTED_WRITE_PROTECT (1 << 16)
/* Controller has unusable command queue engine */
-#define RT_SDHCI_QUIRK_BROKEN_CQE (1 << 17)
+#define RT_SDHCI_QUIRK_BROKEN_CQE (1 << 17)
/* Controller does not like fast PIO transfers */
-#define RT_SDHCI_QUIRK_PIO_NEEDS_DELAY (1 << 18)
+#define RT_SDHCI_QUIRK_PIO_NEEDS_DELAY (1 << 18)
/* Controller does not have a LED */
-#define RT_SDHCI_QUIRK_NO_LED (1 << 19)
+#define RT_SDHCI_QUIRK_NO_LED (1 << 19)
/* Controller has to be forced to use block size of 2048 bytes */
-#define RT_SDHCI_QUIRK_FORCE_BLK_SZ_2048 (1 << 20)
+#define RT_SDHCI_QUIRK_FORCE_BLK_SZ_2048 (1 << 20)
/* Controller cannot do multi-block transfers */
-#define RT_SDHCI_QUIRK_NO_MULTIBLOCK (1 << 21)
+#define RT_SDHCI_QUIRK_NO_MULTIBLOCK (1 << 21)
/* Controller can only handle 1-bit data transfers */
-#define RT_SDHCI_QUIRK_FORCE_1_BIT_DATA (1 << 22)
+#define RT_SDHCI_QUIRK_FORCE_1_BIT_DATA (1 << 22)
/* Controller needs 10ms delay between applying power and clock */
-#define RT_SDHCI_QUIRK_DELAY_AFTER_POWER (1 << 23)
+#define RT_SDHCI_QUIRK_DELAY_AFTER_POWER (1 << 23)
/* Controller uses SDCLK instead of TMCLK for data timeouts */
-#define RT_SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK (1 << 24)
+#define RT_SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK (1 << 24)
/* Controller reports wrong base clock capability */
-#define RT_SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN (1 << 25)
+#define RT_SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN (1 << 25)
/* Controller cannot support End Attribute in NOP ADMA descriptor */
-#define RT_SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC (1 << 26)
+#define RT_SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC (1 << 26)
/* Controller uses Auto CMD12 command to stop the transfer */
-#define RT_SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 (1 << 28)
+#define RT_SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 (1 << 28)
/* Controller doesn't have HISPD bit field in HI-SPEED SD card */
-#define RT_SDHCI_QUIRK_NO_HISPD_BIT (1 << 29)
+#define RT_SDHCI_QUIRK_NO_HISPD_BIT (1 << 29)
/* Controller treats ADMA descriptors with length 0000h incorrectly */
-#define RT_SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC (1 << 30)
+#define RT_SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC (1 << 30)
/* The read-only detection via RT_SDHCI_PRESENT_STATE register is unstable */
-#define RT_SDHCI_QUIRK_UNSTABLE_RO_DETECT (1 << 31)
+#define RT_SDHCI_QUIRK_UNSTABLE_RO_DETECT (1 << 31)
unsigned int quirks2; /* More deviations from spec. */
-#define RT_SDHCI_QUIRK2_HOST_OFF_CARD_ON (1 << 0)
-#define RT_SDHCI_QUIRK2_HOST_NO_CMD23 (1 << 1)
+#define RT_SDHCI_QUIRK2_HOST_OFF_CARD_ON (1 << 0)
+#define RT_SDHCI_QUIRK2_HOST_NO_CMD23 (1 << 1)
/* The system physically doesn't support 1.8v, even if the host does */
-#define RT_SDHCI_QUIRK2_NO_1_8_V (1 << 2)
-#define RT_SDHCI_QUIRK2_PRESET_VALUE_BROKEN (1 << 3)
-#define RT_SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON (1 << 4)
+#define RT_SDHCI_QUIRK2_NO_1_8_V (1 << 2)
+#define RT_SDHCI_QUIRK2_PRESET_VALUE_BROKEN (1 << 3)
+#define RT_SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON (1 << 4)
/* Controller has a non-standard host control register */
-#define RT_SDHCI_QUIRK2_BROKEN_HOST_CONTROL (1 << 5)
+#define RT_SDHCI_QUIRK2_BROKEN_HOST_CONTROL (1 << 5)
/* Controller does not support HS200 */
-#define RT_SDHCI_QUIRK2_BROKEN_HS200 (1 << 6)
+#define RT_SDHCI_QUIRK2_BROKEN_HS200 (1 << 6)
/* Controller does not support DDR50 */
-#define RT_SDHCI_QUIRK2_BROKEN_DDR50 (1 << 7)
+#define RT_SDHCI_QUIRK2_BROKEN_DDR50 (1 << 7)
/* Stop command (CMD12) can set Transfer Complete when not using MMC_RSP_BUSY */
-#define RT_SDHCI_QUIRK2_STOP_WITH_TC (1 << 8)
+#define RT_SDHCI_QUIRK2_STOP_WITH_TC (1 << 8)
/* Controller does not support 64-bit DMA */
-#define RT_SDHCI_QUIRK2_BROKEN_64_BIT_DMA (1 << 9)
+#define RT_SDHCI_QUIRK2_BROKEN_64_BIT_DMA (1 << 9)
/* need clear transfer mode register before send cmd */
-#define RT_SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD (1 << 10)
+#define RT_SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD (1 << 10)
/* Capability register bit-63 indicates HS400 support */
-#define RT_SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 (1 << 11)
+#define RT_SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 (1 << 11)
/* forced tuned clock */
-#define RT_SDHCI_QUIRK2_TUNING_WORK_AROUND (1 << 12)
+#define RT_SDHCI_QUIRK2_TUNING_WORK_AROUND (1 << 12)
/* disable the block count for single block transactions */
-#define RT_SDHCI_QUIRK2_SUPPORT_SINGLE (1 << 13)
+#define RT_SDHCI_QUIRK2_SUPPORT_SINGLE (1 << 13)
/* Controller broken with using ACMD23 */
-#define RT_SDHCI_QUIRK2_ACMD23_BROKEN (1 << 14)
+#define RT_SDHCI_QUIRK2_ACMD23_BROKEN (1 << 14)
/* Broken Clock divider zero in controller */
-#define RT_SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN (1 << 15)
+#define RT_SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN (1 << 15)
/* Controller has CRC in 136 bit Command Response */
-#define RT_SDHCI_QUIRK2_RSP_136_HAS_CRC (1 << 16)
+#define RT_SDHCI_QUIRK2_RSP_136_HAS_CRC (1 << 16)
-#define RT_SDHCI_QUIRK2_DISABLE_HW_TIMEOUT (1 << 17)
+#define RT_SDHCI_QUIRK2_DISABLE_HW_TIMEOUT (1 << 17)
-#define RT_SDHCI_QUIRK2_USE_32BIT_BLK_CNT (1 << 18)
+#define RT_SDHCI_QUIRK2_USE_32BIT_BLK_CNT (1 << 18)
/* Issue CMD and DATA reset together */
-#define RT_SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER (1 << 19)
+#define RT_SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER (1 << 19)
- void *data_buf;
+ void *data_buf;
int irq; /* Device IRQ */
void *ioaddr; /* Mapped address */
char *bounce_buffer; /* For packing SDMA reads/writes */
rt_uint64_t bounce_addr;
unsigned int bounce_buffer_size;
+ void *bounce_orig_buf;
+ rt_bool_t bounce_active;
const struct rt_sdhci_ops *ops; /* Low level hw interface */
/* Internal data */
- struct rt_mmc_host *mmc; /* MMC structure */
- struct rt_mmc_host_ops mmc_host_ops; /* MMC host ops */
- rt_uint64_t dma_mask; /* custom DMA mask */
+ struct rt_mmc_host *mmc; /* MMC structure */
+ struct rt_mmc_host_ops mmc_host_ops; /* MMC host ops */
+ rt_uint64_t dma_mask; /* custom DMA mask */
rt_spinlock_t lock;
int flags; /* Host attributes */
@@ -484,6 +486,7 @@ struct rt_sdhci_host
struct rt_workqueue *irq_wq;
struct rt_work irq_work;
+ struct rt_work poll_work;
struct rt_timer timer; /* Timer for timeouts */
struct rt_timer data_timer; /* Timer for data timeouts */
@@ -530,15 +533,15 @@ struct rt_sdhci_ops
{
rt_uint32_t (*read_l)(struct rt_sdhci_host *host, int reg);
rt_uint16_t (*read_w)(struct rt_sdhci_host *host, int reg);
- rt_uint8_t (*read_b)(struct rt_sdhci_host *host, int reg);
- void (*write_l)(struct rt_sdhci_host *host, rt_uint32_t val, int reg);
- void (*write_w)(struct rt_sdhci_host *host, rt_uint16_t val, int reg);
- void (*write_b)(struct rt_sdhci_host *host, rt_uint8_t val, int reg);
- void (*set_clock)(struct rt_sdhci_host *host, unsigned int clock);
- void (*set_power)(struct rt_sdhci_host *host, unsigned char mode, unsigned short vdd);
+ rt_uint8_t (*read_b)(struct rt_sdhci_host *host, int reg);
+ void (*write_l)(struct rt_sdhci_host *host, rt_uint32_t val, int reg);
+ void (*write_w)(struct rt_sdhci_host *host, rt_uint16_t val, int reg);
+ void (*write_b)(struct rt_sdhci_host *host, rt_uint8_t val, int reg);
+ void (*set_clock)(struct rt_sdhci_host *host, unsigned int clock);
+ void (*set_power)(struct rt_sdhci_host *host, unsigned char mode, unsigned short vdd);
rt_uint32_t (*irq)(struct rt_sdhci_host *host, rt_uint32_t intmask);
- int (*set_dma_mask)(struct rt_sdhci_host *host);
- int (*enable_dma)(struct rt_sdhci_host *host);
+ int (*set_dma_mask)(struct rt_sdhci_host *host);
+ int (*enable_dma)(struct rt_sdhci_host *host);
unsigned int (*get_max_clock)(struct rt_sdhci_host *host);
unsigned int (*get_min_clock)(struct rt_sdhci_host *host);
unsigned int (*get_timeout_clock)(struct rt_sdhci_host *host);
@@ -622,47 +625,47 @@ rt_inline rt_uint8_t rt_sdhci_readb(struct rt_sdhci_host *host, int reg)
}
struct rt_sdhci_host *rt_sdhci_alloc_host(struct rt_device *dev, rt_size_t priv_size);
-void rt_sdhci_free_host(struct rt_sdhci_host *host);
+void rt_sdhci_free_host(struct rt_sdhci_host *host);
rt_inline void *rt_sdhci_priv(struct rt_sdhci_host *host)
{
return host->private;
}
-void rt_sdhci_read_caps(struct rt_sdhci_host *host, const rt_uint16_t *ver,
- const rt_uint32_t *caps, const rt_uint32_t *caps1);
-int rt_sdhci_setup_host(struct rt_sdhci_host *host);
-void rt_sdhci_cleanup_host(struct rt_sdhci_host *host);
-int rt_sdhci_set_and_add_host(struct rt_sdhci_host *host);
-int rt_sdhci_init_host(struct rt_sdhci_host *host);
-void rt_sdhci_uninit_host(struct rt_sdhci_host *host, rt_bool_t dead);
+void rt_sdhci_read_caps(struct rt_sdhci_host *host, const rt_uint16_t *ver,
+ const rt_uint32_t *caps, const rt_uint32_t *caps1);
+int rt_sdhci_setup_host(struct rt_sdhci_host *host);
+void rt_sdhci_cleanup_host(struct rt_sdhci_host *host);
+int rt_sdhci_set_and_add_host(struct rt_sdhci_host *host);
+int rt_sdhci_init_host(struct rt_sdhci_host *host);
+void rt_sdhci_uninit_host(struct rt_sdhci_host *host, rt_bool_t dead);
rt_uint16_t rt_sdhci_clk_set(struct rt_sdhci_host *host, unsigned int clock, unsigned int *actual_clock);
-void rt_sdhci_set_clock(struct rt_sdhci_host *host, unsigned int clock);
-void rt_sdhci_clk_enable(struct rt_sdhci_host *host, rt_uint16_t clk);
-void rt_sdhci_set_power(struct rt_sdhci_host *host, unsigned char mode,unsigned short vdd);
-void rt_read_reg(struct rt_sdhci_host* host);
+void rt_sdhci_set_clock(struct rt_sdhci_host *host, unsigned int clock);
+void rt_sdhci_clk_enable(struct rt_sdhci_host *host, rt_uint16_t clk);
+void rt_sdhci_set_power(struct rt_sdhci_host *host, unsigned char mode, unsigned short vdd);
+void rt_read_reg(struct rt_sdhci_host *host);
-void rt_sdhci_set_power_and_bus_voltage(struct rt_sdhci_host *host, unsigned char mode, unsigned short vdd);
-void rt_sdhci_set_power_with_noreg(struct rt_sdhci_host *host, unsigned char mode, unsigned short vdd);
-void rt_sdhci_start_request(struct rt_mmc_host *mmc, struct rt_mmcsd_req *mrq);
-int rt_sdhci_start_request_atomic(struct rt_mmc_host *mmc, struct rt_mmcsd_req *mrq);
-void rt_sdhci_set_bus_width(struct rt_sdhci_host *host, int width);
-void rt_sdhci_reset(struct rt_sdhci_host *host, rt_uint8_t mask);
-void rt_sdhci_set_uhs(struct rt_sdhci_host *host, unsigned timing);
-int rt_sdhci_execute_tuning(struct rt_mmc_host *mmc, rt_uint32_t opcode);
-int __sdhci_execute_tuning(struct rt_sdhci_host *host, rt_uint32_t opcode);
-void rt_sdhci_ios_set(struct rt_mmc_host *mmc, struct rt_mmcsd_io_cfg *ios);
-int rt_sdhci_start_signal_voltage_switch(struct rt_mmc_host *mmc, struct rt_mmcsd_io_cfg *ios);
-void rt_sdhci_enable_io_irq(struct rt_mmc_host *mmc, int enable);
-void rt_sdhci_start_tuning(struct rt_sdhci_host *host);
-void rt_sdhci_end_tuning(struct rt_sdhci_host *host);
-void rt_sdhci_reset_tuning(struct rt_sdhci_host *host);
-void rt_sdhci_send_tuning(struct rt_sdhci_host *host, rt_uint32_t opcode);
-void rt_sdhci_abort_tuning(struct rt_sdhci_host *host, rt_uint32_t opcode);
-void rt_sdhci_enable_v4_mode(struct rt_sdhci_host *host);
-void rt_sdhci_data_irq_timeout(struct rt_sdhci_host *host, rt_bool_t enable);
-void rt_sdhci_timeout_set(struct rt_sdhci_host *host, struct rt_mmcsd_cmd *cmd);
-void rt_sdhci_read_reg_debug(struct rt_sdhci_host* host);
+void rt_sdhci_set_power_and_bus_voltage(struct rt_sdhci_host *host, unsigned char mode, unsigned short vdd);
+void rt_sdhci_set_power_with_noreg(struct rt_sdhci_host *host, unsigned char mode, unsigned short vdd);
+void rt_sdhci_start_request(struct rt_mmc_host *mmc, struct rt_mmcsd_req *mrq);
+int rt_sdhci_start_request_atomic(struct rt_mmc_host *mmc, struct rt_mmcsd_req *mrq);
+void rt_sdhci_set_bus_width(struct rt_sdhci_host *host, int width);
+void rt_sdhci_reset(struct rt_sdhci_host *host, rt_uint8_t mask);
+void rt_sdhci_set_uhs(struct rt_sdhci_host *host, unsigned timing);
+int rt_sdhci_execute_tuning(struct rt_mmc_host *mmc, rt_uint32_t opcode);
+int __sdhci_execute_tuning(struct rt_sdhci_host *host, rt_uint32_t opcode);
+void rt_sdhci_ios_set(struct rt_mmc_host *mmc, struct rt_mmcsd_io_cfg *ios);
+int rt_sdhci_start_signal_voltage_switch(struct rt_mmc_host *mmc, struct rt_mmcsd_io_cfg *ios);
+void rt_sdhci_enable_io_irq(struct rt_mmc_host *mmc, int enable);
+void rt_sdhci_start_tuning(struct rt_sdhci_host *host);
+void rt_sdhci_end_tuning(struct rt_sdhci_host *host);
+void rt_sdhci_reset_tuning(struct rt_sdhci_host *host);
+void rt_sdhci_send_tuning(struct rt_sdhci_host *host, rt_uint32_t opcode);
+void rt_sdhci_abort_tuning(struct rt_sdhci_host *host, rt_uint32_t opcode);
+void rt_sdhci_enable_v4_mode(struct rt_sdhci_host *host);
+void rt_sdhci_data_irq_timeout(struct rt_sdhci_host *host, rt_bool_t enable);
+void rt_sdhci_timeout_set(struct rt_sdhci_host *host, struct rt_mmcsd_cmd *cmd);
+void rt_sdhci_read_reg_debug(struct rt_sdhci_host *host);
#endif /* __DEV_SDHCI_H__ */
diff --git a/components/drivers/sdio/dev_regulator.c b/components/drivers/sdio/dev_regulator.c
index 6b62f7b519..c7792f29db 100755
--- a/components/drivers/sdio/dev_regulator.c
+++ b/components/drivers/sdio/dev_regulator.c
@@ -10,11 +10,11 @@
#include "dev_sdio_dm.h"
-#define DBG_TAG "SDIO"
+#define DBG_TAG "SDIO"
#ifdef RT_SDIO_DEBUG
-#define DBG_LVL DBG_LOG
+#define DBG_LVL DBG_LOG
#else
-#define DBG_LVL DBG_INFO
+#define DBG_LVL DBG_INFO
#endif /* RT_SDIO_DEBUG */
#include <rtdbg.h>
@@ -44,7 +44,7 @@ static rt_err_t ocrbitnum_to_vdd(int vdd_bit, int *min_uvolt, int *max_uvolt)
}
rt_err_t sdio_regulator_set_ocr(struct rt_mmcsd_host *host,
- struct rt_regulator *supply, rt_uint16_t vdd_bit)
+ struct rt_regulator *supply, rt_uint16_t vdd_bit)
{
rt_err_t err = RT_EOK;
@@ -94,10 +94,26 @@ rt_err_t sdio_regulator_set_ocr(struct rt_mmcsd_host *host,
return err;
}
+rt_bool_t sdio_regulator_supports_vqmmc_voltage(struct rt_regulator *regulator,
+ int min_uvolt, int target_uvolt, int max_uvolt)
+{
+ if (!regulator)
+ {
+ return RT_FALSE;
+ }
+
+ if (rt_regulator_is_supported_voltage(regulator, min_uvolt, max_uvolt))
+ {
+ return RT_TRUE;
+ }
+
+ return rt_regulator_is_supported_voltage(regulator, target_uvolt, target_uvolt);
+}
+
static int regulator_set_voltage_if_supported(struct rt_regulator *regulator,
- int min_uvolt, int target_uvolt, int max_uvolt)
+ int min_uvolt, int target_uvolt, int max_uvolt)
{
- if (!rt_regulator_is_supported_voltage(regulator, min_uvolt, max_uvolt))
+ if (!regulator)
{
return -RT_EINVAL;
}
@@ -107,12 +123,26 @@ static int regulator_set_voltage_if_supported(struct rt_regulator *regulator,
return RT_EOK;
}
- return rt_regulator_set_voltage_triplet(regulator, min_uvolt, target_uvolt,
- max_uvolt);
+ if (rt_regulator_is_supported_voltage(regulator, min_uvolt, max_uvolt))
+ {
+ return rt_regulator_set_voltage_triplet(regulator, min_uvolt, target_uvolt,
+ max_uvolt);
+ }
+
+ /*
+ * gpio regulator may declare min above the SDHCI nominal range
+ * (e.g. 1.8V only) while still supporting the target voltage.
+ */
+ if (rt_regulator_is_supported_voltage(regulator, target_uvolt, target_uvolt))
+ {
+ return rt_regulator_set_voltage(regulator, target_uvolt, target_uvolt);
+ }
+
+ return -RT_EINVAL;
}
rt_err_t sdio_regulator_set_vqmmc(struct rt_mmcsd_host *host,
- struct rt_mmcsd_io_cfg *ios)
+ struct rt_mmcsd_io_cfg *ios)
{
rt_err_t err;
int uvolt, min_uvolt, max_uvolt;
@@ -126,11 +156,11 @@ rt_err_t sdio_regulator_set_vqmmc(struct rt_mmcsd_host *host,
{
case MMCSD_SIGNAL_VOLTAGE_120:
return regulator_set_voltage_if_supported(host->supply.vqmmc,
- 1100000, 1200000, 1300000);
+ 1100000, 1200000, 1300000);
case MMCSD_SIGNAL_VOLTAGE_180:
return regulator_set_voltage_if_supported(host->supply.vqmmc,
- 1700000, 1800000, 1950000);
+ 1700000, 1800000, 1950000);
case MMCSD_SIGNAL_VOLTAGE_330:
err = ocrbitnum_to_vdd(host->io_cfg.vdd, &uvolt, &max_uvolt);
@@ -144,14 +174,14 @@ rt_err_t sdio_regulator_set_vqmmc(struct rt_mmcsd_host *host,
max_uvolt = rt_min(max_uvolt + 200000, 3600000);
err = regulator_set_voltage_if_supported(host->supply.vqmmc,
- min_uvolt, uvolt, max_uvolt);
+ min_uvolt, uvolt, max_uvolt);
if (err >= 0)
{
return err;
}
return regulator_set_voltage_if_supported(host->supply.vqmmc,
- 2700000, uvolt, 3600000);
+ 2700000, uvolt, 3600000);
default:
return -RT_EINVAL;
diff --git a/components/drivers/sdio/dev_sdhci.c b/components/drivers/sdio/dev_sdhci.c
index c8fd0646fa..9c5b679917 100755
--- a/components/drivers/sdio/dev_sdhci.c
+++ b/components/drivers/sdio/dev_sdhci.c
@@ -10,11 +10,18 @@
#include <rtthread.h>
+#define RT_SDHCI_SMALL_BOUNCE_SIZE 512
+#define RT_SDHCI_DMA_MIN_ALIGN rt_max_t(rt_size_t, RT_CPU_CACHE_LINE_SZ, 64)
+
+#ifndef ENOMEDIUM
+#define ENOMEDIUM 123
+#endif
+
#define DBG_TAG "SDHCI"
#ifdef RT_SDIO_DEBUG
#define DBG_LVL DBG_LOG
#else
-#define DBG_LVL DBG_INFO
+#define DBG_LVL DBG_WARNING
#endif /* RT_SDIO_DEBUG */
#include <rtdbg.h>
@@ -114,6 +121,11 @@ void rt_sdhci_enable_v4_mode(struct rt_sdhci_host *host)
sdhci_do_enable_v4_mode(host);
}
+static void sdhci_writel_signal_enable(struct rt_sdhci_host *host, rt_uint32_t ier)
+{
+ rt_sdhci_writel(host, ier, RT_SDHCI_SIGNAL_ENABLE);
+}
+
void rt_sdhci_data_irq_timeout(struct rt_sdhci_host *host, rt_bool_t enable)
{
if (enable)
@@ -126,7 +138,7 @@ void rt_sdhci_data_irq_timeout(struct rt_sdhci_host *host, rt_bool_t enable)
}
rt_sdhci_writel(host, host->ier, RT_SDHCI_INT_ENABLE);
- rt_sdhci_writel(host, host->ier, RT_SDHCI_SIGNAL_ENABLE);
+ sdhci_writel_signal_enable(host, host->ier);
}
void rt_sdhci_set_uhs(struct rt_sdhci_host *host, unsigned timing)
@@ -207,6 +219,13 @@ void rt_sdhci_cleanup_host(struct rt_sdhci_host *host)
{
struct rt_mmc_host *mmc = host->mmc;
+ if (host->bounce_buffer)
+ {
+ rt_free_align(host->bounce_buffer);
+ host->bounce_buffer = RT_NULL;
+ host->bounce_buffer_size = 0;
+ }
+
if (host->sdhci_core_to_disable_vqmmc)
{
rt_regulator_disable(mmc->rthost.supply.vqmmc);
@@ -227,7 +246,7 @@ static void sdhci_set_default_irqs(struct rt_sdhci_host *host)
}
rt_sdhci_writel(host, host->ier, RT_SDHCI_INT_ENABLE);
- rt_sdhci_writel(host, host->ier, RT_SDHCI_SIGNAL_ENABLE);
+ sdhci_writel_signal_enable(host, host->ier);
}
rt_inline void sdhci_auto_cmd_select(struct rt_sdhci_host *host,
@@ -339,7 +358,7 @@ static void sdhci_set_card_detection(struct rt_sdhci_host *host, rt_bool_t enabl
}
rt_sdhci_writel(host, host->ier, RT_SDHCI_INT_ENABLE);
- rt_sdhci_writel(host, host->ier, RT_SDHCI_SIGNAL_ENABLE);
+ sdhci_writel_signal_enable(host, host->ier);
}
static void sdhci_enable_card_detection(struct rt_sdhci_host *host)
@@ -363,9 +382,9 @@ enum sdhci_reset_reason
static rt_bool_t sdhci_needs_reset(struct rt_sdhci_host *host, struct rt_mmcsd_req *mrq)
{
return (!(host->flags & RT_SDHCI_DEVICE_DEAD) &&
- ((mrq->cmd && mrq->cmd->err) || (mrq->sbc && mrq->sbc->err) ||
- (mrq->data && mrq->data->stop && mrq->data->stop->err) ||
- (host->quirks & RT_SDHCI_QUIRK_RESET_AFTER_REQUEST)));
+ ((mrq->cmd && mrq->cmd->err) || (mrq->sbc && mrq->sbc->err) ||
+ (mrq->data && mrq->data->stop && mrq->data->stop->err) ||
+ (host->quirks & RT_SDHCI_QUIRK_RESET_AFTER_REQUEST)));
}
static rt_bool_t sdhci_do_reset(struct rt_sdhci_host *host, rt_uint8_t mask)
@@ -454,6 +473,7 @@ static void sdhci_runtime_pm_bus_off(struct rt_sdhci_host *host)
void rt_sdhci_reset(struct rt_sdhci_host *host, rt_uint8_t mask)
{
+ rt_tick_t start;
rt_ssize_t timeout;
rt_sdhci_writeb(host, mask, RT_SDHCI_SOFTWARE_RESET);
@@ -469,17 +489,16 @@ void rt_sdhci_reset(struct rt_sdhci_host *host, rt_uint8_t mask)
}
timeout = rt_tick_from_millisecond(150);
+ start = rt_tick_get();
while (RT_TRUE)
{
- timeout = timeout - rt_tick_get();
-
if (!(rt_sdhci_readb(host, RT_SDHCI_SOFTWARE_RESET) & mask))
{
break;
}
- if (timeout < 0)
+ if ((rt_tick_get() - start) >= timeout)
{
rt_kprintf("%s: Reset 0x%x never completed.\n",
mmc_hostname(host->mmc), (int)mask);
@@ -637,12 +656,14 @@ static void sdhci_set_transfer_irqs(struct rt_sdhci_host *host)
}
rt_sdhci_writel(host, host->ier, RT_SDHCI_INT_ENABLE);
- rt_sdhci_writel(host, host->ier, RT_SDHCI_SIGNAL_ENABLE);
+ sdhci_writel_signal_enable(host, host->ier);
}
static void sdhci_prepare_data(struct rt_sdhci_host *host, struct rt_mmcsd_cmd *cmd)
{
struct rt_mmcsd_data *data = cmd->data;
+ rt_size_t data_size = data->blks * data->blksize;
+ rt_bool_t dma_unaligned;
RT_ASSERT(!(data->blksize * data->blks > 524288));
RT_ASSERT(!(data->blksize > host->mmc->max_blk_size));
@@ -651,6 +672,8 @@ static void sdhci_prepare_data(struct rt_sdhci_host *host, struct rt_mmcsd_cmd *
host->data = data;
host->data_early = 0;
host->data->bytes_xfered = 0;
+ host->bounce_active = RT_FALSE;
+ host->bounce_orig_buf = RT_NULL;
if (host->flags & RT_SDHCI_USE_SDMA)
{
@@ -670,7 +693,7 @@ static void sdhci_prepare_data(struct rt_sdhci_host *host, struct rt_mmcsd_cmd *
offset_mask = 3;
}
- if ((data->blks * data->blksize) & length_mask)
+ if (data_size & length_mask)
{
host->flags &= ~RT_SDHCI_REQ_USE_DMA;
}
@@ -678,6 +701,31 @@ static void sdhci_prepare_data(struct rt_sdhci_host *host, struct rt_mmcsd_cmd *
{
host->flags &= ~RT_SDHCI_REQ_USE_DMA;
}
+
+ /* Cache maintenance on a partial cache line can discard unrelated
+ * dirty data owned by the allocator. Bounce small buffers and use PIO
+ * only when an unaligned transfer is too large for the bounce area. */
+ dma_unaligned = ((rt_ubase_t)data->buf & (RT_SDHCI_DMA_MIN_ALIGN - 1)) ||
+ (data_size & (RT_SDHCI_DMA_MIN_ALIGN - 1));
+
+ if ((data->blks == 1 && data_size <= host->bounce_buffer_size) ||
+ (dma_unaligned && data_size <= host->bounce_buffer_size))
+ {
+ host->bounce_orig_buf = data->buf;
+ host->bounce_active = RT_TRUE;
+
+ if (mmc_get_dma_dir(data) == DMA_TO_DEVICE)
+ {
+ rt_memcpy(host->bounce_buffer, data->buf, data_size);
+ }
+
+ data->buf = (rt_uint32_t *)host->bounce_buffer;
+ data->host_cookie = RT_SDHCI_COOKIE_MAPPED;
+ }
+ else if (dma_unaligned)
+ {
+ host->flags &= ~RT_SDHCI_REQ_USE_DMA;
+ }
}
sdhci_config_dma(host);
@@ -686,11 +734,11 @@ static void sdhci_prepare_data(struct rt_sdhci_host *host, struct rt_mmcsd_cmd *
{
if (mmc_get_dma_dir(data) == DMA_FROM_DEVICE)
{
- rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, data->buf, data->blks * data->blksize);
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, data->buf, data_size);
}
else
{
- rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, data->buf, data->blks * data->blksize);
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, data->buf, data_size);
}
sdhci_set_sdma_addr(host, sdhci_sdma_address(host));
@@ -699,6 +747,7 @@ static void sdhci_prepare_data(struct rt_sdhci_host *host, struct rt_mmcsd_cmd *
if (!(host->flags & RT_SDHCI_REQ_USE_DMA))
{
host->blocks = data->blks;
+ host->data_buf = data->buf;
}
sdhci_set_transfer_irqs(host);
@@ -737,11 +786,10 @@ rt_inline rt_bool_t sdhci_defer_done(struct rt_sdhci_host *host,
struct rt_mmcsd_data *data = mrq->data;
return host->pending_reset || host->always_defer_done ||
- ((host->flags & RT_SDHCI_REQ_USE_DMA) && data &&
- data->host_cookie == RT_SDHCI_COOKIE_MAPPED);
+ ((host->flags & RT_SDHCI_REQ_USE_DMA) && data &&
+ data->host_cookie == RT_SDHCI_COOKIE_MAPPED);
}
-
/********************************************************* */
/* pio */
/********************************************************* */
@@ -763,7 +811,7 @@ static void rt_sdhci_read_block_pio(struct rt_sdhci_host *host, void **buf)
}
}
-static void rt_sdhci_write_block_pio(struct rt_sdhci_host *host,void **buf)
+static void rt_sdhci_write_block_pio(struct rt_sdhci_host *host, void **buf)
{
rt_uint32_t scratch;
rt_size_t blksize, len;
@@ -787,7 +835,6 @@ static void rt_sdhci_write_block_pio(struct rt_sdhci_host *host,void **buf)
static void sdhci_transfer_pio(struct rt_sdhci_host *host)
{
- void *buf;
rt_uint32_t mask;
if (host->blocks == 0)
@@ -809,8 +856,6 @@ static void sdhci_transfer_pio(struct rt_sdhci_host *host)
mask = ~0;
}
- buf = (void *)host->data->buf;
-
while (rt_sdhci_readl(host, RT_SDHCI_PRESENT_STATE) & mask)
{
if (host->quirks & RT_SDHCI_QUIRK_PIO_NEEDS_DELAY)
@@ -820,16 +865,16 @@ static void sdhci_transfer_pio(struct rt_sdhci_host *host)
if (host->data->flags & DATA_DIR_READ)
{
- rt_sdhci_read_block_pio(host,&buf);
+ rt_sdhci_read_block_pio(host, &host->data_buf);
}
else
{
- rt_sdhci_write_block_pio(host,&buf);
+ rt_sdhci_write_block_pio(host, &host->data_buf);
}
- --host->data->blks;
+ --host->blocks;
- if (host->data->blks == 0)
+ if (host->blocks == 0)
{
break;
}
@@ -858,13 +903,13 @@ static rt_bool_t sdhci_timing_has_preset(unsigned char timing)
static rt_bool_t sdhci_preset_needed(struct rt_sdhci_host *host, unsigned char timing)
{
return !(host->quirks2 & RT_SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&
- sdhci_timing_has_preset(timing);
+ sdhci_timing_has_preset(timing);
}
static rt_bool_t sdhci_presetable_values_change(struct rt_sdhci_host *host, struct rt_mmcsd_io_cfg *ios)
{
return !host->preset_enabled &&
- (sdhci_preset_needed(host, ios->timing) || host->drv_type != ios->drv_type);
+ (sdhci_preset_needed(host, ios->timing) || host->drv_type != ios->drv_type);
}
static void sdhci_preset_value_enable(struct rt_sdhci_host *host, rt_bool_t enable)
@@ -1017,12 +1062,12 @@ void rt_sdhci_set_power(struct rt_sdhci_host *host, unsigned char mode,
}
}
-
int rt_sdhci_start_signal_voltage_switch(struct rt_mmc_host *mmc,
struct rt_mmcsd_io_cfg *ios)
{
int ret;
rt_uint16_t ctrl;
+ rt_bool_t force_no_vqmmc = RT_FALSE;
struct rt_sdhci_host *host = rt_mmc_priv(mmc);
if (host->version < RT_SDHCI_SPEC_300)
@@ -1043,12 +1088,13 @@ int rt_sdhci_start_signal_voltage_switch(struct rt_mmc_host *mmc,
ctrl &= ~RT_SDHCI_CTRL_VDD_180;
rt_sdhci_writew(host, ctrl, RT_SDHCI_HOST_CONTROL2);
- if (mmc->rthost.supply.vqmmc)
+ if (!rt_is_err_or_null(mmc->rthost.supply.vqmmc))
{
ret = sdio_regulator_set_vqmmc(&mmc->rthost, ios);
if (ret < 0)
{
- return -EIO;
+ LOG_D("%s: set vqmmc to 3.3V failed ret=%d, ignore",
+ mmc_hostname(mmc), ret);
}
}
@@ -1068,17 +1114,37 @@ int rt_sdhci_start_signal_voltage_switch(struct rt_mmc_host *mmc,
return -EINVAL;
}
- if (mmc->rthost.supply.vqmmc)
+ if (rt_is_err_or_null(mmc->rthost.supply.vqmmc))
+ {
+ _no_vqmmc_180:
+ ctrl |= RT_SDHCI_CTRL_VDD_180;
+ rt_sdhci_writew(host, ctrl, RT_SDHCI_HOST_CONTROL2);
+
+ if (host->ops->voltage_switch)
+ {
+ host->ops->voltage_switch(host);
+ }
+
+ rt_thread_mdelay(1);
+ return 0;
+ }
+
+ if (!rt_is_err_or_null(mmc->rthost.supply.vqmmc))
{
ret = sdio_regulator_set_vqmmc(&mmc->rthost, ios);
if (ret < 0)
{
- LOG_D("%s: Switching to 1.8V signalling voltage failed",
- mmc_hostname(mmc));
- return -EIO;
+ LOG_D("%s: set vqmmc to 1.8V failed ret=%d, treat as no-vqmmc",
+ mmc_hostname(mmc), ret);
+ force_no_vqmmc = RT_TRUE;
}
}
+ if (force_no_vqmmc)
+ {
+ goto _no_vqmmc_180;
+ }
+
ctrl |= RT_SDHCI_CTRL_VDD_180;
rt_sdhci_writew(host, ctrl, RT_SDHCI_HOST_CONTROL2);
@@ -1087,6 +1153,8 @@ int rt_sdhci_start_signal_voltage_switch(struct rt_mmc_host *mmc,
host->ops->voltage_switch(host);
}
+ rt_thread_mdelay(5);
+
ctrl = rt_sdhci_readw(host, RT_SDHCI_HOST_CONTROL2);
if (ctrl & RT_SDHCI_CTRL_VDD_180)
{
@@ -1104,7 +1172,7 @@ int rt_sdhci_start_signal_voltage_switch(struct rt_mmc_host *mmc,
return -EINVAL;
}
- if (mmc->rthost.supply.vqmmc)
+ if (!rt_is_err_or_null(mmc->rthost.supply.vqmmc))
{
ret = sdio_regulator_set_vqmmc(&mmc->rthost, ios);
if (ret < 0)
@@ -1221,7 +1289,7 @@ static void rt_sdhci_enable_io_irq_nolock(struct rt_sdhci_host *host, int enable
}
rt_sdhci_writel(host, host->ier, RT_SDHCI_INT_ENABLE);
- rt_sdhci_writel(host, host->ier, RT_SDHCI_SIGNAL_ENABLE);
+ sdhci_writel_signal_enable(host, host->ier);
}
}
@@ -1248,6 +1316,11 @@ static void sdhci_del_timer(struct rt_sdhci_host *host, struct rt_mmcsd_req *mrq
}
}
+static rt_bool_t sdhci_poll_pending_irq(struct rt_sdhci_host *host);
+static void sdhci_schedule_complete(struct rt_sdhci_host *host);
+static void sdhci_start_poll(struct rt_sdhci_host *host);
+static void sdhci_stop_poll(struct rt_sdhci_host *host);
+
static unsigned int sdhci_target_timeout(struct rt_sdhci_host *host,
struct rt_mmcsd_cmd *cmd,
struct rt_mmcsd_data *data)
@@ -1458,6 +1531,7 @@ static void __sdhci_finish_mrq(struct rt_sdhci_host *host, struct rt_mmcsd_req *
sdhci_set_mrq_done(host, mrq);
sdhci_del_timer(host, mrq);
+ sdhci_stop_poll(host);
}
static void sdhci_finish_mrq(struct rt_sdhci_host *host, struct rt_mmcsd_req *mrq)
@@ -1532,7 +1606,7 @@ static int sdhci_prepare_hs400_tuning(struct rt_mmc_host *mmc, struct rt_mmcsd_i
return 0;
}
-static void sdhci_set_transfer_mode(struct rt_sdhci_host *host,
+static void sdhci_set_transfer_mode(struct rt_sdhci_host *host,
struct rt_mmcsd_cmd *cmd)
{
rt_uint16_t mode = 0;
@@ -1684,6 +1758,9 @@ static rt_bool_t sdhci_send_command(struct rt_sdhci_host *host, struct rt_mmcsd_
sdhci_start_timer(host, cmd->mrq, timeout);
rt_sdhci_writew(host, RT_SDHCI_MAKE_CMD(cmd->cmd_code, flags), RT_SDHCI_COMMAND);
+ sdhci_poll_pending_irq(host);
+ sdhci_schedule_complete(host);
+ sdhci_start_poll(host);
return RT_TRUE;
}
@@ -1755,7 +1832,6 @@ static void sdhci_finish_data(struct rt_sdhci_host *host)
__sdhci_finish_data(host, RT_FALSE);
}
-
/********************************************************* */
/* irq */
/********************************************************* */
@@ -1845,9 +1921,9 @@ static void sdhci_data_irq(struct rt_sdhci_host *host, rt_uint32_t intmask)
rt_uint32_t dmastart, dmanow;
dmastart = sdhci_sdma_address(host);
- dmanow = dmastart + host->data->bytes_xfered;
- dmanow = (dmanow & ~((rt_uint32_t)RT_SDHCI_DEFAULT_BOUNDARY_SIZE - 1));
- dmanow += RT_SDHCI_DEFAULT_BOUNDARY_SIZE;
+ dmanow = dmastart + host->data->bytes_xfered;
+ dmanow = (dmanow & ~((rt_uint32_t)RT_SDHCI_DEFAULT_BOUNDARY_SIZE - 1));
+ dmanow += RT_SDHCI_DEFAULT_BOUNDARY_SIZE;
host->data->bytes_xfered = dmanow - dmastart;
LOG_D("DMA base %p, transferred 0x%06x bytes, next %p",
@@ -1973,8 +2049,7 @@ static void sdhci_cmd_irq(struct rt_sdhci_host *host,
struct rt_mmcsd_req *mrq = host->data_cmd->mrq;
auto_cmd_status = rt_sdhci_readw(host, RT_SDHCI_AUTO_CMD_STATUS);
- data_err_bit = (auto_cmd_status & RT_SDHCI_AUTO_CMD_TIMEOUT) ?
- RT_SDHCI_INT_DATA_TIMEOUT : RT_SDHCI_INT_DATA_CRC;
+ data_err_bit = (auto_cmd_status & RT_SDHCI_AUTO_CMD_TIMEOUT) ? RT_SDHCI_INT_DATA_TIMEOUT : RT_SDHCI_INT_DATA_CRC;
if (!mrq->sbc && (host->flags & RT_SDHCI_AUTO_CMD12))
{
@@ -1997,6 +2072,30 @@ static void sdhci_cmd_irq(struct rt_sdhci_host *host,
return;
}
+ /*
+ * DWC may assert command TIMEOUT together with RESPONSE on R2 (CMD2/CMD9)
+ * even when the response is valid. Accept only if R136 data looks sane.
+ */
+ if ((host->quirks & RT_SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) &&
+ !host->cmd->data &&
+ (intmask & RT_SDHCI_INT_RESPONSE) &&
+ (intmask & RT_SDHCI_INT_TIMEOUT) &&
+ (host->cmd->flags & MMC_RSP_136))
+ {
+ struct rt_mmcsd_cmd *cmd = host->cmd;
+
+ rt_sdhci_read_rsp_136(host, cmd);
+ if (cmd->resp[0] | cmd->resp[1] | cmd->resp[2] | cmd->resp[3])
+ {
+ host->cmd = RT_NULL;
+ __sdhci_finish_mrq(host, cmd->mrq);
+ return;
+ }
+
+ LOG_W("%s: CMD%d R2 rsp+timeout but response invalid",
+ mmc_hostname(host->mmc), cmd->cmd_code);
+ }
+
if (intmask & (RT_SDHCI_INT_TIMEOUT | RT_SDHCI_INT_CRC | RT_SDHCI_INT_END_BIT | RT_SDHCI_INT_INDEX))
{
if (intmask & RT_SDHCI_INT_TIMEOUT)
@@ -2043,6 +2142,111 @@ static void sdhci_cmd_irq(struct rt_sdhci_host *host,
}
}
+/* Drain INT_STATUS when the IRQ line did not fire. */
+static rt_bool_t sdhci_poll_pending_irq(struct rt_sdhci_host *host)
+{
+ rt_uint32_t intmask, intmask_p, mask;
+
+ intmask = rt_sdhci_readl(host, RT_SDHCI_INT_STATUS);
+ if (!intmask || intmask == 0xffffffff)
+ {
+ return RT_FALSE;
+ }
+
+ if (host->ops->irq)
+ {
+ intmask = host->ops->irq(host, intmask);
+ if (!intmask)
+ {
+ return RT_FALSE;
+ }
+ }
+
+ if (!(intmask & (RT_SDHCI_INT_CMD_MASK | RT_SDHCI_INT_DATA_MASK | RT_SDHCI_INT_BUS_POWER)))
+ {
+ return RT_FALSE;
+ }
+
+ intmask_p = intmask;
+ mask = intmask & (RT_SDHCI_INT_CMD_MASK | RT_SDHCI_INT_DATA_MASK | RT_SDHCI_INT_BUS_POWER);
+ rt_sdhci_writel(host, mask, RT_SDHCI_INT_STATUS);
+
+ if (intmask & RT_SDHCI_INT_CMD_MASK)
+ {
+ sdhci_cmd_irq(host, intmask & RT_SDHCI_INT_CMD_MASK, &intmask_p);
+ }
+
+ if (intmask & RT_SDHCI_INT_DATA_MASK)
+ {
+ sdhci_data_irq(host, intmask & RT_SDHCI_INT_DATA_MASK);
+ }
+
+ if (intmask & RT_SDHCI_INT_BUS_POWER)
+ {
+ rt_kprintf("%s: Card is consuming too much power!\n",
+ mmc_hostname(host->mmc));
+ }
+
+ return RT_TRUE;
+}
+
+static void sdhci_schedule_complete(struct rt_sdhci_host *host)
+{
+ int i;
+
+ if (!host->complete_wq)
+ {
+ return;
+ }
+
+ for (i = 0; i < RT_SDHCI_MAX_MRQS; ++i)
+ {
+ if (host->mrqs_done[i])
+ {
+ rt_workqueue_submit_work(host->complete_wq, &host->complete_work, 0);
+ return;
+ }
+ }
+}
+
+static void sdhci_poll_work_fn(struct rt_work *work, void *data)
+{
+ struct rt_sdhci_host *host = data;
+ rt_base_t flags;
+ rt_bool_t active;
+
+ flags = rt_spin_lock_irqsave(&host->lock);
+
+ while (sdhci_poll_pending_irq(host))
+ {
+ }
+
+ sdhci_schedule_complete(host);
+ active = host->cmd || host->data || host->data_cmd;
+ rt_spin_unlock_irqrestore(&host->lock, flags);
+
+ if (active && host->irq_wq)
+ {
+ rt_workqueue_submit_work(host->irq_wq, &host->poll_work, 1);
+ }
+}
+
+static void sdhci_start_poll(struct rt_sdhci_host *host)
+{
+ if (host->irq_wq)
+ {
+ rt_workqueue_submit_work(host->irq_wq, &host->poll_work, 0);
+ }
+}
+
+static void sdhci_stop_poll(struct rt_sdhci_host *host)
+{
+ if (host->irq_wq)
+ {
+ rt_workqueue_cancel_work(host->irq_wq, &host->poll_work);
+ }
+}
+
static void sdhci_irq(int irq, void *dev_id)
{
#define IRQ_NONE 0
@@ -2068,7 +2272,8 @@ static void sdhci_irq(int irq, void *dev_id)
goto _out;
}
- do {
+ do
+ {
LOG_D("IRQ status 0x%08x", intmask);
if (host->ops->irq)
@@ -2091,7 +2296,7 @@ static void sdhci_irq(int irq, void *dev_id)
host->ier &= ~(RT_SDHCI_INT_CARD_INSERT | RT_SDHCI_INT_CARD_REMOVE);
host->ier |= present ? RT_SDHCI_INT_CARD_REMOVE : RT_SDHCI_INT_CARD_INSERT;
rt_sdhci_writel(host, host->ier, RT_SDHCI_INT_ENABLE);
- rt_sdhci_writel(host, host->ier, RT_SDHCI_SIGNAL_ENABLE);
+ sdhci_writel_signal_enable(host, host->ier);
rt_sdhci_writel(host, intmask & (RT_SDHCI_INT_CARD_INSERT | RT_SDHCI_INT_CARD_REMOVE),
RT_SDHCI_INT_STATUS);
@@ -2282,56 +2487,47 @@ static rt_bool_t rt_sdhci_start_request_done(struct rt_sdhci_host *host)
sdhci_reset_for(host, REQUEST_ERROR);
host->pending_reset = RT_FALSE;
+
+ if (host->clock)
+ {
+ host->ops->set_clock(host, host->clock);
+ }
}
if (host->flags & RT_SDHCI_REQ_USE_DMA)
{
struct rt_mmcsd_data *data = mrq->data;
- if (data && data->host_cookie == RT_SDHCI_COOKIE_MAPPED)
- {
- if (host->bounce_buffer)
- {
- /* On reads, copy the bounced data into the sglist */
- if (mmc_get_dma_dir(data) == DMA_FROM_DEVICE)
- {
- unsigned int length = data->bytes_xfered;
-
- if (length > host->bounce_buffer_size)
- {
- LOG_E("%s: bounce buffer is %u bytes but DMA claims to have transferred %u bytes",
- mmc_hostname(host->mmc),
- host->bounce_buffer_size,
- data->bytes_xfered);
- /* Cap it down and continue */
- length = host->bounce_buffer_size;
- }
- rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, data->buf,
- data->blks * data->blksize);
- }
- else
- {
- /* No copying, just switch ownership */
- rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, data->buf,
- data->blks * data->blksize);
- }
- }
- data->host_cookie = RT_SDHCI_COOKIE_UNMAPPED;
- }
- else
+ if (data)
{
if (mmc_get_dma_dir(data) == DMA_FROM_DEVICE)
{
rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, data->buf,
data->blks * data->blksize);
+
+ if (host->bounce_active && !data->err)
+ {
+ rt_memcpy(host->bounce_orig_buf, data->buf,
+ data->blks * data->blksize);
+ }
}
else
{
- /* No copying, just switch ownership */
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, data->buf,
data->blks * data->blksize);
}
+
+ if (host->bounce_active)
+ {
+ data->buf = host->bounce_orig_buf;
+ host->bounce_orig_buf = RT_NULL;
+ host->bounce_active = RT_FALSE;
+ }
+
+ data->host_cookie = RT_SDHCI_COOKIE_UNMAPPED;
}
+
+ host->flags &= ~RT_SDHCI_REQ_USE_DMA;
}
host->mrqs_done[i] = RT_NULL;
@@ -2386,14 +2582,13 @@ static void sdhci_thread_irq(struct rt_work *work, void *work_data)
void rt_sdhci_enable_io_irq(struct rt_mmc_host *mmc, int enable)
{
struct rt_sdhci_host *host = rt_mmc_priv(mmc);
- rt_uint32_t flags;
+ rt_uint32_t flags;
flags = rt_spin_lock_irqsave(&host->lock);
rt_sdhci_enable_io_irq_nolock(host, enable);
rt_spin_unlock_irqrestore(&host->lock, flags);
}
-
/********************************************************* */
/* request */
/********************************************************* */
@@ -2452,6 +2647,18 @@ static void sdhci_timeout_timer(void *parameter)
if (host->cmd && !sdhci_data_line_cmd(host->cmd))
{
+ while (host->cmd && sdhci_poll_pending_irq(host))
+ {
+ }
+
+ sdhci_schedule_complete(host);
+
+ if (!host->cmd)
+ {
+ rt_spin_unlock_irqrestore(&host->lock, flags);
+ return;
+ }
+
rt_kprintf("%s: Timeout waiting for hardware cmd interrupt.\n",
mmc_hostname(host->mmc));
rt_sdhci_read_reg_debug(host);
@@ -2472,6 +2679,21 @@ static void sdhci_timeout_data_timer(void *parameter)
if (host->data || host->data_cmd || (host->cmd && sdhci_data_line_cmd(host->cmd)))
{
+ while ((host->data || host->data_cmd ||
+ (host->cmd && sdhci_data_line_cmd(host->cmd))) &&
+ sdhci_poll_pending_irq(host))
+ {
+ }
+
+ sdhci_schedule_complete(host);
+
+ if (!host->data && !host->data_cmd &&
+ !(host->cmd && sdhci_data_line_cmd(host->cmd)))
+ {
+ rt_spin_unlock_irqrestore(&host->lock, flags);
+ return;
+ }
+
rt_kprintf("%s: Timeout waiting for hardware interrupt.\n",
mmc_hostname(host->mmc));
rt_sdhci_read_reg_debug(host);
@@ -2618,13 +2840,13 @@ void rt_sdhci_start_tuning(struct rt_sdhci_host *host)
rt_sdhci_writew(host, ctrl, RT_SDHCI_HOST_CONTROL2);
rt_sdhci_writel(host, RT_SDHCI_INT_DATA_AVAIL, RT_SDHCI_INT_ENABLE);
- rt_sdhci_writel(host, RT_SDHCI_INT_DATA_AVAIL, RT_SDHCI_SIGNAL_ENABLE);
+ sdhci_writel_signal_enable(host, RT_SDHCI_INT_DATA_AVAIL);
}
void rt_sdhci_end_tuning(struct rt_sdhci_host *host)
{
rt_sdhci_writel(host, host->ier, RT_SDHCI_INT_ENABLE);
- rt_sdhci_writel(host, host->ier, RT_SDHCI_SIGNAL_ENABLE);
+ sdhci_writel_signal_enable(host, host->ier);
}
void rt_sdhci_abort_tuning(struct rt_sdhci_host *host, rt_uint32_t opcode)
@@ -2689,23 +2911,21 @@ void rt_sdhci_reset_tuning(struct rt_sdhci_host *host)
rt_sdhci_writew(host, ctrl, RT_SDHCI_HOST_CONTROL2);
}
-
/********************************************************* */
/* error */
/********************************************************* */
-static const struct rt_mmc_host_ops rt_sdhci_ops =
-{
- .request = rt_sdhci_start_request,
- .set_ios = rt_sdhci_ios_set,
- .get_cd = sdhci_get_cd,
- .get_ro = rt_sdhci_ro_get,
- .enable_sdio_irq = rt_sdhci_enable_io_irq,
- .ack_sdio_irq = sdhci_ack_sdio_irq,
+static const struct rt_mmc_host_ops rt_sdhci_ops = {
+ .request = rt_sdhci_start_request,
+ .set_ios = rt_sdhci_ios_set,
+ .get_cd = sdhci_get_cd,
+ .get_ro = rt_sdhci_ro_get,
+ .enable_sdio_irq = rt_sdhci_enable_io_irq,
+ .ack_sdio_irq = sdhci_ack_sdio_irq,
.start_signal_voltage_switch = rt_sdhci_start_signal_voltage_switch,
- .prepare_hs400_tuning = sdhci_prepare_hs400_tuning,
- .execute_tuning = rt_sdhci_execute_tuning,
- .card_event = sdhci_card_event,
- .card_busy = sdhci_card_busy,
+ .prepare_hs400_tuning = sdhci_prepare_hs400_tuning,
+ .execute_tuning = rt_sdhci_execute_tuning,
+ .card_event = sdhci_card_event,
+ .card_busy = sdhci_card_busy,
};
void rt_sdhci_uninit_host(struct rt_sdhci_host *host, rt_bool_t dead)
@@ -2812,7 +3032,7 @@ rt_uint16_t rt_sdhci_clk_set(struct rt_sdhci_host *host, unsigned int clock,
}
else
{
- for (div = 2; div < RT_SDHCI_MAX_DIV_SPEC_300; div += 2)
+ for (div = 2; div < RT_SDHCI_MAX_DIV_SPEC_300; div += 2)
{
if ((host->max_clk / div) <= clock)
{
@@ -2822,8 +3042,7 @@ rt_uint16_t rt_sdhci_clk_set(struct rt_sdhci_host *host, unsigned int clock,
}
real_div = div;
div >>= 1;
- if ((host->quirks2 & RT_SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN)
- && !div && host->max_clk <= 25000000)
+ if ((host->quirks2 & RT_SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN) && !div && host->max_clk <= 25000000)
{
div = 1;
}
@@ -2856,23 +3075,24 @@ _clock_set:
void rt_sdhci_clk_enable(struct rt_sdhci_host *host, rt_uint16_t clk)
{
- long timeout;
+ rt_tick_t start;
+ rt_tick_t wait;
+ rt_bool_t reenable_only = (clk == 0);
clk |= RT_SDHCI_CLOCK_INT_EN;
rt_sdhci_writew(host, clk, RT_SDHCI_CLOCK_CONTROL);
- timeout = rt_tick_from_millisecond(150);
+ start = rt_tick_get();
+ wait = rt_tick_from_millisecond(150);
while (RT_TRUE)
{
- timeout = timeout - rt_tick_get();
-
clk = rt_sdhci_readw(host, RT_SDHCI_CLOCK_CONTROL);
if (clk & RT_SDHCI_CLOCK_INT_STABLE)
{
break;
}
- if (timeout < 0)
+ if ((rt_tick_get() - start) >= wait)
{
rt_kprintf("%s: Internal clock never stabilised.\n",
mmc_hostname(host->mmc));
@@ -2890,18 +3110,17 @@ void rt_sdhci_clk_enable(struct rt_sdhci_host *host, rt_uint16_t clk)
clk &= ~RT_SDHCI_CLOCK_INT_STABLE;
rt_sdhci_writew(host, clk, RT_SDHCI_CLOCK_CONTROL);
- timeout = rt_tick_from_millisecond(150);
+ start = rt_tick_get();
+ wait = rt_tick_from_millisecond(150);
while (RT_TRUE)
{
- timeout = timeout - rt_tick_get();
-
clk = rt_sdhci_readw(host, RT_SDHCI_CLOCK_CONTROL);
if (clk & RT_SDHCI_CLOCK_INT_STABLE)
{
break;
}
- if (timeout < 0)
+ if ((rt_tick_get() - start) >= wait)
{
rt_kprintf("%s: PLL clock never stabilised.\n",
mmc_hostname(host->mmc));
@@ -2916,6 +3135,11 @@ void rt_sdhci_clk_enable(struct rt_sdhci_host *host, rt_uint16_t clk)
clk |= RT_SDHCI_CLOCK_CARD_EN;
rt_sdhci_writew(host, clk, RT_SDHCI_CLOCK_CONTROL);
+
+ if (reenable_only && host->clock)
+ {
+ host->mmc->actual_clock = host->clock;
+ }
}
void rt_sdhci_set_clock(struct rt_sdhci_host *host, unsigned int clock)
@@ -3041,9 +3265,9 @@ int rt_sdhci_setup_host(struct rt_sdhci_host *host)
mmc = host->mmc;
- if (!mmc->rthost.supply.vqmmc)
+ if (rt_is_err_or_null(mmc->rthost.supply.vqmmc))
{
- ret = sdio_regulator_get_supply(mmc->parent,&mmc->rthost);
+ ret = sdio_regulator_get_supply(mmc->parent, &mmc->rthost);
if (ret)
{
return ret;
@@ -3059,7 +3283,7 @@ int rt_sdhci_setup_host(struct rt_sdhci_host *host)
rt_sdhci_readl(host, RT_SDHCI_CAPABILITIES),
rt_sdhci_readl(host, RT_SDHCI_CAPABILITIES_1));
- rt_sdhci_read_caps(host,RT_NULL,RT_NULL,RT_NULL);
+ rt_sdhci_read_caps(host, RT_NULL, RT_NULL, RT_NULL);
override_timeout_clk = host->timeout_clk;
@@ -3093,6 +3317,12 @@ int rt_sdhci_setup_host(struct rt_sdhci_host *host)
host->flags |= RT_SDHCI_USE_64_BIT_DMA;
}
+ /* Keep 32-bit SDMA available when only 64-bit addressing is broken. */
+ if (host->quirks2 & RT_SDHCI_QUIRK2_BROKEN_64_BIT_DMA)
+ {
+ host->flags &= ~RT_SDHCI_USE_64_BIT_DMA;
+ }
+
if (host->flags & RT_SDHCI_USE_SDMA)
{
if (host->ops->set_dma_mask)
@@ -3113,6 +3343,18 @@ int rt_sdhci_setup_host(struct rt_sdhci_host *host)
ret = 0;
}
+
+ if (host->flags & RT_SDHCI_USE_SDMA)
+ {
+ host->bounce_buffer = rt_malloc_align(RT_SDHCI_SMALL_BOUNCE_SIZE,
+ RT_SDHCI_DMA_MIN_ALIGN);
+ if (!host->bounce_buffer)
+ {
+ ret = -ENOMEM;
+ goto _unreg;
+ }
+ host->bounce_buffer_size = RT_SDHCI_SMALL_BOUNCE_SIZE;
+ }
}
if ((host->flags & RT_SDHCI_USE_64_BIT_DMA) && !host->v4_mode)
@@ -3206,8 +3448,7 @@ int rt_sdhci_setup_host(struct rt_sdhci_host *host)
host->timeout_clk = override_timeout_clk;
}
- mmc->max_busy_timeout = host->ops->get_max_timeout_count ?
- host->ops->get_max_timeout_count(host) : 1 << 27;
+ mmc->max_busy_timeout = host->ops->get_max_timeout_count ? host->ops->get_max_timeout_count(host) : 1 << 27;
mmc->max_busy_timeout /= host->timeout_clk;
}
@@ -3226,7 +3467,7 @@ int rt_sdhci_setup_host(struct rt_sdhci_host *host)
if ((host->version >= RT_SDHCI_SPEC_300) &&
(!(host->flags & RT_SDHCI_USE_SDMA) || host->v4_mode) &&
- !(host->quirks2 & RT_SDHCI_QUIRK2_ACMD23_BROKEN))
+ !(host->quirks2 & RT_SDHCI_QUIRK2_ACMD23_BROKEN))
{
host->flags |= RT_SDHCI_AUTO_CMD23;
LOG_D("Auto-CMD23 available");
@@ -3256,7 +3497,7 @@ int rt_sdhci_setup_host(struct rt_sdhci_host *host)
mmc->caps |= MMC_CAP_NEEDS_POLL;
}
- if (mmc->rthost.supply.vqmmc)
+ if (!rt_is_err_or_null(mmc->rthost.supply.vqmmc))
{
if (enable_vqmmc)
{
@@ -3264,12 +3505,14 @@ int rt_sdhci_setup_host(struct rt_sdhci_host *host)
host->sdhci_core_to_disable_vqmmc = !ret;
}
- if (!rt_regulator_is_supported_voltage(mmc->rthost.supply.vqmmc, 1700000, 1950000))
+ if (!sdio_regulator_supports_vqmmc_voltage(mmc->rthost.supply.vqmmc,
+ 1700000, 1800000, 1950000))
{
host->caps1 &= ~(RT_SDHCI_SUPPORT_SDR104 | RT_SDHCI_SUPPORT_SDR50 | RT_SDHCI_SUPPORT_DDR50);
}
- if (!rt_regulator_is_supported_voltage(mmc->rthost.supply.vqmmc, 2700000, 3600000))
+ if (!sdio_regulator_supports_vqmmc_voltage(mmc->rthost.supply.vqmmc,
+ 2700000, 3300000, 3600000))
{
host->flags &= ~RT_SDHCI_SIGNALING_330;
}
@@ -3286,7 +3529,7 @@ int rt_sdhci_setup_host(struct rt_sdhci_host *host)
{
host->caps1 &= ~(RT_SDHCI_SUPPORT_SDR104 | RT_SDHCI_SUPPORT_SDR50 | RT_SDHCI_SUPPORT_DDR50);
mmc->caps2 &= ~(MMC_CAP2_HSX00_1_8V | MMC_CAP2_HS400_ES);
- mmc->caps &= ~(MMC_CAP_1_8V_DDR | MMC_CAP_UHS);
+ mmc->caps &= ~(MMC_CAP_1_8V_DDR | MMC_CAP_UHS);
}
if (host->caps1 & (RT_SDHCI_SUPPORT_SDR104 | RT_SDHCI_SUPPORT_SDR50 | RT_SDHCI_SUPPORT_DDR50))
@@ -3314,7 +3557,7 @@ int rt_sdhci_setup_host(struct rt_sdhci_host *host)
mmc->caps2 |= MMC_CAP2_HS400;
}
if ((mmc->caps2 & MMC_CAP2_HSX00_1_2V) && (!mmc->rthost.supply.vqmmc ||
- !rt_regulator_is_supported_voltage(mmc->rthost.supply.vqmmc, 1100000, 1300000)))
+ !rt_regulator_is_supported_voltage(mmc->rthost.supply.vqmmc, 1100000, 1300000)))
{
mmc->caps2 &= ~MMC_CAP2_HSX00_1_2V;
}
@@ -3391,6 +3634,8 @@ int rt_sdhci_setup_host(struct rt_sdhci_host *host)
mmc->max_current_180 = RT_FIELD_GET(RT_SDHCI_MAX_CURRENT_180_MASK, max_current_caps);
mmc->max_current_180 *= RT_SDHCI_MAX_CURRENT_MULTIPLIER;
+
+ host->flags |= RT_SDHCI_SIGNALING_180;
}
if (host->ocr_mask)
@@ -3488,6 +3733,12 @@ _unreg:
rt_regulator_disable(mmc->rthost.supply.vqmmc);
}
_undma:
+ if (ret && host->bounce_buffer)
+ {
+ rt_free_align(host->bounce_buffer);
+ host->bounce_buffer = RT_NULL;
+ host->bounce_buffer_size = 0;
+ }
return ret;
}
@@ -3508,6 +3759,11 @@ static void sdhci_init(struct rt_sdhci_host *host, int soft)
sdhci_set_default_irqs(host);
rt_spin_unlock_irqrestore(&host->lock, flags);
+ if (host->quirks & RT_SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)
+ {
+ rt_sdhci_writeb(host, host->max_timeout_count, RT_SDHCI_TIMEOUT_CONTROL);
+ }
+
host->cqe_on = RT_FALSE;
if (soft)
@@ -3567,6 +3823,7 @@ int rt_sdhci_init_host(struct rt_sdhci_host *host)
rt_sprintf(&dev_name[len], "-irq");
host->irq_wq = rt_workqueue_create(dev_name, RT_SYSTEM_WORKQUEUE_STACKSIZE, 1);
rt_work_init(&host->irq_work, sdhci_thread_irq, host);
+ rt_work_init(&host->poll_work, sdhci_poll_work_fn, host);
rt_hw_interrupt_install(host->irq, sdhci_irq, host, mmc_hostname(mmc));
rt_pic_irq_unmask(host->irq);
@@ -3663,8 +3920,7 @@ void rt_sdhci_ios_set(struct rt_mmc_host *mmc, struct rt_mmcsd_io_cfg *ios)
if (host->quirks & RT_SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK && host->clock)
{
host->timeout_clk = mmc->actual_clock ? mmc->actual_clock / 1000 : host->clock / 1000;
- mmc->max_busy_timeout = host->ops->get_max_timeout_count ?
- host->ops->get_max_timeout_count(host) : 1 << 27;
+ mmc->max_busy_timeout = host->ops->get_max_timeout_count ? host->ops->get_max_timeout_count(host) : 1 << 27;
mmc->max_busy_timeout /= host->timeout_clk;
}
}
diff --git a/components/drivers/sdio/dev_sdio_dm.h b/components/drivers/sdio/dev_sdio_dm.h
index 675ff3d442..b0a7e134ac 100755
--- a/components/drivers/sdio/dev_sdio_dm.h
+++ b/components/drivers/sdio/dev_sdio_dm.h
@@ -19,9 +19,11 @@ int sdio_host_set_name(struct rt_mmcsd_host *host, char *out_devname);
#ifdef RT_USING_REGULATOR
rt_err_t sdio_regulator_set_ocr(struct rt_mmcsd_host *host,
- struct rt_regulator *supply, rt_uint16_t vdd_bit);
+ struct rt_regulator *supply, rt_uint16_t vdd_bit);
rt_err_t sdio_regulator_set_vqmmc(struct rt_mmcsd_host *host,
- struct rt_mmcsd_io_cfg *ios);
+ struct rt_mmcsd_io_cfg *ios);
+rt_bool_t sdio_regulator_supports_vqmmc_voltage(struct rt_regulator *regulator,
+ int min_uvolt, int target_uvolt, int max_uvolt);
rt_err_t sdio_regulator_get_supply(struct rt_device *dev, struct rt_mmcsd_host *host);
rt_err_t sdio_regulator_enable_vqmmc(struct rt_mmcsd_host *host);
void sdio_regulator_disable_vqmmc(struct rt_mmcsd_host *host);
diff --git a/components/drivers/sdio/host/Kconfig b/components/drivers/sdio/host/Kconfig
index 8576b19d8f..603e392abc 100755
--- a/components/drivers/sdio/host/Kconfig
+++ b/components/drivers/sdio/host/Kconfig
@@ -19,4 +19,10 @@ config RT_SDIO_DW_MMC_PCI
depends on RT_USING_PCI
default n
+config RT_SDIO_SDHCI_DWCMSHC
+ bool "Synopsys DWC MSHC SDHCI"
+ depends on RT_USING_OFW
+ select RT_USING_SDHCI
+ default n
+
osource "$(SOC_DM_SDIO_DIR)/Kconfig"
diff --git a/components/drivers/sdio/host/SConscript b/components/drivers/sdio/host/SConscript
index 242de85644..756e138df6 100755
--- a/components/drivers/sdio/host/SConscript
+++ b/components/drivers/sdio/host/SConscript
@@ -19,6 +19,9 @@ if GetDepend(['RT_SDIO_DW_MMC']):
if GetDepend(['RT_SDIO_DW_MMC_PCI']):
src += ['sdio-dw-pci.c']
+if GetDepend(['RT_SDIO_SDHCI_DWCMSHC']):
+ src += ['sdhci-dwcmshc.c', 'sdhci-dwcmshc-platform.c']
+
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
Return('group')
diff --git a/components/drivers/sdio/host/sdhci-dwcmshc-platform.c b/components/drivers/sdio/host/sdhci-dwcmshc-platform.c
new file mode 100644
index 0000000000..ca7f4c033d
--- /dev/null
+++ b/components/drivers/sdio/host/sdhci-dwcmshc-platform.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2006-2024, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2024-01-30 RT-Thread first version
+ */
+
+#include "sdhci-dwcmshc-platform.h"
+
+rt_err_t sdhci_dwcmshc_platform_register(struct rt_platform_device *pdev,
+ const struct sdhci_dwcmshc_drv_data *drv_data)
+{
+ return sdhci_dwcmshc_probe(pdev, drv_data);
+}
+
+static rt_err_t sdhci_dwcmshc_platform_probe(struct rt_platform_device *pdev)
+{
+ const struct sdhci_dwcmshc_drv_data *drv_data = RT_NULL;
+
+ if (pdev->parent.ofw_node)
+ {
+ drv_data = pdev->id->data;
+ }
+
+ if (!drv_data)
+ {
+ drv_data = &sdhci_dwcmshc_generic_drv_data;
+ }
+
+ return sdhci_dwcmshc_platform_register(pdev, drv_data);
+}
+
+static rt_err_t sdhci_dwcmshc_platform_remove(struct rt_platform_device *pdev)
+{
+ return sdhci_dwcmshc_remove(pdev);
+}
+
+static const struct rt_ofw_node_id sdhci_dwcmshc_platform_ofw_ids[] = {
+ {
+ .compatible = "snps,dwcmshc-sdhci",
+ .data = &sdhci_dwcmshc_generic_drv_data,
+ },
+ { /* sentinel */ }
+};
+
+static struct rt_platform_driver sdhci_dwcmshc_platform_driver = {
+ .name = "sdhci-dwcmshc",
+ .ids = sdhci_dwcmshc_platform_ofw_ids,
+
+ .probe = sdhci_dwcmshc_platform_probe,
+ .remove = sdhci_dwcmshc_platform_remove,
+};
+RT_PLATFORM_DRIVER_EXPORT(sdhci_dwcmshc_platform_driver);
diff --git a/components/drivers/sdio/host/sdhci-dwcmshc-platform.h b/components/drivers/sdio/host/sdhci-dwcmshc-platform.h
new file mode 100644
index 0000000000..727bfe4417
--- /dev/null
+++ b/components/drivers/sdio/host/sdhci-dwcmshc-platform.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2006-2024, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2024-01-30 RT-Thread first version
+ */
+
+#ifndef __SDHCI_DWCMSHC_PLATFORM_H__
+#define __SDHCI_DWCMSHC_PLATFORM_H__
+
+#include "sdhci-dwcmshc.h"
+
+rt_err_t sdhci_dwcmshc_platform_register(struct rt_platform_device *pdev,
+ const struct sdhci_dwcmshc_drv_data *drv_data);
+
+#endif /* __SDHCI_DWCMSHC_PLATFORM_H__ */
diff --git a/components/drivers/sdio/host/sdhci-dwcmshc.c b/components/drivers/sdio/host/sdhci-dwcmshc.c
new file mode 100644
index 0000000000..5a200c084c
--- /dev/null
+++ b/components/drivers/sdio/host/sdhci-dwcmshc.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2006-2024, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2024-01-30 RT-Thread first version
+ */
+
+#include "sdhci-dwcmshc.h"
+
+#include <drivers/dev_sdhci_host.h>
+
+#define DBG_TAG "sdhci.dwcmshc"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+static unsigned int sdhci_dwcmshc_get_max_clock(struct rt_sdhci_host *host)
+{
+ struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host);
+
+ if (pltfm_host->clk)
+ {
+ return rt_sdhci_pltfm_clk_get_max_clock(host);
+ }
+
+ return pltfm_host->clock;
+}
+
+static void sdhci_dwcmshc_check_auto_cmd23(struct rt_mmc_host *mmc, struct rt_mmcsd_req *mrq)
+{
+ struct rt_sdhci_host *host = rt_mmc_priv(mmc);
+
+ /*
+ * No matter V4 is enabled or not, ARGUMENT2 register is 32-bit
+ * block count register which doesn't support stuff bits of
+ * CMD23 argument on dwcmshc host controller.
+ */
+ if (mrq->sbc && (mrq->sbc->arg & SDHCI_DWCMSHC_ARG2_STUFF))
+ {
+ host->flags &= ~RT_SDHCI_AUTO_CMD23;
+ }
+ else
+ {
+ host->flags |= RT_SDHCI_AUTO_CMD23;
+ }
+}
+
+static void sdhci_dwcmshc_request(struct rt_mmc_host *mmc, struct rt_mmcsd_req *mrq)
+{
+ sdhci_dwcmshc_check_auto_cmd23(mmc, mrq);
+
+ rt_sdhci_start_request(mmc, mrq);
+}
+
+void sdhci_dwcmshc_set_uhs_signaling(struct rt_sdhci_host *host, unsigned int timing)
+{
+ rt_uint16_t ctrl_2;
+ rt_uint32_t ctrl;
+ struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host);
+ struct sdhci_dwcmshc *priv = rt_sdhci_pltfm_priv(pltfm_host);
+
+ ctrl_2 = rt_sdhci_readw(host, RT_SDHCI_HOST_CONTROL2);
+
+ /* Select Bus Speed Mode for host */
+ ctrl_2 &= ~RT_SDHCI_CTRL_UHS_MASK;
+ if (timing == MMC_TIMING_MMC_HS200 || timing == MMC_TIMING_UHS_SDR104)
+ {
+ ctrl_2 |= RT_SDHCI_CTRL_UHS_SDR104;
+ }
+ else if (timing == MMC_TIMING_UHS_SDR12)
+ {
+ ctrl_2 |= RT_SDHCI_CTRL_UHS_SDR12;
+ }
+ else if (timing == MMC_TIMING_UHS_SDR25 || timing == MMC_TIMING_MMC_HS)
+ {
+ ctrl_2 |= RT_SDHCI_CTRL_UHS_SDR25;
+ }
+ else if (timing == MMC_TIMING_UHS_SDR50)
+ {
+ ctrl_2 |= RT_SDHCI_CTRL_UHS_SDR50;
+ }
+ else if (timing == MMC_TIMING_UHS_DDR50 || timing == MMC_TIMING_MMC_DDR52)
+ {
+ ctrl_2 |= RT_SDHCI_CTRL_UHS_DDR50;
+ }
+ else if (timing == MMC_TIMING_MMC_HS400)
+ {
+ /* Set CARD_IS_EMMC bit to enable Data Strobe for HS400 */
+ ctrl = rt_sdhci_readl(host, priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL);
+ ctrl |= DWCMSHC_CARD_IS_EMMC;
+ rt_sdhci_writel(host, ctrl, priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL);
+
+ ctrl_2 |= DWCMSHC_CTRL_HS400;
+ }
+
+ rt_sdhci_writew(host, ctrl_2, RT_SDHCI_HOST_CONTROL2);
+}
+
+static void sdhci_dwcmshc_hs400_enhanced_strobe(struct rt_mmc_host *mmc, struct rt_mmcsd_io_cfg *ios)
+{
+ int reg;
+ rt_uint32_t vendor;
+ struct rt_sdhci_host *host = rt_mmc_priv(mmc);
+ struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host);
+ struct sdhci_dwcmshc *priv = rt_sdhci_pltfm_priv(pltfm_host);
+
+ reg = priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL;
+ vendor = rt_sdhci_readl(host, reg);
+
+ if (ios->enhanced_strobe)
+ {
+ vendor |= DWCMSHC_ENHANCED_STROBE;
+ }
+ else
+ {
+ vendor &= ~DWCMSHC_ENHANCED_STROBE;
+ }
+
+ rt_sdhci_writel(host, vendor, reg);
+}
+
+static int sdhci_dwcmshc_execute_tuning(struct rt_mmc_host *mmc, rt_uint32_t opcode)
+{
+ int err;
+ struct rt_sdhci_host *host = rt_mmc_priv(mmc);
+
+ if ((err = rt_sdhci_execute_tuning(mmc, opcode)))
+ {
+ return err;
+ }
+
+ /*
+ * Tuning can leave the IP in an active state (Buffer Read Enable bit
+ * set) which prevents the entry to low power states (i.e. S0i3). Data
+ * reset will clear it.
+ */
+ rt_sdhci_reset(host, RT_SDHCI_RESET_DATA);
+
+ return 0;
+}
+
+static void sdhci_dwcmshc_disable_card_clk(struct rt_sdhci_host *host)
+{
+ rt_uint16_t ctrl;
+
+ ctrl = rt_sdhci_readw(host, RT_SDHCI_CLOCK_CONTROL);
+ if (ctrl & RT_SDHCI_CLOCK_CARD_EN)
+ {
+ ctrl &= ~RT_SDHCI_CLOCK_CARD_EN;
+ rt_sdhci_writew(host, ctrl, RT_SDHCI_CLOCK_CONTROL);
+ }
+}
+
+static const struct rt_sdhci_ops sdhci_dwcmshc_ops = {
+ .set_clock = rt_sdhci_set_clock,
+ .set_bus_width = rt_sdhci_set_bus_width,
+ .set_uhs_signaling = sdhci_dwcmshc_set_uhs_signaling,
+ .get_max_clock = sdhci_dwcmshc_get_max_clock,
+ .reset = rt_sdhci_reset,
+};
+
+static const struct rt_sdhci_pltfm_data sdhci_dwcmshc_pdata = {
+ .ops = &sdhci_dwcmshc_ops,
+ .quirks = RT_SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
+ .quirks2 = RT_SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+};
+
+const struct sdhci_dwcmshc_drv_data sdhci_dwcmshc_generic_drv_data = {
+ .pdata = &sdhci_dwcmshc_pdata,
+};
+
+#ifdef RT_USING_PM
+static rt_err_t sdhci_dwcmshc_pm_suspend(const struct rt_device *device, rt_uint8_t mode)
+{
+ rt_uint16_t data;
+ struct rt_sdhci_host *host = device->user_data;
+
+ data = rt_sdhci_readw(host, RT_SDHCI_CLOCK_CONTROL);
+ data &= ~RT_SDHCI_CLOCK_CARD_EN;
+ rt_sdhci_writew(host, data, RT_SDHCI_CLOCK_CONTROL);
+
+ return RT_EOK;
+}
+
+static void sdhci_dwcmshc_pm_resume(const struct rt_device *device, rt_uint8_t mode)
+{
+ rt_uint16_t data;
+ struct rt_sdhci_host *host = device->user_data;
+
+ data = rt_sdhci_readw(host, RT_SDHCI_CLOCK_CONTROL);
+ data |= RT_SDHCI_CLOCK_CARD_EN;
+ rt_sdhci_writew(host, data, RT_SDHCI_CLOCK_CONTROL);
+}
+
+static const struct rt_device_pm_ops sdhci_dwcmshc_pm_ops = {
+ .suspend = sdhci_dwcmshc_pm_suspend,
+ .resume = sdhci_dwcmshc_pm_resume,
+};
+#endif /* RT_USING_PM */
+
+rt_err_t sdhci_dwcmshc_probe(struct rt_platform_device *pdev,
+ const struct sdhci_dwcmshc_drv_data *drv_data)
+{
+ rt_err_t err;
+ struct rt_device *dev = &pdev->parent;
+ struct rt_sdhci_pltfm_host *pltfm_host;
+ struct rt_sdhci_host *host;
+ struct sdhci_dwcmshc *priv;
+
+ if (!drv_data || !drv_data->pdata)
+ {
+ return -RT_EINVAL;
+ }
+
+ host = rt_sdhci_pltfm_init(pdev, drv_data->pdata, sizeof(struct sdhci_dwcmshc));
+
+ if (rt_is_err(host))
+ {
+ return rt_ptr_err(host);
+ }
+
+ pltfm_host = rt_sdhci_priv(host);
+ priv = rt_sdhci_pltfm_priv(pltfm_host);
+ priv->drv_data = drv_data;
+
+ pltfm_host->clk = rt_clk_get_by_name(dev, "core");
+ if (rt_is_err(pltfm_host->clk))
+ {
+ err = rt_ptr_err(pltfm_host->clk);
+ LOG_E("failed to get core clk %s", rt_strerror(err));
+ goto _free_pltfm;
+ }
+
+ err = rt_clk_prepare_enable(pltfm_host->clk);
+ if (err)
+ {
+ goto _err_clk;
+ }
+
+ priv->bus_clk = rt_clk_get_by_name(dev, "bus");
+ if (!rt_is_err(priv->bus_clk))
+ {
+ err = rt_clk_prepare_enable(priv->bus_clk);
+ if (err)
+ {
+ LOG_E("failed to enable bus clk %s", rt_strerror(err));
+ goto _err_core_clk;
+ }
+ }
+
+ err = rt_mmc_of_parse(host->mmc);
+ if (err)
+ {
+ goto _err_clk;
+ }
+
+ rt_sdhci_get_of_property(pdev);
+
+ priv->vendor_specific_area1 = rt_sdhci_readl(host, DWCMSHC_P_VENDOR_AREA1) & DWCMSHC_AREA1_MASK;
+
+ host->mmc_host_ops.request = sdhci_dwcmshc_request;
+ host->mmc_host_ops.hs400_enhanced_strobe = sdhci_dwcmshc_hs400_enhanced_strobe;
+ host->mmc_host_ops.execute_tuning = sdhci_dwcmshc_execute_tuning;
+
+ if (drv_data->init)
+ {
+ if ((err = drv_data->init(host, priv)))
+ {
+ goto _err_clk;
+ }
+ }
+
+ if (rt_sdhci_readl(host, RT_SDHCI_CAPABILITIES) & RT_SDHCI_CAN_64BIT_V4)
+ {
+ rt_sdhci_enable_v4_mode(host);
+ }
+
+ err = rt_sdhci_setup_host(host);
+ if (err)
+ {
+ goto _err_setup_host;
+ }
+
+ if (drv_data->postinit)
+ {
+ drv_data->postinit(host, priv);
+ }
+
+ err = rt_sdhci_init_host(host);
+ if (err)
+ {
+ goto _err_setup_host;
+ }
+
+#ifdef RT_USING_PM
+ dev->user_data = host;
+ rt_pm_device_register(dev, &sdhci_dwcmshc_pm_ops);
+#endif
+
+ return RT_EOK;
+
+_err_setup_host:
+ rt_sdhci_cleanup_host(host);
+
+_err_clk:
+ if (drv_data->remove)
+ {
+ drv_data->remove(host, priv);
+ }
+
+ if (!rt_is_err(priv->bus_clk))
+ {
+ rt_clk_disable_unprepare(priv->bus_clk);
+ }
+
+_err_core_clk:
+ if (!rt_is_err(pltfm_host->clk))
+ {
+ rt_clk_disable_unprepare(pltfm_host->clk);
+ }
+
+_free_pltfm:
+ rt_sdhci_pltfm_free(pdev);
+
+ return err;
+}
+
+rt_err_t sdhci_dwcmshc_remove(struct rt_platform_device *pdev)
+{
+ struct rt_sdhci_host *host = pdev->priv;
+ struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host);
+ struct sdhci_dwcmshc *priv = rt_sdhci_pltfm_priv(pltfm_host);
+
+#ifdef RT_USING_PM
+ rt_pm_device_unregister(&pdev->parent);
+#endif
+
+ rt_sdhci_uninit_host(host, 0);
+
+ sdhci_dwcmshc_disable_card_clk(host);
+
+ if (priv->drv_data && priv->drv_data->remove)
+ {
+ priv->drv_data->remove(host, priv);
+ }
+
+ rt_clk_disable_unprepare(pltfm_host->clk);
+
+ if (!rt_is_err(priv->bus_clk))
+ {
+ rt_clk_disable_unprepare(priv->bus_clk);
+ }
+
+ rt_sdhci_pltfm_free(pdev);
+
+ return RT_EOK;
+}
diff --git a/components/drivers/sdio/host/sdhci-dwcmshc.h b/components/drivers/sdio/host/sdhci-dwcmshc.h
new file mode 100644
index 0000000000..692f4199c8
--- /dev/null
+++ b/components/drivers/sdio/host/sdhci-dwcmshc.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2006-2024, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2024-01-30 RT-Thread first version
+ */
+
+#ifndef __SDHCI_DWCMSHC_H__
+#define __SDHCI_DWCMSHC_H__
+
+#include "../dev_sdhci_dm.h"
+
+#define SDHCI_DWCMSHC_ARG2_STUFF RT_GENMASK(31, 16)
+
+/* DWCMSHC specific Mode Select value */
+#define DWCMSHC_CTRL_HS400 0x7
+
+/* DWC IP vendor area 1 pointer */
+#define DWCMSHC_P_VENDOR_AREA1 0xe8
+#define DWCMSHC_AREA1_MASK RT_GENMASK(11, 0)
+/* Offset inside the vendor area 1 */
+#define DWCMSHC_HOST_CTRL3 0x8
+#define DWCMSHC_EMMC_CONTROL 0x2c
+#define DWCMSHC_CARD_IS_EMMC RT_BIT(0)
+#define DWCMSHC_ENHANCED_STROBE RT_BIT(8)
+#define DWCMSHC_EMMC_ATCTRL 0x40
+
+/* DWC IP vendor area 2 pointer */
+#define DWCMSHC_P_VENDOR_AREA2 0xea
+
+struct sdhci_dwcmshc;
+
+struct sdhci_dwcmshc_drv_data
+{
+ const struct rt_sdhci_pltfm_data *pdata;
+
+ rt_err_t (*init)(struct rt_sdhci_host *host, struct sdhci_dwcmshc *priv);
+ void (*postinit)(struct rt_sdhci_host *host, struct sdhci_dwcmshc *priv);
+ void (*remove)(struct rt_sdhci_host *host, struct sdhci_dwcmshc *priv);
+
+ void *vendor_priv;
+};
+
+struct sdhci_dwcmshc
+{
+ struct rt_clk *bus_clk;
+ /* P_VENDOR_SPECIFIC_AREA1/2 reg */
+ int vendor_specific_area1;
+ int vendor_specific_area2;
+
+ void *vendor_priv;
+ const struct sdhci_dwcmshc_drv_data *drv_data;
+};
+
+extern const struct sdhci_dwcmshc_drv_data sdhci_dwcmshc_generic_drv_data;
+
+rt_err_t sdhci_dwcmshc_probe(struct rt_platform_device *pdev,
+ const struct sdhci_dwcmshc_drv_data *drv_data);
+rt_err_t sdhci_dwcmshc_remove(struct rt_platform_device *pdev);
+
+void sdhci_dwcmshc_set_uhs_signaling(struct rt_sdhci_host *host, unsigned int timing);
+
+#endif /* __SDHCI_DWCMSHC_H__ */