diff mbox

[v2,1/1] mmc: dw_mmc: Add IDMAC 64-bit address mode support

Message ID 705D14B1C7978B40A723277C067CEDE2CD76FE@IN01WEMBXB.internal.synopsys.com (mailing list archive)
State New, archived
Headers show

Commit Message

Prabu Thangamuthu Aug. 13, 2013, 1:23 p.m. UTC
Synopsys DW_MMC IP core supports Internal DMA Controller
with 64-bit address mode from IP version 2.70a onwards.
For 64-bit address mode, IP has new registers and different offset
for some of the registers which were used in 32-bit address mode.
Added driver modifications under the macro CONFIG_MMC_DW_IDMAC_64BIT_ADDRESS
to support IDMAC 64-bit address mode.

Tested the features in DW_MMC IP core v2.70a with HAPS-51 setup and driver is working fine.

Signed-off-by: Prabu Thangamuthu <prabu.t@synopsys.com>
---
Change log v2:
	-Add the configuration.

 drivers/mmc/host/Kconfig  |    9 ++++
 drivers/mmc/host/dw_mmc.c |  106 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/mmc/host/dw_mmc.h |   11 +++++
 3 files changed, 126 insertions(+), 0 deletions(-)

Comments

Jaehoon Chung Aug. 14, 2013, 4:20 a.m. UTC | #1
Hi Prabu,

If IP version is the lower than 2.70a, 64bit address mode didn't support.
How do you control on this case?
(If CONFIG_MMC_DW_IDMAC_64BIT_ADDRESS is enabled and dw-mmc ip version is lower than 2.70a..)

And I think that some code should reuse the existing code..

Best Regards,
Jaehoon Chung

On 08/13/2013 10:23 PM, Prabu Thangamuthu wrote:
> Synopsys DW_MMC IP core supports Internal DMA Controller
> with 64-bit address mode from IP version 2.70a onwards.
> For 64-bit address mode, IP has new registers and different offset
> for some of the registers which were used in 32-bit address mode.
> Added driver modifications under the macro CONFIG_MMC_DW_IDMAC_64BIT_ADDRESS
> to support IDMAC 64-bit address mode.
> 
> Tested the features in DW_MMC IP core v2.70a with HAPS-51 setup and driver is working fine.
> 
> Signed-off-by: Prabu Thangamuthu <prabu.t@synopsys.com>
> ---
> Change log v2:
> 	-Add the configuration.
> 
>  drivers/mmc/host/Kconfig  |    9 ++++
>  drivers/mmc/host/dw_mmc.c |  106 +++++++++++++++++++++++++++++++++++++++++++++
>  drivers/mmc/host/dw_mmc.h |   11 +++++
>  3 files changed, 126 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> index 8a4c066..a5ef53f 100644
> --- a/drivers/mmc/host/Kconfig
> +++ b/drivers/mmc/host/Kconfig
> @@ -544,6 +544,15 @@ config MMC_DW_IDMAC
>  	  Designware Mobile Storage IP block. This disables the external DMA
>  	  interface.
>  
> +config MMC_DW_IDMAC_64BIT_ADDRESS
> +	bool "Internal DMAC with 64-bit address support"
> +	depends on MMC_DW_IDMAC
> +	help
> +	  This selects support for the internal DMA controller with 64-bit
> +	  address mode driver. This should be enabled only if the IP
> +	  supports internal DMA controller block with 64-bit addressing
> +	  mode.
> +
>  config MMC_DW_PLTFM
>  	tristate "Synopsys Designware MCI Support as platform device"
>  	depends on MMC_DW
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index ee5f167..de60f61 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -55,7 +55,31 @@
>  				 SDMMC_IDMAC_INT_CES | SDMMC_IDMAC_INT_DU | \
>  				 SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \
>  				 SDMMC_IDMAC_INT_TI)
> +#ifdef CONFIG_MMC_DW_IDMAC_64BIT_ADDRESS
> +struct idmac_desc64 {
> +	u32		des0;	/* Control Descriptor */
> +#define IDMAC_DES0_DIC	BIT(1)
> +#define IDMAC_DES0_LD	BIT(2)
> +#define IDMAC_DES0_FD	BIT(3)
> +#define IDMAC_DES0_CH	BIT(4)
> +#define IDMAC_DES0_ER	BIT(5)
> +#define IDMAC_DES0_CES	BIT(30)
> +#define IDMAC_DES0_OWN	BIT(31)
> +
> +	u32		des1;	/* Reserved */
>  
> +	u32		des2;	/* Buffer sizes */
> +#define IDMAC_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 */
> +};
> +#else
>  struct idmac_desc {
>  	u32		des0;	/* Control Descriptor */
>  #define IDMAC_DES0_DIC	BIT(1)
> @@ -74,6 +98,7 @@ struct idmac_desc {
>  
>  	u32		des3;	/* buffer 2 physical address */
>  };
> +#endif /* CONFIG_MMC_DW_IDMAC_64BIT_ADDRESS */
>  #endif /* CONFIG_MMC_DW_IDMAC */
>  
>  /**
> @@ -365,6 +390,40 @@ static void dw_mci_idmac_complete_dma(struct dw_mci *host)
>  	}
>  }
>  
> +#ifdef CONFIG_MMC_DW_IDMAC_64BIT_ADDRESS
> +static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
> +				    unsigned int sg_len)
> +{
> +	int i;
> +	struct idmac_desc64 *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_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 last descriptor */
> +	desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc64);
> +	desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
> +	desc->des0 |= IDMAC_DES0_LD;
> +
> +	wmb();
> +}
> +#else
>  static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
>  				    unsigned int sg_len)
>  {
> @@ -396,6 +455,7 @@ static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
>  
>  	wmb();
>  }
> +#endif /* CONFIG_MMC_DW_IDMAC_64BIT_ADDRESS */
>  
>  static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
>  {
> @@ -419,6 +479,40 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
>  	mci_writel(host, PLDMND, 1);
>  }
>  
> +#ifdef CONFIG_MMC_DW_IDMAC_64BIT_ADDRESS
> +static int dw_mci_idmac_init(struct dw_mci *host)
> +{
> +	struct idmac_desc64 *p;
> +	int i;
> +
> +	/* Number of descriptors in the ring buffer */
> +	host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc64);
> +
> +	/* 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_desc64) *
> +						(i + 1))) & 0xffffffff;
> +		p->des7 = (host->sg_dma + (sizeof(struct idmac_desc64) *
> +						(i + 1))) >> 32;
> +	}
> +
> +	/* 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;
> +
> +	mci_writel(host, BMOD, SDMMC_IDMAC_SWRESET);
> +
> +	/* Mask out interrupts - get Tx & Rx complete only */
> +	mci_writel(host, IDINTEN, 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);
> +	return 0;
> +}
> +#else
>  static int dw_mci_idmac_init(struct dw_mci *host)
>  {
>  	struct idmac_desc *p;
> @@ -446,6 +540,7 @@ static int dw_mci_idmac_init(struct dw_mci *host)
>  	mci_writel(host, DBADDR, host->sg_dma);
>  	return 0;
>  }
> +#endif /* CONFIG_MMC_DW_IDMAC_64BIT_ADDRESS */
>  
>  static const struct dw_mci_dma_ops dw_mci_idmac_ops = {
>  	.init = dw_mci_idmac_init,
> @@ -2036,6 +2131,17 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
>  
>  static void dw_mci_init_dma(struct dw_mci *host)
>  {
> +	u32 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) {
> +		dev_info(host->dev, "IDMAC with 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
> +			goto no_dma;
> +	}
> +
>  	/* 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..a3a5e9c 100644
> --- a/drivers/mmc/host/dw_mmc.h
> +++ b/drivers/mmc/host/dw_mmc.h
> @@ -48,11 +48,22 @@
>  #define SDMMC_UHS_REG		0x074
>  #define SDMMC_BMOD		0x080
>  #define SDMMC_PLDMND		0x084
> +#ifdef CONFIG_MMC_DW_IDMAC_64BIT_ADDRESS
> +#define SDMMC_DBADDRL		0x088
> +#define SDMMC_DBADDRU		0x08c
> +#define SDMMC_IDSTS		0x090
> +#define SDMMC_IDINTEN		0x094
> +#define SDMMC_DSCADDRL		0x098
> +#define SDMMC_DSCADDRU		0x09c
> +#define SDMMC_BUFADDRL		0x0A0
> +#define SDMMC_BUFADDRU		0x0A4
> +#else
>  #define SDMMC_DBADDR		0x088
>  #define SDMMC_IDSTS		0x08c
>  #define SDMMC_IDINTEN		0x090
>  #define SDMMC_DSCADDR		0x094
>  #define SDMMC_BUFADDR		0x098
> +#endif
>  #define SDMMC_DATA(x)		(x)
>  
>  /*
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Prabu Thangamuthu Aug. 14, 2013, 10:14 a.m. UTC | #2
Hi Jaehoon Chung,

>On 08/14/2013 09:51 AM, Jaehoon Chung wrote:
> Hi Prabu,
> 
> If IP version is the lower than 2.70a, 64bit address mode didn't support.
> How do you control on this case?
> (If CONFIG_MMC_DW_IDMAC_64BIT_ADDRESS is enabled and dw-mmc ip
> version is lower than 2.70a..)
It's a valid test case, thanks for reporting it.
I missed this condition check in my patch. Let me update it.

As per dw_mmc IP data book, the register offsets are different for both 32-bit and 64-bit configurations.
We can't use the driver in 32-bit address mode IDMAC if the driver was compiled with the CONFIG_MMC_DW_IDMAC_64BIT_ADDRESS since it will have the register offset corresponds to 64-bit configuration. 
So, If there is any mismatch between software and hardware configurations, then we should not use the internal DMA. I will add this condition check and send it. 

> And I think that some code should reuse the existing code..
Let me try to reuse the existing code as much as possible and create a new patch.

Thanks & regards,
Prabu Thangamuthu.
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 8a4c066..a5ef53f 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -544,6 +544,15 @@  config MMC_DW_IDMAC
 	  Designware Mobile Storage IP block. This disables the external DMA
 	  interface.
 
+config MMC_DW_IDMAC_64BIT_ADDRESS
+	bool "Internal DMAC with 64-bit address support"
+	depends on MMC_DW_IDMAC
+	help
+	  This selects support for the internal DMA controller with 64-bit
+	  address mode driver. This should be enabled only if the IP
+	  supports internal DMA controller block with 64-bit addressing
+	  mode.
+
 config MMC_DW_PLTFM
 	tristate "Synopsys Designware MCI Support as platform device"
 	depends on MMC_DW
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index ee5f167..de60f61 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -55,7 +55,31 @@ 
 				 SDMMC_IDMAC_INT_CES | SDMMC_IDMAC_INT_DU | \
 				 SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \
 				 SDMMC_IDMAC_INT_TI)
+#ifdef CONFIG_MMC_DW_IDMAC_64BIT_ADDRESS
+struct idmac_desc64 {
+	u32		des0;	/* Control Descriptor */
+#define IDMAC_DES0_DIC	BIT(1)
+#define IDMAC_DES0_LD	BIT(2)
+#define IDMAC_DES0_FD	BIT(3)
+#define IDMAC_DES0_CH	BIT(4)
+#define IDMAC_DES0_ER	BIT(5)
+#define IDMAC_DES0_CES	BIT(30)
+#define IDMAC_DES0_OWN	BIT(31)
+
+	u32		des1;	/* Reserved */
 
+	u32		des2;	/* Buffer sizes */
+#define IDMAC_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 */
+};
+#else
 struct idmac_desc {
 	u32		des0;	/* Control Descriptor */
 #define IDMAC_DES0_DIC	BIT(1)
@@ -74,6 +98,7 @@  struct idmac_desc {
 
 	u32		des3;	/* buffer 2 physical address */
 };
+#endif /* CONFIG_MMC_DW_IDMAC_64BIT_ADDRESS */
 #endif /* CONFIG_MMC_DW_IDMAC */
 
 /**
@@ -365,6 +390,40 @@  static void dw_mci_idmac_complete_dma(struct dw_mci *host)
 	}
 }
 
+#ifdef CONFIG_MMC_DW_IDMAC_64BIT_ADDRESS
+static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
+				    unsigned int sg_len)
+{
+	int i;
+	struct idmac_desc64 *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_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 last descriptor */
+	desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc64);
+	desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
+	desc->des0 |= IDMAC_DES0_LD;
+
+	wmb();
+}
+#else
 static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
 				    unsigned int sg_len)
 {
@@ -396,6 +455,7 @@  static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
 
 	wmb();
 }
+#endif /* CONFIG_MMC_DW_IDMAC_64BIT_ADDRESS */
 
 static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
 {
@@ -419,6 +479,40 @@  static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
 	mci_writel(host, PLDMND, 1);
 }
 
+#ifdef CONFIG_MMC_DW_IDMAC_64BIT_ADDRESS
+static int dw_mci_idmac_init(struct dw_mci *host)
+{
+	struct idmac_desc64 *p;
+	int i;
+
+	/* Number of descriptors in the ring buffer */
+	host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc64);
+
+	/* 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_desc64) *
+						(i + 1))) & 0xffffffff;
+		p->des7 = (host->sg_dma + (sizeof(struct idmac_desc64) *
+						(i + 1))) >> 32;
+	}
+
+	/* 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;
+
+	mci_writel(host, BMOD, SDMMC_IDMAC_SWRESET);
+
+	/* Mask out interrupts - get Tx & Rx complete only */
+	mci_writel(host, IDINTEN, 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);
+	return 0;
+}
+#else
 static int dw_mci_idmac_init(struct dw_mci *host)
 {
 	struct idmac_desc *p;
@@ -446,6 +540,7 @@  static int dw_mci_idmac_init(struct dw_mci *host)
 	mci_writel(host, DBADDR, host->sg_dma);
 	return 0;
 }
+#endif /* CONFIG_MMC_DW_IDMAC_64BIT_ADDRESS */
 
 static const struct dw_mci_dma_ops dw_mci_idmac_ops = {
 	.init = dw_mci_idmac_init,
@@ -2036,6 +2131,17 @@  static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
 
 static void dw_mci_init_dma(struct dw_mci *host)
 {
+	u32 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) {
+		dev_info(host->dev, "IDMAC with 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
+			goto no_dma;
+	}
+
 	/* 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..a3a5e9c 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -48,11 +48,22 @@ 
 #define SDMMC_UHS_REG		0x074
 #define SDMMC_BMOD		0x080
 #define SDMMC_PLDMND		0x084
+#ifdef CONFIG_MMC_DW_IDMAC_64BIT_ADDRESS
+#define SDMMC_DBADDRL		0x088
+#define SDMMC_DBADDRU		0x08c
+#define SDMMC_IDSTS		0x090
+#define SDMMC_IDINTEN		0x094
+#define SDMMC_DSCADDRL		0x098
+#define SDMMC_DSCADDRU		0x09c
+#define SDMMC_BUFADDRL		0x0A0
+#define SDMMC_BUFADDRU		0x0A4
+#else
 #define SDMMC_DBADDR		0x088
 #define SDMMC_IDSTS		0x08c
 #define SDMMC_IDINTEN		0x090
 #define SDMMC_DSCADDR		0x094
 #define SDMMC_BUFADDR		0x098
+#endif
 #define SDMMC_DATA(x)		(x)
 
 /*