SDMMC: to support tuning scheme for the speed modes HS200 and SDR104
authorxbw <xbw@rock-chips.com>
Tue, 4 Mar 2014 09:17:33 +0000 (17:17 +0800)
committerxbw <xbw@rock-chips.com>
Tue, 4 Mar 2014 09:18:34 +0000 (17:18 +0800)
drivers/mmc/host/rk_sdmmc.c
drivers/mmc/host/rk_sdmmc.h

index 9b836a7eee06e41bc1d5a07fec68f510f5d17015..b719917cebc79325cc9c93c397529eb17888d720 100755 (executable)
@@ -73,45 +73,34 @@ struct idmac_desc {
 };
 #endif /* CONFIG_MMC_DW_IDMAC */
 
-/**
- * struct dw_mci_slot - MMC slot state
- * @mmc: The mmc_host representing this slot.
- * @host: The MMC controller this slot is using.
- * @quirks: Slot-level quirks (DW_MCI_SLOT_QUIRK_XXX)
- * @wp_gpio: If gpio_is_valid() we'll use this to read write protect.
- * @ctype: Card type for this slot.
- * @mrq: mmc_request currently being processed or waiting to be
- *     processed, or NULL when the slot is idle.
- * @queue_node: List node for placing this node in the @queue list of
- *     &struct dw_mci.
- * @clock: Clock rate configured by set_ios(). Protected by host->lock.
- * @__clk_old: The last updated clock with reflecting clock divider.
- *     Keeping track of this helps us to avoid spamming the console
- *     with CONFIG_MMC_CLKGATE.
- * @flags: Random state bits associated with the slot.
- * @id: Number of this slot.
- * @last_detect_state: Most recently observed card detect state.
- */
-struct dw_mci_slot {
-       struct mmc_host         *mmc;
-       struct dw_mci           *host;
-
-       int                     quirks;
-       int                     wp_gpio;
-    int         pwr_en_gpio;
-       u32                     ctype;
-
-       struct mmc_request      *mrq;
-       struct list_head        queue_node;
-
-       unsigned int            clock;
-       unsigned int            __clk_old;
-
-       unsigned long           flags;
-#define DW_MMC_CARD_PRESENT    0
-#define DW_MMC_CARD_NEED_INIT  1
-       int                     id;
-       int                     last_detect_state;
+static const u8 tuning_blk_pattern_4bit[] = {
+       0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
+       0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
+       0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
+       0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
+       0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
+       0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
+       0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
+       0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
+};
+
+static const u8 tuning_blk_pattern_8bit[] = {
+       0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+       0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
+       0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
+       0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
+       0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
+       0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
+       0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
+       0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
+       0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+       0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
+       0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
+       0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
+       0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
+       0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
+       0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
+       0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
 };
 
 #if defined(CONFIG_DEBUG_FS)
@@ -949,6 +938,38 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
        }
 }
 
+static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+       struct dw_mci_slot *slot = mmc_priv(mmc);
+       struct dw_mci *host = slot->host;
+       const struct dw_mci_drv_data *drv_data = host->drv_data;
+       struct dw_mci_tuning_data tuning_data;
+       int err = -ENOSYS;
+
+       if (opcode == MMC_SEND_TUNING_BLOCK_HS200) {
+               if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) {
+                       tuning_data.blk_pattern = tuning_blk_pattern_8bit;
+                       tuning_data.blksz = sizeof(tuning_blk_pattern_8bit);
+               } else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) {
+                       tuning_data.blk_pattern = tuning_blk_pattern_4bit;
+                       tuning_data.blksz = sizeof(tuning_blk_pattern_4bit);
+               } else {
+                       return -EINVAL;
+               }
+       } else if (opcode == MMC_SEND_TUNING_BLOCK) {
+               tuning_data.blk_pattern = tuning_blk_pattern_4bit;
+               tuning_data.blksz = sizeof(tuning_blk_pattern_4bit);
+       } else {
+               dev_err(host->dev,
+                       "Undefined command(%d) for tuning\n", opcode);
+               return -EINVAL;
+       }
+
+       if (drv_data && drv_data->execute_tuning)
+               err = drv_data->execute_tuning(slot, opcode, &tuning_data);
+       return err;
+}
+
 static const struct mmc_host_ops dw_mci_ops = {
        .request                = dw_mci_request,
        .pre_req                = dw_mci_pre_req,
@@ -957,6 +978,7 @@ static const struct mmc_host_ops dw_mci_ops = {
        .get_ro                 = dw_mci_get_ro,
        .get_cd                 = dw_mci_get_cd,
        .enable_sdio_irq        = dw_mci_enable_sdio_irq,
+       .execute_tuning         = dw_mci_execute_tuning,
 };
 
 static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
index 2f52c87bbce90b4c63bdfce9284fbea3a0d91d92..47c60a2b4297b9b390d778c733a3339bedeb2312 100755 (executable)
@@ -53,6 +53,7 @@
 #define SDMMC_IDINTEN          0x090
 #define SDMMC_DSCADDR          0x094
 #define SDMMC_BUFADDR          0x098
+#define SDMMC_CDTHRCTL         0x100
 #define SDMMC_DATA(x)          (x)
 
 /*
 #define SDMMC_INT_ERROR                        0xbfc2
 /* Command register defines */
 #define SDMMC_CMD_START                        BIT(31)
+#define SDMMC_CMD_USE_HOLD_REG BIT(29)
 #define SDMMC_CMD_CCS_EXP              BIT(23)
 #define SDMMC_CMD_CEATA_RD             BIT(22)
 #define SDMMC_CMD_UPD_CLK              BIT(21)
 #define SDMMC_CMD_INDX(n)              ((n) & 0x1F)
 /* Status register defines */
 #define SDMMC_GET_FCNT(x)              (((x)>>17) & 0x1FFF)
+/* FIFOTH register defines */
+#define SDMMC_SET_FIFOTH(m, r, t)      (((m) & 0x7) << 28 | \
+                                        ((r) & 0xFFF) << 16 | \
+                                        ((t) & 0xFFF))
 /* Internal DMAC interrupt defines */
 #define SDMMC_IDMAC_INT_AI             BIT(9)
 #define SDMMC_IDMAC_INT_NI             BIT(8)
 #define SDMMC_IDMAC_SWRESET            BIT(0)
 /* Version ID register define */
 #define SDMMC_GET_VERID(x)             ((x) & 0xFFFF)
+/* Card read threshold */
+#define SDMMC_SET_RD_THLD(v, x)                (((v) & 0x1FFF) << 16 | (x))
 
 /* Register access macros */
 #define mci_readl(dev, reg)                    \
@@ -182,6 +190,52 @@ extern int dw_mci_suspend(struct dw_mci *host);
 extern int dw_mci_resume(struct dw_mci *host);
 #endif
 
+/**
+ * struct dw_mci_slot - MMC slot state
+ * @mmc: The mmc_host representing this slot.
+ * @host: The MMC controller this slot is using.
+ * @quirks: Slot-level quirks (DW_MCI_SLOT_QUIRK_XXX)
+ * @wp_gpio: If gpio_is_valid() we'll use this to read write protect.
+ * @ctype: Card type for this slot.
+ * @mrq: mmc_request currently being processed or waiting to be
+ *     processed, or NULL when the slot is idle.
+ * @queue_node: List node for placing this node in the @queue list of
+ *     &struct dw_mci.
+ * @clock: Clock rate configured by set_ios(). Protected by host->lock.
+ * @__clk_old: The last updated clock with reflecting clock divider.
+ *     Keeping track of this helps us to avoid spamming the console
+ *     with CONFIG_MMC_CLKGATE.
+ * @flags: Random state bits associated with the slot.
+ * @id: Number of this slot.
+ * @last_detect_state: Most recently observed card detect state.
+ */
+struct dw_mci_slot {
+       struct mmc_host         *mmc;
+       struct dw_mci           *host;
+
+       int                     quirks;
+       int                     wp_gpio;
+    int         pwr_en_gpio;
+       u32                     ctype;
+
+       struct mmc_request      *mrq;
+       struct list_head        queue_node;
+
+       unsigned int            clock;
+       unsigned int            __clk_old;
+
+       unsigned long           flags;
+#define DW_MMC_CARD_PRESENT    0
+#define DW_MMC_CARD_NEED_INIT  1
+       int                     id;
+       int                     last_detect_state;
+};
+
+struct dw_mci_tuning_data {
+       const u8 *blk_pattern;
+       unsigned int blksz;
+};
+
 /**
  * dw_mci driver data - dw-mshc implementation specific driver data.
  * @caps: mmc subsystem specified capabilities of the controller(s).
@@ -202,5 +256,7 @@ struct dw_mci_drv_data {
        void            (*prepare_command)(struct dw_mci *host, u32 *cmdr);
        void            (*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
        int             (*parse_dt)(struct dw_mci *host);
+       int             (*execute_tuning)(struct dw_mci_slot *slot, u32 opcode,
+                                       struct dw_mci_tuning_data *tuning_data);
 };
 #endif /* _DW_MMC_H_ */