]> git.ipfire.org Git - thirdparty/u-boot.git/blobdiff - include/sdhci.h
mmc: sdhci: Fix potential ADMA descriptor table overflow
[thirdparty/u-boot.git] / include / sdhci.h
index eee493ab5f578fdd81082827ae2cf1f4ab65e8a3..2dd13b4c714a5c1d85c89aa0351a1303db0efcbb 100644 (file)
@@ -9,6 +9,9 @@
 #ifndef __SDHCI_HW_H
 #define __SDHCI_HW_H
 
+#include <linux/bitops.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
 #include <asm/io.h>
 #include <mmc.h>
 #include <asm/gpio.h>
@@ -55,6 +58,7 @@
 #define SDHCI_PRESENT_STATE    0x24
 #define  SDHCI_CMD_INHIBIT     BIT(0)
 #define  SDHCI_DATA_INHIBIT    BIT(1)
+#define  SDHCI_DAT_ACTIVE      BIT(2)
 #define  SDHCI_DOING_WRITE     BIT(8)
 #define  SDHCI_DOING_READ      BIT(9)
 #define  SDHCI_SPACE_AVAILABLE BIT(10)
@@ -63,6 +67,8 @@
 #define  SDHCI_CARD_STATE_STABLE       BIT(17)
 #define  SDHCI_CARD_DETECT_PIN_LEVEL   BIT(18)
 #define  SDHCI_WRITE_PROTECT   BIT(19)
+#define  SDHCI_DATA_LVL_MASK   0x00F00000
+#define   SDHCI_DATA_0_LVL_MASK BIT(20)
 
 #define SDHCI_HOST_CONTROL     0x28
 #define  SDHCI_CTRL_LED                BIT(0)
 
 #define SDHCI_ACMD12_ERR       0x3C
 
-/* 3E-3F reserved */
+#define SDHCI_HOST_CONTROL2    0x3E
+#define  SDHCI_CTRL_UHS_MASK   0x0007
+#define  SDHCI_CTRL_UHS_SDR12  0x0000
+#define  SDHCI_CTRL_UHS_SDR25  0x0001
+#define  SDHCI_CTRL_UHS_SDR50  0x0002
+#define  SDHCI_CTRL_UHS_SDR104 0x0003
+#define  SDHCI_CTRL_UHS_DDR50  0x0004
+#define  SDHCI_CTRL_HS400      0x0005 /* Non-standard */
+#define  SDHCI_CTRL_VDD_180    0x0008
+#define  SDHCI_CTRL_DRV_TYPE_MASK      0x0030
+#define  SDHCI_CTRL_DRV_TYPE_B 0x0000
+#define  SDHCI_CTRL_DRV_TYPE_A 0x0010
+#define  SDHCI_CTRL_DRV_TYPE_C 0x0020
+#define  SDHCI_CTRL_DRV_TYPE_D 0x0030
+#define  SDHCI_CTRL_EXEC_TUNING        0x0040
+#define  SDHCI_CTRL_TUNED_CLK  0x0080
+#define  SDHCI_CTRL_PRESET_VAL_ENABLE  0x8000
 
 #define SDHCI_CAPABILITIES     0x40
 #define  SDHCI_TIMEOUT_CLK_MASK        0x0000003F
 #define  SDHCI_SUPPORT_SDR50   0x00000001
 #define  SDHCI_SUPPORT_SDR104  0x00000002
 #define  SDHCI_SUPPORT_DDR50   0x00000004
+#define  SDHCI_SUPPORT_HS400   BIT(31)
 #define  SDHCI_USE_SDR50_TUNING        0x00002000
 
 #define  SDHCI_CLOCK_MUL_MASK  0x00FF0000
 #define SDHCI_QUIRK_WAIT_SEND_CMD      (1 << 6)
 #define SDHCI_QUIRK_USE_WIDE8          (1 << 8)
 #define SDHCI_QUIRK_NO_1_8_V           (1 << 9)
+#define SDHCI_QUIRK_SUPPORT_SINGLE     (1 << 10)
+/* Capability register bit-63 indicates HS400 support */
+#define SDHCI_QUIRK_CAPS_BIT63_FOR_HS400       BIT(11)
 
 /* to make gcc happy */
 struct sdhci_host;
@@ -247,21 +273,40 @@ struct sdhci_ops {
 #endif
        int     (*get_cd)(struct sdhci_host *host);
        void    (*set_control_reg)(struct sdhci_host *host);
-       void    (*set_ios_post)(struct sdhci_host *host);
+       int     (*set_ios_post)(struct sdhci_host *host);
        void    (*set_clock)(struct sdhci_host *host, u32 div);
        int (*platform_execute_tuning)(struct mmc *host, u8 opcode);
-       void (*set_delay)(struct sdhci_host *host);
+       int (*set_delay)(struct sdhci_host *host);
+       /* Callback function to set DLL clock configuration */
+       int (*config_dll)(struct sdhci_host *host, u32 clock, bool enable);
+       int     (*deferred_probe)(struct sdhci_host *host);
+
+       /**
+        * set_enhanced_strobe() - Set HS400 Enhanced Strobe config
+        *
+        * This is called after setting the card speed and mode to
+        * HS400 ES, and should set any host-specific configuration
+        * necessary for it.
+        *
+        * @host: SDHCI host structure
+        * Return: 0 if successful, -ve on error
+        */
+       int     (*set_enhanced_strobe)(struct sdhci_host *host);
+
+#ifdef CONFIG_MMC_SDHCI_ADMA_HELPERS
+       void    (*adma_write_desc)(struct sdhci_host *host, void **desc,
+                                  dma_addr_t addr, int len, bool end);
+#endif
 };
 
-#if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA)
 #define ADMA_MAX_LEN   65532
 #ifdef CONFIG_DMA_ADDR_T_64BIT
 #define ADMA_DESC_LEN  16
 #else
 #define ADMA_DESC_LEN  8
 #endif
-#define ADMA_TABLE_NO_ENTRIES (CONFIG_SYS_MMC_MAX_BLK_COUNT * \
-                              MMC_MAX_BLOCK_LEN) / ADMA_MAX_LEN
+#define ADMA_TABLE_NO_ENTRIES DIV_ROUND_UP(CONFIG_SYS_MMC_MAX_BLK_COUNT * \
+                             MMC_MAX_BLOCK_LEN, ADMA_MAX_LEN)
 
 #define ADMA_TABLE_SZ (ADMA_TABLE_NO_ENTRIES * ADMA_DESC_LEN)
 
@@ -284,7 +329,7 @@ struct sdhci_adma_desc {
        u32 addr_hi;
 #endif
 } __packed;
-#endif
+
 struct sdhci_host {
        const char *name;
        void *ioaddr;
@@ -305,6 +350,8 @@ struct sdhci_host {
        uint    voltages;
 
        struct mmc_config cfg;
+       void *align_buffer;
+       bool force_align_buffer;
        dma_addr_t start_addr;
        int flags;
 #define USE_SDMA       (0x1 << 0)
@@ -314,7 +361,6 @@ struct sdhci_host {
        dma_addr_t adma_addr;
 #if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA)
        struct sdhci_adma_desc *adma_desc_table;
-       uint desc_slot;
 #endif
 };
 
@@ -421,10 +467,10 @@ static inline u8 sdhci_readb(struct sdhci_host *host, int reg)
  * ...
  *
  * Inside U_BOOT_DRIVER():
- *     .platdata_auto_alloc_size = sizeof(struct msm_sdhc_plat),
+ *     .plat_auto      = sizeof(struct msm_sdhc_plat),
  *
  * To access platform data:
- *     struct msm_sdhc_plat *plat = dev_get_platdata(dev);
+ *     struct msm_sdhc_plat *plat = dev_get_plat(dev);
  *
  * See msm_sdhci.c for an example.
  *
@@ -449,7 +495,7 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
  * @cfg:       Empty configuration structure (generally &plat->cfg). This is
  *             normally all zeroes at this point. The only purpose of passing
  *             this in is to set mmc->cfg to it.
- * @return 0 if OK, -ve if the block device could not be created
+ * Return: 0 if OK, -ve if the block device could not be created
  */
 int sdhci_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config *cfg);
 #else
@@ -462,16 +508,35 @@ int sdhci_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config *cfg);
  * @host:      SDHCI host structure
  * @f_max:     Maximum supported clock frequency in HZ (0 for default)
  * @f_min:     Minimum supported clock frequency in HZ (0 for default)
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int add_sdhci(struct sdhci_host *host, u32 f_max, u32 f_min);
 #endif /* !CONFIG_BLK */
 
+void sdhci_set_uhs_timing(struct sdhci_host *host);
 #ifdef CONFIG_DM_MMC
 /* Export the operations to drivers */
 int sdhci_probe(struct udevice *dev);
+int sdhci_set_clock(struct mmc *mmc, unsigned int clock);
+
+/**
+ * sdhci_set_control_reg - Set control registers
+ *
+ * This is used set up control registers for voltage level and UHS speed
+ * mode.
+ *
+ * @host: SDHCI host structure
+ */
+void sdhci_set_control_reg(struct sdhci_host *host);
 extern const struct dm_mmc_ops sdhci_ops;
 #else
 #endif
 
+void sdhci_adma_write_desc(struct sdhci_host *host, void **next_desc,
+                          dma_addr_t addr, int len, bool end);
+struct sdhci_adma_desc *sdhci_adma_init(void);
+void sdhci_prepare_adma_table(struct sdhci_host *host,
+                             struct sdhci_adma_desc *table,
+                             struct mmc_data *data, dma_addr_t start_addr);
+
 #endif /* __SDHCI_HW_H */