aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPrabu Thangamuthu <Prabu.T@synopsys.com>2014-10-20 03:12:33 -0400
committerUlf Hansson <ulf.hansson@linaro.org>2014-11-26 08:30:50 -0500
commit69d99fdcfd7815dfb2318f0777a46181d5bf42dc (patch)
tree1e9c2cf01589da8fe2593c176d91fa7760a078ce
parente765bfa22a8f06f0964a97e3e81148511d75140a (diff)
mmc: dw_mmc: Add IDMAC 64-bit address mode support
Synopsys DW_MMC IP core supports Internal DMA Controller with 64-bit address mode from IP version 2.70a onwards. Updated the driver to support IDMAC 64-bit addressing mode. Signed-off-by: Prabu Thangamuthu <prabu.t@synopsys.com> Reviewed-by: Alim Akhtar <alim.akhtar@samsung.com> Acked-by: Jaehoon Chung <jh80.chung@samsung.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
-rw-r--r--drivers/mmc/host/dw_mmc.c199
-rw-r--r--drivers/mmc/host/dw_mmc.h11
-rw-r--r--include/linux/mmc/dw_mmc.h2
3 files changed, 174 insertions, 38 deletions
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index bb46b1b8d16b..5a37c33879a1 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -61,6 +61,24 @@
61 SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \ 61 SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \
62 SDMMC_IDMAC_INT_TI) 62 SDMMC_IDMAC_INT_TI)
63 63
64struct idmac_desc_64addr {
65 u32 des0; /* Control Descriptor */
66
67 u32 des1; /* Reserved */
68
69 u32 des2; /*Buffer sizes */
70#define IDMAC_64ADDR_SET_BUFFER1_SIZE(d, s) \
71 ((d)->des2 = ((d)->des2 & 0x03ffe000) | ((s) & 0x1fff))
72
73 u32 des3; /* Reserved */
74
75 u32 des4; /* Lower 32-bits of Buffer Address Pointer 1*/
76 u32 des5; /* Upper 32-bits of Buffer Address Pointer 1*/
77
78 u32 des6; /* Lower 32-bits of Next Descriptor Address */
79 u32 des7; /* Upper 32-bits of Next Descriptor Address */
80};
81
64struct idmac_desc { 82struct idmac_desc {
65 u32 des0; /* Control Descriptor */ 83 u32 des0; /* Control Descriptor */
66#define IDMAC_DES0_DIC BIT(1) 84#define IDMAC_DES0_DIC BIT(1)
@@ -414,30 +432,66 @@ static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
414 unsigned int sg_len) 432 unsigned int sg_len)
415{ 433{
416 int i; 434 int i;
417 struct idmac_desc *desc = host->sg_cpu; 435 if (host->dma_64bit_address == 1) {
436 struct idmac_desc_64addr *desc = host->sg_cpu;
418 437
419 for (i = 0; i < sg_len; i++, desc++) { 438 for (i = 0; i < sg_len; i++, desc++) {
420 unsigned int length = sg_dma_len(&data->sg[i]); 439 unsigned int length = sg_dma_len(&data->sg[i]);
421 u32 mem_addr = sg_dma_address(&data->sg[i]); 440 u64 mem_addr = sg_dma_address(&data->sg[i]);
422 441
423 /* Set the OWN bit and disable interrupts for this descriptor */ 442 /*
424 desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | IDMAC_DES0_CH; 443 * Set the OWN bit and disable interrupts for this
444 * descriptor
445 */
446 desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC |
447 IDMAC_DES0_CH;
448 /* Buffer length */
449 IDMAC_64ADDR_SET_BUFFER1_SIZE(desc, length);
450
451 /* Physical address to DMA to/from */
452 desc->des4 = mem_addr & 0xffffffff;
453 desc->des5 = mem_addr >> 32;
454 }
425 455
426 /* Buffer length */ 456 /* Set first descriptor */
427 IDMAC_SET_BUFFER1_SIZE(desc, length); 457 desc = host->sg_cpu;
458 desc->des0 |= IDMAC_DES0_FD;
428 459
429 /* Physical address to DMA to/from */ 460 /* Set last descriptor */
430 desc->des2 = mem_addr; 461 desc = host->sg_cpu + (i - 1) *
431 } 462 sizeof(struct idmac_desc_64addr);
463 desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
464 desc->des0 |= IDMAC_DES0_LD;
465
466 } else {
467 struct idmac_desc *desc = host->sg_cpu;
468
469 for (i = 0; i < sg_len; i++, desc++) {
470 unsigned int length = sg_dma_len(&data->sg[i]);
471 u32 mem_addr = sg_dma_address(&data->sg[i]);
472
473 /*
474 * Set the OWN bit and disable interrupts for this
475 * descriptor
476 */
477 desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC |
478 IDMAC_DES0_CH;
479 /* Buffer length */
480 IDMAC_SET_BUFFER1_SIZE(desc, length);
481
482 /* Physical address to DMA to/from */
483 desc->des2 = mem_addr;
484 }
432 485
433 /* Set first descriptor */ 486 /* Set first descriptor */
434 desc = host->sg_cpu; 487 desc = host->sg_cpu;
435 desc->des0 |= IDMAC_DES0_FD; 488 desc->des0 |= IDMAC_DES0_FD;
436 489
437 /* Set last descriptor */ 490 /* Set last descriptor */
438 desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc); 491 desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc);
439 desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC); 492 desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
440 desc->des0 |= IDMAC_DES0_LD; 493 desc->des0 |= IDMAC_DES0_LD;
494 }
441 495
442 wmb(); 496 wmb();
443} 497}
@@ -470,29 +524,71 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
470 524
471static int dw_mci_idmac_init(struct dw_mci *host) 525static int dw_mci_idmac_init(struct dw_mci *host)
472{ 526{
473 struct idmac_desc *p;
474 int i; 527 int i;
475 528
476 /* Number of descriptors in the ring buffer */ 529 if (host->dma_64bit_address == 1) {
477 host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc); 530 struct idmac_desc_64addr *p;
531 /* Number of descriptors in the ring buffer */
532 host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc_64addr);
533
534 /* Forward link the descriptor list */
535 for (i = 0, p = host->sg_cpu; i < host->ring_size - 1;
536 i++, p++) {
537 p->des6 = (host->sg_dma +
538 (sizeof(struct idmac_desc_64addr) *
539 (i + 1))) & 0xffffffff;
540
541 p->des7 = (u64)(host->sg_dma +
542 (sizeof(struct idmac_desc_64addr) *
543 (i + 1))) >> 32;
544 /* Initialize reserved and buffer size fields to "0" */
545 p->des1 = 0;
546 p->des2 = 0;
547 p->des3 = 0;
548 }
549
550 /* Set the last descriptor as the end-of-ring descriptor */
551 p->des6 = host->sg_dma & 0xffffffff;
552 p->des7 = (u64)host->sg_dma >> 32;
553 p->des0 = IDMAC_DES0_ER;
554
555 } else {
556 struct idmac_desc *p;
557 /* Number of descriptors in the ring buffer */
558 host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
478 559
479 /* Forward link the descriptor list */ 560 /* Forward link the descriptor list */
480 for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++) 561 for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
481 p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1)); 562 p->des3 = host->sg_dma + (sizeof(struct idmac_desc) *
563 (i + 1));
482 564
483 /* Set the last descriptor as the end-of-ring descriptor */ 565 /* Set the last descriptor as the end-of-ring descriptor */
484 p->des3 = host->sg_dma; 566 p->des3 = host->sg_dma;
485 p->des0 = IDMAC_DES0_ER; 567 p->des0 = IDMAC_DES0_ER;
568 }
486 569
487 dw_mci_idmac_reset(host); 570 dw_mci_idmac_reset(host);
488 571
489 /* Mask out interrupts - get Tx & Rx complete only */ 572 if (host->dma_64bit_address == 1) {
490 mci_writel(host, IDSTS, IDMAC_INT_CLR); 573 /* Mask out interrupts - get Tx & Rx complete only */
491 mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI | 574 mci_writel(host, IDSTS64, IDMAC_INT_CLR);
492 SDMMC_IDMAC_INT_TI); 575 mci_writel(host, IDINTEN64, SDMMC_IDMAC_INT_NI |
576 SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI);
577
578 /* Set the descriptor base address */
579 mci_writel(host, DBADDRL, host->sg_dma & 0xffffffff);
580 mci_writel(host, DBADDRU, (u64)host->sg_dma >> 32);
581
582 } else {
583 /* Mask out interrupts - get Tx & Rx complete only */
584 mci_writel(host, IDSTS, IDMAC_INT_CLR);
585 mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI |
586 SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI);
587
588 /* Set the descriptor base address */
589 mci_writel(host, DBADDR, host->sg_dma);
590 }
493 591
494 /* Set the descriptor base address */
495 mci_writel(host, DBADDR, host->sg_dma);
496 return 0; 592 return 0;
497} 593}
498 594
@@ -2066,11 +2162,22 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
2066 2162
2067#ifdef CONFIG_MMC_DW_IDMAC 2163#ifdef CONFIG_MMC_DW_IDMAC
2068 /* Handle DMA interrupts */ 2164 /* Handle DMA interrupts */
2069 pending = mci_readl(host, IDSTS); 2165 if (host->dma_64bit_address == 1) {
2070 if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) { 2166 pending = mci_readl(host, IDSTS64);
2071 mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI); 2167 if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
2072 mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI); 2168 mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_TI |
2073 host->dma_ops->complete(host); 2169 SDMMC_IDMAC_INT_RI);
2170 mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_NI);
2171 host->dma_ops->complete(host);
2172 }
2173 } else {
2174 pending = mci_readl(host, IDSTS);
2175 if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
2176 mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI |
2177 SDMMC_IDMAC_INT_RI);
2178 mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
2179 host->dma_ops->complete(host);
2180 }
2074 } 2181 }
2075#endif 2182#endif
2076 2183
@@ -2245,6 +2352,22 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
2245 2352
2246static void dw_mci_init_dma(struct dw_mci *host) 2353static void dw_mci_init_dma(struct dw_mci *host)
2247{ 2354{
2355 int addr_config;
2356 /* Check ADDR_CONFIG bit in HCON to find IDMAC address bus width */
2357 addr_config = (mci_readl(host, HCON) >> 27) & 0x01;
2358
2359 if (addr_config == 1) {
2360 /* host supports IDMAC in 64-bit address mode */
2361 host->dma_64bit_address = 1;
2362 dev_info(host->dev, "IDMAC supports 64-bit address mode.\n");
2363 if (!dma_set_mask(host->dev, DMA_BIT_MASK(64)))
2364 dma_set_coherent_mask(host->dev, DMA_BIT_MASK(64));
2365 } else {
2366 /* host supports IDMAC in 32-bit address mode */
2367 host->dma_64bit_address = 0;
2368 dev_info(host->dev, "IDMAC supports 32-bit address mode.\n");
2369 }
2370
2248 /* Alloc memory for sg translation */ 2371 /* Alloc memory for sg translation */
2249 host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE, 2372 host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE,
2250 &host->sg_dma, GFP_KERNEL); 2373 &host->sg_dma, GFP_KERNEL);
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 71d499557edc..58d8a54d644b 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -55,6 +55,17 @@
55#define SDMMC_BUFADDR 0x098 55#define SDMMC_BUFADDR 0x098
56#define SDMMC_CDTHRCTL 0x100 56#define SDMMC_CDTHRCTL 0x100
57#define SDMMC_DATA(x) (x) 57#define SDMMC_DATA(x) (x)
58/*
59* Registers to support idmac 64-bit address mode
60*/
61#define SDMMC_DBADDRL 0x088
62#define SDMMC_DBADDRU 0x08c
63#define SDMMC_IDSTS64 0x090
64#define SDMMC_IDINTEN64 0x094
65#define SDMMC_DSCADDRL 0x098
66#define SDMMC_DSCADDRU 0x09c
67#define SDMMC_BUFADDRL 0x0A0
68#define SDMMC_BUFADDRU 0x0A4
58 69
59/* 70/*
60 * Data offset is difference according to Version 71 * Data offset is difference according to Version
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index 69d08144cfad..0a551152d600 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -54,6 +54,7 @@ struct mmc_data;
54 * transfer is in progress. 54 * transfer is in progress.
55 * @use_dma: Whether DMA channel is initialized or not. 55 * @use_dma: Whether DMA channel is initialized or not.
56 * @using_dma: Whether DMA is in use for the current transfer. 56 * @using_dma: Whether DMA is in use for the current transfer.
57 * @dma_64bit_address: Whether DMA supports 64-bit address mode or not.
57 * @sg_dma: Bus address of DMA buffer. 58 * @sg_dma: Bus address of DMA buffer.
58 * @sg_cpu: Virtual address of DMA buffer. 59 * @sg_cpu: Virtual address of DMA buffer.
59 * @dma_ops: Pointer to platform-specific DMA callbacks. 60 * @dma_ops: Pointer to platform-specific DMA callbacks.
@@ -139,6 +140,7 @@ struct dw_mci {
139 /* DMA interface members*/ 140 /* DMA interface members*/
140 int use_dma; 141 int use_dma;
141 int using_dma; 142 int using_dma;
143 int dma_64bit_address;
142 144
143 dma_addr_t sg_dma; 145 dma_addr_t sg_dma;
144 void *sg_cpu; 146 void *sg_cpu;