diff options
| -rw-r--r-- | Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt | 12 | ||||
| -rw-r--r-- | drivers/mmc/core/block.c | 3 | ||||
| -rw-r--r-- | drivers/mmc/core/mmc.c | 36 | ||||
| -rw-r--r-- | drivers/mmc/core/queue.c | 125 | ||||
| -rw-r--r-- | drivers/mmc/core/queue.h | 6 | ||||
| -rw-r--r-- | drivers/mmc/host/cavium.c | 2 | ||||
| -rw-r--r-- | drivers/mmc/host/meson-gx-mmc.c | 26 | ||||
| -rw-r--r-- | drivers/mmc/host/pxamci.c | 6 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-xenon.c | 24 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-xenon.h | 1 | ||||
| -rw-r--r-- | include/linux/mmc/host.h | 2 |
11 files changed, 81 insertions, 162 deletions
diff --git a/Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt b/Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt index b878a1e305af..ed1456f5c94d 100644 --- a/Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt +++ b/Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt | |||
| @@ -16,11 +16,13 @@ Required Properties: | |||
| 16 | 16 | ||
| 17 | - clocks: | 17 | - clocks: |
| 18 | Array of clocks required for SDHC. | 18 | Array of clocks required for SDHC. |
| 19 | Require at least input clock for Xenon IP core. | 19 | Require at least input clock for Xenon IP core. For Armada AP806 and |
| 20 | CP110, the AXI clock is also mandatory. | ||
| 20 | 21 | ||
| 21 | - clock-names: | 22 | - clock-names: |
| 22 | Array of names corresponding to clocks property. | 23 | Array of names corresponding to clocks property. |
| 23 | The input clock for Xenon IP core should be named as "core". | 24 | The input clock for Xenon IP core should be named as "core". |
| 25 | The input clock for the AXI bus must be named as "axi". | ||
| 24 | 26 | ||
| 25 | - reg: | 27 | - reg: |
| 26 | * For "marvell,armada-3700-sdhci", two register areas. | 28 | * For "marvell,armada-3700-sdhci", two register areas. |
| @@ -106,8 +108,8 @@ Example: | |||
| 106 | compatible = "marvell,armada-ap806-sdhci"; | 108 | compatible = "marvell,armada-ap806-sdhci"; |
| 107 | reg = <0xaa0000 0x1000>; | 109 | reg = <0xaa0000 0x1000>; |
| 108 | interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH> | 110 | interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH> |
| 109 | clocks = <&emmc_clk>; | 111 | clocks = <&emmc_clk>,<&axi_clk>; |
| 110 | clock-names = "core"; | 112 | clock-names = "core", "axi"; |
| 111 | bus-width = <4>; | 113 | bus-width = <4>; |
| 112 | marvell,xenon-phy-slow-mode; | 114 | marvell,xenon-phy-slow-mode; |
| 113 | marvell,xenon-tun-count = <11>; | 115 | marvell,xenon-tun-count = <11>; |
| @@ -126,8 +128,8 @@ Example: | |||
| 126 | interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH> | 128 | interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH> |
| 127 | vqmmc-supply = <&sd_vqmmc_regulator>; | 129 | vqmmc-supply = <&sd_vqmmc_regulator>; |
| 128 | vmmc-supply = <&sd_vmmc_regulator>; | 130 | vmmc-supply = <&sd_vmmc_regulator>; |
| 129 | clocks = <&sdclk>; | 131 | clocks = <&sdclk>, <&axi_clk>; |
| 130 | clock-names = "core"; | 132 | clock-names = "core", "axi"; |
| 131 | bus-width = <4>; | 133 | bus-width = <4>; |
| 132 | marvell,xenon-tun-count = <9>; | 134 | marvell,xenon-tun-count = <9>; |
| 133 | }; | 135 | }; |
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 29fc1e662891..2ad7b5c69156 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c | |||
| @@ -1634,8 +1634,6 @@ static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq, | |||
| 1634 | } | 1634 | } |
| 1635 | 1635 | ||
| 1636 | mqrq->areq.mrq = &brq->mrq; | 1636 | mqrq->areq.mrq = &brq->mrq; |
| 1637 | |||
| 1638 | mmc_queue_bounce_pre(mqrq); | ||
| 1639 | } | 1637 | } |
| 1640 | 1638 | ||
| 1641 | static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, | 1639 | static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, |
| @@ -1829,7 +1827,6 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) | |||
| 1829 | brq = &mq_rq->brq; | 1827 | brq = &mq_rq->brq; |
| 1830 | old_req = mmc_queue_req_to_req(mq_rq); | 1828 | old_req = mmc_queue_req_to_req(mq_rq); |
| 1831 | type = rq_data_dir(old_req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE; | 1829 | type = rq_data_dir(old_req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE; |
| 1832 | mmc_queue_bounce_post(mq_rq); | ||
| 1833 | 1830 | ||
| 1834 | switch (status) { | 1831 | switch (status) { |
| 1835 | case MMC_BLK_SUCCESS: | 1832 | case MMC_BLK_SUCCESS: |
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index a7eb623f8daa..36217ad5e9b1 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c | |||
| @@ -1286,6 +1286,23 @@ out_err: | |||
| 1286 | return err; | 1286 | return err; |
| 1287 | } | 1287 | } |
| 1288 | 1288 | ||
| 1289 | static void mmc_select_driver_type(struct mmc_card *card) | ||
| 1290 | { | ||
| 1291 | int card_drv_type, drive_strength, drv_type; | ||
| 1292 | |||
| 1293 | card_drv_type = card->ext_csd.raw_driver_strength | | ||
| 1294 | mmc_driver_type_mask(0); | ||
| 1295 | |||
| 1296 | drive_strength = mmc_select_drive_strength(card, | ||
| 1297 | card->ext_csd.hs200_max_dtr, | ||
| 1298 | card_drv_type, &drv_type); | ||
| 1299 | |||
| 1300 | card->drive_strength = drive_strength; | ||
| 1301 | |||
| 1302 | if (drv_type) | ||
| 1303 | mmc_set_driver_type(card->host, drv_type); | ||
| 1304 | } | ||
| 1305 | |||
| 1289 | static int mmc_select_hs400es(struct mmc_card *card) | 1306 | static int mmc_select_hs400es(struct mmc_card *card) |
| 1290 | { | 1307 | { |
| 1291 | struct mmc_host *host = card->host; | 1308 | struct mmc_host *host = card->host; |
| @@ -1341,6 +1358,8 @@ static int mmc_select_hs400es(struct mmc_card *card) | |||
| 1341 | goto out_err; | 1358 | goto out_err; |
| 1342 | } | 1359 | } |
| 1343 | 1360 | ||
| 1361 | mmc_select_driver_type(card); | ||
| 1362 | |||
| 1344 | /* Switch card to HS400 */ | 1363 | /* Switch card to HS400 */ |
| 1345 | val = EXT_CSD_TIMING_HS400 | | 1364 | val = EXT_CSD_TIMING_HS400 | |
| 1346 | card->drive_strength << EXT_CSD_DRV_STR_SHIFT; | 1365 | card->drive_strength << EXT_CSD_DRV_STR_SHIFT; |
| @@ -1374,23 +1393,6 @@ out_err: | |||
| 1374 | return err; | 1393 | return err; |
| 1375 | } | 1394 | } |
| 1376 | 1395 | ||
| 1377 | static void mmc_select_driver_type(struct mmc_card *card) | ||
| 1378 | { | ||
| 1379 | int card_drv_type, drive_strength, drv_type; | ||
| 1380 | |||
| 1381 | card_drv_type = card->ext_csd.raw_driver_strength | | ||
| 1382 | mmc_driver_type_mask(0); | ||
| 1383 | |||
| 1384 | drive_strength = mmc_select_drive_strength(card, | ||
| 1385 | card->ext_csd.hs200_max_dtr, | ||
| 1386 | card_drv_type, &drv_type); | ||
| 1387 | |||
| 1388 | card->drive_strength = drive_strength; | ||
| 1389 | |||
| 1390 | if (drv_type) | ||
| 1391 | mmc_set_driver_type(card->host, drv_type); | ||
| 1392 | } | ||
| 1393 | |||
| 1394 | /* | 1396 | /* |
| 1395 | * For device supporting HS200 mode, the following sequence | 1397 | * For device supporting HS200 mode, the following sequence |
| 1396 | * should be done before executing the tuning process. | 1398 | * should be done before executing the tuning process. |
diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 74c663b1c0a7..0a4e77a5ba33 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c | |||
| @@ -23,8 +23,6 @@ | |||
| 23 | #include "core.h" | 23 | #include "core.h" |
| 24 | #include "card.h" | 24 | #include "card.h" |
| 25 | 25 | ||
| 26 | #define MMC_QUEUE_BOUNCESZ 65536 | ||
| 27 | |||
| 28 | /* | 26 | /* |
| 29 | * Prepare a MMC request. This just filters out odd stuff. | 27 | * Prepare a MMC request. This just filters out odd stuff. |
| 30 | */ | 28 | */ |
| @@ -150,26 +148,6 @@ static void mmc_queue_setup_discard(struct request_queue *q, | |||
| 150 | queue_flag_set_unlocked(QUEUE_FLAG_SECERASE, q); | 148 | queue_flag_set_unlocked(QUEUE_FLAG_SECERASE, q); |
| 151 | } | 149 | } |
| 152 | 150 | ||
| 153 | static unsigned int mmc_queue_calc_bouncesz(struct mmc_host *host) | ||
| 154 | { | ||
| 155 | unsigned int bouncesz = MMC_QUEUE_BOUNCESZ; | ||
| 156 | |||
| 157 | if (host->max_segs != 1 || (host->caps & MMC_CAP_NO_BOUNCE_BUFF)) | ||
| 158 | return 0; | ||
| 159 | |||
| 160 | if (bouncesz > host->max_req_size) | ||
| 161 | bouncesz = host->max_req_size; | ||
| 162 | if (bouncesz > host->max_seg_size) | ||
| 163 | bouncesz = host->max_seg_size; | ||
| 164 | if (bouncesz > host->max_blk_count * 512) | ||
| 165 | bouncesz = host->max_blk_count * 512; | ||
| 166 | |||
| 167 | if (bouncesz <= 512) | ||
| 168 | return 0; | ||
| 169 | |||
| 170 | return bouncesz; | ||
| 171 | } | ||
| 172 | |||
| 173 | /** | 151 | /** |
| 174 | * mmc_init_request() - initialize the MMC-specific per-request data | 152 | * mmc_init_request() - initialize the MMC-specific per-request data |
| 175 | * @q: the request queue | 153 | * @q: the request queue |
| @@ -184,26 +162,9 @@ static int mmc_init_request(struct request_queue *q, struct request *req, | |||
| 184 | struct mmc_card *card = mq->card; | 162 | struct mmc_card *card = mq->card; |
| 185 | struct mmc_host *host = card->host; | 163 | struct mmc_host *host = card->host; |
| 186 | 164 | ||
| 187 | if (card->bouncesz) { | 165 | mq_rq->sg = mmc_alloc_sg(host->max_segs, gfp); |
| 188 | mq_rq->bounce_buf = kmalloc(card->bouncesz, gfp); | 166 | if (!mq_rq->sg) |
| 189 | if (!mq_rq->bounce_buf) | 167 | return -ENOMEM; |
| 190 | return -ENOMEM; | ||
| 191 | if (card->bouncesz > 512) { | ||
| 192 | mq_rq->sg = mmc_alloc_sg(1, gfp); | ||
| 193 | if (!mq_rq->sg) | ||
| 194 | return -ENOMEM; | ||
| 195 | mq_rq->bounce_sg = mmc_alloc_sg(card->bouncesz / 512, | ||
| 196 | gfp); | ||
| 197 | if (!mq_rq->bounce_sg) | ||
| 198 | return -ENOMEM; | ||
| 199 | } | ||
| 200 | } else { | ||
| 201 | mq_rq->bounce_buf = NULL; | ||
| 202 | mq_rq->bounce_sg = NULL; | ||
| 203 | mq_rq->sg = mmc_alloc_sg(host->max_segs, gfp); | ||
| 204 | if (!mq_rq->sg) | ||
| 205 | return -ENOMEM; | ||
| 206 | } | ||
| 207 | 168 | ||
| 208 | return 0; | 169 | return 0; |
| 209 | } | 170 | } |
| @@ -212,13 +173,6 @@ static void mmc_exit_request(struct request_queue *q, struct request *req) | |||
| 212 | { | 173 | { |
| 213 | struct mmc_queue_req *mq_rq = req_to_mmc_queue_req(req); | 174 | struct mmc_queue_req *mq_rq = req_to_mmc_queue_req(req); |
| 214 | 175 | ||
| 215 | /* It is OK to kfree(NULL) so this will be smooth */ | ||
| 216 | kfree(mq_rq->bounce_sg); | ||
| 217 | mq_rq->bounce_sg = NULL; | ||
| 218 | |||
| 219 | kfree(mq_rq->bounce_buf); | ||
| 220 | mq_rq->bounce_buf = NULL; | ||
| 221 | |||
| 222 | kfree(mq_rq->sg); | 176 | kfree(mq_rq->sg); |
| 223 | mq_rq->sg = NULL; | 177 | mq_rq->sg = NULL; |
| 224 | } | 178 | } |
| @@ -242,12 +196,6 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, | |||
| 242 | if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask) | 196 | if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask) |
| 243 | limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT; | 197 | limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT; |
| 244 | 198 | ||
| 245 | /* | ||
| 246 | * mmc_init_request() depends on card->bouncesz so it must be calculated | ||
| 247 | * before blk_init_allocated_queue() starts allocating requests. | ||
| 248 | */ | ||
| 249 | card->bouncesz = mmc_queue_calc_bouncesz(host); | ||
| 250 | |||
| 251 | mq->card = card; | 199 | mq->card = card; |
| 252 | mq->queue = blk_alloc_queue(GFP_KERNEL); | 200 | mq->queue = blk_alloc_queue(GFP_KERNEL); |
| 253 | if (!mq->queue) | 201 | if (!mq->queue) |
| @@ -271,17 +219,11 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, | |||
| 271 | if (mmc_can_erase(card)) | 219 | if (mmc_can_erase(card)) |
| 272 | mmc_queue_setup_discard(mq->queue, card); | 220 | mmc_queue_setup_discard(mq->queue, card); |
| 273 | 221 | ||
| 274 | if (card->bouncesz) { | 222 | blk_queue_bounce_limit(mq->queue, limit); |
| 275 | blk_queue_max_hw_sectors(mq->queue, card->bouncesz / 512); | 223 | blk_queue_max_hw_sectors(mq->queue, |
| 276 | blk_queue_max_segments(mq->queue, card->bouncesz / 512); | 224 | min(host->max_blk_count, host->max_req_size / 512)); |
| 277 | blk_queue_max_segment_size(mq->queue, card->bouncesz); | 225 | blk_queue_max_segments(mq->queue, host->max_segs); |
| 278 | } else { | 226 | blk_queue_max_segment_size(mq->queue, host->max_seg_size); |
| 279 | blk_queue_bounce_limit(mq->queue, limit); | ||
| 280 | blk_queue_max_hw_sectors(mq->queue, | ||
| 281 | min(host->max_blk_count, host->max_req_size / 512)); | ||
| 282 | blk_queue_max_segments(mq->queue, host->max_segs); | ||
| 283 | blk_queue_max_segment_size(mq->queue, host->max_seg_size); | ||
| 284 | } | ||
| 285 | 227 | ||
| 286 | sema_init(&mq->thread_sem, 1); | 228 | sema_init(&mq->thread_sem, 1); |
| 287 | 229 | ||
| @@ -370,56 +312,7 @@ void mmc_queue_resume(struct mmc_queue *mq) | |||
| 370 | */ | 312 | */ |
| 371 | unsigned int mmc_queue_map_sg(struct mmc_queue *mq, struct mmc_queue_req *mqrq) | 313 | unsigned int mmc_queue_map_sg(struct mmc_queue *mq, struct mmc_queue_req *mqrq) |
| 372 | { | 314 | { |
| 373 | unsigned int sg_len; | ||
| 374 | size_t buflen; | ||
| 375 | struct scatterlist *sg; | ||
| 376 | struct request *req = mmc_queue_req_to_req(mqrq); | 315 | struct request *req = mmc_queue_req_to_req(mqrq); |
| 377 | int i; | ||
| 378 | |||
| 379 | if (!mqrq->bounce_buf) | ||
| 380 | return blk_rq_map_sg(mq->queue, req, mqrq->sg); | ||
| 381 | |||
| 382 | sg_len = blk_rq_map_sg(mq->queue, req, mqrq->bounce_sg); | ||
| 383 | |||
| 384 | mqrq->bounce_sg_len = sg_len; | ||
| 385 | |||
| 386 | buflen = 0; | ||
| 387 | for_each_sg(mqrq->bounce_sg, sg, sg_len, i) | ||
| 388 | buflen += sg->length; | ||
| 389 | |||
| 390 | sg_init_one(mqrq->sg, mqrq->bounce_buf, buflen); | ||
| 391 | |||
| 392 | return 1; | ||
| 393 | } | ||
| 394 | |||
| 395 | /* | ||
| 396 | * If writing, bounce the data to the buffer before the request | ||
| 397 | * is sent to the host driver | ||
| 398 | */ | ||
| 399 | void mmc_queue_bounce_pre(struct mmc_queue_req *mqrq) | ||
| 400 | { | ||
| 401 | if (!mqrq->bounce_buf) | ||
| 402 | return; | ||
| 403 | |||
| 404 | if (rq_data_dir(mmc_queue_req_to_req(mqrq)) != WRITE) | ||
| 405 | return; | ||
| 406 | |||
| 407 | sg_copy_to_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len, | ||
| 408 | mqrq->bounce_buf, mqrq->sg[0].length); | ||
| 409 | } | ||
| 410 | |||
| 411 | /* | ||
| 412 | * If reading, bounce the data from the buffer after the request | ||
| 413 | * has been handled by the host driver | ||
| 414 | */ | ||
| 415 | void mmc_queue_bounce_post(struct mmc_queue_req *mqrq) | ||
| 416 | { | ||
| 417 | if (!mqrq->bounce_buf) | ||
| 418 | return; | ||
| 419 | |||
| 420 | if (rq_data_dir(mmc_queue_req_to_req(mqrq)) != READ) | ||
| 421 | return; | ||
| 422 | 316 | ||
| 423 | sg_copy_from_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len, | 317 | return blk_rq_map_sg(mq->queue, req, mqrq->sg); |
| 424 | mqrq->bounce_buf, mqrq->sg[0].length); | ||
| 425 | } | 318 | } |
diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h index 04fc89360a7a..f18d3f656baa 100644 --- a/drivers/mmc/core/queue.h +++ b/drivers/mmc/core/queue.h | |||
| @@ -49,9 +49,6 @@ enum mmc_drv_op { | |||
| 49 | struct mmc_queue_req { | 49 | struct mmc_queue_req { |
| 50 | struct mmc_blk_request brq; | 50 | struct mmc_blk_request brq; |
| 51 | struct scatterlist *sg; | 51 | struct scatterlist *sg; |
| 52 | char *bounce_buf; | ||
| 53 | struct scatterlist *bounce_sg; | ||
| 54 | unsigned int bounce_sg_len; | ||
| 55 | struct mmc_async_req areq; | 52 | struct mmc_async_req areq; |
| 56 | enum mmc_drv_op drv_op; | 53 | enum mmc_drv_op drv_op; |
| 57 | int drv_op_result; | 54 | int drv_op_result; |
| @@ -81,11 +78,8 @@ extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *, | |||
| 81 | extern void mmc_cleanup_queue(struct mmc_queue *); | 78 | extern void mmc_cleanup_queue(struct mmc_queue *); |
| 82 | extern void mmc_queue_suspend(struct mmc_queue *); | 79 | extern void mmc_queue_suspend(struct mmc_queue *); |
| 83 | extern void mmc_queue_resume(struct mmc_queue *); | 80 | extern void mmc_queue_resume(struct mmc_queue *); |
| 84 | |||
| 85 | extern unsigned int mmc_queue_map_sg(struct mmc_queue *, | 81 | extern unsigned int mmc_queue_map_sg(struct mmc_queue *, |
| 86 | struct mmc_queue_req *); | 82 | struct mmc_queue_req *); |
| 87 | extern void mmc_queue_bounce_pre(struct mmc_queue_req *); | ||
| 88 | extern void mmc_queue_bounce_post(struct mmc_queue_req *); | ||
| 89 | 83 | ||
| 90 | extern int mmc_access_rpmb(struct mmc_queue *); | 84 | extern int mmc_access_rpmb(struct mmc_queue *); |
| 91 | 85 | ||
diff --git a/drivers/mmc/host/cavium.c b/drivers/mmc/host/cavium.c index 27fb625cbcf3..fbd29f00fca0 100644 --- a/drivers/mmc/host/cavium.c +++ b/drivers/mmc/host/cavium.c | |||
| @@ -1038,7 +1038,7 @@ int cvm_mmc_of_slot_probe(struct device *dev, struct cvm_mmc_host *host) | |||
| 1038 | */ | 1038 | */ |
| 1039 | mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | | 1039 | mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | |
| 1040 | MMC_CAP_ERASE | MMC_CAP_CMD23 | MMC_CAP_POWER_OFF_CARD | | 1040 | MMC_CAP_ERASE | MMC_CAP_CMD23 | MMC_CAP_POWER_OFF_CARD | |
| 1041 | MMC_CAP_3_3V_DDR | MMC_CAP_NO_BOUNCE_BUFF; | 1041 | MMC_CAP_3_3V_DDR; |
| 1042 | 1042 | ||
| 1043 | if (host->use_sg) | 1043 | if (host->use_sg) |
| 1044 | mmc->max_segs = 16; | 1044 | mmc->max_segs = 16; |
diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index c885c2d4b904..85745ef179e2 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c | |||
| @@ -531,8 +531,7 @@ static int meson_mmc_clk_init(struct meson_host *host) | |||
| 531 | div->shift = __ffs(CLK_DIV_MASK); | 531 | div->shift = __ffs(CLK_DIV_MASK); |
| 532 | div->width = __builtin_popcountl(CLK_DIV_MASK); | 532 | div->width = __builtin_popcountl(CLK_DIV_MASK); |
| 533 | div->hw.init = &init; | 533 | div->hw.init = &init; |
| 534 | div->flags = (CLK_DIVIDER_ONE_BASED | | 534 | div->flags = CLK_DIVIDER_ONE_BASED; |
| 535 | CLK_DIVIDER_ROUND_CLOSEST); | ||
| 536 | 535 | ||
| 537 | clk = devm_clk_register(host->dev, &div->hw); | 536 | clk = devm_clk_register(host->dev, &div->hw); |
| 538 | if (WARN_ON(IS_ERR(clk))) | 537 | if (WARN_ON(IS_ERR(clk))) |
| @@ -717,6 +716,22 @@ static int meson_mmc_clk_phase_tuning(struct mmc_host *mmc, u32 opcode, | |||
| 717 | static int meson_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode) | 716 | static int meson_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode) |
| 718 | { | 717 | { |
| 719 | struct meson_host *host = mmc_priv(mmc); | 718 | struct meson_host *host = mmc_priv(mmc); |
| 719 | int ret; | ||
| 720 | |||
| 721 | /* | ||
| 722 | * If this is the initial tuning, try to get a sane Rx starting | ||
| 723 | * phase before doing the actual tuning. | ||
| 724 | */ | ||
| 725 | if (!mmc->doing_retune) { | ||
| 726 | ret = meson_mmc_clk_phase_tuning(mmc, opcode, host->rx_clk); | ||
| 727 | |||
| 728 | if (ret) | ||
| 729 | return ret; | ||
| 730 | } | ||
| 731 | |||
| 732 | ret = meson_mmc_clk_phase_tuning(mmc, opcode, host->tx_clk); | ||
| 733 | if (ret) | ||
| 734 | return ret; | ||
| 720 | 735 | ||
| 721 | return meson_mmc_clk_phase_tuning(mmc, opcode, host->rx_clk); | 736 | return meson_mmc_clk_phase_tuning(mmc, opcode, host->rx_clk); |
| 722 | } | 737 | } |
| @@ -746,6 +761,11 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
| 746 | case MMC_POWER_UP: | 761 | case MMC_POWER_UP: |
| 747 | if (!IS_ERR(mmc->supply.vmmc)) | 762 | if (!IS_ERR(mmc->supply.vmmc)) |
| 748 | mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); | 763 | mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); |
| 764 | |||
| 765 | /* Reset phases */ | ||
| 766 | clk_set_phase(host->rx_clk, 0); | ||
| 767 | clk_set_phase(host->tx_clk, 270); | ||
| 768 | |||
| 749 | break; | 769 | break; |
| 750 | 770 | ||
| 751 | case MMC_POWER_ON: | 771 | case MMC_POWER_ON: |
| @@ -759,8 +779,6 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
| 759 | host->vqmmc_enabled = true; | 779 | host->vqmmc_enabled = true; |
| 760 | } | 780 | } |
| 761 | 781 | ||
| 762 | /* Reset rx phase */ | ||
| 763 | clk_set_phase(host->rx_clk, 0); | ||
| 764 | break; | 782 | break; |
| 765 | } | 783 | } |
| 766 | 784 | ||
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 59ab194cb009..c763b404510f 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c | |||
| @@ -702,11 +702,7 @@ static int pxamci_probe(struct platform_device *pdev) | |||
| 702 | 702 | ||
| 703 | pxamci_init_ocr(host); | 703 | pxamci_init_ocr(host); |
| 704 | 704 | ||
| 705 | /* | 705 | mmc->caps = 0; |
| 706 | * This architecture used to disable bounce buffers through its | ||
| 707 | * defconfig, now it is done at runtime as a host property. | ||
| 708 | */ | ||
| 709 | mmc->caps = MMC_CAP_NO_BOUNCE_BUFF; | ||
| 710 | host->cmdat = 0; | 706 | host->cmdat = 0; |
| 711 | if (!cpu_is_pxa25x()) { | 707 | if (!cpu_is_pxa25x()) { |
| 712 | mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; | 708 | mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; |
diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c index 2eec2e652c53..0842bbc2d7ad 100644 --- a/drivers/mmc/host/sdhci-xenon.c +++ b/drivers/mmc/host/sdhci-xenon.c | |||
| @@ -466,6 +466,7 @@ static int xenon_probe(struct platform_device *pdev) | |||
| 466 | { | 466 | { |
| 467 | struct sdhci_pltfm_host *pltfm_host; | 467 | struct sdhci_pltfm_host *pltfm_host; |
| 468 | struct sdhci_host *host; | 468 | struct sdhci_host *host; |
| 469 | struct xenon_priv *priv; | ||
| 469 | int err; | 470 | int err; |
| 470 | 471 | ||
| 471 | host = sdhci_pltfm_init(pdev, &sdhci_xenon_pdata, | 472 | host = sdhci_pltfm_init(pdev, &sdhci_xenon_pdata, |
| @@ -474,6 +475,7 @@ static int xenon_probe(struct platform_device *pdev) | |||
| 474 | return PTR_ERR(host); | 475 | return PTR_ERR(host); |
| 475 | 476 | ||
| 476 | pltfm_host = sdhci_priv(host); | 477 | pltfm_host = sdhci_priv(host); |
| 478 | priv = sdhci_pltfm_priv(pltfm_host); | ||
| 477 | 479 | ||
| 478 | /* | 480 | /* |
| 479 | * Link Xenon specific mmc_host_ops function, | 481 | * Link Xenon specific mmc_host_ops function, |
| @@ -491,9 +493,20 @@ static int xenon_probe(struct platform_device *pdev) | |||
| 491 | if (err) | 493 | if (err) |
| 492 | goto free_pltfm; | 494 | goto free_pltfm; |
| 493 | 495 | ||
| 496 | priv->axi_clk = devm_clk_get(&pdev->dev, "axi"); | ||
| 497 | if (IS_ERR(priv->axi_clk)) { | ||
| 498 | err = PTR_ERR(priv->axi_clk); | ||
| 499 | if (err == -EPROBE_DEFER) | ||
| 500 | goto err_clk; | ||
| 501 | } else { | ||
| 502 | err = clk_prepare_enable(priv->axi_clk); | ||
| 503 | if (err) | ||
| 504 | goto err_clk; | ||
| 505 | } | ||
| 506 | |||
| 494 | err = mmc_of_parse(host->mmc); | 507 | err = mmc_of_parse(host->mmc); |
| 495 | if (err) | 508 | if (err) |
| 496 | goto err_clk; | 509 | goto err_clk_axi; |
| 497 | 510 | ||
| 498 | sdhci_get_of_property(pdev); | 511 | sdhci_get_of_property(pdev); |
| 499 | 512 | ||
| @@ -502,11 +515,11 @@ static int xenon_probe(struct platform_device *pdev) | |||
| 502 | /* Xenon specific dt parse */ | 515 | /* Xenon specific dt parse */ |
| 503 | err = xenon_probe_dt(pdev); | 516 | err = xenon_probe_dt(pdev); |
| 504 | if (err) | 517 | if (err) |
| 505 | goto err_clk; | 518 | goto err_clk_axi; |
| 506 | 519 | ||
| 507 | err = xenon_sdhc_prepare(host); | 520 | err = xenon_sdhc_prepare(host); |
| 508 | if (err) | 521 | if (err) |
| 509 | goto err_clk; | 522 | goto err_clk_axi; |
| 510 | 523 | ||
| 511 | pm_runtime_get_noresume(&pdev->dev); | 524 | pm_runtime_get_noresume(&pdev->dev); |
| 512 | pm_runtime_set_active(&pdev->dev); | 525 | pm_runtime_set_active(&pdev->dev); |
| @@ -527,6 +540,8 @@ remove_sdhc: | |||
| 527 | pm_runtime_disable(&pdev->dev); | 540 | pm_runtime_disable(&pdev->dev); |
| 528 | pm_runtime_put_noidle(&pdev->dev); | 541 | pm_runtime_put_noidle(&pdev->dev); |
| 529 | xenon_sdhc_unprepare(host); | 542 | xenon_sdhc_unprepare(host); |
| 543 | err_clk_axi: | ||
| 544 | clk_disable_unprepare(priv->axi_clk); | ||
| 530 | err_clk: | 545 | err_clk: |
| 531 | clk_disable_unprepare(pltfm_host->clk); | 546 | clk_disable_unprepare(pltfm_host->clk); |
| 532 | free_pltfm: | 547 | free_pltfm: |
| @@ -538,6 +553,7 @@ static int xenon_remove(struct platform_device *pdev) | |||
| 538 | { | 553 | { |
| 539 | struct sdhci_host *host = platform_get_drvdata(pdev); | 554 | struct sdhci_host *host = platform_get_drvdata(pdev); |
| 540 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | 555 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
| 556 | struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); | ||
| 541 | 557 | ||
| 542 | pm_runtime_get_sync(&pdev->dev); | 558 | pm_runtime_get_sync(&pdev->dev); |
| 543 | pm_runtime_disable(&pdev->dev); | 559 | pm_runtime_disable(&pdev->dev); |
| @@ -546,7 +562,7 @@ static int xenon_remove(struct platform_device *pdev) | |||
| 546 | sdhci_remove_host(host, 0); | 562 | sdhci_remove_host(host, 0); |
| 547 | 563 | ||
| 548 | xenon_sdhc_unprepare(host); | 564 | xenon_sdhc_unprepare(host); |
| 549 | 565 | clk_disable_unprepare(priv->axi_clk); | |
| 550 | clk_disable_unprepare(pltfm_host->clk); | 566 | clk_disable_unprepare(pltfm_host->clk); |
| 551 | 567 | ||
| 552 | sdhci_pltfm_free(pdev); | 568 | sdhci_pltfm_free(pdev); |
diff --git a/drivers/mmc/host/sdhci-xenon.h b/drivers/mmc/host/sdhci-xenon.h index 2bc0510c0769..9994995c7c56 100644 --- a/drivers/mmc/host/sdhci-xenon.h +++ b/drivers/mmc/host/sdhci-xenon.h | |||
| @@ -83,6 +83,7 @@ struct xenon_priv { | |||
| 83 | unsigned char bus_width; | 83 | unsigned char bus_width; |
| 84 | unsigned char timing; | 84 | unsigned char timing; |
| 85 | unsigned int clock; | 85 | unsigned int clock; |
| 86 | struct clk *axi_clk; | ||
| 86 | 87 | ||
| 87 | int phy_type; | 88 | int phy_type; |
| 88 | /* | 89 | /* |
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index f3f2d07feb2a..9a43763a68ad 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h | |||
| @@ -316,7 +316,7 @@ struct mmc_host { | |||
| 316 | #define MMC_CAP_UHS_SDR50 (1 << 18) /* Host supports UHS SDR50 mode */ | 316 | #define MMC_CAP_UHS_SDR50 (1 << 18) /* Host supports UHS SDR50 mode */ |
| 317 | #define MMC_CAP_UHS_SDR104 (1 << 19) /* Host supports UHS SDR104 mode */ | 317 | #define MMC_CAP_UHS_SDR104 (1 << 19) /* Host supports UHS SDR104 mode */ |
| 318 | #define MMC_CAP_UHS_DDR50 (1 << 20) /* Host supports UHS DDR50 mode */ | 318 | #define MMC_CAP_UHS_DDR50 (1 << 20) /* Host supports UHS DDR50 mode */ |
| 319 | #define MMC_CAP_NO_BOUNCE_BUFF (1 << 21) /* Disable bounce buffers on host */ | 319 | /* (1 << 21) is free for reuse */ |
| 320 | #define MMC_CAP_DRIVER_TYPE_A (1 << 23) /* Host supports Driver Type A */ | 320 | #define MMC_CAP_DRIVER_TYPE_A (1 << 23) /* Host supports Driver Type A */ |
| 321 | #define MMC_CAP_DRIVER_TYPE_C (1 << 24) /* Host supports Driver Type C */ | 321 | #define MMC_CAP_DRIVER_TYPE_C (1 << 24) /* Host supports Driver Type C */ |
| 322 | #define MMC_CAP_DRIVER_TYPE_D (1 << 25) /* Host supports Driver Type D */ | 322 | #define MMC_CAP_DRIVER_TYPE_D (1 << 25) /* Host supports Driver Type D */ |
