All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jaehoon Chung <jh80.chung@samsung.com>
To: Prabu Thangamuthu <Prabu.T@synopsys.com>
Cc: Seungwon Jeon <tgih.jun@samsung.com>,
	'Chris Ball' <cjb@laptop.org>,
	'Wei WANG' <wei_wang@realsil.com.cn>,
	'Ludovic Desroches' <ludovic.desroches@atmel.com>,
	'Greg Kroah-Hartman' <gregkh@linuxfoundation.org>,
	'Arnd Bergmann' <arnd@arndb.de>,
	'Manjunath M Bettegowda' <Manjunath.MB@synopsys.com>,
	"linux-mmc@vger.kernel.org" <linux-mmc@vger.kernel.org>
Subject: Re: [PATCH v4 1/1] mmc: dw_mmc: Add IDMAC 64-bit address mode support
Date: Fri, 23 Aug 2013 21:19:09 +0900	[thread overview]
Message-ID: <5217533D.8010100@samsung.com> (raw)
In-Reply-To: <705D14B1C7978B40A723277C067CEDE2CD8187@IN01WEMBXB.internal.synopsys.com>

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


  reply	other threads:[~2013-08-23 12:19 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
2013-08-23 13:09   ` Prabu Thangamuthu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5217533D.8010100@samsung.com \
    --to=jh80.chung@samsung.com \
    --cc=Manjunath.MB@synopsys.com \
    --cc=Prabu.T@synopsys.com \
    --cc=arnd@arndb.de \
    --cc=cjb@laptop.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-mmc@vger.kernel.org \
    --cc=ludovic.desroches@atmel.com \
    --cc=tgih.jun@samsung.com \
    --cc=wei_wang@realsil.com.cn \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.