From fd26b5490bef8e8a37e33a9b3c4960d7a8734067 Mon Sep 17 00:00:00 2001 From: Chin Liang See Date: Wed, 18 Dec 2013 11:16:01 -0600 Subject: mmc/dwmmc: Using calloc instead malloc To enhance the SDMMC DesignWare driver to use calloc instead of malloc. This will avoid the incident that uninitialized members of mmc structure are later used for NULL comparison. Signed-off-by: Chin Liang See Cc: Rajeshwari Shinde Cc: Jaehoon Chung Cc: Mischa Jonker Cc: Alexey Brodkin Cc: Andy Fleming Cc: Pantelis Antoniou Acked-by: Pantelis Antoniou --- drivers/mmc/dw_mmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) mode change 100644 => 100755 drivers/mmc/dw_mmc.c (limited to 'drivers') diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c old mode 100644 new mode 100755 index 19d9b0b..82abe19 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -336,9 +336,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; } -- cgit v1.1 From 2a7a210e2cb724f4a941786e58878baf6edce846 Mon Sep 17 00:00:00 2001 From: Alexey Brodkin Date: Thu, 26 Dec 2013 15:29:07 +0400 Subject: mmc/dwmmc: use bounce buffer for data exchange between CPU and MMC controller Bounce buffer implementation takes care of proper data buffer alignemt and correct flush/invalidation of data cache at once so we no longer depend on input data variety and make sure CPU and MMC controller deal with expected data in case of enabled data cache. Bounce buffer requires to add its definition (CONFIG_BOUNCE_BUFFER) in board configuration, otherwise corresponding library won't be compiled and linker will fail to build resulting executable. Difference since v1 - fixed compile-time warning with type casting to "void *": Slight edit to remove UTF8 characters in the commit message. Acked-by: Jaehoon Chung Tested-by: Jaehoon Chung Acked-by: Pantelis Antoniou ==== passing argument 2 of 'bounce_buffer_start' discards 'const' qualifier from pointer target type ==== Signed-off-by: Alexey Brodkin Cc: Mischa Jonker Cc: Alim Akhtar Cc: Rajeshwari Shinde Cc: Jaehoon Chung Cc: Amar Cc: Kyungmin Park Cc: Minkyu Kang Cc: Simon Glass Cc: Pantelis Antoniou Cc: Andy Fleming --- drivers/mmc/dw_mmc.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index 82abe19..4cec5aa 100755 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -6,6 +6,7 @@ * SPDX-License-Identifier: GPL-2.0+ */ +#include #include #include #include @@ -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); -- cgit v1.1 From 30e6d979fa9da56a5badcb981cdddd58638d3375 Mon Sep 17 00:00:00 2001 From: Darwin Rambo Date: Thu, 19 Dec 2013 15:13:25 -0800 Subject: mmc: Minor cleanup of sdhci.c Fixup prints to show where the print is done from, and a few minor formatting/grammar issues. Signed-off-by: Darwin Rambo Acked-by: Pantelis Antoniou --- drivers/mmc/sdhci.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) (limited to 'drivers') 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) -- cgit v1.1 From ab71188ce87ebb66192a5bdbbb9d58052bd32d93 Mon Sep 17 00:00:00 2001 From: Markus Niebel Date: Mon, 16 Dec 2013 13:40:46 +0100 Subject: mmc: add setdsr support The eMMC and the SD-Card specifications describe the optional SET_DSR command. During measurements at our lab we found that some cards implementing this feature having really strong driver strengts per default. This can lead to voltage peaks above the specification of the host on signal edges for data sent from a card to the host. Since availability of a given card type may be shorter than the time a certain hardware will be produced it is useful to have support for this command (Alternative would be changing termination resistors and adapting the driver strength of the host to the used card.) Following proposal for an implementation: - new field that reflects CSD field DSR_IMP in struct mmc - new field for design specific DSR value in struct mmc - board code can set DSR value in mmc struct just after registering an controller - mmc_startup sends the the stored DSR value before selecting a card, if DSR_IMP is set Additionally the mmc command is extended to make is possible to play around with different DSR values. The concept was tested on a i.MX53 based platform using a Micron eMMC card where the default DSR is 0x0400 (12mA) but in our design 0x0100 (0x0100) were enough. To use this feature for instance on a mx53loco one have to add a call to mmc_set_dsr() in board_mmc_init() after calling fsl_esdhc_initialize() for the eMMC. Signed-off-by: Markus Niebel Acked-by: Pantelis Antoniou --- drivers/mmc/mmc.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') 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 -- cgit v1.1 From c5c1af21764d9423b45c1d03e835c4547a8bc5cb Mon Sep 17 00:00:00 2001 From: Chin Liang See Date: Mon, 30 Dec 2013 18:26:14 -0600 Subject: socfpga/dwmmc: Adding DesignWare MMC driver support for SOCFPGA To add the DesignWare MMC driver support for Altera SOCFPGA. It required information such as clocks and bus width from platform specific files (SOCFPGA handoff files) Signed-off-by: Chin Liang See Cc: Rajeshwari Shinde Cc: Jaehoon Chung Cc: Pantelis Antoniou Cc: Wolfgang Denk Acked-by: Pantelis Antoniou --- drivers/mmc/Makefile | 1 + drivers/mmc/socfpga_dw_mmc.c | 68 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 drivers/mmc/socfpga_dw_mmc.c (limited to 'drivers') 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/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 + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include + +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); +} + -- cgit v1.1