aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorSeungwon Jeon <tgih.jun@samsung.com>2013-08-30 11:12:42 -0400
committerChris Ball <cjb@laptop.org>2013-09-25 21:32:59 -0400
commit0976f16d2d7fdd3d33738c1f64b83cde6f783db3 (patch)
treef6de0fe07a393779626b76fc61322fa54c070b80 /drivers/mmc
parent6bce431ca13bb72261adbd20b7bc58c447ef2ce3 (diff)
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: Seungwon Jeon <tgih.jun@samsung.com> Tested-by: Alim Akhtar <alim.akhtar@samsung.com> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/dw_mmc.c97
-rw-r--r--drivers/mmc/host/dw_mmc.h48
2 files changed, 108 insertions, 37 deletions
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 9595922e231a..696bb468fc8e 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -76,44 +76,34 @@ struct idmac_desc {
76}; 76};
77#endif /* CONFIG_MMC_DW_IDMAC */ 77#endif /* CONFIG_MMC_DW_IDMAC */
78 78
79/** 79static const u8 tuning_blk_pattern_4bit[] = {
80 * struct dw_mci_slot - MMC slot state 80 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
81 * @mmc: The mmc_host representing this slot. 81 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
82 * @host: The MMC controller this slot is using. 82 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
83 * @quirks: Slot-level quirks (DW_MCI_SLOT_QUIRK_XXX) 83 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
84 * @wp_gpio: If gpio_is_valid() we'll use this to read write protect. 84 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
85 * @ctype: Card type for this slot. 85 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
86 * @mrq: mmc_request currently being processed or waiting to be 86 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
87 * processed, or NULL when the slot is idle. 87 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
88 * @queue_node: List node for placing this node in the @queue list of 88};
89 * &struct dw_mci.
90 * @clock: Clock rate configured by set_ios(). Protected by host->lock.
91 * @__clk_old: The last updated clock with reflecting clock divider.
92 * Keeping track of this helps us to avoid spamming the console
93 * with CONFIG_MMC_CLKGATE.
94 * @flags: Random state bits associated with the slot.
95 * @id: Number of this slot.
96 * @last_detect_state: Most recently observed card detect state.
97 */
98struct dw_mci_slot {
99 struct mmc_host *mmc;
100 struct dw_mci *host;
101
102 int quirks;
103 int wp_gpio;
104
105 u32 ctype;
106
107 struct mmc_request *mrq;
108 struct list_head queue_node;
109 89
110 unsigned int clock; 90static const u8 tuning_blk_pattern_8bit[] = {
111 unsigned int __clk_old; 91 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
112 unsigned long flags; 92 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
113#define DW_MMC_CARD_PRESENT 0 93 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
114#define DW_MMC_CARD_NEED_INIT 1 94 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
115 int id; 95 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
116 int last_detect_state; 96 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
97 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
98 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
99 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
100 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
101 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
102 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
103 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
104 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
105 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
106 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
117}; 107};
118 108
119#if defined(CONFIG_DEBUG_FS) 109#if defined(CONFIG_DEBUG_FS)
@@ -951,6 +941,38 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
951 } 941 }
952} 942}
953 943
944static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
945{
946 struct dw_mci_slot *slot = mmc_priv(mmc);
947 struct dw_mci *host = slot->host;
948 const struct dw_mci_drv_data *drv_data = host->drv_data;
949 struct dw_mci_tuning_data tuning_data;
950 int err = -ENOSYS;
951
952 if (opcode == MMC_SEND_TUNING_BLOCK_HS200) {
953 if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) {
954 tuning_data.blk_pattern = tuning_blk_pattern_8bit;
955 tuning_data.blksz = sizeof(tuning_blk_pattern_8bit);
956 } else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) {
957 tuning_data.blk_pattern = tuning_blk_pattern_4bit;
958 tuning_data.blksz = sizeof(tuning_blk_pattern_4bit);
959 } else {
960 return -EINVAL;
961 }
962 } else if (opcode == MMC_SEND_TUNING_BLOCK) {
963 tuning_data.blk_pattern = tuning_blk_pattern_4bit;
964 tuning_data.blksz = sizeof(tuning_blk_pattern_4bit);
965 } else {
966 dev_err(host->dev,
967 "Undefined command(%d) for tuning\n", opcode);
968 return -EINVAL;
969 }
970
971 if (drv_data && drv_data->execute_tuning)
972 err = drv_data->execute_tuning(slot, opcode, &tuning_data);
973 return err;
974}
975
954static const struct mmc_host_ops dw_mci_ops = { 976static const struct mmc_host_ops dw_mci_ops = {
955 .request = dw_mci_request, 977 .request = dw_mci_request,
956 .pre_req = dw_mci_pre_req, 978 .pre_req = dw_mci_pre_req,
@@ -959,6 +981,7 @@ static const struct mmc_host_ops dw_mci_ops = {
959 .get_ro = dw_mci_get_ro, 981 .get_ro = dw_mci_get_ro,
960 .get_cd = dw_mci_get_cd, 982 .get_cd = dw_mci_get_cd,
961 .enable_sdio_irq = dw_mci_enable_sdio_irq, 983 .enable_sdio_irq = dw_mci_enable_sdio_irq,
984 .execute_tuning = dw_mci_execute_tuning,
962}; 985};
963 986
964static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) 987static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 81b29941c5b9..b281fdc6835f 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -184,6 +184,52 @@ extern int dw_mci_resume(struct dw_mci *host);
184#endif 184#endif
185 185
186/** 186/**
187 * struct dw_mci_slot - MMC slot state
188 * @mmc: The mmc_host representing this slot.
189 * @host: The MMC controller this slot is using.
190 * @quirks: Slot-level quirks (DW_MCI_SLOT_QUIRK_XXX)
191 * @wp_gpio: If gpio_is_valid() we'll use this to read write protect.
192 * @ctype: Card type for this slot.
193 * @mrq: mmc_request currently being processed or waiting to be
194 * processed, or NULL when the slot is idle.
195 * @queue_node: List node for placing this node in the @queue list of
196 * &struct dw_mci.
197 * @clock: Clock rate configured by set_ios(). Protected by host->lock.
198 * @__clk_old: The last updated clock with reflecting clock divider.
199 * Keeping track of this helps us to avoid spamming the console
200 * with CONFIG_MMC_CLKGATE.
201 * @flags: Random state bits associated with the slot.
202 * @id: Number of this slot.
203 * @last_detect_state: Most recently observed card detect state.
204 */
205struct dw_mci_slot {
206 struct mmc_host *mmc;
207 struct dw_mci *host;
208
209 int quirks;
210 int wp_gpio;
211
212 u32 ctype;
213
214 struct mmc_request *mrq;
215 struct list_head queue_node;
216
217 unsigned int clock;
218 unsigned int __clk_old;
219
220 unsigned long flags;
221#define DW_MMC_CARD_PRESENT 0
222#define DW_MMC_CARD_NEED_INIT 1
223 int id;
224 int last_detect_state;
225};
226
227struct dw_mci_tuning_data {
228 const u8 *blk_pattern;
229 unsigned int blksz;
230};
231
232/**
187 * dw_mci driver data - dw-mshc implementation specific driver data. 233 * dw_mci driver data - dw-mshc implementation specific driver data.
188 * @caps: mmc subsystem specified capabilities of the controller(s). 234 * @caps: mmc subsystem specified capabilities of the controller(s).
189 * @init: early implementation specific initialization. 235 * @init: early implementation specific initialization.
@@ -203,5 +249,7 @@ struct dw_mci_drv_data {
203 void (*prepare_command)(struct dw_mci *host, u32 *cmdr); 249 void (*prepare_command)(struct dw_mci *host, u32 *cmdr);
204 void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios); 250 void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
205 int (*parse_dt)(struct dw_mci *host); 251 int (*parse_dt)(struct dw_mci *host);
252 int (*execute_tuning)(struct dw_mci_slot *slot, u32 opcode,
253 struct dw_mci_tuning_data *tuning_data);
206}; 254};
207#endif /* _DW_MMC_H_ */ 255#endif /* _DW_MMC_H_ */