[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(¤t);
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