diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mmc/Makefile | 1 | ||||
-rwxr-xr-x[-rw-r--r--] | drivers/mmc/dw_mmc.c | 36 | ||||
-rw-r--r-- | drivers/mmc/mmc.c | 18 | ||||
-rw-r--r-- | drivers/mmc/sdhci.c | 32 | ||||
-rw-r--r-- | drivers/mmc/socfpga_dw_mmc.c | 68 |
5 files changed, 130 insertions, 25 deletions
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 1ed26ca..e793ed9 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_TEGRA_MMC) += tegra_mmc.o obj-$(CONFIG_DWMMC) += dw_mmc.o obj-$(CONFIG_EXYNOS_DWMMC) += exynos_dw_mmc.o obj-$(CONFIG_ZYNQ_SDHCI) += zynq_sdhci.o +obj-$(CONFIG_SOCFPGA_DWMMC) += socfpga_dw_mmc.o ifdef CONFIG_SPL_BUILD obj-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o else diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index 19d9b0b..4cec5aa 100644..100755 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -6,6 +6,7 @@ * SPDX-License-Identifier: GPL-2.0+ */ +#include <bouncebuf.h> #include <common.h> #include <malloc.h> #include <mmc.h> @@ -41,11 +42,13 @@ static void dwmci_set_idma_desc(struct dwmci_idmac *idmac, } static void dwmci_prepare_data(struct dwmci_host *host, - struct mmc_data *data, struct dwmci_idmac *cur_idmac) + struct mmc_data *data, + struct dwmci_idmac *cur_idmac, + void *bounce_buffer) { unsigned long ctrl; unsigned int i = 0, flags, cnt, blk_cnt; - ulong data_start, data_end, start_addr; + ulong data_start, data_end; blk_cnt = data->blocks; @@ -55,11 +58,6 @@ static void dwmci_prepare_data(struct dwmci_host *host, data_start = (ulong)cur_idmac; dwmci_writel(host, DWMCI_DBADDR, (unsigned int)cur_idmac); - if (data->flags == MMC_DATA_READ) - start_addr = (unsigned int)data->dest; - else - start_addr = (unsigned int)data->src; - do { flags = DWMCI_IDMAC_OWN | DWMCI_IDMAC_CH ; flags |= (i == 0) ? DWMCI_IDMAC_FS : 0; @@ -70,7 +68,7 @@ static void dwmci_prepare_data(struct dwmci_host *host, cnt = data->blocksize * 8; dwmci_set_idma_desc(cur_idmac, flags, cnt, - start_addr + (i * PAGE_SIZE)); + (u32)bounce_buffer + (i * PAGE_SIZE)); if (blk_cnt <= 8) break; @@ -117,6 +115,7 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, u32 retry = 10000; u32 mask, ctrl; ulong start = get_timer(0); + struct bounce_buffer bbstate; while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) { if (get_timer(start) > timeout) { @@ -127,8 +126,19 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL); - if (data) - dwmci_prepare_data(host, data, cur_idmac); + if (data) { + if (data->flags == MMC_DATA_READ) { + bounce_buffer_start(&bbstate, (void*)data->dest, + data->blocksize * + data->blocks, GEN_BB_WRITE); + } else { + bounce_buffer_start(&bbstate, (void*)data->src, + data->blocksize * + data->blocks, GEN_BB_READ); + } + dwmci_prepare_data(host, data, cur_idmac, + bbstate.bounce_buffer); + } dwmci_writel(host, DWMCI_CMDARG, cmd->cmdarg); @@ -204,6 +214,8 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, ctrl = dwmci_readl(host, DWMCI_CTRL); ctrl &= ~(DWMCI_DMA_EN); dwmci_writel(host, DWMCI_CTRL, ctrl); + + bounce_buffer_stop(&bbstate); } udelay(100); @@ -336,9 +348,9 @@ int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk) struct mmc *mmc; int err = 0; - mmc = malloc(sizeof(struct mmc)); + mmc = calloc(sizeof(struct mmc), 1); if (!mmc) { - printf("mmc malloc fail!\n"); + printf("mmc calloc fail!\n"); return -1; } diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index e1461a9..c6a1c23 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -877,6 +877,7 @@ static int mmc_startup(struct mmc *mmc) mmc->tran_speed = freq * mult; + mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); if (IS_SD(mmc)) @@ -907,6 +908,14 @@ static int mmc_startup(struct mmc *mmc) if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) mmc->write_bl_len = MMC_MAX_BLOCK_LEN; + if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { + cmd.cmdidx = MMC_CMD_SET_DSR; + cmd.cmdarg = (mmc->dsr & 0xffff) << 16; + cmd.resp_type = MMC_RSP_NONE; + if (mmc_send_cmd(mmc, &cmd, NULL)) + printf("MMC: SET_DSR failed\n"); + } + /* Select the card, and put it into Transfer Mode */ if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ cmd.cmdidx = MMC_CMD_SELECT_CARD; @@ -1163,6 +1172,9 @@ static int mmc_send_if_cond(struct mmc *mmc) int mmc_register(struct mmc *mmc) { + /* Setup dsr related values */ + mmc->dsr_imp = 0; + mmc->dsr = 0xffffffff; /* Setup the universal parts of the block interface just once */ mmc->block_dev.if_type = IF_TYPE_MMC; mmc->block_dev.dev = cur_dev_num++; @@ -1280,6 +1292,12 @@ int mmc_init(struct mmc *mmc) return err; } +int mmc_set_dsr(struct mmc *mmc, u16 val) +{ + mmc->dsr = val; + return 0; +} + /* * CPU and board-specific MMC initializations. Aliased function * signals caller to move on diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 46ae9cb..1e86b92 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -24,7 +24,8 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask) sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET); while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) { if (timeout == 0) { - printf("Reset 0x%x never completed.\n", (int)mask); + printf("%s: Reset 0x%x never completed.\n", + __func__, (int)mask); return; } timeout--; @@ -79,7 +80,8 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data, do { stat = sdhci_readl(host, SDHCI_INT_STATUS); if (stat & SDHCI_INT_ERROR) { - printf("Error detected in status(0x%X)!\n", stat); + printf("%s: Error detected in status(0x%X)!\n", + __func__, stat); return -1; } if (stat & rdy) { @@ -102,7 +104,7 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data, if (timeout-- > 0) udelay(10); else { - printf("Transfer data timeout\n"); + printf("%s: Transfer data timeout\n", __func__); return -1; } } while (!(stat & SDHCI_INT_DATA_END)); @@ -147,7 +149,7 @@ int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) { if (time >= cmd_timeout) { - printf("MMC: %d busy ", mmc_dev); + printf("%s: MMC: %d busy ", __func__, mmc_dev); if (2 * cmd_timeout <= CONFIG_SDHCI_CMD_MAX_TIMEOUT) { cmd_timeout += cmd_timeout; printf("timeout increasing to: %u ms.\n", @@ -179,7 +181,7 @@ int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, if (data) flags |= SDHCI_CMD_DATA; - /*Set Transfer mode regarding to data flag*/ + /* Set Transfer mode regarding to data flag */ if (data != 0) { sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL); mode = SDHCI_TRNS_BLK_CNT_EN; @@ -230,7 +232,7 @@ int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, if (host->quirks & SDHCI_QUIRK_BROKEN_R1B) return 0; else { - printf("Timeout for status update!\n"); + printf("%s: Timeout for status update!\n", __func__); return TIMEOUT; } } @@ -307,7 +309,8 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) & SDHCI_CLOCK_INT_STABLE)) { if (timeout == 0) { - printf("Internal clock never stabilised.\n"); + printf("%s: Internal clock never stabilised.\n", + __func__); return -1; } timeout--; @@ -397,7 +400,8 @@ int sdhci_init(struct mmc *mmc) if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !aligned_buffer) { aligned_buffer = memalign(8, 512*1024); if (!aligned_buffer) { - printf("Aligned buffer alloc failed!!!"); + printf("%s: Aligned buffer alloc failed!!!\n", + __func__); return -1; } } @@ -418,8 +422,8 @@ int sdhci_init(struct mmc *mmc) } /* Enable only interrupts served by the SD controller */ - sdhci_writel(host, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK - , SDHCI_INT_ENABLE); + sdhci_writel(host, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK, + SDHCI_INT_ENABLE); /* Mask all sdhci interrupt sources */ sdhci_writel(host, 0x0, SDHCI_SIGNAL_ENABLE); @@ -433,7 +437,7 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk) mmc = malloc(sizeof(struct mmc)); if (!mmc) { - printf("mmc malloc fail!\n"); + printf("%s: mmc malloc fail!\n", __func__); return -1; } @@ -450,7 +454,8 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk) caps = sdhci_readl(host, SDHCI_CAPABILITIES); #ifdef CONFIG_MMC_SDMA if (!(caps & SDHCI_CAN_DO_SDMA)) { - printf("Your controller don't support sdma!!\n"); + printf("%s: Your controller doesn't support SDMA!!\n", + __func__); return -1; } #endif @@ -467,7 +472,8 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk) mmc->f_max *= 1000000; } if (mmc->f_max == 0) { - printf("Hardware doesn't specify base clock frequency\n"); + printf("%s: Hardware doesn't specify base clock frequency\n", + __func__); return -1; } if (min_clk) diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c new file mode 100644 index 0000000..bc53a5d --- /dev/null +++ b/drivers/mmc/socfpga_dw_mmc.c @@ -0,0 +1,68 @@ +/* + * (C) Copyright 2013 Altera Corporation <www.altera.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <malloc.h> +#include <dwmmc.h> +#include <asm/arch/dwmmc.h> +#include <asm/arch/clock_manager.h> +#include <asm/arch/system_manager.h> + +static const struct socfpga_clock_manager *clock_manager_base = + (void *)SOCFPGA_CLKMGR_ADDRESS; +static const struct socfpga_system_manager *system_manager_base = + (void *)SOCFPGA_SYSMGR_ADDRESS; + +static char *SOCFPGA_NAME = "SOCFPGA DWMMC"; + +static void socfpga_dwmci_clksel(struct dwmci_host *host) +{ + unsigned int drvsel; + unsigned int smplsel; + + /* Disable SDMMC clock. */ + clrbits_le32(&clock_manager_base->per_pll_en, + CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK); + + /* Configures drv_sel and smpl_sel */ + drvsel = CONFIG_SOCFPGA_DWMMC_DRVSEL; + smplsel = CONFIG_SOCFPGA_DWMMC_SMPSEL; + + debug("%s: drvsel %d smplsel %d\n", __func__, drvsel, smplsel); + writel(SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel), + &system_manager_base->sdmmcgrp_ctrl); + + debug("%s: SYSMGR_SDMMCGRP_CTRL_REG = 0x%x\n", __func__, + readl(&system_manager_base->sdmmcgrp_ctrl)); + + /* Enable SDMMC clock */ + setbits_le32(&clock_manager_base->per_pll_en, + CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK); +} + +int socfpga_dwmmc_init(u32 regbase, int bus_width, int index) +{ + struct dwmci_host *host = NULL; + host = calloc(sizeof(struct dwmci_host), 1); + if (!host) { + printf("dwmci_host calloc fail!\n"); + return -1; + } + + host->name = SOCFPGA_NAME; + host->ioaddr = (void *)regbase; + host->buswidth = bus_width; + host->clksel = socfpga_dwmci_clksel; + host->dev_index = index; + /* fixed clock divide by 4 which due to the SDMMC wrapper */ + host->bus_hz = CONFIG_SOCFPGA_DWMMC_BUS_HZ; + host->fifoth_val = MSIZE(0x2) | + RX_WMARK(CONFIG_SOCFPGA_DWMMC_FIFO_DEPTH / 2 - 1) | + TX_WMARK(CONFIG_SOCFPGA_DWMMC_FIFO_DEPTH / 2); + + return add_dwmci(host, host->bus_hz, 400000); +} + |