* [PATCH v4 1/1] mmc: dw_mmc: Add IDMAC 64-bit address mode support
@ 2013-08-21 9:33 Prabu Thangamuthu
2013-08-23 12:19 ` Jaehoon Chung
0 siblings, 1 reply; 3+ messages in thread
From: Prabu Thangamuthu @ 2013-08-21 9:33 UTC (permalink / raw)
To: Seungwon Jeon, 'Chris Ball', 'Jaehoon Chung',
'Wei WANG', 'Ludovic Desroches',
'Greg Kroah-Hartman', 'Arnd Bergmann'
Cc: 'Manjunath M Bettegowda', prabu.t, linux-mmc
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.
Tested the features in DW_MMC IP core v2.70a and v2.40a with HAPS-51 setup and driver is working fine.
Signed-off-by: Prabu Thangamuthu <prabu.t@synopsys.com>
---
Change log v4:
- Add the dynamic support for 32-bit and 64-bit address mode based on hw configuration.
- Removed the CONFIG_MMC_DW_IDMAC_64BIT_ADDRESS macro.
Change log v3:
-Add the condition check to find the IDMAC configuration mismatches between sw & hw.
-Driver should not use the IDMAC if any conflict between sw & hw configurations
since the register offsets are different for both 32-bit and 64-bit configurations.
-Reused the existing code.
Change log v2:
-Add the configuration.
drivers/mmc/host/dw_mmc.c | 195 +++++++++++++++++++++++++++++++++++---------
drivers/mmc/host/dw_mmc.h | 11 +++
include/linux/mmc/dw_mmc.h | 2 +
3 files changed, 169 insertions(+), 39 deletions(-)
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index ee5f167..523b3d7 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -55,7 +55,23 @@
SDMMC_IDMAC_INT_CES | SDMMC_IDMAC_INT_DU | \
SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \
SDMMC_IDMAC_INT_TI)
+struct idmac_desc_64addr {
+ u32 des0; /* Control Descriptor */
+
+ u32 des1; /* Reserved */
+
+ u32 des2; /*Buffer sizes */
+#define IDMAC_64ADDR_SET_BUFFER1_SIZE(d, s) \
+ ((d)->des2 = ((d)->des2 & 0x03ffe000) | ((s) & 0x1fff))
+
+ u32 des3; /* Reserved */
+
+ u32 des4; /* Lower 32-bits of Buffer Address Pointer 1*/
+ u32 des5; /* Upper 32-bits of Buffer Address Pointer 1*/
+ u32 des6; /* Lower 32-bits of Next Descriptor Address */
+ u32 des7; /* Upper 32-bits of Next Descriptor Address */
+};
struct idmac_desc {
u32 des0; /* Control Descriptor */
#define IDMAC_DES0_DIC BIT(1)
@@ -369,30 +385,67 @@ static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
unsigned int sg_len)
{
int i;
- struct idmac_desc *desc = host->sg_cpu;
- for (i = 0; i < sg_len; i++, desc++) {
- unsigned int length = sg_dma_len(&data->sg[i]);
- u32 mem_addr = sg_dma_address(&data->sg[i]);
+ if (host->dma_64bit_address == 1) {
+ struct idmac_desc_64addr *desc = host->sg_cpu;
+
+ for (i = 0; i < sg_len; i++, desc++) {
+ unsigned int length = sg_dma_len(&data->sg[i]);
+ u64 mem_addr = sg_dma_address(&data->sg[i]);
+
+ /*
+ * Set the OWN bit and disable interrupts for this
+ * descriptor
+ */
+ desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC |
+ IDMAC_DES0_CH;
+ /* Buffer length */
+ IDMAC_64ADDR_SET_BUFFER1_SIZE(desc, length);
+
+ /* Physical address to DMA to/from */
+ desc->des4 = mem_addr & 0xffffffff;
+ desc->des5 = mem_addr >> 32;
+ }
+
+ /* Set first descriptor */
+ desc = host->sg_cpu;
+ desc->des0 |= IDMAC_DES0_FD;
- /* Set the OWN bit and disable interrupts for this descriptor */
- desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | IDMAC_DES0_CH;
+ /* Set last descriptor */
+ desc = host->sg_cpu + (i - 1) *
+ sizeof(struct idmac_desc_64addr);
+ desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
+ desc->des0 |= IDMAC_DES0_LD;
- /* Buffer length */
- IDMAC_SET_BUFFER1_SIZE(desc, length);
+ } else {
+ struct idmac_desc *desc = host->sg_cpu;
- /* Physical address to DMA to/from */
- desc->des2 = mem_addr;
- }
+ for (i = 0; i < sg_len; i++, desc++) {
+ unsigned int length = sg_dma_len(&data->sg[i]);
+ u32 mem_addr = sg_dma_address(&data->sg[i]);
+
+ /*
+ * Set the OWN bit and disable interrupts for this
+ * descriptor
+ */
+ desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC |
+ IDMAC_DES0_CH;
+ /* Buffer length */
+ IDMAC_SET_BUFFER1_SIZE(desc, length);
+
+ /* Physical address to DMA to/from */
+ desc->des2 = mem_addr;
+ }
- /* Set first descriptor */
- desc = host->sg_cpu;
- desc->des0 |= IDMAC_DES0_FD;
+ /* Set first descriptor */
+ desc = host->sg_cpu;
+ desc->des0 |= IDMAC_DES0_FD;
- /* Set last descriptor */
- desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc);
- desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
- desc->des0 |= IDMAC_DES0_LD;
+ /* Set last descriptor */
+ desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc);
+ desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
+ desc->des0 |= IDMAC_DES0_LD;
+ }
wmb();
}
@@ -421,29 +474,66 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
static int dw_mci_idmac_init(struct dw_mci *host)
{
- struct idmac_desc *p;
int i;
+ if (host->dma_64bit_address == 1) {
+ struct idmac_desc_64addr *p;
+ /* Number of descriptors in the ring buffer */
+ host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc_64addr);
+
+ /* Forward link the descriptor list */
+ for (i = 0, p = host->sg_cpu; i < host->ring_size - 1;
+ i++, p++) {
+ p->des6 = (host->sg_dma +
+ (sizeof(struct idmac_desc_64addr) *
+ (i + 1))) & 0xffffffff;
+
+ p->des7 = (host->sg_dma +
+ (sizeof(struct idmac_desc_64addr) *
+ (i + 1))) >> 32;
+ }
- /* Number of descriptors in the ring buffer */
- host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
+ /* Set the last descriptor as the end-of-ring descriptor */
+ p->des6 = host->sg_dma & 0xffffffff;
+ p->des7 = host->sg_dma >> 32;
+ p->des0 = IDMAC_DES0_ER;
- /* Forward link the descriptor list */
- for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
- p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1));
+ } else {
+ struct idmac_desc *p;
+ /* Number of descriptors in the ring buffer */
+ host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
- /* Set the last descriptor as the end-of-ring descriptor */
- p->des3 = host->sg_dma;
- p->des0 = IDMAC_DES0_ER;
+ /* Forward link the descriptor list */
+ for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
+ p->des3 = host->sg_dma + (sizeof(struct idmac_desc) *
+ (i + 1));
+
+ /* Set the last descriptor as the end-of-ring descriptor */
+ p->des3 = host->sg_dma;
+ p->des0 = IDMAC_DES0_ER;
+ }
mci_writel(host, BMOD, SDMMC_IDMAC_SWRESET);
- /* Mask out interrupts - get Tx & Rx complete only */
- mci_writel(host, IDSTS, IDMAC_INT_CLR);
- mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI |
- SDMMC_IDMAC_INT_TI);
+ if (host->dma_64bit_address == 1) {
+ /* Mask out interrupts - get Tx & Rx complete only */
+ mci_writel(host, IDSTS64, IDMAC_INT_CLR);
+ mci_writel(host, IDINTEN64, SDMMC_IDMAC_INT_NI |
+ SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI);
+
+ /* Set the descriptor base address */
+ mci_writel(host, DBADDRL, host->sg_dma & 0xffffffff);
+ mci_writel(host, DBADDRU, host->sg_dma >> 32);
+
+ } else {
+ /* Mask out interrupts - get Tx & Rx complete only */
+ mci_writel(host, IDSTS, IDMAC_INT_CLR);
+ mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI |
+ SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI);
+
+ /* Set the descriptor base address */
+ mci_writel(host, DBADDR, host->sg_dma);
+ }
- /* Set the descriptor base address */
- mci_writel(host, DBADDR, host->sg_dma);
return 0;
}
@@ -1677,11 +1767,22 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
#ifdef CONFIG_MMC_DW_IDMAC
/* Handle DMA interrupts */
- pending = mci_readl(host, IDSTS);
- if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
- mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI);
- mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
- host->dma_ops->complete(host);
+ if (host->dma_64bit_address == 1) {
+ pending = mci_readl(host, IDSTS64);
+ if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
+ mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_TI |
+ SDMMC_IDMAC_INT_RI);
+ mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_NI);
+ host->dma_ops->complete(host);
+ }
+ } else {
+ pending = mci_readl(host, IDSTS);
+ if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
+ mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI |
+ SDMMC_IDMAC_INT_RI);
+ mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
+ host->dma_ops->complete(host);
+ }
}
#endif
@@ -2036,6 +2137,22 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
static void dw_mci_init_dma(struct dw_mci *host)
{
+ int addr_config;
+ /* Check ADDR_CONFIG bit in HCON to find IDMAC address bus width */
+ addr_config = (mci_readl(host, HCON) >> 27) & 0x01;
+
+ if (addr_config == 1) {
+ /* host supports IDMAC in 64-bit address mode */
+ host->dma_64bit_address = 1;
+ dev_info(host->dev, "IDMAC supports 64-bit address mode.\n");
+ if (!dma_set_mask(host->dev, DMA_BIT_MASK(64)))
+ dma_set_coherent_mask(host->dev, DMA_BIT_MASK(64));
+ } else {
+ /* host supports IDMAC in 32-bit address mode */
+ host->dma_64bit_address = 0;
+ dev_info(host->dev, "IDMAC supports 32-bit address mode.\n");
+ }
+
/* Alloc memory for sg translation */
host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE,
&host->sg_dma, GFP_KERNEL);
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 81b2994..7414656 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -54,6 +54,17 @@
#define SDMMC_DSCADDR 0x094
#define SDMMC_BUFADDR 0x098
#define SDMMC_DATA(x) (x)
+/*
+* Registers to support idmac 64-bit address mode
+*/
+#define SDMMC_DBADDRL 0x088
+#define SDMMC_DBADDRU 0x08c
+#define SDMMC_IDSTS64 0x090
+#define SDMMC_IDINTEN64 0x094
+#define SDMMC_DSCADDRL 0x098
+#define SDMMC_DSCADDRU 0x09c
+#define SDMMC_BUFADDRL 0x0A0
+#define SDMMC_BUFADDRU 0x0A4
/*
* Data offset is difference according to Version
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index 198f0fa..7460b04 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -51,6 +51,7 @@ struct mmc_data;
* transfer is in progress.
* @use_dma: Whether DMA channel is initialized or not.
* @using_dma: Whether DMA is in use for the current transfer.
+ * @dma_64bit_address: Whether DMA supports 64-bit address mode or not.
* @sg_dma: Bus address of DMA buffer.
* @sg_cpu: Virtual address of DMA buffer.
* @dma_ops: Pointer to platform-specific DMA callbacks.
@@ -134,6 +135,7 @@ struct dw_mci {
/* DMA interface members*/
int use_dma;
int using_dma;
+ int dma_64bit_address;
dma_addr_t sg_dma;
void *sg_cpu;
--
1.7.6.5
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH v4 1/1] mmc: dw_mmc: Add IDMAC 64-bit address mode support
2013-08-21 9:33 [PATCH v4 1/1] mmc: dw_mmc: Add IDMAC 64-bit address mode support Prabu Thangamuthu
@ 2013-08-23 12:19 ` Jaehoon Chung
2013-08-23 13:09 ` Prabu Thangamuthu
0 siblings, 1 reply; 3+ messages in thread
From: Jaehoon Chung @ 2013-08-23 12:19 UTC (permalink / raw)
To: Prabu Thangamuthu
Cc: Seungwon Jeon, 'Chris Ball', 'Wei WANG',
'Ludovic Desroches', 'Greg Kroah-Hartman',
'Arnd Bergmann', 'Manjunath M Bettegowda',
linux-mmc
Hi Prabu,
Do you have any performance result or other?
Best Regards,
Jaehoon Chung
On 08/21/2013 06:33 PM, Prabu Thangamuthu wrote:
> 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.
>
> Tested the features in DW_MMC IP core v2.70a and v2.40a with HAPS-51 setup and driver is working fine.
>
> Signed-off-by: Prabu Thangamuthu <prabu.t@synopsys.com>
> ---
> Change log v4:
> - Add the dynamic support for 32-bit and 64-bit address mode based on hw configuration.
> - Removed the CONFIG_MMC_DW_IDMAC_64BIT_ADDRESS macro.
>
> Change log v3:
> -Add the condition check to find the IDMAC configuration mismatches between sw & hw.
> -Driver should not use the IDMAC if any conflict between sw & hw configurations
> since the register offsets are different for both 32-bit and 64-bit configurations.
> -Reused the existing code.
>
> Change log v2:
> -Add the configuration.
>
> drivers/mmc/host/dw_mmc.c | 195 +++++++++++++++++++++++++++++++++++---------
> drivers/mmc/host/dw_mmc.h | 11 +++
> include/linux/mmc/dw_mmc.h | 2 +
> 3 files changed, 169 insertions(+), 39 deletions(-)
>
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index ee5f167..523b3d7 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -55,7 +55,23 @@
> SDMMC_IDMAC_INT_CES | SDMMC_IDMAC_INT_DU | \
> SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \
> SDMMC_IDMAC_INT_TI)
> +struct idmac_desc_64addr {
> + u32 des0; /* Control Descriptor */
> +
> + u32 des1; /* Reserved */
> +
> + u32 des2; /*Buffer sizes */
> +#define IDMAC_64ADDR_SET_BUFFER1_SIZE(d, s) \
> + ((d)->des2 = ((d)->des2 & 0x03ffe000) | ((s) & 0x1fff))
> +
> + u32 des3; /* Reserved */
> +
> + u32 des4; /* Lower 32-bits of Buffer Address Pointer 1*/
> + u32 des5; /* Upper 32-bits of Buffer Address Pointer 1*/
>
> + u32 des6; /* Lower 32-bits of Next Descriptor Address */
> + u32 des7; /* Upper 32-bits of Next Descriptor Address */
> +};
> struct idmac_desc {
> u32 des0; /* Control Descriptor */
> #define IDMAC_DES0_DIC BIT(1)
> @@ -369,30 +385,67 @@ static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
> unsigned int sg_len)
> {
> int i;
> - struct idmac_desc *desc = host->sg_cpu;
>
> - for (i = 0; i < sg_len; i++, desc++) {
> - unsigned int length = sg_dma_len(&data->sg[i]);
> - u32 mem_addr = sg_dma_address(&data->sg[i]);
> + if (host->dma_64bit_address == 1) {
> + struct idmac_desc_64addr *desc = host->sg_cpu;
> +
> + for (i = 0; i < sg_len; i++, desc++) {
> + unsigned int length = sg_dma_len(&data->sg[i]);
> + u64 mem_addr = sg_dma_address(&data->sg[i]);
> +
> + /*
> + * Set the OWN bit and disable interrupts for this
> + * descriptor
> + */
> + desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC |
> + IDMAC_DES0_CH;
> + /* Buffer length */
> + IDMAC_64ADDR_SET_BUFFER1_SIZE(desc, length);
> +
> + /* Physical address to DMA to/from */
> + desc->des4 = mem_addr & 0xffffffff;
> + desc->des5 = mem_addr >> 32;
> + }
> +
> + /* Set first descriptor */
> + desc = host->sg_cpu;
> + desc->des0 |= IDMAC_DES0_FD;
>
> - /* Set the OWN bit and disable interrupts for this descriptor */
> - desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | IDMAC_DES0_CH;
> + /* Set last descriptor */
> + desc = host->sg_cpu + (i - 1) *
> + sizeof(struct idmac_desc_64addr);
> + desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
> + desc->des0 |= IDMAC_DES0_LD;
>
> - /* Buffer length */
> - IDMAC_SET_BUFFER1_SIZE(desc, length);
> + } else {
> + struct idmac_desc *desc = host->sg_cpu;
>
> - /* Physical address to DMA to/from */
> - desc->des2 = mem_addr;
> - }
> + for (i = 0; i < sg_len; i++, desc++) {
> + unsigned int length = sg_dma_len(&data->sg[i]);
> + u32 mem_addr = sg_dma_address(&data->sg[i]);
> +
> + /*
> + * Set the OWN bit and disable interrupts for this
> + * descriptor
> + */
> + desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC |
> + IDMAC_DES0_CH;
> + /* Buffer length */
> + IDMAC_SET_BUFFER1_SIZE(desc, length);
> +
> + /* Physical address to DMA to/from */
> + desc->des2 = mem_addr;
> + }
>
> - /* Set first descriptor */
> - desc = host->sg_cpu;
> - desc->des0 |= IDMAC_DES0_FD;
> + /* Set first descriptor */
> + desc = host->sg_cpu;
> + desc->des0 |= IDMAC_DES0_FD;
>
> - /* Set last descriptor */
> - desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc);
> - desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
> - desc->des0 |= IDMAC_DES0_LD;
> + /* Set last descriptor */
> + desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc);
> + desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
> + desc->des0 |= IDMAC_DES0_LD;
> + }
>
> wmb();
> }
> @@ -421,29 +474,66 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
>
> static int dw_mci_idmac_init(struct dw_mci *host)
> {
> - struct idmac_desc *p;
> int i;
> + if (host->dma_64bit_address == 1) {
> + struct idmac_desc_64addr *p;
> + /* Number of descriptors in the ring buffer */
> + host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc_64addr);
> +
> + /* Forward link the descriptor list */
> + for (i = 0, p = host->sg_cpu; i < host->ring_size - 1;
> + i++, p++) {
> + p->des6 = (host->sg_dma +
> + (sizeof(struct idmac_desc_64addr) *
> + (i + 1))) & 0xffffffff;
> +
> + p->des7 = (host->sg_dma +
> + (sizeof(struct idmac_desc_64addr) *
> + (i + 1))) >> 32;
> + }
>
> - /* Number of descriptors in the ring buffer */
> - host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
> + /* Set the last descriptor as the end-of-ring descriptor */
> + p->des6 = host->sg_dma & 0xffffffff;
> + p->des7 = host->sg_dma >> 32;
> + p->des0 = IDMAC_DES0_ER;
>
> - /* Forward link the descriptor list */
> - for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
> - p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1));
> + } else {
> + struct idmac_desc *p;
> + /* Number of descriptors in the ring buffer */
> + host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
>
> - /* Set the last descriptor as the end-of-ring descriptor */
> - p->des3 = host->sg_dma;
> - p->des0 = IDMAC_DES0_ER;
> + /* Forward link the descriptor list */
> + for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
> + p->des3 = host->sg_dma + (sizeof(struct idmac_desc) *
> + (i + 1));
> +
> + /* Set the last descriptor as the end-of-ring descriptor */
> + p->des3 = host->sg_dma;
> + p->des0 = IDMAC_DES0_ER;
> + }
>
> mci_writel(host, BMOD, SDMMC_IDMAC_SWRESET);
>
> - /* Mask out interrupts - get Tx & Rx complete only */
> - mci_writel(host, IDSTS, IDMAC_INT_CLR);
> - mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI |
> - SDMMC_IDMAC_INT_TI);
> + if (host->dma_64bit_address == 1) {
> + /* Mask out interrupts - get Tx & Rx complete only */
> + mci_writel(host, IDSTS64, IDMAC_INT_CLR);
> + mci_writel(host, IDINTEN64, SDMMC_IDMAC_INT_NI |
> + SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI);
> +
> + /* Set the descriptor base address */
> + mci_writel(host, DBADDRL, host->sg_dma & 0xffffffff);
> + mci_writel(host, DBADDRU, host->sg_dma >> 32);
> +
> + } else {
> + /* Mask out interrupts - get Tx & Rx complete only */
> + mci_writel(host, IDSTS, IDMAC_INT_CLR);
> + mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI |
> + SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI);
> +
> + /* Set the descriptor base address */
> + mci_writel(host, DBADDR, host->sg_dma);
> + }
>
> - /* Set the descriptor base address */
> - mci_writel(host, DBADDR, host->sg_dma);
> return 0;
> }
>
> @@ -1677,11 +1767,22 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
>
> #ifdef CONFIG_MMC_DW_IDMAC
> /* Handle DMA interrupts */
> - pending = mci_readl(host, IDSTS);
> - if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
> - mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI);
> - mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
> - host->dma_ops->complete(host);
> + if (host->dma_64bit_address == 1) {
> + pending = mci_readl(host, IDSTS64);
> + if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
> + mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_TI |
> + SDMMC_IDMAC_INT_RI);
> + mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_NI);
> + host->dma_ops->complete(host);
> + }
> + } else {
> + pending = mci_readl(host, IDSTS);
> + if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
> + mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI |
> + SDMMC_IDMAC_INT_RI);
> + mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
> + host->dma_ops->complete(host);
> + }
> }
> #endif
>
> @@ -2036,6 +2137,22 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
>
> static void dw_mci_init_dma(struct dw_mci *host)
> {
> + int addr_config;
> + /* Check ADDR_CONFIG bit in HCON to find IDMAC address bus width */
> + addr_config = (mci_readl(host, HCON) >> 27) & 0x01;
> +
> + if (addr_config == 1) {
> + /* host supports IDMAC in 64-bit address mode */
> + host->dma_64bit_address = 1;
> + dev_info(host->dev, "IDMAC supports 64-bit address mode.\n");
> + if (!dma_set_mask(host->dev, DMA_BIT_MASK(64)))
> + dma_set_coherent_mask(host->dev, DMA_BIT_MASK(64));
> + } else {
> + /* host supports IDMAC in 32-bit address mode */
> + host->dma_64bit_address = 0;
> + dev_info(host->dev, "IDMAC supports 32-bit address mode.\n");
> + }
> +
> /* Alloc memory for sg translation */
> host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE,
> &host->sg_dma, GFP_KERNEL);
> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
> index 81b2994..7414656 100644
> --- a/drivers/mmc/host/dw_mmc.h
> +++ b/drivers/mmc/host/dw_mmc.h
> @@ -54,6 +54,17 @@
> #define SDMMC_DSCADDR 0x094
> #define SDMMC_BUFADDR 0x098
> #define SDMMC_DATA(x) (x)
> +/*
> +* Registers to support idmac 64-bit address mode
> +*/
> +#define SDMMC_DBADDRL 0x088
> +#define SDMMC_DBADDRU 0x08c
> +#define SDMMC_IDSTS64 0x090
> +#define SDMMC_IDINTEN64 0x094
> +#define SDMMC_DSCADDRL 0x098
> +#define SDMMC_DSCADDRU 0x09c
> +#define SDMMC_BUFADDRL 0x0A0
> +#define SDMMC_BUFADDRU 0x0A4
>
> /*
> * Data offset is difference according to Version
> diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
> index 198f0fa..7460b04 100644
> --- a/include/linux/mmc/dw_mmc.h
> +++ b/include/linux/mmc/dw_mmc.h
> @@ -51,6 +51,7 @@ struct mmc_data;
> * transfer is in progress.
> * @use_dma: Whether DMA channel is initialized or not.
> * @using_dma: Whether DMA is in use for the current transfer.
> + * @dma_64bit_address: Whether DMA supports 64-bit address mode or not.
> * @sg_dma: Bus address of DMA buffer.
> * @sg_cpu: Virtual address of DMA buffer.
> * @dma_ops: Pointer to platform-specific DMA callbacks.
> @@ -134,6 +135,7 @@ struct dw_mci {
> /* DMA interface members*/
> int use_dma;
> int using_dma;
> + int dma_64bit_address;
>
> dma_addr_t sg_dma;
> void *sg_cpu;
>
^ permalink raw reply [flat|nested] 3+ messages in thread
* RE: [PATCH v4 1/1] mmc: dw_mmc: Add IDMAC 64-bit address mode support
2013-08-23 12:19 ` Jaehoon Chung
@ 2013-08-23 13:09 ` Prabu Thangamuthu
0 siblings, 0 replies; 3+ messages in thread
From: Prabu Thangamuthu @ 2013-08-23 13:09 UTC (permalink / raw)
To: Jaehoon Chung
Cc: Seungwon Jeon, 'Chris Ball', 'Wei WANG',
'Ludovic Desroches', 'Greg Kroah-Hartman',
'Arnd Bergmann', 'Manjunath M Bettegowda',
linux-mmc
Hi Jaehoon Chung,
We have tested the data read/write in different SD and MMC cards and verified the data integrity check (md5sum) for both read and write.
We have not tried the performance test.
Thanks & regards,
Prabu Thangamuthu.
On 08/23/2013 06:33 PM, Jaehoon Chung wrote:
> Hi Prabu,
>
> Do you have any performance result or other?
>
> Best Regards,
> Jaehoon Chung
>
> On 08/21/2013 06:33 PM, Prabu Thangamuthu wrote:
> > 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.
> >
> > Tested the features in DW_MMC IP core v2.70a and v2.40a with HAPS-51
> setup and driver is working fine.
> >
> > Signed-off-by: Prabu Thangamuthu <prabu.t@synopsys.com>
> > ---
> > Change log v4:
> > - Add the dynamic support for 32-bit and 64-bit address mode based on
> hw configuration.
> > - Removed the CONFIG_MMC_DW_IDMAC_64BIT_ADDRESS macro.
> >
> > Change log v3:
> > -Add the condition check to find the IDMAC configuration mismatches
> between sw & hw.
> > -Driver should not use the IDMAC if any conflict between sw & hw
> configurations
> > since the register offsets are different for both 32-bit and 64-bit
> configurations.
> > -Reused the existing code.
> >
> > Change log v2:
> > -Add the configuration.
> >
> > drivers/mmc/host/dw_mmc.c | 195
> +++++++++++++++++++++++++++++++++++---------
> > drivers/mmc/host/dw_mmc.h | 11 +++
> > include/linux/mmc/dw_mmc.h | 2 +
> > 3 files changed, 169 insertions(+), 39 deletions(-)
> >
> > diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> > index ee5f167..523b3d7 100644
> > --- a/drivers/mmc/host/dw_mmc.c
> > +++ b/drivers/mmc/host/dw_mmc.c
> > @@ -55,7 +55,23 @@
> > SDMMC_IDMAC_INT_CES |
> SDMMC_IDMAC_INT_DU | \
> > SDMMC_IDMAC_INT_FBE |
> SDMMC_IDMAC_INT_RI | \
> > SDMMC_IDMAC_INT_TI)
> > +struct idmac_desc_64addr {
> > + u32 des0; /* Control Descriptor */
> > +
> > + u32 des1; /* Reserved */
> > +
> > + u32 des2; /*Buffer sizes */
> > +#define IDMAC_64ADDR_SET_BUFFER1_SIZE(d, s) \
> > + ((d)->des2 = ((d)->des2 & 0x03ffe000) | ((s) & 0x1fff))
> > +
> > + u32 des3; /* Reserved */
> > +
> > + u32 des4; /* Lower 32-bits of Buffer Address Pointer 1*/
> > + u32 des5; /* Upper 32-bits of Buffer Address Pointer 1*/
> >
> > + u32 des6; /* Lower 32-bits of Next Descriptor Address */
> > + u32 des7; /* Upper 32-bits of Next Descriptor Address */
> > +};
> > struct idmac_desc {
> > u32 des0; /* Control Descriptor */
> > #define IDMAC_DES0_DIC BIT(1)
> > @@ -369,30 +385,67 @@ static void dw_mci_translate_sglist(struct dw_mci
> *host, struct mmc_data *data,
> > unsigned int sg_len)
> > {
> > int i;
> > - struct idmac_desc *desc = host->sg_cpu;
> >
> > - for (i = 0; i < sg_len; i++, desc++) {
> > - unsigned int length = sg_dma_len(&data->sg[i]);
> > - u32 mem_addr = sg_dma_address(&data->sg[i]);
> > + if (host->dma_64bit_address == 1) {
> > + struct idmac_desc_64addr *desc = host->sg_cpu;
> > +
> > + for (i = 0; i < sg_len; i++, desc++) {
> > + unsigned int length = sg_dma_len(&data->sg[i]);
> > + u64 mem_addr = sg_dma_address(&data->sg[i]);
> > +
> > + /*
> > + * Set the OWN bit and disable interrupts for this
> > + * descriptor
> > + */
> > + desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC
> |
> > + IDMAC_DES0_CH;
> > + /* Buffer length */
> > + IDMAC_64ADDR_SET_BUFFER1_SIZE(desc, length);
> > +
> > + /* Physical address to DMA to/from */
> > + desc->des4 = mem_addr & 0xffffffff;
> > + desc->des5 = mem_addr >> 32;
> > + }
> > +
> > + /* Set first descriptor */
> > + desc = host->sg_cpu;
> > + desc->des0 |= IDMAC_DES0_FD;
> >
> > - /* Set the OWN bit and disable interrupts for this descriptor */
> > - desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC |
> IDMAC_DES0_CH;
> > + /* Set last descriptor */
> > + desc = host->sg_cpu + (i - 1) *
> > + sizeof(struct idmac_desc_64addr);
> > + desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
> > + desc->des0 |= IDMAC_DES0_LD;
> >
> > - /* Buffer length */
> > - IDMAC_SET_BUFFER1_SIZE(desc, length);
> > + } else {
> > + struct idmac_desc *desc = host->sg_cpu;
> >
> > - /* Physical address to DMA to/from */
> > - desc->des2 = mem_addr;
> > - }
> > + for (i = 0; i < sg_len; i++, desc++) {
> > + unsigned int length = sg_dma_len(&data->sg[i]);
> > + u32 mem_addr = sg_dma_address(&data->sg[i]);
> > +
> > + /*
> > + * Set the OWN bit and disable interrupts for this
> > + * descriptor
> > + */
> > + desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC
> |
> > + IDMAC_DES0_CH;
> > + /* Buffer length */
> > + IDMAC_SET_BUFFER1_SIZE(desc, length);
> > +
> > + /* Physical address to DMA to/from */
> > + desc->des2 = mem_addr;
> > + }
> >
> > - /* Set first descriptor */
> > - desc = host->sg_cpu;
> > - desc->des0 |= IDMAC_DES0_FD;
> > + /* Set first descriptor */
> > + desc = host->sg_cpu;
> > + desc->des0 |= IDMAC_DES0_FD;
> >
> > - /* Set last descriptor */
> > - desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc);
> > - desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
> > - desc->des0 |= IDMAC_DES0_LD;
> > + /* Set last descriptor */
> > + desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc);
> > + desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
> > + desc->des0 |= IDMAC_DES0_LD;
> > + }
> >
> > wmb();
> > }
> > @@ -421,29 +474,66 @@ static void dw_mci_idmac_start_dma(struct
> dw_mci
> > *host, unsigned int sg_len)
> >
> > static int dw_mci_idmac_init(struct dw_mci *host) {
> > - struct idmac_desc *p;
> > int i;
> > + if (host->dma_64bit_address == 1) {
> > + struct idmac_desc_64addr *p;
> > + /* Number of descriptors in the ring buffer */
> > + host->ring_size = PAGE_SIZE / sizeof(struct
> idmac_desc_64addr);
> > +
> > + /* Forward link the descriptor list */
> > + for (i = 0, p = host->sg_cpu; i < host->ring_size - 1;
> > + i++, p++) {
> > + p->des6 = (host->sg_dma +
> > + (sizeof(struct idmac_desc_64addr) *
> > + (i + 1))) & 0xffffffff;
> > +
> > + p->des7 = (host->sg_dma +
> > + (sizeof(struct idmac_desc_64addr) *
> > + (i + 1))) >> 32;
> > + }
> >
> > - /* Number of descriptors in the ring buffer */
> > - host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
> > + /* Set the last descriptor as the end-of-ring descriptor */
> > + p->des6 = host->sg_dma & 0xffffffff;
> > + p->des7 = host->sg_dma >> 32;
> > + p->des0 = IDMAC_DES0_ER;
> >
> > - /* Forward link the descriptor list */
> > - for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
> > - p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1));
> > + } else {
> > + struct idmac_desc *p;
> > + /* Number of descriptors in the ring buffer */
> > + host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
> >
> > - /* Set the last descriptor as the end-of-ring descriptor */
> > - p->des3 = host->sg_dma;
> > - p->des0 = IDMAC_DES0_ER;
> > + /* Forward link the descriptor list */
> > + for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
> > + p->des3 = host->sg_dma + (sizeof(struct idmac_desc) *
> > + (i + 1));
> > +
> > + /* Set the last descriptor as the end-of-ring descriptor */
> > + p->des3 = host->sg_dma;
> > + p->des0 = IDMAC_DES0_ER;
> > + }
> >
> > mci_writel(host, BMOD, SDMMC_IDMAC_SWRESET);
> >
> > - /* Mask out interrupts - get Tx & Rx complete only */
> > - mci_writel(host, IDSTS, IDMAC_INT_CLR);
> > - mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI |
> SDMMC_IDMAC_INT_RI |
> > - SDMMC_IDMAC_INT_TI);
> > + if (host->dma_64bit_address == 1) {
> > + /* Mask out interrupts - get Tx & Rx complete only */
> > + mci_writel(host, IDSTS64, IDMAC_INT_CLR);
> > + mci_writel(host, IDINTEN64, SDMMC_IDMAC_INT_NI |
> > + SDMMC_IDMAC_INT_RI |
> SDMMC_IDMAC_INT_TI);
> > +
> > + /* Set the descriptor base address */
> > + mci_writel(host, DBADDRL, host->sg_dma & 0xffffffff);
> > + mci_writel(host, DBADDRU, host->sg_dma >> 32);
> > +
> > + } else {
> > + /* Mask out interrupts - get Tx & Rx complete only */
> > + mci_writel(host, IDSTS, IDMAC_INT_CLR);
> > + mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI |
> > + SDMMC_IDMAC_INT_RI |
> SDMMC_IDMAC_INT_TI);
> > +
> > + /* Set the descriptor base address */
> > + mci_writel(host, DBADDR, host->sg_dma);
> > + }
> >
> > - /* Set the descriptor base address */
> > - mci_writel(host, DBADDR, host->sg_dma);
> > return 0;
> > }
> >
> > @@ -1677,11 +1767,22 @@ static irqreturn_t dw_mci_interrupt(int irq,
> > void *dev_id)
> >
> > #ifdef CONFIG_MMC_DW_IDMAC
> > /* Handle DMA interrupts */
> > - pending = mci_readl(host, IDSTS);
> > - if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
> > - mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI |
> SDMMC_IDMAC_INT_RI);
> > - mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
> > - host->dma_ops->complete(host);
> > + if (host->dma_64bit_address == 1) {
> > + pending = mci_readl(host, IDSTS64);
> > + if (pending & (SDMMC_IDMAC_INT_TI |
> SDMMC_IDMAC_INT_RI)) {
> > + mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_TI |
> > +
> SDMMC_IDMAC_INT_RI);
> > + mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_NI);
> > + host->dma_ops->complete(host);
> > + }
> > + } else {
> > + pending = mci_readl(host, IDSTS);
> > + if (pending & (SDMMC_IDMAC_INT_TI |
> SDMMC_IDMAC_INT_RI)) {
> > + mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI |
> > +
> SDMMC_IDMAC_INT_RI);
> > + mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
> > + host->dma_ops->complete(host);
> > + }
> > }
> > #endif
> >
> > @@ -2036,6 +2137,22 @@ static void dw_mci_cleanup_slot(struct
> > dw_mci_slot *slot, unsigned int id)
> >
> > static void dw_mci_init_dma(struct dw_mci *host) {
> > + int addr_config;
> > + /* Check ADDR_CONFIG bit in HCON to find IDMAC address bus width
> */
> > + addr_config = (mci_readl(host, HCON) >> 27) & 0x01;
> > +
> > + if (addr_config == 1) {
> > + /* host supports IDMAC in 64-bit address mode */
> > + host->dma_64bit_address = 1;
> > + dev_info(host->dev, "IDMAC supports 64-bit address mode.\n");
> > + if (!dma_set_mask(host->dev, DMA_BIT_MASK(64)))
> > + dma_set_coherent_mask(host->dev,
> DMA_BIT_MASK(64));
> > + } else {
> > + /* host supports IDMAC in 32-bit address mode */
> > + host->dma_64bit_address = 0;
> > + dev_info(host->dev, "IDMAC supports 32-bit address mode.\n");
> > + }
> > +
> > /* Alloc memory for sg translation */
> > host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE,
> > &host->sg_dma, GFP_KERNEL);
> > diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
> > index 81b2994..7414656 100644
> > --- a/drivers/mmc/host/dw_mmc.h
> > +++ b/drivers/mmc/host/dw_mmc.h
> > @@ -54,6 +54,17 @@
> > #define SDMMC_DSCADDR 0x094
> > #define SDMMC_BUFADDR 0x098
> > #define SDMMC_DATA(x) (x)
> > +/*
> > +* Registers to support idmac 64-bit address mode */
> > +#define SDMMC_DBADDRL 0x088
> > +#define SDMMC_DBADDRU 0x08c
> > +#define SDMMC_IDSTS64 0x090
> > +#define SDMMC_IDINTEN64 0x094
> > +#define SDMMC_DSCADDRL 0x098
> > +#define SDMMC_DSCADDRU 0x09c
> > +#define SDMMC_BUFADDRL 0x0A0
> > +#define SDMMC_BUFADDRU 0x0A4
> >
> > /*
> > * Data offset is difference according to Version diff --git
> > a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h index
> > 198f0fa..7460b04 100644
> > --- a/include/linux/mmc/dw_mmc.h
> > +++ b/include/linux/mmc/dw_mmc.h
> > @@ -51,6 +51,7 @@ struct mmc_data;
> > * transfer is in progress.
> > * @use_dma: Whether DMA channel is initialized or not.
> > * @using_dma: Whether DMA is in use for the current transfer.
> > + * @dma_64bit_address: Whether DMA supports 64-bit address mode or
> not.
> > * @sg_dma: Bus address of DMA buffer.
> > * @sg_cpu: Virtual address of DMA buffer.
> > * @dma_ops: Pointer to platform-specific DMA callbacks.
> > @@ -134,6 +135,7 @@ struct dw_mci {
> > /* DMA interface members*/
> > int use_dma;
> > int using_dma;
> > + int dma_64bit_address;
> >
> > dma_addr_t sg_dma;
> > void *sg_cpu;
> >
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2013-08-23 13:09 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-08-21 9:33 [PATCH v4 1/1] mmc: dw_mmc: Add IDMAC 64-bit address mode support Prabu Thangamuthu
2013-08-23 12:19 ` Jaehoon Chung
2013-08-23 13:09 ` Prabu Thangamuthu
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.