diff options
| author | Prabu Thangamuthu <Prabu.T@synopsys.com> | 2014-10-20 03:12:33 -0400 |
|---|---|---|
| committer | Ulf Hansson <ulf.hansson@linaro.org> | 2014-11-26 08:30:50 -0500 |
| commit | 69d99fdcfd7815dfb2318f0777a46181d5bf42dc (patch) | |
| tree | 1e9c2cf01589da8fe2593c176d91fa7760a078ce | |
| parent | e765bfa22a8f06f0964a97e3e81148511d75140a (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.c | 199 | ||||
| -rw-r--r-- | drivers/mmc/host/dw_mmc.h | 11 | ||||
| -rw-r--r-- | include/linux/mmc/dw_mmc.h | 2 |
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 | ||
| 64 | struct 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 | |||
| 64 | struct idmac_desc { | 82 | struct 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 | ||
| 471 | static int dw_mci_idmac_init(struct dw_mci *host) | 525 | static 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 | ||
| 2246 | static void dw_mci_init_dma(struct dw_mci *host) | 2353 | static 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; |
