From 48dbc663d75e6b7e45e50cd099acb88b35e65a0a Mon Sep 17 00:00:00 2001 From: Lee Leahy Date: Mon, 8 May 2017 16:56:03 -0700 Subject: commonlib: Move drivers/storage into commonlib/storage Move drivers/storage into commonlib/storage to enable access by libpayload and indirectly by payloads. * Remove SD/MMC specific include files from include/device * Remove files from drivers/storage * Add SD/MMC specific include files to commonlib/include * Add files to commonlib/storage * Fix header file references * Add subdir entry in commonlib/Makefile.inc to build the SD/MMC driver * Add Kconfig source for commonlib/storage * Rename *DEVICE* to *COMMONLIB* * Rename *DRIVERS_STORAGE* to *COMMONLIB_STORAGE* TEST=Build and run on Galileo Gen2 Change-Id: I4339e4378491db9a0da1f2dc34e1906a5ba31ad6 Signed-off-by: Lee Leahy Reviewed-on: https://review.coreboot.org/19672 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi --- src/commonlib/storage/sdhci_adma.c | 194 +++++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 src/commonlib/storage/sdhci_adma.c (limited to 'src/commonlib/storage/sdhci_adma.c') diff --git a/src/commonlib/storage/sdhci_adma.c b/src/commonlib/storage/sdhci_adma.c new file mode 100644 index 0000000000..e95742b35b --- /dev/null +++ b/src/commonlib/storage/sdhci_adma.c @@ -0,0 +1,194 @@ +/* + * Copyright 2011, Marvell Semiconductor Inc. + * Lei Wen + * + * Copyright 2017 Intel Corporation + * + * Secure Digital (SD) Host Controller interface DMA support code + * + * 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. + */ + +#include +#include +#include +#include +#include +#include "sdhci.h" +#include "sd_mmc.h" +#include "storage.h" +#include +#include + +static void sdhci_alloc_adma_descs(struct sdhci_ctrlr *sdhci_ctrlr, + u32 need_descriptors) +{ + if (sdhci_ctrlr->adma_descs) { + if (sdhci_ctrlr->adma_desc_count < need_descriptors) { + /* Previously allocated array is too small */ + free(sdhci_ctrlr->adma_descs); + sdhci_ctrlr->adma_desc_count = 0; + sdhci_ctrlr->adma_descs = NULL; + } + } + + /* use dma_malloc() to make sure we get the coherent/uncached memory */ + if (!sdhci_ctrlr->adma_descs) { + sdhci_ctrlr->adma_descs = malloc(need_descriptors + * sizeof(*sdhci_ctrlr->adma_descs)); + if (sdhci_ctrlr->adma_descs == NULL) + die("fail to malloc adma_descs\n"); + sdhci_ctrlr->adma_desc_count = need_descriptors; + } + + memset(sdhci_ctrlr->adma_descs, 0, sizeof(*sdhci_ctrlr->adma_descs) + * need_descriptors); +} + +static void sdhci_alloc_adma64_descs(struct sdhci_ctrlr *sdhci_ctrlr, + u32 need_descriptors) +{ + if (sdhci_ctrlr->adma64_descs) { + if (sdhci_ctrlr->adma_desc_count < need_descriptors) { + /* Previously allocated array is too small */ + free(sdhci_ctrlr->adma64_descs); + sdhci_ctrlr->adma_desc_count = 0; + sdhci_ctrlr->adma64_descs = NULL; + } + } + + /* use dma_malloc() to make sure we get the coherent/uncached memory */ + if (!sdhci_ctrlr->adma64_descs) { + sdhci_ctrlr->adma64_descs = malloc(need_descriptors + * sizeof(*sdhci_ctrlr->adma64_descs)); + if (sdhci_ctrlr->adma64_descs == NULL) + die("fail to malloc adma64_descs\n"); + + sdhci_ctrlr->adma_desc_count = need_descriptors; + } + + memset(sdhci_ctrlr->adma64_descs, 0, sizeof(*sdhci_ctrlr->adma64_descs) + * need_descriptors); +} + +int sdhci_setup_adma(struct sdhci_ctrlr *sdhci_ctrlr, struct mmc_data *data) +{ + int i, togo, need_descriptors; + int dma64; + char *buffer_data; + u16 attributes; + + togo = data->blocks * data->blocksize; + if (!togo) { + sdhc_error("%s: MmcData corrupted: %d blocks of %d bytes\n", + __func__, data->blocks, data->blocksize); + return -1; + } + + need_descriptors = 1 + togo / SDHCI_MAX_PER_DESCRIPTOR; + dma64 = sdhci_ctrlr->sd_mmc_ctrlr.caps & DRVR_CAP_DMA_64BIT; + if (dma64) + sdhci_alloc_adma64_descs(sdhci_ctrlr, need_descriptors); + else + sdhci_alloc_adma_descs(sdhci_ctrlr, 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 (dma64) { + sdhci_ctrlr->adma64_descs[i].addr = + (uintptr_t)buffer_data; + sdhci_ctrlr->adma64_descs[i].addr_hi = 0; + sdhci_ctrlr->adma64_descs[i].length = desc_length; + sdhci_ctrlr->adma64_descs[i].attributes = attributes; + + } else { + sdhci_ctrlr->adma_descs[i].addr = + (uintptr_t)buffer_data; + sdhci_ctrlr->adma_descs[i].length = desc_length; + sdhci_ctrlr->adma_descs[i].attributes = attributes; + } + + buffer_data += desc_length; + } + + if (dma64) + sdhci_writel(sdhci_ctrlr, (uintptr_t) sdhci_ctrlr->adma64_descs, + SDHCI_ADMA_ADDRESS); + else + sdhci_writel(sdhci_ctrlr, (uintptr_t) sdhci_ctrlr->adma_descs, + SDHCI_ADMA_ADDRESS); + + return 0; +} + +int sdhci_complete_adma(struct sdhci_ctrlr *sdhci_ctrlr, + struct mmc_command *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(sdhci_ctrlr, SDHCI_INT_STATUS); + if (stat & mask) + break; + udelay(1); + } + + sdhci_writel(sdhci_ctrlr, 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(sdhci_ctrlr, SDHCI_INT_STATUS); + if (stat & mask) + break; + udelay(1); + } + + sdhci_writel(sdhci_ctrlr, stat, SDHCI_INT_STATUS); + if (retry && !(stat & SDHCI_INT_ERROR)) { + sdhci_cmd_done(sdhci_ctrlr, cmd); + return 0; + } + } + + sdhc_error("%s: transfer error, stat %#x, adma error %#x, retry %d\n", + __func__, stat, sdhci_readl(sdhci_ctrlr, SDHCI_ADMA_ERROR), + retry); + + sdhci_reset(sdhci_ctrlr, SDHCI_RESET_CMD); + sdhci_reset(sdhci_ctrlr, SDHCI_RESET_DATA); + + if (stat & SDHCI_INT_TIMEOUT) + return CARD_TIMEOUT; + return CARD_COMM_ERR; +} -- cgit v1.2.3