[coreboot-gerrit] Change in coreboot[master]: drivers/storage: Split out ADMA support

Lee Leahy (Code Review) gerrit at coreboot.org
Mon Mar 27 21:40:02 CEST 2017


Lee Leahy has uploaded a new change for review. ( https://review.coreboot.org/19015 )

Change subject: drivers/storage: Split out ADMA support
......................................................................

drivers/storage: Split out ADMA support

On x86 sysems DMA is only supported to RAM, early stages must do
programed I/O to send/receive data from the SD/MMC device.  Use Kconfig
values to enable DMA during early boot stages.

TEST=Build and run on reef

Change-Id: I70aad97c74aa8a72e50627740d96fecb7485dde4
Signed-off-by: Lee Leahy <Leroy.P.Leahy at intel.com>
---
M src/drivers/storage/Kconfig
M src/drivers/storage/Makefile.inc
M src/drivers/storage/sdhci.c
A src/drivers/storage/sdhci_adma.c
M src/include/device/sdhci.h
5 files changed, 239 insertions(+), 178 deletions(-)


  git pull ssh://review.coreboot.org:29418/coreboot refs/changes/15/19015/1

diff --git a/src/drivers/storage/Kconfig b/src/drivers/storage/Kconfig
index 5774843..03e8bce 100644
--- a/src/drivers/storage/Kconfig
+++ b/src/drivers/storage/Kconfig
@@ -31,6 +31,24 @@
 	help
 	  Display MMC commands and responses
 
+config SDHCI_ADMA_IN_BOOTBLOCK
+	bool
+	default n
+	help
+	  Determine if bootblock is able to use ADMA2 or ADMA64
+
+config SDHCI_ADMA_IN_ROMSTAGE
+	bool
+	default n
+	help
+	  Determine if romstage is able to use ADMA2 or ADMA64
+
+config SDHCI_ADMA_IN_VERSTAGE
+	bool
+	default n
+	help
+	  Determine if verstage is able to use ADMA2 or ADMA64
+
 config SDHCI_DEBUG
 	bool "Debug SD/MMC host controller"
 	default n
diff --git a/src/drivers/storage/Makefile.inc b/src/drivers/storage/Makefile.inc
index 460d4f8..47dfb4f 100644
--- a/src/drivers/storage/Makefile.inc
+++ b/src/drivers/storage/Makefile.inc
@@ -26,13 +26,11 @@
 romstage-y += mmc.c
 romstage-y += pci_sdhci.c
 romstage-y += sdhci.c
-
-postcar-y += mmc.c
-postcar-y += pci_sdhci.c
-postcar-y += sdhci.c
+romstage-$(CONFIG_SDHCI_ADMA_IN_ROMSTAGE) += sdhci_adma.c
 
 ramstage-y += mmc.c
 ramstage-y += pci_sdhci.c
 ramstage-y += sdhci.c
+ramstage-y += sdhci_adma.c
 
 endif # CONFIG_DRIVERS_STORAGE
diff --git a/src/drivers/storage/sdhci.c b/src/drivers/storage/sdhci.c
index f4fe256..cccae17 100644
--- a/src/drivers/storage/sdhci.c
+++ b/src/drivers/storage/sdhci.c
@@ -30,7 +30,12 @@
 #include <string.h>
 #include <timer.h>
 
-static void sdhci_reset(SdhciHost *host, u8 mask)
+#define DMA_AVAILABLE	((CONFIG_SDHCI_ADMA_IN_BOOTBLOCK && ENV_BOOTBLOCK) \
+			|| (CONFIG_SDHCI_ADMA_IN_VERSTAGE && ENV_VERSTAGE) \
+			|| (CONFIG_SDHCI_ADMA_IN_ROMSTAGE && ENV_ROMSTAGE) \
+			|| ENV_POSTCAR || ENV_RAMSTAGE)
+
+void sdhci_reset(SdhciHost *host, u8 mask)
 {
 	unsigned long timeout;
         struct mono_time current, end;
@@ -54,7 +59,7 @@
 	}
 }
 
-static void sdhci_cmd_done(SdhciHost *host, MmcCommand *cmd)
+void sdhci_cmd_done(SdhciHost *host, MmcCommand *cmd)
 {
 	int i;
 	if (cmd->resp_type & MMC_RSP_136) {
@@ -115,165 +120,6 @@
 		}
 	} while (!(stat & SDHCI_INT_DATA_END));
 	return 0;
-}
-
-static void sdhci_alloc_adma_descs(SdhciHost *host, u32 need_descriptors)
-{
-	if (host->adma_descs) {
-		if (host->adma_desc_count < need_descriptors) {
-			/* Previously allocated array is too small */
-			free(host->adma_descs);
-			host->adma_desc_count = 0;
-			host->adma_descs = NULL;
-		}
-	}
-
-	/* use dma_malloc() to make sure we get the coherent/uncached memory */
-	if (!host->adma_descs) {
-		host->adma_descs = malloc(need_descriptors *
-					      sizeof(*host->adma_descs));
-		if (host->adma_descs == NULL)
-			die("fail to malloc adma_descs\n");
-		host->adma_desc_count = need_descriptors;
-	}
-
-	memset(host->adma_descs, 0, sizeof(*host->adma_descs) *
-	       need_descriptors);
-}
-
-static void sdhci_alloc_adma64_descs(SdhciHost *host, u32 need_descriptors)
-{
-	if (host->adma64_descs) {
-		if (host->adma_desc_count < need_descriptors) {
-			/* Previously allocated array is too small */
-			free(host->adma64_descs);
-			host->adma_desc_count = 0;
-			host->adma64_descs = NULL;
-		}
-	}
-
-	/* use dma_malloc() to make sure we get the coherent/uncached memory */
-	if (!host->adma64_descs) {
-		host->adma64_descs = malloc(need_descriptors *
-					   sizeof(*host->adma64_descs));
-		if (host->adma64_descs == NULL)
-			die("fail to malloc adma64_descs\n");
-
-		host->adma_desc_count = need_descriptors;
-	}
-
-	memset(host->adma64_descs, 0, sizeof(*host->adma64_descs) *
-	       need_descriptors);
-}
-
-static int sdhci_setup_adma(SdhciHost *host, MmcData *data)
-{
-	int i, togo, need_descriptors;
-	char *buffer_data;
-	u16 attributes;
-
-	togo = data->blocks * data->blocksize;
-	if (!togo) {
-		printf("%s: MmcData corrupted: %d blocks of %d bytes\n",
-		       __func__, data->blocks, data->blocksize);
-		return -1;
-	}
-
-	need_descriptors = 1 +  togo / SDHCI_MAX_PER_DESCRIPTOR;
-
-	if (host->dma64)
-		sdhci_alloc_adma64_descs(host, need_descriptors);
-	else
-		sdhci_alloc_adma_descs(host, need_descriptors);
-	buffer_data = data->dest;
-
-	/* Now set up the descriptor chain. */
-	for (i = 0; togo; i++) {
-		unsigned int desc_length;
-
-		if (togo < SDHCI_MAX_PER_DESCRIPTOR)
-			desc_length = togo;
-		else
-			desc_length = SDHCI_MAX_PER_DESCRIPTOR;
-		togo -= desc_length;
-
-		attributes = SDHCI_ADMA_VALID | SDHCI_ACT_TRAN;
-		if (togo == 0)
-			attributes |= SDHCI_ADMA_END;
-
-		if (host->dma64) {
-			host->adma64_descs[i].addr = (uintptr_t) buffer_data;
-			host->adma64_descs[i].addr_hi = 0;
-			host->adma64_descs[i].length = desc_length;
-			host->adma64_descs[i].attributes = attributes;
-
-		} else {
-			host->adma_descs[i].addr = (uintptr_t) buffer_data;
-			host->adma_descs[i].length = desc_length;
-			host->adma_descs[i].attributes = attributes;
-		}
-
-		buffer_data += desc_length;
-	}
-
-	if (host->dma64)
-		sdhci_writel(host, (uintptr_t) host->adma64_descs,
-			     SDHCI_ADMA_ADDRESS);
-	else
-		sdhci_writel(host, (uintptr_t) host->adma_descs,
-			     SDHCI_ADMA_ADDRESS);
-
-	return 0;
-}
-
-static int sdhci_complete_adma(SdhciHost *host, MmcCommand *cmd)
-{
-	int retry;
-	u32 stat = 0, mask;
-
-	mask = SDHCI_INT_RESPONSE | SDHCI_INT_ERROR;
-
-	retry = 10000; /* Command should be done in way less than 10 ms. */
-	while (--retry) {
-		stat = sdhci_readl(host, SDHCI_INT_STATUS);
-		if (stat & mask)
-			break;
-		udelay(1);
-	}
-
-	sdhci_writel(host, SDHCI_INT_RESPONSE, SDHCI_INT_STATUS);
-
-	if (retry && !(stat & SDHCI_INT_ERROR)) {
-		/* Command OK, let's wait for data transfer completion. */
-		mask = SDHCI_INT_DATA_END |
-			SDHCI_INT_ERROR | SDHCI_INT_ADMA_ERROR;
-
-		/* Transfer should take 10 seconds tops. */
-		retry = 10 * 1000 * 1000;
-		while (--retry) {
-			stat = sdhci_readl(host, SDHCI_INT_STATUS);
-			if (stat & mask)
-				break;
-			udelay(1);
-		}
-
-		sdhci_writel(host, stat, SDHCI_INT_STATUS);
-		if (retry && !(stat & SDHCI_INT_ERROR)) {
-			sdhci_cmd_done(host, cmd);
-			return 0;
-		}
-	}
-
-	printf("%s: transfer error, stat %#x, adma error %#x, retry %d\n",
-	       __func__, stat, sdhci_readl(host, SDHCI_ADMA_ERROR), retry);
-
-	sdhci_reset(host, SDHCI_RESET_CMD);
-	sdhci_reset(host, SDHCI_RESET_DATA);
-
-	if (stat & SDHCI_INT_TIMEOUT)
-		return MMC_TIMEOUT;
-	else
-		return MMC_COMM_ERR;
 }
 
 static int sdhci_send_command(MmcCtrlr *mmc_ctrl, MmcCommand *cmd,
@@ -343,11 +189,12 @@
 
 		sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
 
-		if (host->host_caps & MMC_AUTO_CMD12) {
-			if (sdhci_setup_adma(host, data))
-				return -1;
-
-			mode |= SDHCI_TRNS_DMA;
+		if (DMA_AVAILABLE) {
+			if (host->host_caps & MMC_AUTO_CMD12) {
+				if (sdhci_setup_adma(host, data))
+					return -1;
+				mode |= SDHCI_TRNS_DMA;
+			}
 		}
 		sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
 	}
@@ -355,8 +202,10 @@
 	sdhci_writel(host, cmd->cmdarg, SDHCI_ARGUMENT);
 	sdhci_writew(host, SDHCI_MAKE_CMD(cmd->cmdidx, flags), SDHCI_COMMAND);
 
-	if (data && (host->host_caps & MMC_AUTO_CMD12))
-		return sdhci_complete_adma(host, cmd);
+	if (DMA_AVAILABLE) {
+		if (data && (host->host_caps & MMC_AUTO_CMD12))
+			return sdhci_complete_adma(host, cmd);
+	}
 
         timer_monotonic_get(&current);
         end = current;
@@ -619,12 +468,14 @@
 
 	sdhci_set_uhs_signaling(host, mmc_ctrlr->timing);
 
-	if (host->host_caps & MMC_AUTO_CMD12) {
-		ctrl &= ~SDHCI_CTRL_DMA_MASK;
-		if (host->dma64)
-			ctrl |= SDHCI_CTRL_ADMA64;
-		else
-			ctrl |= SDHCI_CTRL_ADMA32;
+	if (DMA_AVAILABLE) {
+		if (host->host_caps & MMC_AUTO_CMD12) {
+			ctrl &= ~SDHCI_CTRL_DMA_MASK;
+			if (host->dma64)
+				ctrl |= SDHCI_CTRL_ADMA64;
+			else
+				ctrl |= SDHCI_CTRL_ADMA32;
+		}
 	}
 
 	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
diff --git a/src/drivers/storage/sdhci_adma.c b/src/drivers/storage/sdhci_adma.c
new file mode 100644
index 0000000..61ab5c3
--- /dev/null
+++ b/src/drivers/storage/sdhci_adma.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2011, Marvell Semiconductor Inc.
+ * Lei Wen <leiwen at marvell.com>
+ *
+ * Copyrigit 2017 Intel Corporation
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Back ported to the 8xx platform (from the 8260 platform) by
+ * Murray.Jensen at cmst.csiro.au, 27-Jan-01.
+ */
+
+#include <assert.h>
+#include <delay.h>
+#include <device/mmc.h>
+#include <device/sdhci.h>
+#include <endian.h>
+#include "storage.h"
+#include <string.h>
+#include <timer.h>
+
+static void sdhci_alloc_adma_descs(SdhciHost *host, u32 need_descriptors)
+{
+	if (host->adma_descs) {
+		if (host->adma_desc_count < need_descriptors) {
+			/* Previously allocated array is too small */
+			free(host->adma_descs);
+			host->adma_desc_count = 0;
+			host->adma_descs = NULL;
+		}
+	}
+
+	/* use dma_malloc() to make sure we get the coherent/uncached memory */
+	if (!host->adma_descs) {
+		host->adma_descs = malloc(need_descriptors *
+					      sizeof(*host->adma_descs));
+		if (host->adma_descs == NULL)
+			die("fail to malloc adma_descs\n");
+		host->adma_desc_count = need_descriptors;
+	}
+
+	memset(host->adma_descs, 0, sizeof(*host->adma_descs) *
+	       need_descriptors);
+}
+
+static void sdhci_alloc_adma64_descs(SdhciHost *host, u32 need_descriptors)
+{
+	if (host->adma64_descs) {
+		if (host->adma_desc_count < need_descriptors) {
+			/* Previously allocated array is too small */
+			free(host->adma64_descs);
+			host->adma_desc_count = 0;
+			host->adma64_descs = NULL;
+		}
+	}
+
+	/* use dma_malloc() to make sure we get the coherent/uncached memory */
+	if (!host->adma64_descs) {
+		host->adma64_descs = malloc(need_descriptors *
+					   sizeof(*host->adma64_descs));
+		if (host->adma64_descs == NULL)
+			die("fail to malloc adma64_descs\n");
+
+		host->adma_desc_count = need_descriptors;
+	}
+
+	memset(host->adma64_descs, 0, sizeof(*host->adma64_descs) *
+	       need_descriptors);
+}
+
+int sdhci_setup_adma(SdhciHost *host, MmcData *data)
+{
+	int i, togo, need_descriptors;
+	char *buffer_data;
+	u16 attributes;
+
+	togo = data->blocks * data->blocksize;
+	if (!togo) {
+		printf("%s: MmcData corrupted: %d blocks of %d bytes\n",
+		       __func__, data->blocks, data->blocksize);
+		return -1;
+	}
+
+	need_descriptors = 1 +  togo / SDHCI_MAX_PER_DESCRIPTOR;
+
+	if (host->dma64)
+		sdhci_alloc_adma64_descs(host, need_descriptors);
+	else
+		sdhci_alloc_adma_descs(host, need_descriptors);
+	buffer_data = data->dest;
+
+	/* Now set up the descriptor chain. */
+	for (i = 0; togo; i++) {
+		unsigned int desc_length;
+
+		if (togo < SDHCI_MAX_PER_DESCRIPTOR)
+			desc_length = togo;
+		else
+			desc_length = SDHCI_MAX_PER_DESCRIPTOR;
+		togo -= desc_length;
+
+		attributes = SDHCI_ADMA_VALID | SDHCI_ACT_TRAN;
+		if (togo == 0)
+			attributes |= SDHCI_ADMA_END;
+
+		if (host->dma64) {
+			host->adma64_descs[i].addr = (uintptr_t) buffer_data;
+			host->adma64_descs[i].addr_hi = 0;
+			host->adma64_descs[i].length = desc_length;
+			host->adma64_descs[i].attributes = attributes;
+
+		} else {
+			host->adma_descs[i].addr = (uintptr_t) buffer_data;
+			host->adma_descs[i].length = desc_length;
+			host->adma_descs[i].attributes = attributes;
+		}
+
+		buffer_data += desc_length;
+	}
+
+	if (host->dma64)
+		sdhci_writel(host, (uintptr_t) host->adma64_descs,
+			     SDHCI_ADMA_ADDRESS);
+	else
+		sdhci_writel(host, (uintptr_t) host->adma_descs,
+			     SDHCI_ADMA_ADDRESS);
+
+	return 0;
+}
+
+int sdhci_complete_adma(SdhciHost *host, MmcCommand *cmd)
+{
+	int retry;
+	u32 stat = 0, mask;
+
+	mask = SDHCI_INT_RESPONSE | SDHCI_INT_ERROR;
+
+	retry = 10000; /* Command should be done in way less than 10 ms. */
+	while (--retry) {
+		stat = sdhci_readl(host, SDHCI_INT_STATUS);
+		if (stat & mask)
+			break;
+		udelay(1);
+	}
+
+	sdhci_writel(host, SDHCI_INT_RESPONSE, SDHCI_INT_STATUS);
+
+	if (retry && !(stat & SDHCI_INT_ERROR)) {
+		/* Command OK, let's wait for data transfer completion. */
+		mask = SDHCI_INT_DATA_END |
+			SDHCI_INT_ERROR | SDHCI_INT_ADMA_ERROR;
+
+		/* Transfer should take 10 seconds tops. */
+		retry = 10 * 1000 * 1000;
+		while (--retry) {
+			stat = sdhci_readl(host, SDHCI_INT_STATUS);
+			if (stat & mask)
+				break;
+			udelay(1);
+		}
+
+		sdhci_writel(host, stat, SDHCI_INT_STATUS);
+		if (retry && !(stat & SDHCI_INT_ERROR)) {
+			sdhci_cmd_done(host, cmd);
+			return 0;
+		}
+	}
+
+	printf("%s: transfer error, stat %#x, adma error %#x, retry %d\n",
+	       __func__, stat, sdhci_readl(host, SDHCI_ADMA_ERROR), retry);
+
+	sdhci_reset(host, SDHCI_RESET_CMD);
+	sdhci_reset(host, SDHCI_RESET_DATA);
+
+	if (stat & SDHCI_INT_TIMEOUT)
+		return MMC_TIMEOUT;
+	else
+		return MMC_COMM_ERR;
+}
diff --git a/src/include/device/sdhci.h b/src/include/device/sdhci.h
index 8976db6..7f59085 100644
--- a/src/include/device/sdhci.h
+++ b/src/include/device/sdhci.h
@@ -361,6 +361,10 @@
 	return readb(host->ioaddr + reg);
 }
 
+void sdhci_reset(SdhciHost *host, u8 mask);
+void sdhci_cmd_done(SdhciHost *host, MmcCommand *cmd);
+int sdhci_setup_adma(SdhciHost *host, MmcData *data);
+int sdhci_complete_adma(SdhciHost *host, MmcCommand *cmd);
 int add_sdhci(SdhciHost *host);
 int sdhci_host_init(SdhciHost *host, void *ioaddr, int platform_info,
 	int clock_min, int clock_max, int clock_base);

-- 
To view, visit https://review.coreboot.org/19015
To unsubscribe, visit https://review.coreboot.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I70aad97c74aa8a72e50627740d96fecb7485dde4
Gerrit-PatchSet: 1
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Owner: Lee Leahy <leroy.p.leahy at intel.com>



More information about the coreboot-gerrit mailing list