diff options
| author | Sandeep Paulraj <s-paulraj@ti.com> | 2010-12-20 20:01:21 -0500 | 
|---|---|---|
| committer | Albert Aribaud <albert.aribaud@free.fr> | 2011-02-02 00:54:44 +0100 | 
| commit | 57418d2139f032f9dae8cea38917aa90fdd673d8 (patch) | |
| tree | f14c2061d406b8a56bf0c77fa16540eef0de0a34 | |
| parent | 36b4e2dddd3ee481411fa50e1c34dbf823eb5f5d (diff) | |
| download | olio-uboot-2014.01-57418d2139f032f9dae8cea38917aa90fdd673d8.tar.xz olio-uboot-2014.01-57418d2139f032f9dae8cea38917aa90fdd673d8.zip | |
Davinci MMCSD Support
Added support for MMC/SD cards for Davinci.  This feature is enabled by
CONFIG_DAVINCI_MMC and is dependant on CONFIG_MMC and CONFIG_GENERIC_MMC
options. This is tested on DM355 and DM365 EVMs with both the available mmc
controllers.
Signed-off-by: Alagu Sankar <alagusankar@embwise.com>
Signed-off-by: Sandeep Paulraj <s-paulraj@ti.com>
| -rw-r--r-- | arch/arm/include/asm/arch-davinci/sdmmc_defs.h | 175 | ||||
| -rw-r--r-- | drivers/mmc/Makefile | 1 | ||||
| -rw-r--r-- | drivers/mmc/davinci_mmc.c | 404 | ||||
| -rw-r--r-- | include/mmc.h | 3 | 
4 files changed, 583 insertions, 0 deletions
| diff --git a/arch/arm/include/asm/arch-davinci/sdmmc_defs.h b/arch/arm/include/asm/arch-davinci/sdmmc_defs.h new file mode 100644 index 000000000..853fd4097 --- /dev/null +++ b/arch/arm/include/asm/arch-davinci/sdmmc_defs.h @@ -0,0 +1,175 @@ +/* + * Davinci MMC Controller Defines - Based on Linux davinci_mmc.c + * + * Copyright (C) 2010 Texas Instruments Incorporated + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _SDMMC_DEFS_H_ +#define _SDMMC_DEFS_H_ + +#include <asm/arch/hardware.h> + +/* MMC Control Reg fields */ +#define MMCCTL_DATRST		(1 << 0) +#define MMCCTL_CMDRST		(1 << 1) +#define MMCCTL_WIDTH_4_BIT	(1 << 2) +#define MMCCTL_DATEG_DISABLED	(0 << 6) +#define MMCCTL_DATEG_RISING	(1 << 6) +#define MMCCTL_DATEG_FALLING	(2 << 6) +#define MMCCTL_DATEG_BOTH	(3 << 6) +#define MMCCTL_PERMDR_LE	(0 << 9) +#define MMCCTL_PERMDR_BE	(1 << 9) +#define MMCCTL_PERMDX_LE	(0 << 10) +#define MMCCTL_PERMDX_BE	(1 << 10) + +/* MMC Clock Control Reg fields */ +#define MMCCLK_CLKEN		(1 << 8) +#define MMCCLK_CLKRT_MASK	(0xFF << 0) + +/* MMC Status Reg0 fields */ +#define MMCST0_DATDNE		(1 << 0) +#define MMCST0_BSYDNE		(1 << 1) +#define MMCST0_RSPDNE		(1 << 2) +#define MMCST0_TOUTRD		(1 << 3) +#define MMCST0_TOUTRS		(1 << 4) +#define MMCST0_CRCWR		(1 << 5) +#define MMCST0_CRCRD		(1 << 6) +#define MMCST0_CRCRS		(1 << 7) +#define MMCST0_DXRDY		(1 << 9) +#define MMCST0_DRRDY		(1 << 10) +#define MMCST0_DATED		(1 << 11) +#define MMCST0_TRNDNE		(1 << 12) + +#define MMCST0_ERR_MASK		(0x00F8) + +/* MMC Status Reg1 fields */ +#define MMCST1_BUSY		(1 << 0) +#define MMCST1_CLKSTP		(1 << 1) +#define MMCST1_DXEMP		(1 << 2) +#define MMCST1_DRFUL		(1 << 3) +#define MMCST1_DAT3ST		(1 << 4) +#define MMCST1_FIFOEMP		(1 << 5) +#define MMCST1_FIFOFUL		(1 << 6) + +/* MMC INT Mask Reg fields */ +#define MMCIM_EDATDNE		(1 << 0) +#define MMCIM_EBSYDNE		(1 << 1) +#define MMCIM_ERSPDNE		(1 << 2) +#define MMCIM_ETOUTRD		(1 << 3) +#define MMCIM_ETOUTRS		(1 << 4) +#define MMCIM_ECRCWR		(1 << 5) +#define MMCIM_ECRCRD		(1 << 6) +#define MMCIM_ECRCRS		(1 << 7) +#define MMCIM_EDXRDY		(1 << 9) +#define MMCIM_EDRRDY		(1 << 10) +#define MMCIM_EDATED		(1 << 11) +#define MMCIM_ETRNDNE		(1 << 12) + +#define MMCIM_MASKALL		(0xFFFFFFFF) + +/* MMC Resp Tout Reg fields */ +#define MMCTOR_TOR_MASK		(0xFF)		/* dont write to reg, | it */ +#define MMCTOR_TOD_20_16_SHIFT  (8) + +/* MMC Data Read Tout Reg fields */ +#define MMCTOD_TOD_0_15_MASK	(0xFFFF) + +/* MMC Block len Reg fields */ +#define MMCBLEN_BLEN_MASK	(0xFFF) + +/* MMC Num Blocks Reg fields */ +#define MMCNBLK_NBLK_MASK	(0xFFFF) +#define MMCNBLK_NBLK_MAX	(0xFFFF) + +/* MMC Num Blocks Counter Reg fields */ +#define MMCNBLC_NBLC_MASK	(0xFFFF) + +/* MMC Cmd Reg fields */ +#define MMCCMD_CMD_MASK		(0x3F) +#define MMCCMD_PPLEN		(1 << 7) +#define MMCCMD_BSYEXP		(1 << 8) +#define MMCCMD_RSPFMT_NONE	(0 << 9) +#define MMCCMD_RSPFMT_R1567	(1 << 9) +#define MMCCMD_RSPFMT_R2	(2 << 9) +#define MMCCMD_RSPFMT_R3	(3 << 9) +#define MMCCMD_DTRW		(1 << 11) +#define MMCCMD_STRMTP		(1 << 12) +#define MMCCMD_WDATX		(1 << 13) +#define MMCCMD_INITCK		(1 << 14) +#define MMCCMD_DCLR		(1 << 15) +#define MMCCMD_DMATRIG		(1 << 16) + +/* FIFO control Reg fields */ +#define MMCFIFOCTL_FIFORST	(1 << 0) +#define MMCFIFOCTL_FIFODIR	(1 << 1) +#define MMCFIFOCTL_FIFOLEV	(1 << 2) +#define MMCFIFOCTL_ACCWD_4	(0 << 3)	/* access width of 4 bytes */ +#define MMCFIFOCTL_ACCWD_3	(1 << 3)	/* access width of 3 bytes */ +#define MMCFIFOCTL_ACCWD_2	(2 << 3)	/* access width of 2 bytes */ +#define MMCFIFOCTL_ACCWD_1	(3 << 3)	/* access width of 1 byte */ + +/* Davinci MMC Register definitions */ +struct davinci_mmc_regs { +	dv_reg mmcctl; +	dv_reg mmcclk; +	dv_reg mmcst0; +	dv_reg mmcst1; +	dv_reg mmcim; +	dv_reg mmctor; +	dv_reg mmctod; +	dv_reg mmcblen; +	dv_reg mmcnblk; +	dv_reg mmcnblc; +	dv_reg mmcdrr; +	dv_reg mmcdxr; +	dv_reg mmccmd; +	dv_reg mmcarghl; +	dv_reg mmcrsp01; +	dv_reg mmcrsp23; +	dv_reg mmcrsp45; +	dv_reg mmcrsp67; +	dv_reg mmcdrsp; +	dv_reg mmcetok; +	dv_reg mmccidx; +	dv_reg mmcckc; +	dv_reg mmctorc; +	dv_reg mmctodc; +	dv_reg mmcblnc; +	dv_reg sdioctl; +	dv_reg sdiost0; +	dv_reg sdioien; +	dv_reg sdioist; +	dv_reg mmcfifoctl; +}; + +/* Davinci MMC board definitions */ +struct davinci_mmc { +	struct davinci_mmc_regs *reg_base;	/* Register base address */ +	uint input_clk;		/* Input clock to MMC controller */ +	uint host_caps;		/* Host capabilities */ +	uint voltages;		/* Host supported voltages */ +	uint version;		/* MMC Controller version */ +}; + +enum { +	MMC_CTLR_VERSION_1 = 0,	/* DM644x and DM355 */ +	MMC_CTLR_VERSION_2,	/* DA830 */ +}; + +int davinci_mmc_init(bd_t *bis, struct davinci_mmc *host); + +#endif /* _SDMMC_DEFS_H */ diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 68afd30ef..3496f0aa0 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -27,6 +27,7 @@ LIB	:= $(obj)libmmc.o  COBJS-$(CONFIG_ATMEL_MCI) += atmel_mci.o  COBJS-$(CONFIG_BFIN_SDH) += bfin_sdh.o +COBJS-$(CONFIG_DAVINCI_MMC) += davinci_mmc.o  COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o  COBJS-$(CONFIG_GENERIC_MMC) += mmc.o  COBJS-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o diff --git a/drivers/mmc/davinci_mmc.c b/drivers/mmc/davinci_mmc.c new file mode 100644 index 000000000..4e572dc53 --- /dev/null +++ b/drivers/mmc/davinci_mmc.c @@ -0,0 +1,404 @@ +/* + * Davinci MMC Controller Driver + * + * Copyright (C) 2010 Texas Instruments Incorporated + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <config.h> +#include <common.h> +#include <command.h> +#include <mmc.h> +#include <part.h> +#include <malloc.h> +#include <asm/io.h> +#include <asm/arch/sdmmc_defs.h> + +#define DAVINCI_MAX_BLOCKS	(32) +#define WATCHDOG_COUNT		(100000) + +#define get_val(addr)		REG(addr) +#define set_val(addr, val)	REG(addr) = (val) +#define set_bit(addr, val)	set_val((addr), (get_val(addr) | (val))) +#define clear_bit(addr, val)	set_val((addr), (get_val(addr) & ~(val))) + +/* Set davinci clock prescalar value based on the required clock in HZ */ +static void dmmc_set_clock(struct mmc *mmc, uint clock) +{ +	struct davinci_mmc *host = mmc->priv; +	struct davinci_mmc_regs *regs = host->reg_base; +	uint clkrt, sysclk2, act_clock; + +	if (clock < mmc->f_min) +		clock = mmc->f_min; +	if (clock > mmc->f_max) +		clock = mmc->f_max; + +	set_val(®s->mmcclk, 0); +	sysclk2 = host->input_clk; +	clkrt = (sysclk2 / (2 * clock)) - 1; + +	/* Calculate the actual clock for the divider used */ +	act_clock = (sysclk2 / (2 * (clkrt + 1))); + +	/* Adjust divider if actual clock exceeds the required clock */ +	if (act_clock > clock) +		clkrt++; + +	/* check clock divider boundary and correct it */ +	if (clkrt > 0xFF) +		clkrt = 0xFF; + +	set_val(®s->mmcclk, (clkrt | MMCCLK_CLKEN)); +} + +/* Status bit wait loop for MMCST1 */ +static int +dmmc_wait_fifo_status(volatile struct davinci_mmc_regs *regs, uint status) +{ +	uint mmcstatus1, wdog = WATCHDOG_COUNT; +	mmcstatus1 = get_val(®s->mmcst1); +	while (--wdog && ((get_val(®s->mmcst1) & status) != status)) +		udelay(10); + +	if (!(get_val(®s->mmcctl) & MMCCTL_WIDTH_4_BIT)) +		udelay(100); + +	if (wdog == 0) +		return COMM_ERR; + +	return 0; +} + +/* Busy bit wait loop for MMCST1 */ +static int dmmc_busy_wait(volatile struct davinci_mmc_regs *regs) +{ +	uint mmcstatus1, wdog = WATCHDOG_COUNT; + +	mmcstatus1 = get_val(®s->mmcst1); +	while (--wdog && (get_val(®s->mmcst1) & MMCST1_BUSY)) +		udelay(10); + +	if (wdog == 0) +		return COMM_ERR; + +	return 0; +} + +/* Status bit wait loop for MMCST0 - Checks for error bits as well */ +static int dmmc_check_status(volatile struct davinci_mmc_regs *regs, +		uint *cur_st, uint st_ready, uint st_error) +{ +	uint wdog = WATCHDOG_COUNT; +	uint mmcstatus = *cur_st; + +	while (wdog--) { +		if (mmcstatus & st_ready) { +			*cur_st = mmcstatus; +			mmcstatus = get_val(®s->mmcst1); +			return 0; +		} else if (mmcstatus & st_error) { +			if (mmcstatus & MMCST0_TOUTRS) +				return TIMEOUT; +			printf("[ ST0 ERROR %x]\n", mmcstatus); +			/* +			 * Ignore CRC errors as some MMC cards fail to +			 * initialize on DM365-EVM on the SD1 slot +			 */ +			if (mmcstatus & MMCST0_CRCRS) +				return 0; +			return COMM_ERR; +		} +		udelay(10); + +		mmcstatus = get_val(®s->mmcst0); +	} + +	printf("Status %x Timeout ST0:%x ST1:%x\n", st_ready, mmcstatus, +			get_val(®s->mmcst1)); +	return COMM_ERR; +} + +/* + * Sends a command out on the bus.  Takes the mmc pointer, + * a command pointer, and an optional data pointer. + */ +static int +dmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) +{ +	struct davinci_mmc *host = mmc->priv; +	volatile struct davinci_mmc_regs *regs = host->reg_base; +	uint mmcstatus, status_rdy, status_err; +	uint i, cmddata, bytes_left = 0; +	int fifo_words, fifo_bytes, err; +	char *data_buf = NULL; + +	/* Clear status registers */ +	mmcstatus = get_val(®s->mmcst0); +	fifo_words = (host->version == MMC_CTLR_VERSION_2) ? 16 : 8; +	fifo_bytes = fifo_words << 2; + +	/* Wait for any previous busy signal to be cleared */ +	dmmc_busy_wait(regs); + +	cmddata = cmd->cmdidx; +	cmddata |= MMCCMD_PPLEN; + +	/* Send init clock for CMD0 */ +	if (cmd->cmdidx == MMC_CMD_GO_IDLE_STATE) +		cmddata |= MMCCMD_INITCK; + +	switch (cmd->resp_type) { +	case MMC_RSP_R1b: +		cmddata |= MMCCMD_BSYEXP; +		/* Fall-through */ +	case MMC_RSP_R1:    /* R1, R1b, R5, R6, R7 */ +		cmddata |= MMCCMD_RSPFMT_R1567; +		break; +	case MMC_RSP_R2: +		cmddata |= MMCCMD_RSPFMT_R2; +		break; +	case MMC_RSP_R3: /* R3, R4 */ +		cmddata |= MMCCMD_RSPFMT_R3; +		break; +	} + +	set_val(®s->mmcim, 0); + +	if (data) { +		/* clear previous data transfer if any and set new one */ +		bytes_left = (data->blocksize * data->blocks); + +		/* Reset FIFO - Always use 32 byte fifo threshold */ +		set_val(®s->mmcfifoctl, +				(MMCFIFOCTL_FIFOLEV | MMCFIFOCTL_FIFORST)); + +		if (host->version == MMC_CTLR_VERSION_2) +			cmddata |= MMCCMD_DMATRIG; + +		cmddata |= MMCCMD_WDATX; +		if (data->flags == MMC_DATA_READ) { +			set_val(®s->mmcfifoctl, MMCFIFOCTL_FIFOLEV); +		} else if (data->flags == MMC_DATA_WRITE) { +			set_val(®s->mmcfifoctl, +					(MMCFIFOCTL_FIFOLEV | +					 MMCFIFOCTL_FIFODIR)); +			cmddata |= MMCCMD_DTRW; +		} + +		set_val(®s->mmctod, 0xFFFF); +		set_val(®s->mmcnblk, (data->blocks & MMCNBLK_NBLK_MASK)); +		set_val(®s->mmcblen, (data->blocksize & MMCBLEN_BLEN_MASK)); + +		if (data->flags == MMC_DATA_WRITE) { +			uint val; +			data_buf = (char *)data->src; +			/* For write, fill FIFO with data before issue of CMD */ +			for (i = 0; (i < fifo_words) && bytes_left; i++) { +				memcpy((char *)&val, data_buf, 4); +				set_val(®s->mmcdxr, val); +				data_buf += 4; +				bytes_left -= 4; +			} +		} +	} else { +		set_val(®s->mmcblen, 0); +		set_val(®s->mmcnblk, 0); +	} + +	set_val(®s->mmctor, 0x1FFF); + +	/* Send the command */ +	set_val(®s->mmcarghl, cmd->cmdarg); +	set_val(®s->mmccmd, cmddata); + +	status_rdy = MMCST0_RSPDNE; +	status_err = (MMCST0_TOUTRS | MMCST0_TOUTRD | +			MMCST0_CRCWR | MMCST0_CRCRD); +	if (cmd->resp_type & MMC_RSP_CRC) +		status_err |= MMCST0_CRCRS; + +	mmcstatus = get_val(®s->mmcst0); +	err = dmmc_check_status(regs, &mmcstatus, status_rdy, status_err); +	if (err) +		return err; + +	/* For R1b wait for busy done */ +	if (cmd->resp_type == MMC_RSP_R1b) +		dmmc_busy_wait(regs); + +	/* Collect response from controller for specific commands */ +	if (mmcstatus & MMCST0_RSPDNE) { +		/* Copy the response to the response buffer */ +		if (cmd->resp_type & MMC_RSP_136) { +			cmd->response[0] = get_val(®s->mmcrsp67); +			cmd->response[1] = get_val(®s->mmcrsp45); +			cmd->response[2] = get_val(®s->mmcrsp23); +			cmd->response[3] = get_val(®s->mmcrsp01); +		} else if (cmd->resp_type & MMC_RSP_PRESENT) { +			cmd->response[0] = get_val(®s->mmcrsp67); +		} +	} + +	if (data == NULL) +		return 0; + +	if (data->flags == MMC_DATA_READ) { +		/* check for DATDNE along with DRRDY as the controller might +		 * set the DATDNE without DRRDY for smaller transfers with +		 * less than FIFO threshold bytes +		 */ +		status_rdy = MMCST0_DRRDY | MMCST0_DATDNE; +		status_err = MMCST0_TOUTRD | MMCST0_CRCRD; +		data_buf = data->dest; +	} else { +		status_rdy = MMCST0_DXRDY | MMCST0_DATDNE; +		status_err = MMCST0_CRCWR; +	} + +	/* Wait until all of the blocks are transferred */ +	while (bytes_left) { +		err = dmmc_check_status(regs, &mmcstatus, status_rdy, +				status_err); +		if (err) +			return err; + +		if (data->flags == MMC_DATA_READ) { +			/* +			 * MMC controller sets the Data receive ready bit +			 * (DRRDY) in MMCST0 even before the entire FIFO is +			 * full. This results in erratic behavior if we start +			 * reading the FIFO soon after DRRDY.  Wait for the +			 * FIFO full bit in MMCST1 for proper FIFO clearing. +			 */ +			if (bytes_left > fifo_bytes) +				dmmc_wait_fifo_status(regs, 0x4a); +			else if (bytes_left == fifo_bytes) +				dmmc_wait_fifo_status(regs, 0x40); + +			for (i = 0; bytes_left && (i < fifo_words); i++) { +				cmddata = get_val(®s->mmcdrr); +				memcpy(data_buf, (char *)&cmddata, 4); +				data_buf += 4; +				bytes_left -= 4; +			} +		} else { +			/* +			 * MMC controller sets the Data transmit ready bit +			 * (DXRDY) in MMCST0 even before the entire FIFO is +			 * empty. This results in erratic behavior if we start +			 * writing the FIFO soon after DXRDY.  Wait for the +			 * FIFO empty bit in MMCST1 for proper FIFO clearing. +			 */ +			dmmc_wait_fifo_status(regs, MMCST1_FIFOEMP); +			for (i = 0; bytes_left && (i < fifo_words); i++) { +				memcpy((char *)&cmddata, data_buf, 4); +				set_val(®s->mmcdxr, cmddata); +				data_buf += 4; +				bytes_left -= 4; +			} +			dmmc_busy_wait(regs); +		} +	} + +	err = dmmc_check_status(regs, &mmcstatus, MMCST0_DATDNE, status_err); +	if (err) +		return err; + +	return 0; +} + +/* Initialize Davinci MMC controller */ +static int dmmc_init(struct mmc *mmc) +{ +	struct davinci_mmc *host = mmc->priv; +	struct davinci_mmc_regs *regs = host->reg_base; + +	/* Clear status registers explicitly - soft reset doesn't clear it +	 * If Uboot is invoked from UBL with SDMMC Support, the status +	 * registers can have uncleared bits +	 */ +	get_val(®s->mmcst0); +	get_val(®s->mmcst1); + +	/* Hold software reset */ +	set_bit(®s->mmcctl, MMCCTL_DATRST); +	set_bit(®s->mmcctl, MMCCTL_CMDRST); +	udelay(10); + +	set_val(®s->mmcclk, 0x0); +	set_val(®s->mmctor, 0x1FFF); +	set_val(®s->mmctod, 0xFFFF); + +	/* Clear software reset */ +	clear_bit(®s->mmcctl, MMCCTL_DATRST); +	clear_bit(®s->mmcctl, MMCCTL_CMDRST); + +	udelay(10); + +	/* Reset FIFO - Always use the maximum fifo threshold */ +	set_val(®s->mmcfifoctl, (MMCFIFOCTL_FIFOLEV | MMCFIFOCTL_FIFORST)); +	set_val(®s->mmcfifoctl, MMCFIFOCTL_FIFOLEV); + +	return 0; +} + +/* Set buswidth or clock as indicated by the GENERIC_MMC framework */ +static void dmmc_set_ios(struct mmc *mmc) +{ +	struct davinci_mmc *host = mmc->priv; +	struct davinci_mmc_regs *regs = host->reg_base; + +	/* Set the bus width */ +	if (mmc->bus_width == 4) +		set_bit(®s->mmcctl, MMCCTL_WIDTH_4_BIT); +	else +		clear_bit(®s->mmcctl, MMCCTL_WIDTH_4_BIT); + +	/* Set clock speed */ +	if (mmc->clock) +		dmmc_set_clock(mmc, mmc->clock); +} + +/* Called from board_mmc_init during startup. Can be called multiple times + * depending on the number of slots available on board and controller + */ +int davinci_mmc_init(bd_t *bis, struct davinci_mmc *host) +{ +	struct mmc *mmc; + +	mmc = malloc(sizeof(struct mmc)); +	memset(mmc, 0, sizeof(struct mmc)); + +	sprintf(mmc->name, "davinci"); +	mmc->priv = host; +	mmc->send_cmd = dmmc_send_cmd; +	mmc->set_ios = dmmc_set_ios; +	mmc->init = dmmc_init; + +	mmc->f_min = 200000; +	mmc->f_max = 25000000; +	mmc->voltages = host->voltages; +	mmc->host_caps = host->host_caps; + +#ifdef CONFIG_MMC_MBLOCK +	mmc->b_max = DAVINCI_MAX_BLOCKS; +#endif +	mmc_register(mmc); + +	return 0; +} + diff --git a/include/mmc.h b/include/mmc.h index 74c0b1d0e..fcd0fd1de 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -274,6 +274,9 @@ struct mmc {  			struct mmc_cmd *cmd, struct mmc_data *data);  	void (*set_ios)(struct mmc *mmc);  	int (*init)(struct mmc *mmc); +#ifdef CONFIG_MMC_MBLOCK +	uint b_max; +#endif  };  int mmc_register(struct mmc *mmc); |