aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2014-08-19 04:45:51 -0400
committerUlf Hansson <ulf.hansson@linaro.org>2014-09-09 07:59:07 -0400
commit3d705d14fe4c72be83bae1610680e209ee226b9d (patch)
treef62e06a2feffe512962cf2ec00baccf52460cdbf
parentb315376573778b195e640a163675fb9f5937ddca (diff)
mmc: implement Driver Stage Register handling
Some eMMC and SD cards implement a DSR register that allows to tune raise/fall times and drive strength of the CMD and DATA outputs. The values to use depend on the card in use and the host. It might be needed to reduce the drive strength to prevent voltage peaks above the host's specification. Implement a 'dsr' devicetree property that allows to specify the value to set the DSR to. For non-dt setups the new members of mmc_host can be set by board code. This patch was initially authored by Sascha Hauer. It contains improvements authored by Markus Niebel and Uwe Kleine-König. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Signed-off-by: Markus Niebel <Markus.Niebel@tq-group.com> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
-rw-r--r--Documentation/devicetree/bindings/mmc/mmc.txt2
-rw-r--r--drivers/mmc/core/host.c8
-rw-r--r--drivers/mmc/core/mmc.c8
-rw-r--r--drivers/mmc/core/mmc_ops.c20
-rw-r--r--drivers/mmc/core/mmc_ops.h1
-rw-r--r--drivers/mmc/core/sd.c8
-rw-r--r--include/linux/mmc/card.h3
-rw-r--r--include/linux/mmc/host.h3
8 files changed, 52 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt
index 431716e37a39..b52628b18a53 100644
--- a/Documentation/devicetree/bindings/mmc/mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/mmc.txt
@@ -40,6 +40,8 @@ Optional properties:
40- mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported 40- mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported
41- mmc-hs400-1_8v: eMMC HS400 mode(1.8V I/O) is supported 41- mmc-hs400-1_8v: eMMC HS400 mode(1.8V I/O) is supported
42- mmc-hs400-1_2v: eMMC HS400 mode(1.2V I/O) is supported 42- mmc-hs400-1_2v: eMMC HS400 mode(1.2V I/O) is supported
43- dsr: Value the card's (optional) Driver Stage Register (DSR) should be
44 programmed with. Valid range: [0 .. 0xffff].
43 45
44*NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line 46*NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
45polarity properties, we have to fix the meaning of the "normal" and "inverted" 47polarity properties, we have to fix the meaning of the "normal" and "inverted"
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 95cceae96944..d572b2beb65a 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -452,6 +452,14 @@ int mmc_of_parse(struct mmc_host *host)
452 if (of_find_property(np, "mmc-hs400-1_2v", &len)) 452 if (of_find_property(np, "mmc-hs400-1_2v", &len))
453 host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR; 453 host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
454 454
455 host->dsr_req = !of_property_read_u32(np, "dsr", &host->dsr);
456 if (host->dsr_req && (host->dsr & ~0xffff)) {
457 dev_err(host->parent,
458 "device tree specified broken value for DSR: 0x%x, ignoring\n",
459 host->dsr);
460 host->dsr_req = 0;
461 }
462
455 return 0; 463 return 0;
456 464
457out: 465out:
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 1eda8dd8c867..31c43165f8bc 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -162,6 +162,7 @@ static int mmc_decode_csd(struct mmc_card *card)
162 csd->read_partial = UNSTUFF_BITS(resp, 79, 1); 162 csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
163 csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); 163 csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
164 csd->read_misalign = UNSTUFF_BITS(resp, 77, 1); 164 csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
165 csd->dsr_imp = UNSTUFF_BITS(resp, 76, 1);
165 csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3); 166 csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
166 csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4); 167 csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
167 csd->write_partial = UNSTUFF_BITS(resp, 21, 1); 168 csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
@@ -1272,6 +1273,13 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
1272 } 1273 }
1273 1274
1274 /* 1275 /*
1276 * handling only for cards supporting DSR and hosts requesting
1277 * DSR configuration
1278 */
1279 if (card->csd.dsr_imp && host->dsr_req)
1280 mmc_set_dsr(host);
1281
1282 /*
1275 * Select card, as all following commands rely on that. 1283 * Select card, as all following commands rely on that.
1276 */ 1284 */
1277 if (!mmc_host_is_spi(host)) { 1285 if (!mmc_host_is_spi(host)) {
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index f51b5ba3bbea..ba0275e90617 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -93,6 +93,26 @@ int mmc_deselect_cards(struct mmc_host *host)
93 return _mmc_select_card(host, NULL); 93 return _mmc_select_card(host, NULL);
94} 94}
95 95
96/*
97 * Write the value specified in the device tree or board code into the optional
98 * 16 bit Driver Stage Register. This can be used to tune raise/fall times and
99 * drive strength of the DAT and CMD outputs. The actual meaning of a given
100 * value is hardware dependant.
101 * The presence of the DSR register can be determined from the CSD register,
102 * bit 76.
103 */
104int mmc_set_dsr(struct mmc_host *host)
105{
106 struct mmc_command cmd = {0};
107
108 cmd.opcode = MMC_SET_DSR;
109
110 cmd.arg = (host->dsr << 16) | 0xffff;
111 cmd.flags = MMC_RSP_NONE | MMC_CMD_AC;
112
113 return mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
114}
115
96int mmc_go_idle(struct mmc_host *host) 116int mmc_go_idle(struct mmc_host *host)
97{ 117{
98 int err; 118 int err;
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 80ae9f4e0293..390dac665b2a 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -14,6 +14,7 @@
14 14
15int mmc_select_card(struct mmc_card *card); 15int mmc_select_card(struct mmc_card *card);
16int mmc_deselect_cards(struct mmc_host *host); 16int mmc_deselect_cards(struct mmc_host *host);
17int mmc_set_dsr(struct mmc_host *host);
17int mmc_go_idle(struct mmc_host *host); 18int mmc_go_idle(struct mmc_host *host);
18int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); 19int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
19int mmc_all_send_cid(struct mmc_host *host, u32 *cid); 20int mmc_all_send_cid(struct mmc_host *host, u32 *cid);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 0c44510bf717..25913889cbaa 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -127,6 +127,7 @@ static int mmc_decode_csd(struct mmc_card *card)
127 csd->read_partial = UNSTUFF_BITS(resp, 79, 1); 127 csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
128 csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); 128 csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
129 csd->read_misalign = UNSTUFF_BITS(resp, 77, 1); 129 csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
130 csd->dsr_imp = UNSTUFF_BITS(resp, 76, 1);
130 csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3); 131 csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
131 csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4); 132 csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
132 csd->write_partial = UNSTUFF_BITS(resp, 21, 1); 133 csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
@@ -954,6 +955,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
954 } 955 }
955 956
956 /* 957 /*
958 * handling only for cards supporting DSR and hosts requesting
959 * DSR configuration
960 */
961 if (card->csd.dsr_imp && host->dsr_req)
962 mmc_set_dsr(host);
963
964 /*
957 * Select card, as all following commands rely on that. 965 * Select card, as all following commands rely on that.
958 */ 966 */
959 if (!mmc_host_is_spi(host)) { 967 if (!mmc_host_is_spi(host)) {
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index bde5147a4221..0ea795f5feb9 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -42,7 +42,8 @@ struct mmc_csd {
42 unsigned int read_partial:1, 42 unsigned int read_partial:1,
43 read_misalign:1, 43 read_misalign:1,
44 write_partial:1, 44 write_partial:1,
45 write_misalign:1; 45 write_misalign:1,
46 dsr_imp:1;
46}; 47};
47 48
48struct mmc_ext_csd { 49struct mmc_ext_csd {
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 7960424d0bc0..4cbf61476999 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -365,6 +365,9 @@ struct mmc_host {
365 365
366 unsigned int slotno; /* used for sdio acpi binding */ 366 unsigned int slotno; /* used for sdio acpi binding */
367 367
368 int dsr_req; /* DSR value is valid */
369 u32 dsr; /* optional driver stage (DSR) value */
370
368 unsigned long private[0] ____cacheline_aligned; 371 unsigned long private[0] ____cacheline_aligned;
369}; 372};
370 373