All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/6] mmc: dw_mmc: add support for device tree based instantiation
@ 2012-07-12 12:54 ` Thomas Abraham
  0 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-12 12:54 UTC (permalink / raw)
  To: linux-mmc, devicetree-discuss
  Cc: linux-kernel, linux-arm-kernel, cjb, grant.likely, rob.herring,
	linux-samsung-soc, kgene.kim, patches

This patch series adds device tree support for Synopsis Designware Mobile
Storage Host Controller.

The first patch converts the copy of controller device instance into a
reference. This is need to allow device resource management api to correctly
manage the resources allocated by the driver. The second patch fixes the
incorrect abort of the probe in case a slot initialization fails. This is
fixed by allowing as many slots to be initialized successfully and failing
only if there are no slots that were initialized.

The third patch adds clock lookup in the driver and this is optional. Platforms
that do not need any clock gating and control for the dw_mmc controllers will
not be affected with this change. The fourth patch adds a quirk to notify the
controller about the absence of the write protect line.

The fifth patch adds device tree based discovery support for the dw_mmc driver.
The sixth patch add Samsung Exynos5250 specific extentions to the driver.

This patchset is based on Samsung kernel tree's for-next branch with the
mmc tree's mmc-next branch merged.

Thomas Abraham (6):
  mmc: dw_mmc: convert copy of struct device in struct dw_mci to a reference
  mmc: dw_mmc: allow probe to succeed even if one slot is initialized
  mmc: dw_mmc: lookup for optional biu and ciu clocks
  mmc: dw_mmc: add quirk to indicate missing write protect line
  mmc: dw_mmc: add device tree support
  mmc: dw_mmc: add samsung exynos5250 specific extentions

 .../devicetree/bindings/mmc/synposis-dw-mshc.txt   |  144 ++++++++
 drivers/mmc/host/dw_mmc-pci.c                      |    2 +-
 drivers/mmc/host/dw_mmc-pltfm.c                    |   41 +++-
 drivers/mmc/host/dw_mmc.c                          |  364 +++++++++++++++++---
 drivers/mmc/host/dw_mmc.h                          |   23 ++
 include/linux/mmc/dw_mmc.h                         |   17 +-
 6 files changed, 538 insertions(+), 53 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v3 0/6] mmc: dw_mmc: add support for device tree based instantiation
@ 2012-07-12 12:54 ` Thomas Abraham
  0 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-12 12:54 UTC (permalink / raw)
  To: linux-arm-kernel

This patch series adds device tree support for Synopsis Designware Mobile
Storage Host Controller.

The first patch converts the copy of controller device instance into a
reference. This is need to allow device resource management api to correctly
manage the resources allocated by the driver. The second patch fixes the
incorrect abort of the probe in case a slot initialization fails. This is
fixed by allowing as many slots to be initialized successfully and failing
only if there are no slots that were initialized.

The third patch adds clock lookup in the driver and this is optional. Platforms
that do not need any clock gating and control for the dw_mmc controllers will
not be affected with this change. The fourth patch adds a quirk to notify the
controller about the absence of the write protect line.

The fifth patch adds device tree based discovery support for the dw_mmc driver.
The sixth patch add Samsung Exynos5250 specific extentions to the driver.

This patchset is based on Samsung kernel tree's for-next branch with the
mmc tree's mmc-next branch merged.

Thomas Abraham (6):
  mmc: dw_mmc: convert copy of struct device in struct dw_mci to a reference
  mmc: dw_mmc: allow probe to succeed even if one slot is initialized
  mmc: dw_mmc: lookup for optional biu and ciu clocks
  mmc: dw_mmc: add quirk to indicate missing write protect line
  mmc: dw_mmc: add device tree support
  mmc: dw_mmc: add samsung exynos5250 specific extentions

 .../devicetree/bindings/mmc/synposis-dw-mshc.txt   |  144 ++++++++
 drivers/mmc/host/dw_mmc-pci.c                      |    2 +-
 drivers/mmc/host/dw_mmc-pltfm.c                    |   41 +++-
 drivers/mmc/host/dw_mmc.c                          |  364 +++++++++++++++++---
 drivers/mmc/host/dw_mmc.h                          |   23 ++
 include/linux/mmc/dw_mmc.h                         |   17 +-
 6 files changed, 538 insertions(+), 53 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v3 1/6] mmc: dw_mmc: convert copy of struct device in struct dw_mci to a reference
  2012-07-12 12:54 ` Thomas Abraham
@ 2012-07-12 12:54   ` Thomas Abraham
  -1 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-12 12:54 UTC (permalink / raw)
  To: linux-mmc, devicetree-discuss
  Cc: linux-kernel, linux-arm-kernel, cjb, grant.likely, rob.herring,
	linux-samsung-soc, kgene.kim, patches

The 'struct dw_mci' maintains a copy of the pdev->dev instance instead of
maintaining a reference to that 'struct device' instance. Any resource
allocated using the device resource management kernel API with the instance
of 'struct device' in 'struct dw_mci' is then incorrect. Fix this by
converting the copy of 'struct device' in 'struct dw_mci' to a reference.

Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
---
 drivers/mmc/host/dw_mmc-pci.c   |    2 +-
 drivers/mmc/host/dw_mmc-pltfm.c |    2 +-
 drivers/mmc/host/dw_mmc.c       |   56 +++++++++++++++++++-------------------
 include/linux/mmc/dw_mmc.h      |    2 +-
 4 files changed, 31 insertions(+), 31 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc-pci.c b/drivers/mmc/host/dw_mmc-pci.c
index dc0d25a..592545a 100644
--- a/drivers/mmc/host/dw_mmc-pci.c
+++ b/drivers/mmc/host/dw_mmc-pci.c
@@ -59,7 +59,7 @@ static int __devinit dw_mci_pci_probe(struct pci_dev *pdev,
 
 	host->irq = pdev->irq;
 	host->irq_flags = IRQF_SHARED;
-	host->dev = pdev->dev;
+	host->dev = &pdev->dev;
 	host->pdata = &pci_board_data;
 
 	host->regs = pci_iomap(pdev, PCI_BAR_NO, COMPLETE_BAR);
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 92ec3eb..9a63299 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -43,7 +43,7 @@ static int dw_mci_pltfm_probe(struct platform_device *pdev)
 		goto err_free;
 	}
 
-	host->dev = pdev->dev;
+	host->dev = &pdev->dev;
 	host->irq_flags = 0;
 	host->pdata = pdev->dev.platform_data;
 	ret = -ENOMEM;
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 72dc3cd..948a7ac 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -266,7 +266,7 @@ static void dw_mci_start_command(struct dw_mci *host,
 				 struct mmc_command *cmd, u32 cmd_flags)
 {
 	host->cmd = cmd;
-	dev_vdbg(&host->dev,
+	dev_vdbg(host->dev,
 		 "start command: ARGR=0x%08x CMDR=0x%08x\n",
 		 cmd->arg, cmd_flags);
 
@@ -308,7 +308,7 @@ static void dw_mci_dma_cleanup(struct dw_mci *host)
 
 	if (data)
 		if (!data->host_cookie)
-			dma_unmap_sg(&host->dev,
+			dma_unmap_sg(host->dev,
 				     data->sg,
 				     data->sg_len,
 				     dw_mci_get_dma_dir(data));
@@ -334,7 +334,7 @@ static void dw_mci_idmac_complete_dma(struct dw_mci *host)
 {
 	struct mmc_data *data = host->data;
 
-	dev_vdbg(&host->dev, "DMA complete\n");
+	dev_vdbg(host->dev, "DMA complete\n");
 
 	host->dma_ops->cleanup(host);
 
@@ -414,13 +414,13 @@ static int dw_mci_idmac_init(struct dw_mci *host)
 	dma_support = (mci_readl(host, HCON) >> 16) & 0x3;
 
 	if (!dma_support || dma_support > 2) {
-		dev_err(&host->dev,
+		dev_err(host->dev,
 			"Host Controller does not support IDMA Tx.\n");
 		host->dma_ops = NULL;
 		return -ENODEV;
 	}
 
-	dev_info(&host->dev, "Using internal DMA controller.\n");
+	dev_info(host->dev, "Using internal DMA controller.\n");
 
 	/* Forward link the descriptor list */
 	for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
@@ -476,7 +476,7 @@ static int dw_mci_pre_dma_transfer(struct dw_mci *host,
 			return -EINVAL;
 	}
 
-	sg_len = dma_map_sg(&host->dev,
+	sg_len = dma_map_sg(host->dev,
 			    data->sg,
 			    data->sg_len,
 			    dw_mci_get_dma_dir(data));
@@ -519,7 +519,7 @@ static void dw_mci_post_req(struct mmc_host *mmc,
 		return;
 
 	if (data->host_cookie)
-		dma_unmap_sg(&slot->host->dev,
+		dma_unmap_sg(slot->host->dev,
 			     data->sg,
 			     data->sg_len,
 			     dw_mci_get_dma_dir(data));
@@ -545,7 +545,7 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
 
 	host->using_dma = 1;
 
-	dev_vdbg(&host->dev,
+	dev_vdbg(host->dev,
 		 "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n",
 		 (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma,
 		 sg_len);
@@ -904,12 +904,12 @@ static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
 		slot = list_entry(host->queue.next,
 				  struct dw_mci_slot, queue_node);
 		list_del(&slot->queue_node);
-		dev_vdbg(&host->dev, "list not empty: %s is next\n",
+		dev_vdbg(host->dev, "list not empty: %s is next\n",
 			 mmc_hostname(slot->mmc));
 		host->state = STATE_SENDING_CMD;
 		dw_mci_start_request(host, slot);
 	} else {
-		dev_vdbg(&host->dev, "list empty\n");
+		dev_vdbg(host->dev, "list empty\n");
 		host->state = STATE_IDLE;
 	}
 
@@ -1048,7 +1048,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
 					data->bytes_xfered = 0;
 					data->error = -ETIMEDOUT;
 				} else {
-					dev_err(&host->dev,
+					dev_err(host->dev,
 						"data FIFO error "
 						"(status=%08x)\n",
 						status);
@@ -1765,7 +1765,7 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 	struct mmc_host *mmc;
 	struct dw_mci_slot *slot;
 
-	mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), &host->dev);
+	mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
 	if (!mmc)
 		return -ENOMEM;
 
@@ -1877,10 +1877,10 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
 static void dw_mci_init_dma(struct dw_mci *host)
 {
 	/* Alloc memory for sg translation */
-	host->sg_cpu = dma_alloc_coherent(&host->dev, PAGE_SIZE,
+	host->sg_cpu = dma_alloc_coherent(host->dev, PAGE_SIZE,
 					  &host->sg_dma, GFP_KERNEL);
 	if (!host->sg_cpu) {
-		dev_err(&host->dev, "%s: could not alloc DMA memory\n",
+		dev_err(host->dev, "%s: could not alloc DMA memory\n",
 			__func__);
 		goto no_dma;
 	}
@@ -1896,12 +1896,12 @@ static void dw_mci_init_dma(struct dw_mci *host)
 	if (host->dma_ops->init && host->dma_ops->start &&
 	    host->dma_ops->stop && host->dma_ops->cleanup) {
 		if (host->dma_ops->init(host)) {
-			dev_err(&host->dev, "%s: Unable to initialize "
+			dev_err(host->dev, "%s: Unable to initialize "
 				"DMA Controller.\n", __func__);
 			goto no_dma;
 		}
 	} else {
-		dev_err(&host->dev, "DMA initialization not found.\n");
+		dev_err(host->dev, "DMA initialization not found.\n");
 		goto no_dma;
 	}
 
@@ -1909,7 +1909,7 @@ static void dw_mci_init_dma(struct dw_mci *host)
 	return;
 
 no_dma:
-	dev_info(&host->dev, "Using PIO mode.\n");
+	dev_info(host->dev, "Using PIO mode.\n");
 	host->use_dma = 0;
 	return;
 }
@@ -1941,19 +1941,19 @@ int dw_mci_probe(struct dw_mci *host)
 	u32 fifo_size;
 
 	if (!host->pdata || !host->pdata->init) {
-		dev_err(&host->dev,
+		dev_err(host->dev,
 			"Platform data must supply init function\n");
 		return -ENODEV;
 	}
 
 	if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
-		dev_err(&host->dev,
+		dev_err(host->dev,
 			"Platform data must supply select_slot function\n");
 		return -ENODEV;
 	}
 
 	if (!host->pdata->bus_hz) {
-		dev_err(&host->dev,
+		dev_err(host->dev,
 			"Platform data must supply bus speed\n");
 		return -ENODEV;
 	}
@@ -1991,7 +1991,7 @@ int dw_mci_probe(struct dw_mci *host)
 	}
 
 	/* Reset all blocks */
-	if (!mci_wait_reset(&host->dev, host))
+	if (!mci_wait_reset(host->dev, host))
 		return -ENODEV;
 
 	host->dma_ops = host->pdata->dma_ops;
@@ -2058,7 +2058,7 @@ int dw_mci_probe(struct dw_mci *host)
 	 * Need to check the version-id and set data-offset for DATA register.
 	 */
 	host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
-	dev_info(&host->dev, "Version ID is %04x\n", host->verid);
+	dev_info(host->dev, "Version ID is %04x\n", host->verid);
 
 	if (host->verid < DW_MMC_240A)
 		host->data_offset = DATA_OFFSET;
@@ -2075,12 +2075,12 @@ int dw_mci_probe(struct dw_mci *host)
 		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
 	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */
 
-	dev_info(&host->dev, "DW MMC controller at irq %d, "
+	dev_info(host->dev, "DW MMC controller at irq %d, "
 		 "%d bit host data width, "
 		 "%u deep fifo\n",
 		 host->irq, width, fifo_size);
 	if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
-		dev_info(&host->dev, "Internal DMAC interrupt fix enabled.\n");
+		dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n");
 
 	return 0;
 
@@ -2099,7 +2099,7 @@ err_workqueue:
 err_dmaunmap:
 	if (host->use_dma && host->dma_ops->exit)
 		host->dma_ops->exit(host);
-	dma_free_coherent(&host->dev, PAGE_SIZE,
+	dma_free_coherent(host->dev, PAGE_SIZE,
 			  host->sg_cpu, host->sg_dma);
 
 	if (host->vmmc) {
@@ -2118,7 +2118,7 @@ void dw_mci_remove(struct dw_mci *host)
 	mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
 
 	for (i = 0; i < host->num_slots; i++) {
-		dev_dbg(&host->dev, "remove slot %d\n", i);
+		dev_dbg(host->dev, "remove slot %d\n", i);
 		if (host->slot[i])
 			dw_mci_cleanup_slot(host->slot[i], i);
 	}
@@ -2129,7 +2129,7 @@ void dw_mci_remove(struct dw_mci *host)
 
 	free_irq(host->irq, host);
 	destroy_workqueue(host->card_workqueue);
-	dma_free_coherent(&host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+	dma_free_coherent(host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
 
 	if (host->use_dma && host->dma_ops->exit)
 		host->dma_ops->exit(host);
@@ -2181,7 +2181,7 @@ int dw_mci_resume(struct dw_mci *host)
 	if (host->vmmc)
 		regulator_enable(host->vmmc);
 
-	if (!mci_wait_reset(&host->dev, host)) {
+	if (!mci_wait_reset(host->dev, host)) {
 		ret = -ENODEV;
 		return ret;
 	}
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index 7a7ebd3..a37a573 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -156,7 +156,7 @@ struct dw_mci {
 	u32			fifoth_val;
 	u16			verid;
 	u16			data_offset;
-	struct device		dev;
+	struct device		*dev;
 	struct dw_mci_board	*pdata;
 	struct dw_mci_slot	*slot[MAX_MCI_SLOTS];
 
-- 
1.6.6.rc2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v3 1/6] mmc: dw_mmc: convert copy of struct device in struct dw_mci to a reference
@ 2012-07-12 12:54   ` Thomas Abraham
  0 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-12 12:54 UTC (permalink / raw)
  To: linux-arm-kernel

The 'struct dw_mci' maintains a copy of the pdev->dev instance instead of
maintaining a reference to that 'struct device' instance. Any resource
allocated using the device resource management kernel API with the instance
of 'struct device' in 'struct dw_mci' is then incorrect. Fix this by
converting the copy of 'struct device' in 'struct dw_mci' to a reference.

Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
---
 drivers/mmc/host/dw_mmc-pci.c   |    2 +-
 drivers/mmc/host/dw_mmc-pltfm.c |    2 +-
 drivers/mmc/host/dw_mmc.c       |   56 +++++++++++++++++++-------------------
 include/linux/mmc/dw_mmc.h      |    2 +-
 4 files changed, 31 insertions(+), 31 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc-pci.c b/drivers/mmc/host/dw_mmc-pci.c
index dc0d25a..592545a 100644
--- a/drivers/mmc/host/dw_mmc-pci.c
+++ b/drivers/mmc/host/dw_mmc-pci.c
@@ -59,7 +59,7 @@ static int __devinit dw_mci_pci_probe(struct pci_dev *pdev,
 
 	host->irq = pdev->irq;
 	host->irq_flags = IRQF_SHARED;
-	host->dev = pdev->dev;
+	host->dev = &pdev->dev;
 	host->pdata = &pci_board_data;
 
 	host->regs = pci_iomap(pdev, PCI_BAR_NO, COMPLETE_BAR);
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 92ec3eb..9a63299 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -43,7 +43,7 @@ static int dw_mci_pltfm_probe(struct platform_device *pdev)
 		goto err_free;
 	}
 
-	host->dev = pdev->dev;
+	host->dev = &pdev->dev;
 	host->irq_flags = 0;
 	host->pdata = pdev->dev.platform_data;
 	ret = -ENOMEM;
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 72dc3cd..948a7ac 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -266,7 +266,7 @@ static void dw_mci_start_command(struct dw_mci *host,
 				 struct mmc_command *cmd, u32 cmd_flags)
 {
 	host->cmd = cmd;
-	dev_vdbg(&host->dev,
+	dev_vdbg(host->dev,
 		 "start command: ARGR=0x%08x CMDR=0x%08x\n",
 		 cmd->arg, cmd_flags);
 
@@ -308,7 +308,7 @@ static void dw_mci_dma_cleanup(struct dw_mci *host)
 
 	if (data)
 		if (!data->host_cookie)
-			dma_unmap_sg(&host->dev,
+			dma_unmap_sg(host->dev,
 				     data->sg,
 				     data->sg_len,
 				     dw_mci_get_dma_dir(data));
@@ -334,7 +334,7 @@ static void dw_mci_idmac_complete_dma(struct dw_mci *host)
 {
 	struct mmc_data *data = host->data;
 
-	dev_vdbg(&host->dev, "DMA complete\n");
+	dev_vdbg(host->dev, "DMA complete\n");
 
 	host->dma_ops->cleanup(host);
 
@@ -414,13 +414,13 @@ static int dw_mci_idmac_init(struct dw_mci *host)
 	dma_support = (mci_readl(host, HCON) >> 16) & 0x3;
 
 	if (!dma_support || dma_support > 2) {
-		dev_err(&host->dev,
+		dev_err(host->dev,
 			"Host Controller does not support IDMA Tx.\n");
 		host->dma_ops = NULL;
 		return -ENODEV;
 	}
 
-	dev_info(&host->dev, "Using internal DMA controller.\n");
+	dev_info(host->dev, "Using internal DMA controller.\n");
 
 	/* Forward link the descriptor list */
 	for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
@@ -476,7 +476,7 @@ static int dw_mci_pre_dma_transfer(struct dw_mci *host,
 			return -EINVAL;
 	}
 
-	sg_len = dma_map_sg(&host->dev,
+	sg_len = dma_map_sg(host->dev,
 			    data->sg,
 			    data->sg_len,
 			    dw_mci_get_dma_dir(data));
@@ -519,7 +519,7 @@ static void dw_mci_post_req(struct mmc_host *mmc,
 		return;
 
 	if (data->host_cookie)
-		dma_unmap_sg(&slot->host->dev,
+		dma_unmap_sg(slot->host->dev,
 			     data->sg,
 			     data->sg_len,
 			     dw_mci_get_dma_dir(data));
@@ -545,7 +545,7 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
 
 	host->using_dma = 1;
 
-	dev_vdbg(&host->dev,
+	dev_vdbg(host->dev,
 		 "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n",
 		 (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma,
 		 sg_len);
@@ -904,12 +904,12 @@ static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
 		slot = list_entry(host->queue.next,
 				  struct dw_mci_slot, queue_node);
 		list_del(&slot->queue_node);
-		dev_vdbg(&host->dev, "list not empty: %s is next\n",
+		dev_vdbg(host->dev, "list not empty: %s is next\n",
 			 mmc_hostname(slot->mmc));
 		host->state = STATE_SENDING_CMD;
 		dw_mci_start_request(host, slot);
 	} else {
-		dev_vdbg(&host->dev, "list empty\n");
+		dev_vdbg(host->dev, "list empty\n");
 		host->state = STATE_IDLE;
 	}
 
@@ -1048,7 +1048,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
 					data->bytes_xfered = 0;
 					data->error = -ETIMEDOUT;
 				} else {
-					dev_err(&host->dev,
+					dev_err(host->dev,
 						"data FIFO error "
 						"(status=%08x)\n",
 						status);
@@ -1765,7 +1765,7 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 	struct mmc_host *mmc;
 	struct dw_mci_slot *slot;
 
-	mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), &host->dev);
+	mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
 	if (!mmc)
 		return -ENOMEM;
 
@@ -1877,10 +1877,10 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
 static void dw_mci_init_dma(struct dw_mci *host)
 {
 	/* Alloc memory for sg translation */
-	host->sg_cpu = dma_alloc_coherent(&host->dev, PAGE_SIZE,
+	host->sg_cpu = dma_alloc_coherent(host->dev, PAGE_SIZE,
 					  &host->sg_dma, GFP_KERNEL);
 	if (!host->sg_cpu) {
-		dev_err(&host->dev, "%s: could not alloc DMA memory\n",
+		dev_err(host->dev, "%s: could not alloc DMA memory\n",
 			__func__);
 		goto no_dma;
 	}
@@ -1896,12 +1896,12 @@ static void dw_mci_init_dma(struct dw_mci *host)
 	if (host->dma_ops->init && host->dma_ops->start &&
 	    host->dma_ops->stop && host->dma_ops->cleanup) {
 		if (host->dma_ops->init(host)) {
-			dev_err(&host->dev, "%s: Unable to initialize "
+			dev_err(host->dev, "%s: Unable to initialize "
 				"DMA Controller.\n", __func__);
 			goto no_dma;
 		}
 	} else {
-		dev_err(&host->dev, "DMA initialization not found.\n");
+		dev_err(host->dev, "DMA initialization not found.\n");
 		goto no_dma;
 	}
 
@@ -1909,7 +1909,7 @@ static void dw_mci_init_dma(struct dw_mci *host)
 	return;
 
 no_dma:
-	dev_info(&host->dev, "Using PIO mode.\n");
+	dev_info(host->dev, "Using PIO mode.\n");
 	host->use_dma = 0;
 	return;
 }
@@ -1941,19 +1941,19 @@ int dw_mci_probe(struct dw_mci *host)
 	u32 fifo_size;
 
 	if (!host->pdata || !host->pdata->init) {
-		dev_err(&host->dev,
+		dev_err(host->dev,
 			"Platform data must supply init function\n");
 		return -ENODEV;
 	}
 
 	if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
-		dev_err(&host->dev,
+		dev_err(host->dev,
 			"Platform data must supply select_slot function\n");
 		return -ENODEV;
 	}
 
 	if (!host->pdata->bus_hz) {
-		dev_err(&host->dev,
+		dev_err(host->dev,
 			"Platform data must supply bus speed\n");
 		return -ENODEV;
 	}
@@ -1991,7 +1991,7 @@ int dw_mci_probe(struct dw_mci *host)
 	}
 
 	/* Reset all blocks */
-	if (!mci_wait_reset(&host->dev, host))
+	if (!mci_wait_reset(host->dev, host))
 		return -ENODEV;
 
 	host->dma_ops = host->pdata->dma_ops;
@@ -2058,7 +2058,7 @@ int dw_mci_probe(struct dw_mci *host)
 	 * Need to check the version-id and set data-offset for DATA register.
 	 */
 	host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
-	dev_info(&host->dev, "Version ID is %04x\n", host->verid);
+	dev_info(host->dev, "Version ID is %04x\n", host->verid);
 
 	if (host->verid < DW_MMC_240A)
 		host->data_offset = DATA_OFFSET;
@@ -2075,12 +2075,12 @@ int dw_mci_probe(struct dw_mci *host)
 		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
 	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */
 
-	dev_info(&host->dev, "DW MMC controller at irq %d, "
+	dev_info(host->dev, "DW MMC controller at irq %d, "
 		 "%d bit host data width, "
 		 "%u deep fifo\n",
 		 host->irq, width, fifo_size);
 	if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
-		dev_info(&host->dev, "Internal DMAC interrupt fix enabled.\n");
+		dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n");
 
 	return 0;
 
@@ -2099,7 +2099,7 @@ err_workqueue:
 err_dmaunmap:
 	if (host->use_dma && host->dma_ops->exit)
 		host->dma_ops->exit(host);
-	dma_free_coherent(&host->dev, PAGE_SIZE,
+	dma_free_coherent(host->dev, PAGE_SIZE,
 			  host->sg_cpu, host->sg_dma);
 
 	if (host->vmmc) {
@@ -2118,7 +2118,7 @@ void dw_mci_remove(struct dw_mci *host)
 	mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
 
 	for (i = 0; i < host->num_slots; i++) {
-		dev_dbg(&host->dev, "remove slot %d\n", i);
+		dev_dbg(host->dev, "remove slot %d\n", i);
 		if (host->slot[i])
 			dw_mci_cleanup_slot(host->slot[i], i);
 	}
@@ -2129,7 +2129,7 @@ void dw_mci_remove(struct dw_mci *host)
 
 	free_irq(host->irq, host);
 	destroy_workqueue(host->card_workqueue);
-	dma_free_coherent(&host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+	dma_free_coherent(host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
 
 	if (host->use_dma && host->dma_ops->exit)
 		host->dma_ops->exit(host);
@@ -2181,7 +2181,7 @@ int dw_mci_resume(struct dw_mci *host)
 	if (host->vmmc)
 		regulator_enable(host->vmmc);
 
-	if (!mci_wait_reset(&host->dev, host)) {
+	if (!mci_wait_reset(host->dev, host)) {
 		ret = -ENODEV;
 		return ret;
 	}
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index 7a7ebd3..a37a573 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -156,7 +156,7 @@ struct dw_mci {
 	u32			fifoth_val;
 	u16			verid;
 	u16			data_offset;
-	struct device		dev;
+	struct device		*dev;
 	struct dw_mci_board	*pdata;
 	struct dw_mci_slot	*slot[MAX_MCI_SLOTS];
 
-- 
1.6.6.rc2

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v3 2/6] mmc: dw_mmc: allow probe to succeed even if one slot is initialized
@ 2012-07-12 12:54   ` Thomas Abraham
  0 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-12 12:54 UTC (permalink / raw)
  To: linux-mmc, devicetree-discuss
  Cc: linux-kernel, linux-arm-kernel, cjb, grant.likely, rob.herring,
	linux-samsung-soc, kgene.kim, patches

Instead of aborting the probe in case a slot initialization fails, allow
initialization of as many slots as possible. If there are atleast one
instance of slot that is successfully initialized, allow the driver probe
to succeed.

Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
---
 drivers/mmc/host/dw_mmc.c |   23 +++++++++++++----------
 1 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 948a7ac..cd58063 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1939,6 +1939,7 @@ int dw_mci_probe(struct dw_mci *host)
 {
 	int width, i, ret = 0;
 	u32 fifo_size;
+	int init_slots = 0;
 
 	if (!host->pdata || !host->pdata->init) {
 		dev_err(host->dev,
@@ -2047,10 +2048,18 @@ int dw_mci_probe(struct dw_mci *host)
 	/* We need at least one slot to succeed */
 	for (i = 0; i < host->num_slots; i++) {
 		ret = dw_mci_init_slot(host, i);
-		if (ret) {
-			ret = -ENODEV;
-			goto err_init_slot;
-		}
+		if (ret)
+			dev_dbg(host->dev, "slot %d init failed\n", i);
+		else
+			init_slots++;
+	}
+
+	if (init_slots) {
+		dev_info(host->dev, "%d slots initialized\n", init_slots);
+	} else {
+		dev_dbg(host->dev, "attempted to initialize %d slots, "
+					"but failed on all\n", host->num_slots);
+		goto err_init_slot;
 	}
 
 	/*
@@ -2085,12 +2094,6 @@ int dw_mci_probe(struct dw_mci *host)
 	return 0;
 
 err_init_slot:
-	/* De-init any initialized slots */
-	while (i > 0) {
-		if (host->slot[i])
-			dw_mci_cleanup_slot(host->slot[i], i);
-		i--;
-	}
 	free_irq(host->irq, host);
 
 err_workqueue:
-- 
1.6.6.rc2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v3 2/6] mmc: dw_mmc: allow probe to succeed even if one slot is initialized
@ 2012-07-12 12:54   ` Thomas Abraham
  0 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-12 12:54 UTC (permalink / raw)
  To: linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
  Cc: linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	patches-QSEj5FYQhm4dnm+yROfE0A,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	rob.herring-bsGFqQB8/DxBDgjK7y7TUQ,
	kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, cjb-2X9k7bc8m7Mdnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Instead of aborting the probe in case a slot initialization fails, allow
initialization of as many slots as possible. If there are atleast one
instance of slot that is successfully initialized, allow the driver probe
to succeed.

Signed-off-by: Thomas Abraham <thomas.abraham-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
 drivers/mmc/host/dw_mmc.c |   23 +++++++++++++----------
 1 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 948a7ac..cd58063 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1939,6 +1939,7 @@ int dw_mci_probe(struct dw_mci *host)
 {
 	int width, i, ret = 0;
 	u32 fifo_size;
+	int init_slots = 0;
 
 	if (!host->pdata || !host->pdata->init) {
 		dev_err(host->dev,
@@ -2047,10 +2048,18 @@ int dw_mci_probe(struct dw_mci *host)
 	/* We need at least one slot to succeed */
 	for (i = 0; i < host->num_slots; i++) {
 		ret = dw_mci_init_slot(host, i);
-		if (ret) {
-			ret = -ENODEV;
-			goto err_init_slot;
-		}
+		if (ret)
+			dev_dbg(host->dev, "slot %d init failed\n", i);
+		else
+			init_slots++;
+	}
+
+	if (init_slots) {
+		dev_info(host->dev, "%d slots initialized\n", init_slots);
+	} else {
+		dev_dbg(host->dev, "attempted to initialize %d slots, "
+					"but failed on all\n", host->num_slots);
+		goto err_init_slot;
 	}
 
 	/*
@@ -2085,12 +2094,6 @@ int dw_mci_probe(struct dw_mci *host)
 	return 0;
 
 err_init_slot:
-	/* De-init any initialized slots */
-	while (i > 0) {
-		if (host->slot[i])
-			dw_mci_cleanup_slot(host->slot[i], i);
-		i--;
-	}
 	free_irq(host->irq, host);
 
 err_workqueue:
-- 
1.6.6.rc2

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v3 2/6] mmc: dw_mmc: allow probe to succeed even if one slot is initialized
@ 2012-07-12 12:54   ` Thomas Abraham
  0 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-12 12:54 UTC (permalink / raw)
  To: linux-arm-kernel

Instead of aborting the probe in case a slot initialization fails, allow
initialization of as many slots as possible. If there are atleast one
instance of slot that is successfully initialized, allow the driver probe
to succeed.

Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
---
 drivers/mmc/host/dw_mmc.c |   23 +++++++++++++----------
 1 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 948a7ac..cd58063 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1939,6 +1939,7 @@ int dw_mci_probe(struct dw_mci *host)
 {
 	int width, i, ret = 0;
 	u32 fifo_size;
+	int init_slots = 0;
 
 	if (!host->pdata || !host->pdata->init) {
 		dev_err(host->dev,
@@ -2047,10 +2048,18 @@ int dw_mci_probe(struct dw_mci *host)
 	/* We need at least one slot to succeed */
 	for (i = 0; i < host->num_slots; i++) {
 		ret = dw_mci_init_slot(host, i);
-		if (ret) {
-			ret = -ENODEV;
-			goto err_init_slot;
-		}
+		if (ret)
+			dev_dbg(host->dev, "slot %d init failed\n", i);
+		else
+			init_slots++;
+	}
+
+	if (init_slots) {
+		dev_info(host->dev, "%d slots initialized\n", init_slots);
+	} else {
+		dev_dbg(host->dev, "attempted to initialize %d slots, "
+					"but failed on all\n", host->num_slots);
+		goto err_init_slot;
 	}
 
 	/*
@@ -2085,12 +2094,6 @@ int dw_mci_probe(struct dw_mci *host)
 	return 0;
 
 err_init_slot:
-	/* De-init any initialized slots */
-	while (i > 0) {
-		if (host->slot[i])
-			dw_mci_cleanup_slot(host->slot[i], i);
-		i--;
-	}
 	free_irq(host->irq, host);
 
 err_workqueue:
-- 
1.6.6.rc2

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v3 3/6] mmc: dw_mmc: lookup for optional biu and ciu clocks
@ 2012-07-12 12:54   ` Thomas Abraham
  0 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-12 12:54 UTC (permalink / raw)
  To: linux-mmc, devicetree-discuss
  Cc: linux-kernel, linux-arm-kernel, cjb, grant.likely, rob.herring,
	linux-samsung-soc, kgene.kim, patches

Some platforms allow for clock gating and control of bus interface unit clock
and card interface unit clock. Add support for clock lookup of optional biu
and ciu clocks for clock gating and clock speed determination.

Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
---
 drivers/mmc/host/dw_mmc.c  |   42 +++++++++++++++++++++++++++++++++++++++---
 include/linux/mmc/dw_mmc.h |    4 ++++
 2 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index cd58063..679473c 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1953,18 +1953,38 @@ int dw_mci_probe(struct dw_mci *host)
 		return -ENODEV;
 	}
 
-	if (!host->pdata->bus_hz) {
+	host->biu_clk = clk_get(host->dev, "biu");
+	if (IS_ERR(host->biu_clk))
+		dev_dbg(host->dev, "biu clock not available\n");
+	else
+		clk_prepare_enable(host->biu_clk);
+
+	host->ciu_clk = clk_get(host->dev, "ciu");
+	if (IS_ERR(host->ciu_clk))
+		dev_dbg(host->dev, "ciu clock not available\n");
+	else
+		clk_prepare_enable(host->ciu_clk);
+
+	if (IS_ERR(host->ciu_clk))
+		host->bus_hz = host->pdata->bus_hz;
+	else
+		host->bus_hz = clk_get_rate(host->ciu_clk);
+
+	if (!host->bus_hz) {
 		dev_err(host->dev,
 			"Platform data must supply bus speed\n");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto err_clk;
 	}
 
-	host->bus_hz = host->pdata->bus_hz;
 	host->quirks = host->pdata->quirks;
 
 	spin_lock_init(&host->lock);
 	INIT_LIST_HEAD(&host->queue);
 
+	host->dma_ops = host->pdata->dma_ops;
+	dw_mci_init_dma(host);
+
 	/*
 	 * Get the host data width - this assumes that HCON has been set with
 	 * the correct values.
@@ -2109,6 +2129,16 @@ err_dmaunmap:
 		regulator_disable(host->vmmc);
 		regulator_put(host->vmmc);
 	}
+
+err_clk:
+	if (!IS_ERR(host->ciu_clk)) {
+		clk_disable_unprepare(host->ciu_clk);
+		clk_put(host->ciu_clk);
+	}
+	if (!IS_ERR(host->biu_clk)) {
+		clk_disable_unprepare(host->biu_clk);
+		clk_put(host->biu_clk);
+	}
 	return ret;
 }
 EXPORT_SYMBOL(dw_mci_probe);
@@ -2142,6 +2172,12 @@ void dw_mci_remove(struct dw_mci *host)
 		regulator_put(host->vmmc);
 	}
 
+	if (!IS_ERR(host->ciu_clk))
+		clk_disable_unprepare(host->ciu_clk);
+	if (!IS_ERR(host->biu_clk))
+		clk_disable_unprepare(host->biu_clk);
+	clk_put(host->ciu_clk);
+	clk_put(host->biu_clk);
 }
 EXPORT_SYMBOL(dw_mci_remove);
 
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index a37a573..787ad56 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -78,6 +78,8 @@ struct mmc_data;
  * @data_offset: Set the offset of DATA register according to VERID.
  * @dev: Device associated with the MMC controller.
  * @pdata: Platform data associated with the MMC controller.
+ * @biu_clk: Pointer to bus interface unit clock instance.
+ * @ciu_clk: Pointer to card interface unit clock instance.
  * @slot: Slots sharing this MMC controller.
  * @fifo_depth: depth of FIFO.
  * @data_shift: log2 of FIFO item size.
@@ -158,6 +160,8 @@ struct dw_mci {
 	u16			data_offset;
 	struct device		*dev;
 	struct dw_mci_board	*pdata;
+	struct clk		*biu_clk;
+	struct clk		*ciu_clk;
 	struct dw_mci_slot	*slot[MAX_MCI_SLOTS];
 
 	/* FIFO push and pull */
-- 
1.6.6.rc2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v3 3/6] mmc: dw_mmc: lookup for optional biu and ciu clocks
@ 2012-07-12 12:54   ` Thomas Abraham
  0 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-12 12:54 UTC (permalink / raw)
  To: linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
  Cc: linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	patches-QSEj5FYQhm4dnm+yROfE0A,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	rob.herring-bsGFqQB8/DxBDgjK7y7TUQ,
	kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, cjb-2X9k7bc8m7Mdnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Some platforms allow for clock gating and control of bus interface unit clock
and card interface unit clock. Add support for clock lookup of optional biu
and ciu clocks for clock gating and clock speed determination.

Signed-off-by: Abhilash Kesavan <a.kesavan-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Thomas Abraham <thomas.abraham-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
 drivers/mmc/host/dw_mmc.c  |   42 +++++++++++++++++++++++++++++++++++++++---
 include/linux/mmc/dw_mmc.h |    4 ++++
 2 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index cd58063..679473c 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1953,18 +1953,38 @@ int dw_mci_probe(struct dw_mci *host)
 		return -ENODEV;
 	}
 
-	if (!host->pdata->bus_hz) {
+	host->biu_clk = clk_get(host->dev, "biu");
+	if (IS_ERR(host->biu_clk))
+		dev_dbg(host->dev, "biu clock not available\n");
+	else
+		clk_prepare_enable(host->biu_clk);
+
+	host->ciu_clk = clk_get(host->dev, "ciu");
+	if (IS_ERR(host->ciu_clk))
+		dev_dbg(host->dev, "ciu clock not available\n");
+	else
+		clk_prepare_enable(host->ciu_clk);
+
+	if (IS_ERR(host->ciu_clk))
+		host->bus_hz = host->pdata->bus_hz;
+	else
+		host->bus_hz = clk_get_rate(host->ciu_clk);
+
+	if (!host->bus_hz) {
 		dev_err(host->dev,
 			"Platform data must supply bus speed\n");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto err_clk;
 	}
 
-	host->bus_hz = host->pdata->bus_hz;
 	host->quirks = host->pdata->quirks;
 
 	spin_lock_init(&host->lock);
 	INIT_LIST_HEAD(&host->queue);
 
+	host->dma_ops = host->pdata->dma_ops;
+	dw_mci_init_dma(host);
+
 	/*
 	 * Get the host data width - this assumes that HCON has been set with
 	 * the correct values.
@@ -2109,6 +2129,16 @@ err_dmaunmap:
 		regulator_disable(host->vmmc);
 		regulator_put(host->vmmc);
 	}
+
+err_clk:
+	if (!IS_ERR(host->ciu_clk)) {
+		clk_disable_unprepare(host->ciu_clk);
+		clk_put(host->ciu_clk);
+	}
+	if (!IS_ERR(host->biu_clk)) {
+		clk_disable_unprepare(host->biu_clk);
+		clk_put(host->biu_clk);
+	}
 	return ret;
 }
 EXPORT_SYMBOL(dw_mci_probe);
@@ -2142,6 +2172,12 @@ void dw_mci_remove(struct dw_mci *host)
 		regulator_put(host->vmmc);
 	}
 
+	if (!IS_ERR(host->ciu_clk))
+		clk_disable_unprepare(host->ciu_clk);
+	if (!IS_ERR(host->biu_clk))
+		clk_disable_unprepare(host->biu_clk);
+	clk_put(host->ciu_clk);
+	clk_put(host->biu_clk);
 }
 EXPORT_SYMBOL(dw_mci_remove);
 
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index a37a573..787ad56 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -78,6 +78,8 @@ struct mmc_data;
  * @data_offset: Set the offset of DATA register according to VERID.
  * @dev: Device associated with the MMC controller.
  * @pdata: Platform data associated with the MMC controller.
+ * @biu_clk: Pointer to bus interface unit clock instance.
+ * @ciu_clk: Pointer to card interface unit clock instance.
  * @slot: Slots sharing this MMC controller.
  * @fifo_depth: depth of FIFO.
  * @data_shift: log2 of FIFO item size.
@@ -158,6 +160,8 @@ struct dw_mci {
 	u16			data_offset;
 	struct device		*dev;
 	struct dw_mci_board	*pdata;
+	struct clk		*biu_clk;
+	struct clk		*ciu_clk;
 	struct dw_mci_slot	*slot[MAX_MCI_SLOTS];
 
 	/* FIFO push and pull */
-- 
1.6.6.rc2

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v3 3/6] mmc: dw_mmc: lookup for optional biu and ciu clocks
@ 2012-07-12 12:54   ` Thomas Abraham
  0 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-12 12:54 UTC (permalink / raw)
  To: linux-arm-kernel

Some platforms allow for clock gating and control of bus interface unit clock
and card interface unit clock. Add support for clock lookup of optional biu
and ciu clocks for clock gating and clock speed determination.

Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
---
 drivers/mmc/host/dw_mmc.c  |   42 +++++++++++++++++++++++++++++++++++++++---
 include/linux/mmc/dw_mmc.h |    4 ++++
 2 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index cd58063..679473c 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1953,18 +1953,38 @@ int dw_mci_probe(struct dw_mci *host)
 		return -ENODEV;
 	}
 
-	if (!host->pdata->bus_hz) {
+	host->biu_clk = clk_get(host->dev, "biu");
+	if (IS_ERR(host->biu_clk))
+		dev_dbg(host->dev, "biu clock not available\n");
+	else
+		clk_prepare_enable(host->biu_clk);
+
+	host->ciu_clk = clk_get(host->dev, "ciu");
+	if (IS_ERR(host->ciu_clk))
+		dev_dbg(host->dev, "ciu clock not available\n");
+	else
+		clk_prepare_enable(host->ciu_clk);
+
+	if (IS_ERR(host->ciu_clk))
+		host->bus_hz = host->pdata->bus_hz;
+	else
+		host->bus_hz = clk_get_rate(host->ciu_clk);
+
+	if (!host->bus_hz) {
 		dev_err(host->dev,
 			"Platform data must supply bus speed\n");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto err_clk;
 	}
 
-	host->bus_hz = host->pdata->bus_hz;
 	host->quirks = host->pdata->quirks;
 
 	spin_lock_init(&host->lock);
 	INIT_LIST_HEAD(&host->queue);
 
+	host->dma_ops = host->pdata->dma_ops;
+	dw_mci_init_dma(host);
+
 	/*
 	 * Get the host data width - this assumes that HCON has been set with
 	 * the correct values.
@@ -2109,6 +2129,16 @@ err_dmaunmap:
 		regulator_disable(host->vmmc);
 		regulator_put(host->vmmc);
 	}
+
+err_clk:
+	if (!IS_ERR(host->ciu_clk)) {
+		clk_disable_unprepare(host->ciu_clk);
+		clk_put(host->ciu_clk);
+	}
+	if (!IS_ERR(host->biu_clk)) {
+		clk_disable_unprepare(host->biu_clk);
+		clk_put(host->biu_clk);
+	}
 	return ret;
 }
 EXPORT_SYMBOL(dw_mci_probe);
@@ -2142,6 +2172,12 @@ void dw_mci_remove(struct dw_mci *host)
 		regulator_put(host->vmmc);
 	}
 
+	if (!IS_ERR(host->ciu_clk))
+		clk_disable_unprepare(host->ciu_clk);
+	if (!IS_ERR(host->biu_clk))
+		clk_disable_unprepare(host->biu_clk);
+	clk_put(host->ciu_clk);
+	clk_put(host->biu_clk);
 }
 EXPORT_SYMBOL(dw_mci_remove);
 
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index a37a573..787ad56 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -78,6 +78,8 @@ struct mmc_data;
  * @data_offset: Set the offset of DATA register according to VERID.
  * @dev: Device associated with the MMC controller.
  * @pdata: Platform data associated with the MMC controller.
+ * @biu_clk: Pointer to bus interface unit clock instance.
+ * @ciu_clk: Pointer to card interface unit clock instance.
  * @slot: Slots sharing this MMC controller.
  * @fifo_depth: depth of FIFO.
  * @data_shift: log2 of FIFO item size.
@@ -158,6 +160,8 @@ struct dw_mci {
 	u16			data_offset;
 	struct device		*dev;
 	struct dw_mci_board	*pdata;
+	struct clk		*biu_clk;
+	struct clk		*ciu_clk;
 	struct dw_mci_slot	*slot[MAX_MCI_SLOTS];
 
 	/* FIFO push and pull */
-- 
1.6.6.rc2

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v3 4/6] mmc: dw_mmc: add quirk to indicate missing write protect line
  2012-07-12 12:54 ` Thomas Abraham
@ 2012-07-12 12:54   ` Thomas Abraham
  -1 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-12 12:54 UTC (permalink / raw)
  To: linux-mmc, devicetree-discuss
  Cc: linux-kernel, linux-arm-kernel, cjb, grant.likely, rob.herring,
	linux-samsung-soc, kgene.kim, patches

If the write protect pad of the controller is not connected to the write
protect pin of the slot, the driver should be notified of this condition
so that incorrect check for write protection by reading the WRTORT
register can avoided. The get_ro platform callback can be used for in
such cases, but with device tree support enabled, such platform callbacks
cannot be supported.

Add a new quirk for notifying the driver about the missing write protect
line so the driver can assume that the card write protection is disabled.

Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
Acked-by: Will Newton <will.newton@imgtec.com>
---
 drivers/mmc/host/dw_mmc.c  |    4 +++-
 include/linux/mmc/dw_mmc.h |    3 ++-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 679473c..075f89d 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -827,7 +827,9 @@ static int dw_mci_get_ro(struct mmc_host *mmc)
 	struct dw_mci_board *brd = slot->host->pdata;
 
 	/* Use platform get_ro function, else try on board write protect */
-	if (brd->get_ro)
+	if (brd->quirks & DW_MCI_QUIRK_NO_WRITE_PROTECT)
+		read_only = 0;
+	else if (brd->get_ro)
 		read_only = brd->get_ro(slot->id);
 	else
 		read_only =
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index 787ad56..b72e4aa 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -205,7 +205,8 @@ struct dw_mci_dma_ops {
 #define DW_MCI_QUIRK_HIGHSPEED			BIT(2)
 /* Unreliable card detection */
 #define DW_MCI_QUIRK_BROKEN_CARD_DETECTION	BIT(3)
-
+/* Write Protect detection not available */
+#define DW_MCI_QUIRK_NO_WRITE_PROTECT		BIT(4)
 
 struct dma_pdata;
 
-- 
1.6.6.rc2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v3 4/6] mmc: dw_mmc: add quirk to indicate missing write protect line
@ 2012-07-12 12:54   ` Thomas Abraham
  0 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-12 12:54 UTC (permalink / raw)
  To: linux-arm-kernel

If the write protect pad of the controller is not connected to the write
protect pin of the slot, the driver should be notified of this condition
so that incorrect check for write protection by reading the WRTORT
register can avoided. The get_ro platform callback can be used for in
such cases, but with device tree support enabled, such platform callbacks
cannot be supported.

Add a new quirk for notifying the driver about the missing write protect
line so the driver can assume that the card write protection is disabled.

Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
Acked-by: Will Newton <will.newton@imgtec.com>
---
 drivers/mmc/host/dw_mmc.c  |    4 +++-
 include/linux/mmc/dw_mmc.h |    3 ++-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 679473c..075f89d 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -827,7 +827,9 @@ static int dw_mci_get_ro(struct mmc_host *mmc)
 	struct dw_mci_board *brd = slot->host->pdata;
 
 	/* Use platform get_ro function, else try on board write protect */
-	if (brd->get_ro)
+	if (brd->quirks & DW_MCI_QUIRK_NO_WRITE_PROTECT)
+		read_only = 0;
+	else if (brd->get_ro)
 		read_only = brd->get_ro(slot->id);
 	else
 		read_only =
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index 787ad56..b72e4aa 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -205,7 +205,8 @@ struct dw_mci_dma_ops {
 #define DW_MCI_QUIRK_HIGHSPEED			BIT(2)
 /* Unreliable card detection */
 #define DW_MCI_QUIRK_BROKEN_CARD_DETECTION	BIT(3)
-
+/* Write Protect detection not available */
+#define DW_MCI_QUIRK_NO_WRITE_PROTECT		BIT(4)
 
 struct dma_pdata;
 
-- 
1.6.6.rc2

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v3 5/6] mmc: dw_mmc: add device tree support
  2012-07-12 12:54 ` Thomas Abraham
@ 2012-07-12 12:54   ` Thomas Abraham
  -1 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-12 12:54 UTC (permalink / raw)
  To: linux-mmc, devicetree-discuss
  Cc: linux-kernel, linux-arm-kernel, cjb, grant.likely, rob.herring,
	linux-samsung-soc, kgene.kim, patches

Add device tree based discovery support.

Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
---
 .../devicetree/bindings/mmc/synposis-dw-mshc.txt   |  108 +++++++++++
 drivers/mmc/host/dw_mmc-pltfm.c                    |   24 +++
 drivers/mmc/host/dw_mmc.c                          |  201 +++++++++++++++++++-
 drivers/mmc/host/dw_mmc.h                          |    9 +
 include/linux/mmc/dw_mmc.h                         |    2 +
 5 files changed, 338 insertions(+), 6 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt

diff --git a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
new file mode 100644
index 0000000..3acd6c9
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
@@ -0,0 +1,108 @@
+* Synopsis Designware Mobile Storage Host Controller
+
+The Synopsis designware mobile storage host controller is used to interface
+a SoC with storage medium such as eMMC or SD/MMC cards.
+
+Required Properties:
+
+* compatible: should be one of the following
+	- snps,dw-mshc: for controllers compliant with synopsis dw-mshc.
+
+* reg: physical base address of the dw-mshc controller and size of its memory
+  region.
+
+* interrupts: interrupt specifier for the controller. The format and value of
+  the interrupt specifier depends on the interrupt parent for the controller.
+
+* #address-cells: should be 1.
+
+* #size-cells: should be 0.
+
+# Slots: The slot specific information are contained within child-nodes with
+  each child-node representing a supported slot. There should be atleast one
+  child node representing a card slot. The name of the child node representing
+  the slot is recommended to be slot@n where n is the unique number of the slot
+  connnected to the controller. The following are optional properties which
+  can be included in the slot child node.
+
+	* reg: specifies the physical slot number. The valid values of this
+	  property is 0 to (num-slots -1), where num-slots is the value
+	  specified by the num-slots property.
+
+	* bus-width: specifies the width of the data bus connected from the
+	  controller to the card slot. The value should be 1, 4 or 8. In case
+	  this property is not specified, a default value of 1 is assumed for
+	  this property.
+
+	* cd-gpios: specifies the card detect gpio line. The format of the
+	  gpio specifier depends on the gpio controller.
+
+	* wp-gpios: specifies the write protect gpio line. The format of the
+	  gpio specifier depends on the gpio controller.
+
+	* gpios: specifies a list of gpios used for command, clock and data
+	  bus. The first gpio is the command line and the second gpio is the
+	  clock line. The rest of the gpios (depending on the bus-width
+	  property) are the data lines in no particular order. The format of
+	  the gpio specifier depends on the gpio controller.
+
+Optional properties:
+
+* num-slots: specifies the number of slots supported by the controller.
+  The number of physical slots actually used could be equal or less than the
+  value specified by num-slots. If this property is not specified, the value
+  of num-slot property is assumed to be 1.
+
+* fifo-depth: The maximum size of the tx/rx fifo's. If this property is not
+  specified, the default value of the fifo size is determined from the
+  controller registers.
+
+* card-detect-delay: Delay in milli-seconds before detecting card after card
+  insert event. The default value is 0.
+
+* supports-highspeed: Enables support for high speed cards (upto 50MHz)
+
+* card-detection-broken: The card detection functionality is not available on
+  any of the slots.
+
+* no-write-protect: The write protect pad of the controller is not connected
+  to the write protect pin on the slot.
+
+Aliases:
+
+- All the MSHC controller nodes should be represented in the aliases node using
+  the following format 'mshc{n}' where n is a unique number for the alias.
+
+
+Example:
+
+  The MSHC controller node can be split into two portions, SoC specific and
+  board specific portions as listed below.
+
+	dwmmc0@12200000 {
+		compatible = "snps,dw-mshc";
+		reg = <0x12200000 0x1000>;
+		interrupts = <0 75 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+
+	dwmmc0@12200000 {
+		num-slots = <1>;
+		supports-highspeed;
+		card-detection-broken;
+		no-write-protect;
+		fifo-depth = <0x80>;
+		card-detect-delay = <200>;
+
+		slot@0 {
+			reg = <0>;
+			bus-width = <8>;
+			cd-gpios = <&gpc0 2 2 3 3>;
+			gpios = <&gpc0 0 2 0 3>, <&gpc0 1 2 0 3>,
+				<&gpc1 0 2 3 3>, <&gpc1 1 2 3 3>,
+				<&gpc1 2 2 3 3>, <&gpc1 3 2 3 3>,
+				<&gpc0 3 2 3 3>, <&gpc0 4 2 3 3>,
+				<&gpc0 5 2 3 3>, <&gpc0 6 2 3 3>;
+		};
+	};
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 9a63299..8d24f6d 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -19,8 +19,24 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/dw_mmc.h>
+#include <linux/of.h>
 #include "dw_mmc.h"
 
+#ifdef CONFIG_OF
+static struct dw_mci_drv_data synopsis_drv_data = {
+	.ctrl_type	= DW_MCI_TYPE_SYNOPSIS,
+};
+
+static const struct of_device_id dw_mci_pltfm_match[] = {
+	{ .compatible = "snps,dw-mshc",
+			.data = (void *)&synopsis_drv_data, },
+	{},
+};
+MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
+#else
+static const struct of_device_id dw_mci_pltfm_match[];
+#endif
+
 static int dw_mci_pltfm_probe(struct platform_device *pdev)
 {
 	struct dw_mci *host;
@@ -51,6 +67,13 @@ static int dw_mci_pltfm_probe(struct platform_device *pdev)
 	if (!host->regs)
 		goto err_free;
 	platform_set_drvdata(pdev, host);
+
+	if (pdev->dev.of_node) {
+		const struct of_device_id *match;
+		match = of_match_node(dw_mci_pltfm_match, pdev->dev.of_node);
+		host->drv_data = match->data;
+	}
+
 	ret = dw_mci_probe(host);
 	if (ret)
 		goto err_out;
@@ -111,6 +134,7 @@ static struct platform_driver dw_mci_pltfm_driver = {
 	.remove		= __exit_p(dw_mci_pltfm_remove),
 	.driver		= {
 		.name		= "dw_mmc",
+		.of_match_table	= of_match_ptr(dw_mci_pltfm_match),
 		.pm		= &dw_mci_pltfm_pmops,
 	},
 };
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 075f89d..3bc276d 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -33,9 +33,13 @@
 #include <linux/bitops.h>
 #include <linux/regulator/consumer.h>
 #include <linux/workqueue.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 
 #include "dw_mmc.h"
 
+#define NUM_PINS(x) (x + 2)
+
 /* Common flag combinations */
 #define DW_MCI_DATA_ERROR_FLAGS	(SDMMC_INT_DTO | SDMMC_INT_DCRC | \
 				 SDMMC_INT_HTO | SDMMC_INT_SBE  | \
@@ -86,6 +90,8 @@ struct idmac_desc {
 struct dw_mci_slot {
 	struct mmc_host		*mmc;
 	struct dw_mci		*host;
+	int			wp_gpio;
+	int			cd_gpio;
 
 	u32			ctype;
 
@@ -1762,10 +1768,106 @@ static void dw_mci_work_routine_card(struct work_struct *work)
 	}
 }
 
+#ifdef CONFIG_OF
+static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
+{
+	struct device_node *np;
+	const __be32 *addr;
+	int len;
+
+	if (!dev || !dev->of_node)
+		return NULL;
+
+	for_each_child_of_node(dev->of_node, np) {
+		addr = of_get_property(np, "reg", &len);
+		if (!addr || (len < sizeof(int)))
+			continue;
+		if (be32_to_cpup(addr) == slot)
+			return np;
+	}
+	return NULL;
+}
+
+static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
+{
+	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
+	u32 bus_wd = 1;
+
+	if (!np)
+		return 1;
+
+	if (of_property_read_u32(np, "bus-width", &bus_wd))
+		dev_err(dev, "bus-width property not found, assuming width"
+			       " as 1\n");
+	return bus_wd;
+}
+
+static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
+{
+	struct device_node *np = dw_mci_of_find_slot_node(host->dev, slot);
+	int idx, gpio, ret;
+
+	if (!np)
+		return -EINVAL;
+
+	for (idx = 0; idx < NUM_PINS(bus_wd); idx++) {
+		gpio = of_get_gpio(np, idx);
+		if (!gpio_is_valid(gpio)) {
+			dev_err(host->dev, "invalid gpio: %d\n", gpio);
+			return -EINVAL;
+		}
+
+		ret = devm_gpio_request(host->dev, gpio, "dw-mci-bus");
+		if (ret) {
+			dev_err(host->dev, "gpio [%d] request failed\n", gpio);
+			return -EBUSY;
+		}
+	}
+
+	host->slot[slot]->wp_gpio = -1;
+	gpio = of_get_named_gpio(np, "wp-gpios", 0);
+	if (!gpio_is_valid(gpio)) {
+		dev_info(host->dev, "wp gpio not available");
+	} else {
+		ret = devm_gpio_request(host->dev, gpio, "dw-mci-wp");
+		if (ret)
+			dev_info(host->dev, "gpio [%d] request failed\n",
+						gpio);
+		else
+			host->slot[slot]->wp_gpio = gpio;
+	}
+
+	host->slot[slot]->cd_gpio = -1;
+	gpio = of_get_named_gpio(np, "cd-gpios", 0);
+	if (!gpio_is_valid(gpio)) {
+		dev_info(host->dev, "cd gpio not available");
+	} else {
+		ret = devm_gpio_request(host->dev, gpio, "dw-mci-cd");
+		if (ret)
+			dev_err(host->dev, "gpio [%d] request failed\n", gpio);
+		else
+			host->slot[slot]->cd_gpio = gpio;
+	}
+
+	return 0;
+}
+#else /* CONFIG_OF */
+static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
+{
+	return 1;
+}
+
+static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
+{
+	return -EINVAL;
+}
+#endif /* CONFIG_OF */
+
 static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 {
 	struct mmc_host *mmc;
 	struct dw_mci_slot *slot;
+	int ctrl_id, ret;
 
 	mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
 	if (!mmc)
@@ -1775,6 +1877,7 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 	slot->id = id;
 	slot->mmc = mmc;
 	slot->host = host;
+	host->slot[id] = slot;
 
 	mmc->ops = &dw_mci_ops;
 	mmc->f_min = DIV_ROUND_UP(host->bus_hz, 510);
@@ -1795,12 +1898,33 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 	if (host->pdata->caps)
 		mmc->caps = host->pdata->caps;
 
+	if (host->dev->of_node) {
+		ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
+		if (ctrl_id < 0)
+			ctrl_id = 0;
+	}
+	if (host->drv_data->caps)
+		mmc->caps |= host->drv_data->caps[ctrl_id];
+
 	if (host->pdata->caps2)
 		mmc->caps2 = host->pdata->caps2;
 
-	if (host->pdata->get_bus_wd)
+	if (host->pdata->get_bus_wd) {
 		if (host->pdata->get_bus_wd(slot->id) >= 4)
 			mmc->caps |= MMC_CAP_4_BIT_DATA;
+	} else if (host->dev->of_node) {
+		unsigned int bus_width;
+		bus_width = dw_mci_of_get_bus_wd(host->dev, slot->id);
+		switch (bus_width) {
+		case 8:
+			mmc->caps |= MMC_CAP_8_BIT_DATA;
+		case 4:
+			mmc->caps |= MMC_CAP_4_BIT_DATA;
+		}
+		ret = dw_mci_of_setup_bus(host, slot->id, bus_width);
+		if (ret)
+			goto err_setup_bus;
+	}
 
 	if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED)
 		mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
@@ -1845,7 +1969,6 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 	else
 		clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
 
-	host->slot[id] = slot;
 	mmc_add_host(mmc);
 
 #if defined(CONFIG_DEBUG_FS)
@@ -1862,6 +1985,10 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 	queue_work(host->card_workqueue, &host->card_work);
 
 	return 0;
+
+err_setup_bus:
+	mmc_free_host(mmc);
+	return -EINVAL;
 }
 
 static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
@@ -1937,16 +2064,78 @@ static bool mci_wait_reset(struct device *dev, struct dw_mci *host)
 	return false;
 }
 
+#ifdef CONFIG_OF
+static struct dw_mci_of_quirks {
+	char *quirk;
+	int id;
+} of_quriks[] = {
+	{
+		.quirk	= "supports-highspeed",
+		.id	= DW_MCI_QUIRK_HIGHSPEED,
+	}, {
+		.quirk	= "card-detection-broken",
+		.id	= DW_MCI_QUIRK_BROKEN_CARD_DETECTION,
+	}, {
+		.quirk	= "no-write-protect",
+		.id	= DW_MCI_QUIRK_NO_WRITE_PROTECT,
+	}
+};
+
+static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
+{
+	struct dw_mci_board *pdata;
+	struct device *dev = host->dev;
+	struct device_node *np = dev->of_node;
+	int idx, cnt;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(dev, "could not allocate memory for pdata\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	/* find out number of slots supported */
+	if (of_property_read_u32(dev->of_node, "num-slots",
+				&pdata->num_slots)) {
+		dev_info(dev, "num-slots property not found, "
+				"assuming 1 slot is available\n");
+		pdata->num_slots = 1;
+	}
+
+	/* get quirks */
+	cnt = sizeof(of_quriks) / sizeof(struct dw_mci_of_quirks);
+	for (idx = 0; idx < cnt; idx++)
+		if (of_get_property(np, of_quriks[idx].quirk, NULL))
+			pdata->quirks |= of_quriks[idx].id;
+
+	if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
+		dev_info(dev, "fifo-depth property not found, using "
+				"value of FIFOTH register as default\n");
+
+	of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
+
+	return pdata;
+}
+
+#else /* CONFIG_OF */
+static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
+{
+	return ERR_PTR(-EINVAL);
+}
+#endif /* CONFIG_OF */
+
 int dw_mci_probe(struct dw_mci *host)
 {
 	int width, i, ret = 0;
 	u32 fifo_size;
 	int init_slots = 0;
 
-	if (!host->pdata || !host->pdata->init) {
-		dev_err(host->dev,
-			"Platform data must supply init function\n");
-		return -ENODEV;
+	if (!host->pdata) {
+		host->pdata = dw_mci_parse_dt(host);
+		if (IS_ERR(host->pdata)) {
+			dev_err(host->dev, "platform data not available\n");
+			return -EINVAL;
+		}
 	}
 
 	if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 15c27e1..1ecaa02 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -182,4 +182,13 @@ extern int dw_mci_suspend(struct dw_mci *host);
 extern int dw_mci_resume(struct dw_mci *host);
 #endif
 
+/* Variations in the dw_mci controller */
+#define DW_MCI_TYPE_SYNOPSIS		0
+
+/* dw_mci platform driver data */
+struct dw_mci_drv_data {
+	unsigned long		ctrl_type;
+	unsigned long		*caps;
+};
+
 #endif /* _DW_MMC_H_ */
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index b72e4aa..ae45e4f 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -78,6 +78,7 @@ struct mmc_data;
  * @data_offset: Set the offset of DATA register according to VERID.
  * @dev: Device associated with the MMC controller.
  * @pdata: Platform data associated with the MMC controller.
+ * @drv_data: Driver specific data for identified variant of the controller
  * @biu_clk: Pointer to bus interface unit clock instance.
  * @ciu_clk: Pointer to card interface unit clock instance.
  * @slot: Slots sharing this MMC controller.
@@ -160,6 +161,7 @@ struct dw_mci {
 	u16			data_offset;
 	struct device		*dev;
 	struct dw_mci_board	*pdata;
+	struct dw_mci_drv_data	*drv_data;
 	struct clk		*biu_clk;
 	struct clk		*ciu_clk;
 	struct dw_mci_slot	*slot[MAX_MCI_SLOTS];
-- 
1.6.6.rc2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v3 5/6] mmc: dw_mmc: add device tree support
@ 2012-07-12 12:54   ` Thomas Abraham
  0 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-12 12:54 UTC (permalink / raw)
  To: linux-arm-kernel

Add device tree based discovery support.

Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
---
 .../devicetree/bindings/mmc/synposis-dw-mshc.txt   |  108 +++++++++++
 drivers/mmc/host/dw_mmc-pltfm.c                    |   24 +++
 drivers/mmc/host/dw_mmc.c                          |  201 +++++++++++++++++++-
 drivers/mmc/host/dw_mmc.h                          |    9 +
 include/linux/mmc/dw_mmc.h                         |    2 +
 5 files changed, 338 insertions(+), 6 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt

diff --git a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
new file mode 100644
index 0000000..3acd6c9
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
@@ -0,0 +1,108 @@
+* Synopsis Designware Mobile Storage Host Controller
+
+The Synopsis designware mobile storage host controller is used to interface
+a SoC with storage medium such as eMMC or SD/MMC cards.
+
+Required Properties:
+
+* compatible: should be one of the following
+	- snps,dw-mshc: for controllers compliant with synopsis dw-mshc.
+
+* reg: physical base address of the dw-mshc controller and size of its memory
+  region.
+
+* interrupts: interrupt specifier for the controller. The format and value of
+  the interrupt specifier depends on the interrupt parent for the controller.
+
+* #address-cells: should be 1.
+
+* #size-cells: should be 0.
+
+# Slots: The slot specific information are contained within child-nodes with
+  each child-node representing a supported slot. There should be atleast one
+  child node representing a card slot. The name of the child node representing
+  the slot is recommended to be slot at n where n is the unique number of the slot
+  connnected to the controller. The following are optional properties which
+  can be included in the slot child node.
+
+	* reg: specifies the physical slot number. The valid values of this
+	  property is 0 to (num-slots -1), where num-slots is the value
+	  specified by the num-slots property.
+
+	* bus-width: specifies the width of the data bus connected from the
+	  controller to the card slot. The value should be 1, 4 or 8. In case
+	  this property is not specified, a default value of 1 is assumed for
+	  this property.
+
+	* cd-gpios: specifies the card detect gpio line. The format of the
+	  gpio specifier depends on the gpio controller.
+
+	* wp-gpios: specifies the write protect gpio line. The format of the
+	  gpio specifier depends on the gpio controller.
+
+	* gpios: specifies a list of gpios used for command, clock and data
+	  bus. The first gpio is the command line and the second gpio is the
+	  clock line. The rest of the gpios (depending on the bus-width
+	  property) are the data lines in no particular order. The format of
+	  the gpio specifier depends on the gpio controller.
+
+Optional properties:
+
+* num-slots: specifies the number of slots supported by the controller.
+  The number of physical slots actually used could be equal or less than the
+  value specified by num-slots. If this property is not specified, the value
+  of num-slot property is assumed to be 1.
+
+* fifo-depth: The maximum size of the tx/rx fifo's. If this property is not
+  specified, the default value of the fifo size is determined from the
+  controller registers.
+
+* card-detect-delay: Delay in milli-seconds before detecting card after card
+  insert event. The default value is 0.
+
+* supports-highspeed: Enables support for high speed cards (upto 50MHz)
+
+* card-detection-broken: The card detection functionality is not available on
+  any of the slots.
+
+* no-write-protect: The write protect pad of the controller is not connected
+  to the write protect pin on the slot.
+
+Aliases:
+
+- All the MSHC controller nodes should be represented in the aliases node using
+  the following format 'mshc{n}' where n is a unique number for the alias.
+
+
+Example:
+
+  The MSHC controller node can be split into two portions, SoC specific and
+  board specific portions as listed below.
+
+	dwmmc0 at 12200000 {
+		compatible = "snps,dw-mshc";
+		reg = <0x12200000 0x1000>;
+		interrupts = <0 75 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+
+	dwmmc0 at 12200000 {
+		num-slots = <1>;
+		supports-highspeed;
+		card-detection-broken;
+		no-write-protect;
+		fifo-depth = <0x80>;
+		card-detect-delay = <200>;
+
+		slot at 0 {
+			reg = <0>;
+			bus-width = <8>;
+			cd-gpios = <&gpc0 2 2 3 3>;
+			gpios = <&gpc0 0 2 0 3>, <&gpc0 1 2 0 3>,
+				<&gpc1 0 2 3 3>, <&gpc1 1 2 3 3>,
+				<&gpc1 2 2 3 3>, <&gpc1 3 2 3 3>,
+				<&gpc0 3 2 3 3>, <&gpc0 4 2 3 3>,
+				<&gpc0 5 2 3 3>, <&gpc0 6 2 3 3>;
+		};
+	};
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 9a63299..8d24f6d 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -19,8 +19,24 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/dw_mmc.h>
+#include <linux/of.h>
 #include "dw_mmc.h"
 
+#ifdef CONFIG_OF
+static struct dw_mci_drv_data synopsis_drv_data = {
+	.ctrl_type	= DW_MCI_TYPE_SYNOPSIS,
+};
+
+static const struct of_device_id dw_mci_pltfm_match[] = {
+	{ .compatible = "snps,dw-mshc",
+			.data = (void *)&synopsis_drv_data, },
+	{},
+};
+MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
+#else
+static const struct of_device_id dw_mci_pltfm_match[];
+#endif
+
 static int dw_mci_pltfm_probe(struct platform_device *pdev)
 {
 	struct dw_mci *host;
@@ -51,6 +67,13 @@ static int dw_mci_pltfm_probe(struct platform_device *pdev)
 	if (!host->regs)
 		goto err_free;
 	platform_set_drvdata(pdev, host);
+
+	if (pdev->dev.of_node) {
+		const struct of_device_id *match;
+		match = of_match_node(dw_mci_pltfm_match, pdev->dev.of_node);
+		host->drv_data = match->data;
+	}
+
 	ret = dw_mci_probe(host);
 	if (ret)
 		goto err_out;
@@ -111,6 +134,7 @@ static struct platform_driver dw_mci_pltfm_driver = {
 	.remove		= __exit_p(dw_mci_pltfm_remove),
 	.driver		= {
 		.name		= "dw_mmc",
+		.of_match_table	= of_match_ptr(dw_mci_pltfm_match),
 		.pm		= &dw_mci_pltfm_pmops,
 	},
 };
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 075f89d..3bc276d 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -33,9 +33,13 @@
 #include <linux/bitops.h>
 #include <linux/regulator/consumer.h>
 #include <linux/workqueue.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 
 #include "dw_mmc.h"
 
+#define NUM_PINS(x) (x + 2)
+
 /* Common flag combinations */
 #define DW_MCI_DATA_ERROR_FLAGS	(SDMMC_INT_DTO | SDMMC_INT_DCRC | \
 				 SDMMC_INT_HTO | SDMMC_INT_SBE  | \
@@ -86,6 +90,8 @@ struct idmac_desc {
 struct dw_mci_slot {
 	struct mmc_host		*mmc;
 	struct dw_mci		*host;
+	int			wp_gpio;
+	int			cd_gpio;
 
 	u32			ctype;
 
@@ -1762,10 +1768,106 @@ static void dw_mci_work_routine_card(struct work_struct *work)
 	}
 }
 
+#ifdef CONFIG_OF
+static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
+{
+	struct device_node *np;
+	const __be32 *addr;
+	int len;
+
+	if (!dev || !dev->of_node)
+		return NULL;
+
+	for_each_child_of_node(dev->of_node, np) {
+		addr = of_get_property(np, "reg", &len);
+		if (!addr || (len < sizeof(int)))
+			continue;
+		if (be32_to_cpup(addr) == slot)
+			return np;
+	}
+	return NULL;
+}
+
+static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
+{
+	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
+	u32 bus_wd = 1;
+
+	if (!np)
+		return 1;
+
+	if (of_property_read_u32(np, "bus-width", &bus_wd))
+		dev_err(dev, "bus-width property not found, assuming width"
+			       " as 1\n");
+	return bus_wd;
+}
+
+static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
+{
+	struct device_node *np = dw_mci_of_find_slot_node(host->dev, slot);
+	int idx, gpio, ret;
+
+	if (!np)
+		return -EINVAL;
+
+	for (idx = 0; idx < NUM_PINS(bus_wd); idx++) {
+		gpio = of_get_gpio(np, idx);
+		if (!gpio_is_valid(gpio)) {
+			dev_err(host->dev, "invalid gpio: %d\n", gpio);
+			return -EINVAL;
+		}
+
+		ret = devm_gpio_request(host->dev, gpio, "dw-mci-bus");
+		if (ret) {
+			dev_err(host->dev, "gpio [%d] request failed\n", gpio);
+			return -EBUSY;
+		}
+	}
+
+	host->slot[slot]->wp_gpio = -1;
+	gpio = of_get_named_gpio(np, "wp-gpios", 0);
+	if (!gpio_is_valid(gpio)) {
+		dev_info(host->dev, "wp gpio not available");
+	} else {
+		ret = devm_gpio_request(host->dev, gpio, "dw-mci-wp");
+		if (ret)
+			dev_info(host->dev, "gpio [%d] request failed\n",
+						gpio);
+		else
+			host->slot[slot]->wp_gpio = gpio;
+	}
+
+	host->slot[slot]->cd_gpio = -1;
+	gpio = of_get_named_gpio(np, "cd-gpios", 0);
+	if (!gpio_is_valid(gpio)) {
+		dev_info(host->dev, "cd gpio not available");
+	} else {
+		ret = devm_gpio_request(host->dev, gpio, "dw-mci-cd");
+		if (ret)
+			dev_err(host->dev, "gpio [%d] request failed\n", gpio);
+		else
+			host->slot[slot]->cd_gpio = gpio;
+	}
+
+	return 0;
+}
+#else /* CONFIG_OF */
+static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
+{
+	return 1;
+}
+
+static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
+{
+	return -EINVAL;
+}
+#endif /* CONFIG_OF */
+
 static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 {
 	struct mmc_host *mmc;
 	struct dw_mci_slot *slot;
+	int ctrl_id, ret;
 
 	mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
 	if (!mmc)
@@ -1775,6 +1877,7 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 	slot->id = id;
 	slot->mmc = mmc;
 	slot->host = host;
+	host->slot[id] = slot;
 
 	mmc->ops = &dw_mci_ops;
 	mmc->f_min = DIV_ROUND_UP(host->bus_hz, 510);
@@ -1795,12 +1898,33 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 	if (host->pdata->caps)
 		mmc->caps = host->pdata->caps;
 
+	if (host->dev->of_node) {
+		ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
+		if (ctrl_id < 0)
+			ctrl_id = 0;
+	}
+	if (host->drv_data->caps)
+		mmc->caps |= host->drv_data->caps[ctrl_id];
+
 	if (host->pdata->caps2)
 		mmc->caps2 = host->pdata->caps2;
 
-	if (host->pdata->get_bus_wd)
+	if (host->pdata->get_bus_wd) {
 		if (host->pdata->get_bus_wd(slot->id) >= 4)
 			mmc->caps |= MMC_CAP_4_BIT_DATA;
+	} else if (host->dev->of_node) {
+		unsigned int bus_width;
+		bus_width = dw_mci_of_get_bus_wd(host->dev, slot->id);
+		switch (bus_width) {
+		case 8:
+			mmc->caps |= MMC_CAP_8_BIT_DATA;
+		case 4:
+			mmc->caps |= MMC_CAP_4_BIT_DATA;
+		}
+		ret = dw_mci_of_setup_bus(host, slot->id, bus_width);
+		if (ret)
+			goto err_setup_bus;
+	}
 
 	if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED)
 		mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
@@ -1845,7 +1969,6 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 	else
 		clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
 
-	host->slot[id] = slot;
 	mmc_add_host(mmc);
 
 #if defined(CONFIG_DEBUG_FS)
@@ -1862,6 +1985,10 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 	queue_work(host->card_workqueue, &host->card_work);
 
 	return 0;
+
+err_setup_bus:
+	mmc_free_host(mmc);
+	return -EINVAL;
 }
 
 static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
@@ -1937,16 +2064,78 @@ static bool mci_wait_reset(struct device *dev, struct dw_mci *host)
 	return false;
 }
 
+#ifdef CONFIG_OF
+static struct dw_mci_of_quirks {
+	char *quirk;
+	int id;
+} of_quriks[] = {
+	{
+		.quirk	= "supports-highspeed",
+		.id	= DW_MCI_QUIRK_HIGHSPEED,
+	}, {
+		.quirk	= "card-detection-broken",
+		.id	= DW_MCI_QUIRK_BROKEN_CARD_DETECTION,
+	}, {
+		.quirk	= "no-write-protect",
+		.id	= DW_MCI_QUIRK_NO_WRITE_PROTECT,
+	}
+};
+
+static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
+{
+	struct dw_mci_board *pdata;
+	struct device *dev = host->dev;
+	struct device_node *np = dev->of_node;
+	int idx, cnt;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(dev, "could not allocate memory for pdata\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	/* find out number of slots supported */
+	if (of_property_read_u32(dev->of_node, "num-slots",
+				&pdata->num_slots)) {
+		dev_info(dev, "num-slots property not found, "
+				"assuming 1 slot is available\n");
+		pdata->num_slots = 1;
+	}
+
+	/* get quirks */
+	cnt = sizeof(of_quriks) / sizeof(struct dw_mci_of_quirks);
+	for (idx = 0; idx < cnt; idx++)
+		if (of_get_property(np, of_quriks[idx].quirk, NULL))
+			pdata->quirks |= of_quriks[idx].id;
+
+	if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
+		dev_info(dev, "fifo-depth property not found, using "
+				"value of FIFOTH register as default\n");
+
+	of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
+
+	return pdata;
+}
+
+#else /* CONFIG_OF */
+static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
+{
+	return ERR_PTR(-EINVAL);
+}
+#endif /* CONFIG_OF */
+
 int dw_mci_probe(struct dw_mci *host)
 {
 	int width, i, ret = 0;
 	u32 fifo_size;
 	int init_slots = 0;
 
-	if (!host->pdata || !host->pdata->init) {
-		dev_err(host->dev,
-			"Platform data must supply init function\n");
-		return -ENODEV;
+	if (!host->pdata) {
+		host->pdata = dw_mci_parse_dt(host);
+		if (IS_ERR(host->pdata)) {
+			dev_err(host->dev, "platform data not available\n");
+			return -EINVAL;
+		}
 	}
 
 	if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 15c27e1..1ecaa02 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -182,4 +182,13 @@ extern int dw_mci_suspend(struct dw_mci *host);
 extern int dw_mci_resume(struct dw_mci *host);
 #endif
 
+/* Variations in the dw_mci controller */
+#define DW_MCI_TYPE_SYNOPSIS		0
+
+/* dw_mci platform driver data */
+struct dw_mci_drv_data {
+	unsigned long		ctrl_type;
+	unsigned long		*caps;
+};
+
 #endif /* _DW_MMC_H_ */
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index b72e4aa..ae45e4f 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -78,6 +78,7 @@ struct mmc_data;
  * @data_offset: Set the offset of DATA register according to VERID.
  * @dev: Device associated with the MMC controller.
  * @pdata: Platform data associated with the MMC controller.
+ * @drv_data: Driver specific data for identified variant of the controller
  * @biu_clk: Pointer to bus interface unit clock instance.
  * @ciu_clk: Pointer to card interface unit clock instance.
  * @slot: Slots sharing this MMC controller.
@@ -160,6 +161,7 @@ struct dw_mci {
 	u16			data_offset;
 	struct device		*dev;
 	struct dw_mci_board	*pdata;
+	struct dw_mci_drv_data	*drv_data;
 	struct clk		*biu_clk;
 	struct clk		*ciu_clk;
 	struct dw_mci_slot	*slot[MAX_MCI_SLOTS];
-- 
1.6.6.rc2

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v3 6/6] mmc: dw_mmc: add samsung exynos5250 specific extentions
  2012-07-12 12:54 ` Thomas Abraham
@ 2012-07-12 12:54   ` Thomas Abraham
  -1 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-12 12:54 UTC (permalink / raw)
  To: linux-mmc, devicetree-discuss
  Cc: linux-kernel, linux-arm-kernel, cjb, grant.likely, rob.herring,
	linux-samsung-soc, kgene.kim, patches

The instantiation of the Synopsis Designware controller on Exynos5250
include extension for SDR and DDR specific tx/rx phase shift timing
and CIU internal divider. In addition to that, the option to skip the
command hold stage is also introduced. Add support for these Exynos5250
specfic extenstions.

Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
---
 .../devicetree/bindings/mmc/synposis-dw-mshc.txt   |   38 ++++++++++++++++++-
 drivers/mmc/host/dw_mmc-pltfm.c                    |   15 +++++++
 drivers/mmc/host/dw_mmc.c                          |   40 +++++++++++++++++++-
 drivers/mmc/host/dw_mmc.h                          |   14 +++++++
 include/linux/mmc/dw_mmc.h                         |    6 +++
 5 files changed, 110 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
index 3acd6c9..69d78c1 100644
--- a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
+++ b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
@@ -7,6 +7,8 @@ Required Properties:
 
 * compatible: should be one of the following
 	- snps,dw-mshc: for controllers compliant with synopsis dw-mshc.
+	- samsung,exynos5250-dw-mshc: for controllers with Samsung
+	  Exynos5250 specific extentions.
 
 * reg: physical base address of the dw-mshc controller and size of its memory
   region.
@@ -74,13 +76,45 @@ Aliases:
   the following format 'mshc{n}' where n is a unique number for the alias.
 
 
+Samsung Exynos4/5 specific properties:
+
+Some of the variants of Exynos4 (such as Exynos4412) and Exynos5 SoC's
+includes few extensions to the Synopsis Designware Mobile Storage Host
+Controller. The following properties are used to describe those extensions.
+
+* samsung,dw-mshc-sdr-timing: Specifies the value of CUI clock divider, CIU
+  clock phase shift value in transmit mode and CIU clock phase shift value in
+  receive mode for single data rate mode operation. Refer notes of the valid
+  values below.
+
+* samsung,dw-mshc-ddr-timing: Specifies the value of CUI clock divider, CIU
+  clock phase shift value in transmit mode and CIU clock phase shift value in
+  receive mode for double data rate mode operation. Refer notes of the valid
+  values below. The order of the cells should be
+
+    - First Cell: 	CIU clock divider value (applicable only for Exynos5
+			SoC's, should be zero for Exynos4 SoC's)
+    - Second Cell:	CIU clock phase shift value for tx mode.
+    - Third Cell:	CIU clock phase shift value for rx mode.
+
+  Valid values for SDR and DDR CIU clock timing for Exynos5250:
+
+    - valid values for CIU clock divider, tx phase shift and rx phase shift
+      is 0 to 7.
+
+    - When CIU clock divider value is set to 3, all possible 8 phase shift
+      values can be used.
+
+    - If CIU clock divider value is 0 (that is divide by 1), both tx and rx
+      phase shift clocks should be 0.
+
 Example:
 
   The MSHC controller node can be split into two portions, SoC specific and
   board specific portions as listed below.
 
 	dwmmc0@12200000 {
-		compatible = "snps,dw-mshc";
+		compatible = "samsung,exynos5250-dw-mshc";
 		reg = <0x12200000 0x1000>;
 		interrupts = <0 75 0>;
 		#address-cells = <1>;
@@ -94,6 +128,8 @@ Example:
 		no-write-protect;
 		fifo-depth = <0x80>;
 		card-detect-delay = <200>;
+		samsung,dw-mshc-sdr-timing = <2 3 3>;
+		samsung,dw-mshc-ddr-timing = <1 2 3>;
 
 		slot@0 {
 			reg = <0>;
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 8d24f6d..900f412 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -27,9 +27,24 @@ static struct dw_mci_drv_data synopsis_drv_data = {
 	.ctrl_type	= DW_MCI_TYPE_SYNOPSIS,
 };
 
+static unsigned long exynos5250_dwmmc_caps[4] = {
+	MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
+		MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
+	MMC_CAP_CMD23,
+	MMC_CAP_CMD23,
+	MMC_CAP_CMD23,
+};
+
+static struct dw_mci_drv_data exynos5250_drv_data = {
+	.ctrl_type	= DW_MCI_TYPE_EXYNOS5250,
+	.caps		= exynos5250_dwmmc_caps,
+};
+
 static const struct of_device_id dw_mci_pltfm_match[] = {
 	{ .compatible = "snps,dw-mshc",
 			.data = (void *)&synopsis_drv_data, },
+	{ .compatible = "samsung,exynos5250-dw-mshc",
+			.data = (void *)&exynos5250_drv_data, },
 	{},
 };
 MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 3bc276d..bbf1209 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -236,6 +236,7 @@ static void dw_mci_set_timeout(struct dw_mci *host)
 static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
 {
 	struct mmc_data	*data;
+	struct dw_mci_slot *slot = mmc_priv(mmc);
 	u32 cmdr;
 	cmd->error = -EINPROGRESS;
 
@@ -265,6 +266,17 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
 			cmdr |= SDMMC_CMD_DAT_WR;
 	}
 
+	/*
+	 * Samsung Exynos5250 extends the use of CMD register with the use of
+	 * bit 29 (which is reserved on standard MSHC controllers) for
+	 * optionally bypassing the HOLD register for command and data. The
+	 * HOLD register should be bypassed in case there is no phase shift
+	 * applied on CMD/DATA that is sent to the card.
+	 */
+	if (slot->host->drv_data->ctrl_type == DW_MCI_TYPE_EXYNOS5250)
+		if (SDMMC_CLKSEL_GET_SELCLK_DRV(mci_readl(slot->host, CLKSEL)))
+			cmdr |= SDMMC_CMD_USE_HOLD_REG;
+
 	return cmdr;
 }
 
@@ -802,10 +814,19 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	regs = mci_readl(slot->host, UHS_REG);
 
 	/* DDR mode set */
-	if (ios->timing == MMC_TIMING_UHS_DDR50)
+	if (ios->timing == MMC_TIMING_UHS_DDR50) {
 		regs |= (0x1 << slot->id) << 16;
-	else
+		mci_writel(slot->host, CLKSEL, slot->host->ddr_timing);
+	} else {
 		regs &= ~(0x1 << slot->id) << 16;
+		mci_writel(slot->host, CLKSEL, slot->host->sdr_timing);
+	}
+
+	if (slot->host->drv_data->ctrl_type == DW_MCI_TYPE_EXYNOS5250) {
+		slot->host->bus_hz = clk_get_rate(slot->host->ciu_clk);
+		slot->host->bus_hz /= SDMMC_CLKSEL_GET_DIVRATIO(
+					mci_readl(slot->host, CLKSEL));
+	}
 
 	mci_writel(slot->host, UHS_REG, regs);
 
@@ -2086,6 +2107,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
 	struct dw_mci_board *pdata;
 	struct device *dev = host->dev;
 	struct device_node *np = dev->of_node;
+	u32 timing[3];
 	int idx, cnt;
 
 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
@@ -2108,6 +2130,20 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
 		if (of_get_property(np, of_quriks[idx].quirk, NULL))
 			pdata->quirks |= of_quriks[idx].id;
 
+	if (of_property_read_u32_array(dev->of_node,
+			"samsung,dw-mshc-sdr-timing", timing, 3))
+		host->sdr_timing = DW_MCI_DEF_SDR_TIMING;
+	else
+		host->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0],
+					timing[1], timing[2]);
+
+	if (of_property_read_u32_array(dev->of_node,
+			"samsung,dw-mshc-ddr-timing", timing, 3))
+		host->ddr_timing = DW_MCI_DEF_DDR_TIMING;
+	else
+		host->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0],
+					timing[1], timing[2]);
+
 	if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
 		dev_info(dev, "fifo-depth property not found, using "
 				"value of FIFOTH register as default\n");
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 1ecaa02..6c17282 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -53,6 +53,7 @@
 #define SDMMC_IDINTEN		0x090
 #define SDMMC_DSCADDR		0x094
 #define SDMMC_BUFADDR		0x098
+#define SDMMC_CLKSEL		0x09C /* specific to Samsung Exynos5250 */
 #define SDMMC_DATA(x)		(x)
 
 /*
@@ -111,6 +112,7 @@
 #define SDMMC_INT_ERROR			0xbfc2
 /* Command register defines */
 #define SDMMC_CMD_START			BIT(31)
+#define SDMMC_CMD_USE_HOLD_REG		BIT(29)
 #define SDMMC_CMD_CCS_EXP		BIT(23)
 #define SDMMC_CMD_CEATA_RD		BIT(22)
 #define SDMMC_CMD_UPD_CLK		BIT(21)
@@ -142,6 +144,17 @@
 /* Version ID register define */
 #define SDMMC_GET_VERID(x)		((x) & 0xFFFF)
 
+#define DW_MCI_DEF_SDR_TIMING		0x03030002
+#define DW_MCI_DEF_DDR_TIMING		0x03020001
+#define SDMMC_CLKSEL_CCLK_SAMPLE(x)	(((x) & 3) << 0)
+#define SDMMC_CLKSEL_CCLK_DRIVE(x)	(((x) & 3) << 16)
+#define SDMMC_CLKSEL_CCLK_DIVIDER(x)	(((x) & 3) << 24)
+#define SDMMC_CLKSEL_TIMING(x, y, z)	(SDMMC_CLKSEL_CCLK_SAMPLE(x) |	\
+					SDMMC_CLKSEL_CCLK_DRIVE(y) |	\
+					SDMMC_CLKSEL_CCLK_DIVIDER(z))
+#define SDMMC_CLKSEL_GET_DIVRATIO(x)	((((x) >> 24) & 0x7) + 1)
+#define SDMMC_CLKSEL_GET_SELCLK_DRV(x)	(((x) >> 16) & 0x7)
+
 /* Register access macros */
 #define mci_readl(dev, reg)			\
 	__raw_readl((dev)->regs + SDMMC_##reg)
@@ -184,6 +197,7 @@ extern int dw_mci_resume(struct dw_mci *host);
 
 /* Variations in the dw_mci controller */
 #define DW_MCI_TYPE_SYNOPSIS		0
+#define DW_MCI_TYPE_EXYNOS5250		1 /* Samsung Exynos5250 Extensions */
 
 /* dw_mci platform driver data */
 struct dw_mci_drv_data {
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index ae45e4f..32c778f 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -82,6 +82,8 @@ struct mmc_data;
  * @biu_clk: Pointer to bus interface unit clock instance.
  * @ciu_clk: Pointer to card interface unit clock instance.
  * @slot: Slots sharing this MMC controller.
+ * @sdr_timing: Clock phase shifting for driving and sampling in sdr mode
+ * @ddr_timing: Clock phase shifting for driving and sampling in ddr mode
  * @fifo_depth: depth of FIFO.
  * @data_shift: log2 of FIFO item size.
  * @part_buf_start: Start index in part_buf.
@@ -166,6 +168,10 @@ struct dw_mci {
 	struct clk		*ciu_clk;
 	struct dw_mci_slot	*slot[MAX_MCI_SLOTS];
 
+	/* Phase Shift Value (for exynos5250 variant) */
+	u32			sdr_timing;
+	u32			ddr_timing;
+
 	/* FIFO push and pull */
 	int			fifo_depth;
 	int			data_shift;
-- 
1.6.6.rc2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v3 6/6] mmc: dw_mmc: add samsung exynos5250 specific extentions
@ 2012-07-12 12:54   ` Thomas Abraham
  0 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-12 12:54 UTC (permalink / raw)
  To: linux-arm-kernel

The instantiation of the Synopsis Designware controller on Exynos5250
include extension for SDR and DDR specific tx/rx phase shift timing
and CIU internal divider. In addition to that, the option to skip the
command hold stage is also introduced. Add support for these Exynos5250
specfic extenstions.

Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
---
 .../devicetree/bindings/mmc/synposis-dw-mshc.txt   |   38 ++++++++++++++++++-
 drivers/mmc/host/dw_mmc-pltfm.c                    |   15 +++++++
 drivers/mmc/host/dw_mmc.c                          |   40 +++++++++++++++++++-
 drivers/mmc/host/dw_mmc.h                          |   14 +++++++
 include/linux/mmc/dw_mmc.h                         |    6 +++
 5 files changed, 110 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
index 3acd6c9..69d78c1 100644
--- a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
+++ b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
@@ -7,6 +7,8 @@ Required Properties:
 
 * compatible: should be one of the following
 	- snps,dw-mshc: for controllers compliant with synopsis dw-mshc.
+	- samsung,exynos5250-dw-mshc: for controllers with Samsung
+	  Exynos5250 specific extentions.
 
 * reg: physical base address of the dw-mshc controller and size of its memory
   region.
@@ -74,13 +76,45 @@ Aliases:
   the following format 'mshc{n}' where n is a unique number for the alias.
 
 
+Samsung Exynos4/5 specific properties:
+
+Some of the variants of Exynos4 (such as Exynos4412) and Exynos5 SoC's
+includes few extensions to the Synopsis Designware Mobile Storage Host
+Controller. The following properties are used to describe those extensions.
+
+* samsung,dw-mshc-sdr-timing: Specifies the value of CUI clock divider, CIU
+  clock phase shift value in transmit mode and CIU clock phase shift value in
+  receive mode for single data rate mode operation. Refer notes of the valid
+  values below.
+
+* samsung,dw-mshc-ddr-timing: Specifies the value of CUI clock divider, CIU
+  clock phase shift value in transmit mode and CIU clock phase shift value in
+  receive mode for double data rate mode operation. Refer notes of the valid
+  values below. The order of the cells should be
+
+    - First Cell: 	CIU clock divider value (applicable only for Exynos5
+			SoC's, should be zero for Exynos4 SoC's)
+    - Second Cell:	CIU clock phase shift value for tx mode.
+    - Third Cell:	CIU clock phase shift value for rx mode.
+
+  Valid values for SDR and DDR CIU clock timing for Exynos5250:
+
+    - valid values for CIU clock divider, tx phase shift and rx phase shift
+      is 0 to 7.
+
+    - When CIU clock divider value is set to 3, all possible 8 phase shift
+      values can be used.
+
+    - If CIU clock divider value is 0 (that is divide by 1), both tx and rx
+      phase shift clocks should be 0.
+
 Example:
 
   The MSHC controller node can be split into two portions, SoC specific and
   board specific portions as listed below.
 
 	dwmmc0 at 12200000 {
-		compatible = "snps,dw-mshc";
+		compatible = "samsung,exynos5250-dw-mshc";
 		reg = <0x12200000 0x1000>;
 		interrupts = <0 75 0>;
 		#address-cells = <1>;
@@ -94,6 +128,8 @@ Example:
 		no-write-protect;
 		fifo-depth = <0x80>;
 		card-detect-delay = <200>;
+		samsung,dw-mshc-sdr-timing = <2 3 3>;
+		samsung,dw-mshc-ddr-timing = <1 2 3>;
 
 		slot at 0 {
 			reg = <0>;
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 8d24f6d..900f412 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -27,9 +27,24 @@ static struct dw_mci_drv_data synopsis_drv_data = {
 	.ctrl_type	= DW_MCI_TYPE_SYNOPSIS,
 };
 
+static unsigned long exynos5250_dwmmc_caps[4] = {
+	MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
+		MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
+	MMC_CAP_CMD23,
+	MMC_CAP_CMD23,
+	MMC_CAP_CMD23,
+};
+
+static struct dw_mci_drv_data exynos5250_drv_data = {
+	.ctrl_type	= DW_MCI_TYPE_EXYNOS5250,
+	.caps		= exynos5250_dwmmc_caps,
+};
+
 static const struct of_device_id dw_mci_pltfm_match[] = {
 	{ .compatible = "snps,dw-mshc",
 			.data = (void *)&synopsis_drv_data, },
+	{ .compatible = "samsung,exynos5250-dw-mshc",
+			.data = (void *)&exynos5250_drv_data, },
 	{},
 };
 MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 3bc276d..bbf1209 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -236,6 +236,7 @@ static void dw_mci_set_timeout(struct dw_mci *host)
 static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
 {
 	struct mmc_data	*data;
+	struct dw_mci_slot *slot = mmc_priv(mmc);
 	u32 cmdr;
 	cmd->error = -EINPROGRESS;
 
@@ -265,6 +266,17 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
 			cmdr |= SDMMC_CMD_DAT_WR;
 	}
 
+	/*
+	 * Samsung Exynos5250 extends the use of CMD register with the use of
+	 * bit 29 (which is reserved on standard MSHC controllers) for
+	 * optionally bypassing the HOLD register for command and data. The
+	 * HOLD register should be bypassed in case there is no phase shift
+	 * applied on CMD/DATA that is sent to the card.
+	 */
+	if (slot->host->drv_data->ctrl_type == DW_MCI_TYPE_EXYNOS5250)
+		if (SDMMC_CLKSEL_GET_SELCLK_DRV(mci_readl(slot->host, CLKSEL)))
+			cmdr |= SDMMC_CMD_USE_HOLD_REG;
+
 	return cmdr;
 }
 
@@ -802,10 +814,19 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	regs = mci_readl(slot->host, UHS_REG);
 
 	/* DDR mode set */
-	if (ios->timing == MMC_TIMING_UHS_DDR50)
+	if (ios->timing == MMC_TIMING_UHS_DDR50) {
 		regs |= (0x1 << slot->id) << 16;
-	else
+		mci_writel(slot->host, CLKSEL, slot->host->ddr_timing);
+	} else {
 		regs &= ~(0x1 << slot->id) << 16;
+		mci_writel(slot->host, CLKSEL, slot->host->sdr_timing);
+	}
+
+	if (slot->host->drv_data->ctrl_type == DW_MCI_TYPE_EXYNOS5250) {
+		slot->host->bus_hz = clk_get_rate(slot->host->ciu_clk);
+		slot->host->bus_hz /= SDMMC_CLKSEL_GET_DIVRATIO(
+					mci_readl(slot->host, CLKSEL));
+	}
 
 	mci_writel(slot->host, UHS_REG, regs);
 
@@ -2086,6 +2107,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
 	struct dw_mci_board *pdata;
 	struct device *dev = host->dev;
 	struct device_node *np = dev->of_node;
+	u32 timing[3];
 	int idx, cnt;
 
 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
@@ -2108,6 +2130,20 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
 		if (of_get_property(np, of_quriks[idx].quirk, NULL))
 			pdata->quirks |= of_quriks[idx].id;
 
+	if (of_property_read_u32_array(dev->of_node,
+			"samsung,dw-mshc-sdr-timing", timing, 3))
+		host->sdr_timing = DW_MCI_DEF_SDR_TIMING;
+	else
+		host->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0],
+					timing[1], timing[2]);
+
+	if (of_property_read_u32_array(dev->of_node,
+			"samsung,dw-mshc-ddr-timing", timing, 3))
+		host->ddr_timing = DW_MCI_DEF_DDR_TIMING;
+	else
+		host->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0],
+					timing[1], timing[2]);
+
 	if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
 		dev_info(dev, "fifo-depth property not found, using "
 				"value of FIFOTH register as default\n");
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 1ecaa02..6c17282 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -53,6 +53,7 @@
 #define SDMMC_IDINTEN		0x090
 #define SDMMC_DSCADDR		0x094
 #define SDMMC_BUFADDR		0x098
+#define SDMMC_CLKSEL		0x09C /* specific to Samsung Exynos5250 */
 #define SDMMC_DATA(x)		(x)
 
 /*
@@ -111,6 +112,7 @@
 #define SDMMC_INT_ERROR			0xbfc2
 /* Command register defines */
 #define SDMMC_CMD_START			BIT(31)
+#define SDMMC_CMD_USE_HOLD_REG		BIT(29)
 #define SDMMC_CMD_CCS_EXP		BIT(23)
 #define SDMMC_CMD_CEATA_RD		BIT(22)
 #define SDMMC_CMD_UPD_CLK		BIT(21)
@@ -142,6 +144,17 @@
 /* Version ID register define */
 #define SDMMC_GET_VERID(x)		((x) & 0xFFFF)
 
+#define DW_MCI_DEF_SDR_TIMING		0x03030002
+#define DW_MCI_DEF_DDR_TIMING		0x03020001
+#define SDMMC_CLKSEL_CCLK_SAMPLE(x)	(((x) & 3) << 0)
+#define SDMMC_CLKSEL_CCLK_DRIVE(x)	(((x) & 3) << 16)
+#define SDMMC_CLKSEL_CCLK_DIVIDER(x)	(((x) & 3) << 24)
+#define SDMMC_CLKSEL_TIMING(x, y, z)	(SDMMC_CLKSEL_CCLK_SAMPLE(x) |	\
+					SDMMC_CLKSEL_CCLK_DRIVE(y) |	\
+					SDMMC_CLKSEL_CCLK_DIVIDER(z))
+#define SDMMC_CLKSEL_GET_DIVRATIO(x)	((((x) >> 24) & 0x7) + 1)
+#define SDMMC_CLKSEL_GET_SELCLK_DRV(x)	(((x) >> 16) & 0x7)
+
 /* Register access macros */
 #define mci_readl(dev, reg)			\
 	__raw_readl((dev)->regs + SDMMC_##reg)
@@ -184,6 +197,7 @@ extern int dw_mci_resume(struct dw_mci *host);
 
 /* Variations in the dw_mci controller */
 #define DW_MCI_TYPE_SYNOPSIS		0
+#define DW_MCI_TYPE_EXYNOS5250		1 /* Samsung Exynos5250 Extensions */
 
 /* dw_mci platform driver data */
 struct dw_mci_drv_data {
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index ae45e4f..32c778f 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -82,6 +82,8 @@ struct mmc_data;
  * @biu_clk: Pointer to bus interface unit clock instance.
  * @ciu_clk: Pointer to card interface unit clock instance.
  * @slot: Slots sharing this MMC controller.
+ * @sdr_timing: Clock phase shifting for driving and sampling in sdr mode
+ * @ddr_timing: Clock phase shifting for driving and sampling in ddr mode
  * @fifo_depth: depth of FIFO.
  * @data_shift: log2 of FIFO item size.
  * @part_buf_start: Start index in part_buf.
@@ -166,6 +168,10 @@ struct dw_mci {
 	struct clk		*ciu_clk;
 	struct dw_mci_slot	*slot[MAX_MCI_SLOTS];
 
+	/* Phase Shift Value (for exynos5250 variant) */
+	u32			sdr_timing;
+	u32			ddr_timing;
+
 	/* FIFO push and pull */
 	int			fifo_depth;
 	int			data_shift;
-- 
1.6.6.rc2

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 3/6] mmc: dw_mmc: lookup for optional biu and ciu clocks
  2012-07-12 12:54   ` Thomas Abraham
@ 2012-07-13  9:11     ` Girish K S
  -1 siblings, 0 replies; 53+ messages in thread
From: Girish K S @ 2012-07-13  9:11 UTC (permalink / raw)
  To: Thomas Abraham
  Cc: linux-mmc, devicetree-discuss, linux-kernel, linux-arm-kernel,
	cjb, grant.likely, rob.herring, linux-samsung-soc, kgene.kim,
	patches

On 12 July 2012 18:24, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> Some platforms allow for clock gating and control of bus interface unit clock
> and card interface unit clock. Add support for clock lookup of optional biu
> and ciu clocks for clock gating and clock speed determination.
>
> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
> ---
>  drivers/mmc/host/dw_mmc.c  |   42 +++++++++++++++++++++++++++++++++++++++---
>  include/linux/mmc/dw_mmc.h |    4 ++++
>  2 files changed, 43 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index cd58063..679473c 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -1953,18 +1953,38 @@ int dw_mci_probe(struct dw_mci *host)
>                 return -ENODEV;
>         }
>
> -       if (!host->pdata->bus_hz) {
> +       host->biu_clk = clk_get(host->dev, "biu");
> +       if (IS_ERR(host->biu_clk))
> +               dev_dbg(host->dev, "biu clock not available\n");
> +       else
> +               clk_prepare_enable(host->biu_clk);
> +
> +       host->ciu_clk = clk_get(host->dev, "ciu");
> +       if (IS_ERR(host->ciu_clk))
> +               dev_dbg(host->dev, "ciu clock not available\n");
> +       else
> +               clk_prepare_enable(host->ciu_clk);
> +
> +       if (IS_ERR(host->ciu_clk))
> +               host->bus_hz = host->pdata->bus_hz;
> +       else
> +               host->bus_hz = clk_get_rate(host->ciu_clk);
> +
> +       if (!host->bus_hz) {
>                 dev_err(host->dev,
>                         "Platform data must supply bus speed\n");
> -               return -ENODEV;
> +               ret = -ENODEV;
> +               goto err_clk;
>         }
>
> -       host->bus_hz = host->pdata->bus_hz;
>         host->quirks = host->pdata->quirks;
>
>         spin_lock_init(&host->lock);
>         INIT_LIST_HEAD(&host->queue);
>
> +       host->dma_ops = host->pdata->dma_ops;
> +       dw_mci_init_dma(host);
This initialization is already done.
> +
>         /*
>          * Get the host data width - this assumes that HCON has been set with
>          * the correct values.
> @@ -2109,6 +2129,16 @@ err_dmaunmap:
>                 regulator_disable(host->vmmc);
>                 regulator_put(host->vmmc);
>         }
> +
> +err_clk:
> +       if (!IS_ERR(host->ciu_clk)) {
> +               clk_disable_unprepare(host->ciu_clk);
> +               clk_put(host->ciu_clk);
> +       }
> +       if (!IS_ERR(host->biu_clk)) {
> +               clk_disable_unprepare(host->biu_clk);
> +               clk_put(host->biu_clk);
> +       }
>         return ret;
>  }
>  EXPORT_SYMBOL(dw_mci_probe);
> @@ -2142,6 +2172,12 @@ void dw_mci_remove(struct dw_mci *host)
>                 regulator_put(host->vmmc);
>         }
>
> +       if (!IS_ERR(host->ciu_clk))
> +               clk_disable_unprepare(host->ciu_clk);
> +       if (!IS_ERR(host->biu_clk))
> +               clk_disable_unprepare(host->biu_clk);
> +       clk_put(host->ciu_clk);
> +       clk_put(host->biu_clk);
>  }
>  EXPORT_SYMBOL(dw_mci_remove);
>
> diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
> index a37a573..787ad56 100644
> --- a/include/linux/mmc/dw_mmc.h
> +++ b/include/linux/mmc/dw_mmc.h
> @@ -78,6 +78,8 @@ struct mmc_data;
>   * @data_offset: Set the offset of DATA register according to VERID.
>   * @dev: Device associated with the MMC controller.
>   * @pdata: Platform data associated with the MMC controller.
> + * @biu_clk: Pointer to bus interface unit clock instance.
> + * @ciu_clk: Pointer to card interface unit clock instance.
>   * @slot: Slots sharing this MMC controller.
>   * @fifo_depth: depth of FIFO.
>   * @data_shift: log2 of FIFO item size.
> @@ -158,6 +160,8 @@ struct dw_mci {
>         u16                     data_offset;
>         struct device           *dev;
>         struct dw_mci_board     *pdata;
> +       struct clk              *biu_clk;
> +       struct clk              *ciu_clk;
>         struct dw_mci_slot      *slot[MAX_MCI_SLOTS];
>
>         /* FIFO push and pull */
> --
> 1.6.6.rc2
>
> --
> 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

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v3 3/6] mmc: dw_mmc: lookup for optional biu and ciu clocks
@ 2012-07-13  9:11     ` Girish K S
  0 siblings, 0 replies; 53+ messages in thread
From: Girish K S @ 2012-07-13  9:11 UTC (permalink / raw)
  To: linux-arm-kernel

On 12 July 2012 18:24, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> Some platforms allow for clock gating and control of bus interface unit clock
> and card interface unit clock. Add support for clock lookup of optional biu
> and ciu clocks for clock gating and clock speed determination.
>
> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
> ---
>  drivers/mmc/host/dw_mmc.c  |   42 +++++++++++++++++++++++++++++++++++++++---
>  include/linux/mmc/dw_mmc.h |    4 ++++
>  2 files changed, 43 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index cd58063..679473c 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -1953,18 +1953,38 @@ int dw_mci_probe(struct dw_mci *host)
>                 return -ENODEV;
>         }
>
> -       if (!host->pdata->bus_hz) {
> +       host->biu_clk = clk_get(host->dev, "biu");
> +       if (IS_ERR(host->biu_clk))
> +               dev_dbg(host->dev, "biu clock not available\n");
> +       else
> +               clk_prepare_enable(host->biu_clk);
> +
> +       host->ciu_clk = clk_get(host->dev, "ciu");
> +       if (IS_ERR(host->ciu_clk))
> +               dev_dbg(host->dev, "ciu clock not available\n");
> +       else
> +               clk_prepare_enable(host->ciu_clk);
> +
> +       if (IS_ERR(host->ciu_clk))
> +               host->bus_hz = host->pdata->bus_hz;
> +       else
> +               host->bus_hz = clk_get_rate(host->ciu_clk);
> +
> +       if (!host->bus_hz) {
>                 dev_err(host->dev,
>                         "Platform data must supply bus speed\n");
> -               return -ENODEV;
> +               ret = -ENODEV;
> +               goto err_clk;
>         }
>
> -       host->bus_hz = host->pdata->bus_hz;
>         host->quirks = host->pdata->quirks;
>
>         spin_lock_init(&host->lock);
>         INIT_LIST_HEAD(&host->queue);
>
> +       host->dma_ops = host->pdata->dma_ops;
> +       dw_mci_init_dma(host);
This initialization is already done.
> +
>         /*
>          * Get the host data width - this assumes that HCON has been set with
>          * the correct values.
> @@ -2109,6 +2129,16 @@ err_dmaunmap:
>                 regulator_disable(host->vmmc);
>                 regulator_put(host->vmmc);
>         }
> +
> +err_clk:
> +       if (!IS_ERR(host->ciu_clk)) {
> +               clk_disable_unprepare(host->ciu_clk);
> +               clk_put(host->ciu_clk);
> +       }
> +       if (!IS_ERR(host->biu_clk)) {
> +               clk_disable_unprepare(host->biu_clk);
> +               clk_put(host->biu_clk);
> +       }
>         return ret;
>  }
>  EXPORT_SYMBOL(dw_mci_probe);
> @@ -2142,6 +2172,12 @@ void dw_mci_remove(struct dw_mci *host)
>                 regulator_put(host->vmmc);
>         }
>
> +       if (!IS_ERR(host->ciu_clk))
> +               clk_disable_unprepare(host->ciu_clk);
> +       if (!IS_ERR(host->biu_clk))
> +               clk_disable_unprepare(host->biu_clk);
> +       clk_put(host->ciu_clk);
> +       clk_put(host->biu_clk);
>  }
>  EXPORT_SYMBOL(dw_mci_remove);
>
> diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
> index a37a573..787ad56 100644
> --- a/include/linux/mmc/dw_mmc.h
> +++ b/include/linux/mmc/dw_mmc.h
> @@ -78,6 +78,8 @@ struct mmc_data;
>   * @data_offset: Set the offset of DATA register according to VERID.
>   * @dev: Device associated with the MMC controller.
>   * @pdata: Platform data associated with the MMC controller.
> + * @biu_clk: Pointer to bus interface unit clock instance.
> + * @ciu_clk: Pointer to card interface unit clock instance.
>   * @slot: Slots sharing this MMC controller.
>   * @fifo_depth: depth of FIFO.
>   * @data_shift: log2 of FIFO item size.
> @@ -158,6 +160,8 @@ struct dw_mci {
>         u16                     data_offset;
>         struct device           *dev;
>         struct dw_mci_board     *pdata;
> +       struct clk              *biu_clk;
> +       struct clk              *ciu_clk;
>         struct dw_mci_slot      *slot[MAX_MCI_SLOTS];
>
>         /* FIFO push and pull */
> --
> 1.6.6.rc2
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 5/6] mmc: dw_mmc: add device tree support
  2012-07-12 12:54   ` Thomas Abraham
@ 2012-07-16  4:15     ` Girish K S
  -1 siblings, 0 replies; 53+ messages in thread
From: Girish K S @ 2012-07-16  4:15 UTC (permalink / raw)
  To: Thomas Abraham
  Cc: linux-mmc, devicetree-discuss, linux-kernel, linux-arm-kernel,
	cjb, grant.likely, rob.herring, linux-samsung-soc, kgene.kim,
	patches

On 12 July 2012 18:24, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> Add device tree based discovery support.
>
> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
> ---
>  .../devicetree/bindings/mmc/synposis-dw-mshc.txt   |  108 +++++++++++
>  drivers/mmc/host/dw_mmc-pltfm.c                    |   24 +++
>  drivers/mmc/host/dw_mmc.c                          |  201 +++++++++++++++++++-
>  drivers/mmc/host/dw_mmc.h                          |    9 +
>  include/linux/mmc/dw_mmc.h                         |    2 +
>  5 files changed, 338 insertions(+), 6 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
>
> diff --git a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> new file mode 100644
> index 0000000..3acd6c9
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> @@ -0,0 +1,108 @@
> +* Synopsis Designware Mobile Storage Host Controller
> +
> +The Synopsis designware mobile storage host controller is used to interface
> +a SoC with storage medium such as eMMC or SD/MMC cards.
> +
> +Required Properties:
> +
> +* compatible: should be one of the following
> +       - snps,dw-mshc: for controllers compliant with synopsis dw-mshc.
> +
> +* reg: physical base address of the dw-mshc controller and size of its memory
> +  region.
> +
> +* interrupts: interrupt specifier for the controller. The format and value of
> +  the interrupt specifier depends on the interrupt parent for the controller.
> +
> +* #address-cells: should be 1.
> +
> +* #size-cells: should be 0.
> +
> +# Slots: The slot specific information are contained within child-nodes with
> +  each child-node representing a supported slot. There should be atleast one
> +  child node representing a card slot. The name of the child node representing
> +  the slot is recommended to be slot@n where n is the unique number of the slot
> +  connnected to the controller. The following are optional properties which
> +  can be included in the slot child node.
> +
> +       * reg: specifies the physical slot number. The valid values of this
> +         property is 0 to (num-slots -1), where num-slots is the value
> +         specified by the num-slots property.
> +
> +       * bus-width: specifies the width of the data bus connected from the
> +         controller to the card slot. The value should be 1, 4 or 8. In case
> +         this property is not specified, a default value of 1 is assumed for
> +         this property.
> +
> +       * cd-gpios: specifies the card detect gpio line. The format of the
> +         gpio specifier depends on the gpio controller.
> +
> +       * wp-gpios: specifies the write protect gpio line. The format of the
> +         gpio specifier depends on the gpio controller.
> +
> +       * gpios: specifies a list of gpios used for command, clock and data
> +         bus. The first gpio is the command line and the second gpio is the
> +         clock line. The rest of the gpios (depending on the bus-width
> +         property) are the data lines in no particular order. The format of
> +         the gpio specifier depends on the gpio controller.
> +
> +Optional properties:
> +
> +* num-slots: specifies the number of slots supported by the controller.
> +  The number of physical slots actually used could be equal or less than the
> +  value specified by num-slots. If this property is not specified, the value
> +  of num-slot property is assumed to be 1.
> +
> +* fifo-depth: The maximum size of the tx/rx fifo's. If this property is not
> +  specified, the default value of the fifo size is determined from the
> +  controller registers.
> +
> +* card-detect-delay: Delay in milli-seconds before detecting card after card
> +  insert event. The default value is 0.
> +
> +* supports-highspeed: Enables support for high speed cards (upto 50MHz)
> +
> +* card-detection-broken: The card detection functionality is not available on
> +  any of the slots.
> +
> +* no-write-protect: The write protect pad of the controller is not connected
> +  to the write protect pin on the slot.
> +
> +Aliases:
> +
> +- All the MSHC controller nodes should be represented in the aliases node using
> +  the following format 'mshc{n}' where n is a unique number for the alias.
> +
> +
> +Example:
> +
> +  The MSHC controller node can be split into two portions, SoC specific and
> +  board specific portions as listed below.
> +
> +       dwmmc0@12200000 {
> +               compatible = "snps,dw-mshc";
> +               reg = <0x12200000 0x1000>;
> +               interrupts = <0 75 0>;
> +               #address-cells = <1>;
> +               #size-cells = <0>;
> +       };
> +
> +       dwmmc0@12200000 {
> +               num-slots = <1>;
> +               supports-highspeed;
> +               card-detection-broken;
> +               no-write-protect;
> +               fifo-depth = <0x80>;
> +               card-detect-delay = <200>;
> +
> +               slot@0 {
> +                       reg = <0>;
> +                       bus-width = <8>;
> +                       cd-gpios = <&gpc0 2 2 3 3>;
> +                       gpios = <&gpc0 0 2 0 3>, <&gpc0 1 2 0 3>,
> +                               <&gpc1 0 2 3 3>, <&gpc1 1 2 3 3>,
> +                               <&gpc1 2 2 3 3>, <&gpc1 3 2 3 3>,
> +                               <&gpc0 3 2 3 3>, <&gpc0 4 2 3 3>,
> +                               <&gpc0 5 2 3 3>, <&gpc0 6 2 3 3>;
> +               };
> +       };
> diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
> index 9a63299..8d24f6d 100644
> --- a/drivers/mmc/host/dw_mmc-pltfm.c
> +++ b/drivers/mmc/host/dw_mmc-pltfm.c
> @@ -19,8 +19,24 @@
>  #include <linux/mmc/host.h>
>  #include <linux/mmc/mmc.h>
>  #include <linux/mmc/dw_mmc.h>
> +#include <linux/of.h>
>  #include "dw_mmc.h"
>
> +#ifdef CONFIG_OF
> +static struct dw_mci_drv_data synopsis_drv_data = {
> +       .ctrl_type      = DW_MCI_TYPE_SYNOPSIS,
> +};
> +
> +static const struct of_device_id dw_mci_pltfm_match[] = {
> +       { .compatible = "snps,dw-mshc",
> +                       .data = (void *)&synopsis_drv_data, },
> +       {},
> +};
> +MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
> +#else
> +static const struct of_device_id dw_mci_pltfm_match[];
the #else and a statement can be completely removed if of_match_ptr is
used while accessing the dw_mci_pltfm_match in of_match_node function.
> +#endif
> +
>  static int dw_mci_pltfm_probe(struct platform_device *pdev)
>  {
>         struct dw_mci *host;
> @@ -51,6 +67,13 @@ static int dw_mci_pltfm_probe(struct platform_device *pdev)
>         if (!host->regs)
>                 goto err_free;
>         platform_set_drvdata(pdev, host);
> +
> +       if (pdev->dev.of_node) {
> +               const struct of_device_id *match;
> +               match = of_match_node(dw_mci_pltfm_match, pdev->dev.of_node);
can be modified to of_match_node(of_match_pt(dw_mci_pltfm_match),
pdev->dev.of_node);
This will remove the dummy allocation of variable as mentioned above.
Also it will be generic in non dt case.
> +               host->drv_data = match->data;
> +       }
> +
>         ret = dw_mci_probe(host);
>         if (ret)
>                 goto err_out;
> @@ -111,6 +134,7 @@ static struct platform_driver dw_mci_pltfm_driver = {
>         .remove         = __exit_p(dw_mci_pltfm_remove),
>         .driver         = {
>                 .name           = "dw_mmc",
> +               .of_match_table = of_match_ptr(dw_mci_pltfm_match),
>                 .pm             = &dw_mci_pltfm_pmops,
>         },
>  };
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index 075f89d..3bc276d 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -33,9 +33,13 @@
>  #include <linux/bitops.h>
>  #include <linux/regulator/consumer.h>
>  #include <linux/workqueue.h>
> +#include <linux/of.h>
> +#include <linux/of_gpio.h>
>
>  #include "dw_mmc.h"
>
> +#define NUM_PINS(x) (x + 2)
> +
>  /* Common flag combinations */
>  #define DW_MCI_DATA_ERROR_FLAGS        (SDMMC_INT_DTO | SDMMC_INT_DCRC | \
>                                  SDMMC_INT_HTO | SDMMC_INT_SBE  | \
> @@ -86,6 +90,8 @@ struct idmac_desc {
>  struct dw_mci_slot {
>         struct mmc_host         *mmc;
>         struct dw_mci           *host;
> +       int                     wp_gpio;
> +       int                     cd_gpio;
>
>         u32                     ctype;
>
> @@ -1762,10 +1768,106 @@ static void dw_mci_work_routine_card(struct work_struct *work)
>         }
>  }
>
> +#ifdef CONFIG_OF
> +static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
> +{
> +       struct device_node *np;
> +       const __be32 *addr;
> +       int len;
> +
> +       if (!dev || !dev->of_node)
> +               return NULL;
> +
> +       for_each_child_of_node(dev->of_node, np) {
> +               addr = of_get_property(np, "reg", &len);
> +               if (!addr || (len < sizeof(int)))
> +                       continue;
> +               if (be32_to_cpup(addr) == slot)
> +                       return np;
> +       }
> +       return NULL;
> +}
> +
> +static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
> +{
> +       struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
> +       u32 bus_wd = 1;
> +
> +       if (!np)
> +               return 1;
> +
> +       if (of_property_read_u32(np, "bus-width", &bus_wd))
> +               dev_err(dev, "bus-width property not found, assuming width"
> +                              " as 1\n");
> +       return bus_wd;
> +}
> +
> +static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
> +{
> +       struct device_node *np = dw_mci_of_find_slot_node(host->dev, slot);
> +       int idx, gpio, ret;
> +
> +       if (!np)
> +               return -EINVAL;
> +
> +       for (idx = 0; idx < NUM_PINS(bus_wd); idx++) {
> +               gpio = of_get_gpio(np, idx);
> +               if (!gpio_is_valid(gpio)) {
> +                       dev_err(host->dev, "invalid gpio: %d\n", gpio);
> +                       return -EINVAL;
> +               }
> +
> +               ret = devm_gpio_request(host->dev, gpio, "dw-mci-bus");
> +               if (ret) {
> +                       dev_err(host->dev, "gpio [%d] request failed\n", gpio);
> +                       return -EBUSY;
> +               }
> +       }
> +
> +       host->slot[slot]->wp_gpio = -1;
> +       gpio = of_get_named_gpio(np, "wp-gpios", 0);
> +       if (!gpio_is_valid(gpio)) {
> +               dev_info(host->dev, "wp gpio not available");
> +       } else {
> +               ret = devm_gpio_request(host->dev, gpio, "dw-mci-wp");
> +               if (ret)
> +                       dev_info(host->dev, "gpio [%d] request failed\n",
> +                                               gpio);
> +               else
> +                       host->slot[slot]->wp_gpio = gpio;
> +       }
> +
> +       host->slot[slot]->cd_gpio = -1;
> +       gpio = of_get_named_gpio(np, "cd-gpios", 0);
> +       if (!gpio_is_valid(gpio)) {
> +               dev_info(host->dev, "cd gpio not available");
> +       } else {
> +               ret = devm_gpio_request(host->dev, gpio, "dw-mci-cd");
> +               if (ret)
> +                       dev_err(host->dev, "gpio [%d] request failed\n", gpio);
> +               else
> +                       host->slot[slot]->cd_gpio = gpio;
> +       }
> +
> +       return 0;
> +}
> +#else /* CONFIG_OF */
> +static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
> +{
> +       return 1;
> +}
> +
> +static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
> +{
> +       return -EINVAL;
> +}
> +#endif /* CONFIG_OF */
> +
>  static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>  {
>         struct mmc_host *mmc;
>         struct dw_mci_slot *slot;
> +       int ctrl_id, ret;
>
>         mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
>         if (!mmc)
> @@ -1775,6 +1877,7 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>         slot->id = id;
>         slot->mmc = mmc;
>         slot->host = host;
> +       host->slot[id] = slot;
>
>         mmc->ops = &dw_mci_ops;
>         mmc->f_min = DIV_ROUND_UP(host->bus_hz, 510);
> @@ -1795,12 +1898,33 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>         if (host->pdata->caps)
>                 mmc->caps = host->pdata->caps;
>
> +       if (host->dev->of_node) {
> +               ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
> +               if (ctrl_id < 0)
> +                       ctrl_id = 0;
> +       }
> +       if (host->drv_data->caps)
> +               mmc->caps |= host->drv_data->caps[ctrl_id];
> +
>         if (host->pdata->caps2)
>                 mmc->caps2 = host->pdata->caps2;
>
> -       if (host->pdata->get_bus_wd)
> +       if (host->pdata->get_bus_wd) {
>                 if (host->pdata->get_bus_wd(slot->id) >= 4)
>                         mmc->caps |= MMC_CAP_4_BIT_DATA;
> +       } else if (host->dev->of_node) {
> +               unsigned int bus_width;
> +               bus_width = dw_mci_of_get_bus_wd(host->dev, slot->id);
> +               switch (bus_width) {
> +               case 8:
> +                       mmc->caps |= MMC_CAP_8_BIT_DATA;
> +               case 4:
> +                       mmc->caps |= MMC_CAP_4_BIT_DATA;
> +               }
> +               ret = dw_mci_of_setup_bus(host, slot->id, bus_width);
> +               if (ret)
> +                       goto err_setup_bus;
> +       }
>
>         if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED)
>                 mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
> @@ -1845,7 +1969,6 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>         else
>                 clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
>
> -       host->slot[id] = slot;
>         mmc_add_host(mmc);
>
>  #if defined(CONFIG_DEBUG_FS)
> @@ -1862,6 +1985,10 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>         queue_work(host->card_workqueue, &host->card_work);
>
>         return 0;
> +
> +err_setup_bus:
> +       mmc_free_host(mmc);
> +       return -EINVAL;
>  }
>
>  static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
> @@ -1937,16 +2064,78 @@ static bool mci_wait_reset(struct device *dev, struct dw_mci *host)
>         return false;
>  }
>
> +#ifdef CONFIG_OF
> +static struct dw_mci_of_quirks {
> +       char *quirk;
> +       int id;
> +} of_quriks[] = {
> +       {
> +               .quirk  = "supports-highspeed",
> +               .id     = DW_MCI_QUIRK_HIGHSPEED,
> +       }, {
> +               .quirk  = "card-detection-broken",
> +               .id     = DW_MCI_QUIRK_BROKEN_CARD_DETECTION,
> +       }, {
> +               .quirk  = "no-write-protect",
> +               .id     = DW_MCI_QUIRK_NO_WRITE_PROTECT,
> +       }
> +};
> +
> +static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
> +{
> +       struct dw_mci_board *pdata;
> +       struct device *dev = host->dev;
> +       struct device_node *np = dev->of_node;
> +       int idx, cnt;
> +
> +       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
> +       if (!pdata) {
> +               dev_err(dev, "could not allocate memory for pdata\n");
> +               return ERR_PTR(-ENOMEM);
> +       }
> +
> +       /* find out number of slots supported */
> +       if (of_property_read_u32(dev->of_node, "num-slots",
> +                               &pdata->num_slots)) {
> +               dev_info(dev, "num-slots property not found, "
> +                               "assuming 1 slot is available\n");
> +               pdata->num_slots = 1;
> +       }
> +
> +       /* get quirks */
> +       cnt = sizeof(of_quriks) / sizeof(struct dw_mci_of_quirks);
> +       for (idx = 0; idx < cnt; idx++)
> +               if (of_get_property(np, of_quriks[idx].quirk, NULL))
> +                       pdata->quirks |= of_quriks[idx].id;
> +
> +       if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
> +               dev_info(dev, "fifo-depth property not found, using "
> +                               "value of FIFOTH register as default\n");
> +
> +       of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
> +
> +       return pdata;
> +}
> +
> +#else /* CONFIG_OF */
> +static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
> +{
> +       return ERR_PTR(-EINVAL);
> +}
> +#endif /* CONFIG_OF */
> +
>  int dw_mci_probe(struct dw_mci *host)
>  {
>         int width, i, ret = 0;
>         u32 fifo_size;
>         int init_slots = 0;
>
> -       if (!host->pdata || !host->pdata->init) {
> -               dev_err(host->dev,
> -                       "Platform data must supply init function\n");
> -               return -ENODEV;
> +       if (!host->pdata) {
> +               host->pdata = dw_mci_parse_dt(host);
> +               if (IS_ERR(host->pdata)) {
> +                       dev_err(host->dev, "platform data not available\n");
> +                       return -EINVAL;
> +               }
>         }
>
>         if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
> index 15c27e1..1ecaa02 100644
> --- a/drivers/mmc/host/dw_mmc.h
> +++ b/drivers/mmc/host/dw_mmc.h
> @@ -182,4 +182,13 @@ extern int dw_mci_suspend(struct dw_mci *host);
>  extern int dw_mci_resume(struct dw_mci *host);
>  #endif
>
> +/* Variations in the dw_mci controller */
> +#define DW_MCI_TYPE_SYNOPSIS           0
> +
> +/* dw_mci platform driver data */
> +struct dw_mci_drv_data {
> +       unsigned long           ctrl_type;
> +       unsigned long           *caps;
> +};
> +
>  #endif /* _DW_MMC_H_ */
> diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
> index b72e4aa..ae45e4f 100644
> --- a/include/linux/mmc/dw_mmc.h
> +++ b/include/linux/mmc/dw_mmc.h
> @@ -78,6 +78,7 @@ struct mmc_data;
>   * @data_offset: Set the offset of DATA register according to VERID.
>   * @dev: Device associated with the MMC controller.
>   * @pdata: Platform data associated with the MMC controller.
> + * @drv_data: Driver specific data for identified variant of the controller
>   * @biu_clk: Pointer to bus interface unit clock instance.
>   * @ciu_clk: Pointer to card interface unit clock instance.
>   * @slot: Slots sharing this MMC controller.
> @@ -160,6 +161,7 @@ struct dw_mci {
>         u16                     data_offset;
>         struct device           *dev;
>         struct dw_mci_board     *pdata;
> +       struct dw_mci_drv_data  *drv_data;
>         struct clk              *biu_clk;
>         struct clk              *ciu_clk;
>         struct dw_mci_slot      *slot[MAX_MCI_SLOTS];
> --
> 1.6.6.rc2
>
> --
> 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

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v3 5/6] mmc: dw_mmc: add device tree support
@ 2012-07-16  4:15     ` Girish K S
  0 siblings, 0 replies; 53+ messages in thread
From: Girish K S @ 2012-07-16  4:15 UTC (permalink / raw)
  To: linux-arm-kernel

On 12 July 2012 18:24, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> Add device tree based discovery support.
>
> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
> ---
>  .../devicetree/bindings/mmc/synposis-dw-mshc.txt   |  108 +++++++++++
>  drivers/mmc/host/dw_mmc-pltfm.c                    |   24 +++
>  drivers/mmc/host/dw_mmc.c                          |  201 +++++++++++++++++++-
>  drivers/mmc/host/dw_mmc.h                          |    9 +
>  include/linux/mmc/dw_mmc.h                         |    2 +
>  5 files changed, 338 insertions(+), 6 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
>
> diff --git a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> new file mode 100644
> index 0000000..3acd6c9
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> @@ -0,0 +1,108 @@
> +* Synopsis Designware Mobile Storage Host Controller
> +
> +The Synopsis designware mobile storage host controller is used to interface
> +a SoC with storage medium such as eMMC or SD/MMC cards.
> +
> +Required Properties:
> +
> +* compatible: should be one of the following
> +       - snps,dw-mshc: for controllers compliant with synopsis dw-mshc.
> +
> +* reg: physical base address of the dw-mshc controller and size of its memory
> +  region.
> +
> +* interrupts: interrupt specifier for the controller. The format and value of
> +  the interrupt specifier depends on the interrupt parent for the controller.
> +
> +* #address-cells: should be 1.
> +
> +* #size-cells: should be 0.
> +
> +# Slots: The slot specific information are contained within child-nodes with
> +  each child-node representing a supported slot. There should be atleast one
> +  child node representing a card slot. The name of the child node representing
> +  the slot is recommended to be slot at n where n is the unique number of the slot
> +  connnected to the controller. The following are optional properties which
> +  can be included in the slot child node.
> +
> +       * reg: specifies the physical slot number. The valid values of this
> +         property is 0 to (num-slots -1), where num-slots is the value
> +         specified by the num-slots property.
> +
> +       * bus-width: specifies the width of the data bus connected from the
> +         controller to the card slot. The value should be 1, 4 or 8. In case
> +         this property is not specified, a default value of 1 is assumed for
> +         this property.
> +
> +       * cd-gpios: specifies the card detect gpio line. The format of the
> +         gpio specifier depends on the gpio controller.
> +
> +       * wp-gpios: specifies the write protect gpio line. The format of the
> +         gpio specifier depends on the gpio controller.
> +
> +       * gpios: specifies a list of gpios used for command, clock and data
> +         bus. The first gpio is the command line and the second gpio is the
> +         clock line. The rest of the gpios (depending on the bus-width
> +         property) are the data lines in no particular order. The format of
> +         the gpio specifier depends on the gpio controller.
> +
> +Optional properties:
> +
> +* num-slots: specifies the number of slots supported by the controller.
> +  The number of physical slots actually used could be equal or less than the
> +  value specified by num-slots. If this property is not specified, the value
> +  of num-slot property is assumed to be 1.
> +
> +* fifo-depth: The maximum size of the tx/rx fifo's. If this property is not
> +  specified, the default value of the fifo size is determined from the
> +  controller registers.
> +
> +* card-detect-delay: Delay in milli-seconds before detecting card after card
> +  insert event. The default value is 0.
> +
> +* supports-highspeed: Enables support for high speed cards (upto 50MHz)
> +
> +* card-detection-broken: The card detection functionality is not available on
> +  any of the slots.
> +
> +* no-write-protect: The write protect pad of the controller is not connected
> +  to the write protect pin on the slot.
> +
> +Aliases:
> +
> +- All the MSHC controller nodes should be represented in the aliases node using
> +  the following format 'mshc{n}' where n is a unique number for the alias.
> +
> +
> +Example:
> +
> +  The MSHC controller node can be split into two portions, SoC specific and
> +  board specific portions as listed below.
> +
> +       dwmmc0 at 12200000 {
> +               compatible = "snps,dw-mshc";
> +               reg = <0x12200000 0x1000>;
> +               interrupts = <0 75 0>;
> +               #address-cells = <1>;
> +               #size-cells = <0>;
> +       };
> +
> +       dwmmc0 at 12200000 {
> +               num-slots = <1>;
> +               supports-highspeed;
> +               card-detection-broken;
> +               no-write-protect;
> +               fifo-depth = <0x80>;
> +               card-detect-delay = <200>;
> +
> +               slot at 0 {
> +                       reg = <0>;
> +                       bus-width = <8>;
> +                       cd-gpios = <&gpc0 2 2 3 3>;
> +                       gpios = <&gpc0 0 2 0 3>, <&gpc0 1 2 0 3>,
> +                               <&gpc1 0 2 3 3>, <&gpc1 1 2 3 3>,
> +                               <&gpc1 2 2 3 3>, <&gpc1 3 2 3 3>,
> +                               <&gpc0 3 2 3 3>, <&gpc0 4 2 3 3>,
> +                               <&gpc0 5 2 3 3>, <&gpc0 6 2 3 3>;
> +               };
> +       };
> diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
> index 9a63299..8d24f6d 100644
> --- a/drivers/mmc/host/dw_mmc-pltfm.c
> +++ b/drivers/mmc/host/dw_mmc-pltfm.c
> @@ -19,8 +19,24 @@
>  #include <linux/mmc/host.h>
>  #include <linux/mmc/mmc.h>
>  #include <linux/mmc/dw_mmc.h>
> +#include <linux/of.h>
>  #include "dw_mmc.h"
>
> +#ifdef CONFIG_OF
> +static struct dw_mci_drv_data synopsis_drv_data = {
> +       .ctrl_type      = DW_MCI_TYPE_SYNOPSIS,
> +};
> +
> +static const struct of_device_id dw_mci_pltfm_match[] = {
> +       { .compatible = "snps,dw-mshc",
> +                       .data = (void *)&synopsis_drv_data, },
> +       {},
> +};
> +MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
> +#else
> +static const struct of_device_id dw_mci_pltfm_match[];
the #else and a statement can be completely removed if of_match_ptr is
used while accessing the dw_mci_pltfm_match in of_match_node function.
> +#endif
> +
>  static int dw_mci_pltfm_probe(struct platform_device *pdev)
>  {
>         struct dw_mci *host;
> @@ -51,6 +67,13 @@ static int dw_mci_pltfm_probe(struct platform_device *pdev)
>         if (!host->regs)
>                 goto err_free;
>         platform_set_drvdata(pdev, host);
> +
> +       if (pdev->dev.of_node) {
> +               const struct of_device_id *match;
> +               match = of_match_node(dw_mci_pltfm_match, pdev->dev.of_node);
can be modified to of_match_node(of_match_pt(dw_mci_pltfm_match),
pdev->dev.of_node);
This will remove the dummy allocation of variable as mentioned above.
Also it will be generic in non dt case.
> +               host->drv_data = match->data;
> +       }
> +
>         ret = dw_mci_probe(host);
>         if (ret)
>                 goto err_out;
> @@ -111,6 +134,7 @@ static struct platform_driver dw_mci_pltfm_driver = {
>         .remove         = __exit_p(dw_mci_pltfm_remove),
>         .driver         = {
>                 .name           = "dw_mmc",
> +               .of_match_table = of_match_ptr(dw_mci_pltfm_match),
>                 .pm             = &dw_mci_pltfm_pmops,
>         },
>  };
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index 075f89d..3bc276d 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -33,9 +33,13 @@
>  #include <linux/bitops.h>
>  #include <linux/regulator/consumer.h>
>  #include <linux/workqueue.h>
> +#include <linux/of.h>
> +#include <linux/of_gpio.h>
>
>  #include "dw_mmc.h"
>
> +#define NUM_PINS(x) (x + 2)
> +
>  /* Common flag combinations */
>  #define DW_MCI_DATA_ERROR_FLAGS        (SDMMC_INT_DTO | SDMMC_INT_DCRC | \
>                                  SDMMC_INT_HTO | SDMMC_INT_SBE  | \
> @@ -86,6 +90,8 @@ struct idmac_desc {
>  struct dw_mci_slot {
>         struct mmc_host         *mmc;
>         struct dw_mci           *host;
> +       int                     wp_gpio;
> +       int                     cd_gpio;
>
>         u32                     ctype;
>
> @@ -1762,10 +1768,106 @@ static void dw_mci_work_routine_card(struct work_struct *work)
>         }
>  }
>
> +#ifdef CONFIG_OF
> +static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
> +{
> +       struct device_node *np;
> +       const __be32 *addr;
> +       int len;
> +
> +       if (!dev || !dev->of_node)
> +               return NULL;
> +
> +       for_each_child_of_node(dev->of_node, np) {
> +               addr = of_get_property(np, "reg", &len);
> +               if (!addr || (len < sizeof(int)))
> +                       continue;
> +               if (be32_to_cpup(addr) == slot)
> +                       return np;
> +       }
> +       return NULL;
> +}
> +
> +static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
> +{
> +       struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
> +       u32 bus_wd = 1;
> +
> +       if (!np)
> +               return 1;
> +
> +       if (of_property_read_u32(np, "bus-width", &bus_wd))
> +               dev_err(dev, "bus-width property not found, assuming width"
> +                              " as 1\n");
> +       return bus_wd;
> +}
> +
> +static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
> +{
> +       struct device_node *np = dw_mci_of_find_slot_node(host->dev, slot);
> +       int idx, gpio, ret;
> +
> +       if (!np)
> +               return -EINVAL;
> +
> +       for (idx = 0; idx < NUM_PINS(bus_wd); idx++) {
> +               gpio = of_get_gpio(np, idx);
> +               if (!gpio_is_valid(gpio)) {
> +                       dev_err(host->dev, "invalid gpio: %d\n", gpio);
> +                       return -EINVAL;
> +               }
> +
> +               ret = devm_gpio_request(host->dev, gpio, "dw-mci-bus");
> +               if (ret) {
> +                       dev_err(host->dev, "gpio [%d] request failed\n", gpio);
> +                       return -EBUSY;
> +               }
> +       }
> +
> +       host->slot[slot]->wp_gpio = -1;
> +       gpio = of_get_named_gpio(np, "wp-gpios", 0);
> +       if (!gpio_is_valid(gpio)) {
> +               dev_info(host->dev, "wp gpio not available");
> +       } else {
> +               ret = devm_gpio_request(host->dev, gpio, "dw-mci-wp");
> +               if (ret)
> +                       dev_info(host->dev, "gpio [%d] request failed\n",
> +                                               gpio);
> +               else
> +                       host->slot[slot]->wp_gpio = gpio;
> +       }
> +
> +       host->slot[slot]->cd_gpio = -1;
> +       gpio = of_get_named_gpio(np, "cd-gpios", 0);
> +       if (!gpio_is_valid(gpio)) {
> +               dev_info(host->dev, "cd gpio not available");
> +       } else {
> +               ret = devm_gpio_request(host->dev, gpio, "dw-mci-cd");
> +               if (ret)
> +                       dev_err(host->dev, "gpio [%d] request failed\n", gpio);
> +               else
> +                       host->slot[slot]->cd_gpio = gpio;
> +       }
> +
> +       return 0;
> +}
> +#else /* CONFIG_OF */
> +static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
> +{
> +       return 1;
> +}
> +
> +static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
> +{
> +       return -EINVAL;
> +}
> +#endif /* CONFIG_OF */
> +
>  static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>  {
>         struct mmc_host *mmc;
>         struct dw_mci_slot *slot;
> +       int ctrl_id, ret;
>
>         mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
>         if (!mmc)
> @@ -1775,6 +1877,7 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>         slot->id = id;
>         slot->mmc = mmc;
>         slot->host = host;
> +       host->slot[id] = slot;
>
>         mmc->ops = &dw_mci_ops;
>         mmc->f_min = DIV_ROUND_UP(host->bus_hz, 510);
> @@ -1795,12 +1898,33 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>         if (host->pdata->caps)
>                 mmc->caps = host->pdata->caps;
>
> +       if (host->dev->of_node) {
> +               ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
> +               if (ctrl_id < 0)
> +                       ctrl_id = 0;
> +       }
> +       if (host->drv_data->caps)
> +               mmc->caps |= host->drv_data->caps[ctrl_id];
> +
>         if (host->pdata->caps2)
>                 mmc->caps2 = host->pdata->caps2;
>
> -       if (host->pdata->get_bus_wd)
> +       if (host->pdata->get_bus_wd) {
>                 if (host->pdata->get_bus_wd(slot->id) >= 4)
>                         mmc->caps |= MMC_CAP_4_BIT_DATA;
> +       } else if (host->dev->of_node) {
> +               unsigned int bus_width;
> +               bus_width = dw_mci_of_get_bus_wd(host->dev, slot->id);
> +               switch (bus_width) {
> +               case 8:
> +                       mmc->caps |= MMC_CAP_8_BIT_DATA;
> +               case 4:
> +                       mmc->caps |= MMC_CAP_4_BIT_DATA;
> +               }
> +               ret = dw_mci_of_setup_bus(host, slot->id, bus_width);
> +               if (ret)
> +                       goto err_setup_bus;
> +       }
>
>         if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED)
>                 mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
> @@ -1845,7 +1969,6 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>         else
>                 clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
>
> -       host->slot[id] = slot;
>         mmc_add_host(mmc);
>
>  #if defined(CONFIG_DEBUG_FS)
> @@ -1862,6 +1985,10 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>         queue_work(host->card_workqueue, &host->card_work);
>
>         return 0;
> +
> +err_setup_bus:
> +       mmc_free_host(mmc);
> +       return -EINVAL;
>  }
>
>  static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
> @@ -1937,16 +2064,78 @@ static bool mci_wait_reset(struct device *dev, struct dw_mci *host)
>         return false;
>  }
>
> +#ifdef CONFIG_OF
> +static struct dw_mci_of_quirks {
> +       char *quirk;
> +       int id;
> +} of_quriks[] = {
> +       {
> +               .quirk  = "supports-highspeed",
> +               .id     = DW_MCI_QUIRK_HIGHSPEED,
> +       }, {
> +               .quirk  = "card-detection-broken",
> +               .id     = DW_MCI_QUIRK_BROKEN_CARD_DETECTION,
> +       }, {
> +               .quirk  = "no-write-protect",
> +               .id     = DW_MCI_QUIRK_NO_WRITE_PROTECT,
> +       }
> +};
> +
> +static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
> +{
> +       struct dw_mci_board *pdata;
> +       struct device *dev = host->dev;
> +       struct device_node *np = dev->of_node;
> +       int idx, cnt;
> +
> +       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
> +       if (!pdata) {
> +               dev_err(dev, "could not allocate memory for pdata\n");
> +               return ERR_PTR(-ENOMEM);
> +       }
> +
> +       /* find out number of slots supported */
> +       if (of_property_read_u32(dev->of_node, "num-slots",
> +                               &pdata->num_slots)) {
> +               dev_info(dev, "num-slots property not found, "
> +                               "assuming 1 slot is available\n");
> +               pdata->num_slots = 1;
> +       }
> +
> +       /* get quirks */
> +       cnt = sizeof(of_quriks) / sizeof(struct dw_mci_of_quirks);
> +       for (idx = 0; idx < cnt; idx++)
> +               if (of_get_property(np, of_quriks[idx].quirk, NULL))
> +                       pdata->quirks |= of_quriks[idx].id;
> +
> +       if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
> +               dev_info(dev, "fifo-depth property not found, using "
> +                               "value of FIFOTH register as default\n");
> +
> +       of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
> +
> +       return pdata;
> +}
> +
> +#else /* CONFIG_OF */
> +static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
> +{
> +       return ERR_PTR(-EINVAL);
> +}
> +#endif /* CONFIG_OF */
> +
>  int dw_mci_probe(struct dw_mci *host)
>  {
>         int width, i, ret = 0;
>         u32 fifo_size;
>         int init_slots = 0;
>
> -       if (!host->pdata || !host->pdata->init) {
> -               dev_err(host->dev,
> -                       "Platform data must supply init function\n");
> -               return -ENODEV;
> +       if (!host->pdata) {
> +               host->pdata = dw_mci_parse_dt(host);
> +               if (IS_ERR(host->pdata)) {
> +                       dev_err(host->dev, "platform data not available\n");
> +                       return -EINVAL;
> +               }
>         }
>
>         if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
> index 15c27e1..1ecaa02 100644
> --- a/drivers/mmc/host/dw_mmc.h
> +++ b/drivers/mmc/host/dw_mmc.h
> @@ -182,4 +182,13 @@ extern int dw_mci_suspend(struct dw_mci *host);
>  extern int dw_mci_resume(struct dw_mci *host);
>  #endif
>
> +/* Variations in the dw_mci controller */
> +#define DW_MCI_TYPE_SYNOPSIS           0
> +
> +/* dw_mci platform driver data */
> +struct dw_mci_drv_data {
> +       unsigned long           ctrl_type;
> +       unsigned long           *caps;
> +};
> +
>  #endif /* _DW_MMC_H_ */
> diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
> index b72e4aa..ae45e4f 100644
> --- a/include/linux/mmc/dw_mmc.h
> +++ b/include/linux/mmc/dw_mmc.h
> @@ -78,6 +78,7 @@ struct mmc_data;
>   * @data_offset: Set the offset of DATA register according to VERID.
>   * @dev: Device associated with the MMC controller.
>   * @pdata: Platform data associated with the MMC controller.
> + * @drv_data: Driver specific data for identified variant of the controller
>   * @biu_clk: Pointer to bus interface unit clock instance.
>   * @ciu_clk: Pointer to card interface unit clock instance.
>   * @slot: Slots sharing this MMC controller.
> @@ -160,6 +161,7 @@ struct dw_mci {
>         u16                     data_offset;
>         struct device           *dev;
>         struct dw_mci_board     *pdata;
> +       struct dw_mci_drv_data  *drv_data;
>         struct clk              *biu_clk;
>         struct clk              *ciu_clk;
>         struct dw_mci_slot      *slot[MAX_MCI_SLOTS];
> --
> 1.6.6.rc2
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 5/6] mmc: dw_mmc: add device tree support
  2012-07-12 12:54   ` Thomas Abraham
@ 2012-07-16  4:23     ` Chris Ball
  -1 siblings, 0 replies; 53+ messages in thread
From: Chris Ball @ 2012-07-16  4:23 UTC (permalink / raw)
  To: Thomas Abraham
  Cc: linux-mmc, devicetree-discuss, linux-kernel, linux-arm-kernel,
	grant.likely, rob.herring, linux-samsung-soc, kgene.kim, patches

Hi,

On Thu, Jul 12 2012, Thomas Abraham wrote:
> diff --git a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> new file mode 100644
> index 0000000..3acd6c9
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> @@ -0,0 +1,108 @@
> +* Synopsis Designware Mobile Storage Host Controller
> +
> +The Synopsis designware mobile storage host controller is used to interface
> +a SoC with storage medium such as eMMC or SD/MMC cards.
> +
> +Required Properties:
> +
> +* compatible: should be one of the following
> +	- snps,dw-mshc: for controllers compliant with synopsis dw-mshc.
> +
> +* reg: physical base address of the dw-mshc controller and size of its memory
> +  region.
> +
> +* interrupts: interrupt specifier for the controller. The format and value of
> +  the interrupt specifier depends on the interrupt parent for the controller.

Please instead add:

This file documents differences between the core properties described
by mmc.txt and the properties used by the dw_mmc driver.

mmc.txt already describes compatible, reg, interrupts, bus-width,
cd-gpios, and wp-gpios, so you don't need to describe those again.

> +	cnt = sizeof(of_quriks) / sizeof(struct dw_mci_of_quirks);
> +	for (idx = 0; idx < cnt; idx++)
> +		if (of_get_property(np, of_quriks[idx].quirk, NULL))
> +			pdata->quirks |= of_quriks[idx].id;

of_quirks, not of_quriks.

Thanks,

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>
One Laptop Per Child

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v3 5/6] mmc: dw_mmc: add device tree support
@ 2012-07-16  4:23     ` Chris Ball
  0 siblings, 0 replies; 53+ messages in thread
From: Chris Ball @ 2012-07-16  4:23 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Thu, Jul 12 2012, Thomas Abraham wrote:
> diff --git a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> new file mode 100644
> index 0000000..3acd6c9
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> @@ -0,0 +1,108 @@
> +* Synopsis Designware Mobile Storage Host Controller
> +
> +The Synopsis designware mobile storage host controller is used to interface
> +a SoC with storage medium such as eMMC or SD/MMC cards.
> +
> +Required Properties:
> +
> +* compatible: should be one of the following
> +	- snps,dw-mshc: for controllers compliant with synopsis dw-mshc.
> +
> +* reg: physical base address of the dw-mshc controller and size of its memory
> +  region.
> +
> +* interrupts: interrupt specifier for the controller. The format and value of
> +  the interrupt specifier depends on the interrupt parent for the controller.

Please instead add:

This file documents differences between the core properties described
by mmc.txt and the properties used by the dw_mmc driver.

mmc.txt already describes compatible, reg, interrupts, bus-width,
cd-gpios, and wp-gpios, so you don't need to describe those again.

> +	cnt = sizeof(of_quriks) / sizeof(struct dw_mci_of_quirks);
> +	for (idx = 0; idx < cnt; idx++)
> +		if (of_get_property(np, of_quriks[idx].quirk, NULL))
> +			pdata->quirks |= of_quriks[idx].id;

of_quirks, not of_quriks.

Thanks,

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>
One Laptop Per Child

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 5/6] mmc: dw_mmc: add device tree support
  2012-07-16  4:15     ` Girish K S
@ 2012-07-16  4:30       ` Girish K S
  -1 siblings, 0 replies; 53+ messages in thread
From: Girish K S @ 2012-07-16  4:30 UTC (permalink / raw)
  To: Thomas Abraham
  Cc: linux-mmc, devicetree-discuss, linux-kernel, linux-arm-kernel,
	cjb, grant.likely, rob.herring, linux-samsung-soc, kgene.kim,
	patches

On 16 July 2012 09:45, Girish K S <girish.shivananjappa@linaro.org> wrote:
> On 12 July 2012 18:24, Thomas Abraham <thomas.abraham@linaro.org> wrote:
>> Add device tree based discovery support.
>>
>> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
>> ---
>>  .../devicetree/bindings/mmc/synposis-dw-mshc.txt   |  108 +++++++++++
>>  drivers/mmc/host/dw_mmc-pltfm.c                    |   24 +++
>>  drivers/mmc/host/dw_mmc.c                          |  201 +++++++++++++++++++-
>>  drivers/mmc/host/dw_mmc.h                          |    9 +
>>  include/linux/mmc/dw_mmc.h                         |    2 +
>>  5 files changed, 338 insertions(+), 6 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
>>
>> diff --git a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
>> new file mode 100644
>> index 0000000..3acd6c9
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
>> @@ -0,0 +1,108 @@
>> +* Synopsis Designware Mobile Storage Host Controller
>> +
>> +The Synopsis designware mobile storage host controller is used to interface
>> +a SoC with storage medium such as eMMC or SD/MMC cards.
>> +
>> +Required Properties:
>> +
>> +* compatible: should be one of the following
>> +       - snps,dw-mshc: for controllers compliant with synopsis dw-mshc.
>> +
>> +* reg: physical base address of the dw-mshc controller and size of its memory
>> +  region.
>> +
>> +* interrupts: interrupt specifier for the controller. The format and value of
>> +  the interrupt specifier depends on the interrupt parent for the controller.
>> +
>> +* #address-cells: should be 1.
>> +
>> +* #size-cells: should be 0.
>> +
>> +# Slots: The slot specific information are contained within child-nodes with
>> +  each child-node representing a supported slot. There should be atleast one
>> +  child node representing a card slot. The name of the child node representing
>> +  the slot is recommended to be slot@n where n is the unique number of the slot
>> +  connnected to the controller. The following are optional properties which
>> +  can be included in the slot child node.
>> +
>> +       * reg: specifies the physical slot number. The valid values of this
>> +         property is 0 to (num-slots -1), where num-slots is the value
>> +         specified by the num-slots property.
>> +
>> +       * bus-width: specifies the width of the data bus connected from the
>> +         controller to the card slot. The value should be 1, 4 or 8. In case
>> +         this property is not specified, a default value of 1 is assumed for
>> +         this property.
>> +
>> +       * cd-gpios: specifies the card detect gpio line. The format of the
>> +         gpio specifier depends on the gpio controller.
>> +
>> +       * wp-gpios: specifies the write protect gpio line. The format of the
>> +         gpio specifier depends on the gpio controller.
>> +
>> +       * gpios: specifies a list of gpios used for command, clock and data
>> +         bus. The first gpio is the command line and the second gpio is the
>> +         clock line. The rest of the gpios (depending on the bus-width
>> +         property) are the data lines in no particular order. The format of
>> +         the gpio specifier depends on the gpio controller.
>> +
>> +Optional properties:
>> +
>> +* num-slots: specifies the number of slots supported by the controller.
>> +  The number of physical slots actually used could be equal or less than the
>> +  value specified by num-slots. If this property is not specified, the value
>> +  of num-slot property is assumed to be 1.
>> +
>> +* fifo-depth: The maximum size of the tx/rx fifo's. If this property is not
>> +  specified, the default value of the fifo size is determined from the
>> +  controller registers.
>> +
>> +* card-detect-delay: Delay in milli-seconds before detecting card after card
>> +  insert event. The default value is 0.
>> +
>> +* supports-highspeed: Enables support for high speed cards (upto 50MHz)
>> +
>> +* card-detection-broken: The card detection functionality is not available on
>> +  any of the slots.
>> +
>> +* no-write-protect: The write protect pad of the controller is not connected
>> +  to the write protect pin on the slot.
>> +
>> +Aliases:
>> +
>> +- All the MSHC controller nodes should be represented in the aliases node using
>> +  the following format 'mshc{n}' where n is a unique number for the alias.
>> +
>> +
>> +Example:
>> +
>> +  The MSHC controller node can be split into two portions, SoC specific and
>> +  board specific portions as listed below.
>> +
>> +       dwmmc0@12200000 {
>> +               compatible = "snps,dw-mshc";
>> +               reg = <0x12200000 0x1000>;
>> +               interrupts = <0 75 0>;
>> +               #address-cells = <1>;
>> +               #size-cells = <0>;
>> +       };
>> +
>> +       dwmmc0@12200000 {
>> +               num-slots = <1>;
>> +               supports-highspeed;
>> +               card-detection-broken;
>> +               no-write-protect;
>> +               fifo-depth = <0x80>;
>> +               card-detect-delay = <200>;
>> +
>> +               slot@0 {
>> +                       reg = <0>;
>> +                       bus-width = <8>;
>> +                       cd-gpios = <&gpc0 2 2 3 3>;
>> +                       gpios = <&gpc0 0 2 0 3>, <&gpc0 1 2 0 3>,
>> +                               <&gpc1 0 2 3 3>, <&gpc1 1 2 3 3>,
>> +                               <&gpc1 2 2 3 3>, <&gpc1 3 2 3 3>,
>> +                               <&gpc0 3 2 3 3>, <&gpc0 4 2 3 3>,
>> +                               <&gpc0 5 2 3 3>, <&gpc0 6 2 3 3>;
>> +               };
>> +       };
>> diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
>> index 9a63299..8d24f6d 100644
>> --- a/drivers/mmc/host/dw_mmc-pltfm.c
>> +++ b/drivers/mmc/host/dw_mmc-pltfm.c
>> @@ -19,8 +19,24 @@
>>  #include <linux/mmc/host.h>
>>  #include <linux/mmc/mmc.h>
>>  #include <linux/mmc/dw_mmc.h>
>> +#include <linux/of.h>
>>  #include "dw_mmc.h"
>>
>> +#ifdef CONFIG_OF
>> +static struct dw_mci_drv_data synopsis_drv_data = {
>> +       .ctrl_type      = DW_MCI_TYPE_SYNOPSIS,
>> +};
>> +
>> +static const struct of_device_id dw_mci_pltfm_match[] = {
>> +       { .compatible = "snps,dw-mshc",
>> +                       .data = (void *)&synopsis_drv_data, },
>> +       {},
>> +};
>> +MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
>> +#else
>> +static const struct of_device_id dw_mci_pltfm_match[];
> the #else and a statement can be completely removed if of_match_ptr is
> used while accessing the dw_mci_pltfm_match in of_match_node function.
>> +#endif
>> +
>>  static int dw_mci_pltfm_probe(struct platform_device *pdev)
>>  {
>>         struct dw_mci *host;
>> @@ -51,6 +67,13 @@ static int dw_mci_pltfm_probe(struct platform_device *pdev)
>>         if (!host->regs)
>>                 goto err_free;
>>         platform_set_drvdata(pdev, host);
>> +
>> +       if (pdev->dev.of_node) {
>> +               const struct of_device_id *match;
>> +               match = of_match_node(dw_mci_pltfm_match, pdev->dev.of_node);
> can be modified to of_match_node(of_match_pt(dw_mci_pltfm_match),
> pdev->dev.of_node);
> This will remove the dummy allocation of variable as mentioned above.
Sorry not allocation but declaration
> Also it will be generic in non dt case.
>> +               host->drv_data = match->data;
>> +       }
>> +
>>         ret = dw_mci_probe(host);
>>         if (ret)
>>                 goto err_out;
>> @@ -111,6 +134,7 @@ static struct platform_driver dw_mci_pltfm_driver = {
>>         .remove         = __exit_p(dw_mci_pltfm_remove),
>>         .driver         = {
>>                 .name           = "dw_mmc",
>> +               .of_match_table = of_match_ptr(dw_mci_pltfm_match),
>>                 .pm             = &dw_mci_pltfm_pmops,
>>         },
>>  };
>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
>> index 075f89d..3bc276d 100644
>> --- a/drivers/mmc/host/dw_mmc.c
>> +++ b/drivers/mmc/host/dw_mmc.c
>> @@ -33,9 +33,13 @@
>>  #include <linux/bitops.h>
>>  #include <linux/regulator/consumer.h>
>>  #include <linux/workqueue.h>
>> +#include <linux/of.h>
>> +#include <linux/of_gpio.h>
>>
>>  #include "dw_mmc.h"
>>
>> +#define NUM_PINS(x) (x + 2)
>> +
>>  /* Common flag combinations */
>>  #define DW_MCI_DATA_ERROR_FLAGS        (SDMMC_INT_DTO | SDMMC_INT_DCRC | \
>>                                  SDMMC_INT_HTO | SDMMC_INT_SBE  | \
>> @@ -86,6 +90,8 @@ struct idmac_desc {
>>  struct dw_mci_slot {
>>         struct mmc_host         *mmc;
>>         struct dw_mci           *host;
>> +       int                     wp_gpio;
>> +       int                     cd_gpio;
>>
>>         u32                     ctype;
>>
>> @@ -1762,10 +1768,106 @@ static void dw_mci_work_routine_card(struct work_struct *work)
>>         }
>>  }
>>
>> +#ifdef CONFIG_OF
>> +static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
>> +{
>> +       struct device_node *np;
>> +       const __be32 *addr;
>> +       int len;
>> +
>> +       if (!dev || !dev->of_node)
>> +               return NULL;
>> +
>> +       for_each_child_of_node(dev->of_node, np) {
>> +               addr = of_get_property(np, "reg", &len);
>> +               if (!addr || (len < sizeof(int)))
>> +                       continue;
>> +               if (be32_to_cpup(addr) == slot)
>> +                       return np;
>> +       }
>> +       return NULL;
>> +}
>> +
>> +static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
>> +{
>> +       struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
>> +       u32 bus_wd = 1;
>> +
>> +       if (!np)
>> +               return 1;
>> +
>> +       if (of_property_read_u32(np, "bus-width", &bus_wd))
>> +               dev_err(dev, "bus-width property not found, assuming width"
>> +                              " as 1\n");
>> +       return bus_wd;
>> +}
>> +
>> +static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
>> +{
>> +       struct device_node *np = dw_mci_of_find_slot_node(host->dev, slot);
>> +       int idx, gpio, ret;
>> +
>> +       if (!np)
>> +               return -EINVAL;
>> +
>> +       for (idx = 0; idx < NUM_PINS(bus_wd); idx++) {
>> +               gpio = of_get_gpio(np, idx);
>> +               if (!gpio_is_valid(gpio)) {
>> +                       dev_err(host->dev, "invalid gpio: %d\n", gpio);
>> +                       return -EINVAL;
>> +               }
>> +
>> +               ret = devm_gpio_request(host->dev, gpio, "dw-mci-bus");
>> +               if (ret) {
>> +                       dev_err(host->dev, "gpio [%d] request failed\n", gpio);
>> +                       return -EBUSY;
>> +               }
>> +       }
>> +
>> +       host->slot[slot]->wp_gpio = -1;
>> +       gpio = of_get_named_gpio(np, "wp-gpios", 0);
>> +       if (!gpio_is_valid(gpio)) {
>> +               dev_info(host->dev, "wp gpio not available");
>> +       } else {
>> +               ret = devm_gpio_request(host->dev, gpio, "dw-mci-wp");
>> +               if (ret)
>> +                       dev_info(host->dev, "gpio [%d] request failed\n",
>> +                                               gpio);
>> +               else
>> +                       host->slot[slot]->wp_gpio = gpio;
>> +       }
>> +
>> +       host->slot[slot]->cd_gpio = -1;
>> +       gpio = of_get_named_gpio(np, "cd-gpios", 0);
>> +       if (!gpio_is_valid(gpio)) {
>> +               dev_info(host->dev, "cd gpio not available");
>> +       } else {
>> +               ret = devm_gpio_request(host->dev, gpio, "dw-mci-cd");
>> +               if (ret)
>> +                       dev_err(host->dev, "gpio [%d] request failed\n", gpio);
>> +               else
>> +                       host->slot[slot]->cd_gpio = gpio;
>> +       }
>> +
>> +       return 0;
>> +}
>> +#else /* CONFIG_OF */
>> +static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
>> +{
>> +       return 1;
>> +}
>> +
>> +static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
>> +{
>> +       return -EINVAL;
>> +}
>> +#endif /* CONFIG_OF */
>> +
>>  static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>>  {
>>         struct mmc_host *mmc;
>>         struct dw_mci_slot *slot;
>> +       int ctrl_id, ret;
>>
>>         mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
>>         if (!mmc)
>> @@ -1775,6 +1877,7 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>>         slot->id = id;
>>         slot->mmc = mmc;
>>         slot->host = host;
>> +       host->slot[id] = slot;
>>
>>         mmc->ops = &dw_mci_ops;
>>         mmc->f_min = DIV_ROUND_UP(host->bus_hz, 510);
>> @@ -1795,12 +1898,33 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>>         if (host->pdata->caps)
>>                 mmc->caps = host->pdata->caps;
>>
>> +       if (host->dev->of_node) {
>> +               ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
>> +               if (ctrl_id < 0)
>> +                       ctrl_id = 0;
>> +       }
>> +       if (host->drv_data->caps)
>> +               mmc->caps |= host->drv_data->caps[ctrl_id];
>> +
>>         if (host->pdata->caps2)
>>                 mmc->caps2 = host->pdata->caps2;
>>
>> -       if (host->pdata->get_bus_wd)
>> +       if (host->pdata->get_bus_wd) {
>>                 if (host->pdata->get_bus_wd(slot->id) >= 4)
>>                         mmc->caps |= MMC_CAP_4_BIT_DATA;
>> +       } else if (host->dev->of_node) {
>> +               unsigned int bus_width;
>> +               bus_width = dw_mci_of_get_bus_wd(host->dev, slot->id);
>> +               switch (bus_width) {
>> +               case 8:
>> +                       mmc->caps |= MMC_CAP_8_BIT_DATA;
>> +               case 4:
>> +                       mmc->caps |= MMC_CAP_4_BIT_DATA;
>> +               }
>> +               ret = dw_mci_of_setup_bus(host, slot->id, bus_width);
>> +               if (ret)
>> +                       goto err_setup_bus;
>> +       }
>>
>>         if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED)
>>                 mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
>> @@ -1845,7 +1969,6 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>>         else
>>                 clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
>>
>> -       host->slot[id] = slot;
>>         mmc_add_host(mmc);
>>
>>  #if defined(CONFIG_DEBUG_FS)
>> @@ -1862,6 +1985,10 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>>         queue_work(host->card_workqueue, &host->card_work);
>>
>>         return 0;
>> +
>> +err_setup_bus:
>> +       mmc_free_host(mmc);
>> +       return -EINVAL;
>>  }
>>
>>  static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
>> @@ -1937,16 +2064,78 @@ static bool mci_wait_reset(struct device *dev, struct dw_mci *host)
>>         return false;
>>  }
>>
>> +#ifdef CONFIG_OF
>> +static struct dw_mci_of_quirks {
>> +       char *quirk;
>> +       int id;
>> +} of_quriks[] = {
>> +       {
>> +               .quirk  = "supports-highspeed",
>> +               .id     = DW_MCI_QUIRK_HIGHSPEED,
>> +       }, {
>> +               .quirk  = "card-detection-broken",
>> +               .id     = DW_MCI_QUIRK_BROKEN_CARD_DETECTION,
>> +       }, {
>> +               .quirk  = "no-write-protect",
>> +               .id     = DW_MCI_QUIRK_NO_WRITE_PROTECT,
>> +       }
>> +};
>> +
>> +static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
>> +{
>> +       struct dw_mci_board *pdata;
>> +       struct device *dev = host->dev;
>> +       struct device_node *np = dev->of_node;
>> +       int idx, cnt;
>> +
>> +       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
>> +       if (!pdata) {
>> +               dev_err(dev, "could not allocate memory for pdata\n");
>> +               return ERR_PTR(-ENOMEM);
>> +       }
>> +
>> +       /* find out number of slots supported */
>> +       if (of_property_read_u32(dev->of_node, "num-slots",
>> +                               &pdata->num_slots)) {
>> +               dev_info(dev, "num-slots property not found, "
>> +                               "assuming 1 slot is available\n");
>> +               pdata->num_slots = 1;
>> +       }
>> +
>> +       /* get quirks */
>> +       cnt = sizeof(of_quriks) / sizeof(struct dw_mci_of_quirks);
>> +       for (idx = 0; idx < cnt; idx++)
>> +               if (of_get_property(np, of_quriks[idx].quirk, NULL))
>> +                       pdata->quirks |= of_quriks[idx].id;
>> +
>> +       if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
>> +               dev_info(dev, "fifo-depth property not found, using "
>> +                               "value of FIFOTH register as default\n");
>> +
>> +       of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
>> +
>> +       return pdata;
>> +}
>> +
>> +#else /* CONFIG_OF */
>> +static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
>> +{
>> +       return ERR_PTR(-EINVAL);
>> +}
>> +#endif /* CONFIG_OF */
>> +
>>  int dw_mci_probe(struct dw_mci *host)
>>  {
>>         int width, i, ret = 0;
>>         u32 fifo_size;
>>         int init_slots = 0;
>>
>> -       if (!host->pdata || !host->pdata->init) {
>> -               dev_err(host->dev,
>> -                       "Platform data must supply init function\n");
>> -               return -ENODEV;
>> +       if (!host->pdata) {
>> +               host->pdata = dw_mci_parse_dt(host);
>> +               if (IS_ERR(host->pdata)) {
>> +                       dev_err(host->dev, "platform data not available\n");
>> +                       return -EINVAL;
>> +               }
>>         }
>>
>>         if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
>> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
>> index 15c27e1..1ecaa02 100644
>> --- a/drivers/mmc/host/dw_mmc.h
>> +++ b/drivers/mmc/host/dw_mmc.h
>> @@ -182,4 +182,13 @@ extern int dw_mci_suspend(struct dw_mci *host);
>>  extern int dw_mci_resume(struct dw_mci *host);
>>  #endif
>>
>> +/* Variations in the dw_mci controller */
>> +#define DW_MCI_TYPE_SYNOPSIS           0
>> +
>> +/* dw_mci platform driver data */
>> +struct dw_mci_drv_data {
>> +       unsigned long           ctrl_type;
>> +       unsigned long           *caps;
>> +};
>> +
>>  #endif /* _DW_MMC_H_ */
>> diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
>> index b72e4aa..ae45e4f 100644
>> --- a/include/linux/mmc/dw_mmc.h
>> +++ b/include/linux/mmc/dw_mmc.h
>> @@ -78,6 +78,7 @@ struct mmc_data;
>>   * @data_offset: Set the offset of DATA register according to VERID.
>>   * @dev: Device associated with the MMC controller.
>>   * @pdata: Platform data associated with the MMC controller.
>> + * @drv_data: Driver specific data for identified variant of the controller
>>   * @biu_clk: Pointer to bus interface unit clock instance.
>>   * @ciu_clk: Pointer to card interface unit clock instance.
>>   * @slot: Slots sharing this MMC controller.
>> @@ -160,6 +161,7 @@ struct dw_mci {
>>         u16                     data_offset;
>>         struct device           *dev;
>>         struct dw_mci_board     *pdata;
>> +       struct dw_mci_drv_data  *drv_data;
>>         struct clk              *biu_clk;
>>         struct clk              *ciu_clk;
>>         struct dw_mci_slot      *slot[MAX_MCI_SLOTS];
>> --
>> 1.6.6.rc2
>>
>> --
>> 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

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v3 5/6] mmc: dw_mmc: add device tree support
@ 2012-07-16  4:30       ` Girish K S
  0 siblings, 0 replies; 53+ messages in thread
From: Girish K S @ 2012-07-16  4:30 UTC (permalink / raw)
  To: linux-arm-kernel

On 16 July 2012 09:45, Girish K S <girish.shivananjappa@linaro.org> wrote:
> On 12 July 2012 18:24, Thomas Abraham <thomas.abraham@linaro.org> wrote:
>> Add device tree based discovery support.
>>
>> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
>> ---
>>  .../devicetree/bindings/mmc/synposis-dw-mshc.txt   |  108 +++++++++++
>>  drivers/mmc/host/dw_mmc-pltfm.c                    |   24 +++
>>  drivers/mmc/host/dw_mmc.c                          |  201 +++++++++++++++++++-
>>  drivers/mmc/host/dw_mmc.h                          |    9 +
>>  include/linux/mmc/dw_mmc.h                         |    2 +
>>  5 files changed, 338 insertions(+), 6 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
>>
>> diff --git a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
>> new file mode 100644
>> index 0000000..3acd6c9
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
>> @@ -0,0 +1,108 @@
>> +* Synopsis Designware Mobile Storage Host Controller
>> +
>> +The Synopsis designware mobile storage host controller is used to interface
>> +a SoC with storage medium such as eMMC or SD/MMC cards.
>> +
>> +Required Properties:
>> +
>> +* compatible: should be one of the following
>> +       - snps,dw-mshc: for controllers compliant with synopsis dw-mshc.
>> +
>> +* reg: physical base address of the dw-mshc controller and size of its memory
>> +  region.
>> +
>> +* interrupts: interrupt specifier for the controller. The format and value of
>> +  the interrupt specifier depends on the interrupt parent for the controller.
>> +
>> +* #address-cells: should be 1.
>> +
>> +* #size-cells: should be 0.
>> +
>> +# Slots: The slot specific information are contained within child-nodes with
>> +  each child-node representing a supported slot. There should be atleast one
>> +  child node representing a card slot. The name of the child node representing
>> +  the slot is recommended to be slot at n where n is the unique number of the slot
>> +  connnected to the controller. The following are optional properties which
>> +  can be included in the slot child node.
>> +
>> +       * reg: specifies the physical slot number. The valid values of this
>> +         property is 0 to (num-slots -1), where num-slots is the value
>> +         specified by the num-slots property.
>> +
>> +       * bus-width: specifies the width of the data bus connected from the
>> +         controller to the card slot. The value should be 1, 4 or 8. In case
>> +         this property is not specified, a default value of 1 is assumed for
>> +         this property.
>> +
>> +       * cd-gpios: specifies the card detect gpio line. The format of the
>> +         gpio specifier depends on the gpio controller.
>> +
>> +       * wp-gpios: specifies the write protect gpio line. The format of the
>> +         gpio specifier depends on the gpio controller.
>> +
>> +       * gpios: specifies a list of gpios used for command, clock and data
>> +         bus. The first gpio is the command line and the second gpio is the
>> +         clock line. The rest of the gpios (depending on the bus-width
>> +         property) are the data lines in no particular order. The format of
>> +         the gpio specifier depends on the gpio controller.
>> +
>> +Optional properties:
>> +
>> +* num-slots: specifies the number of slots supported by the controller.
>> +  The number of physical slots actually used could be equal or less than the
>> +  value specified by num-slots. If this property is not specified, the value
>> +  of num-slot property is assumed to be 1.
>> +
>> +* fifo-depth: The maximum size of the tx/rx fifo's. If this property is not
>> +  specified, the default value of the fifo size is determined from the
>> +  controller registers.
>> +
>> +* card-detect-delay: Delay in milli-seconds before detecting card after card
>> +  insert event. The default value is 0.
>> +
>> +* supports-highspeed: Enables support for high speed cards (upto 50MHz)
>> +
>> +* card-detection-broken: The card detection functionality is not available on
>> +  any of the slots.
>> +
>> +* no-write-protect: The write protect pad of the controller is not connected
>> +  to the write protect pin on the slot.
>> +
>> +Aliases:
>> +
>> +- All the MSHC controller nodes should be represented in the aliases node using
>> +  the following format 'mshc{n}' where n is a unique number for the alias.
>> +
>> +
>> +Example:
>> +
>> +  The MSHC controller node can be split into two portions, SoC specific and
>> +  board specific portions as listed below.
>> +
>> +       dwmmc0 at 12200000 {
>> +               compatible = "snps,dw-mshc";
>> +               reg = <0x12200000 0x1000>;
>> +               interrupts = <0 75 0>;
>> +               #address-cells = <1>;
>> +               #size-cells = <0>;
>> +       };
>> +
>> +       dwmmc0 at 12200000 {
>> +               num-slots = <1>;
>> +               supports-highspeed;
>> +               card-detection-broken;
>> +               no-write-protect;
>> +               fifo-depth = <0x80>;
>> +               card-detect-delay = <200>;
>> +
>> +               slot at 0 {
>> +                       reg = <0>;
>> +                       bus-width = <8>;
>> +                       cd-gpios = <&gpc0 2 2 3 3>;
>> +                       gpios = <&gpc0 0 2 0 3>, <&gpc0 1 2 0 3>,
>> +                               <&gpc1 0 2 3 3>, <&gpc1 1 2 3 3>,
>> +                               <&gpc1 2 2 3 3>, <&gpc1 3 2 3 3>,
>> +                               <&gpc0 3 2 3 3>, <&gpc0 4 2 3 3>,
>> +                               <&gpc0 5 2 3 3>, <&gpc0 6 2 3 3>;
>> +               };
>> +       };
>> diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
>> index 9a63299..8d24f6d 100644
>> --- a/drivers/mmc/host/dw_mmc-pltfm.c
>> +++ b/drivers/mmc/host/dw_mmc-pltfm.c
>> @@ -19,8 +19,24 @@
>>  #include <linux/mmc/host.h>
>>  #include <linux/mmc/mmc.h>
>>  #include <linux/mmc/dw_mmc.h>
>> +#include <linux/of.h>
>>  #include "dw_mmc.h"
>>
>> +#ifdef CONFIG_OF
>> +static struct dw_mci_drv_data synopsis_drv_data = {
>> +       .ctrl_type      = DW_MCI_TYPE_SYNOPSIS,
>> +};
>> +
>> +static const struct of_device_id dw_mci_pltfm_match[] = {
>> +       { .compatible = "snps,dw-mshc",
>> +                       .data = (void *)&synopsis_drv_data, },
>> +       {},
>> +};
>> +MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
>> +#else
>> +static const struct of_device_id dw_mci_pltfm_match[];
> the #else and a statement can be completely removed if of_match_ptr is
> used while accessing the dw_mci_pltfm_match in of_match_node function.
>> +#endif
>> +
>>  static int dw_mci_pltfm_probe(struct platform_device *pdev)
>>  {
>>         struct dw_mci *host;
>> @@ -51,6 +67,13 @@ static int dw_mci_pltfm_probe(struct platform_device *pdev)
>>         if (!host->regs)
>>                 goto err_free;
>>         platform_set_drvdata(pdev, host);
>> +
>> +       if (pdev->dev.of_node) {
>> +               const struct of_device_id *match;
>> +               match = of_match_node(dw_mci_pltfm_match, pdev->dev.of_node);
> can be modified to of_match_node(of_match_pt(dw_mci_pltfm_match),
> pdev->dev.of_node);
> This will remove the dummy allocation of variable as mentioned above.
Sorry not allocation but declaration
> Also it will be generic in non dt case.
>> +               host->drv_data = match->data;
>> +       }
>> +
>>         ret = dw_mci_probe(host);
>>         if (ret)
>>                 goto err_out;
>> @@ -111,6 +134,7 @@ static struct platform_driver dw_mci_pltfm_driver = {
>>         .remove         = __exit_p(dw_mci_pltfm_remove),
>>         .driver         = {
>>                 .name           = "dw_mmc",
>> +               .of_match_table = of_match_ptr(dw_mci_pltfm_match),
>>                 .pm             = &dw_mci_pltfm_pmops,
>>         },
>>  };
>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
>> index 075f89d..3bc276d 100644
>> --- a/drivers/mmc/host/dw_mmc.c
>> +++ b/drivers/mmc/host/dw_mmc.c
>> @@ -33,9 +33,13 @@
>>  #include <linux/bitops.h>
>>  #include <linux/regulator/consumer.h>
>>  #include <linux/workqueue.h>
>> +#include <linux/of.h>
>> +#include <linux/of_gpio.h>
>>
>>  #include "dw_mmc.h"
>>
>> +#define NUM_PINS(x) (x + 2)
>> +
>>  /* Common flag combinations */
>>  #define DW_MCI_DATA_ERROR_FLAGS        (SDMMC_INT_DTO | SDMMC_INT_DCRC | \
>>                                  SDMMC_INT_HTO | SDMMC_INT_SBE  | \
>> @@ -86,6 +90,8 @@ struct idmac_desc {
>>  struct dw_mci_slot {
>>         struct mmc_host         *mmc;
>>         struct dw_mci           *host;
>> +       int                     wp_gpio;
>> +       int                     cd_gpio;
>>
>>         u32                     ctype;
>>
>> @@ -1762,10 +1768,106 @@ static void dw_mci_work_routine_card(struct work_struct *work)
>>         }
>>  }
>>
>> +#ifdef CONFIG_OF
>> +static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
>> +{
>> +       struct device_node *np;
>> +       const __be32 *addr;
>> +       int len;
>> +
>> +       if (!dev || !dev->of_node)
>> +               return NULL;
>> +
>> +       for_each_child_of_node(dev->of_node, np) {
>> +               addr = of_get_property(np, "reg", &len);
>> +               if (!addr || (len < sizeof(int)))
>> +                       continue;
>> +               if (be32_to_cpup(addr) == slot)
>> +                       return np;
>> +       }
>> +       return NULL;
>> +}
>> +
>> +static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
>> +{
>> +       struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
>> +       u32 bus_wd = 1;
>> +
>> +       if (!np)
>> +               return 1;
>> +
>> +       if (of_property_read_u32(np, "bus-width", &bus_wd))
>> +               dev_err(dev, "bus-width property not found, assuming width"
>> +                              " as 1\n");
>> +       return bus_wd;
>> +}
>> +
>> +static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
>> +{
>> +       struct device_node *np = dw_mci_of_find_slot_node(host->dev, slot);
>> +       int idx, gpio, ret;
>> +
>> +       if (!np)
>> +               return -EINVAL;
>> +
>> +       for (idx = 0; idx < NUM_PINS(bus_wd); idx++) {
>> +               gpio = of_get_gpio(np, idx);
>> +               if (!gpio_is_valid(gpio)) {
>> +                       dev_err(host->dev, "invalid gpio: %d\n", gpio);
>> +                       return -EINVAL;
>> +               }
>> +
>> +               ret = devm_gpio_request(host->dev, gpio, "dw-mci-bus");
>> +               if (ret) {
>> +                       dev_err(host->dev, "gpio [%d] request failed\n", gpio);
>> +                       return -EBUSY;
>> +               }
>> +       }
>> +
>> +       host->slot[slot]->wp_gpio = -1;
>> +       gpio = of_get_named_gpio(np, "wp-gpios", 0);
>> +       if (!gpio_is_valid(gpio)) {
>> +               dev_info(host->dev, "wp gpio not available");
>> +       } else {
>> +               ret = devm_gpio_request(host->dev, gpio, "dw-mci-wp");
>> +               if (ret)
>> +                       dev_info(host->dev, "gpio [%d] request failed\n",
>> +                                               gpio);
>> +               else
>> +                       host->slot[slot]->wp_gpio = gpio;
>> +       }
>> +
>> +       host->slot[slot]->cd_gpio = -1;
>> +       gpio = of_get_named_gpio(np, "cd-gpios", 0);
>> +       if (!gpio_is_valid(gpio)) {
>> +               dev_info(host->dev, "cd gpio not available");
>> +       } else {
>> +               ret = devm_gpio_request(host->dev, gpio, "dw-mci-cd");
>> +               if (ret)
>> +                       dev_err(host->dev, "gpio [%d] request failed\n", gpio);
>> +               else
>> +                       host->slot[slot]->cd_gpio = gpio;
>> +       }
>> +
>> +       return 0;
>> +}
>> +#else /* CONFIG_OF */
>> +static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
>> +{
>> +       return 1;
>> +}
>> +
>> +static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
>> +{
>> +       return -EINVAL;
>> +}
>> +#endif /* CONFIG_OF */
>> +
>>  static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>>  {
>>         struct mmc_host *mmc;
>>         struct dw_mci_slot *slot;
>> +       int ctrl_id, ret;
>>
>>         mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
>>         if (!mmc)
>> @@ -1775,6 +1877,7 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>>         slot->id = id;
>>         slot->mmc = mmc;
>>         slot->host = host;
>> +       host->slot[id] = slot;
>>
>>         mmc->ops = &dw_mci_ops;
>>         mmc->f_min = DIV_ROUND_UP(host->bus_hz, 510);
>> @@ -1795,12 +1898,33 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>>         if (host->pdata->caps)
>>                 mmc->caps = host->pdata->caps;
>>
>> +       if (host->dev->of_node) {
>> +               ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
>> +               if (ctrl_id < 0)
>> +                       ctrl_id = 0;
>> +       }
>> +       if (host->drv_data->caps)
>> +               mmc->caps |= host->drv_data->caps[ctrl_id];
>> +
>>         if (host->pdata->caps2)
>>                 mmc->caps2 = host->pdata->caps2;
>>
>> -       if (host->pdata->get_bus_wd)
>> +       if (host->pdata->get_bus_wd) {
>>                 if (host->pdata->get_bus_wd(slot->id) >= 4)
>>                         mmc->caps |= MMC_CAP_4_BIT_DATA;
>> +       } else if (host->dev->of_node) {
>> +               unsigned int bus_width;
>> +               bus_width = dw_mci_of_get_bus_wd(host->dev, slot->id);
>> +               switch (bus_width) {
>> +               case 8:
>> +                       mmc->caps |= MMC_CAP_8_BIT_DATA;
>> +               case 4:
>> +                       mmc->caps |= MMC_CAP_4_BIT_DATA;
>> +               }
>> +               ret = dw_mci_of_setup_bus(host, slot->id, bus_width);
>> +               if (ret)
>> +                       goto err_setup_bus;
>> +       }
>>
>>         if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED)
>>                 mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
>> @@ -1845,7 +1969,6 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>>         else
>>                 clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
>>
>> -       host->slot[id] = slot;
>>         mmc_add_host(mmc);
>>
>>  #if defined(CONFIG_DEBUG_FS)
>> @@ -1862,6 +1985,10 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>>         queue_work(host->card_workqueue, &host->card_work);
>>
>>         return 0;
>> +
>> +err_setup_bus:
>> +       mmc_free_host(mmc);
>> +       return -EINVAL;
>>  }
>>
>>  static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
>> @@ -1937,16 +2064,78 @@ static bool mci_wait_reset(struct device *dev, struct dw_mci *host)
>>         return false;
>>  }
>>
>> +#ifdef CONFIG_OF
>> +static struct dw_mci_of_quirks {
>> +       char *quirk;
>> +       int id;
>> +} of_quriks[] = {
>> +       {
>> +               .quirk  = "supports-highspeed",
>> +               .id     = DW_MCI_QUIRK_HIGHSPEED,
>> +       }, {
>> +               .quirk  = "card-detection-broken",
>> +               .id     = DW_MCI_QUIRK_BROKEN_CARD_DETECTION,
>> +       }, {
>> +               .quirk  = "no-write-protect",
>> +               .id     = DW_MCI_QUIRK_NO_WRITE_PROTECT,
>> +       }
>> +};
>> +
>> +static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
>> +{
>> +       struct dw_mci_board *pdata;
>> +       struct device *dev = host->dev;
>> +       struct device_node *np = dev->of_node;
>> +       int idx, cnt;
>> +
>> +       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
>> +       if (!pdata) {
>> +               dev_err(dev, "could not allocate memory for pdata\n");
>> +               return ERR_PTR(-ENOMEM);
>> +       }
>> +
>> +       /* find out number of slots supported */
>> +       if (of_property_read_u32(dev->of_node, "num-slots",
>> +                               &pdata->num_slots)) {
>> +               dev_info(dev, "num-slots property not found, "
>> +                               "assuming 1 slot is available\n");
>> +               pdata->num_slots = 1;
>> +       }
>> +
>> +       /* get quirks */
>> +       cnt = sizeof(of_quriks) / sizeof(struct dw_mci_of_quirks);
>> +       for (idx = 0; idx < cnt; idx++)
>> +               if (of_get_property(np, of_quriks[idx].quirk, NULL))
>> +                       pdata->quirks |= of_quriks[idx].id;
>> +
>> +       if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
>> +               dev_info(dev, "fifo-depth property not found, using "
>> +                               "value of FIFOTH register as default\n");
>> +
>> +       of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
>> +
>> +       return pdata;
>> +}
>> +
>> +#else /* CONFIG_OF */
>> +static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
>> +{
>> +       return ERR_PTR(-EINVAL);
>> +}
>> +#endif /* CONFIG_OF */
>> +
>>  int dw_mci_probe(struct dw_mci *host)
>>  {
>>         int width, i, ret = 0;
>>         u32 fifo_size;
>>         int init_slots = 0;
>>
>> -       if (!host->pdata || !host->pdata->init) {
>> -               dev_err(host->dev,
>> -                       "Platform data must supply init function\n");
>> -               return -ENODEV;
>> +       if (!host->pdata) {
>> +               host->pdata = dw_mci_parse_dt(host);
>> +               if (IS_ERR(host->pdata)) {
>> +                       dev_err(host->dev, "platform data not available\n");
>> +                       return -EINVAL;
>> +               }
>>         }
>>
>>         if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
>> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
>> index 15c27e1..1ecaa02 100644
>> --- a/drivers/mmc/host/dw_mmc.h
>> +++ b/drivers/mmc/host/dw_mmc.h
>> @@ -182,4 +182,13 @@ extern int dw_mci_suspend(struct dw_mci *host);
>>  extern int dw_mci_resume(struct dw_mci *host);
>>  #endif
>>
>> +/* Variations in the dw_mci controller */
>> +#define DW_MCI_TYPE_SYNOPSIS           0
>> +
>> +/* dw_mci platform driver data */
>> +struct dw_mci_drv_data {
>> +       unsigned long           ctrl_type;
>> +       unsigned long           *caps;
>> +};
>> +
>>  #endif /* _DW_MMC_H_ */
>> diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
>> index b72e4aa..ae45e4f 100644
>> --- a/include/linux/mmc/dw_mmc.h
>> +++ b/include/linux/mmc/dw_mmc.h
>> @@ -78,6 +78,7 @@ struct mmc_data;
>>   * @data_offset: Set the offset of DATA register according to VERID.
>>   * @dev: Device associated with the MMC controller.
>>   * @pdata: Platform data associated with the MMC controller.
>> + * @drv_data: Driver specific data for identified variant of the controller
>>   * @biu_clk: Pointer to bus interface unit clock instance.
>>   * @ciu_clk: Pointer to card interface unit clock instance.
>>   * @slot: Slots sharing this MMC controller.
>> @@ -160,6 +161,7 @@ struct dw_mci {
>>         u16                     data_offset;
>>         struct device           *dev;
>>         struct dw_mci_board     *pdata;
>> +       struct dw_mci_drv_data  *drv_data;
>>         struct clk              *biu_clk;
>>         struct clk              *ciu_clk;
>>         struct dw_mci_slot      *slot[MAX_MCI_SLOTS];
>> --
>> 1.6.6.rc2
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 5/6] mmc: dw_mmc: add device tree support
  2012-07-16  4:15     ` Girish K S
@ 2012-07-17 10:19       ` Thomas Abraham
  -1 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-17 10:19 UTC (permalink / raw)
  To: Girish K S
  Cc: linux-mmc, devicetree-discuss, linux-kernel, linux-arm-kernel,
	cjb, grant.likely, rob.herring, linux-samsung-soc, kgene.kim,
	patches

On 16 July 2012 09:45, Girish K S <girish.shivananjappa@linaro.org> wrote:
> On 12 July 2012 18:24, Thomas Abraham <thomas.abraham@linaro.org> wrote:

[...]

>>
>> +#ifdef CONFIG_OF
>> +static struct dw_mci_drv_data synopsis_drv_data = {
>> +       .ctrl_type      = DW_MCI_TYPE_SYNOPSIS,
>> +};
>> +
>> +static const struct of_device_id dw_mci_pltfm_match[] = {
>> +       { .compatible = "snps,dw-mshc",
>> +                       .data = (void *)&synopsis_drv_data, },
>> +       {},
>> +};
>> +MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
>> +#else
>> +static const struct of_device_id dw_mci_pltfm_match[];
> the #else and a statement can be completely removed if of_match_ptr is
> used while accessing the dw_mci_pltfm_match in of_match_node function.
>> +#endif
>> +
>>  static int dw_mci_pltfm_probe(struct platform_device *pdev)
>>  {
>>         struct dw_mci *host;
>> @@ -51,6 +67,13 @@ static int dw_mci_pltfm_probe(struct platform_device *pdev)
>>         if (!host->regs)
>>                 goto err_free;
>>         platform_set_drvdata(pdev, host);
>> +
>> +       if (pdev->dev.of_node) {
>> +               const struct of_device_id *match;
>> +               match = of_match_node(dw_mci_pltfm_match, pdev->dev.of_node);
> can be modified to of_match_node(of_match_pt(dw_mci_pltfm_match),
> pdev->dev.of_node);
> This will remove the dummy allocation of variable as mentioned above.
> Also it will be generic in non dt case.

Ok. Thanks for the suggestion. I will modify it as per your suggestion.

Thanks,
Thomas.

[...]

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v3 5/6] mmc: dw_mmc: add device tree support
@ 2012-07-17 10:19       ` Thomas Abraham
  0 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-17 10:19 UTC (permalink / raw)
  To: linux-arm-kernel

On 16 July 2012 09:45, Girish K S <girish.shivananjappa@linaro.org> wrote:
> On 12 July 2012 18:24, Thomas Abraham <thomas.abraham@linaro.org> wrote:

[...]

>>
>> +#ifdef CONFIG_OF
>> +static struct dw_mci_drv_data synopsis_drv_data = {
>> +       .ctrl_type      = DW_MCI_TYPE_SYNOPSIS,
>> +};
>> +
>> +static const struct of_device_id dw_mci_pltfm_match[] = {
>> +       { .compatible = "snps,dw-mshc",
>> +                       .data = (void *)&synopsis_drv_data, },
>> +       {},
>> +};
>> +MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
>> +#else
>> +static const struct of_device_id dw_mci_pltfm_match[];
> the #else and a statement can be completely removed if of_match_ptr is
> used while accessing the dw_mci_pltfm_match in of_match_node function.
>> +#endif
>> +
>>  static int dw_mci_pltfm_probe(struct platform_device *pdev)
>>  {
>>         struct dw_mci *host;
>> @@ -51,6 +67,13 @@ static int dw_mci_pltfm_probe(struct platform_device *pdev)
>>         if (!host->regs)
>>                 goto err_free;
>>         platform_set_drvdata(pdev, host);
>> +
>> +       if (pdev->dev.of_node) {
>> +               const struct of_device_id *match;
>> +               match = of_match_node(dw_mci_pltfm_match, pdev->dev.of_node);
> can be modified to of_match_node(of_match_pt(dw_mci_pltfm_match),
> pdev->dev.of_node);
> This will remove the dummy allocation of variable as mentioned above.
> Also it will be generic in non dt case.

Ok. Thanks for the suggestion. I will modify it as per your suggestion.

Thanks,
Thomas.

[...]

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 5/6] mmc: dw_mmc: add device tree support
@ 2012-07-17 10:21       ` Thomas Abraham
  0 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-17 10:21 UTC (permalink / raw)
  To: Chris Ball
  Cc: linux-mmc, devicetree-discuss, linux-kernel, linux-arm-kernel,
	grant.likely, rob.herring, linux-samsung-soc, kgene.kim, patches

On 16 July 2012 09:53, Chris Ball <cjb@laptop.org> wrote:
> Hi,
>
> On Thu, Jul 12 2012, Thomas Abraham wrote:
>> diff --git a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
>> new file mode 100644
>> index 0000000..3acd6c9
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
>> @@ -0,0 +1,108 @@
>> +* Synopsis Designware Mobile Storage Host Controller
>> +
>> +The Synopsis designware mobile storage host controller is used to interface
>> +a SoC with storage medium such as eMMC or SD/MMC cards.
>> +
>> +Required Properties:
>> +
>> +* compatible: should be one of the following
>> +     - snps,dw-mshc: for controllers compliant with synopsis dw-mshc.
>> +
>> +* reg: physical base address of the dw-mshc controller and size of its memory
>> +  region.
>> +
>> +* interrupts: interrupt specifier for the controller. The format and value of
>> +  the interrupt specifier depends on the interrupt parent for the controller.
>
> Please instead add:
>
> This file documents differences between the core properties described
> by mmc.txt and the properties used by the dw_mmc driver.
>
> mmc.txt already describes compatible, reg, interrupts, bus-width,
> cd-gpios, and wp-gpios, so you don't need to describe those again.

Ok. I will change it.

>
>> +     cnt = sizeof(of_quriks) / sizeof(struct dw_mci_of_quirks);
>> +     for (idx = 0; idx < cnt; idx++)
>> +             if (of_get_property(np, of_quriks[idx].quirk, NULL))
>> +                     pdata->quirks |= of_quriks[idx].id;
>
> of_quirks, not of_quriks.

Yes, thanks for pointing this out. I will fix this.

Thanks,
Thomas.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 5/6] mmc: dw_mmc: add device tree support
@ 2012-07-17 10:21       ` Thomas Abraham
  0 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-17 10:21 UTC (permalink / raw)
  To: Chris Ball
  Cc: linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	patches-QSEj5FYQhm4dnm+yROfE0A,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	rob.herring-bsGFqQB8/DxBDgjK7y7TUQ,
	kgene.kim-Sze3O3UU22JBDgjK7y7TUQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On 16 July 2012 09:53, Chris Ball <cjb-2X9k7bc8m7Mdnm+yROfE0A@public.gmane.org> wrote:
> Hi,
>
> On Thu, Jul 12 2012, Thomas Abraham wrote:
>> diff --git a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
>> new file mode 100644
>> index 0000000..3acd6c9
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
>> @@ -0,0 +1,108 @@
>> +* Synopsis Designware Mobile Storage Host Controller
>> +
>> +The Synopsis designware mobile storage host controller is used to interface
>> +a SoC with storage medium such as eMMC or SD/MMC cards.
>> +
>> +Required Properties:
>> +
>> +* compatible: should be one of the following
>> +     - snps,dw-mshc: for controllers compliant with synopsis dw-mshc.
>> +
>> +* reg: physical base address of the dw-mshc controller and size of its memory
>> +  region.
>> +
>> +* interrupts: interrupt specifier for the controller. The format and value of
>> +  the interrupt specifier depends on the interrupt parent for the controller.
>
> Please instead add:
>
> This file documents differences between the core properties described
> by mmc.txt and the properties used by the dw_mmc driver.
>
> mmc.txt already describes compatible, reg, interrupts, bus-width,
> cd-gpios, and wp-gpios, so you don't need to describe those again.

Ok. I will change it.

>
>> +     cnt = sizeof(of_quriks) / sizeof(struct dw_mci_of_quirks);
>> +     for (idx = 0; idx < cnt; idx++)
>> +             if (of_get_property(np, of_quriks[idx].quirk, NULL))
>> +                     pdata->quirks |= of_quriks[idx].id;
>
> of_quirks, not of_quriks.

Yes, thanks for pointing this out. I will fix this.

Thanks,
Thomas.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v3 5/6] mmc: dw_mmc: add device tree support
@ 2012-07-17 10:21       ` Thomas Abraham
  0 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-17 10:21 UTC (permalink / raw)
  To: linux-arm-kernel

On 16 July 2012 09:53, Chris Ball <cjb@laptop.org> wrote:
> Hi,
>
> On Thu, Jul 12 2012, Thomas Abraham wrote:
>> diff --git a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
>> new file mode 100644
>> index 0000000..3acd6c9
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
>> @@ -0,0 +1,108 @@
>> +* Synopsis Designware Mobile Storage Host Controller
>> +
>> +The Synopsis designware mobile storage host controller is used to interface
>> +a SoC with storage medium such as eMMC or SD/MMC cards.
>> +
>> +Required Properties:
>> +
>> +* compatible: should be one of the following
>> +     - snps,dw-mshc: for controllers compliant with synopsis dw-mshc.
>> +
>> +* reg: physical base address of the dw-mshc controller and size of its memory
>> +  region.
>> +
>> +* interrupts: interrupt specifier for the controller. The format and value of
>> +  the interrupt specifier depends on the interrupt parent for the controller.
>
> Please instead add:
>
> This file documents differences between the core properties described
> by mmc.txt and the properties used by the dw_mmc driver.
>
> mmc.txt already describes compatible, reg, interrupts, bus-width,
> cd-gpios, and wp-gpios, so you don't need to describe those again.

Ok. I will change it.

>
>> +     cnt = sizeof(of_quriks) / sizeof(struct dw_mci_of_quirks);
>> +     for (idx = 0; idx < cnt; idx++)
>> +             if (of_get_property(np, of_quriks[idx].quirk, NULL))
>> +                     pdata->quirks |= of_quriks[idx].id;
>
> of_quirks, not of_quriks.

Yes, thanks for pointing this out. I will fix this.

Thanks,
Thomas.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH 5/9] mmc: dw_mmc: add device tree support
  2012-07-17 10:21       ` Thomas Abraham
@ 2012-07-17 10:37         ` Thomas Abraham
  -1 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-17 10:37 UTC (permalink / raw)
  To: linux-mmc, devicetree-discuss
  Cc: linux-kernel, linux-arm-kernel, cjb, grant.likely, rob.herring,
	linux-samsung-soc, kgene.kim, patches

Add device tree based discovery support.

Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
---
 .../devicetree/bindings/mmc/synposis-dw-mshc.txt   |   99 ++++++++++
 drivers/mmc/host/dw_mmc-pltfm.c                    |   23 +++
 drivers/mmc/host/dw_mmc.c                          |  201 +++++++++++++++++++-
 drivers/mmc/host/dw_mmc.h                          |    9 +
 include/linux/mmc/dw_mmc.h                         |    2 +
 5 files changed, 328 insertions(+), 6 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt

diff --git a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
new file mode 100644
index 0000000..e69a295
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
@@ -0,0 +1,99 @@
+* Synopsis Designware Mobile Storage Host Controller
+
+The Synopsis designware mobile storage host controller is used to interface
+a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
+differences between the core properties described by mmc.txt and the
+properties used by the dw_mmc driver.
+
+Required Properties:
+
+* compatible: should be one of the following
+	- snps,dw-mshc: for controllers compliant with synopsis dw-mshc.
+
+* #address-cells: should be 1.
+
+* #size-cells: should be 0.
+
+# Slots: The slot specific information are contained within child-nodes with
+  each child-node representing a supported slot. There should be atleast one
+  child node representing a card slot. The name of the child node representing
+  the slot is recommended to be slot@n where n is the unique number of the slot
+  connnected to the controller. The following are optional properties which
+  can be included in the slot child node.
+
+	* reg: specifies the physical slot number. The valid values of this
+	  property is 0 to (num-slots -1), where num-slots is the value
+	  specified by the num-slots property.
+
+	* bus-width: Refer to mmc.txt for details.
+
+	* cd-gpios: Refer to mmc.txt for details.
+
+	* wp-gpios: Refer to mmc.txt for details.
+
+	* gpios: specifies a list of gpios used for command, clock and data
+	  bus. The first gpio is the command line and the second gpio is the
+	  clock line. The rest of the gpios (depending on the bus-width
+	  property) are the data lines in no particular order. The format of
+	  the gpio specifier depends on the gpio controller.
+
+Optional properties:
+
+* num-slots: specifies the number of slots supported by the controller.
+  The number of physical slots actually used could be equal or less than the
+  value specified by num-slots. If this property is not specified, the value
+  of num-slot property is assumed to be 1.
+
+* fifo-depth: The maximum size of the tx/rx fifo's. If this property is not
+  specified, the default value of the fifo size is determined from the
+  controller registers.
+
+* card-detect-delay: Delay in milli-seconds before detecting card after card
+  insert event. The default value is 0.
+
+* supports-highspeed: Enables support for high speed cards (upto 50MHz)
+
+* card-detection-broken: The card detection functionality is not available on
+  any of the slots.
+
+* no-write-protect: The write protect pad of the controller is not connected
+  to the write protect pin on the slot.
+
+Aliases:
+
+- All the MSHC controller nodes should be represented in the aliases node using
+  the following format 'mshc{n}' where n is a unique number for the alias.
+
+
+Example:
+
+  The MSHC controller node can be split into two portions, SoC specific and
+  board specific portions as listed below.
+
+	dwmmc0@12200000 {
+		compatible = "snps,dw-mshc";
+		reg = <0x12200000 0x1000>;
+		interrupts = <0 75 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+
+	dwmmc0@12200000 {
+		num-slots = <1>;
+		supports-highspeed;
+		card-detection-broken;
+		no-write-protect;
+		fifo-depth = <0x80>;
+		card-detect-delay = <200>;
+
+		slot@0 {
+			reg = <0>;
+			bus-width = <8>;
+			cd-gpios = <&gpc0 2 2 3 3>;
+			gpios = <&gpc0 0 2 0 3>, <&gpc0 1 2 0 3>,
+				<&gpc1 0 2 3 3>, <&gpc1 1 2 3 3>,
+				<&gpc1 2 2 3 3>, <&gpc1 3 2 3 3>,
+				<&gpc0 3 2 3 3>, <&gpc0 4 2 3 3>,
+				<&gpc0 5 2 3 3>, <&gpc0 6 2 3 3>;
+		};
+	};
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 9a63299..a048c1a 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -19,8 +19,22 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/dw_mmc.h>
+#include <linux/of.h>
 #include "dw_mmc.h"
 
+#ifdef CONFIG_OF
+static struct dw_mci_drv_data synopsis_drv_data = {
+	.ctrl_type	= DW_MCI_TYPE_SYNOPSIS,
+};
+
+static const struct of_device_id dw_mci_pltfm_match[] = {
+	{ .compatible = "snps,dw-mshc",
+			.data = (void *)&synopsis_drv_data, },
+	{},
+};
+MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
+#endif
+
 static int dw_mci_pltfm_probe(struct platform_device *pdev)
 {
 	struct dw_mci *host;
@@ -51,6 +65,14 @@ static int dw_mci_pltfm_probe(struct platform_device *pdev)
 	if (!host->regs)
 		goto err_free;
 	platform_set_drvdata(pdev, host);
+
+	if (pdev->dev.of_node) {
+		const struct of_device_id *match;
+		match = of_match_node(of_match_ptr(dw_mci_pltfm_match),
+					pdev->dev.of_node);
+		host->drv_data = match->data;
+	}
+
 	ret = dw_mci_probe(host);
 	if (ret)
 		goto err_out;
@@ -111,6 +133,7 @@ static struct platform_driver dw_mci_pltfm_driver = {
 	.remove		= __exit_p(dw_mci_pltfm_remove),
 	.driver		= {
 		.name		= "dw_mmc",
+		.of_match_table	= of_match_ptr(dw_mci_pltfm_match),
 		.pm		= &dw_mci_pltfm_pmops,
 	},
 };
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index cb96a40..7af4089 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -33,9 +33,13 @@
 #include <linux/bitops.h>
 #include <linux/regulator/consumer.h>
 #include <linux/workqueue.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 
 #include "dw_mmc.h"
 
+#define NUM_PINS(x) (x + 2)
+
 /* Common flag combinations */
 #define DW_MCI_DATA_ERROR_FLAGS	(SDMMC_INT_DTO | SDMMC_INT_DCRC | \
 				 SDMMC_INT_HTO | SDMMC_INT_SBE  | \
@@ -86,6 +90,8 @@ struct idmac_desc {
 struct dw_mci_slot {
 	struct mmc_host		*mmc;
 	struct dw_mci		*host;
+	int			wp_gpio;
+	int			cd_gpio;
 
 	u32			ctype;
 
@@ -1762,10 +1768,106 @@ static void dw_mci_work_routine_card(struct work_struct *work)
 	}
 }
 
+#ifdef CONFIG_OF
+static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
+{
+	struct device_node *np;
+	const __be32 *addr;
+	int len;
+
+	if (!dev || !dev->of_node)
+		return NULL;
+
+	for_each_child_of_node(dev->of_node, np) {
+		addr = of_get_property(np, "reg", &len);
+		if (!addr || (len < sizeof(int)))
+			continue;
+		if (be32_to_cpup(addr) == slot)
+			return np;
+	}
+	return NULL;
+}
+
+static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
+{
+	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
+	u32 bus_wd = 1;
+
+	if (!np)
+		return 1;
+
+	if (of_property_read_u32(np, "bus-width", &bus_wd))
+		dev_err(dev, "bus-width property not found, assuming width"
+			       " as 1\n");
+	return bus_wd;
+}
+
+static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
+{
+	struct device_node *np = dw_mci_of_find_slot_node(host->dev, slot);
+	int idx, gpio, ret;
+
+	if (!np)
+		return -EINVAL;
+
+	for (idx = 0; idx < NUM_PINS(bus_wd); idx++) {
+		gpio = of_get_gpio(np, idx);
+		if (!gpio_is_valid(gpio)) {
+			dev_err(host->dev, "invalid gpio: %d\n", gpio);
+			return -EINVAL;
+		}
+
+		ret = devm_gpio_request(host->dev, gpio, "dw-mci-bus");
+		if (ret) {
+			dev_err(host->dev, "gpio [%d] request failed\n", gpio);
+			return -EBUSY;
+		}
+	}
+
+	host->slot[slot]->wp_gpio = -1;
+	gpio = of_get_named_gpio(np, "wp-gpios", 0);
+	if (!gpio_is_valid(gpio)) {
+		dev_info(host->dev, "wp gpio not available");
+	} else {
+		ret = devm_gpio_request(host->dev, gpio, "dw-mci-wp");
+		if (ret)
+			dev_info(host->dev, "gpio [%d] request failed\n",
+						gpio);
+		else
+			host->slot[slot]->wp_gpio = gpio;
+	}
+
+	host->slot[slot]->cd_gpio = -1;
+	gpio = of_get_named_gpio(np, "cd-gpios", 0);
+	if (!gpio_is_valid(gpio)) {
+		dev_info(host->dev, "cd gpio not available");
+	} else {
+		ret = devm_gpio_request(host->dev, gpio, "dw-mci-cd");
+		if (ret)
+			dev_err(host->dev, "gpio [%d] request failed\n", gpio);
+		else
+			host->slot[slot]->cd_gpio = gpio;
+	}
+
+	return 0;
+}
+#else /* CONFIG_OF */
+static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
+{
+	return 1;
+}
+
+static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
+{
+	return -EINVAL;
+}
+#endif /* CONFIG_OF */
+
 static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 {
 	struct mmc_host *mmc;
 	struct dw_mci_slot *slot;
+	int ctrl_id, ret;
 
 	mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
 	if (!mmc)
@@ -1775,6 +1877,7 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 	slot->id = id;
 	slot->mmc = mmc;
 	slot->host = host;
+	host->slot[id] = slot;
 
 	mmc->ops = &dw_mci_ops;
 	mmc->f_min = DIV_ROUND_UP(host->bus_hz, 510);
@@ -1795,12 +1898,33 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 	if (host->pdata->caps)
 		mmc->caps = host->pdata->caps;
 
+	if (host->dev->of_node) {
+		ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
+		if (ctrl_id < 0)
+			ctrl_id = 0;
+	}
+	if (host->drv_data->caps)
+		mmc->caps |= host->drv_data->caps[ctrl_id];
+
 	if (host->pdata->caps2)
 		mmc->caps2 = host->pdata->caps2;
 
-	if (host->pdata->get_bus_wd)
+	if (host->pdata->get_bus_wd) {
 		if (host->pdata->get_bus_wd(slot->id) >= 4)
 			mmc->caps |= MMC_CAP_4_BIT_DATA;
+	} else if (host->dev->of_node) {
+		unsigned int bus_width;
+		bus_width = dw_mci_of_get_bus_wd(host->dev, slot->id);
+		switch (bus_width) {
+		case 8:
+			mmc->caps |= MMC_CAP_8_BIT_DATA;
+		case 4:
+			mmc->caps |= MMC_CAP_4_BIT_DATA;
+		}
+		ret = dw_mci_of_setup_bus(host, slot->id, bus_width);
+		if (ret)
+			goto err_setup_bus;
+	}
 
 	if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED)
 		mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
@@ -1845,7 +1969,6 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 	else
 		clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
 
-	host->slot[id] = slot;
 	mmc_add_host(mmc);
 
 #if defined(CONFIG_DEBUG_FS)
@@ -1862,6 +1985,10 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 	queue_work(host->card_workqueue, &host->card_work);
 
 	return 0;
+
+err_setup_bus:
+	mmc_free_host(mmc);
+	return -EINVAL;
 }
 
 static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
@@ -1937,16 +2064,78 @@ static bool mci_wait_reset(struct device *dev, struct dw_mci *host)
 	return false;
 }
 
+#ifdef CONFIG_OF
+static struct dw_mci_of_quirks {
+	char *quirk;
+	int id;
+} of_quirks[] = {
+	{
+		.quirk	= "supports-highspeed",
+		.id	= DW_MCI_QUIRK_HIGHSPEED,
+	}, {
+		.quirk	= "card-detection-broken",
+		.id	= DW_MCI_QUIRK_BROKEN_CARD_DETECTION,
+	}, {
+		.quirk	= "no-write-protect",
+		.id	= DW_MCI_QUIRK_NO_WRITE_PROTECT,
+	}
+};
+
+static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
+{
+	struct dw_mci_board *pdata;
+	struct device *dev = host->dev;
+	struct device_node *np = dev->of_node;
+	int idx, cnt;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(dev, "could not allocate memory for pdata\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	/* find out number of slots supported */
+	if (of_property_read_u32(dev->of_node, "num-slots",
+				&pdata->num_slots)) {
+		dev_info(dev, "num-slots property not found, "
+				"assuming 1 slot is available\n");
+		pdata->num_slots = 1;
+	}
+
+	/* get quirks */
+	cnt = sizeof(of_quirks) / sizeof(struct dw_mci_of_quirks);
+	for (idx = 0; idx < cnt; idx++)
+		if (of_get_property(np, of_quirks[idx].quirk, NULL))
+			pdata->quirks |= of_quirks[idx].id;
+
+	if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
+		dev_info(dev, "fifo-depth property not found, using "
+				"value of FIFOTH register as default\n");
+
+	of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
+
+	return pdata;
+}
+
+#else /* CONFIG_OF */
+static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
+{
+	return ERR_PTR(-EINVAL);
+}
+#endif /* CONFIG_OF */
+
 int dw_mci_probe(struct dw_mci *host)
 {
 	int width, i, ret = 0;
 	u32 fifo_size;
 	int init_slots = 0;
 
-	if (!host->pdata || !host->pdata->init) {
-		dev_err(host->dev,
-			"Platform data must supply init function\n");
-		return -ENODEV;
+	if (!host->pdata) {
+		host->pdata = dw_mci_parse_dt(host);
+		if (IS_ERR(host->pdata)) {
+			dev_err(host->dev, "platform data not available\n");
+			return -EINVAL;
+		}
 	}
 
 	if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 15c27e1..1ecaa02 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -182,4 +182,13 @@ extern int dw_mci_suspend(struct dw_mci *host);
 extern int dw_mci_resume(struct dw_mci *host);
 #endif
 
+/* Variations in the dw_mci controller */
+#define DW_MCI_TYPE_SYNOPSIS		0
+
+/* dw_mci platform driver data */
+struct dw_mci_drv_data {
+	unsigned long		ctrl_type;
+	unsigned long		*caps;
+};
+
 #endif /* _DW_MMC_H_ */
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index b72e4aa..ae45e4f 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -78,6 +78,7 @@ struct mmc_data;
  * @data_offset: Set the offset of DATA register according to VERID.
  * @dev: Device associated with the MMC controller.
  * @pdata: Platform data associated with the MMC controller.
+ * @drv_data: Driver specific data for identified variant of the controller
  * @biu_clk: Pointer to bus interface unit clock instance.
  * @ciu_clk: Pointer to card interface unit clock instance.
  * @slot: Slots sharing this MMC controller.
@@ -160,6 +161,7 @@ struct dw_mci {
 	u16			data_offset;
 	struct device		*dev;
 	struct dw_mci_board	*pdata;
+	struct dw_mci_drv_data	*drv_data;
 	struct clk		*biu_clk;
 	struct clk		*ciu_clk;
 	struct dw_mci_slot	*slot[MAX_MCI_SLOTS];
-- 
1.6.6.rc2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 5/9] mmc: dw_mmc: add device tree support
@ 2012-07-17 10:37         ` Thomas Abraham
  0 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-17 10:37 UTC (permalink / raw)
  To: linux-arm-kernel

Add device tree based discovery support.

Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
---
 .../devicetree/bindings/mmc/synposis-dw-mshc.txt   |   99 ++++++++++
 drivers/mmc/host/dw_mmc-pltfm.c                    |   23 +++
 drivers/mmc/host/dw_mmc.c                          |  201 +++++++++++++++++++-
 drivers/mmc/host/dw_mmc.h                          |    9 +
 include/linux/mmc/dw_mmc.h                         |    2 +
 5 files changed, 328 insertions(+), 6 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt

diff --git a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
new file mode 100644
index 0000000..e69a295
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
@@ -0,0 +1,99 @@
+* Synopsis Designware Mobile Storage Host Controller
+
+The Synopsis designware mobile storage host controller is used to interface
+a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
+differences between the core properties described by mmc.txt and the
+properties used by the dw_mmc driver.
+
+Required Properties:
+
+* compatible: should be one of the following
+	- snps,dw-mshc: for controllers compliant with synopsis dw-mshc.
+
+* #address-cells: should be 1.
+
+* #size-cells: should be 0.
+
+# Slots: The slot specific information are contained within child-nodes with
+  each child-node representing a supported slot. There should be atleast one
+  child node representing a card slot. The name of the child node representing
+  the slot is recommended to be slot at n where n is the unique number of the slot
+  connnected to the controller. The following are optional properties which
+  can be included in the slot child node.
+
+	* reg: specifies the physical slot number. The valid values of this
+	  property is 0 to (num-slots -1), where num-slots is the value
+	  specified by the num-slots property.
+
+	* bus-width: Refer to mmc.txt for details.
+
+	* cd-gpios: Refer to mmc.txt for details.
+
+	* wp-gpios: Refer to mmc.txt for details.
+
+	* gpios: specifies a list of gpios used for command, clock and data
+	  bus. The first gpio is the command line and the second gpio is the
+	  clock line. The rest of the gpios (depending on the bus-width
+	  property) are the data lines in no particular order. The format of
+	  the gpio specifier depends on the gpio controller.
+
+Optional properties:
+
+* num-slots: specifies the number of slots supported by the controller.
+  The number of physical slots actually used could be equal or less than the
+  value specified by num-slots. If this property is not specified, the value
+  of num-slot property is assumed to be 1.
+
+* fifo-depth: The maximum size of the tx/rx fifo's. If this property is not
+  specified, the default value of the fifo size is determined from the
+  controller registers.
+
+* card-detect-delay: Delay in milli-seconds before detecting card after card
+  insert event. The default value is 0.
+
+* supports-highspeed: Enables support for high speed cards (upto 50MHz)
+
+* card-detection-broken: The card detection functionality is not available on
+  any of the slots.
+
+* no-write-protect: The write protect pad of the controller is not connected
+  to the write protect pin on the slot.
+
+Aliases:
+
+- All the MSHC controller nodes should be represented in the aliases node using
+  the following format 'mshc{n}' where n is a unique number for the alias.
+
+
+Example:
+
+  The MSHC controller node can be split into two portions, SoC specific and
+  board specific portions as listed below.
+
+	dwmmc0 at 12200000 {
+		compatible = "snps,dw-mshc";
+		reg = <0x12200000 0x1000>;
+		interrupts = <0 75 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+
+	dwmmc0 at 12200000 {
+		num-slots = <1>;
+		supports-highspeed;
+		card-detection-broken;
+		no-write-protect;
+		fifo-depth = <0x80>;
+		card-detect-delay = <200>;
+
+		slot at 0 {
+			reg = <0>;
+			bus-width = <8>;
+			cd-gpios = <&gpc0 2 2 3 3>;
+			gpios = <&gpc0 0 2 0 3>, <&gpc0 1 2 0 3>,
+				<&gpc1 0 2 3 3>, <&gpc1 1 2 3 3>,
+				<&gpc1 2 2 3 3>, <&gpc1 3 2 3 3>,
+				<&gpc0 3 2 3 3>, <&gpc0 4 2 3 3>,
+				<&gpc0 5 2 3 3>, <&gpc0 6 2 3 3>;
+		};
+	};
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 9a63299..a048c1a 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -19,8 +19,22 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/dw_mmc.h>
+#include <linux/of.h>
 #include "dw_mmc.h"
 
+#ifdef CONFIG_OF
+static struct dw_mci_drv_data synopsis_drv_data = {
+	.ctrl_type	= DW_MCI_TYPE_SYNOPSIS,
+};
+
+static const struct of_device_id dw_mci_pltfm_match[] = {
+	{ .compatible = "snps,dw-mshc",
+			.data = (void *)&synopsis_drv_data, },
+	{},
+};
+MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
+#endif
+
 static int dw_mci_pltfm_probe(struct platform_device *pdev)
 {
 	struct dw_mci *host;
@@ -51,6 +65,14 @@ static int dw_mci_pltfm_probe(struct platform_device *pdev)
 	if (!host->regs)
 		goto err_free;
 	platform_set_drvdata(pdev, host);
+
+	if (pdev->dev.of_node) {
+		const struct of_device_id *match;
+		match = of_match_node(of_match_ptr(dw_mci_pltfm_match),
+					pdev->dev.of_node);
+		host->drv_data = match->data;
+	}
+
 	ret = dw_mci_probe(host);
 	if (ret)
 		goto err_out;
@@ -111,6 +133,7 @@ static struct platform_driver dw_mci_pltfm_driver = {
 	.remove		= __exit_p(dw_mci_pltfm_remove),
 	.driver		= {
 		.name		= "dw_mmc",
+		.of_match_table	= of_match_ptr(dw_mci_pltfm_match),
 		.pm		= &dw_mci_pltfm_pmops,
 	},
 };
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index cb96a40..7af4089 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -33,9 +33,13 @@
 #include <linux/bitops.h>
 #include <linux/regulator/consumer.h>
 #include <linux/workqueue.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 
 #include "dw_mmc.h"
 
+#define NUM_PINS(x) (x + 2)
+
 /* Common flag combinations */
 #define DW_MCI_DATA_ERROR_FLAGS	(SDMMC_INT_DTO | SDMMC_INT_DCRC | \
 				 SDMMC_INT_HTO | SDMMC_INT_SBE  | \
@@ -86,6 +90,8 @@ struct idmac_desc {
 struct dw_mci_slot {
 	struct mmc_host		*mmc;
 	struct dw_mci		*host;
+	int			wp_gpio;
+	int			cd_gpio;
 
 	u32			ctype;
 
@@ -1762,10 +1768,106 @@ static void dw_mci_work_routine_card(struct work_struct *work)
 	}
 }
 
+#ifdef CONFIG_OF
+static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
+{
+	struct device_node *np;
+	const __be32 *addr;
+	int len;
+
+	if (!dev || !dev->of_node)
+		return NULL;
+
+	for_each_child_of_node(dev->of_node, np) {
+		addr = of_get_property(np, "reg", &len);
+		if (!addr || (len < sizeof(int)))
+			continue;
+		if (be32_to_cpup(addr) == slot)
+			return np;
+	}
+	return NULL;
+}
+
+static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
+{
+	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
+	u32 bus_wd = 1;
+
+	if (!np)
+		return 1;
+
+	if (of_property_read_u32(np, "bus-width", &bus_wd))
+		dev_err(dev, "bus-width property not found, assuming width"
+			       " as 1\n");
+	return bus_wd;
+}
+
+static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
+{
+	struct device_node *np = dw_mci_of_find_slot_node(host->dev, slot);
+	int idx, gpio, ret;
+
+	if (!np)
+		return -EINVAL;
+
+	for (idx = 0; idx < NUM_PINS(bus_wd); idx++) {
+		gpio = of_get_gpio(np, idx);
+		if (!gpio_is_valid(gpio)) {
+			dev_err(host->dev, "invalid gpio: %d\n", gpio);
+			return -EINVAL;
+		}
+
+		ret = devm_gpio_request(host->dev, gpio, "dw-mci-bus");
+		if (ret) {
+			dev_err(host->dev, "gpio [%d] request failed\n", gpio);
+			return -EBUSY;
+		}
+	}
+
+	host->slot[slot]->wp_gpio = -1;
+	gpio = of_get_named_gpio(np, "wp-gpios", 0);
+	if (!gpio_is_valid(gpio)) {
+		dev_info(host->dev, "wp gpio not available");
+	} else {
+		ret = devm_gpio_request(host->dev, gpio, "dw-mci-wp");
+		if (ret)
+			dev_info(host->dev, "gpio [%d] request failed\n",
+						gpio);
+		else
+			host->slot[slot]->wp_gpio = gpio;
+	}
+
+	host->slot[slot]->cd_gpio = -1;
+	gpio = of_get_named_gpio(np, "cd-gpios", 0);
+	if (!gpio_is_valid(gpio)) {
+		dev_info(host->dev, "cd gpio not available");
+	} else {
+		ret = devm_gpio_request(host->dev, gpio, "dw-mci-cd");
+		if (ret)
+			dev_err(host->dev, "gpio [%d] request failed\n", gpio);
+		else
+			host->slot[slot]->cd_gpio = gpio;
+	}
+
+	return 0;
+}
+#else /* CONFIG_OF */
+static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
+{
+	return 1;
+}
+
+static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
+{
+	return -EINVAL;
+}
+#endif /* CONFIG_OF */
+
 static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 {
 	struct mmc_host *mmc;
 	struct dw_mci_slot *slot;
+	int ctrl_id, ret;
 
 	mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
 	if (!mmc)
@@ -1775,6 +1877,7 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 	slot->id = id;
 	slot->mmc = mmc;
 	slot->host = host;
+	host->slot[id] = slot;
 
 	mmc->ops = &dw_mci_ops;
 	mmc->f_min = DIV_ROUND_UP(host->bus_hz, 510);
@@ -1795,12 +1898,33 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 	if (host->pdata->caps)
 		mmc->caps = host->pdata->caps;
 
+	if (host->dev->of_node) {
+		ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
+		if (ctrl_id < 0)
+			ctrl_id = 0;
+	}
+	if (host->drv_data->caps)
+		mmc->caps |= host->drv_data->caps[ctrl_id];
+
 	if (host->pdata->caps2)
 		mmc->caps2 = host->pdata->caps2;
 
-	if (host->pdata->get_bus_wd)
+	if (host->pdata->get_bus_wd) {
 		if (host->pdata->get_bus_wd(slot->id) >= 4)
 			mmc->caps |= MMC_CAP_4_BIT_DATA;
+	} else if (host->dev->of_node) {
+		unsigned int bus_width;
+		bus_width = dw_mci_of_get_bus_wd(host->dev, slot->id);
+		switch (bus_width) {
+		case 8:
+			mmc->caps |= MMC_CAP_8_BIT_DATA;
+		case 4:
+			mmc->caps |= MMC_CAP_4_BIT_DATA;
+		}
+		ret = dw_mci_of_setup_bus(host, slot->id, bus_width);
+		if (ret)
+			goto err_setup_bus;
+	}
 
 	if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED)
 		mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
@@ -1845,7 +1969,6 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 	else
 		clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
 
-	host->slot[id] = slot;
 	mmc_add_host(mmc);
 
 #if defined(CONFIG_DEBUG_FS)
@@ -1862,6 +1985,10 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 	queue_work(host->card_workqueue, &host->card_work);
 
 	return 0;
+
+err_setup_bus:
+	mmc_free_host(mmc);
+	return -EINVAL;
 }
 
 static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
@@ -1937,16 +2064,78 @@ static bool mci_wait_reset(struct device *dev, struct dw_mci *host)
 	return false;
 }
 
+#ifdef CONFIG_OF
+static struct dw_mci_of_quirks {
+	char *quirk;
+	int id;
+} of_quirks[] = {
+	{
+		.quirk	= "supports-highspeed",
+		.id	= DW_MCI_QUIRK_HIGHSPEED,
+	}, {
+		.quirk	= "card-detection-broken",
+		.id	= DW_MCI_QUIRK_BROKEN_CARD_DETECTION,
+	}, {
+		.quirk	= "no-write-protect",
+		.id	= DW_MCI_QUIRK_NO_WRITE_PROTECT,
+	}
+};
+
+static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
+{
+	struct dw_mci_board *pdata;
+	struct device *dev = host->dev;
+	struct device_node *np = dev->of_node;
+	int idx, cnt;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(dev, "could not allocate memory for pdata\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	/* find out number of slots supported */
+	if (of_property_read_u32(dev->of_node, "num-slots",
+				&pdata->num_slots)) {
+		dev_info(dev, "num-slots property not found, "
+				"assuming 1 slot is available\n");
+		pdata->num_slots = 1;
+	}
+
+	/* get quirks */
+	cnt = sizeof(of_quirks) / sizeof(struct dw_mci_of_quirks);
+	for (idx = 0; idx < cnt; idx++)
+		if (of_get_property(np, of_quirks[idx].quirk, NULL))
+			pdata->quirks |= of_quirks[idx].id;
+
+	if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
+		dev_info(dev, "fifo-depth property not found, using "
+				"value of FIFOTH register as default\n");
+
+	of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
+
+	return pdata;
+}
+
+#else /* CONFIG_OF */
+static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
+{
+	return ERR_PTR(-EINVAL);
+}
+#endif /* CONFIG_OF */
+
 int dw_mci_probe(struct dw_mci *host)
 {
 	int width, i, ret = 0;
 	u32 fifo_size;
 	int init_slots = 0;
 
-	if (!host->pdata || !host->pdata->init) {
-		dev_err(host->dev,
-			"Platform data must supply init function\n");
-		return -ENODEV;
+	if (!host->pdata) {
+		host->pdata = dw_mci_parse_dt(host);
+		if (IS_ERR(host->pdata)) {
+			dev_err(host->dev, "platform data not available\n");
+			return -EINVAL;
+		}
 	}
 
 	if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 15c27e1..1ecaa02 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -182,4 +182,13 @@ extern int dw_mci_suspend(struct dw_mci *host);
 extern int dw_mci_resume(struct dw_mci *host);
 #endif
 
+/* Variations in the dw_mci controller */
+#define DW_MCI_TYPE_SYNOPSIS		0
+
+/* dw_mci platform driver data */
+struct dw_mci_drv_data {
+	unsigned long		ctrl_type;
+	unsigned long		*caps;
+};
+
 #endif /* _DW_MMC_H_ */
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index b72e4aa..ae45e4f 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -78,6 +78,7 @@ struct mmc_data;
  * @data_offset: Set the offset of DATA register according to VERID.
  * @dev: Device associated with the MMC controller.
  * @pdata: Platform data associated with the MMC controller.
+ * @drv_data: Driver specific data for identified variant of the controller
  * @biu_clk: Pointer to bus interface unit clock instance.
  * @ciu_clk: Pointer to card interface unit clock instance.
  * @slot: Slots sharing this MMC controller.
@@ -160,6 +161,7 @@ struct dw_mci {
 	u16			data_offset;
 	struct device		*dev;
 	struct dw_mci_board	*pdata;
+	struct dw_mci_drv_data	*drv_data;
 	struct clk		*biu_clk;
 	struct clk		*ciu_clk;
 	struct dw_mci_slot	*slot[MAX_MCI_SLOTS];
-- 
1.6.6.rc2

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 3/9] mmc: dw_mmc: lookup for optional biu and ciu clocks
  2012-07-13  9:11     ` Girish K S
@ 2012-07-17 10:38       ` Thomas Abraham
  -1 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-17 10:38 UTC (permalink / raw)
  To: linux-mmc, devicetree-discuss
  Cc: linux-kernel, linux-arm-kernel, cjb, grant.likely, rob.herring,
	linux-samsung-soc, kgene.kim, patches

Some platforms allow for clock gating and control of bus interface unit clock
and card interface unit clock. Add support for clock lookup of optional biu
and ciu clocks for clock gating and clock speed determination.

Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
---
 drivers/mmc/host/dw_mmc.c  |   39 ++++++++++++++++++++++++++++++++++++---
 include/linux/mmc/dw_mmc.h |    4 ++++
 2 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index cd58063..ebd22d8 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1953,13 +1953,30 @@ int dw_mci_probe(struct dw_mci *host)
 		return -ENODEV;
 	}
 
-	if (!host->pdata->bus_hz) {
+	host->biu_clk = clk_get(host->dev, "biu");
+	if (IS_ERR(host->biu_clk))
+		dev_dbg(host->dev, "biu clock not available\n");
+	else
+		clk_prepare_enable(host->biu_clk);
+
+	host->ciu_clk = clk_get(host->dev, "ciu");
+	if (IS_ERR(host->ciu_clk))
+		dev_dbg(host->dev, "ciu clock not available\n");
+	else
+		clk_prepare_enable(host->ciu_clk);
+
+	if (IS_ERR(host->ciu_clk))
+		host->bus_hz = host->pdata->bus_hz;
+	else
+		host->bus_hz = clk_get_rate(host->ciu_clk);
+
+	if (!host->bus_hz) {
 		dev_err(host->dev,
 			"Platform data must supply bus speed\n");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto err_clk;
 	}
 
-	host->bus_hz = host->pdata->bus_hz;
 	host->quirks = host->pdata->quirks;
 
 	spin_lock_init(&host->lock);
@@ -2109,6 +2126,16 @@ err_dmaunmap:
 		regulator_disable(host->vmmc);
 		regulator_put(host->vmmc);
 	}
+
+err_clk:
+	if (!IS_ERR(host->ciu_clk)) {
+		clk_disable_unprepare(host->ciu_clk);
+		clk_put(host->ciu_clk);
+	}
+	if (!IS_ERR(host->biu_clk)) {
+		clk_disable_unprepare(host->biu_clk);
+		clk_put(host->biu_clk);
+	}
 	return ret;
 }
 EXPORT_SYMBOL(dw_mci_probe);
@@ -2142,6 +2169,12 @@ void dw_mci_remove(struct dw_mci *host)
 		regulator_put(host->vmmc);
 	}
 
+	if (!IS_ERR(host->ciu_clk))
+		clk_disable_unprepare(host->ciu_clk);
+	if (!IS_ERR(host->biu_clk))
+		clk_disable_unprepare(host->biu_clk);
+	clk_put(host->ciu_clk);
+	clk_put(host->biu_clk);
 }
 EXPORT_SYMBOL(dw_mci_remove);
 
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index a37a573..787ad56 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -78,6 +78,8 @@ struct mmc_data;
  * @data_offset: Set the offset of DATA register according to VERID.
  * @dev: Device associated with the MMC controller.
  * @pdata: Platform data associated with the MMC controller.
+ * @biu_clk: Pointer to bus interface unit clock instance.
+ * @ciu_clk: Pointer to card interface unit clock instance.
  * @slot: Slots sharing this MMC controller.
  * @fifo_depth: depth of FIFO.
  * @data_shift: log2 of FIFO item size.
@@ -158,6 +160,8 @@ struct dw_mci {
 	u16			data_offset;
 	struct device		*dev;
 	struct dw_mci_board	*pdata;
+	struct clk		*biu_clk;
+	struct clk		*ciu_clk;
 	struct dw_mci_slot	*slot[MAX_MCI_SLOTS];
 
 	/* FIFO push and pull */
-- 
1.6.6.rc2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 3/9] mmc: dw_mmc: lookup for optional biu and ciu clocks
@ 2012-07-17 10:38       ` Thomas Abraham
  0 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-17 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

Some platforms allow for clock gating and control of bus interface unit clock
and card interface unit clock. Add support for clock lookup of optional biu
and ciu clocks for clock gating and clock speed determination.

Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
---
 drivers/mmc/host/dw_mmc.c  |   39 ++++++++++++++++++++++++++++++++++++---
 include/linux/mmc/dw_mmc.h |    4 ++++
 2 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index cd58063..ebd22d8 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1953,13 +1953,30 @@ int dw_mci_probe(struct dw_mci *host)
 		return -ENODEV;
 	}
 
-	if (!host->pdata->bus_hz) {
+	host->biu_clk = clk_get(host->dev, "biu");
+	if (IS_ERR(host->biu_clk))
+		dev_dbg(host->dev, "biu clock not available\n");
+	else
+		clk_prepare_enable(host->biu_clk);
+
+	host->ciu_clk = clk_get(host->dev, "ciu");
+	if (IS_ERR(host->ciu_clk))
+		dev_dbg(host->dev, "ciu clock not available\n");
+	else
+		clk_prepare_enable(host->ciu_clk);
+
+	if (IS_ERR(host->ciu_clk))
+		host->bus_hz = host->pdata->bus_hz;
+	else
+		host->bus_hz = clk_get_rate(host->ciu_clk);
+
+	if (!host->bus_hz) {
 		dev_err(host->dev,
 			"Platform data must supply bus speed\n");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto err_clk;
 	}
 
-	host->bus_hz = host->pdata->bus_hz;
 	host->quirks = host->pdata->quirks;
 
 	spin_lock_init(&host->lock);
@@ -2109,6 +2126,16 @@ err_dmaunmap:
 		regulator_disable(host->vmmc);
 		regulator_put(host->vmmc);
 	}
+
+err_clk:
+	if (!IS_ERR(host->ciu_clk)) {
+		clk_disable_unprepare(host->ciu_clk);
+		clk_put(host->ciu_clk);
+	}
+	if (!IS_ERR(host->biu_clk)) {
+		clk_disable_unprepare(host->biu_clk);
+		clk_put(host->biu_clk);
+	}
 	return ret;
 }
 EXPORT_SYMBOL(dw_mci_probe);
@@ -2142,6 +2169,12 @@ void dw_mci_remove(struct dw_mci *host)
 		regulator_put(host->vmmc);
 	}
 
+	if (!IS_ERR(host->ciu_clk))
+		clk_disable_unprepare(host->ciu_clk);
+	if (!IS_ERR(host->biu_clk))
+		clk_disable_unprepare(host->biu_clk);
+	clk_put(host->ciu_clk);
+	clk_put(host->biu_clk);
 }
 EXPORT_SYMBOL(dw_mci_remove);
 
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index a37a573..787ad56 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -78,6 +78,8 @@ struct mmc_data;
  * @data_offset: Set the offset of DATA register according to VERID.
  * @dev: Device associated with the MMC controller.
  * @pdata: Platform data associated with the MMC controller.
+ * @biu_clk: Pointer to bus interface unit clock instance.
+ * @ciu_clk: Pointer to card interface unit clock instance.
  * @slot: Slots sharing this MMC controller.
  * @fifo_depth: depth of FIFO.
  * @data_shift: log2 of FIFO item size.
@@ -158,6 +160,8 @@ struct dw_mci {
 	u16			data_offset;
 	struct device		*dev;
 	struct dw_mci_board	*pdata;
+	struct clk		*biu_clk;
+	struct clk		*ciu_clk;
 	struct dw_mci_slot	*slot[MAX_MCI_SLOTS];
 
 	/* FIFO push and pull */
-- 
1.6.6.rc2

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* RE: [PATCH v3 6/6] mmc: dw_mmc: add samsung exynos5250 specific extentions
  2012-07-12 12:54   ` Thomas Abraham
@ 2012-07-19  3:51     ` Seungwon Jeon
  -1 siblings, 0 replies; 53+ messages in thread
From: Seungwon Jeon @ 2012-07-19  3:51 UTC (permalink / raw)
  To: 'Thomas Abraham', linux-mmc, devicetree-discuss
  Cc: linux-kernel, linux-arm-kernel, cjb, grant.likely, rob.herring,
	linux-samsung-soc, kgene.kim, patches

Hi,

This version does not seems to consider previous reviews fully.
Could you check the comments below?

July 12, 2012, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> The instantiation of the Synopsis Designware controller on Exynos5250
> include extension for SDR and DDR specific tx/rx phase shift timing
> and CIU internal divider. In addition to that, the option to skip the
> command hold stage is also introduced. Add support for these Exynos5250
> specfic extenstions.
> 
> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
> ---
>  .../devicetree/bindings/mmc/synposis-dw-mshc.txt   |   38 ++++++++++++++++++-
>  drivers/mmc/host/dw_mmc-pltfm.c                    |   15 +++++++
>  drivers/mmc/host/dw_mmc.c                          |   40 +++++++++++++++++++-
>  drivers/mmc/host/dw_mmc.h                          |   14 +++++++
>  include/linux/mmc/dw_mmc.h                         |    6 +++
>  5 files changed, 110 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> index 3acd6c9..69d78c1 100644
> --- a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> +++ b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> @@ -7,6 +7,8 @@ Required Properties:
> 
>  * compatible: should be one of the following
>  	- snps,dw-mshc: for controllers compliant with synopsis dw-mshc.
> +	- samsung,exynos5250-dw-mshc: for controllers with Samsung
> +	  Exynos5250 specific extentions.
> 
>  * reg: physical base address of the dw-mshc controller and size of its memory
>    region.
> @@ -74,13 +76,45 @@ Aliases:
>    the following format 'mshc{n}' where n is a unique number for the alias.
> 
> 
> +Samsung Exynos4/5 specific properties:
> +
> +Some of the variants of Exynos4 (such as Exynos4412) and Exynos5 SoC's
> +includes few extensions to the Synopsis Designware Mobile Storage Host
> +Controller. The following properties are used to describe those extensions.
> +
> +* samsung,dw-mshc-sdr-timing: Specifies the value of CUI clock divider, CIU
> +  clock phase shift value in transmit mode and CIU clock phase shift value in
> +  receive mode for single data rate mode operation. Refer notes of the valid
> +  values below.
> +
> +* samsung,dw-mshc-ddr-timing: Specifies the value of CUI clock divider, CIU
> +  clock phase shift value in transmit mode and CIU clock phase shift value in
> +  receive mode for double data rate mode operation. Refer notes of the valid
> +  values below. The order of the cells should be
> +
> +    - First Cell: 	CIU clock divider value (applicable only for Exynos5
> +			SoC's, should be zero for Exynos4 SoC's)
> +    - Second Cell:	CIU clock phase shift value for tx mode.
> +    - Third Cell:	CIU clock phase shift value for rx mode.
> +
> +  Valid values for SDR and DDR CIU clock timing for Exynos5250:
> +
> +    - valid values for CIU clock divider, tx phase shift and rx phase shift
> +      is 0 to 7.
> +
> +    - When CIU clock divider value is set to 3, all possible 8 phase shift
> +      values can be used.
> +
> +    - If CIU clock divider value is 0 (that is divide by 1), both tx and rx
> +      phase shift clocks should be 0.
> +
>  Example:
> 
>    The MSHC controller node can be split into two portions, SoC specific and
>    board specific portions as listed below.
> 
>  	dwmmc0@12200000 {
> -		compatible = "snps,dw-mshc";
> +		compatible = "samsung,exynos5250-dw-mshc";
>  		reg = <0x12200000 0x1000>;
>  		interrupts = <0 75 0>;
>  		#address-cells = <1>;
> @@ -94,6 +128,8 @@ Example:
>  		no-write-protect;
>  		fifo-depth = <0x80>;
>  		card-detect-delay = <200>;
> +		samsung,dw-mshc-sdr-timing = <2 3 3>;
> +		samsung,dw-mshc-ddr-timing = <1 2 3>;
> 
>  		slot@0 {
>  			reg = <0>;
> diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
> index 8d24f6d..900f412 100644
> --- a/drivers/mmc/host/dw_mmc-pltfm.c
> +++ b/drivers/mmc/host/dw_mmc-pltfm.c
> @@ -27,9 +27,24 @@ static struct dw_mci_drv_data synopsis_drv_data = {
>  	.ctrl_type	= DW_MCI_TYPE_SYNOPSIS,
>  };
> 
> +static unsigned long exynos5250_dwmmc_caps[4] = {
> +	MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
> +		MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
> +	MMC_CAP_CMD23,
> +	MMC_CAP_CMD23,
> +	MMC_CAP_CMD23,
> +};
> +
Kyungmin Park has already pointed .
It's not still proper place for board specific caps.
If I'm incorrect, please let me know.
And why MMC_CAP_CMD23 is default caps for all channel of hosts?

> +static struct dw_mci_drv_data exynos5250_drv_data = {
> +	.ctrl_type	= DW_MCI_TYPE_EXYNOS5250,
> +	.caps		= exynos5250_dwmmc_caps,
> +};
> +
>  static const struct of_device_id dw_mci_pltfm_match[] = {
>  	{ .compatible = "snps,dw-mshc",
>  			.data = (void *)&synopsis_drv_data, },
> +	{ .compatible = "samsung,exynos5250-dw-mshc",
> +			.data = (void *)&exynos5250_drv_data, },
>  	{},
>  };
>  MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index 3bc276d..bbf1209 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -236,6 +236,7 @@ static void dw_mci_set_timeout(struct dw_mci *host)
>  static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
>  {
>  	struct mmc_data	*data;
> +	struct dw_mci_slot *slot = mmc_priv(mmc);
>  	u32 cmdr;
>  	cmd->error = -EINPROGRESS;
> 
> @@ -265,6 +266,17 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
>  			cmdr |= SDMMC_CMD_DAT_WR;
>  	}
> 
> +	/*
> +	 * Samsung Exynos5250 extends the use of CMD register with the use of
> +	 * bit 29 (which is reserved on standard MSHC controllers) for
> +	 * optionally bypassing the HOLD register for command and data. The
> +	 * HOLD register should be bypassed in case there is no phase shift
> +	 * applied on CMD/DATA that is sent to the card.
> +	 */
> +	if (slot->host->drv_data->ctrl_type == DW_MCI_TYPE_EXYNOS5250)
> +		if (SDMMC_CLKSEL_GET_SELCLK_DRV(mci_readl(slot->host, CLKSEL)))
> +			cmdr |= SDMMC_CMD_USE_HOLD_REG;
> +
>  	return cmdr;
>  }
> 
> @@ -802,10 +814,19 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
>  	regs = mci_readl(slot->host, UHS_REG);
> 
>  	/* DDR mode set */
> -	if (ios->timing == MMC_TIMING_UHS_DDR50)
> +	if (ios->timing == MMC_TIMING_UHS_DDR50) {
>  		regs |= (0x1 << slot->id) << 16;
> -	else
> +		mci_writel(slot->host, CLKSEL, slot->host->ddr_timing);
> +	} else {
>  		regs &= ~(0x1 << slot->id) << 16;
> +		mci_writel(slot->host, CLKSEL, slot->host->sdr_timing);
> +	}
> +
> +	if (slot->host->drv_data->ctrl_type == DW_MCI_TYPE_EXYNOS5250) {
> +		slot->host->bus_hz = clk_get_rate(slot->host->ciu_clk);
> +		slot->host->bus_hz /= SDMMC_CLKSEL_GET_DIVRATIO(
> +					mci_readl(slot->host, CLKSEL));
> +	}
As you know, CLKSEL is specific for Samsung soc.
0x09C(CLKSEL)  is reserved area in Synopsys memory map.
In case of non-samsung-soc, we cannot ensure this usage.
In previous version, I have suggested separating the variant into another file.

> 
>  	mci_writel(slot->host, UHS_REG, regs);
> 
> @@ -2086,6 +2107,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
>  	struct dw_mci_board *pdata;
>  	struct device *dev = host->dev;
>  	struct device_node *np = dev->of_node;
> +	u32 timing[3];
>  	int idx, cnt;
> 
>  	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
> @@ -2108,6 +2130,20 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
>  		if (of_get_property(np, of_quriks[idx].quirk, NULL))
>  			pdata->quirks |= of_quriks[idx].id;
> 
> +	if (of_property_read_u32_array(dev->of_node,
> +			"samsung,dw-mshc-sdr-timing", timing, 3))
> +		host->sdr_timing = DW_MCI_DEF_SDR_TIMING;
Host of non-samsung will reach here.
host->sdr_timing is needed for this host? host->ddr_timing is the same.

> +	else
> +		host->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0],
> +					timing[1], timing[2]);
> +
> +	if (of_property_read_u32_array(dev->of_node,
> +			"samsung,dw-mshc-ddr-timing", timing, 3))
> +		host->ddr_timing = DW_MCI_DEF_DDR_TIMING;
> +	else
> +		host->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0],
> +					timing[1], timing[2]);
> +
>  	if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
>  		dev_info(dev, "fifo-depth property not found, using "
>  				"value of FIFOTH register as default\n");
> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
> index 1ecaa02..6c17282 100644
> --- a/drivers/mmc/host/dw_mmc.h
> +++ b/drivers/mmc/host/dw_mmc.h
> @@ -53,6 +53,7 @@
>  #define SDMMC_IDINTEN		0x090
>  #define SDMMC_DSCADDR		0x094
>  #define SDMMC_BUFADDR		0x098
> +#define SDMMC_CLKSEL		0x09C /* specific to Samsung Exynos5250 */
>  #define SDMMC_DATA(x)		(x)
> 
>  /*
> @@ -111,6 +112,7 @@
>  #define SDMMC_INT_ERROR			0xbfc2
>  /* Command register defines */
>  #define SDMMC_CMD_START			BIT(31)
> +#define SDMMC_CMD_USE_HOLD_REG		BIT(29)
>  #define SDMMC_CMD_CCS_EXP		BIT(23)
>  #define SDMMC_CMD_CEATA_RD		BIT(22)
>  #define SDMMC_CMD_UPD_CLK		BIT(21)
> @@ -142,6 +144,17 @@
>  /* Version ID register define */
>  #define SDMMC_GET_VERID(x)		((x) & 0xFFFF)
> 
> +#define DW_MCI_DEF_SDR_TIMING		0x03030002
> +#define DW_MCI_DEF_DDR_TIMING		0x03020001
What is the basis for these timing?
These values is board-specific.

> +#define SDMMC_CLKSEL_CCLK_SAMPLE(x)	(((x) & 3) << 0)
> +#define SDMMC_CLKSEL_CCLK_DRIVE(x)	(((x) & 3) << 16)
> +#define SDMMC_CLKSEL_CCLK_DIVIDER(x)	(((x) & 3) << 24)
If it's for exynos5, it will be 7 not 3.

> +#define SDMMC_CLKSEL_TIMING(x, y, z)	(SDMMC_CLKSEL_CCLK_SAMPLE(x) |	\
> +					SDMMC_CLKSEL_CCLK_DRIVE(y) |	\
> +					SDMMC_CLKSEL_CCLK_DIVIDER(z))
> +#define SDMMC_CLKSEL_GET_DIVRATIO(x)	((((x) >> 24) & 0x7) + 1)
> +#define SDMMC_CLKSEL_GET_SELCLK_DRV(x)	(((x) >> 16) & 0x7)
> +
Is this patch considered only for exynos5250?
In case of exynos4210, the number of bits is different.
If upper macros is backward-compatible, it would be better.

Best regards,
Seungwon Jeon

>  /* Register access macros */
>  #define mci_readl(dev, reg)			\
>  	__raw_readl((dev)->regs + SDMMC_##reg)
> @@ -184,6 +197,7 @@ extern int dw_mci_resume(struct dw_mci *host);
> 
>  /* Variations in the dw_mci controller */
>  #define DW_MCI_TYPE_SYNOPSIS		0
> +#define DW_MCI_TYPE_EXYNOS5250		1 /* Samsung Exynos5250 Extensions */
> 
>  /* dw_mci platform driver data */
>  struct dw_mci_drv_data {
> diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
> index ae45e4f..32c778f 100644
> --- a/include/linux/mmc/dw_mmc.h
> +++ b/include/linux/mmc/dw_mmc.h
> @@ -82,6 +82,8 @@ struct mmc_data;
>   * @biu_clk: Pointer to bus interface unit clock instance.
>   * @ciu_clk: Pointer to card interface unit clock instance.
>   * @slot: Slots sharing this MMC controller.
> + * @sdr_timing: Clock phase shifting for driving and sampling in sdr mode
> + * @ddr_timing: Clock phase shifting for driving and sampling in ddr mode
>   * @fifo_depth: depth of FIFO.
>   * @data_shift: log2 of FIFO item size.
>   * @part_buf_start: Start index in part_buf.
> @@ -166,6 +168,10 @@ struct dw_mci {
>  	struct clk		*ciu_clk;
>  	struct dw_mci_slot	*slot[MAX_MCI_SLOTS];
> 
> +	/* Phase Shift Value (for exynos5250 variant) */
> +	u32			sdr_timing;
> +	u32			ddr_timing;
> +
>  	/* FIFO push and pull */
>  	int			fifo_depth;
>  	int			data_shift;
> --
> 1.6.6.rc2
> 
> --
> 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


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v3 6/6] mmc: dw_mmc: add samsung exynos5250 specific extentions
@ 2012-07-19  3:51     ` Seungwon Jeon
  0 siblings, 0 replies; 53+ messages in thread
From: Seungwon Jeon @ 2012-07-19  3:51 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

This version does not seems to consider previous reviews fully.
Could you check the comments below?

July 12, 2012, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> The instantiation of the Synopsis Designware controller on Exynos5250
> include extension for SDR and DDR specific tx/rx phase shift timing
> and CIU internal divider. In addition to that, the option to skip the
> command hold stage is also introduced. Add support for these Exynos5250
> specfic extenstions.
> 
> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
> ---
>  .../devicetree/bindings/mmc/synposis-dw-mshc.txt   |   38 ++++++++++++++++++-
>  drivers/mmc/host/dw_mmc-pltfm.c                    |   15 +++++++
>  drivers/mmc/host/dw_mmc.c                          |   40 +++++++++++++++++++-
>  drivers/mmc/host/dw_mmc.h                          |   14 +++++++
>  include/linux/mmc/dw_mmc.h                         |    6 +++
>  5 files changed, 110 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> index 3acd6c9..69d78c1 100644
> --- a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> +++ b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> @@ -7,6 +7,8 @@ Required Properties:
> 
>  * compatible: should be one of the following
>  	- snps,dw-mshc: for controllers compliant with synopsis dw-mshc.
> +	- samsung,exynos5250-dw-mshc: for controllers with Samsung
> +	  Exynos5250 specific extentions.
> 
>  * reg: physical base address of the dw-mshc controller and size of its memory
>    region.
> @@ -74,13 +76,45 @@ Aliases:
>    the following format 'mshc{n}' where n is a unique number for the alias.
> 
> 
> +Samsung Exynos4/5 specific properties:
> +
> +Some of the variants of Exynos4 (such as Exynos4412) and Exynos5 SoC's
> +includes few extensions to the Synopsis Designware Mobile Storage Host
> +Controller. The following properties are used to describe those extensions.
> +
> +* samsung,dw-mshc-sdr-timing: Specifies the value of CUI clock divider, CIU
> +  clock phase shift value in transmit mode and CIU clock phase shift value in
> +  receive mode for single data rate mode operation. Refer notes of the valid
> +  values below.
> +
> +* samsung,dw-mshc-ddr-timing: Specifies the value of CUI clock divider, CIU
> +  clock phase shift value in transmit mode and CIU clock phase shift value in
> +  receive mode for double data rate mode operation. Refer notes of the valid
> +  values below. The order of the cells should be
> +
> +    - First Cell: 	CIU clock divider value (applicable only for Exynos5
> +			SoC's, should be zero for Exynos4 SoC's)
> +    - Second Cell:	CIU clock phase shift value for tx mode.
> +    - Third Cell:	CIU clock phase shift value for rx mode.
> +
> +  Valid values for SDR and DDR CIU clock timing for Exynos5250:
> +
> +    - valid values for CIU clock divider, tx phase shift and rx phase shift
> +      is 0 to 7.
> +
> +    - When CIU clock divider value is set to 3, all possible 8 phase shift
> +      values can be used.
> +
> +    - If CIU clock divider value is 0 (that is divide by 1), both tx and rx
> +      phase shift clocks should be 0.
> +
>  Example:
> 
>    The MSHC controller node can be split into two portions, SoC specific and
>    board specific portions as listed below.
> 
>  	dwmmc0 at 12200000 {
> -		compatible = "snps,dw-mshc";
> +		compatible = "samsung,exynos5250-dw-mshc";
>  		reg = <0x12200000 0x1000>;
>  		interrupts = <0 75 0>;
>  		#address-cells = <1>;
> @@ -94,6 +128,8 @@ Example:
>  		no-write-protect;
>  		fifo-depth = <0x80>;
>  		card-detect-delay = <200>;
> +		samsung,dw-mshc-sdr-timing = <2 3 3>;
> +		samsung,dw-mshc-ddr-timing = <1 2 3>;
> 
>  		slot at 0 {
>  			reg = <0>;
> diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
> index 8d24f6d..900f412 100644
> --- a/drivers/mmc/host/dw_mmc-pltfm.c
> +++ b/drivers/mmc/host/dw_mmc-pltfm.c
> @@ -27,9 +27,24 @@ static struct dw_mci_drv_data synopsis_drv_data = {
>  	.ctrl_type	= DW_MCI_TYPE_SYNOPSIS,
>  };
> 
> +static unsigned long exynos5250_dwmmc_caps[4] = {
> +	MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
> +		MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
> +	MMC_CAP_CMD23,
> +	MMC_CAP_CMD23,
> +	MMC_CAP_CMD23,
> +};
> +
Kyungmin Park has already pointed .
It's not still proper place for board specific caps.
If I'm incorrect, please let me know.
And why MMC_CAP_CMD23 is default caps for all channel of hosts?

> +static struct dw_mci_drv_data exynos5250_drv_data = {
> +	.ctrl_type	= DW_MCI_TYPE_EXYNOS5250,
> +	.caps		= exynos5250_dwmmc_caps,
> +};
> +
>  static const struct of_device_id dw_mci_pltfm_match[] = {
>  	{ .compatible = "snps,dw-mshc",
>  			.data = (void *)&synopsis_drv_data, },
> +	{ .compatible = "samsung,exynos5250-dw-mshc",
> +			.data = (void *)&exynos5250_drv_data, },
>  	{},
>  };
>  MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index 3bc276d..bbf1209 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -236,6 +236,7 @@ static void dw_mci_set_timeout(struct dw_mci *host)
>  static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
>  {
>  	struct mmc_data	*data;
> +	struct dw_mci_slot *slot = mmc_priv(mmc);
>  	u32 cmdr;
>  	cmd->error = -EINPROGRESS;
> 
> @@ -265,6 +266,17 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
>  			cmdr |= SDMMC_CMD_DAT_WR;
>  	}
> 
> +	/*
> +	 * Samsung Exynos5250 extends the use of CMD register with the use of
> +	 * bit 29 (which is reserved on standard MSHC controllers) for
> +	 * optionally bypassing the HOLD register for command and data. The
> +	 * HOLD register should be bypassed in case there is no phase shift
> +	 * applied on CMD/DATA that is sent to the card.
> +	 */
> +	if (slot->host->drv_data->ctrl_type == DW_MCI_TYPE_EXYNOS5250)
> +		if (SDMMC_CLKSEL_GET_SELCLK_DRV(mci_readl(slot->host, CLKSEL)))
> +			cmdr |= SDMMC_CMD_USE_HOLD_REG;
> +
>  	return cmdr;
>  }
> 
> @@ -802,10 +814,19 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
>  	regs = mci_readl(slot->host, UHS_REG);
> 
>  	/* DDR mode set */
> -	if (ios->timing == MMC_TIMING_UHS_DDR50)
> +	if (ios->timing == MMC_TIMING_UHS_DDR50) {
>  		regs |= (0x1 << slot->id) << 16;
> -	else
> +		mci_writel(slot->host, CLKSEL, slot->host->ddr_timing);
> +	} else {
>  		regs &= ~(0x1 << slot->id) << 16;
> +		mci_writel(slot->host, CLKSEL, slot->host->sdr_timing);
> +	}
> +
> +	if (slot->host->drv_data->ctrl_type == DW_MCI_TYPE_EXYNOS5250) {
> +		slot->host->bus_hz = clk_get_rate(slot->host->ciu_clk);
> +		slot->host->bus_hz /= SDMMC_CLKSEL_GET_DIVRATIO(
> +					mci_readl(slot->host, CLKSEL));
> +	}
As you know, CLKSEL is specific for Samsung soc.
0x09C(CLKSEL)  is reserved area in Synopsys memory map.
In case of non-samsung-soc, we cannot ensure this usage.
In previous version, I have suggested separating the variant into another file.

> 
>  	mci_writel(slot->host, UHS_REG, regs);
> 
> @@ -2086,6 +2107,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
>  	struct dw_mci_board *pdata;
>  	struct device *dev = host->dev;
>  	struct device_node *np = dev->of_node;
> +	u32 timing[3];
>  	int idx, cnt;
> 
>  	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
> @@ -2108,6 +2130,20 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
>  		if (of_get_property(np, of_quriks[idx].quirk, NULL))
>  			pdata->quirks |= of_quriks[idx].id;
> 
> +	if (of_property_read_u32_array(dev->of_node,
> +			"samsung,dw-mshc-sdr-timing", timing, 3))
> +		host->sdr_timing = DW_MCI_DEF_SDR_TIMING;
Host of non-samsung will reach here.
host->sdr_timing is needed for this host? host->ddr_timing is the same.

> +	else
> +		host->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0],
> +					timing[1], timing[2]);
> +
> +	if (of_property_read_u32_array(dev->of_node,
> +			"samsung,dw-mshc-ddr-timing", timing, 3))
> +		host->ddr_timing = DW_MCI_DEF_DDR_TIMING;
> +	else
> +		host->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0],
> +					timing[1], timing[2]);
> +
>  	if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
>  		dev_info(dev, "fifo-depth property not found, using "
>  				"value of FIFOTH register as default\n");
> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
> index 1ecaa02..6c17282 100644
> --- a/drivers/mmc/host/dw_mmc.h
> +++ b/drivers/mmc/host/dw_mmc.h
> @@ -53,6 +53,7 @@
>  #define SDMMC_IDINTEN		0x090
>  #define SDMMC_DSCADDR		0x094
>  #define SDMMC_BUFADDR		0x098
> +#define SDMMC_CLKSEL		0x09C /* specific to Samsung Exynos5250 */
>  #define SDMMC_DATA(x)		(x)
> 
>  /*
> @@ -111,6 +112,7 @@
>  #define SDMMC_INT_ERROR			0xbfc2
>  /* Command register defines */
>  #define SDMMC_CMD_START			BIT(31)
> +#define SDMMC_CMD_USE_HOLD_REG		BIT(29)
>  #define SDMMC_CMD_CCS_EXP		BIT(23)
>  #define SDMMC_CMD_CEATA_RD		BIT(22)
>  #define SDMMC_CMD_UPD_CLK		BIT(21)
> @@ -142,6 +144,17 @@
>  /* Version ID register define */
>  #define SDMMC_GET_VERID(x)		((x) & 0xFFFF)
> 
> +#define DW_MCI_DEF_SDR_TIMING		0x03030002
> +#define DW_MCI_DEF_DDR_TIMING		0x03020001
What is the basis for these timing?
These values is board-specific.

> +#define SDMMC_CLKSEL_CCLK_SAMPLE(x)	(((x) & 3) << 0)
> +#define SDMMC_CLKSEL_CCLK_DRIVE(x)	(((x) & 3) << 16)
> +#define SDMMC_CLKSEL_CCLK_DIVIDER(x)	(((x) & 3) << 24)
If it's for exynos5, it will be 7 not 3.

> +#define SDMMC_CLKSEL_TIMING(x, y, z)	(SDMMC_CLKSEL_CCLK_SAMPLE(x) |	\
> +					SDMMC_CLKSEL_CCLK_DRIVE(y) |	\
> +					SDMMC_CLKSEL_CCLK_DIVIDER(z))
> +#define SDMMC_CLKSEL_GET_DIVRATIO(x)	((((x) >> 24) & 0x7) + 1)
> +#define SDMMC_CLKSEL_GET_SELCLK_DRV(x)	(((x) >> 16) & 0x7)
> +
Is this patch considered only for exynos5250?
In case of exynos4210, the number of bits is different.
If upper macros is backward-compatible, it would be better.

Best regards,
Seungwon Jeon

>  /* Register access macros */
>  #define mci_readl(dev, reg)			\
>  	__raw_readl((dev)->regs + SDMMC_##reg)
> @@ -184,6 +197,7 @@ extern int dw_mci_resume(struct dw_mci *host);
> 
>  /* Variations in the dw_mci controller */
>  #define DW_MCI_TYPE_SYNOPSIS		0
> +#define DW_MCI_TYPE_EXYNOS5250		1 /* Samsung Exynos5250 Extensions */
> 
>  /* dw_mci platform driver data */
>  struct dw_mci_drv_data {
> diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
> index ae45e4f..32c778f 100644
> --- a/include/linux/mmc/dw_mmc.h
> +++ b/include/linux/mmc/dw_mmc.h
> @@ -82,6 +82,8 @@ struct mmc_data;
>   * @biu_clk: Pointer to bus interface unit clock instance.
>   * @ciu_clk: Pointer to card interface unit clock instance.
>   * @slot: Slots sharing this MMC controller.
> + * @sdr_timing: Clock phase shifting for driving and sampling in sdr mode
> + * @ddr_timing: Clock phase shifting for driving and sampling in ddr mode
>   * @fifo_depth: depth of FIFO.
>   * @data_shift: log2 of FIFO item size.
>   * @part_buf_start: Start index in part_buf.
> @@ -166,6 +168,10 @@ struct dw_mci {
>  	struct clk		*ciu_clk;
>  	struct dw_mci_slot	*slot[MAX_MCI_SLOTS];
> 
> +	/* Phase Shift Value (for exynos5250 variant) */
> +	u32			sdr_timing;
> +	u32			ddr_timing;
> +
>  	/* FIFO push and pull */
>  	int			fifo_depth;
>  	int			data_shift;
> --
> 1.6.6.rc2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 53+ messages in thread

* RE: [PATCH 3/9] mmc: dw_mmc: lookup for optional biu and ciu clocks
  2012-07-17 10:38       ` Thomas Abraham
@ 2012-07-19 10:27         ` Seungwon Jeon
  -1 siblings, 0 replies; 53+ messages in thread
From: Seungwon Jeon @ 2012-07-19 10:27 UTC (permalink / raw)
  To: 'Thomas Abraham', linux-mmc, devicetree-discuss
  Cc: linux-kernel, linux-arm-kernel, cjb, grant.likely, rob.herring,
	linux-samsung-soc, kgene.kim, patches

July 17, 2012, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> Some platforms allow for clock gating and control of bus interface unit clock
> and card interface unit clock. Add support for clock lookup of optional biu
> and ciu clocks for clock gating and clock speed determination.
> 
> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
> ---
>  drivers/mmc/host/dw_mmc.c  |   39 ++++++++++++++++++++++++++++++++++++---
>  include/linux/mmc/dw_mmc.h |    4 ++++
>  2 files changed, 40 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index cd58063..ebd22d8 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -1953,13 +1953,30 @@ int dw_mci_probe(struct dw_mci *host)
>  		return -ENODEV;
>  	}
> 
> -	if (!host->pdata->bus_hz) {
> +	host->biu_clk = clk_get(host->dev, "biu");
> +	if (IS_ERR(host->biu_clk))
> +		dev_dbg(host->dev, "biu clock not available\n");
> +	else
> +		clk_prepare_enable(host->biu_clk);
> +
> +	host->ciu_clk = clk_get(host->dev, "ciu");
> +	if (IS_ERR(host->ciu_clk))
> +		dev_dbg(host->dev, "ciu clock not available\n");
> +	else
> +		clk_prepare_enable(host->ciu_clk);
> +
> +	if (IS_ERR(host->ciu_clk))
> +		host->bus_hz = host->pdata->bus_hz;
> +	else
> +		host->bus_hz = clk_get_rate(host->ciu_clk);
I have posted similar patch some time back.
bus_hz represents input rate for cclk_in of mshc.
Host of samsung soc doesn't use input clock from system directly.
As you have introduced CLKSEL in your another patch, input clock can be changed prior to cclk_in.
For non-samsung  host, we don't need to consider this with generic way?

Thanks,
Seungwon Jeon

> +
> +	if (!host->bus_hz) {
>  		dev_err(host->dev,
>  			"Platform data must supply bus speed\n");
> -		return -ENODEV;
> +		ret = -ENODEV;
> +		goto err_clk;
>  	}
> 
> -	host->bus_hz = host->pdata->bus_hz;
>  	host->quirks = host->pdata->quirks;
> 
>  	spin_lock_init(&host->lock);
> @@ -2109,6 +2126,16 @@ err_dmaunmap:
>  		regulator_disable(host->vmmc);
>  		regulator_put(host->vmmc);
>  	}
> +
> +err_clk:
> +	if (!IS_ERR(host->ciu_clk)) {
> +		clk_disable_unprepare(host->ciu_clk);
> +		clk_put(host->ciu_clk);
> +	}
> +	if (!IS_ERR(host->biu_clk)) {
> +		clk_disable_unprepare(host->biu_clk);
> +		clk_put(host->biu_clk);
> +	}
>  	return ret;
>  }
>  EXPORT_SYMBOL(dw_mci_probe);
> @@ -2142,6 +2169,12 @@ void dw_mci_remove(struct dw_mci *host)
>  		regulator_put(host->vmmc);
>  	}
> 
> +	if (!IS_ERR(host->ciu_clk))
> +		clk_disable_unprepare(host->ciu_clk);
> +	if (!IS_ERR(host->biu_clk))
> +		clk_disable_unprepare(host->biu_clk);
> +	clk_put(host->ciu_clk);
> +	clk_put(host->biu_clk);
>  }
>  EXPORT_SYMBOL(dw_mci_remove);
> 
> diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
> index a37a573..787ad56 100644
> --- a/include/linux/mmc/dw_mmc.h
> +++ b/include/linux/mmc/dw_mmc.h
> @@ -78,6 +78,8 @@ struct mmc_data;
>   * @data_offset: Set the offset of DATA register according to VERID.
>   * @dev: Device associated with the MMC controller.
>   * @pdata: Platform data associated with the MMC controller.
> + * @biu_clk: Pointer to bus interface unit clock instance.
> + * @ciu_clk: Pointer to card interface unit clock instance.
>   * @slot: Slots sharing this MMC controller.
>   * @fifo_depth: depth of FIFO.
>   * @data_shift: log2 of FIFO item size.
> @@ -158,6 +160,8 @@ struct dw_mci {
>  	u16			data_offset;
>  	struct device		*dev;
>  	struct dw_mci_board	*pdata;
> +	struct clk		*biu_clk;
> +	struct clk		*ciu_clk;
>  	struct dw_mci_slot	*slot[MAX_MCI_SLOTS];
> 
>  	/* FIFO push and pull */
> --
> 1.6.6.rc2
> 
> --
> 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


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH 3/9] mmc: dw_mmc: lookup for optional biu and ciu clocks
@ 2012-07-19 10:27         ` Seungwon Jeon
  0 siblings, 0 replies; 53+ messages in thread
From: Seungwon Jeon @ 2012-07-19 10:27 UTC (permalink / raw)
  To: linux-arm-kernel

July 17, 2012, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> Some platforms allow for clock gating and control of bus interface unit clock
> and card interface unit clock. Add support for clock lookup of optional biu
> and ciu clocks for clock gating and clock speed determination.
> 
> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
> ---
>  drivers/mmc/host/dw_mmc.c  |   39 ++++++++++++++++++++++++++++++++++++---
>  include/linux/mmc/dw_mmc.h |    4 ++++
>  2 files changed, 40 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index cd58063..ebd22d8 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -1953,13 +1953,30 @@ int dw_mci_probe(struct dw_mci *host)
>  		return -ENODEV;
>  	}
> 
> -	if (!host->pdata->bus_hz) {
> +	host->biu_clk = clk_get(host->dev, "biu");
> +	if (IS_ERR(host->biu_clk))
> +		dev_dbg(host->dev, "biu clock not available\n");
> +	else
> +		clk_prepare_enable(host->biu_clk);
> +
> +	host->ciu_clk = clk_get(host->dev, "ciu");
> +	if (IS_ERR(host->ciu_clk))
> +		dev_dbg(host->dev, "ciu clock not available\n");
> +	else
> +		clk_prepare_enable(host->ciu_clk);
> +
> +	if (IS_ERR(host->ciu_clk))
> +		host->bus_hz = host->pdata->bus_hz;
> +	else
> +		host->bus_hz = clk_get_rate(host->ciu_clk);
I have posted similar patch some time back.
bus_hz represents input rate for cclk_in of mshc.
Host of samsung soc doesn't use input clock from system directly.
As you have introduced CLKSEL in your another patch, input clock can be changed prior to cclk_in.
For non-samsung  host, we don't need to consider this with generic way?

Thanks,
Seungwon Jeon

> +
> +	if (!host->bus_hz) {
>  		dev_err(host->dev,
>  			"Platform data must supply bus speed\n");
> -		return -ENODEV;
> +		ret = -ENODEV;
> +		goto err_clk;
>  	}
> 
> -	host->bus_hz = host->pdata->bus_hz;
>  	host->quirks = host->pdata->quirks;
> 
>  	spin_lock_init(&host->lock);
> @@ -2109,6 +2126,16 @@ err_dmaunmap:
>  		regulator_disable(host->vmmc);
>  		regulator_put(host->vmmc);
>  	}
> +
> +err_clk:
> +	if (!IS_ERR(host->ciu_clk)) {
> +		clk_disable_unprepare(host->ciu_clk);
> +		clk_put(host->ciu_clk);
> +	}
> +	if (!IS_ERR(host->biu_clk)) {
> +		clk_disable_unprepare(host->biu_clk);
> +		clk_put(host->biu_clk);
> +	}
>  	return ret;
>  }
>  EXPORT_SYMBOL(dw_mci_probe);
> @@ -2142,6 +2169,12 @@ void dw_mci_remove(struct dw_mci *host)
>  		regulator_put(host->vmmc);
>  	}
> 
> +	if (!IS_ERR(host->ciu_clk))
> +		clk_disable_unprepare(host->ciu_clk);
> +	if (!IS_ERR(host->biu_clk))
> +		clk_disable_unprepare(host->biu_clk);
> +	clk_put(host->ciu_clk);
> +	clk_put(host->biu_clk);
>  }
>  EXPORT_SYMBOL(dw_mci_remove);
> 
> diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
> index a37a573..787ad56 100644
> --- a/include/linux/mmc/dw_mmc.h
> +++ b/include/linux/mmc/dw_mmc.h
> @@ -78,6 +78,8 @@ struct mmc_data;
>   * @data_offset: Set the offset of DATA register according to VERID.
>   * @dev: Device associated with the MMC controller.
>   * @pdata: Platform data associated with the MMC controller.
> + * @biu_clk: Pointer to bus interface unit clock instance.
> + * @ciu_clk: Pointer to card interface unit clock instance.
>   * @slot: Slots sharing this MMC controller.
>   * @fifo_depth: depth of FIFO.
>   * @data_shift: log2 of FIFO item size.
> @@ -158,6 +160,8 @@ struct dw_mci {
>  	u16			data_offset;
>  	struct device		*dev;
>  	struct dw_mci_board	*pdata;
> +	struct clk		*biu_clk;
> +	struct clk		*ciu_clk;
>  	struct dw_mci_slot	*slot[MAX_MCI_SLOTS];
> 
>  	/* FIFO push and pull */
> --
> 1.6.6.rc2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 0/6] mmc: dw_mmc: add support for device tree based instantiation
  2012-07-12 12:54 ` Thomas Abraham
@ 2012-07-19 15:28   ` Jaehoon Chung
  -1 siblings, 0 replies; 53+ messages in thread
From: Jaehoon Chung @ 2012-07-19 15:28 UTC (permalink / raw)
  To: Thomas Abraham
  Cc: linux-mmc, devicetree-discuss, linux-kernel, linux-arm-kernel,
	cjb, grant.likely, rob.herring, linux-samsung-soc, kgene.kim,
	patches

Hi Thomas,

I think not good that added the samsung specific code into dw_mmc-pltfm.c
How about separating to dw-mmc-exynos.c?

Best Regards,
Jaehoon Chung

On 07/12/2012 09:54 PM, Thomas Abraham wrote:
> This patch series adds device tree support for Synopsis Designware Mobile
> Storage Host Controller.
> 
> The first patch converts the copy of controller device instance into a
> reference. This is need to allow device resource management api to correctly
> manage the resources allocated by the driver. The second patch fixes the
> incorrect abort of the probe in case a slot initialization fails. This is
> fixed by allowing as many slots to be initialized successfully and failing
> only if there are no slots that were initialized.
> 
> The third patch adds clock lookup in the driver and this is optional. Platforms
> that do not need any clock gating and control for the dw_mmc controllers will
> not be affected with this change. The fourth patch adds a quirk to notify the
> controller about the absence of the write protect line.
> 
> The fifth patch adds device tree based discovery support for the dw_mmc driver.
> The sixth patch add Samsung Exynos5250 specific extentions to the driver.
> 
> This patchset is based on Samsung kernel tree's for-next branch with the
> mmc tree's mmc-next branch merged.
> 
> Thomas Abraham (6):
>   mmc: dw_mmc: convert copy of struct device in struct dw_mci to a reference
>   mmc: dw_mmc: allow probe to succeed even if one slot is initialized
>   mmc: dw_mmc: lookup for optional biu and ciu clocks
>   mmc: dw_mmc: add quirk to indicate missing write protect line
>   mmc: dw_mmc: add device tree support
>   mmc: dw_mmc: add samsung exynos5250 specific extentions
> 
>  .../devicetree/bindings/mmc/synposis-dw-mshc.txt   |  144 ++++++++
>  drivers/mmc/host/dw_mmc-pci.c                      |    2 +-
>  drivers/mmc/host/dw_mmc-pltfm.c                    |   41 +++-
>  drivers/mmc/host/dw_mmc.c                          |  364 +++++++++++++++++---
>  drivers/mmc/host/dw_mmc.h                          |   23 ++
>  include/linux/mmc/dw_mmc.h                         |   17 +-
>  6 files changed, 538 insertions(+), 53 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> 
> --
> 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
> 



^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v3 0/6] mmc: dw_mmc: add support for device tree based instantiation
@ 2012-07-19 15:28   ` Jaehoon Chung
  0 siblings, 0 replies; 53+ messages in thread
From: Jaehoon Chung @ 2012-07-19 15:28 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas,

I think not good that added the samsung specific code into dw_mmc-pltfm.c
How about separating to dw-mmc-exynos.c?

Best Regards,
Jaehoon Chung

On 07/12/2012 09:54 PM, Thomas Abraham wrote:
> This patch series adds device tree support for Synopsis Designware Mobile
> Storage Host Controller.
> 
> The first patch converts the copy of controller device instance into a
> reference. This is need to allow device resource management api to correctly
> manage the resources allocated by the driver. The second patch fixes the
> incorrect abort of the probe in case a slot initialization fails. This is
> fixed by allowing as many slots to be initialized successfully and failing
> only if there are no slots that were initialized.
> 
> The third patch adds clock lookup in the driver and this is optional. Platforms
> that do not need any clock gating and control for the dw_mmc controllers will
> not be affected with this change. The fourth patch adds a quirk to notify the
> controller about the absence of the write protect line.
> 
> The fifth patch adds device tree based discovery support for the dw_mmc driver.
> The sixth patch add Samsung Exynos5250 specific extentions to the driver.
> 
> This patchset is based on Samsung kernel tree's for-next branch with the
> mmc tree's mmc-next branch merged.
> 
> Thomas Abraham (6):
>   mmc: dw_mmc: convert copy of struct device in struct dw_mci to a reference
>   mmc: dw_mmc: allow probe to succeed even if one slot is initialized
>   mmc: dw_mmc: lookup for optional biu and ciu clocks
>   mmc: dw_mmc: add quirk to indicate missing write protect line
>   mmc: dw_mmc: add device tree support
>   mmc: dw_mmc: add samsung exynos5250 specific extentions
> 
>  .../devicetree/bindings/mmc/synposis-dw-mshc.txt   |  144 ++++++++
>  drivers/mmc/host/dw_mmc-pci.c                      |    2 +-
>  drivers/mmc/host/dw_mmc-pltfm.c                    |   41 +++-
>  drivers/mmc/host/dw_mmc.c                          |  364 +++++++++++++++++---
>  drivers/mmc/host/dw_mmc.h                          |   23 ++
>  include/linux/mmc/dw_mmc.h                         |   17 +-
>  6 files changed, 538 insertions(+), 53 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 6/6] mmc: dw_mmc: add samsung exynos5250 specific extentions
  2012-07-19  3:51     ` Seungwon Jeon
@ 2012-07-19 18:48       ` Thomas Abraham
  -1 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-19 18:48 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, devicetree-discuss, linux-kernel, linux-arm-kernel,
	cjb, grant.likely, rob.herring, linux-samsung-soc, kgene.kim,
	patches

On 19 July 2012 09:21, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Hi,
>
> This version does not seems to consider previous reviews fully.
> Could you check the comments below?

I did try to address all the comments. I will check again and resubmit
if I have missed anything.

>
> July 12, 2012, Thomas Abraham <thomas.abraham@linaro.org> wrote:
>> The instantiation of the Synopsis Designware controller on Exynos5250
>> include extension for SDR and DDR specific tx/rx phase shift timing
>> and CIU internal divider. In addition to that, the option to skip the
>> command hold stage is also introduced. Add support for these Exynos5250
>> specfic extenstions.
>>
>> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
>> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
>> ---
>>  .../devicetree/bindings/mmc/synposis-dw-mshc.txt   |   38 ++++++++++++++++++-
>>  drivers/mmc/host/dw_mmc-pltfm.c                    |   15 +++++++
>>  drivers/mmc/host/dw_mmc.c                          |   40 +++++++++++++++++++-
>>  drivers/mmc/host/dw_mmc.h                          |   14 +++++++
>>  include/linux/mmc/dw_mmc.h                         |    6 +++
>>  5 files changed, 110 insertions(+), 3 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
>> b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
>> index 3acd6c9..69d78c1 100644
>> --- a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
>> +++ b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
>> @@ -7,6 +7,8 @@ Required Properties:
>>
>>  * compatible: should be one of the following
>>       - snps,dw-mshc: for controllers compliant with synopsis dw-mshc.
>> +     - samsung,exynos5250-dw-mshc: for controllers with Samsung
>> +       Exynos5250 specific extentions.
>>
>>  * reg: physical base address of the dw-mshc controller and size of its memory
>>    region.
>> @@ -74,13 +76,45 @@ Aliases:
>>    the following format 'mshc{n}' where n is a unique number for the alias.
>>
>>
>> +Samsung Exynos4/5 specific properties:
>> +
>> +Some of the variants of Exynos4 (such as Exynos4412) and Exynos5 SoC's
>> +includes few extensions to the Synopsis Designware Mobile Storage Host
>> +Controller. The following properties are used to describe those extensions.
>> +
>> +* samsung,dw-mshc-sdr-timing: Specifies the value of CUI clock divider, CIU
>> +  clock phase shift value in transmit mode and CIU clock phase shift value in
>> +  receive mode for single data rate mode operation. Refer notes of the valid
>> +  values below.
>> +
>> +* samsung,dw-mshc-ddr-timing: Specifies the value of CUI clock divider, CIU
>> +  clock phase shift value in transmit mode and CIU clock phase shift value in
>> +  receive mode for double data rate mode operation. Refer notes of the valid
>> +  values below. The order of the cells should be
>> +
>> +    - First Cell:    CIU clock divider value (applicable only for Exynos5
>> +                     SoC's, should be zero for Exynos4 SoC's)
>> +    - Second Cell:   CIU clock phase shift value for tx mode.
>> +    - Third Cell:    CIU clock phase shift value for rx mode.
>> +
>> +  Valid values for SDR and DDR CIU clock timing for Exynos5250:
>> +
>> +    - valid values for CIU clock divider, tx phase shift and rx phase shift
>> +      is 0 to 7.
>> +
>> +    - When CIU clock divider value is set to 3, all possible 8 phase shift
>> +      values can be used.
>> +
>> +    - If CIU clock divider value is 0 (that is divide by 1), both tx and rx
>> +      phase shift clocks should be 0.
>> +
>>  Example:
>>
>>    The MSHC controller node can be split into two portions, SoC specific and
>>    board specific portions as listed below.
>>
>>       dwmmc0@12200000 {
>> -             compatible = "snps,dw-mshc";
>> +             compatible = "samsung,exynos5250-dw-mshc";
>>               reg = <0x12200000 0x1000>;
>>               interrupts = <0 75 0>;
>>               #address-cells = <1>;
>> @@ -94,6 +128,8 @@ Example:
>>               no-write-protect;
>>               fifo-depth = <0x80>;
>>               card-detect-delay = <200>;
>> +             samsung,dw-mshc-sdr-timing = <2 3 3>;
>> +             samsung,dw-mshc-ddr-timing = <1 2 3>;
>>
>>               slot@0 {
>>                       reg = <0>;
>> diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
>> index 8d24f6d..900f412 100644
>> --- a/drivers/mmc/host/dw_mmc-pltfm.c
>> +++ b/drivers/mmc/host/dw_mmc-pltfm.c
>> @@ -27,9 +27,24 @@ static struct dw_mci_drv_data synopsis_drv_data = {
>>       .ctrl_type      = DW_MCI_TYPE_SYNOPSIS,
>>  };
>>
>> +static unsigned long exynos5250_dwmmc_caps[4] = {
>> +     MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
>> +             MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
>> +     MMC_CAP_CMD23,
>> +     MMC_CAP_CMD23,
>> +     MMC_CAP_CMD23,
>> +};
>> +
> Kyungmin Park has already pointed .
> It's not still proper place for board specific caps.
> If I'm incorrect, please let me know.
> And why MMC_CAP_CMD23 is default caps for all channel of hosts?

The cap listed above are specifying controller capabilities for dw-mmc
controllers on Exynos5 SoC. They are not board specific caps. All the
Exynos5 dw-mmc controllers can support MMC_CAP_CMD23 cap and hence, it
has been listed for all the controllers. Please let me know if you
feel there is any change required here.

>
>> +static struct dw_mci_drv_data exynos5250_drv_data = {
>> +     .ctrl_type      = DW_MCI_TYPE_EXYNOS5250,
>> +     .caps           = exynos5250_dwmmc_caps,
>> +};
>> +
>>  static const struct of_device_id dw_mci_pltfm_match[] = {
>>       { .compatible = "snps,dw-mshc",
>>                       .data = (void *)&synopsis_drv_data, },
>> +     { .compatible = "samsung,exynos5250-dw-mshc",
>> +                     .data = (void *)&exynos5250_drv_data, },
>>       {},
>>  };
>>  MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
>> index 3bc276d..bbf1209 100644
>> --- a/drivers/mmc/host/dw_mmc.c
>> +++ b/drivers/mmc/host/dw_mmc.c
>> @@ -236,6 +236,7 @@ static void dw_mci_set_timeout(struct dw_mci *host)
>>  static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
>>  {
>>       struct mmc_data *data;
>> +     struct dw_mci_slot *slot = mmc_priv(mmc);
>>       u32 cmdr;
>>       cmd->error = -EINPROGRESS;
>>
>> @@ -265,6 +266,17 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
>>                       cmdr |= SDMMC_CMD_DAT_WR;
>>       }
>>
>> +     /*
>> +      * Samsung Exynos5250 extends the use of CMD register with the use of
>> +      * bit 29 (which is reserved on standard MSHC controllers) for
>> +      * optionally bypassing the HOLD register for command and data. The
>> +      * HOLD register should be bypassed in case there is no phase shift
>> +      * applied on CMD/DATA that is sent to the card.
>> +      */
>> +     if (slot->host->drv_data->ctrl_type == DW_MCI_TYPE_EXYNOS5250)
>> +             if (SDMMC_CLKSEL_GET_SELCLK_DRV(mci_readl(slot->host, CLKSEL)))
>> +                     cmdr |= SDMMC_CMD_USE_HOLD_REG;
>> +
>>       return cmdr;
>>  }
>>
>> @@ -802,10 +814,19 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
>>       regs = mci_readl(slot->host, UHS_REG);
>>
>>       /* DDR mode set */
>> -     if (ios->timing == MMC_TIMING_UHS_DDR50)
>> +     if (ios->timing == MMC_TIMING_UHS_DDR50) {
>>               regs |= (0x1 << slot->id) << 16;
>> -     else
>> +             mci_writel(slot->host, CLKSEL, slot->host->ddr_timing);
>> +     } else {
>>               regs &= ~(0x1 << slot->id) << 16;
>> +             mci_writel(slot->host, CLKSEL, slot->host->sdr_timing);
>> +     }
>> +
>> +     if (slot->host->drv_data->ctrl_type == DW_MCI_TYPE_EXYNOS5250) {
>> +             slot->host->bus_hz = clk_get_rate(slot->host->ciu_clk);
>> +             slot->host->bus_hz /= SDMMC_CLKSEL_GET_DIVRATIO(
>> +                                     mci_readl(slot->host, CLKSEL));
>> +     }
> As you know, CLKSEL is specific for Samsung soc.
> 0x09C(CLKSEL)  is reserved area in Synopsys memory map.
> In case of non-samsung-soc, we cannot ensure this usage.
> In previous version, I have suggested separating the variant into another file.

There is a check for type of SoC before using 0x9C as CLKSEL register.
Other implementations of dw-mmc might define custom register at 0x9C
but this will code will not execute on other SoC's and will not break
anything on other implementations. Regarding spliting this Exynos
specific code into another file, I prefer not to do it for now.
Spliting the code means adding new definitions of callback functions
which I am not sure is really required. The present code is fairly
simple one.

>
>>
>>       mci_writel(slot->host, UHS_REG, regs);
>>
>> @@ -2086,6 +2107,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
>>       struct dw_mci_board *pdata;
>>       struct device *dev = host->dev;
>>       struct device_node *np = dev->of_node;
>> +     u32 timing[3];
>>       int idx, cnt;
>>
>>       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
>> @@ -2108,6 +2130,20 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
>>               if (of_get_property(np, of_quriks[idx].quirk, NULL))
>>                       pdata->quirks |= of_quriks[idx].id;
>>
>> +     if (of_property_read_u32_array(dev->of_node,
>> +                     "samsung,dw-mshc-sdr-timing", timing, 3))
>> +             host->sdr_timing = DW_MCI_DEF_SDR_TIMING;
> Host of non-samsung will reach here.
> host->sdr_timing is needed for this host? host->ddr_timing is the same.

Yes, but non-samsung hosts will not have have this property into their
dts file. So the code within the condition will not execute on
non-samsung hosts. SDR and DDR timing are required for Exynos5 SoC.

>
>> +     else
>> +             host->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0],
>> +                                     timing[1], timing[2]);
>> +
>> +     if (of_property_read_u32_array(dev->of_node,
>> +                     "samsung,dw-mshc-ddr-timing", timing, 3))
>> +             host->ddr_timing = DW_MCI_DEF_DDR_TIMING;
>> +     else
>> +             host->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0],
>> +                                     timing[1], timing[2]);
>> +
>>       if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
>>               dev_info(dev, "fifo-depth property not found, using "
>>                               "value of FIFOTH register as default\n");
>> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
>> index 1ecaa02..6c17282 100644
>> --- a/drivers/mmc/host/dw_mmc.h
>> +++ b/drivers/mmc/host/dw_mmc.h
>> @@ -53,6 +53,7 @@
>>  #define SDMMC_IDINTEN                0x090
>>  #define SDMMC_DSCADDR                0x094
>>  #define SDMMC_BUFADDR                0x098
>> +#define SDMMC_CLKSEL         0x09C /* specific to Samsung Exynos5250 */
>>  #define SDMMC_DATA(x)                (x)
>>
>>  /*
>> @@ -111,6 +112,7 @@
>>  #define SDMMC_INT_ERROR                      0xbfc2
>>  /* Command register defines */
>>  #define SDMMC_CMD_START                      BIT(31)
>> +#define SDMMC_CMD_USE_HOLD_REG               BIT(29)
>>  #define SDMMC_CMD_CCS_EXP            BIT(23)
>>  #define SDMMC_CMD_CEATA_RD           BIT(22)
>>  #define SDMMC_CMD_UPD_CLK            BIT(21)
>> @@ -142,6 +144,17 @@
>>  /* Version ID register define */
>>  #define SDMMC_GET_VERID(x)           ((x) & 0xFFFF)
>>
>> +#define DW_MCI_DEF_SDR_TIMING                0x03030002
>> +#define DW_MCI_DEF_DDR_TIMING                0x03020001
> What is the basis for these timing?
> These values is board-specific.
>
>> +#define SDMMC_CLKSEL_CCLK_SAMPLE(x)  (((x) & 3) << 0)
>> +#define SDMMC_CLKSEL_CCLK_DRIVE(x)   (((x) & 3) << 16)
>> +#define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 3) << 24)
> If it's for exynos5, it will be 7 not 3.

Yes, I missed that. Thanks. I will fix this.

>
>> +#define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) |  \
>> +                                     SDMMC_CLKSEL_CCLK_DRIVE(y) |    \
>> +                                     SDMMC_CLKSEL_CCLK_DIVIDER(z))
>> +#define SDMMC_CLKSEL_GET_DIVRATIO(x) ((((x) >> 24) & 0x7) + 1)
>> +#define SDMMC_CLKSEL_GET_SELCLK_DRV(x)       (((x) >> 16) & 0x7)
>> +
> Is this patch considered only for exynos5250?
> In case of exynos4210, the number of bits is different.
> If upper macros is backward-compatible, it would be better.

These consider the Exynos4210 and Exynos4412 implementations as well.
The device tree documentation clearly states that the possible values
for each of the dividers. For Exynos4 SoC's, the divider value is
between 1 to 4 (or 0 to 3). So a bit mask of 7 is backward compatilble
for Exynos4.

Thanks for your review and comments on this patch.

Regards,
Thomas.

>
> Best regards,
> Seungwon Jeon
>
>>  /* Register access macros */
>>  #define mci_readl(dev, reg)                  \
>>       __raw_readl((dev)->regs + SDMMC_##reg)
>> @@ -184,6 +197,7 @@ extern int dw_mci_resume(struct dw_mci *host);
>>
>>  /* Variations in the dw_mci controller */
>>  #define DW_MCI_TYPE_SYNOPSIS         0
>> +#define DW_MCI_TYPE_EXYNOS5250               1 /* Samsung Exynos5250 Extensions */
>>
>>  /* dw_mci platform driver data */
>>  struct dw_mci_drv_data {
>> diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
>> index ae45e4f..32c778f 100644
>> --- a/include/linux/mmc/dw_mmc.h
>> +++ b/include/linux/mmc/dw_mmc.h
>> @@ -82,6 +82,8 @@ struct mmc_data;
>>   * @biu_clk: Pointer to bus interface unit clock instance.
>>   * @ciu_clk: Pointer to card interface unit clock instance.
>>   * @slot: Slots sharing this MMC controller.
>> + * @sdr_timing: Clock phase shifting for driving and sampling in sdr mode
>> + * @ddr_timing: Clock phase shifting for driving and sampling in ddr mode
>>   * @fifo_depth: depth of FIFO.
>>   * @data_shift: log2 of FIFO item size.
>>   * @part_buf_start: Start index in part_buf.
>> @@ -166,6 +168,10 @@ struct dw_mci {
>>       struct clk              *ciu_clk;
>>       struct dw_mci_slot      *slot[MAX_MCI_SLOTS];
>>
>> +     /* Phase Shift Value (for exynos5250 variant) */
>> +     u32                     sdr_timing;
>> +     u32                     ddr_timing;
>> +
>>       /* FIFO push and pull */
>>       int                     fifo_depth;
>>       int                     data_shift;
>> --
>> 1.6.6.rc2
>>
>> --
>> 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
>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v3 6/6] mmc: dw_mmc: add samsung exynos5250 specific extentions
@ 2012-07-19 18:48       ` Thomas Abraham
  0 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-19 18:48 UTC (permalink / raw)
  To: linux-arm-kernel

On 19 July 2012 09:21, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Hi,
>
> This version does not seems to consider previous reviews fully.
> Could you check the comments below?

I did try to address all the comments. I will check again and resubmit
if I have missed anything.

>
> July 12, 2012, Thomas Abraham <thomas.abraham@linaro.org> wrote:
>> The instantiation of the Synopsis Designware controller on Exynos5250
>> include extension for SDR and DDR specific tx/rx phase shift timing
>> and CIU internal divider. In addition to that, the option to skip the
>> command hold stage is also introduced. Add support for these Exynos5250
>> specfic extenstions.
>>
>> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
>> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
>> ---
>>  .../devicetree/bindings/mmc/synposis-dw-mshc.txt   |   38 ++++++++++++++++++-
>>  drivers/mmc/host/dw_mmc-pltfm.c                    |   15 +++++++
>>  drivers/mmc/host/dw_mmc.c                          |   40 +++++++++++++++++++-
>>  drivers/mmc/host/dw_mmc.h                          |   14 +++++++
>>  include/linux/mmc/dw_mmc.h                         |    6 +++
>>  5 files changed, 110 insertions(+), 3 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
>> b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
>> index 3acd6c9..69d78c1 100644
>> --- a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
>> +++ b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
>> @@ -7,6 +7,8 @@ Required Properties:
>>
>>  * compatible: should be one of the following
>>       - snps,dw-mshc: for controllers compliant with synopsis dw-mshc.
>> +     - samsung,exynos5250-dw-mshc: for controllers with Samsung
>> +       Exynos5250 specific extentions.
>>
>>  * reg: physical base address of the dw-mshc controller and size of its memory
>>    region.
>> @@ -74,13 +76,45 @@ Aliases:
>>    the following format 'mshc{n}' where n is a unique number for the alias.
>>
>>
>> +Samsung Exynos4/5 specific properties:
>> +
>> +Some of the variants of Exynos4 (such as Exynos4412) and Exynos5 SoC's
>> +includes few extensions to the Synopsis Designware Mobile Storage Host
>> +Controller. The following properties are used to describe those extensions.
>> +
>> +* samsung,dw-mshc-sdr-timing: Specifies the value of CUI clock divider, CIU
>> +  clock phase shift value in transmit mode and CIU clock phase shift value in
>> +  receive mode for single data rate mode operation. Refer notes of the valid
>> +  values below.
>> +
>> +* samsung,dw-mshc-ddr-timing: Specifies the value of CUI clock divider, CIU
>> +  clock phase shift value in transmit mode and CIU clock phase shift value in
>> +  receive mode for double data rate mode operation. Refer notes of the valid
>> +  values below. The order of the cells should be
>> +
>> +    - First Cell:    CIU clock divider value (applicable only for Exynos5
>> +                     SoC's, should be zero for Exynos4 SoC's)
>> +    - Second Cell:   CIU clock phase shift value for tx mode.
>> +    - Third Cell:    CIU clock phase shift value for rx mode.
>> +
>> +  Valid values for SDR and DDR CIU clock timing for Exynos5250:
>> +
>> +    - valid values for CIU clock divider, tx phase shift and rx phase shift
>> +      is 0 to 7.
>> +
>> +    - When CIU clock divider value is set to 3, all possible 8 phase shift
>> +      values can be used.
>> +
>> +    - If CIU clock divider value is 0 (that is divide by 1), both tx and rx
>> +      phase shift clocks should be 0.
>> +
>>  Example:
>>
>>    The MSHC controller node can be split into two portions, SoC specific and
>>    board specific portions as listed below.
>>
>>       dwmmc0 at 12200000 {
>> -             compatible = "snps,dw-mshc";
>> +             compatible = "samsung,exynos5250-dw-mshc";
>>               reg = <0x12200000 0x1000>;
>>               interrupts = <0 75 0>;
>>               #address-cells = <1>;
>> @@ -94,6 +128,8 @@ Example:
>>               no-write-protect;
>>               fifo-depth = <0x80>;
>>               card-detect-delay = <200>;
>> +             samsung,dw-mshc-sdr-timing = <2 3 3>;
>> +             samsung,dw-mshc-ddr-timing = <1 2 3>;
>>
>>               slot at 0 {
>>                       reg = <0>;
>> diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
>> index 8d24f6d..900f412 100644
>> --- a/drivers/mmc/host/dw_mmc-pltfm.c
>> +++ b/drivers/mmc/host/dw_mmc-pltfm.c
>> @@ -27,9 +27,24 @@ static struct dw_mci_drv_data synopsis_drv_data = {
>>       .ctrl_type      = DW_MCI_TYPE_SYNOPSIS,
>>  };
>>
>> +static unsigned long exynos5250_dwmmc_caps[4] = {
>> +     MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
>> +             MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
>> +     MMC_CAP_CMD23,
>> +     MMC_CAP_CMD23,
>> +     MMC_CAP_CMD23,
>> +};
>> +
> Kyungmin Park has already pointed .
> It's not still proper place for board specific caps.
> If I'm incorrect, please let me know.
> And why MMC_CAP_CMD23 is default caps for all channel of hosts?

The cap listed above are specifying controller capabilities for dw-mmc
controllers on Exynos5 SoC. They are not board specific caps. All the
Exynos5 dw-mmc controllers can support MMC_CAP_CMD23 cap and hence, it
has been listed for all the controllers. Please let me know if you
feel there is any change required here.

>
>> +static struct dw_mci_drv_data exynos5250_drv_data = {
>> +     .ctrl_type      = DW_MCI_TYPE_EXYNOS5250,
>> +     .caps           = exynos5250_dwmmc_caps,
>> +};
>> +
>>  static const struct of_device_id dw_mci_pltfm_match[] = {
>>       { .compatible = "snps,dw-mshc",
>>                       .data = (void *)&synopsis_drv_data, },
>> +     { .compatible = "samsung,exynos5250-dw-mshc",
>> +                     .data = (void *)&exynos5250_drv_data, },
>>       {},
>>  };
>>  MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
>> index 3bc276d..bbf1209 100644
>> --- a/drivers/mmc/host/dw_mmc.c
>> +++ b/drivers/mmc/host/dw_mmc.c
>> @@ -236,6 +236,7 @@ static void dw_mci_set_timeout(struct dw_mci *host)
>>  static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
>>  {
>>       struct mmc_data *data;
>> +     struct dw_mci_slot *slot = mmc_priv(mmc);
>>       u32 cmdr;
>>       cmd->error = -EINPROGRESS;
>>
>> @@ -265,6 +266,17 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
>>                       cmdr |= SDMMC_CMD_DAT_WR;
>>       }
>>
>> +     /*
>> +      * Samsung Exynos5250 extends the use of CMD register with the use of
>> +      * bit 29 (which is reserved on standard MSHC controllers) for
>> +      * optionally bypassing the HOLD register for command and data. The
>> +      * HOLD register should be bypassed in case there is no phase shift
>> +      * applied on CMD/DATA that is sent to the card.
>> +      */
>> +     if (slot->host->drv_data->ctrl_type == DW_MCI_TYPE_EXYNOS5250)
>> +             if (SDMMC_CLKSEL_GET_SELCLK_DRV(mci_readl(slot->host, CLKSEL)))
>> +                     cmdr |= SDMMC_CMD_USE_HOLD_REG;
>> +
>>       return cmdr;
>>  }
>>
>> @@ -802,10 +814,19 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
>>       regs = mci_readl(slot->host, UHS_REG);
>>
>>       /* DDR mode set */
>> -     if (ios->timing == MMC_TIMING_UHS_DDR50)
>> +     if (ios->timing == MMC_TIMING_UHS_DDR50) {
>>               regs |= (0x1 << slot->id) << 16;
>> -     else
>> +             mci_writel(slot->host, CLKSEL, slot->host->ddr_timing);
>> +     } else {
>>               regs &= ~(0x1 << slot->id) << 16;
>> +             mci_writel(slot->host, CLKSEL, slot->host->sdr_timing);
>> +     }
>> +
>> +     if (slot->host->drv_data->ctrl_type == DW_MCI_TYPE_EXYNOS5250) {
>> +             slot->host->bus_hz = clk_get_rate(slot->host->ciu_clk);
>> +             slot->host->bus_hz /= SDMMC_CLKSEL_GET_DIVRATIO(
>> +                                     mci_readl(slot->host, CLKSEL));
>> +     }
> As you know, CLKSEL is specific for Samsung soc.
> 0x09C(CLKSEL)  is reserved area in Synopsys memory map.
> In case of non-samsung-soc, we cannot ensure this usage.
> In previous version, I have suggested separating the variant into another file.

There is a check for type of SoC before using 0x9C as CLKSEL register.
Other implementations of dw-mmc might define custom register at 0x9C
but this will code will not execute on other SoC's and will not break
anything on other implementations. Regarding spliting this Exynos
specific code into another file, I prefer not to do it for now.
Spliting the code means adding new definitions of callback functions
which I am not sure is really required. The present code is fairly
simple one.

>
>>
>>       mci_writel(slot->host, UHS_REG, regs);
>>
>> @@ -2086,6 +2107,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
>>       struct dw_mci_board *pdata;
>>       struct device *dev = host->dev;
>>       struct device_node *np = dev->of_node;
>> +     u32 timing[3];
>>       int idx, cnt;
>>
>>       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
>> @@ -2108,6 +2130,20 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
>>               if (of_get_property(np, of_quriks[idx].quirk, NULL))
>>                       pdata->quirks |= of_quriks[idx].id;
>>
>> +     if (of_property_read_u32_array(dev->of_node,
>> +                     "samsung,dw-mshc-sdr-timing", timing, 3))
>> +             host->sdr_timing = DW_MCI_DEF_SDR_TIMING;
> Host of non-samsung will reach here.
> host->sdr_timing is needed for this host? host->ddr_timing is the same.

Yes, but non-samsung hosts will not have have this property into their
dts file. So the code within the condition will not execute on
non-samsung hosts. SDR and DDR timing are required for Exynos5 SoC.

>
>> +     else
>> +             host->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0],
>> +                                     timing[1], timing[2]);
>> +
>> +     if (of_property_read_u32_array(dev->of_node,
>> +                     "samsung,dw-mshc-ddr-timing", timing, 3))
>> +             host->ddr_timing = DW_MCI_DEF_DDR_TIMING;
>> +     else
>> +             host->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0],
>> +                                     timing[1], timing[2]);
>> +
>>       if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
>>               dev_info(dev, "fifo-depth property not found, using "
>>                               "value of FIFOTH register as default\n");
>> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
>> index 1ecaa02..6c17282 100644
>> --- a/drivers/mmc/host/dw_mmc.h
>> +++ b/drivers/mmc/host/dw_mmc.h
>> @@ -53,6 +53,7 @@
>>  #define SDMMC_IDINTEN                0x090
>>  #define SDMMC_DSCADDR                0x094
>>  #define SDMMC_BUFADDR                0x098
>> +#define SDMMC_CLKSEL         0x09C /* specific to Samsung Exynos5250 */
>>  #define SDMMC_DATA(x)                (x)
>>
>>  /*
>> @@ -111,6 +112,7 @@
>>  #define SDMMC_INT_ERROR                      0xbfc2
>>  /* Command register defines */
>>  #define SDMMC_CMD_START                      BIT(31)
>> +#define SDMMC_CMD_USE_HOLD_REG               BIT(29)
>>  #define SDMMC_CMD_CCS_EXP            BIT(23)
>>  #define SDMMC_CMD_CEATA_RD           BIT(22)
>>  #define SDMMC_CMD_UPD_CLK            BIT(21)
>> @@ -142,6 +144,17 @@
>>  /* Version ID register define */
>>  #define SDMMC_GET_VERID(x)           ((x) & 0xFFFF)
>>
>> +#define DW_MCI_DEF_SDR_TIMING                0x03030002
>> +#define DW_MCI_DEF_DDR_TIMING                0x03020001
> What is the basis for these timing?
> These values is board-specific.
>
>> +#define SDMMC_CLKSEL_CCLK_SAMPLE(x)  (((x) & 3) << 0)
>> +#define SDMMC_CLKSEL_CCLK_DRIVE(x)   (((x) & 3) << 16)
>> +#define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 3) << 24)
> If it's for exynos5, it will be 7 not 3.

Yes, I missed that. Thanks. I will fix this.

>
>> +#define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) |  \
>> +                                     SDMMC_CLKSEL_CCLK_DRIVE(y) |    \
>> +                                     SDMMC_CLKSEL_CCLK_DIVIDER(z))
>> +#define SDMMC_CLKSEL_GET_DIVRATIO(x) ((((x) >> 24) & 0x7) + 1)
>> +#define SDMMC_CLKSEL_GET_SELCLK_DRV(x)       (((x) >> 16) & 0x7)
>> +
> Is this patch considered only for exynos5250?
> In case of exynos4210, the number of bits is different.
> If upper macros is backward-compatible, it would be better.

These consider the Exynos4210 and Exynos4412 implementations as well.
The device tree documentation clearly states that the possible values
for each of the dividers. For Exynos4 SoC's, the divider value is
between 1 to 4 (or 0 to 3). So a bit mask of 7 is backward compatilble
for Exynos4.

Thanks for your review and comments on this patch.

Regards,
Thomas.

>
> Best regards,
> Seungwon Jeon
>
>>  /* Register access macros */
>>  #define mci_readl(dev, reg)                  \
>>       __raw_readl((dev)->regs + SDMMC_##reg)
>> @@ -184,6 +197,7 @@ extern int dw_mci_resume(struct dw_mci *host);
>>
>>  /* Variations in the dw_mci controller */
>>  #define DW_MCI_TYPE_SYNOPSIS         0
>> +#define DW_MCI_TYPE_EXYNOS5250               1 /* Samsung Exynos5250 Extensions */
>>
>>  /* dw_mci platform driver data */
>>  struct dw_mci_drv_data {
>> diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
>> index ae45e4f..32c778f 100644
>> --- a/include/linux/mmc/dw_mmc.h
>> +++ b/include/linux/mmc/dw_mmc.h
>> @@ -82,6 +82,8 @@ struct mmc_data;
>>   * @biu_clk: Pointer to bus interface unit clock instance.
>>   * @ciu_clk: Pointer to card interface unit clock instance.
>>   * @slot: Slots sharing this MMC controller.
>> + * @sdr_timing: Clock phase shifting for driving and sampling in sdr mode
>> + * @ddr_timing: Clock phase shifting for driving and sampling in ddr mode
>>   * @fifo_depth: depth of FIFO.
>>   * @data_shift: log2 of FIFO item size.
>>   * @part_buf_start: Start index in part_buf.
>> @@ -166,6 +168,10 @@ struct dw_mci {
>>       struct clk              *ciu_clk;
>>       struct dw_mci_slot      *slot[MAX_MCI_SLOTS];
>>
>> +     /* Phase Shift Value (for exynos5250 variant) */
>> +     u32                     sdr_timing;
>> +     u32                     ddr_timing;
>> +
>>       /* FIFO push and pull */
>>       int                     fifo_depth;
>>       int                     data_shift;
>> --
>> 1.6.6.rc2
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 0/6] mmc: dw_mmc: add support for device tree based instantiation
  2012-07-19 15:28   ` Jaehoon Chung
@ 2012-07-19 18:59     ` Thomas Abraham
  -1 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-19 18:59 UTC (permalink / raw)
  To: Jaehoon Chung
  Cc: linux-mmc, devicetree-discuss, linux-kernel, linux-arm-kernel,
	cjb, grant.likely, rob.herring, linux-samsung-soc, kgene.kim,
	patches

On 19 July 2012 20:58, Jaehoon Chung <jh80.chung@samsung.com> wrote:
> Hi Thomas,
>
> I think not good that added the samsung specific code into dw_mmc-pltfm.c
> How about separating to dw-mmc-exynos.c?

I am not sure of this. The only samsung specific code in
dw_mmc-pltfm.c file is the data for of_device_id instances. The clock
lookup added into this file in the 3rd patch does not cause any harm
on non-samsung SoC's which might not define those clocks (on clock
lookup failure, there are only warning printed, the driver's probe
does not fail.

I would prefer not to add separate file for Exynos SoC's for now.
Splitting into different files will need to defined new callbacks
which I fell is not really required.

Thanks,
Thomas.

>
> Best Regards,
> Jaehoon Chung
>
> On 07/12/2012 09:54 PM, Thomas Abraham wrote:
>> This patch series adds device tree support for Synopsis Designware Mobile
>> Storage Host Controller.
>>
>> The first patch converts the copy of controller device instance into a
>> reference. This is need to allow device resource management api to correctly
>> manage the resources allocated by the driver. The second patch fixes the
>> incorrect abort of the probe in case a slot initialization fails. This is
>> fixed by allowing as many slots to be initialized successfully and failing
>> only if there are no slots that were initialized.
>>
>> The third patch adds clock lookup in the driver and this is optional. Platforms
>> that do not need any clock gating and control for the dw_mmc controllers will
>> not be affected with this change. The fourth patch adds a quirk to notify the
>> controller about the absence of the write protect line.
>>
>> The fifth patch adds device tree based discovery support for the dw_mmc driver.
>> The sixth patch add Samsung Exynos5250 specific extentions to the driver.
>>
>> This patchset is based on Samsung kernel tree's for-next branch with the
>> mmc tree's mmc-next branch merged.
>>
>> Thomas Abraham (6):
>>   mmc: dw_mmc: convert copy of struct device in struct dw_mci to a reference
>>   mmc: dw_mmc: allow probe to succeed even if one slot is initialized
>>   mmc: dw_mmc: lookup for optional biu and ciu clocks
>>   mmc: dw_mmc: add quirk to indicate missing write protect line
>>   mmc: dw_mmc: add device tree support
>>   mmc: dw_mmc: add samsung exynos5250 specific extentions
>>
>>  .../devicetree/bindings/mmc/synposis-dw-mshc.txt   |  144 ++++++++
>>  drivers/mmc/host/dw_mmc-pci.c                      |    2 +-
>>  drivers/mmc/host/dw_mmc-pltfm.c                    |   41 +++-
>>  drivers/mmc/host/dw_mmc.c                          |  364 +++++++++++++++++---
>>  drivers/mmc/host/dw_mmc.h                          |   23 ++
>>  include/linux/mmc/dw_mmc.h                         |   17 +-
>>  6 files changed, 538 insertions(+), 53 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
>>
>> --
>> 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
>>
>
>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v3 0/6] mmc: dw_mmc: add support for device tree based instantiation
@ 2012-07-19 18:59     ` Thomas Abraham
  0 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-19 18:59 UTC (permalink / raw)
  To: linux-arm-kernel

On 19 July 2012 20:58, Jaehoon Chung <jh80.chung@samsung.com> wrote:
> Hi Thomas,
>
> I think not good that added the samsung specific code into dw_mmc-pltfm.c
> How about separating to dw-mmc-exynos.c?

I am not sure of this. The only samsung specific code in
dw_mmc-pltfm.c file is the data for of_device_id instances. The clock
lookup added into this file in the 3rd patch does not cause any harm
on non-samsung SoC's which might not define those clocks (on clock
lookup failure, there are only warning printed, the driver's probe
does not fail.

I would prefer not to add separate file for Exynos SoC's for now.
Splitting into different files will need to defined new callbacks
which I fell is not really required.

Thanks,
Thomas.

>
> Best Regards,
> Jaehoon Chung
>
> On 07/12/2012 09:54 PM, Thomas Abraham wrote:
>> This patch series adds device tree support for Synopsis Designware Mobile
>> Storage Host Controller.
>>
>> The first patch converts the copy of controller device instance into a
>> reference. This is need to allow device resource management api to correctly
>> manage the resources allocated by the driver. The second patch fixes the
>> incorrect abort of the probe in case a slot initialization fails. This is
>> fixed by allowing as many slots to be initialized successfully and failing
>> only if there are no slots that were initialized.
>>
>> The third patch adds clock lookup in the driver and this is optional. Platforms
>> that do not need any clock gating and control for the dw_mmc controllers will
>> not be affected with this change. The fourth patch adds a quirk to notify the
>> controller about the absence of the write protect line.
>>
>> The fifth patch adds device tree based discovery support for the dw_mmc driver.
>> The sixth patch add Samsung Exynos5250 specific extentions to the driver.
>>
>> This patchset is based on Samsung kernel tree's for-next branch with the
>> mmc tree's mmc-next branch merged.
>>
>> Thomas Abraham (6):
>>   mmc: dw_mmc: convert copy of struct device in struct dw_mci to a reference
>>   mmc: dw_mmc: allow probe to succeed even if one slot is initialized
>>   mmc: dw_mmc: lookup for optional biu and ciu clocks
>>   mmc: dw_mmc: add quirk to indicate missing write protect line
>>   mmc: dw_mmc: add device tree support
>>   mmc: dw_mmc: add samsung exynos5250 specific extentions
>>
>>  .../devicetree/bindings/mmc/synposis-dw-mshc.txt   |  144 ++++++++
>>  drivers/mmc/host/dw_mmc-pci.c                      |    2 +-
>>  drivers/mmc/host/dw_mmc-pltfm.c                    |   41 +++-
>>  drivers/mmc/host/dw_mmc.c                          |  364 +++++++++++++++++---
>>  drivers/mmc/host/dw_mmc.h                          |   23 ++
>>  include/linux/mmc/dw_mmc.h                         |   17 +-
>>  6 files changed, 538 insertions(+), 53 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
>
>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* RE: [PATCH v3 0/6] mmc: dw_mmc: add support for device tree based instantiation
  2012-07-19 18:59     ` Thomas Abraham
@ 2012-07-19 22:47       ` Kukjin Kim
  -1 siblings, 0 replies; 53+ messages in thread
From: Kukjin Kim @ 2012-07-19 22:47 UTC (permalink / raw)
  To: 'Thomas Abraham', 'Jaehoon Chung'
  Cc: linux-mmc, devicetree-discuss, linux-kernel, linux-arm-kernel,
	cjb, grant.likely, rob.herring, linux-samsung-soc, patches

Thomas Abraham wrote:
> 
> On 19 July 2012 20:58, Jaehoon Chung <jh80.chung@samsung.com> wrote:
> > Hi Thomas,
> >
> > I think not good that added the samsung specific code into dw_mmc-
> pltfm.c
> > How about separating to dw-mmc-exynos.c?
> 
> I am not sure of this. The only samsung specific code in
> dw_mmc-pltfm.c file is the data for of_device_id instances. The clock
> lookup added into this file in the 3rd patch does not cause any harm
> on non-samsung SoC's which might not define those clocks (on clock
> lookup failure, there are only warning printed, the driver's probe
> does not fail.
> 
I agree with Thomas' opinion, in addition, the dw_mmc-pltfm.c file can
support that, so adding dw-mmc-exynos.c is not needed now.

> I would prefer not to add separate file for Exynos SoC's for now.
> Splitting into different files will need to defined new callbacks
> which I fell is not really required.
> 
Yes.

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v3 0/6] mmc: dw_mmc: add support for device tree based instantiation
@ 2012-07-19 22:47       ` Kukjin Kim
  0 siblings, 0 replies; 53+ messages in thread
From: Kukjin Kim @ 2012-07-19 22:47 UTC (permalink / raw)
  To: linux-arm-kernel

Thomas Abraham wrote:
> 
> On 19 July 2012 20:58, Jaehoon Chung <jh80.chung@samsung.com> wrote:
> > Hi Thomas,
> >
> > I think not good that added the samsung specific code into dw_mmc-
> pltfm.c
> > How about separating to dw-mmc-exynos.c?
> 
> I am not sure of this. The only samsung specific code in
> dw_mmc-pltfm.c file is the data for of_device_id instances. The clock
> lookup added into this file in the 3rd patch does not cause any harm
> on non-samsung SoC's which might not define those clocks (on clock
> lookup failure, there are only warning printed, the driver's probe
> does not fail.
> 
I agree with Thomas' opinion, in addition, the dw_mmc-pltfm.c file can
support that, so adding dw-mmc-exynos.c is not needed now.

> I would prefer not to add separate file for Exynos SoC's for now.
> Splitting into different files will need to defined new callbacks
> which I fell is not really required.
> 
Yes.

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* RE: [PATCH v3 6/6] mmc: dw_mmc: add samsung exynos5250 specific extentions
  2012-07-19 18:48       ` Thomas Abraham
@ 2012-07-20 10:38         ` Seungwon Jeon
  -1 siblings, 0 replies; 53+ messages in thread
From: Seungwon Jeon @ 2012-07-20 10:38 UTC (permalink / raw)
  To: 'Thomas Abraham'
  Cc: linux-mmc, devicetree-discuss, linux-kernel, linux-arm-kernel,
	cjb, grant.likely, rob.herring, linux-samsung-soc, kgene.kim,
	patches

July 20, 2012, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> On 19 July 2012 09:21, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > Hi,
> >
> > This version does not seems to consider previous reviews fully.
> > Could you check the comments below?
> 
> I did try to address all the comments. I will check again and resubmit
> if I have missed anything.
> 
> >
> > July 12, 2012, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> >> The instantiation of the Synopsis Designware controller on Exynos5250
> >> include extension for SDR and DDR specific tx/rx phase shift timing
> >> and CIU internal divider. In addition to that, the option to skip the
> >> command hold stage is also introduced. Add support for these Exynos5250
> >> specfic extenstions.
> >>
> >> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
> >> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
> >> ---
> >>  .../devicetree/bindings/mmc/synposis-dw-mshc.txt   |   38 ++++++++++++++++++-
> >>  drivers/mmc/host/dw_mmc-pltfm.c                    |   15 +++++++
> >>  drivers/mmc/host/dw_mmc.c                          |   40 +++++++++++++++++++-
> >>  drivers/mmc/host/dw_mmc.h                          |   14 +++++++
> >>  include/linux/mmc/dw_mmc.h                         |    6 +++
> >>  5 files changed, 110 insertions(+), 3 deletions(-)
> >>
> >> diff --git a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> >> b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> >> index 3acd6c9..69d78c1 100644
> >> --- a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> >> +++ b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> >> @@ -7,6 +7,8 @@ Required Properties:
> >>
> >>  * compatible: should be one of the following
> >>       - snps,dw-mshc: for controllers compliant with synopsis dw-mshc.
> >> +     - samsung,exynos5250-dw-mshc: for controllers with Samsung
> >> +       Exynos5250 specific extentions.
> >>
> >>  * reg: physical base address of the dw-mshc controller and size of its memory
> >>    region.
> >> @@ -74,13 +76,45 @@ Aliases:
> >>    the following format 'mshc{n}' where n is a unique number for the alias.
> >>
> >>
> >> +Samsung Exynos4/5 specific properties:
> >> +
> >> +Some of the variants of Exynos4 (such as Exynos4412) and Exynos5 SoC's
> >> +includes few extensions to the Synopsis Designware Mobile Storage Host
> >> +Controller. The following properties are used to describe those extensions.
> >> +
> >> +* samsung,dw-mshc-sdr-timing: Specifies the value of CUI clock divider, CIU
> >> +  clock phase shift value in transmit mode and CIU clock phase shift value in
> >> +  receive mode for single data rate mode operation. Refer notes of the valid
> >> +  values below.
> >> +
> >> +* samsung,dw-mshc-ddr-timing: Specifies the value of CUI clock divider, CIU
> >> +  clock phase shift value in transmit mode and CIU clock phase shift value in
> >> +  receive mode for double data rate mode operation. Refer notes of the valid
> >> +  values below. The order of the cells should be
> >> +
> >> +    - First Cell:    CIU clock divider value (applicable only for Exynos5
> >> +                     SoC's, should be zero for Exynos4 SoC's)
> >> +    - Second Cell:   CIU clock phase shift value for tx mode.
> >> +    - Third Cell:    CIU clock phase shift value for rx mode.
> >> +
> >> +  Valid values for SDR and DDR CIU clock timing for Exynos5250:
> >> +
> >> +    - valid values for CIU clock divider, tx phase shift and rx phase shift
> >> +      is 0 to 7.
> >> +
> >> +    - When CIU clock divider value is set to 3, all possible 8 phase shift
> >> +      values can be used.
> >> +
> >> +    - If CIU clock divider value is 0 (that is divide by 1), both tx and rx
> >> +      phase shift clocks should be 0.
> >> +
> >>  Example:
> >>
> >>    The MSHC controller node can be split into two portions, SoC specific and
> >>    board specific portions as listed below.
> >>
> >>       dwmmc0@12200000 {
> >> -             compatible = "snps,dw-mshc";
> >> +             compatible = "samsung,exynos5250-dw-mshc";
> >>               reg = <0x12200000 0x1000>;
> >>               interrupts = <0 75 0>;
> >>               #address-cells = <1>;
> >> @@ -94,6 +128,8 @@ Example:
> >>               no-write-protect;
> >>               fifo-depth = <0x80>;
> >>               card-detect-delay = <200>;
> >> +             samsung,dw-mshc-sdr-timing = <2 3 3>;
> >> +             samsung,dw-mshc-ddr-timing = <1 2 3>;
> >>
> >>               slot@0 {
> >>                       reg = <0>;
> >> diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
> >> index 8d24f6d..900f412 100644
> >> --- a/drivers/mmc/host/dw_mmc-pltfm.c
> >> +++ b/drivers/mmc/host/dw_mmc-pltfm.c
> >> @@ -27,9 +27,24 @@ static struct dw_mci_drv_data synopsis_drv_data = {
> >>       .ctrl_type      = DW_MCI_TYPE_SYNOPSIS,
> >>  };
> >>
> >> +static unsigned long exynos5250_dwmmc_caps[4] = {
> >> +     MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
> >> +             MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
> >> +     MMC_CAP_CMD23,
> >> +     MMC_CAP_CMD23,
> >> +     MMC_CAP_CMD23,
> >> +};
> >> +
> > Kyungmin Park has already pointed .
> > It's not still proper place for board specific caps.
> > If I'm incorrect, please let me know.
> > And why MMC_CAP_CMD23 is default caps for all channel of hosts?
> 
> The cap listed above are specifying controller capabilities for dw-mmc
> controllers on Exynos5 SoC. They are not board specific caps. All the
> Exynos5 dw-mmc controllers can support MMC_CAP_CMD23 cap and hence, it
> has been listed for all the controllers. Please let me know if you
> feel there is any change required here.
MMC_CAP_8_BIT_DATA could be dependent on board.
I agree about MMC_CAP_CMD23.
Additionally, MMC_CAP_CMD23 is applied for dw-mmc host driver without regard to Exynos5.

> 
> >
> >> +static struct dw_mci_drv_data exynos5250_drv_data = {
> >> +     .ctrl_type      = DW_MCI_TYPE_EXYNOS5250,
> >> +     .caps           = exynos5250_dwmmc_caps,
> >> +};
> >> +
> >>  static const struct of_device_id dw_mci_pltfm_match[] = {
> >>       { .compatible = "snps,dw-mshc",
> >>                       .data = (void *)&synopsis_drv_data, },
> >> +     { .compatible = "samsung,exynos5250-dw-mshc",
> >> +                     .data = (void *)&exynos5250_drv_data, },
> >>       {},
> >>  };
> >>  MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
> >> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> >> index 3bc276d..bbf1209 100644
> >> --- a/drivers/mmc/host/dw_mmc.c
> >> +++ b/drivers/mmc/host/dw_mmc.c
> >> @@ -236,6 +236,7 @@ static void dw_mci_set_timeout(struct dw_mci *host)
> >>  static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
> >>  {
> >>       struct mmc_data *data;
> >> +     struct dw_mci_slot *slot = mmc_priv(mmc);
> >>       u32 cmdr;
> >>       cmd->error = -EINPROGRESS;
> >>
> >> @@ -265,6 +266,17 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command
> *cmd)
> >>                       cmdr |= SDMMC_CMD_DAT_WR;
> >>       }
> >>
> >> +     /*
> >> +      * Samsung Exynos5250 extends the use of CMD register with the use of
> >> +      * bit 29 (which is reserved on standard MSHC controllers) for
> >> +      * optionally bypassing the HOLD register for command and data. The
> >> +      * HOLD register should be bypassed in case there is no phase shift
> >> +      * applied on CMD/DATA that is sent to the card.
> >> +      */
> >> +     if (slot->host->drv_data->ctrl_type == DW_MCI_TYPE_EXYNOS5250)
> >> +             if (SDMMC_CLKSEL_GET_SELCLK_DRV(mci_readl(slot->host, CLKSEL)))
> >> +                     cmdr |= SDMMC_CMD_USE_HOLD_REG;
> >> +
> >>       return cmdr;
> >>  }
> >>
> >> @@ -802,10 +814,19 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> >>       regs = mci_readl(slot->host, UHS_REG);
> >>
> >>       /* DDR mode set */
> >> -     if (ios->timing == MMC_TIMING_UHS_DDR50)
> >> +     if (ios->timing == MMC_TIMING_UHS_DDR50) {
> >>               regs |= (0x1 << slot->id) << 16;
> >> -     else
> >> +             mci_writel(slot->host, CLKSEL, slot->host->ddr_timing);
> >> +     } else {
> >>               regs &= ~(0x1 << slot->id) << 16;
> >> +             mci_writel(slot->host, CLKSEL, slot->host->sdr_timing);
> >> +     }
> >> +
> >> +     if (slot->host->drv_data->ctrl_type == DW_MCI_TYPE_EXYNOS5250) {
> >> +             slot->host->bus_hz = clk_get_rate(slot->host->ciu_clk);
> >> +             slot->host->bus_hz /= SDMMC_CLKSEL_GET_DIVRATIO(
> >> +                                     mci_readl(slot->host, CLKSEL));
> >> +     }
> > As you know, CLKSEL is specific for Samsung soc.
> > 0x09C(CLKSEL)  is reserved area in Synopsys memory map.
> > In case of non-samsung-soc, we cannot ensure this usage.
> > In previous version, I have suggested separating the variant into another file.
> 
> There is a check for type of SoC before using 0x9C as CLKSEL register.
Do you mean checking DW_MCI_TYPE_EXYNOS5250?
But Above two case(ddr_timing/sdr_timing), CLKSEL can be accessed on other soc's.

> Other implementations of dw-mmc might define custom register at 0x9C
Even so, register field can be different with Samsung soc.

> but this will code will not execute on other SoC's and will not break
> anything on other implementations. Regarding spliting this Exynos
> specific code into another file, I prefer not to do it for now.
> Spliting the code means adding new definitions of callback functions
> which I am not sure is really required. The present code is fairly
> simple one.
Yes, callback functions might be needed to accommodate various implementation
of host controller. It would be better to prepare this for other variant next.

> 
> >
> >>
> >>       mci_writel(slot->host, UHS_REG, regs);
> >>
> >> @@ -2086,6 +2107,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
> >>       struct dw_mci_board *pdata;
> >>       struct device *dev = host->dev;
> >>       struct device_node *np = dev->of_node;
> >> +     u32 timing[3];
> >>       int idx, cnt;
> >>
> >>       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
> >> @@ -2108,6 +2130,20 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
> >>               if (of_get_property(np, of_quriks[idx].quirk, NULL))
> >>                       pdata->quirks |= of_quriks[idx].id;
> >>
> >> +     if (of_property_read_u32_array(dev->of_node,
> >> +                     "samsung,dw-mshc-sdr-timing", timing, 3))
> >> +             host->sdr_timing = DW_MCI_DEF_SDR_TIMING;
> > Host of non-samsung will reach here.
> > host->sdr_timing is needed for this host? host->ddr_timing is the same.
> 
> Yes, but non-samsung hosts will not have have this property into their
> dts file. So the code within the condition will not execute on
> non-samsung hosts. SDR and DDR timing are required for Exynos5 SoC.
Yes, these are required only for Exynos Soc. 
Non-samsung host will have default value here, but it seems to be meaningless.

> 
> >
> >> +     else
> >> +             host->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0],
> >> +                                     timing[1], timing[2]);
> >> +
> >> +     if (of_property_read_u32_array(dev->of_node,
> >> +                     "samsung,dw-mshc-ddr-timing", timing, 3))
> >> +             host->ddr_timing = DW_MCI_DEF_DDR_TIMING;
> >> +     else
> >> +             host->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0],
> >> +                                     timing[1], timing[2]);
> >> +
> >>       if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
> >>               dev_info(dev, "fifo-depth property not found, using "
> >>                               "value of FIFOTH register as default\n");
> >> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
> >> index 1ecaa02..6c17282 100644
> >> --- a/drivers/mmc/host/dw_mmc.h
> >> +++ b/drivers/mmc/host/dw_mmc.h
> >> @@ -53,6 +53,7 @@
> >>  #define SDMMC_IDINTEN                0x090
> >>  #define SDMMC_DSCADDR                0x094
> >>  #define SDMMC_BUFADDR                0x098
> >> +#define SDMMC_CLKSEL         0x09C /* specific to Samsung Exynos5250 */
> >>  #define SDMMC_DATA(x)                (x)
> >>
> >>  /*
> >> @@ -111,6 +112,7 @@
> >>  #define SDMMC_INT_ERROR                      0xbfc2
> >>  /* Command register defines */
> >>  #define SDMMC_CMD_START                      BIT(31)
> >> +#define SDMMC_CMD_USE_HOLD_REG               BIT(29)
> >>  #define SDMMC_CMD_CCS_EXP            BIT(23)
> >>  #define SDMMC_CMD_CEATA_RD           BIT(22)
> >>  #define SDMMC_CMD_UPD_CLK            BIT(21)
> >> @@ -142,6 +144,17 @@
> >>  /* Version ID register define */
> >>  #define SDMMC_GET_VERID(x)           ((x) & 0xFFFF)
> >>
> >> +#define DW_MCI_DEF_SDR_TIMING                0x03030002
> >> +#define DW_MCI_DEF_DDR_TIMING                0x03020001
> > What is the basis for these timing?
> > These values is board-specific.
One missed comment?

> >
> >> +#define SDMMC_CLKSEL_CCLK_SAMPLE(x)  (((x) & 3) << 0)
> >> +#define SDMMC_CLKSEL_CCLK_DRIVE(x)   (((x) & 3) << 16)
> >> +#define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 3) << 24)
> > If it's for exynos5, it will be 7 not 3.
> 
> Yes, I missed that. Thanks. I will fix this.
> 
> >
> >> +#define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) |  \
> >> +                                     SDMMC_CLKSEL_CCLK_DRIVE(y) |    \
> >> +                                     SDMMC_CLKSEL_CCLK_DIVIDER(z))
> >> +#define SDMMC_CLKSEL_GET_DIVRATIO(x) ((((x) >> 24) & 0x7) + 1)
> >> +#define SDMMC_CLKSEL_GET_SELCLK_DRV(x)       (((x) >> 16) & 0x7)
> >> +
> > Is this patch considered only for exynos5250?
> > In case of exynos4210, the number of bits is different.
> > If upper macros is backward-compatible, it would be better.
> 
> These consider the Exynos4210 and Exynos4412 implementations as well.
> The device tree documentation clearly states that the possible values
> for each of the dividers. For Exynos4 SoC's, the divider value is
> between 1 to 4 (or 0 to 3). So a bit mask of 7 is backward compatilble
> for Exynos4.
Bit width is 2 for selclk_drv in exynos4210.
So bit mask of 3 is proper.

Let me clear it about divider value.
In case of Exynos4 SoC's, divider value(DIVRATIO) is reserved and host doesn't modify.
But value is fixed internally like following.
Exynos4210 : 2
Exynos4412 : 4

Thanks,
Seungwon Jeon

> 
> Thanks for your review and comments on this patch.
> 
> Regards,
> Thomas.
> 
> >
> > Best regards,
> > Seungwon Jeon
> >
> >>  /* Register access macros */
> >>  #define mci_readl(dev, reg)                  \
> >>       __raw_readl((dev)->regs + SDMMC_##reg)
> >> @@ -184,6 +197,7 @@ extern int dw_mci_resume(struct dw_mci *host);
> >>
> >>  /* Variations in the dw_mci controller */
> >>  #define DW_MCI_TYPE_SYNOPSIS         0
> >> +#define DW_MCI_TYPE_EXYNOS5250               1 /* Samsung Exynos5250 Extensions */
> >>
> >>  /* dw_mci platform driver data */
> >>  struct dw_mci_drv_data {
> >> diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
> >> index ae45e4f..32c778f 100644
> >> --- a/include/linux/mmc/dw_mmc.h
> >> +++ b/include/linux/mmc/dw_mmc.h
> >> @@ -82,6 +82,8 @@ struct mmc_data;
> >>   * @biu_clk: Pointer to bus interface unit clock instance.
> >>   * @ciu_clk: Pointer to card interface unit clock instance.
> >>   * @slot: Slots sharing this MMC controller.
> >> + * @sdr_timing: Clock phase shifting for driving and sampling in sdr mode
> >> + * @ddr_timing: Clock phase shifting for driving and sampling in ddr mode
> >>   * @fifo_depth: depth of FIFO.
> >>   * @data_shift: log2 of FIFO item size.
> >>   * @part_buf_start: Start index in part_buf.
> >> @@ -166,6 +168,10 @@ struct dw_mci {
> >>       struct clk              *ciu_clk;
> >>       struct dw_mci_slot      *slot[MAX_MCI_SLOTS];
> >>
> >> +     /* Phase Shift Value (for exynos5250 variant) */
> >> +     u32                     sdr_timing;
> >> +     u32                     ddr_timing;
> >> +
> >>       /* FIFO push and pull */
> >>       int                     fifo_depth;
> >>       int                     data_shift;
> >> --
> >> 1.6.6.rc2
> >>
> >> --
> >> 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
> >
> --
> 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


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v3 6/6] mmc: dw_mmc: add samsung exynos5250 specific extentions
@ 2012-07-20 10:38         ` Seungwon Jeon
  0 siblings, 0 replies; 53+ messages in thread
From: Seungwon Jeon @ 2012-07-20 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

July 20, 2012, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> On 19 July 2012 09:21, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > Hi,
> >
> > This version does not seems to consider previous reviews fully.
> > Could you check the comments below?
> 
> I did try to address all the comments. I will check again and resubmit
> if I have missed anything.
> 
> >
> > July 12, 2012, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> >> The instantiation of the Synopsis Designware controller on Exynos5250
> >> include extension for SDR and DDR specific tx/rx phase shift timing
> >> and CIU internal divider. In addition to that, the option to skip the
> >> command hold stage is also introduced. Add support for these Exynos5250
> >> specfic extenstions.
> >>
> >> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
> >> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
> >> ---
> >>  .../devicetree/bindings/mmc/synposis-dw-mshc.txt   |   38 ++++++++++++++++++-
> >>  drivers/mmc/host/dw_mmc-pltfm.c                    |   15 +++++++
> >>  drivers/mmc/host/dw_mmc.c                          |   40 +++++++++++++++++++-
> >>  drivers/mmc/host/dw_mmc.h                          |   14 +++++++
> >>  include/linux/mmc/dw_mmc.h                         |    6 +++
> >>  5 files changed, 110 insertions(+), 3 deletions(-)
> >>
> >> diff --git a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> >> b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> >> index 3acd6c9..69d78c1 100644
> >> --- a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> >> +++ b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
> >> @@ -7,6 +7,8 @@ Required Properties:
> >>
> >>  * compatible: should be one of the following
> >>       - snps,dw-mshc: for controllers compliant with synopsis dw-mshc.
> >> +     - samsung,exynos5250-dw-mshc: for controllers with Samsung
> >> +       Exynos5250 specific extentions.
> >>
> >>  * reg: physical base address of the dw-mshc controller and size of its memory
> >>    region.
> >> @@ -74,13 +76,45 @@ Aliases:
> >>    the following format 'mshc{n}' where n is a unique number for the alias.
> >>
> >>
> >> +Samsung Exynos4/5 specific properties:
> >> +
> >> +Some of the variants of Exynos4 (such as Exynos4412) and Exynos5 SoC's
> >> +includes few extensions to the Synopsis Designware Mobile Storage Host
> >> +Controller. The following properties are used to describe those extensions.
> >> +
> >> +* samsung,dw-mshc-sdr-timing: Specifies the value of CUI clock divider, CIU
> >> +  clock phase shift value in transmit mode and CIU clock phase shift value in
> >> +  receive mode for single data rate mode operation. Refer notes of the valid
> >> +  values below.
> >> +
> >> +* samsung,dw-mshc-ddr-timing: Specifies the value of CUI clock divider, CIU
> >> +  clock phase shift value in transmit mode and CIU clock phase shift value in
> >> +  receive mode for double data rate mode operation. Refer notes of the valid
> >> +  values below. The order of the cells should be
> >> +
> >> +    - First Cell:    CIU clock divider value (applicable only for Exynos5
> >> +                     SoC's, should be zero for Exynos4 SoC's)
> >> +    - Second Cell:   CIU clock phase shift value for tx mode.
> >> +    - Third Cell:    CIU clock phase shift value for rx mode.
> >> +
> >> +  Valid values for SDR and DDR CIU clock timing for Exynos5250:
> >> +
> >> +    - valid values for CIU clock divider, tx phase shift and rx phase shift
> >> +      is 0 to 7.
> >> +
> >> +    - When CIU clock divider value is set to 3, all possible 8 phase shift
> >> +      values can be used.
> >> +
> >> +    - If CIU clock divider value is 0 (that is divide by 1), both tx and rx
> >> +      phase shift clocks should be 0.
> >> +
> >>  Example:
> >>
> >>    The MSHC controller node can be split into two portions, SoC specific and
> >>    board specific portions as listed below.
> >>
> >>       dwmmc0 at 12200000 {
> >> -             compatible = "snps,dw-mshc";
> >> +             compatible = "samsung,exynos5250-dw-mshc";
> >>               reg = <0x12200000 0x1000>;
> >>               interrupts = <0 75 0>;
> >>               #address-cells = <1>;
> >> @@ -94,6 +128,8 @@ Example:
> >>               no-write-protect;
> >>               fifo-depth = <0x80>;
> >>               card-detect-delay = <200>;
> >> +             samsung,dw-mshc-sdr-timing = <2 3 3>;
> >> +             samsung,dw-mshc-ddr-timing = <1 2 3>;
> >>
> >>               slot at 0 {
> >>                       reg = <0>;
> >> diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
> >> index 8d24f6d..900f412 100644
> >> --- a/drivers/mmc/host/dw_mmc-pltfm.c
> >> +++ b/drivers/mmc/host/dw_mmc-pltfm.c
> >> @@ -27,9 +27,24 @@ static struct dw_mci_drv_data synopsis_drv_data = {
> >>       .ctrl_type      = DW_MCI_TYPE_SYNOPSIS,
> >>  };
> >>
> >> +static unsigned long exynos5250_dwmmc_caps[4] = {
> >> +     MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
> >> +             MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
> >> +     MMC_CAP_CMD23,
> >> +     MMC_CAP_CMD23,
> >> +     MMC_CAP_CMD23,
> >> +};
> >> +
> > Kyungmin Park has already pointed .
> > It's not still proper place for board specific caps.
> > If I'm incorrect, please let me know.
> > And why MMC_CAP_CMD23 is default caps for all channel of hosts?
> 
> The cap listed above are specifying controller capabilities for dw-mmc
> controllers on Exynos5 SoC. They are not board specific caps. All the
> Exynos5 dw-mmc controllers can support MMC_CAP_CMD23 cap and hence, it
> has been listed for all the controllers. Please let me know if you
> feel there is any change required here.
MMC_CAP_8_BIT_DATA could be dependent on board.
I agree about MMC_CAP_CMD23.
Additionally, MMC_CAP_CMD23 is applied for dw-mmc host driver without regard to Exynos5.

> 
> >
> >> +static struct dw_mci_drv_data exynos5250_drv_data = {
> >> +     .ctrl_type      = DW_MCI_TYPE_EXYNOS5250,
> >> +     .caps           = exynos5250_dwmmc_caps,
> >> +};
> >> +
> >>  static const struct of_device_id dw_mci_pltfm_match[] = {
> >>       { .compatible = "snps,dw-mshc",
> >>                       .data = (void *)&synopsis_drv_data, },
> >> +     { .compatible = "samsung,exynos5250-dw-mshc",
> >> +                     .data = (void *)&exynos5250_drv_data, },
> >>       {},
> >>  };
> >>  MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
> >> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> >> index 3bc276d..bbf1209 100644
> >> --- a/drivers/mmc/host/dw_mmc.c
> >> +++ b/drivers/mmc/host/dw_mmc.c
> >> @@ -236,6 +236,7 @@ static void dw_mci_set_timeout(struct dw_mci *host)
> >>  static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
> >>  {
> >>       struct mmc_data *data;
> >> +     struct dw_mci_slot *slot = mmc_priv(mmc);
> >>       u32 cmdr;
> >>       cmd->error = -EINPROGRESS;
> >>
> >> @@ -265,6 +266,17 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command
> *cmd)
> >>                       cmdr |= SDMMC_CMD_DAT_WR;
> >>       }
> >>
> >> +     /*
> >> +      * Samsung Exynos5250 extends the use of CMD register with the use of
> >> +      * bit 29 (which is reserved on standard MSHC controllers) for
> >> +      * optionally bypassing the HOLD register for command and data. The
> >> +      * HOLD register should be bypassed in case there is no phase shift
> >> +      * applied on CMD/DATA that is sent to the card.
> >> +      */
> >> +     if (slot->host->drv_data->ctrl_type == DW_MCI_TYPE_EXYNOS5250)
> >> +             if (SDMMC_CLKSEL_GET_SELCLK_DRV(mci_readl(slot->host, CLKSEL)))
> >> +                     cmdr |= SDMMC_CMD_USE_HOLD_REG;
> >> +
> >>       return cmdr;
> >>  }
> >>
> >> @@ -802,10 +814,19 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> >>       regs = mci_readl(slot->host, UHS_REG);
> >>
> >>       /* DDR mode set */
> >> -     if (ios->timing == MMC_TIMING_UHS_DDR50)
> >> +     if (ios->timing == MMC_TIMING_UHS_DDR50) {
> >>               regs |= (0x1 << slot->id) << 16;
> >> -     else
> >> +             mci_writel(slot->host, CLKSEL, slot->host->ddr_timing);
> >> +     } else {
> >>               regs &= ~(0x1 << slot->id) << 16;
> >> +             mci_writel(slot->host, CLKSEL, slot->host->sdr_timing);
> >> +     }
> >> +
> >> +     if (slot->host->drv_data->ctrl_type == DW_MCI_TYPE_EXYNOS5250) {
> >> +             slot->host->bus_hz = clk_get_rate(slot->host->ciu_clk);
> >> +             slot->host->bus_hz /= SDMMC_CLKSEL_GET_DIVRATIO(
> >> +                                     mci_readl(slot->host, CLKSEL));
> >> +     }
> > As you know, CLKSEL is specific for Samsung soc.
> > 0x09C(CLKSEL)  is reserved area in Synopsys memory map.
> > In case of non-samsung-soc, we cannot ensure this usage.
> > In previous version, I have suggested separating the variant into another file.
> 
> There is a check for type of SoC before using 0x9C as CLKSEL register.
Do you mean checking DW_MCI_TYPE_EXYNOS5250?
But Above two case(ddr_timing/sdr_timing), CLKSEL can be accessed on other soc's.

> Other implementations of dw-mmc might define custom register at 0x9C
Even so, register field can be different with Samsung soc.

> but this will code will not execute on other SoC's and will not break
> anything on other implementations. Regarding spliting this Exynos
> specific code into another file, I prefer not to do it for now.
> Spliting the code means adding new definitions of callback functions
> which I am not sure is really required. The present code is fairly
> simple one.
Yes, callback functions might be needed to accommodate various implementation
of host controller. It would be better to prepare this for other variant next.

> 
> >
> >>
> >>       mci_writel(slot->host, UHS_REG, regs);
> >>
> >> @@ -2086,6 +2107,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
> >>       struct dw_mci_board *pdata;
> >>       struct device *dev = host->dev;
> >>       struct device_node *np = dev->of_node;
> >> +     u32 timing[3];
> >>       int idx, cnt;
> >>
> >>       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
> >> @@ -2108,6 +2130,20 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
> >>               if (of_get_property(np, of_quriks[idx].quirk, NULL))
> >>                       pdata->quirks |= of_quriks[idx].id;
> >>
> >> +     if (of_property_read_u32_array(dev->of_node,
> >> +                     "samsung,dw-mshc-sdr-timing", timing, 3))
> >> +             host->sdr_timing = DW_MCI_DEF_SDR_TIMING;
> > Host of non-samsung will reach here.
> > host->sdr_timing is needed for this host? host->ddr_timing is the same.
> 
> Yes, but non-samsung hosts will not have have this property into their
> dts file. So the code within the condition will not execute on
> non-samsung hosts. SDR and DDR timing are required for Exynos5 SoC.
Yes, these are required only for Exynos Soc. 
Non-samsung host will have default value here, but it seems to be meaningless.

> 
> >
> >> +     else
> >> +             host->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0],
> >> +                                     timing[1], timing[2]);
> >> +
> >> +     if (of_property_read_u32_array(dev->of_node,
> >> +                     "samsung,dw-mshc-ddr-timing", timing, 3))
> >> +             host->ddr_timing = DW_MCI_DEF_DDR_TIMING;
> >> +     else
> >> +             host->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0],
> >> +                                     timing[1], timing[2]);
> >> +
> >>       if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
> >>               dev_info(dev, "fifo-depth property not found, using "
> >>                               "value of FIFOTH register as default\n");
> >> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
> >> index 1ecaa02..6c17282 100644
> >> --- a/drivers/mmc/host/dw_mmc.h
> >> +++ b/drivers/mmc/host/dw_mmc.h
> >> @@ -53,6 +53,7 @@
> >>  #define SDMMC_IDINTEN                0x090
> >>  #define SDMMC_DSCADDR                0x094
> >>  #define SDMMC_BUFADDR                0x098
> >> +#define SDMMC_CLKSEL         0x09C /* specific to Samsung Exynos5250 */
> >>  #define SDMMC_DATA(x)                (x)
> >>
> >>  /*
> >> @@ -111,6 +112,7 @@
> >>  #define SDMMC_INT_ERROR                      0xbfc2
> >>  /* Command register defines */
> >>  #define SDMMC_CMD_START                      BIT(31)
> >> +#define SDMMC_CMD_USE_HOLD_REG               BIT(29)
> >>  #define SDMMC_CMD_CCS_EXP            BIT(23)
> >>  #define SDMMC_CMD_CEATA_RD           BIT(22)
> >>  #define SDMMC_CMD_UPD_CLK            BIT(21)
> >> @@ -142,6 +144,17 @@
> >>  /* Version ID register define */
> >>  #define SDMMC_GET_VERID(x)           ((x) & 0xFFFF)
> >>
> >> +#define DW_MCI_DEF_SDR_TIMING                0x03030002
> >> +#define DW_MCI_DEF_DDR_TIMING                0x03020001
> > What is the basis for these timing?
> > These values is board-specific.
One missed comment?

> >
> >> +#define SDMMC_CLKSEL_CCLK_SAMPLE(x)  (((x) & 3) << 0)
> >> +#define SDMMC_CLKSEL_CCLK_DRIVE(x)   (((x) & 3) << 16)
> >> +#define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 3) << 24)
> > If it's for exynos5, it will be 7 not 3.
> 
> Yes, I missed that. Thanks. I will fix this.
> 
> >
> >> +#define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) |  \
> >> +                                     SDMMC_CLKSEL_CCLK_DRIVE(y) |    \
> >> +                                     SDMMC_CLKSEL_CCLK_DIVIDER(z))
> >> +#define SDMMC_CLKSEL_GET_DIVRATIO(x) ((((x) >> 24) & 0x7) + 1)
> >> +#define SDMMC_CLKSEL_GET_SELCLK_DRV(x)       (((x) >> 16) & 0x7)
> >> +
> > Is this patch considered only for exynos5250?
> > In case of exynos4210, the number of bits is different.
> > If upper macros is backward-compatible, it would be better.
> 
> These consider the Exynos4210 and Exynos4412 implementations as well.
> The device tree documentation clearly states that the possible values
> for each of the dividers. For Exynos4 SoC's, the divider value is
> between 1 to 4 (or 0 to 3). So a bit mask of 7 is backward compatilble
> for Exynos4.
Bit width is 2 for selclk_drv in exynos4210.
So bit mask of 3 is proper.

Let me clear it about divider value.
In case of Exynos4 SoC's, divider value(DIVRATIO) is reserved and host doesn't modify.
But value is fixed internally like following.
Exynos4210 : 2
Exynos4412 : 4

Thanks,
Seungwon Jeon

> 
> Thanks for your review and comments on this patch.
> 
> Regards,
> Thomas.
> 
> >
> > Best regards,
> > Seungwon Jeon
> >
> >>  /* Register access macros */
> >>  #define mci_readl(dev, reg)                  \
> >>       __raw_readl((dev)->regs + SDMMC_##reg)
> >> @@ -184,6 +197,7 @@ extern int dw_mci_resume(struct dw_mci *host);
> >>
> >>  /* Variations in the dw_mci controller */
> >>  #define DW_MCI_TYPE_SYNOPSIS         0
> >> +#define DW_MCI_TYPE_EXYNOS5250               1 /* Samsung Exynos5250 Extensions */
> >>
> >>  /* dw_mci platform driver data */
> >>  struct dw_mci_drv_data {
> >> diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
> >> index ae45e4f..32c778f 100644
> >> --- a/include/linux/mmc/dw_mmc.h
> >> +++ b/include/linux/mmc/dw_mmc.h
> >> @@ -82,6 +82,8 @@ struct mmc_data;
> >>   * @biu_clk: Pointer to bus interface unit clock instance.
> >>   * @ciu_clk: Pointer to card interface unit clock instance.
> >>   * @slot: Slots sharing this MMC controller.
> >> + * @sdr_timing: Clock phase shifting for driving and sampling in sdr mode
> >> + * @ddr_timing: Clock phase shifting for driving and sampling in ddr mode
> >>   * @fifo_depth: depth of FIFO.
> >>   * @data_shift: log2 of FIFO item size.
> >>   * @part_buf_start: Start index in part_buf.
> >> @@ -166,6 +168,10 @@ struct dw_mci {
> >>       struct clk              *ciu_clk;
> >>       struct dw_mci_slot      *slot[MAX_MCI_SLOTS];
> >>
> >> +     /* Phase Shift Value (for exynos5250 variant) */
> >> +     u32                     sdr_timing;
> >> +     u32                     ddr_timing;
> >> +
> >>       /* FIFO push and pull */
> >>       int                     fifo_depth;
> >>       int                     data_shift;
> >> --
> >> 1.6.6.rc2
> >>
> >> --
> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> >> the body of a message to majordomo at vger.kernel.org
> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 0/6] mmc: dw_mmc: add support for device tree based instantiation
  2012-07-19 22:47       ` Kukjin Kim
@ 2012-07-23  1:57         ` Jaehoon Chung
  -1 siblings, 0 replies; 53+ messages in thread
From: Jaehoon Chung @ 2012-07-23  1:57 UTC (permalink / raw)
  To: Kukjin Kim
  Cc: 'Thomas Abraham', 'Jaehoon Chung',
	linux-mmc, devicetree-discuss, linux-kernel, linux-arm-kernel,
	cjb, grant.likely, rob.herring, linux-samsung-soc, patches

On 07/20/2012 07:47 AM, Kukjin Kim wrote:
> Thomas Abraham wrote:
>>
>> On 19 July 2012 20:58, Jaehoon Chung <jh80.chung@samsung.com> wrote:
>>> Hi Thomas,
>>>
>>> I think not good that added the samsung specific code into dw_mmc-
>> pltfm.c
>>> How about separating to dw-mmc-exynos.c?
>>
>> I am not sure of this. The only samsung specific code in
>> dw_mmc-pltfm.c file is the data for of_device_id instances. The clock
>> lookup added into this file in the 3rd patch does not cause any harm
>> on non-samsung SoC's which might not define those clocks (on clock
>> lookup failure, there are only warning printed, the driver's probe
>> does not fail.
>>
> I agree with Thomas' opinion, in addition, the dw_mmc-pltfm.c file can
> support that, so adding dw-mmc-exynos.c is not needed now.
> 
>> I would prefer not to add separate file for Exynos SoC's for now.
>> Splitting into different files will need to defined new callbacks
>> which I fell is not really required.
Then where is the callback function located?

Best Regards,
Jaehoon Chung
>>
> Yes.
> 
> Thanks.
> 
> Best regards,
> Kgene.
> --
> Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
> SW Solution Development Team, Samsung Electronics Co., Ltd.
> 
> --
> 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
> 



^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v3 0/6] mmc: dw_mmc: add support for device tree based instantiation
@ 2012-07-23  1:57         ` Jaehoon Chung
  0 siblings, 0 replies; 53+ messages in thread
From: Jaehoon Chung @ 2012-07-23  1:57 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/20/2012 07:47 AM, Kukjin Kim wrote:
> Thomas Abraham wrote:
>>
>> On 19 July 2012 20:58, Jaehoon Chung <jh80.chung@samsung.com> wrote:
>>> Hi Thomas,
>>>
>>> I think not good that added the samsung specific code into dw_mmc-
>> pltfm.c
>>> How about separating to dw-mmc-exynos.c?
>>
>> I am not sure of this. The only samsung specific code in
>> dw_mmc-pltfm.c file is the data for of_device_id instances. The clock
>> lookup added into this file in the 3rd patch does not cause any harm
>> on non-samsung SoC's which might not define those clocks (on clock
>> lookup failure, there are only warning printed, the driver's probe
>> does not fail.
>>
> I agree with Thomas' opinion, in addition, the dw_mmc-pltfm.c file can
> support that, so adding dw-mmc-exynos.c is not needed now.
> 
>> I would prefer not to add separate file for Exynos SoC's for now.
>> Splitting into different files will need to defined new callbacks
>> which I fell is not really required.
Then where is the callback function located?

Best Regards,
Jaehoon Chung
>>
> Yes.
> 
> Thanks.
> 
> Best regards,
> Kgene.
> --
> Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
> SW Solution Development Team, Samsung Electronics Co., Ltd.
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 6/6] mmc: dw_mmc: add samsung exynos5250 specific extentions
  2012-07-20 10:38         ` Seungwon Jeon
@ 2012-07-23  6:17           ` Thomas Abraham
  -1 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-23  6:17 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, devicetree-discuss, linux-kernel, linux-arm-kernel,
	cjb, grant.likely, rob.herring, linux-samsung-soc, kgene.kim,
	patches

On 20 July 2012 16:08, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> July 20, 2012, Thomas Abraham <thomas.abraham@linaro.org> wrote:
>> On 19 July 2012 09:21, Seungwon Jeon <tgih.jun@samsung.com> wrote:

[...]

>> >> +static unsigned long exynos5250_dwmmc_caps[4] = {
>> >> +     MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
>> >> +             MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
>> >> +     MMC_CAP_CMD23,
>> >> +     MMC_CAP_CMD23,
>> >> +     MMC_CAP_CMD23,
>> >> +};
>> >> +
>> > Kyungmin Park has already pointed .
>> > It's not still proper place for board specific caps.
>> > If I'm incorrect, please let me know.
>> > And why MMC_CAP_CMD23 is default caps for all channel of hosts?
>>
>> The cap listed above are specifying controller capabilities for dw-mmc
>> controllers on Exynos5 SoC. They are not board specific caps. All the
>> Exynos5 dw-mmc controllers can support MMC_CAP_CMD23 cap and hence, it
>> has been listed for all the controllers. Please let me know if you
>> feel there is any change required here.
> MMC_CAP_8_BIT_DATA could be dependent on board.

A controller can have the MMC_CAP_8_BIT_DATA capability but the board
will decide the bus-width. The bus-width is specified in the dts files
of each board (or platform data). The bus-width for data transfer is
then decided by the MMC core code based on the caps and the bus-width
information. So MMC_CAP_8_BIT_DATA can be specified irrespective   of
whether the board supports 8-bit or not.

> I agree about MMC_CAP_CMD23.
> Additionally, MMC_CAP_CMD23 is applied for dw-mmc host driver without regard to Exynos5.

The caps listed in exynos5250_dwmmc_caps is applicable only for
Exynos5 SoC's. Could you please let me know if there is anything
incorrect here.

[...]

>> >> +     if (slot->host->drv_data->ctrl_type == DW_MCI_TYPE_EXYNOS5250) {
>> >> +             slot->host->bus_hz = clk_get_rate(slot->host->ciu_clk);
>> >> +             slot->host->bus_hz /= SDMMC_CLKSEL_GET_DIVRATIO(
>> >> +                                     mci_readl(slot->host, CLKSEL));
>> >> +     }
>> > As you know, CLKSEL is specific for Samsung soc.
>> > 0x09C(CLKSEL)  is reserved area in Synopsys memory map.
>> > In case of non-samsung-soc, we cannot ensure this usage.
>> > In previous version, I have suggested separating the variant into another file.
>>
>> There is a check for type of SoC before using 0x9C as CLKSEL register.
> Do you mean checking DW_MCI_TYPE_EXYNOS5250?
> But Above two case(ddr_timing/sdr_timing), CLKSEL can be accessed on other soc's.

The tests have only been completed on Exynos5250. I do not have boards
for other Samsung SoC's which have a dw_mmc port connected and used on
the board. When we have other platforms tested with this patchset, we
can extend the 'if' check in the above code for other SoC's.

>
>> Other implementations of dw-mmc might define custom register at 0x9C
> Even so, register field can be different with Samsung soc.

Yes, with the correct checks for the type of SoC, differences in the
usage of 0x9C register can be handled.

>
>> but this will code will not execute on other SoC's and will not break
>> anything on other implementations. Regarding spliting this Exynos
>> specific code into another file, I prefer not to do it for now.
>> Spliting the code means adding new definitions of callback functions
>> which I am not sure is really required. The present code is fairly
>> simple one.
> Yes, callback functions might be needed to accommodate various implementation
> of host controller. It would be better to prepare this for other variant next.
>

Ok. I will relook at these patches and check if we really need split
these changes into a separate exynos specific file. If I again feel
that such a split is not required, I will reply back to you with
justification.

[...]

>> >> +     if (of_property_read_u32_array(dev->of_node,
>> >> +                     "samsung,dw-mshc-sdr-timing", timing, 3))
>> >> +             host->sdr_timing = DW_MCI_DEF_SDR_TIMING;
>> > Host of non-samsung will reach here.
>> > host->sdr_timing is needed for this host? host->ddr_timing is the same.
>>
>> Yes, but non-samsung hosts will not have have this property into their
>> dts file. So the code within the condition will not execute on
>> non-samsung hosts. SDR and DDR timing are required for Exynos5 SoC.
> Yes, these are required only for Exynos Soc.
> Non-samsung host will have default value here, but it seems to be meaningless.

Non-Samsung platforms will not have this property in their dts files.
This property is required on only those platforms that want to define
sdr and ddr timing values. It is not required on platforms that do no
use it.

>
>>
>> >
>> >> +     else
>> >> +             host->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0],
>> >> +                                     timing[1], timing[2]);
>> >> +
>> >> +     if (of_property_read_u32_array(dev->of_node,
>> >> +                     "samsung,dw-mshc-ddr-timing", timing, 3))
>> >> +             host->ddr_timing = DW_MCI_DEF_DDR_TIMING;
>> >> +     else
>> >> +             host->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0],
>> >> +                                     timing[1], timing[2]);
>> >> +
>> >>       if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
>> >>               dev_info(dev, "fifo-depth property not found, using "
>> >>                               "value of FIFOTH register as default\n");
>> >> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
>> >> index 1ecaa02..6c17282 100644
>> >> --- a/drivers/mmc/host/dw_mmc.h
>> >> +++ b/drivers/mmc/host/dw_mmc.h
>> >> @@ -53,6 +53,7 @@
>> >>  #define SDMMC_IDINTEN                0x090
>> >>  #define SDMMC_DSCADDR                0x094
>> >>  #define SDMMC_BUFADDR                0x098
>> >> +#define SDMMC_CLKSEL         0x09C /* specific to Samsung Exynos5250 */
>> >>  #define SDMMC_DATA(x)                (x)
>> >>
>> >>  /*
>> >> @@ -111,6 +112,7 @@
>> >>  #define SDMMC_INT_ERROR                      0xbfc2
>> >>  /* Command register defines */
>> >>  #define SDMMC_CMD_START                      BIT(31)
>> >> +#define SDMMC_CMD_USE_HOLD_REG               BIT(29)
>> >>  #define SDMMC_CMD_CCS_EXP            BIT(23)
>> >>  #define SDMMC_CMD_CEATA_RD           BIT(22)
>> >>  #define SDMMC_CMD_UPD_CLK            BIT(21)
>> >> @@ -142,6 +144,17 @@
>> >>  /* Version ID register define */
>> >>  #define SDMMC_GET_VERID(x)           ((x) & 0xFFFF)
>> >>
>> >> +#define DW_MCI_DEF_SDR_TIMING                0x03030002
>> >> +#define DW_MCI_DEF_DDR_TIMING                0x03020001
>> > What is the basis for these timing?
>> > These values is board-specific.
> One missed comment?

Yes, sorry, missed this last time. These are default values for SDR
and DDR timing in case it is not specified in dts file. It may be
better to make it mandatory to specify the SDR and DDR property in dts
files (for Exynos5250) and remove this default values. Non-samsung
platforms or platforms not using this property are unaffected by this.

>
>> >
>> >> +#define SDMMC_CLKSEL_CCLK_SAMPLE(x)  (((x) & 3) << 0)
>> >> +#define SDMMC_CLKSEL_CCLK_DRIVE(x)   (((x) & 3) << 16)
>> >> +#define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 3) << 24)
>> > If it's for exynos5, it will be 7 not 3.
>>
>> Yes, I missed that. Thanks. I will fix this.
>>
>> >
>> >> +#define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) |  \
>> >> +                                     SDMMC_CLKSEL_CCLK_DRIVE(y) |    \
>> >> +                                     SDMMC_CLKSEL_CCLK_DIVIDER(z))
>> >> +#define SDMMC_CLKSEL_GET_DIVRATIO(x) ((((x) >> 24) & 0x7) + 1)
>> >> +#define SDMMC_CLKSEL_GET_SELCLK_DRV(x)       (((x) >> 16) & 0x7)
>> >> +
>> > Is this patch considered only for exynos5250?
>> > In case of exynos4210, the number of bits is different.
>> > If upper macros is backward-compatible, it would be better.
>>
>> These consider the Exynos4210 and Exynos4412 implementations as well.
>> The device tree documentation clearly states that the possible values
>> for each of the dividers. For Exynos4 SoC's, the divider value is
>> between 1 to 4 (or 0 to 3). So a bit mask of 7 is backward compatilble
>> for Exynos4.
> Bit width is 2 for selclk_drv in exynos4210.
> So bit mask of 3 is proper.
>
> Let me clear it about divider value.
> In case of Exynos4 SoC's, divider value(DIVRATIO) is reserved and host doesn't modify.
> But value is fixed internally like following.
> Exynos4210 : 2
> Exynos4412 : 4

Ok. I will relook into this. Thanks.

Regards,
Thomas.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v3 6/6] mmc: dw_mmc: add samsung exynos5250 specific extentions
@ 2012-07-23  6:17           ` Thomas Abraham
  0 siblings, 0 replies; 53+ messages in thread
From: Thomas Abraham @ 2012-07-23  6:17 UTC (permalink / raw)
  To: linux-arm-kernel

On 20 July 2012 16:08, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> July 20, 2012, Thomas Abraham <thomas.abraham@linaro.org> wrote:
>> On 19 July 2012 09:21, Seungwon Jeon <tgih.jun@samsung.com> wrote:

[...]

>> >> +static unsigned long exynos5250_dwmmc_caps[4] = {
>> >> +     MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
>> >> +             MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
>> >> +     MMC_CAP_CMD23,
>> >> +     MMC_CAP_CMD23,
>> >> +     MMC_CAP_CMD23,
>> >> +};
>> >> +
>> > Kyungmin Park has already pointed .
>> > It's not still proper place for board specific caps.
>> > If I'm incorrect, please let me know.
>> > And why MMC_CAP_CMD23 is default caps for all channel of hosts?
>>
>> The cap listed above are specifying controller capabilities for dw-mmc
>> controllers on Exynos5 SoC. They are not board specific caps. All the
>> Exynos5 dw-mmc controllers can support MMC_CAP_CMD23 cap and hence, it
>> has been listed for all the controllers. Please let me know if you
>> feel there is any change required here.
> MMC_CAP_8_BIT_DATA could be dependent on board.

A controller can have the MMC_CAP_8_BIT_DATA capability but the board
will decide the bus-width. The bus-width is specified in the dts files
of each board (or platform data). The bus-width for data transfer is
then decided by the MMC core code based on the caps and the bus-width
information. So MMC_CAP_8_BIT_DATA can be specified irrespective   of
whether the board supports 8-bit or not.

> I agree about MMC_CAP_CMD23.
> Additionally, MMC_CAP_CMD23 is applied for dw-mmc host driver without regard to Exynos5.

The caps listed in exynos5250_dwmmc_caps is applicable only for
Exynos5 SoC's. Could you please let me know if there is anything
incorrect here.

[...]

>> >> +     if (slot->host->drv_data->ctrl_type == DW_MCI_TYPE_EXYNOS5250) {
>> >> +             slot->host->bus_hz = clk_get_rate(slot->host->ciu_clk);
>> >> +             slot->host->bus_hz /= SDMMC_CLKSEL_GET_DIVRATIO(
>> >> +                                     mci_readl(slot->host, CLKSEL));
>> >> +     }
>> > As you know, CLKSEL is specific for Samsung soc.
>> > 0x09C(CLKSEL)  is reserved area in Synopsys memory map.
>> > In case of non-samsung-soc, we cannot ensure this usage.
>> > In previous version, I have suggested separating the variant into another file.
>>
>> There is a check for type of SoC before using 0x9C as CLKSEL register.
> Do you mean checking DW_MCI_TYPE_EXYNOS5250?
> But Above two case(ddr_timing/sdr_timing), CLKSEL can be accessed on other soc's.

The tests have only been completed on Exynos5250. I do not have boards
for other Samsung SoC's which have a dw_mmc port connected and used on
the board. When we have other platforms tested with this patchset, we
can extend the 'if' check in the above code for other SoC's.

>
>> Other implementations of dw-mmc might define custom register at 0x9C
> Even so, register field can be different with Samsung soc.

Yes, with the correct checks for the type of SoC, differences in the
usage of 0x9C register can be handled.

>
>> but this will code will not execute on other SoC's and will not break
>> anything on other implementations. Regarding spliting this Exynos
>> specific code into another file, I prefer not to do it for now.
>> Spliting the code means adding new definitions of callback functions
>> which I am not sure is really required. The present code is fairly
>> simple one.
> Yes, callback functions might be needed to accommodate various implementation
> of host controller. It would be better to prepare this for other variant next.
>

Ok. I will relook at these patches and check if we really need split
these changes into a separate exynos specific file. If I again feel
that such a split is not required, I will reply back to you with
justification.

[...]

>> >> +     if (of_property_read_u32_array(dev->of_node,
>> >> +                     "samsung,dw-mshc-sdr-timing", timing, 3))
>> >> +             host->sdr_timing = DW_MCI_DEF_SDR_TIMING;
>> > Host of non-samsung will reach here.
>> > host->sdr_timing is needed for this host? host->ddr_timing is the same.
>>
>> Yes, but non-samsung hosts will not have have this property into their
>> dts file. So the code within the condition will not execute on
>> non-samsung hosts. SDR and DDR timing are required for Exynos5 SoC.
> Yes, these are required only for Exynos Soc.
> Non-samsung host will have default value here, but it seems to be meaningless.

Non-Samsung platforms will not have this property in their dts files.
This property is required on only those platforms that want to define
sdr and ddr timing values. It is not required on platforms that do no
use it.

>
>>
>> >
>> >> +     else
>> >> +             host->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0],
>> >> +                                     timing[1], timing[2]);
>> >> +
>> >> +     if (of_property_read_u32_array(dev->of_node,
>> >> +                     "samsung,dw-mshc-ddr-timing", timing, 3))
>> >> +             host->ddr_timing = DW_MCI_DEF_DDR_TIMING;
>> >> +     else
>> >> +             host->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0],
>> >> +                                     timing[1], timing[2]);
>> >> +
>> >>       if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
>> >>               dev_info(dev, "fifo-depth property not found, using "
>> >>                               "value of FIFOTH register as default\n");
>> >> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
>> >> index 1ecaa02..6c17282 100644
>> >> --- a/drivers/mmc/host/dw_mmc.h
>> >> +++ b/drivers/mmc/host/dw_mmc.h
>> >> @@ -53,6 +53,7 @@
>> >>  #define SDMMC_IDINTEN                0x090
>> >>  #define SDMMC_DSCADDR                0x094
>> >>  #define SDMMC_BUFADDR                0x098
>> >> +#define SDMMC_CLKSEL         0x09C /* specific to Samsung Exynos5250 */
>> >>  #define SDMMC_DATA(x)                (x)
>> >>
>> >>  /*
>> >> @@ -111,6 +112,7 @@
>> >>  #define SDMMC_INT_ERROR                      0xbfc2
>> >>  /* Command register defines */
>> >>  #define SDMMC_CMD_START                      BIT(31)
>> >> +#define SDMMC_CMD_USE_HOLD_REG               BIT(29)
>> >>  #define SDMMC_CMD_CCS_EXP            BIT(23)
>> >>  #define SDMMC_CMD_CEATA_RD           BIT(22)
>> >>  #define SDMMC_CMD_UPD_CLK            BIT(21)
>> >> @@ -142,6 +144,17 @@
>> >>  /* Version ID register define */
>> >>  #define SDMMC_GET_VERID(x)           ((x) & 0xFFFF)
>> >>
>> >> +#define DW_MCI_DEF_SDR_TIMING                0x03030002
>> >> +#define DW_MCI_DEF_DDR_TIMING                0x03020001
>> > What is the basis for these timing?
>> > These values is board-specific.
> One missed comment?

Yes, sorry, missed this last time. These are default values for SDR
and DDR timing in case it is not specified in dts file. It may be
better to make it mandatory to specify the SDR and DDR property in dts
files (for Exynos5250) and remove this default values. Non-samsung
platforms or platforms not using this property are unaffected by this.

>
>> >
>> >> +#define SDMMC_CLKSEL_CCLK_SAMPLE(x)  (((x) & 3) << 0)
>> >> +#define SDMMC_CLKSEL_CCLK_DRIVE(x)   (((x) & 3) << 16)
>> >> +#define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 3) << 24)
>> > If it's for exynos5, it will be 7 not 3.
>>
>> Yes, I missed that. Thanks. I will fix this.
>>
>> >
>> >> +#define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) |  \
>> >> +                                     SDMMC_CLKSEL_CCLK_DRIVE(y) |    \
>> >> +                                     SDMMC_CLKSEL_CCLK_DIVIDER(z))
>> >> +#define SDMMC_CLKSEL_GET_DIVRATIO(x) ((((x) >> 24) & 0x7) + 1)
>> >> +#define SDMMC_CLKSEL_GET_SELCLK_DRV(x)       (((x) >> 16) & 0x7)
>> >> +
>> > Is this patch considered only for exynos5250?
>> > In case of exynos4210, the number of bits is different.
>> > If upper macros is backward-compatible, it would be better.
>>
>> These consider the Exynos4210 and Exynos4412 implementations as well.
>> The device tree documentation clearly states that the possible values
>> for each of the dividers. For Exynos4 SoC's, the divider value is
>> between 1 to 4 (or 0 to 3). So a bit mask of 7 is backward compatilble
>> for Exynos4.
> Bit width is 2 for selclk_drv in exynos4210.
> So bit mask of 3 is proper.
>
> Let me clear it about divider value.
> In case of Exynos4 SoC's, divider value(DIVRATIO) is reserved and host doesn't modify.
> But value is fixed internally like following.
> Exynos4210 : 2
> Exynos4412 : 4

Ok. I will relook into this. Thanks.

Regards,
Thomas.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* RE: [PATCH v3 6/6] mmc: dw_mmc: add samsung exynos5250 specific extentions
  2012-07-23  6:17           ` Thomas Abraham
@ 2012-07-23  9:59             ` Seungwon Jeon
  -1 siblings, 0 replies; 53+ messages in thread
From: Seungwon Jeon @ 2012-07-23  9:59 UTC (permalink / raw)
  To: 'Thomas Abraham'
  Cc: linux-mmc, devicetree-discuss, linux-kernel, linux-arm-kernel,
	cjb, grant.likely, rob.herring, linux-samsung-soc, kgene.kim,
	patches

July 23, 2012, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> On 20 July 2012 16:08, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > July 20, 2012, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> >> On 19 July 2012 09:21, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> 
> [...]
> 
> >> >> +static unsigned long exynos5250_dwmmc_caps[4] = {
> >> >> +     MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
> >> >> +             MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
> >> >> +     MMC_CAP_CMD23,
> >> >> +     MMC_CAP_CMD23,
> >> >> +     MMC_CAP_CMD23,
> >> >> +};
> >> >> +
> >> > Kyungmin Park has already pointed .
> >> > It's not still proper place for board specific caps.
> >> > If I'm incorrect, please let me know.
> >> > And why MMC_CAP_CMD23 is default caps for all channel of hosts?
> >>
> >> The cap listed above are specifying controller capabilities for dw-mmc
> >> controllers on Exynos5 SoC. They are not board specific caps. All the
> >> Exynos5 dw-mmc controllers can support MMC_CAP_CMD23 cap and hence, it
> >> has been listed for all the controllers. Please let me know if you
> >> feel there is any change required here.
> > MMC_CAP_8_BIT_DATA could be dependent on board.
> 
> A controller can have the MMC_CAP_8_BIT_DATA capability but the board
> will decide the bus-width. The bus-width is specified in the dts files
> of each board (or platform data). The bus-width for data transfer is
> then decided by the MMC core code based on the caps and the bus-width
> information. So MMC_CAP_8_BIT_DATA can be specified irrespective   of
> whether the board supports 8-bit or not.
> 
> > I agree about MMC_CAP_CMD23.
> > Additionally, MMC_CAP_CMD23 is applied for dw-mmc host driver without regard to Exynos5.
> 
> The caps listed in exynos5250_dwmmc_caps is applicable only for
> Exynos5 SoC's. Could you please let me know if there is anything
> incorrect here.
I mean that MMC_CAP_CMD23 is a capability which is implemented in driver without dependency of SOC.
So, other soc also includes MMC_CAP_CMD23.
It'd rather make a default caps than list in specific soc, considering the other soc.

> 
> [...]
> 
> >> >> +     if (slot->host->drv_data->ctrl_type == DW_MCI_TYPE_EXYNOS5250) {
> >> >> +             slot->host->bus_hz = clk_get_rate(slot->host->ciu_clk);
> >> >> +             slot->host->bus_hz /= SDMMC_CLKSEL_GET_DIVRATIO(
> >> >> +                                     mci_readl(slot->host, CLKSEL));
> >> >> +     }
> >> > As you know, CLKSEL is specific for Samsung soc.
> >> > 0x09C(CLKSEL)  is reserved area in Synopsys memory map.
> >> > In case of non-samsung-soc, we cannot ensure this usage.
> >> > In previous version, I have suggested separating the variant into another file.
> >>
> >> There is a check for type of SoC before using 0x9C as CLKSEL register.
> > Do you mean checking DW_MCI_TYPE_EXYNOS5250?
> > But Above two case(ddr_timing/sdr_timing), CLKSEL can be accessed on other soc's.
> 
> The tests have only been completed on Exynos5250. I do not have boards
> for other Samsung SoC's which have a dw_mmc port connected and used on
> the board. When we have other platforms tested with this patchset, we
> can extend the 'if' check in the above code for other SoC's.
My meaning  seem to be passed incorrectly.

+       if (ios->timing == MMC_TIMING_UHS_DDR50) {
                regs |= (0x1 << slot->id) << 16;
-       else
+               mci_writel(slot->host, CLKSEL, slot->host->ddr_timing);
What is the execution for non-samsung soc?
CLKSEL register is valid  only for Exynos.
dw_mci_set_ios shoud be aware of this.

+       } else {
                regs &= ~(0x1 << slot->id) << 16;
+               mci_writel(slot->host, CLKSEL, slot->host->sdr_timing);
This line is same.
+       }
+

> 
> >
> >> Other implementations of dw-mmc might define custom register at 0x9C
> > Even so, register field can be different with Samsung soc.
> 
> Yes, with the correct checks for the type of SoC, differences in the
> usage of 0x9C register can be handled.
> 
> >
> >> but this will code will not execute on other SoC's and will not break
> >> anything on other implementations. Regarding spliting this Exynos
> >> specific code into another file, I prefer not to do it for now.
> >> Spliting the code means adding new definitions of callback functions
> >> which I am not sure is really required. The present code is fairly
> >> simple one.
> > Yes, callback functions might be needed to accommodate various implementation
> > of host controller. It would be better to prepare this for other variant next.
> >
> 
> Ok. I will relook at these patches and check if we really need split
> these changes into a separate exynos specific file. If I again feel
> that such a split is not required, I will reply back to you with
> justification.
> 
> [...]
> 
> >> >> +     if (of_property_read_u32_array(dev->of_node,
> >> >> +                     "samsung,dw-mshc-sdr-timing", timing, 3))
> >> >> +             host->sdr_timing = DW_MCI_DEF_SDR_TIMING;
> >> > Host of non-samsung will reach here.
> >> > host->sdr_timing is needed for this host? host->ddr_timing is the same.
> >>
> >> Yes, but non-samsung hosts will not have have this property into their
> >> dts file. So the code within the condition will not execute on
> >> non-samsung hosts. SDR and DDR timing are required for Exynos5 SoC.
> > Yes, these are required only for Exynos Soc.
> > Non-samsung host will have default value here, but it seems to be meaningless.
> 
> Non-Samsung platforms will not have this property in their dts files.
> This property is required on only those platforms that want to define
> sdr and ddr timing values. It is not required on platforms that do no
> use it.
> 
> >
> >>
> >> >
> >> >> +     else
> >> >> +             host->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0],
> >> >> +                                     timing[1], timing[2]);
> >> >> +
> >> >> +     if (of_property_read_u32_array(dev->of_node,
> >> >> +                     "samsung,dw-mshc-ddr-timing", timing, 3))
> >> >> +             host->ddr_timing = DW_MCI_DEF_DDR_TIMING;
> >> >> +     else
> >> >> +             host->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0],
> >> >> +                                     timing[1], timing[2]);
> >> >> +
> >> >>       if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
> >> >>               dev_info(dev, "fifo-depth property not found, using "
> >> >>                               "value of FIFOTH register as default\n");
> >> >> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
> >> >> index 1ecaa02..6c17282 100644
> >> >> --- a/drivers/mmc/host/dw_mmc.h
> >> >> +++ b/drivers/mmc/host/dw_mmc.h
> >> >> @@ -53,6 +53,7 @@
> >> >>  #define SDMMC_IDINTEN                0x090
> >> >>  #define SDMMC_DSCADDR                0x094
> >> >>  #define SDMMC_BUFADDR                0x098
> >> >> +#define SDMMC_CLKSEL         0x09C /* specific to Samsung Exynos5250 */
> >> >>  #define SDMMC_DATA(x)                (x)
> >> >>
> >> >>  /*
> >> >> @@ -111,6 +112,7 @@
> >> >>  #define SDMMC_INT_ERROR                      0xbfc2
> >> >>  /* Command register defines */
> >> >>  #define SDMMC_CMD_START                      BIT(31)
> >> >> +#define SDMMC_CMD_USE_HOLD_REG               BIT(29)
> >> >>  #define SDMMC_CMD_CCS_EXP            BIT(23)
> >> >>  #define SDMMC_CMD_CEATA_RD           BIT(22)
> >> >>  #define SDMMC_CMD_UPD_CLK            BIT(21)
> >> >> @@ -142,6 +144,17 @@
> >> >>  /* Version ID register define */
> >> >>  #define SDMMC_GET_VERID(x)           ((x) & 0xFFFF)
> >> >>
> >> >> +#define DW_MCI_DEF_SDR_TIMING                0x03030002
> >> >> +#define DW_MCI_DEF_DDR_TIMING                0x03020001
> >> > What is the basis for these timing?
> >> > These values is board-specific.
> > One missed comment?
> 
> Yes, sorry, missed this last time. These are default values for SDR
> and DDR timing in case it is not specified in dts file. It may be
> better to make it mandatory to specify the SDR and DDR property in dts
> files (for Exynos5250) and remove this default values. Non-samsung
> platforms or platforms not using this property are unaffected by this.
These value(0x03030002, 0x03020001) cannot be acceptable in specific board type of Exynos5250.
Assuming that timing values are not specified in dts file and board is different,
default values may be not proper. As you mentioned, other approach will be needed.

Thanks,
Seungwon Jeon
> 
> >
> >> >
> >> >> +#define SDMMC_CLKSEL_CCLK_SAMPLE(x)  (((x) & 3) << 0)
> >> >> +#define SDMMC_CLKSEL_CCLK_DRIVE(x)   (((x) & 3) << 16)
> >> >> +#define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 3) << 24)
> >> > If it's for exynos5, it will be 7 not 3.
> >>
> >> Yes, I missed that. Thanks. I will fix this.
> >>
> >> >
> >> >> +#define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) |  \
> >> >> +                                     SDMMC_CLKSEL_CCLK_DRIVE(y) |    \
> >> >> +                                     SDMMC_CLKSEL_CCLK_DIVIDER(z))
> >> >> +#define SDMMC_CLKSEL_GET_DIVRATIO(x) ((((x) >> 24) & 0x7) + 1)
> >> >> +#define SDMMC_CLKSEL_GET_SELCLK_DRV(x)       (((x) >> 16) & 0x7)
> >> >> +
> >> > Is this patch considered only for exynos5250?
> >> > In case of exynos4210, the number of bits is different.
> >> > If upper macros is backward-compatible, it would be better.
> >>
> >> These consider the Exynos4210 and Exynos4412 implementations as well.
> >> The device tree documentation clearly states that the possible values
> >> for each of the dividers. For Exynos4 SoC's, the divider value is
> >> between 1 to 4 (or 0 to 3). So a bit mask of 7 is backward compatilble
> >> for Exynos4.
> > Bit width is 2 for selclk_drv in exynos4210.
> > So bit mask of 3 is proper.
> >
> > Let me clear it about divider value.
> > In case of Exynos4 SoC's, divider value(DIVRATIO) is reserved and host doesn't modify.
> > But value is fixed internally like following.
> > Exynos4210 : 2
> > Exynos4412 : 4
> 
> Ok. I will relook into this. Thanks.
> 
> Regards,
> Thomas.
> --
> 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


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v3 6/6] mmc: dw_mmc: add samsung exynos5250 specific extentions
@ 2012-07-23  9:59             ` Seungwon Jeon
  0 siblings, 0 replies; 53+ messages in thread
From: Seungwon Jeon @ 2012-07-23  9:59 UTC (permalink / raw)
  To: linux-arm-kernel

July 23, 2012, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> On 20 July 2012 16:08, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > July 20, 2012, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> >> On 19 July 2012 09:21, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> 
> [...]
> 
> >> >> +static unsigned long exynos5250_dwmmc_caps[4] = {
> >> >> +     MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
> >> >> +             MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
> >> >> +     MMC_CAP_CMD23,
> >> >> +     MMC_CAP_CMD23,
> >> >> +     MMC_CAP_CMD23,
> >> >> +};
> >> >> +
> >> > Kyungmin Park has already pointed .
> >> > It's not still proper place for board specific caps.
> >> > If I'm incorrect, please let me know.
> >> > And why MMC_CAP_CMD23 is default caps for all channel of hosts?
> >>
> >> The cap listed above are specifying controller capabilities for dw-mmc
> >> controllers on Exynos5 SoC. They are not board specific caps. All the
> >> Exynos5 dw-mmc controllers can support MMC_CAP_CMD23 cap and hence, it
> >> has been listed for all the controllers. Please let me know if you
> >> feel there is any change required here.
> > MMC_CAP_8_BIT_DATA could be dependent on board.
> 
> A controller can have the MMC_CAP_8_BIT_DATA capability but the board
> will decide the bus-width. The bus-width is specified in the dts files
> of each board (or platform data). The bus-width for data transfer is
> then decided by the MMC core code based on the caps and the bus-width
> information. So MMC_CAP_8_BIT_DATA can be specified irrespective   of
> whether the board supports 8-bit or not.
> 
> > I agree about MMC_CAP_CMD23.
> > Additionally, MMC_CAP_CMD23 is applied for dw-mmc host driver without regard to Exynos5.
> 
> The caps listed in exynos5250_dwmmc_caps is applicable only for
> Exynos5 SoC's. Could you please let me know if there is anything
> incorrect here.
I mean that MMC_CAP_CMD23 is a capability which is implemented in driver without dependency of SOC.
So, other soc also includes MMC_CAP_CMD23.
It'd rather make a default caps than list in specific soc, considering the other soc.

> 
> [...]
> 
> >> >> +     if (slot->host->drv_data->ctrl_type == DW_MCI_TYPE_EXYNOS5250) {
> >> >> +             slot->host->bus_hz = clk_get_rate(slot->host->ciu_clk);
> >> >> +             slot->host->bus_hz /= SDMMC_CLKSEL_GET_DIVRATIO(
> >> >> +                                     mci_readl(slot->host, CLKSEL));
> >> >> +     }
> >> > As you know, CLKSEL is specific for Samsung soc.
> >> > 0x09C(CLKSEL)  is reserved area in Synopsys memory map.
> >> > In case of non-samsung-soc, we cannot ensure this usage.
> >> > In previous version, I have suggested separating the variant into another file.
> >>
> >> There is a check for type of SoC before using 0x9C as CLKSEL register.
> > Do you mean checking DW_MCI_TYPE_EXYNOS5250?
> > But Above two case(ddr_timing/sdr_timing), CLKSEL can be accessed on other soc's.
> 
> The tests have only been completed on Exynos5250. I do not have boards
> for other Samsung SoC's which have a dw_mmc port connected and used on
> the board. When we have other platforms tested with this patchset, we
> can extend the 'if' check in the above code for other SoC's.
My meaning  seem to be passed incorrectly.

+       if (ios->timing == MMC_TIMING_UHS_DDR50) {
                regs |= (0x1 << slot->id) << 16;
-       else
+               mci_writel(slot->host, CLKSEL, slot->host->ddr_timing);
What is the execution for non-samsung soc?
CLKSEL register is valid  only for Exynos.
dw_mci_set_ios shoud be aware of this.

+       } else {
                regs &= ~(0x1 << slot->id) << 16;
+               mci_writel(slot->host, CLKSEL, slot->host->sdr_timing);
This line is same.
+       }
+

> 
> >
> >> Other implementations of dw-mmc might define custom register at 0x9C
> > Even so, register field can be different with Samsung soc.
> 
> Yes, with the correct checks for the type of SoC, differences in the
> usage of 0x9C register can be handled.
> 
> >
> >> but this will code will not execute on other SoC's and will not break
> >> anything on other implementations. Regarding spliting this Exynos
> >> specific code into another file, I prefer not to do it for now.
> >> Spliting the code means adding new definitions of callback functions
> >> which I am not sure is really required. The present code is fairly
> >> simple one.
> > Yes, callback functions might be needed to accommodate various implementation
> > of host controller. It would be better to prepare this for other variant next.
> >
> 
> Ok. I will relook at these patches and check if we really need split
> these changes into a separate exynos specific file. If I again feel
> that such a split is not required, I will reply back to you with
> justification.
> 
> [...]
> 
> >> >> +     if (of_property_read_u32_array(dev->of_node,
> >> >> +                     "samsung,dw-mshc-sdr-timing", timing, 3))
> >> >> +             host->sdr_timing = DW_MCI_DEF_SDR_TIMING;
> >> > Host of non-samsung will reach here.
> >> > host->sdr_timing is needed for this host? host->ddr_timing is the same.
> >>
> >> Yes, but non-samsung hosts will not have have this property into their
> >> dts file. So the code within the condition will not execute on
> >> non-samsung hosts. SDR and DDR timing are required for Exynos5 SoC.
> > Yes, these are required only for Exynos Soc.
> > Non-samsung host will have default value here, but it seems to be meaningless.
> 
> Non-Samsung platforms will not have this property in their dts files.
> This property is required on only those platforms that want to define
> sdr and ddr timing values. It is not required on platforms that do no
> use it.
> 
> >
> >>
> >> >
> >> >> +     else
> >> >> +             host->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0],
> >> >> +                                     timing[1], timing[2]);
> >> >> +
> >> >> +     if (of_property_read_u32_array(dev->of_node,
> >> >> +                     "samsung,dw-mshc-ddr-timing", timing, 3))
> >> >> +             host->ddr_timing = DW_MCI_DEF_DDR_TIMING;
> >> >> +     else
> >> >> +             host->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0],
> >> >> +                                     timing[1], timing[2]);
> >> >> +
> >> >>       if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
> >> >>               dev_info(dev, "fifo-depth property not found, using "
> >> >>                               "value of FIFOTH register as default\n");
> >> >> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
> >> >> index 1ecaa02..6c17282 100644
> >> >> --- a/drivers/mmc/host/dw_mmc.h
> >> >> +++ b/drivers/mmc/host/dw_mmc.h
> >> >> @@ -53,6 +53,7 @@
> >> >>  #define SDMMC_IDINTEN                0x090
> >> >>  #define SDMMC_DSCADDR                0x094
> >> >>  #define SDMMC_BUFADDR                0x098
> >> >> +#define SDMMC_CLKSEL         0x09C /* specific to Samsung Exynos5250 */
> >> >>  #define SDMMC_DATA(x)                (x)
> >> >>
> >> >>  /*
> >> >> @@ -111,6 +112,7 @@
> >> >>  #define SDMMC_INT_ERROR                      0xbfc2
> >> >>  /* Command register defines */
> >> >>  #define SDMMC_CMD_START                      BIT(31)
> >> >> +#define SDMMC_CMD_USE_HOLD_REG               BIT(29)
> >> >>  #define SDMMC_CMD_CCS_EXP            BIT(23)
> >> >>  #define SDMMC_CMD_CEATA_RD           BIT(22)
> >> >>  #define SDMMC_CMD_UPD_CLK            BIT(21)
> >> >> @@ -142,6 +144,17 @@
> >> >>  /* Version ID register define */
> >> >>  #define SDMMC_GET_VERID(x)           ((x) & 0xFFFF)
> >> >>
> >> >> +#define DW_MCI_DEF_SDR_TIMING                0x03030002
> >> >> +#define DW_MCI_DEF_DDR_TIMING                0x03020001
> >> > What is the basis for these timing?
> >> > These values is board-specific.
> > One missed comment?
> 
> Yes, sorry, missed this last time. These are default values for SDR
> and DDR timing in case it is not specified in dts file. It may be
> better to make it mandatory to specify the SDR and DDR property in dts
> files (for Exynos5250) and remove this default values. Non-samsung
> platforms or platforms not using this property are unaffected by this.
These value(0x03030002, 0x03020001) cannot be acceptable in specific board type of Exynos5250.
Assuming that timing values are not specified in dts file and board is different,
default values may be not proper. As you mentioned, other approach will be needed.

Thanks,
Seungwon Jeon
> 
> >
> >> >
> >> >> +#define SDMMC_CLKSEL_CCLK_SAMPLE(x)  (((x) & 3) << 0)
> >> >> +#define SDMMC_CLKSEL_CCLK_DRIVE(x)   (((x) & 3) << 16)
> >> >> +#define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 3) << 24)
> >> > If it's for exynos5, it will be 7 not 3.
> >>
> >> Yes, I missed that. Thanks. I will fix this.
> >>
> >> >
> >> >> +#define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) |  \
> >> >> +                                     SDMMC_CLKSEL_CCLK_DRIVE(y) |    \
> >> >> +                                     SDMMC_CLKSEL_CCLK_DIVIDER(z))
> >> >> +#define SDMMC_CLKSEL_GET_DIVRATIO(x) ((((x) >> 24) & 0x7) + 1)
> >> >> +#define SDMMC_CLKSEL_GET_SELCLK_DRV(x)       (((x) >> 16) & 0x7)
> >> >> +
> >> > Is this patch considered only for exynos5250?
> >> > In case of exynos4210, the number of bits is different.
> >> > If upper macros is backward-compatible, it would be better.
> >>
> >> These consider the Exynos4210 and Exynos4412 implementations as well.
> >> The device tree documentation clearly states that the possible values
> >> for each of the dividers. For Exynos4 SoC's, the divider value is
> >> between 1 to 4 (or 0 to 3). So a bit mask of 7 is backward compatilble
> >> for Exynos4.
> > Bit width is 2 for selclk_drv in exynos4210.
> > So bit mask of 3 is proper.
> >
> > Let me clear it about divider value.
> > In case of Exynos4 SoC's, divider value(DIVRATIO) is reserved and host doesn't modify.
> > But value is fixed internally like following.
> > Exynos4210 : 2
> > Exynos4412 : 4
> 
> Ok. I will relook into this. Thanks.
> 
> Regards,
> Thomas.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 53+ messages in thread

end of thread, other threads:[~2012-07-23 10:00 UTC | newest]

Thread overview: 53+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-07-12 12:54 [PATCH v3 0/6] mmc: dw_mmc: add support for device tree based instantiation Thomas Abraham
2012-07-12 12:54 ` Thomas Abraham
2012-07-12 12:54 ` [PATCH v3 1/6] mmc: dw_mmc: convert copy of struct device in struct dw_mci to a reference Thomas Abraham
2012-07-12 12:54   ` Thomas Abraham
2012-07-12 12:54 ` [PATCH v3 2/6] mmc: dw_mmc: allow probe to succeed even if one slot is initialized Thomas Abraham
2012-07-12 12:54   ` Thomas Abraham
2012-07-12 12:54   ` Thomas Abraham
2012-07-12 12:54 ` [PATCH v3 3/6] mmc: dw_mmc: lookup for optional biu and ciu clocks Thomas Abraham
2012-07-12 12:54   ` Thomas Abraham
2012-07-12 12:54   ` Thomas Abraham
2012-07-13  9:11   ` Girish K S
2012-07-13  9:11     ` Girish K S
2012-07-17 10:38     ` [PATCH 3/9] " Thomas Abraham
2012-07-17 10:38       ` Thomas Abraham
2012-07-19 10:27       ` Seungwon Jeon
2012-07-19 10:27         ` Seungwon Jeon
2012-07-12 12:54 ` [PATCH v3 4/6] mmc: dw_mmc: add quirk to indicate missing write protect line Thomas Abraham
2012-07-12 12:54   ` Thomas Abraham
2012-07-12 12:54 ` [PATCH v3 5/6] mmc: dw_mmc: add device tree support Thomas Abraham
2012-07-12 12:54   ` Thomas Abraham
2012-07-16  4:15   ` Girish K S
2012-07-16  4:15     ` Girish K S
2012-07-16  4:30     ` Girish K S
2012-07-16  4:30       ` Girish K S
2012-07-17 10:19     ` Thomas Abraham
2012-07-17 10:19       ` Thomas Abraham
2012-07-16  4:23   ` Chris Ball
2012-07-16  4:23     ` Chris Ball
2012-07-17 10:21     ` Thomas Abraham
2012-07-17 10:21       ` Thomas Abraham
2012-07-17 10:21       ` Thomas Abraham
2012-07-17 10:37       ` [PATCH 5/9] " Thomas Abraham
2012-07-17 10:37         ` Thomas Abraham
2012-07-12 12:54 ` [PATCH v3 6/6] mmc: dw_mmc: add samsung exynos5250 specific extentions Thomas Abraham
2012-07-12 12:54   ` Thomas Abraham
2012-07-19  3:51   ` Seungwon Jeon
2012-07-19  3:51     ` Seungwon Jeon
2012-07-19 18:48     ` Thomas Abraham
2012-07-19 18:48       ` Thomas Abraham
2012-07-20 10:38       ` Seungwon Jeon
2012-07-20 10:38         ` Seungwon Jeon
2012-07-23  6:17         ` Thomas Abraham
2012-07-23  6:17           ` Thomas Abraham
2012-07-23  9:59           ` Seungwon Jeon
2012-07-23  9:59             ` Seungwon Jeon
2012-07-19 15:28 ` [PATCH v3 0/6] mmc: dw_mmc: add support for device tree based instantiation Jaehoon Chung
2012-07-19 15:28   ` Jaehoon Chung
2012-07-19 18:59   ` Thomas Abraham
2012-07-19 18:59     ` Thomas Abraham
2012-07-19 22:47     ` Kukjin Kim
2012-07-19 22:47       ` Kukjin Kim
2012-07-23  1:57       ` Jaehoon Chung
2012-07-23  1:57         ` Jaehoon Chung

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.