|
@@ -76,44 +76,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;
|
|
|
-
|
|
|
- u32 ctype;
|
|
|
-
|
|
|
- struct mmc_request *mrq;
|
|
|
- struct list_head queue_node;
|
|
|
+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,
|
|
|
+};
|
|
|
|
|
|
- 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_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)
|
|
@@ -951,6 +941,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,
|
|
@@ -959,6 +981,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)
|