RE: [PATCH v4 1/1] mmc: dw_mmc: Add IDMAC 64-bit address mode support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxxx>
> > ---
> > 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;
> >

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux