Commit 0976f16d authored by Seungwon Jeon's avatar Seungwon Jeon Committed by Chris Ball

mmc: dw_mmc: add support tuning scheme

For the speed modes HS200 and SDR104, tuning is needed to determine the
correct sampling point. Actual tuning procedure is provided by specific
host controller driver.  This patch defines the tuning command and
tuning data.  Additionally, 'struct dw_mci_slot' is moved to header
file to consider the extensive usages in driver.
Signed-off-by: default avatarSeungwon Jeon <tgih.jun@samsung.com>
Tested-by: default avatarAlim Akhtar <alim.akhtar@samsung.com>
Signed-off-by: default avatarChris Ball <cjb@laptop.org>
parent 6bce431c
...@@ -76,44 +76,34 @@ struct idmac_desc { ...@@ -76,44 +76,34 @@ struct idmac_desc {
}; };
#endif /* CONFIG_MMC_DW_IDMAC */ #endif /* CONFIG_MMC_DW_IDMAC */
/** static const u8 tuning_blk_pattern_4bit[] = {
* struct dw_mci_slot - MMC slot state 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
* @mmc: The mmc_host representing this slot. 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
* @host: The MMC controller this slot is using. 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
* @quirks: Slot-level quirks (DW_MCI_SLOT_QUIRK_XXX) 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
* @wp_gpio: If gpio_is_valid() we'll use this to read write protect. 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
* @ctype: Card type for this slot. 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
* @mrq: mmc_request currently being processed or waiting to be 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
* processed, or NULL when the slot is idle. 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
* @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;
unsigned int clock; static const u8 tuning_blk_pattern_8bit[] = {
unsigned int __clk_old; 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
unsigned long flags; 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
#define DW_MMC_CARD_PRESENT 0 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
#define DW_MMC_CARD_NEED_INIT 1 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
int id; 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
int last_detect_state; 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) #if defined(CONFIG_DEBUG_FS)
...@@ -951,6 +941,38 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) ...@@ -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 = { static const struct mmc_host_ops dw_mci_ops = {
.request = dw_mci_request, .request = dw_mci_request,
.pre_req = dw_mci_pre_req, .pre_req = dw_mci_pre_req,
...@@ -959,6 +981,7 @@ static const struct mmc_host_ops dw_mci_ops = { ...@@ -959,6 +981,7 @@ static const struct mmc_host_ops dw_mci_ops = {
.get_ro = dw_mci_get_ro, .get_ro = dw_mci_get_ro,
.get_cd = dw_mci_get_cd, .get_cd = dw_mci_get_cd,
.enable_sdio_irq = dw_mci_enable_sdio_irq, .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) static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
......
...@@ -183,6 +183,52 @@ extern int dw_mci_suspend(struct dw_mci *host); ...@@ -183,6 +183,52 @@ extern int dw_mci_suspend(struct dw_mci *host);
extern int dw_mci_resume(struct dw_mci *host); extern int dw_mci_resume(struct dw_mci *host);
#endif #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;
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. * dw_mci driver data - dw-mshc implementation specific driver data.
* @caps: mmc subsystem specified capabilities of the controller(s). * @caps: mmc subsystem specified capabilities of the controller(s).
...@@ -203,5 +249,7 @@ struct dw_mci_drv_data { ...@@ -203,5 +249,7 @@ struct dw_mci_drv_data {
void (*prepare_command)(struct dw_mci *host, u32 *cmdr); void (*prepare_command)(struct dw_mci *host, u32 *cmdr);
void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios); void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
int (*parse_dt)(struct dw_mci *host); 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_ */ #endif /* _DW_MMC_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment