diff options
Diffstat (limited to 'drivers/mmc')
| -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 1ed26cab3..e793ed994 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 19d9b0b89..4cec5aaa6 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 e1461a98d..c6a1c23fb 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 46ae9cb52..1e86b92be 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 000000000..bc53a5da2 --- /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); +} + |