2293 lines
		
	
	
		
			58 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			2293 lines
		
	
	
		
			58 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/*
 | 
						|
 *  driver/mmc/nvt_ivot_mmc.c
 | 
						|
 *
 | 
						|
 *  Author:	Howard Chang
 | 
						|
 *  Created:	Feb 01, 2019
 | 
						|
 *  Copyright:	Novatek Inc.
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
#include <asm/io.h>
 | 
						|
#include "common.h"
 | 
						|
#include <errno.h>
 | 
						|
#include <dm.h>
 | 
						|
#include <command.h>
 | 
						|
#include <mmc.h>
 | 
						|
#include <malloc.h>
 | 
						|
#include <asm/gpio.h>
 | 
						|
#include "nvt_ivot_mmc.h"
 | 
						|
 | 
						|
#ifdef CONFIG_TARGET_NA51055
 | 
						|
#include <asm/arch/na51055_regs.h>
 | 
						|
#else
 | 
						|
#ifdef CONFIG_TARGET_NA51089
 | 
						|
#include <asm/arch/na51089_regs.h>
 | 
						|
#else
 | 
						|
#if (defined(CONFIG_TARGET_NA51090) || defined(CONFIG_TARGET_NA51090_A64))
 | 
						|
#include <asm/arch/na51090_regs.h>
 | 
						|
#elif (defined(CONFIG_TARGET_NA51102) || defined(CONFIG_TARGET_NA51102_A64))
 | 
						|
#include <asm/arch/na51102_regs.h>
 | 
						|
#elif (defined(CONFIG_TARGET_NA51103) || defined(CONFIG_TARGET_NA51103_A64))
 | 
						|
#include <asm/arch/na51103_regs.h>
 | 
						|
#else
 | 
						|
#include <asm/arch/na51000_regs.h>
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
#include <asm/nvt-common/nvt_types.h>
 | 
						|
#include <asm/nvt-common/nvt_common.h>
 | 
						|
#include <linux/libfdt.h>
 | 
						|
//#define __MMC_DEBUG
 | 
						|
//668 emmc HAL APIs
 | 
						|
//#define FPGA
 | 
						|
#define mmc_resp_type (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE)
 | 
						|
#if (defined(CONFIG_TARGET_NA51000) || defined(CONFIG_TARGET_NA51090) || defined(CONFIG_TARGET_NA51090_A64) || defined(CONFIG_TARGET_NA51102) || defined(CONFIG_TARGET_NA51102_A64) || defined(CONFIG_TARGET_NA51103) || defined(CONFIG_TARGET_NA51103_A64))
 | 
						|
#define PLL_SYS_CR_REG_OFS	0xF0020040
 | 
						|
#else
 | 
						|
#define PLL_SYS_CR_REG_OFS	0xF002003C
 | 
						|
#endif
 | 
						|
 | 
						|
#if (defined(CONFIG_TARGET_NA51090) || defined(CONFIG_TARGET_NA51090_A64) || defined(CONFIG_TARGET_NA51102) || defined(CONFIG_TARGET_NA51102_A64) || defined(CONFIG_TARGET_NA51103) || defined(CONFIG_TARGET_NA51103_A64))
 | 
						|
#define SDIO_MASK		0x7FF
 | 
						|
#define SDIO2_MASK		0x7FF0000
 | 
						|
#else
 | 
						|
#define SDIO_MASK		0x7FF
 | 
						|
#define SDIO2_MASK		0x7FF000
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef CONFIG_NVT_FPGA_EMULATION
 | 
						|
#define FPGA_SDIO_SRCCLK	12000000
 | 
						|
#else
 | 
						|
#define FPGA_SDIO_SRCCLK	192000000
 | 
						|
#endif
 | 
						|
 | 
						|
int mmc_nvt_start_command(struct mmc_nvt_host *host);
 | 
						|
 | 
						|
#ifdef CONFIG_DM_MMC
 | 
						|
/* Novatek IVOT MMC board definitions */
 | 
						|
struct nvt_mmc_plat
 | 
						|
{
 | 
						|
	struct mmc_config cfg;
 | 
						|
	struct mmc mmc;
 | 
						|
};
 | 
						|
#endif
 | 
						|
 | 
						|
static u32 default_pad_driving[SDIO_MAX_MODE_DRIVING] = {20, 15, 15, 20, 15, 15, 30, 25, 25, 40, 30, 30};
 | 
						|
 | 
						|
static void mmc_nvt_parse_driving(struct mmc_nvt_host *host)
 | 
						|
{
 | 
						|
	/* Enable it after dts parsing ready*/
 | 
						|
	ulong fdt_addr = nvt_readl((ulong)nvt_shminfo_boot_fdt_addr);
 | 
						|
	int nodeoffset;
 | 
						|
	u32 *cell = NULL;
 | 
						|
	char path[20] = {0};
 | 
						|
	int i;
 | 
						|
 | 
						|
	if (host->id == SDIO_HOST_ID_1) {
 | 
						|
		sprintf(path,"/mmc@%x",IOADDR_SDIO_REG_BASE);
 | 
						|
	} else if (host->id == SDIO_HOST_ID_2) {
 | 
						|
		sprintf(path,"/mmc@%x",IOADDR_SDIO2_REG_BASE);
 | 
						|
	} else if (host->id == SDIO_HOST_ID_3) {
 | 
						|
		sprintf(path,"/mmc@%x",IOADDR_SDIO3_REG_BASE);
 | 
						|
	}
 | 
						|
 | 
						|
	nodeoffset = fdt_path_offset((const void*)fdt_addr, path);
 | 
						|
 | 
						|
	cell = (u32*)fdt_getprop((const void*)fdt_addr, nodeoffset, "max-frequency", NULL);
 | 
						|
 | 
						|
	if (cell > 0) {
 | 
						|
		host->mmc_default_clk = __be32_to_cpu(cell[0]);
 | 
						|
	}
 | 
						|
 | 
						|
	cell = (u32*)fdt_getprop((const void*)fdt_addr, nodeoffset, "driving", NULL);
 | 
						|
 | 
						|
	if (cell < 0) {
 | 
						|
		for (i = 0; i < SDIO_MAX_MODE_DRIVING; i++) {
 | 
						|
			host->pad_driving[i] = default_pad_driving[i];
 | 
						|
		}
 | 
						|
		printf("\n%s: use default driving table\n", __func__);
 | 
						|
	} else {
 | 
						|
		for (i = 0; i < SDIO_MAX_MODE_DRIVING; i++) {
 | 
						|
			host->pad_driving[i] = __be32_to_cpu(cell[i]);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	cell = (u32*)fdt_getprop((const void*)fdt_addr, nodeoffset, "mmc-hs200-1_8v", NULL);
 | 
						|
	if (cell > 0)
 | 
						|
		host->ext_caps |= MMC_MODE_HS200;
 | 
						|
 | 
						|
	cell = (u32*)fdt_getprop((const void*)fdt_addr, nodeoffset, "indly_sel", NULL);
 | 
						|
	if (cell > 0) {
 | 
						|
		host->indly_sel = __be32_to_cpu(cell[0]);
 | 
						|
	} else {
 | 
						|
		host->indly_sel = -1;
 | 
						|
	}
 | 
						|
 | 
						|
	if (host->id == SDIO_HOST_ID_3) {
 | 
						|
		sprintf(path,"/top@%x/sdio3",IOADDR_TOP_REG_BASE);
 | 
						|
		nodeoffset = fdt_path_offset((const void*)fdt_addr, path);
 | 
						|
		cell = (u32*)fdt_getprop((const void*)fdt_addr, nodeoffset, "pinmux", NULL);
 | 
						|
		host->pinmux_value = __be32_to_cpu(cell[0]);
 | 
						|
 | 
						|
		if (host->pinmux_value & PIN_SDIO_CFG_8BITS)
 | 
						|
			host->enable_8bits = 1;
 | 
						|
		else
 | 
						|
			host->enable_8bits = 0;
 | 
						|
	}
 | 
						|
 | 
						|
#ifdef CONFIG_TARGET_NA51089
 | 
						|
	if (host->id == SDIO_HOST_ID_2) {
 | 
						|
		sprintf(path,"/top@%x/sdio2",IOADDR_TOP_REG_BASE);
 | 
						|
		nodeoffset = fdt_path_offset((const void*)fdt_addr, path);
 | 
						|
		cell = (u32*)fdt_getprop((const void*)fdt_addr, nodeoffset, "pinmux", NULL);
 | 
						|
		host->pinmux_value = __be32_to_cpu(cell[0]);
 | 
						|
	}
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
//=============================================================================================================
 | 
						|
 | 
						|
/*
 | 
						|
	Get SDIO controller register.
 | 
						|
 | 
						|
	@param[in] host			host data structure
 | 
						|
	@param[in] offset       register offset in SDIO controller (word alignment)
 | 
						|
 | 
						|
	@return register value
 | 
						|
*/
 | 
						|
static REGVALUE sdiohost_getreg(struct mmc_nvt_host *host, u32 offset)
 | 
						|
{
 | 
						|
	return readl(host->base + offset);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Set SDIO controller register.
 | 
						|
 | 
						|
	@param[in] host		host data structure
 | 
						|
	@param[in] offset   offset in SDIO controller (word alignment)
 | 
						|
	@param[in] value    register value
 | 
						|
 | 
						|
	@return void
 | 
						|
*/
 | 
						|
static void sdiohost_setreg(struct mmc_nvt_host *host, u32 offset, REGVALUE value)
 | 
						|
{
 | 
						|
	writel(value, host->base + offset);
 | 
						|
}
 | 
						|
 | 
						|
#define RESET_TIMEOUT	10000
 | 
						|
static void sdiohost_setphyrst(struct mmc_nvt_host *host)
 | 
						|
{
 | 
						|
	union SDIO_PHY_REG phyreg, phyreg_read;
 | 
						|
	u8 i;
 | 
						|
 | 
						|
	phyreg.reg = sdiohost_getreg(host, SDIO_PHY_REG_OFS);
 | 
						|
	phyreg.bit.PHY_SW_RST = 1;
 | 
						|
	sdiohost_setreg(host, SDIO_PHY_REG_OFS, phyreg.reg);
 | 
						|
	while (1)
 | 
						|
	{
 | 
						|
		phyreg_read.reg = sdiohost_getreg(host, SDIO_PHY_REG_OFS);
 | 
						|
		if ((phyreg_read.bit.PHY_SW_RST == 0) || (i == RESET_TIMEOUT))
 | 
						|
			break;
 | 
						|
 | 
						|
		i++;
 | 
						|
	}
 | 
						|
 | 
						|
	if (i == RESET_TIMEOUT)
 | 
						|
		printf("phy reset timeout\n");
 | 
						|
}
 | 
						|
 | 
						|
static void sdiohost_setphysample(struct mmc_nvt_host *host, BOOL internal, BOOL before)
 | 
						|
{
 | 
						|
	union SDIO_DLY0_REG dly0_reg;
 | 
						|
 | 
						|
	dly0_reg.reg = sdiohost_getreg(host, SDIO_DLY0_REG_OFS);
 | 
						|
	dly0_reg.bit.SRC_CLK_SEL = internal;    // 0: from pad, 1: from internal
 | 
						|
	dly0_reg.bit.PAD_CLK_SEL = before;      // 0: after pad, 1: before pad
 | 
						|
 | 
						|
	sdiohost_setreg(host, SDIO_DLY0_REG_OFS, dly0_reg.reg);
 | 
						|
}
 | 
						|
 | 
						|
#if 0
 | 
						|
static void sdiohost_setphyclkoutdly(struct mmc_nvt_host *host, u32 dly_setting)
 | 
						|
{
 | 
						|
	union SDIO_CLOCK_CTRL2_REG clk_crtl_reg;
 | 
						|
 | 
						|
	clk_crtl_reg.reg = sdiohost_getreg(host, SDIO_CLOCK_CTRL2_REG_OFS);
 | 
						|
 | 
						|
	clk_crtl_reg.bit.OUTDLY_SEL = dly_setting;
 | 
						|
 | 
						|
	sdiohost_setreg(host, SDIO_CLOCK_CTRL2_REG_OFS, clk_crtl_reg.reg);
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
static void sdiohost_setphyclkindly(struct mmc_nvt_host *host, u32 dly_setting)
 | 
						|
{
 | 
						|
	union SDIO_CLOCK_CTRL2_REG clk_crtl_reg;
 | 
						|
 | 
						|
	clk_crtl_reg.reg = sdiohost_getreg(host, SDIO_CLOCK_CTRL2_REG_OFS);
 | 
						|
 | 
						|
	clk_crtl_reg.bit.INDLY_SEL = dly_setting;
 | 
						|
 | 
						|
	sdiohost_setreg(host, SDIO_CLOCK_CTRL2_REG_OFS, clk_crtl_reg.reg);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Set SDIO bus width.
 | 
						|
 | 
						|
	@param[in] host		host data structure
 | 
						|
	@param[in] Width    SDIO controller bus width
 | 
						|
			- @b SDIO_BUS_WIDTH1: 1 bit data bus
 | 
						|
			- @b SDIO_BUS_WIDTH4: 4 bits data bus
 | 
						|
			- @b SDIO_BUS_WIDTH8: 8 bits data bus
 | 
						|
 | 
						|
	@return void
 | 
						|
*/
 | 
						|
void sdiohost_setbuswidth(struct mmc_nvt_host *host, u32 width)
 | 
						|
{
 | 
						|
	union SDIO_BUS_WIDTH_REG widthreg;
 | 
						|
 | 
						|
	widthreg.reg = 0;
 | 
						|
	widthreg.bit.BUS_WIDTH = width;
 | 
						|
	sdiohost_setreg(host, SDIO_BUS_WIDTH_REG_OFS, widthreg.reg);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Set SDIO clock enable or disable
 | 
						|
 | 
						|
	When set to TRUE, SD controller will output SD clock to SD card.
 | 
						|
	When set to FALSE, SD controller will not output SD clock to SD card.
 | 
						|
 | 
						|
	@param[in] host data structure
 | 
						|
	@param[in] enableflag   enable clock output
 | 
						|
				- @b TRUE: enable SD clock output
 | 
						|
				- @b FALSE: disable SD clock output
 | 
						|
 | 
						|
	@return void
 | 
						|
*/
 | 
						|
void sdiohost_enclkout(struct mmc_nvt_host *host, BOOL enableflag)
 | 
						|
{
 | 
						|
	union SDIO_CLOCK_CTRL_REG clkctrlreg;
 | 
						|
 | 
						|
	clkctrlreg.reg = sdiohost_getreg(host, SDIO_CLOCK_CTRL_REG_OFS);
 | 
						|
 | 
						|
	if (enableflag == TRUE) {
 | 
						|
		/* enabke SDIO CLK */
 | 
						|
		clkctrlreg.bit.CLK_DIS = 0;
 | 
						|
	} else {
 | 
						|
		/* disable SDIO CLK */
 | 
						|
		clkctrlreg.bit.CLK_DIS = 1;
 | 
						|
	}
 | 
						|
 | 
						|
	sdiohost_setreg(host, SDIO_CLOCK_CTRL_REG_OFS, clkctrlreg.reg);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Set SDIO CLK card type.
 | 
						|
 | 
						|
	@param[in] host data structure
 | 
						|
	@param[in] brisingsample    SDIO controller input sampling timing
 | 
						|
			- @b TRUE: sample at rising edge
 | 
						|
			- @b FALSE :sample at falling edge
 | 
						|
 | 
						|
	@return void
 | 
						|
*/
 | 
						|
void sdiohost_setclktype(struct mmc_nvt_host *host, BOOL brisingsample)
 | 
						|
{
 | 
						|
	union SDIO_CLOCK_CTRL_REG clkctrlreg;
 | 
						|
 | 
						|
	clkctrlreg.reg = sdiohost_getreg(host, SDIO_CLOCK_CTRL_REG_OFS);
 | 
						|
 | 
						|
	if (brisingsample)
 | 
						|
		clkctrlreg.bit.CLK_SD = 1;
 | 
						|
	else
 | 
						|
		clkctrlreg.bit.CLK_SD = 0;
 | 
						|
 | 
						|
	sdiohost_setreg(host, SDIO_CLOCK_CTRL_REG_OFS, clkctrlreg.reg);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Set SDIO CLK cmd type.
 | 
						|
 | 
						|
	@param[in] host data sturcture
 | 
						|
	@param[in] brisingsample    SDIO controller input sampling timing
 | 
						|
			- @b TRUE: sample at rising edge
 | 
						|
			- @b FALSE :sample at falling edge
 | 
						|
 | 
						|
	@return void
 | 
						|
*/
 | 
						|
void sdiohost_setclkcmdtype(struct mmc_nvt_host *host, BOOL brisingsample)
 | 
						|
{
 | 
						|
	union SDIO_CLOCK_CTRL_REG clkctrlreg;
 | 
						|
 | 
						|
	clkctrlreg.reg = sdiohost_getreg(host, SDIO_CLOCK_CTRL_REG_OFS);
 | 
						|
 | 
						|
	if (brisingsample)
 | 
						|
		clkctrlreg.bit.CLK_SD_CMD = 1;
 | 
						|
	else
 | 
						|
		clkctrlreg.bit.CLK_SD_CMD = 0;
 | 
						|
 | 
						|
	sdiohost_setreg(host, SDIO_CLOCK_CTRL_REG_OFS, clkctrlreg.reg);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
    Get module clock rate
 | 
						|
 | 
						|
    Get module clock rate, one module at a time.
 | 
						|
 | 
						|
    @param[in] num      Module ID(PLL_CLKSEL_*), one module at a time.
 | 
						|
                          Please refer to pll.h
 | 
						|
 | 
						|
    @return Moudle clock rate(PLL_CLKSEL_*_*), please refer to pll.h
 | 
						|
*/
 | 
						|
u32 pll_get_sdioclock_rate(int id)
 | 
						|
{
 | 
						|
	REGVALUE    regdata;
 | 
						|
 | 
						|
	if (id != SDIO_HOST_ID_3)
 | 
						|
		HAL_READ_UINT32(PLL_SYS_CR_REG_OFS, regdata);
 | 
						|
	else
 | 
						|
		HAL_READ_UINT32(PLL_SYS_CR_REG_OFS + 0x4, regdata);
 | 
						|
 | 
						|
	if (id != SDIO_HOST_ID_2)
 | 
						|
		regdata &= SDIO_MASK;
 | 
						|
	else
 | 
						|
		regdata &= SDIO2_MASK;
 | 
						|
 | 
						|
	return (u32)regdata;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
    Set module clock rate
 | 
						|
 | 
						|
    Set module clock rate, one module at a time.
 | 
						|
 | 
						|
	@param[in] id		SDIO channel
 | 
						|
    @param[in] num      Module ID(PLL_CLKSEL_*), one module at a time.
 | 
						|
                          Please refer to pll.h
 | 
						|
    @param[in] value    Moudle clock rate(PLL_CLKSEL_*_*), please refer to pll.h
 | 
						|
 | 
						|
    @return void
 | 
						|
*/
 | 
						|
void pll_set_sdioclock_rate(int id, u32 value)
 | 
						|
{
 | 
						|
	REGVALUE regdata;
 | 
						|
 | 
						|
	if (id != SDIO_HOST_ID_3)
 | 
						|
		HAL_READ_UINT32(PLL_SYS_CR_REG_OFS, regdata);
 | 
						|
	else
 | 
						|
		HAL_READ_UINT32(PLL_SYS_CR_REG_OFS + 0x4, regdata);
 | 
						|
 | 
						|
	if (id != SDIO_HOST_ID_2) {
 | 
						|
		regdata &= ~SDIO_MASK;
 | 
						|
		regdata |= value;
 | 
						|
	} else {
 | 
						|
		regdata &= ~SDIO2_MASK;
 | 
						|
		regdata |= value << 12;
 | 
						|
	}
 | 
						|
 | 
						|
	if (id != SDIO_HOST_ID_3)
 | 
						|
		HAL_WRITE_UINT32(PLL_SYS_CR_REG_OFS, regdata);
 | 
						|
	else
 | 
						|
		HAL_WRITE_UINT32(PLL_SYS_CR_REG_OFS + 0x4, regdata);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Set bus clock.
 | 
						|
 | 
						|
	@param[in] id		SDIO channel
 | 
						|
	@param[in] uiclock  SD bus clock in Hz
 | 
						|
 | 
						|
	@return void
 | 
						|
*/
 | 
						|
void nvt_clk_set_rate(int id, u32 uiclock)
 | 
						|
{
 | 
						|
	u32 divider, src_clk = FPGA_SDIO_SRCCLK;
 | 
						|
 | 
						|
	divider = (src_clk + uiclock-1)/uiclock;
 | 
						|
	if (!divider)
 | 
						|
		divider = 1;
 | 
						|
 | 
						|
	pll_set_sdioclock_rate(id, divider-1);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Set SDIO bus clock.
 | 
						|
 | 
						|
	@param[in] host data structure
 | 
						|
	@param[in] uiclock  SD bus clock in Hz
 | 
						|
 | 
						|
	@return void
 | 
						|
*/
 | 
						|
void sdiohost_setbusclk(struct mmc_nvt_host *host, u32 uiclock, u32 *ns)
 | 
						|
{
 | 
						|
	union SDIO_CLOCK_CTRL_REG clkctrlreg;
 | 
						|
 | 
						|
	/* Disable SDIO clk */
 | 
						|
	sdiohost_enclkout(host, FALSE);
 | 
						|
 | 
						|
	if (uiclock == 0) {
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	nvt_clk_set_rate(host->id, uiclock);
 | 
						|
 | 
						|
	if (ns)
 | 
						|
		*ns = (1000000) / (uiclock/1000);
 | 
						|
 | 
						|
	/* Enable SDIO clk */
 | 
						|
	sdiohost_enclkout(host, TRUE);
 | 
						|
 | 
						|
	clkctrlreg.reg = sdiohost_getreg(host, SDIO_CLOCK_CTRL_REG_OFS);
 | 
						|
 | 
						|
	clkctrlreg.bit.DLY_ACT = 1;
 | 
						|
 | 
						|
	sdiohost_setreg(host, SDIO_CLOCK_CTRL_REG_OFS, clkctrlreg.reg);
 | 
						|
 | 
						|
	sdiohost_setclktype(host, TRUE);
 | 
						|
	sdiohost_setclkcmdtype(host, TRUE);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Get SDIO bus clock.
 | 
						|
 | 
						|
	@return unit of Hz
 | 
						|
*/
 | 
						|
static u32 sdiohost_getbusclk(int id)
 | 
						|
{
 | 
						|
	u32 uisourceclock;
 | 
						|
	u32 uiclockdivider;
 | 
						|
 | 
						|
	uisourceclock = FPGA_SDIO_SRCCLK;
 | 
						|
 | 
						|
	uiclockdivider = pll_get_sdioclock_rate(id);
 | 
						|
 | 
						|
	return uisourceclock / (uiclockdivider + 1);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Get SDIO Busy or not
 | 
						|
 | 
						|
	@return TRUE: ready
 | 
						|
		FALSE: busy
 | 
						|
*/
 | 
						|
BOOL sdiohost_getrdy(struct mmc_nvt_host *host)
 | 
						|
{
 | 
						|
	union SDIO_BUS_STATUS_REG stsreg;
 | 
						|
 | 
						|
	stsreg.reg = sdiohost_getreg(host, SDIO_BUS_STATUS_REG_OFS);
 | 
						|
 | 
						|
	return stsreg.bit.CARD_READY;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Reset SDIO host controller.
 | 
						|
 | 
						|
	@return void
 | 
						|
*/
 | 
						|
void sdiohost_reset(struct mmc_nvt_host *host)
 | 
						|
{
 | 
						|
	union SDIO_CMD_REG cmdreg;
 | 
						|
 | 
						|
	cmdreg.reg = sdiohost_getreg(host, SDIO_CMD_REG_OFS);
 | 
						|
	cmdreg.bit.SDC_RST = 1;
 | 
						|
	sdiohost_setreg(host, SDIO_CMD_REG_OFS, cmdreg.reg);
 | 
						|
 | 
						|
	while (1) {
 | 
						|
		cmdreg.reg = sdiohost_getreg(host, SDIO_CMD_REG_OFS);
 | 
						|
 | 
						|
		if (cmdreg.bit.SDC_RST == 0)
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	if (host->mmc_input_clk > 1000000)
 | 
						|
		udelay(1);
 | 
						|
	else
 | 
						|
		udelay((1000000/ host->mmc_input_clk) + 1);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Reset SDIO controller data state machine.
 | 
						|
 | 
						|
	@return void
 | 
						|
*/
 | 
						|
void sdiohost_resetdata(struct mmc_nvt_host *host)
 | 
						|
{
 | 
						|
	union SDIO_DATA_CTRL_REG    datactrlreg;
 | 
						|
	union SDIO_FIFO_CONTROL_REG fifoctrlreg;
 | 
						|
	union SDIO_DLY1_REG dlyreg;
 | 
						|
	union SDIO_PHY_REG  phyreg;
 | 
						|
	union SDIO_PHY_REG  phyreg_read;
 | 
						|
	union SDIO_FIFO_SWITCH_REG  fifoswitch;
 | 
						|
 | 
						|
	/* //#NT#Fix SDIO data state machine abnormal when DATA CRC/Timeout
 | 
						|
	occurs before FIFO count complete */
 | 
						|
	union SDIO_STATUS_REG	stsreg;
 | 
						|
 | 
						|
	/* SDIO bug: force to clear data end status to exit
 | 
						|
	waiting data end state*/
 | 
						|
	stsreg.reg          = 0;
 | 
						|
	stsreg.bit.DATA_END = 1;
 | 
						|
	sdiohost_setreg(host, SDIO_STATUS_REG_OFS, stsreg.reg);
 | 
						|
 | 
						|
 | 
						|
	fifoctrlreg.reg = 0;
 | 
						|
	sdiohost_setreg(host, SDIO_FIFO_CONTROL_REG_OFS, fifoctrlreg.reg);
 | 
						|
 | 
						|
	while (1) {
 | 
						|
		fifoctrlreg.reg = sdiohost_getreg(host, SDIO_FIFO_CONTROL_REG_OFS);
 | 
						|
		if (fifoctrlreg.bit.FIFO_EN == 0)
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	datactrlreg.reg = sdiohost_getreg(host, SDIO_DATA_CTRL_REG_OFS);
 | 
						|
	datactrlreg.bit.DATA_EN = 0;
 | 
						|
	sdiohost_setreg(host, SDIO_DATA_CTRL_REG_OFS, datactrlreg.reg);
 | 
						|
 | 
						|
	/* Fix SDIO data state machine abnormal when DATA
 | 
						|
	CRC/Timeout occurs before FIFO count complete */
 | 
						|
	/* Do software reset to reset SD state machine */
 | 
						|
	sdiohost_reset(host);
 | 
						|
 | 
						|
	/* patch begin for sd write hang-up or write byte access error */
 | 
						|
	fifoswitch.reg = sdiohost_getreg(host, SDIO_FIFO_SWITCH_REG_OFS);
 | 
						|
	fifoswitch.bit.FIFO_SWITCH_DLY = 1;
 | 
						|
	sdiohost_setreg(host, SDIO_FIFO_SWITCH_REG_OFS, fifoswitch.reg);
 | 
						|
	/* patch end for sd write hang-up or write byte access error */
 | 
						|
 | 
						|
	phyreg.reg = sdiohost_getreg(host, SDIO_PHY_REG_OFS);
 | 
						|
	phyreg.bit.PHY_SW_RST = 1;
 | 
						|
	phyreg.bit.BLK_FIFO_EN = 1;
 | 
						|
	sdiohost_setreg(host, SDIO_PHY_REG_OFS, phyreg.reg);
 | 
						|
	while (1)
 | 
						|
	{
 | 
						|
		phyreg_read.reg = sdiohost_getreg(host, SDIO_PHY_REG_OFS);
 | 
						|
		if (phyreg_read.bit.PHY_SW_RST == 0)
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	dlyreg.reg = sdiohost_getreg(host, SDIO_DLY1_REG_OFS);
 | 
						|
	dlyreg.bit.DATA_READ_DLY = 2;
 | 
						|
	dlyreg.bit.DET_READ_DLY = 2;
 | 
						|
	sdiohost_setreg(host, SDIO_DLY1_REG_OFS, dlyreg.reg);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Set SDIO controller data timeout.
 | 
						|
 | 
						|
	@param[in] timeout  time out value between data blocks (unit: SD clock)
 | 
						|
 | 
						|
	@return void
 | 
						|
*/
 | 
						|
void sdiohost_setdatatimeout(struct mmc_nvt_host *host, u32 timeout)
 | 
						|
{
 | 
						|
	union SDIO_DATA_TIMER_REG timerreg;
 | 
						|
 | 
						|
	timerreg.bit.Timeout = timeout;
 | 
						|
	sdiohost_setreg(host, SDIO_DATA_TIMER_REG_OFS, timerreg.reg);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Set PAD driving Sink
 | 
						|
 | 
						|
	@param[in] name driving sink name
 | 
						|
	@param[in] paddriving driving current
 | 
						|
 | 
						|
	@return
 | 
						|
		- @b E_OK: sucess
 | 
						|
		- @b Else: fail
 | 
						|
*/
 | 
						|
 | 
						|
static int pad_setdrivingsink(u32 name, u32 paddriving)
 | 
						|
{
 | 
						|
	unsigned long padreg;
 | 
						|
	unsigned long dwoffset = 0x0, bitoffset = 0x0, bitmask = 0x0;
 | 
						|
	unsigned long driving = paddriving;
 | 
						|
 | 
						|
	if (name & PAD_DS_GROUP_40) {
 | 
						|
		dwoffset  = (PAD_DS10_REG_OFS - PAD_DS_REG_OFS);
 | 
						|
		dwoffset += (((name & PAD_DS_GPIO_BASE_MASK)>>5)<<2);
 | 
						|
		bitoffset = name & 0x1F;
 | 
						|
		bitmask = 0x07;
 | 
						|
		driving &= PAD_DS_GROUP_40_MSK;
 | 
						|
 | 
						|
		if (paddriving & PAD_DRIVINGSINK_5MA)
 | 
						|
			driving = 0;
 | 
						|
		else if (paddriving & PAD_DRIVINGSINK_10MA)
 | 
						|
			driving = 1;
 | 
						|
		else if (paddriving & PAD_DRIVINGSINK_15MA)
 | 
						|
			driving = 2;
 | 
						|
		else if (paddriving & PAD_DRIVINGSINK_20MA)
 | 
						|
			driving = 3;
 | 
						|
		else if (paddriving & PAD_DRIVINGSINK_25MA)
 | 
						|
			driving = 4;
 | 
						|
		else if (paddriving & PAD_DRIVINGSINK_30MA)
 | 
						|
			driving = 5;
 | 
						|
		else if (paddriving & PAD_DRIVINGSINK_35MA)
 | 
						|
			driving = 6;
 | 
						|
		else if (paddriving & PAD_DRIVINGSINK_40MA)
 | 
						|
			driving = 7;
 | 
						|
		else {
 | 
						|
			printf("No Valid DS value.(0x%X), PAD_DS_GROUP_40\r\n", name);
 | 
						|
			return E_PAR;
 | 
						|
		}
 | 
						|
	} else if (name & PAD_DS_GROUP_16) {
 | 
						|
#ifdef CONFIG_TARGET_NA51089
 | 
						|
		if ((name & ~PAD_DS_GROUP_MASK) >= (PAD_DS_HSIGPIO0 & ~PAD_DS_GROUP_MASK)) {
 | 
						|
			dwoffset  = (((name & PAD_DS_GPIO_BASE_MASK)>>5)<<2) + 0x28;
 | 
						|
		} else {
 | 
						|
			dwoffset  = (((name & PAD_DS_GPIO_BASE_MASK)>>5)<<2);
 | 
						|
		}
 | 
						|
		bitoffset = name & 0x1F;
 | 
						|
		bitmask   = 0x03;
 | 
						|
 | 
						|
		if (name & PAD_DS_GROUP_16) {
 | 
						|
			driving &= PAD_DS_GROUP_COMBO_MSK;
 | 
						|
 | 
						|
			if (driving == PAD_DRIVINGSINK_4MA) {
 | 
						|
				driving = 0;
 | 
						|
			} else if (driving == PAD_DRIVINGSINK_8MA) {
 | 
						|
				driving = 1;
 | 
						|
			} else if (driving == PAD_DRIVINGSINK_12MA) {
 | 
						|
				driving = 2;
 | 
						|
			} else if (driving == PAD_DRIVINGSINK_16MA) {
 | 
						|
				driving = 3;
 | 
						|
			} else {
 | 
						|
				printf("No Valid DS value.(0x%X), PAD_DS_GROUP_16\r\n", name);
 | 
						|
				return E_PAR;
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			if (driving == PAD_DRIVINGSINK_4MA) {
 | 
						|
				driving = 0;
 | 
						|
			} else if (driving == PAD_DRIVINGSINK_10MA) {
 | 
						|
				driving = 1;
 | 
						|
			} else {
 | 
						|
				printf("No Valid DS value.(0x%X), PAD_DS_GROUP_10\r\n", name);
 | 
						|
				return E_PAR;
 | 
						|
			}
 | 
						|
		}
 | 
						|
#else
 | 
						|
		dwoffset  = (((name & PAD_DS_GPIO_BASE_MASK)>>5)<<2);
 | 
						|
		bitoffset = name & 0x1F;
 | 
						|
		bitmask = 0x01;
 | 
						|
		driving &= PAD_DS_GROUP_16_MSK;
 | 
						|
 | 
						|
		if (driving & PAD_DRIVINGSINK_6MA) {
 | 
						|
			driving = 0;
 | 
						|
		} else if (driving & PAD_DRIVINGSINK_16MA) {
 | 
						|
			driving = 1;
 | 
						|
		} else {
 | 
						|
			printf("No Valid DS value.(0x%X), PAD_DS_GROUP_16/PAD_DS_GROUP_10\r\n", name);
 | 
						|
			return E_PAR;
 | 
						|
		}
 | 
						|
#endif
 | 
						|
	} else {
 | 
						|
		/* 10MA GROUP */
 | 
						|
		if (name >= PAD_DS_HSIGPIO0) {
 | 
						|
			dwoffset  = (((name & PAD_DS_GPIO_BASE_MASK)>>5)<<2) + 0x28;
 | 
						|
		} else {
 | 
						|
			dwoffset  = (((name & PAD_DS_GPIO_BASE_MASK)>>5)<<2);
 | 
						|
		}
 | 
						|
		bitoffset = name & 0x1F;
 | 
						|
		bitmask = 0x01;
 | 
						|
		driving &= PAD_DS_GROUP_10_MSK;
 | 
						|
 | 
						|
		if (driving & PAD_DRIVINGSINK_4MA) {
 | 
						|
			driving = 0;
 | 
						|
		} else if (driving & PAD_DRIVINGSINK_10MA) {
 | 
						|
			driving = 1;
 | 
						|
		} else {
 | 
						|
			return E_PAR;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	HAL_READ_UINT32(IOADDR_PAD_REG_BASE + PAD_DS_REG_OFS + dwoffset, padreg);
 | 
						|
	padreg &= ~(bitmask << bitoffset);
 | 
						|
	padreg |=  (driving << bitoffset);
 | 
						|
	HAL_WRITE_UINT32(IOADDR_PAD_REG_BASE + PAD_DS_REG_OFS + dwoffset, padreg);
 | 
						|
 | 
						|
	return E_OK;
 | 
						|
}
 | 
						|
 | 
						|
static u32 driving_xfer(u32 driving)
 | 
						|
{
 | 
						|
	u32 pad_driving;
 | 
						|
 | 
						|
	if (driving == 40)
 | 
						|
		pad_driving = PAD_DRIVINGSINK_40MA;
 | 
						|
	else if (driving == 10)
 | 
						|
		pad_driving = PAD_DRIVINGSINK_10MA;
 | 
						|
	else if (driving == 15)
 | 
						|
		pad_driving = PAD_DRIVINGSINK_15MA;
 | 
						|
	else if (driving == 20)
 | 
						|
		pad_driving = PAD_DRIVINGSINK_20MA;
 | 
						|
	else if (driving == 25)
 | 
						|
		pad_driving = PAD_DRIVINGSINK_25MA;
 | 
						|
	else if (driving == 30)
 | 
						|
		pad_driving = PAD_DRIVINGSINK_30MA;
 | 
						|
	else if (driving == 35)
 | 
						|
		pad_driving = PAD_DRIVINGSINK_35MA;
 | 
						|
	else if (driving == 16)
 | 
						|
		pad_driving = PAD_DRIVINGSINK_16MA;
 | 
						|
	else if (driving == 6)
 | 
						|
		pad_driving = PAD_DRIVINGSINK_6MA;
 | 
						|
	else if (driving == 4)
 | 
						|
		pad_driving = PAD_DRIVINGSINK_4MA;
 | 
						|
	else if (driving == 8)
 | 
						|
		pad_driving = PAD_DRIVINGSINK_8MA;
 | 
						|
	else if (driving == 12)
 | 
						|
		pad_driving = PAD_DRIVINGSINK_12MA;
 | 
						|
	else if (driving == 16)
 | 
						|
		pad_driving = PAD_DRIVINGSINK_16MA;
 | 
						|
	else
 | 
						|
		pad_driving = PAD_DRIVINGSINK_5MA;
 | 
						|
 | 
						|
	return pad_driving;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Set PAD drive/sink of clock pin for specified SDIO channel.
 | 
						|
 | 
						|
	@param[in] id       SDIO channel ID
 | 
						|
			- @b SDIO_HOST_ID_1: SDIO1
 | 
						|
			- @b SDIO_HOST_ID_2: SDIO2
 | 
						|
	@param[in] driving  desired driving value * 10, unit: mA
 | 
						|
				valid value: 50 ~ 200
 | 
						|
 | 
						|
	@return
 | 
						|
		- @b E_OK: sucess
 | 
						|
		- @b Else: fail
 | 
						|
*/
 | 
						|
static int sdiohost_setpaddriving(struct mmc_nvt_host *host, SDIO_SPEED_MODE mode)
 | 
						|
{
 | 
						|
	UINT32 data_uidriving, cmd_uidriving, clk_uidriving;
 | 
						|
 | 
						|
#ifdef CONFIG_NVT_FPGA_EMULATION
 | 
						|
	return 0;
 | 
						|
#endif
 | 
						|
 | 
						|
	if (mode == SDIO_MODE_DS) {
 | 
						|
		data_uidriving = driving_xfer(host->pad_driving[SDIO_DS_MODE_DATA]);
 | 
						|
		cmd_uidriving = driving_xfer(host->pad_driving[SDIO_DS_MODE_CMD]);
 | 
						|
		clk_uidriving = driving_xfer(host->pad_driving[SDIO_DS_MODE_CLK]);
 | 
						|
	} else if (mode == SDIO_MODE_HS) {
 | 
						|
		data_uidriving = driving_xfer(host->pad_driving[SDIO_HS_MODE_DATA]);
 | 
						|
		cmd_uidriving = driving_xfer(host->pad_driving[SDIO_HS_MODE_CMD]);
 | 
						|
		clk_uidriving = driving_xfer(host->pad_driving[SDIO_HS_MODE_CLK]);
 | 
						|
	} else if (mode == SDIO_MODE_SDR50) {
 | 
						|
		data_uidriving = driving_xfer(host->pad_driving[SDIO_SDR50_MODE_DATA]);
 | 
						|
		cmd_uidriving = driving_xfer(host->pad_driving[SDIO_SDR50_MODE_CMD]);
 | 
						|
		clk_uidriving = driving_xfer(host->pad_driving[SDIO_SDR50_MODE_CLK]);
 | 
						|
	} else {
 | 
						|
		data_uidriving = driving_xfer(host->pad_driving[SDIO_SDR104_MODE_DATA]);
 | 
						|
		cmd_uidriving = driving_xfer(host->pad_driving[SDIO_SDR104_MODE_CMD]);
 | 
						|
		clk_uidriving = driving_xfer(host->pad_driving[SDIO_SDR104_MODE_CLK]);
 | 
						|
	}
 | 
						|
 | 
						|
	if (host->id == SDIO_HOST_ID_1) {
 | 
						|
		pad_setdrivingsink(PAD_DS_CGPIO12, cmd_uidriving);
 | 
						|
		pad_setdrivingsink(PAD_DS_CGPIO13, data_uidriving);
 | 
						|
		pad_setdrivingsink(PAD_DS_CGPIO14, data_uidriving);
 | 
						|
		pad_setdrivingsink(PAD_DS_CGPIO15, data_uidriving);
 | 
						|
		pad_setdrivingsink(PAD_DS_CGPIO16, data_uidriving);
 | 
						|
		return pad_setdrivingsink(PAD_DS_CGPIO11, clk_uidriving);
 | 
						|
	} else if (host->id == SDIO_HOST_ID_2) {
 | 
						|
		pad_setdrivingsink(PAD_DS_CGPIO18, cmd_uidriving);
 | 
						|
		pad_setdrivingsink(PAD_DS_CGPIO19, data_uidriving);
 | 
						|
		pad_setdrivingsink(PAD_DS_CGPIO20, data_uidriving);
 | 
						|
		pad_setdrivingsink(PAD_DS_CGPIO21, data_uidriving);
 | 
						|
		pad_setdrivingsink(PAD_DS_CGPIO22, data_uidriving);
 | 
						|
		return pad_setdrivingsink(PAD_DS_CGPIO17, clk_uidriving);
 | 
						|
	} else {
 | 
						|
		if (host->enable_8bits) {
 | 
						|
			pad_setdrivingsink(PAD_DS_CGPIO4, data_uidriving);
 | 
						|
			pad_setdrivingsink(PAD_DS_CGPIO5, data_uidriving);
 | 
						|
			pad_setdrivingsink(PAD_DS_CGPIO6, data_uidriving);
 | 
						|
			pad_setdrivingsink(PAD_DS_CGPIO7, data_uidriving);
 | 
						|
		}
 | 
						|
		pad_setdrivingsink(PAD_DS_CGPIO0, cmd_uidriving);
 | 
						|
		pad_setdrivingsink(PAD_DS_CGPIO1, data_uidriving);
 | 
						|
		pad_setdrivingsink(PAD_DS_CGPIO2, data_uidriving);
 | 
						|
		pad_setdrivingsink(PAD_DS_CGPIO3, data_uidriving);
 | 
						|
		pad_setdrivingsink(PAD_DS_CGPIO9, data_uidriving);
 | 
						|
		return pad_setdrivingsink(PAD_DS_CGPIO8, clk_uidriving);
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Delay for SDIO module
 | 
						|
 | 
						|
	@param[in] uid the count for dummy read
 | 
						|
 | 
						|
	@return void
 | 
						|
*/
 | 
						|
void sdiohost_delayd(struct mmc_nvt_host *host, u32 uid)
 | 
						|
{
 | 
						|
	u32 i;
 | 
						|
 | 
						|
	for (i = uid; i; i--)
 | 
						|
		sdiohost_getreg(host, SDIO_CMD_REG_OFS);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Set SDIO controller block size.
 | 
						|
 | 
						|
	@param[in] host data structure
 | 
						|
 | 
						|
	@return void
 | 
						|
*/
 | 
						|
void sdiohost_setblksize(struct mmc_nvt_host *host)
 | 
						|
{
 | 
						|
	union SDIO_DATA_CTRL_REG datactrlreg;
 | 
						|
 | 
						|
	datactrlreg.reg = sdiohost_getreg(host, SDIO_DATA_CTRL_REG_OFS);
 | 
						|
	datactrlreg.bit.BLK_SIZE = host->data->blocksize;
 | 
						|
	sdiohost_setreg(host, SDIO_DATA_CTRL_REG_OFS, datactrlreg.reg);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Setup SDIO controller data transfer in DMA mode.
 | 
						|
 | 
						|
	@param[in] uidmaaddress buffer DRAM address
 | 
						|
			- possible value: 0x000_0000 ~ 0xFFF_FFFF
 | 
						|
	@param[in] uidatalength total transfer length
 | 
						|
			- possible value: 0x000_0001 ~ 0x3FF_FFFF
 | 
						|
	@param[in] bisread      read/write mode
 | 
						|
			- @b TRUE: indicate data read transfer
 | 
						|
			- @b FALSE: indicate data write transfer
 | 
						|
 | 
						|
	@return void
 | 
						|
*/
 | 
						|
void sdiohost_setupdatatransferdma(struct mmc_nvt_host *host ,
 | 
						|
u32 uidmaaddress, u32 uidatalength, BOOL bisread)
 | 
						|
{
 | 
						|
	union SDIO_DATA_CTRL_REG datactrlreg;
 | 
						|
	union SDIO_DATA_LENGTH_REG datalenreg;
 | 
						|
	union SDIO_FIFO_CONTROL_REG fifoctrlreg;
 | 
						|
	union SDIO_DMA_START_ADDR_REG dmaaddrreg;
 | 
						|
	u32 uibusclk;
 | 
						|
 | 
						|
	/* dummy read for patch */
 | 
						|
	sdiohost_delayd(host, 2);
 | 
						|
 | 
						|
	uibusclk = sdiohost_getbusclk(host->id);
 | 
						|
 | 
						|
	if (uibusclk >= 48000000)
 | 
						|
		sdiohost_delayd(host, 3);
 | 
						|
	else if ((uibusclk >= 24000000) && (uibusclk < 48000000))
 | 
						|
		sdiohost_delayd(host, 6);
 | 
						|
	else if ((uibusclk >= 12000000) && (uibusclk < 24000000))
 | 
						|
		sdiohost_delayd(host, 9);
 | 
						|
	else
 | 
						|
		sdiohost_delayd(host, 21);
 | 
						|
 | 
						|
	/* patch for sd fifo bug end */
 | 
						|
 | 
						|
	datactrlreg.reg = sdiohost_getreg(host, SDIO_DATA_CTRL_REG_OFS);
 | 
						|
	/* multiple read => disable SDIO INT detection after transfer end */
 | 
						|
	if (bisread && (uidatalength > datactrlreg.bit.BLK_SIZE))
 | 
						|
		datactrlreg.bit.DIS_SDIO_INT_PERIOD = 1;
 | 
						|
	else
 | 
						|
		datactrlreg.bit.DIS_SDIO_INT_PERIOD = 0;
 | 
						|
 | 
						|
	/*move data en after fifo en*/
 | 
						|
	/*datactrlreg.bit.DATA_EN = 1;*/
 | 
						|
	sdiohost_setreg(host, SDIO_DATA_CTRL_REG_OFS, datactrlreg.reg);
 | 
						|
 | 
						|
	dmaaddrreg.reg = 0;
 | 
						|
	dmaaddrreg.bit.DRAM_ADDR = uidmaaddress;
 | 
						|
	sdiohost_setreg(host, SDIO_DMA_START_ADDR_REG_OFS, dmaaddrreg.reg);
 | 
						|
 | 
						|
	datalenreg.reg = 0;
 | 
						|
	datalenreg.bit.LENGTH = uidatalength;
 | 
						|
	sdiohost_setreg(host, SDIO_DATA_LENGTH_REG_OFS, datalenreg.reg);
 | 
						|
 | 
						|
	fifoctrlreg.reg = 0;
 | 
						|
 | 
						|
	/* Flush cache in DMA mode*/
 | 
						|
	if (!bisread)
 | 
						|
		fifoctrlreg.bit.FIFO_DIR = 1;
 | 
						|
	else
 | 
						|
		fifoctrlreg.bit.FIFO_DIR = 0;
 | 
						|
 | 
						|
	fifoctrlreg.bit.FIFO_MODE = 1;
 | 
						|
	sdiohost_setreg(host, SDIO_FIFO_CONTROL_REG_OFS, fifoctrlreg.reg);
 | 
						|
 | 
						|
	datactrlreg.reg = sdiohost_getreg(host, SDIO_DATA_CTRL_REG_OFS);
 | 
						|
	datactrlreg.bit.DATA_EN = 1;
 | 
						|
	sdiohost_setreg(host, SDIO_DATA_CTRL_REG_OFS, datactrlreg.reg);
 | 
						|
 | 
						|
	fifoctrlreg.bit.FIFO_EN = 1;
 | 
						|
	sdiohost_setreg(host, SDIO_FIFO_CONTROL_REG_OFS, fifoctrlreg.reg);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Setup SDIO controller data transfer in PIO mode.
 | 
						|
 | 
						|
	@param[in] uidatalength total transfer length
 | 
						|
			- possible value: 0x000_0001 ~ 0x3FF_FFFF
 | 
						|
	@param[in] bisread      read/write mode
 | 
						|
			- @b TRUE: indicate data read transfer
 | 
						|
			- @b FALSE: indicate data write transfer
 | 
						|
 | 
						|
	@return void
 | 
						|
*/
 | 
						|
void sdiohost_setupdatatransferpio(struct mmc_nvt_host *host,  u32 uidatalength, BOOL bisread)
 | 
						|
{
 | 
						|
	union SDIO_DATA_CTRL_REG datactrlreg;
 | 
						|
	union SDIO_DATA_LENGTH_REG datalenreg;
 | 
						|
	union SDIO_FIFO_CONTROL_REG fifoctrlreg;
 | 
						|
	u32 uibusclk;
 | 
						|
 | 
						|
	/* dummy read for patch */
 | 
						|
	sdiohost_delayd(host, 2);
 | 
						|
 | 
						|
	uibusclk = sdiohost_getbusclk(host->id);
 | 
						|
 | 
						|
	if (uibusclk >= 48000000)
 | 
						|
		sdiohost_delayd(host, 3);
 | 
						|
	else if ((uibusclk >= 24000000) && (uibusclk < 48000000))
 | 
						|
		sdiohost_delayd(host, 6);
 | 
						|
	else if ((uibusclk >= 12000000) && (uibusclk < 24000000))
 | 
						|
		sdiohost_delayd(host, 9);
 | 
						|
	else
 | 
						|
		sdiohost_delayd(host, 21);
 | 
						|
 | 
						|
	/* patch for sd fifo bug end */
 | 
						|
 | 
						|
 | 
						|
	datactrlreg.reg = sdiohost_getreg(host, SDIO_DATA_CTRL_REG_OFS);
 | 
						|
	/* multiple read => disable SDIO INT detection after transfer end */
 | 
						|
	if (bisread && (uidatalength > datactrlreg.bit.BLK_SIZE))
 | 
						|
		datactrlreg.bit.DIS_SDIO_INT_PERIOD = 1;
 | 
						|
	else
 | 
						|
		datactrlreg.bit.DIS_SDIO_INT_PERIOD = 0;
 | 
						|
 | 
						|
	datactrlreg.bit.DATA_EN = 1;
 | 
						|
	sdiohost_setreg(host, SDIO_DATA_CTRL_REG_OFS, datactrlreg.reg);
 | 
						|
 | 
						|
	datalenreg.reg = 0;
 | 
						|
	datalenreg.bit.LENGTH = uidatalength;
 | 
						|
	sdiohost_setreg(host, SDIO_DATA_LENGTH_REG_OFS, datalenreg.reg);
 | 
						|
 | 
						|
	fifoctrlreg.reg = 0;
 | 
						|
 | 
						|
	if (!bisread)
 | 
						|
		fifoctrlreg.bit.FIFO_DIR = 1;
 | 
						|
	else
 | 
						|
		fifoctrlreg.bit.FIFO_DIR = 0;
 | 
						|
 | 
						|
	sdiohost_setreg(host, SDIO_FIFO_CONTROL_REG_OFS, fifoctrlreg.reg);
 | 
						|
 | 
						|
	fifoctrlreg.bit.FIFO_EN = 1;
 | 
						|
	sdiohost_setreg(host, SDIO_FIFO_CONTROL_REG_OFS, fifoctrlreg.reg);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Write SDIO data blocks.
 | 
						|
 | 
						|
 | 
						|
	@note This function should only be called in PIO mode.
 | 
						|
 | 
						|
	@param[in] pbuf         buffer DRAM address
 | 
						|
	@param[in] uiLength     total length (block alignment)
 | 
						|
 | 
						|
	@return
 | 
						|
			- @b E_OK: success
 | 
						|
			- @b E_SYS: data CRC or data timeout error
 | 
						|
*/
 | 
						|
ER sdiohost_writeblock(struct mmc_nvt_host *host, u8 *pbuf, u32 uilength)
 | 
						|
{
 | 
						|
	u32  uiwordcount, i, *pbufword;
 | 
						|
	u32  uifullcount, uiremaincount;
 | 
						|
	BOOL    bwordalignment;
 | 
						|
	union SDIO_DATA_PORT_REG    datareg;
 | 
						|
	union SDIO_FIFO_STATUS_REG  fifostsreg;
 | 
						|
	union SDIO_STATUS_REG       stsreg;
 | 
						|
 | 
						|
	uiwordcount     = (uilength + sizeof(u32) - 1) / sizeof(u32);
 | 
						|
	uifullcount     = uiwordcount / SDIO_HOST_DATA_FIFO_DEPTH;
 | 
						|
	uiremaincount   = uiwordcount % SDIO_HOST_DATA_FIFO_DEPTH;
 | 
						|
	pbufword        = (u32 *)pbuf;
 | 
						|
 | 
						|
	if ((u32)pbuf & 0x3)
 | 
						|
		bwordalignment = FALSE;
 | 
						|
	else
 | 
						|
		bwordalignment = TRUE;
 | 
						|
 | 
						|
	while (uifullcount) {
 | 
						|
		fifostsreg.reg = sdiohost_getreg(host, SDIO_FIFO_STATUS_REG_OFS);
 | 
						|
 | 
						|
		if (fifostsreg.bit.FIFO_EMPTY) {
 | 
						|
			if (bwordalignment == TRUE) {
 | 
						|
				/* Word alignment*/
 | 
						|
				for (i = SDIO_HOST_DATA_FIFO_DEPTH; i; i--) {
 | 
						|
					sdiohost_setreg(host, SDIO_DATA_PORT_REG_OFS, \
 | 
						|
						*pbufword++);
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				/* Not word alignment*/
 | 
						|
				for (i = SDIO_HOST_DATA_FIFO_DEPTH; i; i--) {
 | 
						|
					datareg.reg = *pbuf++;
 | 
						|
					datareg.reg |= (*pbuf++) << 8;
 | 
						|
					datareg.reg |= (*pbuf++) << 16;
 | 
						|
					datareg.reg |= (*pbuf++) << 24;
 | 
						|
 | 
						|
					sdiohost_setreg(host, SDIO_DATA_PORT_REG_OFS, \
 | 
						|
						datareg.reg);
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			uifullcount--;
 | 
						|
		}
 | 
						|
 | 
						|
		stsreg.reg = sdiohost_getreg(host, SDIO_STATUS_REG_OFS);
 | 
						|
 | 
						|
		if (stsreg.bit.DATA_CRC_FAIL || stsreg.bit.DATA_TIMEOUT) {
 | 
						|
			printf("write block fail\n");
 | 
						|
			return E_SYS;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (uiremaincount) {
 | 
						|
		while (1) {
 | 
						|
 | 
						|
			fifostsreg.reg = \
 | 
						|
				sdiohost_getreg(host, SDIO_FIFO_STATUS_REG_OFS);
 | 
						|
 | 
						|
			if (fifostsreg.bit.FIFO_EMPTY)
 | 
						|
				break;
 | 
						|
 | 
						|
			stsreg.reg = sdiohost_getreg(host, SDIO_STATUS_REG_OFS);
 | 
						|
 | 
						|
			if (stsreg.bit.DATA_CRC_FAIL || stsreg.bit.DATA_TIMEOUT)
 | 
						|
				return E_SYS;
 | 
						|
		}
 | 
						|
 | 
						|
		if (bwordalignment == TRUE) {
 | 
						|
			/* Word alignment*/
 | 
						|
			for (i = uiremaincount; i; i--) {
 | 
						|
				sdiohost_setreg(host, SDIO_DATA_PORT_REG_OFS, \
 | 
						|
					*pbufword++);
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			/* Not word alignment*/
 | 
						|
			for (i = uiremaincount; i; i--) {
 | 
						|
				datareg.reg = *pbuf++;
 | 
						|
				datareg.reg |= (*pbuf++) << 8;
 | 
						|
				datareg.reg |= (*pbuf++) << 16;
 | 
						|
				datareg.reg |= (*pbuf++) << 24;
 | 
						|
 | 
						|
				sdiohost_setreg(host, SDIO_DATA_PORT_REG_OFS, \
 | 
						|
					datareg.reg);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return E_OK;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Read SDIO data blocks.
 | 
						|
 | 
						|
	@note This function should only be called in PIO mode.
 | 
						|
 | 
						|
	@param[out] pbuf        buffer DRAM address
 | 
						|
	@param[in] uiLength     total length (block alignment)
 | 
						|
 | 
						|
	@return
 | 
						|
		- @b E_OK: success
 | 
						|
		- @b E_SYS: data CRC or data timeout error
 | 
						|
*/
 | 
						|
ER sdiohost_readblock(struct mmc_nvt_host *host, u8 *pbuf, u32 uilength)
 | 
						|
{
 | 
						|
	u32  uiwordcount, i, *pbufword;
 | 
						|
	u32  uifullcount, uiremaincount;
 | 
						|
	BOOL    bwordalignment;
 | 
						|
	union SDIO_DATA_PORT_REG    datareg;
 | 
						|
	union SDIO_FIFO_STATUS_REG  fifostsreg;
 | 
						|
	union SDIO_STATUS_REG       stsreg;
 | 
						|
 | 
						|
	uiwordcount     = (uilength + sizeof(u32) - 1) / sizeof(u32);
 | 
						|
	uifullcount     = uiwordcount / SDIO_HOST_DATA_FIFO_DEPTH;
 | 
						|
	uiremaincount   = uiwordcount % SDIO_HOST_DATA_FIFO_DEPTH;
 | 
						|
	pbufword        = (u32 *)pbuf;
 | 
						|
 | 
						|
	if ((u32)pbuf & 0x3)
 | 
						|
		bwordalignment = FALSE;
 | 
						|
	else
 | 
						|
		bwordalignment = TRUE;
 | 
						|
 | 
						|
	while (uifullcount) {
 | 
						|
		fifostsreg.reg = sdiohost_getreg(host, SDIO_FIFO_STATUS_REG_OFS);
 | 
						|
 | 
						|
		if (fifostsreg.bit.FIFO_FULL) {
 | 
						|
			if (bwordalignment == TRUE) {
 | 
						|
				/* Word alignment*/
 | 
						|
				for (i = SDIO_HOST_DATA_FIFO_DEPTH; i; i--) {
 | 
						|
					*pbufword++ = \
 | 
						|
					sdiohost_getreg(host, SDIO_DATA_PORT_REG_OFS);
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				/* Not word alignment*/
 | 
						|
				for (i = SDIO_HOST_DATA_FIFO_DEPTH; i; i--) {
 | 
						|
					datareg.reg = \
 | 
						|
					sdiohost_getreg(host, SDIO_DATA_PORT_REG_OFS);
 | 
						|
 | 
						|
					*pbuf++ = datareg.reg & 0xFF;
 | 
						|
					*pbuf++ = (datareg.reg>>8) & 0xFF;
 | 
						|
					*pbuf++ = (datareg.reg>>16) & 0xFF;
 | 
						|
					*pbuf++ = (datareg.reg>>24) & 0xFF;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			uifullcount--;
 | 
						|
		}
 | 
						|
 | 
						|
		stsreg.reg = sdiohost_getreg(host, SDIO_STATUS_REG_OFS);
 | 
						|
 | 
						|
		if (stsreg.bit.DATA_CRC_FAIL || stsreg.bit.DATA_TIMEOUT)
 | 
						|
			return E_SYS;
 | 
						|
	}
 | 
						|
 | 
						|
	if (uiremaincount) {
 | 
						|
		while (1) {
 | 
						|
			fifostsreg.reg = \
 | 
						|
				sdiohost_getreg(host, SDIO_FIFO_STATUS_REG_OFS);
 | 
						|
 | 
						|
			if (fifostsreg.bit.FIFO_CNT == uiremaincount)
 | 
						|
				break;
 | 
						|
 | 
						|
			stsreg.reg = sdiohost_getreg(host, SDIO_STATUS_REG_OFS);
 | 
						|
			if (stsreg.bit.DATA_CRC_FAIL || stsreg.bit.DATA_TIMEOUT)
 | 
						|
				return E_SYS;
 | 
						|
		}
 | 
						|
 | 
						|
		if (bwordalignment == TRUE) {
 | 
						|
			/* Word alignment*/
 | 
						|
			for (i = uiremaincount; i; i--) {
 | 
						|
				*pbufword++ = \
 | 
						|
					sdiohost_getreg(host, SDIO_DATA_PORT_REG_OFS);
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			/* Not word alignment*/
 | 
						|
			for (i = uiremaincount; i; i--) {
 | 
						|
				datareg.reg = \
 | 
						|
					sdiohost_getreg(host, SDIO_DATA_PORT_REG_OFS);
 | 
						|
 | 
						|
				*pbuf++ = datareg.reg & 0xFF;
 | 
						|
				*pbuf++ = (datareg.reg>>8) & 0xFF;
 | 
						|
				*pbuf++ = (datareg.reg>>16) & 0xFF;
 | 
						|
				*pbuf++ = (datareg.reg>>24) & 0xFF;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return E_OK;
 | 
						|
}
 | 
						|
 | 
						|
u32 sdiohost_getstatus(struct mmc_nvt_host *host)
 | 
						|
{
 | 
						|
	return sdiohost_getreg(host, SDIO_STATUS_REG_OFS);
 | 
						|
}
 | 
						|
 | 
						|
void sdiohost_setstatus(struct mmc_nvt_host *host, u32 status)
 | 
						|
{
 | 
						|
	sdiohost_setreg(host, SDIO_STATUS_REG_OFS, status);
 | 
						|
}
 | 
						|
 | 
						|
static void sdiohost_fifo_data_trans(struct mmc_nvt_host *host,
 | 
						|
					unsigned int n)
 | 
						|
{
 | 
						|
	if (host->data_dir == SDIO_HOST_WRITE_DATA) {
 | 
						|
		host->buffer = (u8*) host->data->src;
 | 
						|
		sdiohost_writeblock(host, (u8 *)host->buffer, \
 | 
						|
			host->buffer_bytes_left);
 | 
						|
		host->bytes_left -= host->buffer_bytes_left;
 | 
						|
	} else {
 | 
						|
		host->buffer = (u8*) host->data->dest;
 | 
						|
		sdiohost_readblock(host, (u8 *)host->buffer, \
 | 
						|
			host->buffer_bytes_left);
 | 
						|
		host->bytes_left -= host->buffer_bytes_left;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void sdiohost_clrfifoen(struct mmc_nvt_host *host)
 | 
						|
{
 | 
						|
	union SDIO_FIFO_CONTROL_REG fifoctrlreg;
 | 
						|
 | 
						|
	fifoctrlreg.reg = sdiohost_getreg(host, SDIO_FIFO_CONTROL_REG_OFS);
 | 
						|
	fifoctrlreg.bit.FIFO_EN = 0;
 | 
						|
	sdiohost_setreg(host, SDIO_FIFO_CONTROL_REG_OFS, fifoctrlreg.reg);
 | 
						|
}
 | 
						|
 | 
						|
u32 sdiohost_getfifodir(struct mmc_nvt_host *host)
 | 
						|
{
 | 
						|
	union SDIO_FIFO_CONTROL_REG fifoctrlreg;
 | 
						|
 | 
						|
	fifoctrlreg.reg = sdiohost_getreg(host, SDIO_FIFO_CONTROL_REG_OFS);
 | 
						|
 | 
						|
	return fifoctrlreg.bit.FIFO_DIR;
 | 
						|
}
 | 
						|
 | 
						|
void sdiohost_waitfifoempty(struct mmc_nvt_host *host)
 | 
						|
{
 | 
						|
	union SDIO_FIFO_STATUS_REG fifostsreg;
 | 
						|
	u32 read0, read1;
 | 
						|
 | 
						|
	read0 = 0;
 | 
						|
	while (1) {
 | 
						|
		fifostsreg.reg = sdiohost_getreg(host, SDIO_FIFO_STATUS_REG_OFS);
 | 
						|
		read1 = fifostsreg.bit.FIFO_EMPTY;
 | 
						|
		if (read0 & read1)
 | 
						|
			break;
 | 
						|
		else
 | 
						|
			read0 = read1;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void sdiohost_getlongrsp(struct mmc_nvt_host *host, u32 *prsp3, u32 *prsp2, \
 | 
						|
					u32 *prsp1, u32 *prsp0)
 | 
						|
{
 | 
						|
	union SDIO_RSP0_REG rsp0reg;
 | 
						|
	union SDIO_RSP1_REG rsp1reg;
 | 
						|
	union SDIO_RSP2_REG rsp2reg;
 | 
						|
	union SDIO_RSP3_REG rsp3reg;
 | 
						|
 | 
						|
	rsp0reg.reg = sdiohost_getreg(host, SDIO_RSP0_REG_OFS);
 | 
						|
	*prsp0 = (u32) rsp0reg.reg;
 | 
						|
	rsp1reg.reg = sdiohost_getreg(host, SDIO_RSP1_REG_OFS);
 | 
						|
	*prsp1 = (u32) rsp1reg.reg;
 | 
						|
	rsp2reg.reg = sdiohost_getreg(host, SDIO_RSP2_REG_OFS);
 | 
						|
	*prsp2 = (u32) rsp2reg.reg;
 | 
						|
	rsp3reg.reg = sdiohost_getreg(host, SDIO_RSP3_REG_OFS);
 | 
						|
	*prsp3 = (u32) rsp3reg.reg;
 | 
						|
}
 | 
						|
 | 
						|
void sdiohost_getshortrsp(struct mmc_nvt_host *host, u32 *prsp)
 | 
						|
{
 | 
						|
	union SDIO_RSP0_REG rspreg;
 | 
						|
 | 
						|
	rspreg.reg = sdiohost_getreg(host, SDIO_RSP0_REG_OFS);
 | 
						|
	*prsp = (u32) rspreg.reg;
 | 
						|
}
 | 
						|
 | 
						|
static void mmc_nvt_cmd_done(struct mmc_nvt_host *host)
 | 
						|
{
 | 
						|
	struct mmc_cmd *cmd = host->cmd;
 | 
						|
	host->cmd = NULL;
 | 
						|
 | 
						|
	if (cmd->resp_type & MMC_RSP_PRESENT) {
 | 
						|
		if (cmd->resp_type & MMC_RSP_136) {
 | 
						|
			/* response type 2 */
 | 
						|
			sdiohost_getlongrsp(host, \
 | 
						|
			(u32 *)&cmd->response[0], (u32 *)&cmd->response[1],
 | 
						|
			(u32 *)&cmd->response[2], (u32 *)&cmd->response[3]);
 | 
						|
			debug("lrsp 0x%x 0x%x 0x%x 0x%x\n", cmd->response[0], cmd->response[1], cmd->response[2], cmd->response[3]);
 | 
						|
		} else {
 | 
						|
			/* response types 1, 1b, 3, 4, 5, 6 */
 | 
						|
			sdiohost_getshortrsp(host, (u32 *)&cmd->response[0]);
 | 
						|
			debug("rsp 0x%x\n", cmd->response[0]);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static ER sdiohost_transfer(struct mmc_nvt_host *host)
 | 
						|
{
 | 
						|
	u32 status, qstatus = 0;
 | 
						|
	int end_command = 0;
 | 
						|
	int end_transfer = 0;
 | 
						|
	int err_sts = 1, timeout = 0;
 | 
						|
	struct mmc_data *data = host->data;
 | 
						|
 | 
						|
 | 
						|
	while(1) {
 | 
						|
		status = sdiohost_getstatus(host);
 | 
						|
		//printf("cmd status is 0x%x\n", status);
 | 
						|
		if (status & SDIO_STATUS_REG_CMD_SEND) {
 | 
						|
			qstatus = status;
 | 
						|
			sdiohost_setstatus(host, SDIO_STATUS_REG_CMD_SEND);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (data && host->do_dma) {
 | 
						|
		while(1) {
 | 
						|
			status = sdiohost_getstatus(host);
 | 
						|
			//printf("data status is 0x%x\n", status);
 | 
						|
			if ((status & SDIO_STATUS_REG_DATA_END) || \
 | 
						|
				(status & SDIO_STATUS_REG_DATA_TIMEOUT)) {
 | 
						|
				qstatus = status;
 | 
						|
				sdiohost_setstatus(host, SDIO_STATUS_REG_DATA_END);
 | 
						|
				break;
 | 
						|
			} else if ((status & SDIO_STATUS_REG_RSP_CRC_FAIL) || \
 | 
						|
				(status & SDIO_STATUS_REG_DATA_CRC_FAIL)) {
 | 
						|
				qstatus = status;
 | 
						|
				//printf("crc status is 0x%x\n", status);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
	if ((qstatus & SDIO_STATUS_REG_RSP_CRC_FAIL) ||
 | 
						|
		(qstatus & SDIO_STATUS_REG_DATA_CRC_FAIL) ||
 | 
						|
		(qstatus & SDIO_STATUS_REG_RSP_TIMEOUT) ||
 | 
						|
		(qstatus & SDIO_STATUS_REG_DATA_TIMEOUT)) {
 | 
						|
		err_sts = 1;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		err_sts = 0;
 | 
						|
	}
 | 
						|
	//printf("qstatus is 0x%x, err_sts %d\n", qstatus, err_sts);
 | 
						|
 | 
						|
	if (qstatus & MMCST_RSP_TIMEOUT) {
 | 
						|
		/* Command timeout */
 | 
						|
		if (host->cmd) {
 | 
						|
			printf("CMD%d timeout, status %x\n",host->cmd->cmdidx, qstatus);
 | 
						|
			if (host->data)
 | 
						|
				sdiohost_resetdata(host);
 | 
						|
		}
 | 
						|
		//printf("MMCST_RSP_TIMEOUT\r\n");
 | 
						|
		sdiohost_setstatus(host, MMCST_RSP_TIMEOUT);
 | 
						|
		timeout = 1;
 | 
						|
	}
 | 
						|
 | 
						|
	if (qstatus & MMCST_DATA_TIMEOUT) {
 | 
						|
		printf("data timeout (CMD%d), status 0x%x\n", host->cmd->cmdidx, qstatus);
 | 
						|
		if (host->data)
 | 
						|
			sdiohost_resetdata(host);
 | 
						|
 | 
						|
		//printf("MMCST_DATA_TIMEOUT\r\n");
 | 
						|
		sdiohost_setstatus(host, MMCST_DATA_TIMEOUT);
 | 
						|
	}
 | 
						|
 | 
						|
	if (qstatus & MMCST_RSP_CRC_FAIL) {
 | 
						|
		/* Command CRC error */
 | 
						|
		printf("Command CRC error\n");
 | 
						|
		//printf("MMCST_RSP_CRC_FAIL\r\n");
 | 
						|
		sdiohost_setstatus(host, MMCST_RSP_CRC_FAIL);
 | 
						|
	}
 | 
						|
 | 
						|
	if (qstatus & MMCST_DATA_CRC_FAIL) {
 | 
						|
		/* Data CRC error */
 | 
						|
		printf("data %s error\n", \
 | 
						|
			(host->data->flags & MMC_DATA_WRITE) ? "write" : "read");
 | 
						|
		printf("(CMD%d), status 0x%x\n", host->cmd->cmdidx, qstatus);
 | 
						|
		sdiohost_resetdata(host);
 | 
						|
		//printf("MMCST_DATA_CRC_FAIL\r\n");
 | 
						|
		sdiohost_setstatus(host, MMCST_DATA_CRC_FAIL);
 | 
						|
	}
 | 
						|
 | 
						|
	if (((qstatus & MMCST_RSP_CRC_OK) || (qstatus & MMCST_CMD_SENT)) && !timeout) {
 | 
						|
		/* End of command phase */
 | 
						|
		if (data == NULL)
 | 
						|
			end_command = (int) host->cmd;
 | 
						|
		else {
 | 
						|
			if ((host->bytes_left > 0) && (host->do_dma == 0)) {
 | 
						|
				/* if datasize < rw_threshold
 | 
						|
				 * no RX ints are generated
 | 
						|
				 */
 | 
						|
				sdiohost_fifo_data_trans(host, host->bytes_left);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if (qstatus & MMCST_RSP_CRC_OK)
 | 
						|
			sdiohost_setstatus(host, MMCST_RSP_CRC_OK);
 | 
						|
 | 
						|
		if (qstatus & MMCST_CMD_SENT)
 | 
						|
			sdiohost_setstatus(host, MMCST_CMD_SENT);
 | 
						|
	}
 | 
						|
 | 
						|
	if ((qstatus & MMCST_RSP_CRC_OK))
 | 
						|
		end_command = (int) host->cmd;
 | 
						|
 | 
						|
	if (data && !host->do_dma && !timeout) {
 | 
						|
		while(1) {
 | 
						|
			status = sdiohost_getstatus(host);
 | 
						|
			if ((status & SDIO_STATUS_REG_DATA_END) || \
 | 
						|
				(status & SDIO_STATUS_REG_DATA_TIMEOUT)) {
 | 
						|
				qstatus = status;
 | 
						|
				sdiohost_setstatus(host, SDIO_STATUS_REG_DATA_END);
 | 
						|
				break;
 | 
						|
			} else if ((status & SDIO_STATUS_REG_RSP_CRC_FAIL) || (status & SDIO_STATUS_REG_RSP_TIMEOUT) || \
 | 
						|
				(status & SDIO_STATUS_REG_DATA_CRC_FAIL)) {
 | 
						|
				qstatus = status;
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if ((qstatus & MMCST_DATA_END) || (qstatus & MMCST_DATA_CRC_OK)) {
 | 
						|
		end_transfer = 1;
 | 
						|
		data->dest += data->blocksize;
 | 
						|
		if (!sdiohost_getfifodir(host)) {
 | 
						|
			if (qstatus & MMCST_DATA_END) {
 | 
						|
				if ((qstatus & MMCST_DMA_ERROR)
 | 
						|
					!= MMCST_DMA_ERROR) {
 | 
						|
					sdiohost_waitfifoempty(host);
 | 
						|
				}
 | 
						|
				sdiohost_clrfifoen(host);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if (qstatus & MMCST_DATA_END)
 | 
						|
			sdiohost_setstatus(host, MMCST_DATA_END);
 | 
						|
 | 
						|
		if (qstatus & MMCST_DATA_CRC_OK)
 | 
						|
			sdiohost_setstatus(host, MMCST_DATA_CRC_OK);
 | 
						|
	}
 | 
						|
 | 
						|
	if (end_command)
 | 
						|
		mmc_nvt_cmd_done(host);
 | 
						|
 | 
						|
	if (end_transfer && (!host->cmd)) {
 | 
						|
		host->data = NULL;
 | 
						|
		host->cmd = NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	if (err_sts) {
 | 
						|
		if (timeout)
 | 
						|
			return -ETIMEDOUT;
 | 
						|
 | 
						|
		status = sdiohost_getstatus(host);
 | 
						|
		if(status)
 | 
						|
			printf("end status is 0x%x\n", status);
 | 
						|
		return -ECOMM;
 | 
						|
	}
 | 
						|
 | 
						|
	return SDIO_HOST_CMD_OK;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Send SD command to SD bus.
 | 
						|
 | 
						|
	@param[in] cmd      command value
 | 
						|
	@param[in] rsptype  response type
 | 
						|
			- @b SDIO_HOST_RSP_NONE: no response is required
 | 
						|
			- @b SDIO_HOST_RSP_SHORT: need short (32 bits) response
 | 
						|
			- @b SDIO_HOST_RSP_LONG: need long (128 bits) response
 | 
						|
	@param[in] beniointdetect enable SDIO INT detect after command end
 | 
						|
			- @b TRUE: enable SDIO INT detection
 | 
						|
			- @b FALSE: keep SDIO INT detection
 | 
						|
 | 
						|
	@return command result
 | 
						|
	- @b SDIO_HOST_CMD_OK: command execution success
 | 
						|
	- @b SDIO_HOST_RSP_TIMEOUT: response timeout. no response got from card.
 | 
						|
	- @b SDIO_HOST_RSP_CRCFAIL: response CRC fail.
 | 
						|
	- @b SDIO_HOST_CMD_FAIL: other fail.
 | 
						|
*/
 | 
						|
ER sdiohost_sendcmd(struct mmc_nvt_host *host, \
 | 
						|
	u32 cmd, SDIO_HOST_RESPONSE rsptype, BOOL beniointdetect)
 | 
						|
{
 | 
						|
	union SDIO_CMD_REG cmdreg;
 | 
						|
	u32 status;
 | 
						|
 | 
						|
	/*cmdreg.reg = 0;*/
 | 
						|
	cmdreg.reg = sdiohost_getreg(host, SDIO_CMD_REG_OFS);
 | 
						|
	cmdreg.bit.CMD_IDX = 0;
 | 
						|
	cmdreg.bit.NEED_RSP = 0;
 | 
						|
	cmdreg.bit.LONG_RSP = 0;
 | 
						|
	cmdreg.bit.RSP_TIMEOUT_TYPE = 0;
 | 
						|
	cmdreg.bit.ENABLE_SDIO_INT_DETECT = beniointdetect;
 | 
						|
 | 
						|
	if (rsptype != SDIO_HOST_RSP_NONE) {
 | 
						|
		/* Need response */
 | 
						|
		cmdreg.bit.NEED_RSP = 1;
 | 
						|
 | 
						|
		switch (rsptype) {
 | 
						|
 | 
						|
		default:
 | 
						|
			break;
 | 
						|
 | 
						|
		case SDIO_HOST_RSP_LONG:
 | 
						|
			cmdreg.bit.LONG_RSP = 1;
 | 
						|
			break;
 | 
						|
 | 
						|
		case SDIO_HOST_RSP_SHORT_TYPE2:
 | 
						|
			cmdreg.bit.RSP_TIMEOUT_TYPE = 1;
 | 
						|
			break;
 | 
						|
 | 
						|
		case SDIO_HOST_RSP_LONG_TYPE2:
 | 
						|
			cmdreg.bit.RSP_TIMEOUT_TYPE = 1;
 | 
						|
			cmdreg.bit.LONG_RSP = 1;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	cmdreg.bit.CMD_IDX = cmd;
 | 
						|
	sdiohost_setreg(host, SDIO_CMD_REG_OFS, cmdreg.reg);
 | 
						|
 | 
						|
	/*Clear all status*/
 | 
						|
	status = sdiohost_getstatus(host);
 | 
						|
	sdiohost_setstatus(host, status);
 | 
						|
 | 
						|
	/* Start command/data transmits */
 | 
						|
	cmdreg.bit.CMD_EN = 1;
 | 
						|
	sdiohost_setreg(host, SDIO_CMD_REG_OFS, cmdreg.reg);
 | 
						|
 | 
						|
	return sdiohost_transfer(host);
 | 
						|
}
 | 
						|
 | 
						|
ER sdiohost_sendsdcmd(struct mmc_nvt_host *host, u32 cmdpart)
 | 
						|
{
 | 
						|
	BOOL benintdetect = FALSE;
 | 
						|
	SDIO_HOST_RESPONSE rsptype = SDIO_HOST_RSP_NONE;
 | 
						|
	u32 param = host->cmd->cmdarg;
 | 
						|
 | 
						|
	if ((cmdpart & SDIO_CMD_REG_LONG_RSP) == SDIO_CMD_REG_LONG_RSP) {
 | 
						|
		if (cmdpart & SDIO_CMD_REG_RSP_TYPE2)
 | 
						|
			rsptype = SDIO_HOST_RSP_LONG_TYPE2;
 | 
						|
		else
 | 
						|
			rsptype = SDIO_HOST_RSP_LONG;
 | 
						|
	} else if (cmdpart & SDIO_CMD_REG_VOLTAGE_SWITCH_DETECT) {
 | 
						|
		rsptype = SDIO_HOST_RSP_VOLT_DETECT;
 | 
						|
	} else if (cmdpart & SDIO_CMD_REG_NEED_RSP) {
 | 
						|
 | 
						|
		if (cmdpart & SDIO_CMD_REG_RSP_TYPE2)
 | 
						|
			rsptype = SDIO_HOST_RSP_SHORT_TYPE2;
 | 
						|
		else
 | 
						|
			rsptype = SDIO_HOST_RSP_SHORT;
 | 
						|
	}
 | 
						|
 | 
						|
	if (cmdpart & SDIO_CMD_REG_ABORT)
 | 
						|
		benintdetect = TRUE;
 | 
						|
 | 
						|
	sdiohost_setreg(host, SDIO_ARGU_REG_OFS, param);
 | 
						|
	//printf("bEnIntDetect %d\r\n",benintdetect);
 | 
						|
 | 
						|
	return sdiohost_sendcmd(host, cmdpart & SDIO_CMD_REG_INDEX, \
 | 
						|
			rsptype, benintdetect);
 | 
						|
}
 | 
						|
 | 
						|
static void mmc_nvt_prepare_data(struct mmc_nvt_host *host)
 | 
						|
{
 | 
						|
	u32 size;
 | 
						|
 | 
						|
	if (host->data == NULL) {
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	sdiohost_setblksize(host);
 | 
						|
 | 
						|
	host->buffer = (u8*)(host->data->dest);
 | 
						|
	host->bytes_left = host->data->blocks * host->data->blocksize;
 | 
						|
	host->data_dir = ((host->data->flags & MMC_DATA_WRITE) ?
 | 
						|
		SDIO_HOST_WRITE_DATA : SDIO_HOST_READ_DATA);
 | 
						|
 | 
						|
#if (defined(CONFIG_TARGET_NA51090) || defined(CONFIG_TARGET_NA51090_A64) || defined(CONFIG_TARGET_NA51103) || defined(CONFIG_TARGET_NA51103_A64))
 | 
						|
	if ((host->bytes_left % ARCH_DMA_MINALIGN) || ((u32)host->buffer % ARCH_DMA_MINALIGN) || (host->mmc_input_clk < 24000000)) {
 | 
						|
		if (host->mmc_input_clk < 24000000) {
 | 
						|
			printf("clk(%dHz) < 24MHz, force to PIO\n", host->mmc_input_clk);
 | 
						|
		}
 | 
						|
#else
 | 
						|
	if ((host->bytes_left % ARCH_DMA_MINALIGN) || ((u32)host->buffer % ARCH_DMA_MINALIGN)) {
 | 
						|
#endif
 | 
						|
		host->do_dma = 0;
 | 
						|
		host->buffer_bytes_left = host->bytes_left;
 | 
						|
	} else {
 | 
						|
		host->do_dma = 1;
 | 
						|
	}
 | 
						|
 | 
						|
	if (host->do_dma) {
 | 
						|
		size = (u32)(host->buffer) + host->bytes_left;
 | 
						|
 | 
						|
		if (host->data_dir == SDIO_HOST_WRITE_DATA)
 | 
						|
			flush_dcache_range(ALIGN_FLOOR((u32)host->buffer, ARCH_DMA_MINALIGN), (u32)roundup(size,ARCH_DMA_MINALIGN));
 | 
						|
		else
 | 
						|
			invalidate_dcache_range(ALIGN_FLOOR((u32)host->buffer, ARCH_DMA_MINALIGN), (u32)roundup(size,ARCH_DMA_MINALIGN));
 | 
						|
 | 
						|
		sdiohost_setupdatatransferdma(host, (u32)host->buffer, \
 | 
						|
			host->bytes_left, host->data_dir);
 | 
						|
		/* zero this to ensure we take no PIO paths */
 | 
						|
		host->bytes_left = 0;
 | 
						|
	} else {
 | 
						|
		sdiohost_setupdatatransferpio(host, \
 | 
						|
			host->buffer_bytes_left, \
 | 
						|
			host->data_dir);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
int mmc_nvt_start_command(struct mmc_nvt_host *host)
 | 
						|
{
 | 
						|
	u32 cmd_reg = 0;
 | 
						|
	char *s;
 | 
						|
 | 
						|
	switch (host->cmd->resp_type & mmc_resp_type) {
 | 
						|
	case MMC_RSP_R1: /* 48 bits, CRC */
 | 
						|
		s = ", R1";
 | 
						|
		cmd_reg |= SDIO_CMD_REG_NEED_RSP;
 | 
						|
		break;
 | 
						|
	case MMC_RSP_R1b:
 | 
						|
		s = ", R1b";
 | 
						|
		/* There's some spec confusion about when R1B is
 | 
						|
		 * allowed, but if the card doesn't issue a BUSY
 | 
						|
		 * then it's harmless for us to allow it.
 | 
						|
		 */
 | 
						|
		/*need to check card busy CARD_BUSY2READY bit or
 | 
						|
		 *send _SDIO_SD_SEND_STATUS to check
 | 
						|
		*/
 | 
						|
		cmd_reg |= SDIO_CMD_REG_NEED_RSP;
 | 
						|
		/* FALLTHROUGH */
 | 
						|
		break;
 | 
						|
	case MMC_RSP_R2: /* 136 bits, CRC */
 | 
						|
		s = ", R2";
 | 
						|
		cmd_reg |= SDIO_CMD_REG_LONG_RSP;
 | 
						|
		break;
 | 
						|
	case MMC_RSP_R3: /* 48 bits, no CRC */
 | 
						|
		s = ", R3/R4";
 | 
						|
		cmd_reg |= SDIO_CMD_REG_NEED_RSP;
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		s = ", Rx";
 | 
						|
		cmd_reg |= 0;
 | 
						|
		break;
 | 
						|
	};
 | 
						|
 | 
						|
	debug("CMD%d, arg 0x%08x %s\n", host->cmd->cmdidx, host->cmd->cmdarg, s);
 | 
						|
 | 
						|
	/* Set command index */
 | 
						|
	cmd_reg |= host->cmd->cmdidx;
 | 
						|
 | 
						|
	return sdiohost_sendsdcmd(host, cmd_reg);
 | 
						|
}
 | 
						|
 | 
						|
#if !CONFIG_IS_ENABLED(DM_MMC)
 | 
						|
static int host_request(struct mmc *dev,
 | 
						|
			struct mmc_cmd *cmd,
 | 
						|
			struct mmc_data *data)
 | 
						|
{
 | 
						|
	struct mmc_nvt_host *host = dev->priv;
 | 
						|
#else
 | 
						|
static int host_request(struct udevice *udev,
 | 
						|
			struct mmc_cmd *cmd,
 | 
						|
			struct mmc_data *data)
 | 
						|
{
 | 
						|
	struct mmc_nvt_host *host = dev_get_priv(udev);
 | 
						|
	struct mmc *dev = mmc_get_mmc_dev(udev);
 | 
						|
#endif
 | 
						|
 | 
						|
	int result;
 | 
						|
	unsigned int time_start, time_now, mmcst = 0;
 | 
						|
	host->data = data;
 | 
						|
	host->cmd = cmd;
 | 
						|
	static int cur_clk = 0;
 | 
						|
 | 
						|
#ifdef CONFIG_NVT_IVOT_EMMC
 | 
						|
	if (data || (host->id == SDIO_HOST_ID_3)) {
 | 
						|
#else
 | 
						|
	if (data) {
 | 
						|
#endif
 | 
						|
		time_start = get_timer (0);
 | 
						|
		while(1) {
 | 
						|
			mmcst = sdiohost_getrdy(host);
 | 
						|
			if (mmcst == true)
 | 
						|
				break;
 | 
						|
#ifdef CONFIG_NVT_IVOT_EMMC
 | 
						|
			if (host->id != SDIO_HOST_ID_3) {
 | 
						|
				time_now = get_timer (0);
 | 
						|
				if ((time_now - time_start) > 1000)
 | 
						|
					break;
 | 
						|
			}
 | 
						|
#else
 | 
						|
			time_now = get_timer (0);
 | 
						|
			if ((time_now - time_start) > 1000)
 | 
						|
				break;
 | 
						|
#endif
 | 
						|
		}
 | 
						|
 | 
						|
		if (mmcst == false) {
 | 
						|
			printf("still busy\n");
 | 
						|
			return -ETIMEDOUT;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if(dev->clock != cur_clk) {
 | 
						|
		sdiohost_setdatatimeout(host, (dev->clock/1000)*300);
 | 
						|
	}
 | 
						|
 | 
						|
	cur_clk = dev->clock;
 | 
						|
 | 
						|
	mmc_nvt_prepare_data(host);
 | 
						|
	result = mmc_nvt_start_command(host);
 | 
						|
 | 
						|
	return result;
 | 
						|
}
 | 
						|
 | 
						|
#if !CONFIG_IS_ENABLED(DM_MMC)
 | 
						|
/* MMC uses open drain drivers in the enumeration phase */
 | 
						|
static int mmc_host_reset(struct mmc *dev)
 | 
						|
{
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
static int nvt_emmc_arch_host_preinit(struct mmc_nvt_host *host)
 | 
						|
{
 | 
						|
	if (host->id == SDIO_HOST_ID_1) {
 | 
						|
#ifdef CONFIG_TARGET_NA51000
 | 
						|
		*(uint32_t*) 0xF0010004 |= 0x4000;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF00100A0 &= ~(0x3F0000);
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF00200A4 &= ~(0x4);
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF00200A4 |= 0x4;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020020 &= ~0x30;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020040 &= ~0x7FF;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020040 |= 0x1F0;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020084 |= 0x4;
 | 
						|
#elif (defined(CONFIG_TARGET_NA51090) || defined(CONFIG_TARGET_NA51090_A64) || defined(CONFIG_TARGET_NA51103) || defined(CONFIG_TARGET_NA51103_A64))
 | 
						|
		*(uint32_t*) 0xF0010004 &= ~0x10;        // SDIO_EN
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0010004 |= 0x10;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF00100A8 &= ~(0x7B000);   // PGPIO12~13, PGPIO15~18
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020098 &= ~(0x4);       // SDIO_RSTN
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020098 |= 0x4;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020020 &= ~0x3;         // SDIO_CLKSEL
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020040 &= ~0x7FF;       // SDIO_CLKDIV
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020040 |= 0x1F0;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020074 |= 0x800;        // SDIO_CLKEN
 | 
						|
		udelay(10);
 | 
						|
#elif (defined(CONFIG_TARGET_NA51102) || defined(CONFIG_TARGET_NA51102_A64))
 | 
						|
		*(uint32_t*) 0xF0010004 &= ~0x10;        // SDIO_EN
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0010004 |= 0x10;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF00100A0 &= ~(0x3F << 11);   // PGPIO12~13, PGPIO15~18
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020094 &= ~(0x1 << 11);       // SDIO_RSTN
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020094 |= (0x1 << 11);
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020020 &= ~0x3;         // SDIO_CLKSEL
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020040 &= ~0x7FF;       // SDIO_CLKDIV
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020040 |= 0x1F0;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020074 |= 0x800;        // SDIO_CLKEN
 | 
						|
		udelay(10);
 | 
						|
#else
 | 
						|
		*(uint32_t*) 0xF0010004 |= 0x4000;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF00100A0 &= ~(0x1F800);
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020084 &= ~(0x4);
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020084 |= 0x4;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020020 &= ~0x30;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF002003C &= ~0x7FF;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF002003C |= 0x1F0;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020074 |= 0x4;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0030068 &= ~0xFFFFFF;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0030068 |= 0x111111;
 | 
						|
#endif
 | 
						|
	} else if (host->id == SDIO_HOST_ID_2) {
 | 
						|
#ifdef CONFIG_TARGET_NA51089
 | 
						|
		if (host->pinmux_value & PIN_SDIO_CFG_2ND_PINMUX) {
 | 
						|
			*(uint32_t*) 0xF0010004 &= ~0xC0000;
 | 
						|
			*(uint32_t*) 0xF0010004 |= 0x80000;
 | 
						|
			udelay(10);
 | 
						|
			*(uint32_t*) 0xF00100B0 &= ~(0x18F);
 | 
						|
			udelay(10);
 | 
						|
			*(uint32_t*) 0xF003004C &= ~0x3C0FF;
 | 
						|
			udelay(10);
 | 
						|
			*(uint32_t*) 0xF003004C |= 0x1;
 | 
						|
			udelay(10);
 | 
						|
		} else if (host->pinmux_value & PIN_SDIO_CFG_3RD_PINMUX) {
 | 
						|
			*(uint32_t*) 0xF0010004 &= ~0xC0000;
 | 
						|
			*(uint32_t*) 0xF0010004 |= 0xC0000;
 | 
						|
			udelay(10);
 | 
						|
			*(uint32_t*) 0xF00100E8 &= ~(0xFC);
 | 
						|
			udelay(10);
 | 
						|
			*(uint32_t*) 0xF0030098 &= ~0xFFF0;
 | 
						|
			udelay(10);
 | 
						|
			*(uint32_t*) 0xF0030098 |= 0x10;
 | 
						|
			udelay(10);
 | 
						|
		} else {
 | 
						|
			*(uint32_t*) 0xF0010004 &= ~0xC0000;
 | 
						|
			*(uint32_t*) 0xF0010004 |= 0x40000;
 | 
						|
			udelay(10);
 | 
						|
			*(uint32_t*) 0xF00100A0 &= ~(0x7E0000);
 | 
						|
			udelay(10);
 | 
						|
			*(uint32_t*) 0xF0030068 &= ~0xF000000;
 | 
						|
			udelay(10);
 | 
						|
			*(uint32_t*) 0xF0030068 |= 0x1000000;
 | 
						|
			udelay(10);
 | 
						|
			*(uint32_t*) 0xF0030044 = 0x0;
 | 
						|
			udelay(10);
 | 
						|
		}
 | 
						|
#else
 | 
						|
		*(uint32_t*) 0xF0010004 |= 0x8000;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF00100A0 &= ~(0x7E0000);
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0030068 &= ~0xF000000;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0030068 |= 0x1000000;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0030044 = 0x0;
 | 
						|
		udelay(10);
 | 
						|
#endif
 | 
						|
		*(uint32_t*) 0xF0020084 &= ~(0x8);
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020084 |= 0x8;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020020 &= ~0x300;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF002003C &= ~0x7FF0000;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF002003C |= 0x1F00000;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020074 |= 0x8;
 | 
						|
	} else {
 | 
						|
		*(uint32_t*) 0xF0010004 &= ~(0x80003000);
 | 
						|
		udelay(10);
 | 
						|
		if (host->enable_8bits) {
 | 
						|
			*(uint32_t*) 0xF0010004 |= 0x80020000;
 | 
						|
			//udelay(10);
 | 
						|
			*(uint32_t*) 0xF00100A0 &= ~(0x3FF);
 | 
						|
		} else {
 | 
						|
			*(uint32_t*) 0xF0010004 |= 0x20000;
 | 
						|
			udelay(10);
 | 
						|
			*(uint32_t*) 0xF00100A0 &= ~(0x30F);
 | 
						|
		}
 | 
						|
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020084 &= ~(0x4000);
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020084 |= 0x4000;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020074 &= ~0x1;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020024 &= ~0x3;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020040 &= ~0x7FF;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020040 |= 0x1F0;
 | 
						|
		udelay(10);
 | 
						|
		*(uint32_t*) 0xF0020074 |= 0x4000;
 | 
						|
	}
 | 
						|
 | 
						|
	sdiohost_enclkout(host, TRUE);
 | 
						|
 | 
						|
	sdiohost_setpaddriving(host, SDIO_MODE_DS);
 | 
						|
 | 
						|
	#if (defined(CONFIG_TARGET_NA51000) || defined(CONFIG_TARGET_NA51055))
 | 
						|
	sdiohost_setphysample(host, TRUE, FALSE);
 | 
						|
	#else
 | 
						|
	sdiohost_setphysample(host, FALSE, TRUE);
 | 
						|
	#endif
 | 
						|
 | 
						|
	sdiohost_resetdata(host);
 | 
						|
 | 
						|
	/* Delay 1 ms (SD spec) after clock is outputted. */
 | 
						|
	/* (Delay 1024 us to reduce code size) */
 | 
						|
	udelay(1024);
 | 
						|
 | 
						|
	sdiohost_setreg(host, SDIO_INT_MASK_REG_OFS, 0xFF);
 | 
						|
	sdiohost_setdatatimeout(host, 0x10000000);
 | 
						|
 | 
						|
	sdiohost_setreg(host, 0x1FC, 0x1);
 | 
						|
 | 
						|
	return E_OK;
 | 
						|
}
 | 
						|
 | 
						|
#if !CONFIG_IS_ENABLED(DM_MMC)
 | 
						|
static int host_set_ios(struct mmc *dev)
 | 
						|
{
 | 
						|
	struct mmc_nvt_host *host = dev->priv;
 | 
						|
#else
 | 
						|
static int host_set_ios(struct udevice *udev)
 | 
						|
{
 | 
						|
	struct mmc *dev = mmc_get_mmc_dev(udev);
 | 
						|
	struct mmc_nvt_host *host = dev_get_priv(udev);
 | 
						|
#endif
 | 
						|
	//kwinyee debug
 | 
						|
	//printf("%s called !,clk = %d, bwidth = %d\n",__func__, dev->clock, dev->bus_width);
 | 
						|
 | 
						|
	if (host->id >= 3) {
 | 
						|
		printf("invalid host id %d\n", host->id);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	if (dev->bus_width) {
 | 
						|
		switch (dev->bus_width) {
 | 
						|
		case 8:
 | 
						|
			sdiohost_setbuswidth(host, SDIO_BUS_WIDTH8);
 | 
						|
			break;
 | 
						|
		case 4:
 | 
						|
			sdiohost_setbuswidth(host, SDIO_BUS_WIDTH4);
 | 
						|
			break;
 | 
						|
		case 1:
 | 
						|
			sdiohost_setbuswidth(host, SDIO_BUS_WIDTH1);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (dev->clock) {
 | 
						|
		static int cur_clk[3] = {0};
 | 
						|
		if(dev->clock != cur_clk[host->id]) {
 | 
						|
			sdiohost_setbusclk(host, dev->clock, (u32*)&host->ns_in_one_cycle);
 | 
						|
 | 
						|
			/*Set host sampling strategy according to different speeds and modes*/
 | 
						|
			if (dev->clock >= 192000000) {
 | 
						|
				sdiohost_setphyclkindly(host, 0x9);
 | 
						|
				sdiohost_setpaddriving(host, SDIO_MODE_SDR104);
 | 
						|
			} else if (dev->clock >= 160000000) {
 | 
						|
				sdiohost_setphyclkindly(host, 0x3);
 | 
						|
				sdiohost_setpaddriving(host, SDIO_MODE_SDR104);
 | 
						|
			} else if (dev->clock >= 120000000) {
 | 
						|
				sdiohost_setphyclkindly(host, 0x1f);
 | 
						|
				sdiohost_setpaddriving(host, SDIO_MODE_SDR104);
 | 
						|
			} else if (dev->clock >= 96000000) {
 | 
						|
				sdiohost_setphyclkindly(host, 0x1b);
 | 
						|
				sdiohost_setpaddriving(host, SDIO_MODE_SDR50);
 | 
						|
			} else if (dev->clock >= 64000000) {
 | 
						|
				sdiohost_setphyclkindly(host, 0x0);
 | 
						|
				sdiohost_setpaddriving(host, SDIO_MODE_SDR50);
 | 
						|
			} else if (dev->clock >= 25000000) {
 | 
						|
				sdiohost_setphyclkindly(host, 0x0);
 | 
						|
				sdiohost_setpaddriving(host, SDIO_MODE_HS);
 | 
						|
			} else {
 | 
						|
				sdiohost_setphyclkindly(host, 0x0);
 | 
						|
				sdiohost_setpaddriving(host, SDIO_MODE_DS);
 | 
						|
			}
 | 
						|
 | 
						|
			if (host->indly_sel >= 0) {
 | 
						|
				sdiohost_setphyclkindly(host, host->indly_sel);
 | 
						|
				printf("use dts indly(0x%x)\n", host->indly_sel);
 | 
						|
			}
 | 
						|
 | 
						|
			/*Reset phy to take effect*/
 | 
						|
			sdiohost_setphyrst(host);
 | 
						|
 | 
						|
			sdiohost_reset(host);
 | 
						|
		}
 | 
						|
 | 
						|
		cur_clk[host->id] = dev->clock;
 | 
						|
		host->mmc_input_clk = dev->clock;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
#if !CONFIG_IS_ENABLED(DM_MMC)
 | 
						|
static int mmc_host_getcd(struct mmc *mmc)
 | 
						|
#else
 | 
						|
static int mmc_host_getcd(struct udevice *dev)
 | 
						|
#endif
 | 
						|
{
 | 
						|
	return 1;
 | 
						|
}
 | 
						|
 | 
						|
static char dev_name_0[] = "NVT_MMC0";
 | 
						|
static char dev_name_1[] = "NVT_MMC1";
 | 
						|
static char dev_name_2[] = "NVT_MMC2";
 | 
						|
 | 
						|
#if !CONFIG_IS_ENABLED(DM_MMC)
 | 
						|
static const struct mmc_ops nvt_hsmmc_ops = {
 | 
						|
	.send_cmd = host_request,
 | 
						|
	.set_ios = host_set_ios,
 | 
						|
	.init = mmc_host_reset,
 | 
						|
	.getcd = mmc_host_getcd,
 | 
						|
};
 | 
						|
/*
 | 
						|
 * mmc_host_init - initialize the mmc controller.
 | 
						|
 * Set initial clock and power for mmc slot.
 | 
						|
 * Initialize mmc struct and register with mmc framework.
 | 
						|
 */
 | 
						|
int nvt_mmc_init(int id)
 | 
						|
{
 | 
						|
	struct mmc *dev;
 | 
						|
	struct mmc_nvt_host *host;
 | 
						|
	struct mmc_config *cfg;
 | 
						|
 | 
						|
	host = malloc(sizeof(struct mmc_nvt_host));
 | 
						|
	if (!host)
 | 
						|
		return -ENOMEM;
 | 
						|
 | 
						|
	memset(host, 0, sizeof(struct mmc_nvt_host));
 | 
						|
 | 
						|
	cfg = malloc(sizeof(struct mmc_config));
 | 
						|
	if (!cfg)
 | 
						|
		return -ENOMEM;
 | 
						|
 | 
						|
	memset(cfg, 0, sizeof(struct mmc_config));
 | 
						|
 | 
						|
 | 
						|
	//init host controler
 | 
						|
	host->id = id;
 | 
						|
	if (id == SDIO_HOST_ID_1) {
 | 
						|
		host->base = (u32*)IOADDR_SDIO_REG_BASE;
 | 
						|
		cfg->name = dev_name_0;
 | 
						|
	} else if (id == SDIO_HOST_ID_2) {
 | 
						|
		host->base = (u32*)IOADDR_SDIO2_REG_BASE;
 | 
						|
		cfg->name = dev_name_1;
 | 
						|
	} else {
 | 
						|
		host->base = (u32*)IOADDR_SDIO3_REG_BASE;
 | 
						|
		cfg->name = dev_name_2;
 | 
						|
	}
 | 
						|
 | 
						|
	host->mmc_input_clk = 312500;
 | 
						|
 | 
						|
	host->mmc_default_clk = 48000000;
 | 
						|
 | 
						|
	mmc_nvt_parse_driving(host);
 | 
						|
 | 
						|
	nvt_emmc_arch_host_preinit(host);
 | 
						|
 | 
						|
	cfg->voltages = MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30 \
 | 
						|
			| MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 \
 | 
						|
			| MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36;
 | 
						|
	cfg->f_min = 312500;
 | 
						|
#ifdef CONFIG_NVT_FPGA_EMULATION
 | 
						|
	cfg->f_max = 6000000;
 | 
						|
#else
 | 
						|
	cfg->f_max = host->mmc_default_clk;
 | 
						|
#endif
 | 
						|
	cfg->b_max = (32*1024);
 | 
						|
	cfg->host_caps = MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS;
 | 
						|
 | 
						|
	if(host->enable_8bits)
 | 
						|
		cfg->host_caps |= MMC_MODE_8BIT;
 | 
						|
 | 
						|
	cfg->ops = &nvt_hsmmc_ops;
 | 
						|
 | 
						|
	dev = mmc_create(cfg, NULL);
 | 
						|
	if (dev == NULL) {
 | 
						|
		free(cfg);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	dev->priv = host;
 | 
						|
 | 
						|
	debug("MMC DEBUG : %s done \n", __FUNCTION__);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
#else
 | 
						|
 | 
						|
#ifdef MMC_SUPPORTS_TUNING
 | 
						|
static int host_execute_tuning(struct udevice *dev, uint opcode)
 | 
						|
{
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
static const struct dm_mmc_ops nvt_hsmmc_ops = {
 | 
						|
	.send_cmd = host_request,
 | 
						|
	.set_ios = host_set_ios,
 | 
						|
	.get_cd = mmc_host_getcd,
 | 
						|
#ifdef MMC_SUPPORTS_TUNING
 | 
						|
	.execute_tuning = host_execute_tuning,
 | 
						|
#endif
 | 
						|
};
 | 
						|
 | 
						|
static int nvt_mmc_probe(struct udevice *dev)
 | 
						|
{
 | 
						|
	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
 | 
						|
	struct nvt_mmc_plat *plat = dev_get_platdata(dev);
 | 
						|
	struct mmc_nvt_host *host = dev_get_priv(dev);
 | 
						|
	struct mmc_config *cfg = &plat->cfg;
 | 
						|
	u32 base_addr;
 | 
						|
 | 
						|
	host->base = (void*)dev_read_addr(dev);
 | 
						|
	base_addr = (u32) host->base;
 | 
						|
 | 
						|
	if (base_addr == IOADDR_SDIO_REG_BASE) {
 | 
						|
		host->id = SDIO_HOST_ID_1;
 | 
						|
		cfg->name = dev_name_0;
 | 
						|
	} else if (base_addr == IOADDR_SDIO2_REG_BASE) {
 | 
						|
		host->id = SDIO_HOST_ID_2;
 | 
						|
		cfg->name = dev_name_1;
 | 
						|
	} else if (base_addr == IOADDR_SDIO3_REG_BASE) {
 | 
						|
		host->id = SDIO_HOST_ID_3;
 | 
						|
		cfg->name = dev_name_2;
 | 
						|
	}
 | 
						|
 | 
						|
	host->mmc_input_clk = 312500;
 | 
						|
 | 
						|
	host->mmc_default_clk = 48000000;
 | 
						|
 | 
						|
	host->ext_caps = 0;
 | 
						|
 | 
						|
	host->do_dma = 1;
 | 
						|
 | 
						|
	mmc_nvt_parse_driving(host);
 | 
						|
 | 
						|
	nvt_emmc_arch_host_preinit(host);
 | 
						|
 | 
						|
	cfg->voltages = MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30 \
 | 
						|
			| MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 \
 | 
						|
			| MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36 \
 | 
						|
			| MMC_VDD_165_195;
 | 
						|
#ifdef CONFIG_NVT_FPGA_EMULATION
 | 
						|
	cfg->f_min = 312500;
 | 
						|
	cfg->f_max = 12000000;
 | 
						|
#else
 | 
						|
	cfg->f_min = 312500;
 | 
						|
	cfg->f_max = host->mmc_default_clk;
 | 
						|
#endif
 | 
						|
	cfg->b_max = (32*1024);
 | 
						|
	cfg->host_caps = MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS;
 | 
						|
 | 
						|
	if (host->enable_8bits)
 | 
						|
		cfg->host_caps |= MMC_MODE_8BIT;
 | 
						|
 | 
						|
	if (host->ext_caps) {
 | 
						|
		cfg->host_caps |= host->ext_caps;
 | 
						|
	}
 | 
						|
 | 
						|
	upriv->mmc = &plat->mmc;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
#if CONFIG_BLK
 | 
						|
static int nvt_mmc_bind(struct udevice *dev)
 | 
						|
{
 | 
						|
	struct nvt_mmc_plat *plat = dev_get_platdata(dev);
 | 
						|
 | 
						|
	return mmc_bind(dev, &plat->mmc, &plat->cfg);
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
static int nvt_mmc_remove(struct udevice *dev)
 | 
						|
{
 | 
						|
	struct mmc_nvt_host *host = dev_get_priv(dev);
 | 
						|
 | 
						|
	if (host->id == SDIO_HOST_ID_1) {
 | 
						|
#ifdef CONFIG_SD_CARD1_POWER_PIN
 | 
						|
		u32 reg_val;
 | 
						|
 | 
						|
		gpio_request(CONFIG_SD_CARD1_POWER_PIN, "sdio1_power");
 | 
						|
		gpio_request(C_GPIO(11), "sdio1_clk");
 | 
						|
		gpio_request(C_GPIO(12), "sdio1_cmd");
 | 
						|
		gpio_request(C_GPIO(13), "sdio1_d0");
 | 
						|
		gpio_request(C_GPIO(14), "sdio1_d1");
 | 
						|
		gpio_request(C_GPIO(15), "sdio1_d2");
 | 
						|
		gpio_request(C_GPIO(16), "sdio1_d3");
 | 
						|
 | 
						|
		if (CONFIG_SD_CARD1_ON_STATE)
 | 
						|
			gpio_direction_output(CONFIG_SD_CARD1_POWER_PIN, 0);
 | 
						|
		else
 | 
						|
			gpio_direction_output(CONFIG_SD_CARD1_POWER_PIN, 1);
 | 
						|
 | 
						|
		reg_val = readl(IOADDR_TOP_REG_BASE + 0xA0);
 | 
						|
		reg_val |= 0x1F800;
 | 
						|
		writel(reg_val, IOADDR_TOP_REG_BASE + 0xA0);
 | 
						|
 | 
						|
		reg_val = readl(IOADDR_PAD_REG_BASE);
 | 
						|
		reg_val &= ~0xFFC00000;
 | 
						|
		reg_val |= 0x55400000;
 | 
						|
		writel(reg_val, IOADDR_PAD_REG_BASE);
 | 
						|
 | 
						|
		reg_val = readl(IOADDR_PAD_REG_BASE + 0x4);
 | 
						|
		reg_val &= ~0x3;
 | 
						|
		reg_val |= 0x1;
 | 
						|
		writel(reg_val, IOADDR_PAD_REG_BASE + 0x4);
 | 
						|
 | 
						|
		gpio_direction_output(C_GPIO(11), 0);
 | 
						|
		gpio_direction_output(C_GPIO(12), 0);
 | 
						|
		gpio_direction_output(C_GPIO(13), 0);
 | 
						|
		gpio_direction_output(C_GPIO(14), 0);
 | 
						|
		gpio_direction_output(C_GPIO(15), 0);
 | 
						|
		gpio_direction_output(C_GPIO(16), 0);
 | 
						|
 | 
						|
		/*Disable SDIO CLK*/
 | 
						|
		reg_val = readl(IOADDR_CG_REG_BASE + 0x74);
 | 
						|
		reg_val &= ~(0x1 << 2);
 | 
						|
		writel(reg_val, IOADDR_CG_REG_BASE + 0x74);
 | 
						|
#endif
 | 
						|
	} else if (host->id == SDIO_HOST_ID_2) {
 | 
						|
#ifdef CONFIG_SD_CARD2_POWER_PIN
 | 
						|
		u32 reg_val;
 | 
						|
		int ret;
 | 
						|
 | 
						|
		gpio_request(CONFIG_SD_CARD2_POWER_PIN, "sdio2_power");
 | 
						|
		gpio_request(C_GPIO(17), "sdio2_clk");
 | 
						|
		gpio_request(C_GPIO(18), "sdio2_cmd");
 | 
						|
		gpio_request(C_GPIO(19), "sdio2_d0");
 | 
						|
		gpio_request(C_GPIO(20), "sdio2_d1");
 | 
						|
		gpio_request(C_GPIO(21), "sdio2_d2");
 | 
						|
		gpio_request(C_GPIO(22), "sdio2_d3");
 | 
						|
 | 
						|
		if (CONFIG_SD_CARD2_ON_STATE)
 | 
						|
			gpio_direction_output(CONFIG_SD_CARD2_POWER_PIN, 0);
 | 
						|
		else
 | 
						|
			gpio_direction_output(CONFIG_SD_CARD2_POWER_PIN, 1);
 | 
						|
 | 
						|
		reg_val = readl(IOADDR_TOP_REG_BASE + 0xA0);
 | 
						|
		reg_val |= 0x7E0000;
 | 
						|
		writel(reg_val, IOADDR_TOP_REG_BASE + 0xA0);
 | 
						|
 | 
						|
		reg_val = readl(IOADDR_PAD_REG_BASE + 0x4);
 | 
						|
		reg_val &= ~0x3FFC;
 | 
						|
		reg_val |= 0x1554;
 | 
						|
		writel(reg_val, IOADDR_PAD_REG_BASE + 0x4);
 | 
						|
 | 
						|
		gpio_direction_output(C_GPIO(17), 0);
 | 
						|
		gpio_direction_output(C_GPIO(18), 0);
 | 
						|
		gpio_direction_output(C_GPIO(19), 0);
 | 
						|
		gpio_direction_output(C_GPIO(20), 0);
 | 
						|
		gpio_direction_output(C_GPIO(21), 0);
 | 
						|
		gpio_direction_output(C_GPIO(22), 0);
 | 
						|
 | 
						|
		/*Disable SDIO CLK*/
 | 
						|
		reg_val = readl(IOADDR_CG_REG_BASE + 0x74);
 | 
						|
		reg_val &= ~(0x1 << 3);
 | 
						|
		writel(reg_val, IOADDR_CG_REG_BASE + 0x74);
 | 
						|
#endif
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static const struct udevice_id nvt_mmc_ids[] = {
 | 
						|
	{
 | 
						|
		.compatible = "nvt,nvt_mmc",
 | 
						|
	},
 | 
						|
	{
 | 
						|
		.compatible = "nvt,nvt_mmc2",
 | 
						|
	},
 | 
						|
	{
 | 
						|
		.compatible = "nvt,nvt_mmc3",
 | 
						|
	},
 | 
						|
	{},
 | 
						|
};
 | 
						|
 | 
						|
U_BOOT_DRIVER(nvt_mmc_drv) = {
 | 
						|
	.name = "nvtivot_mmc",
 | 
						|
	.id		= UCLASS_MMC,
 | 
						|
	.of_match	= nvt_mmc_ids,
 | 
						|
#if CONFIG_BLK
 | 
						|
	.bind		= nvt_mmc_bind,
 | 
						|
#endif
 | 
						|
	.probe = nvt_mmc_probe,
 | 
						|
	.ops = &nvt_hsmmc_ops,
 | 
						|
	.platdata_auto_alloc_size = sizeof(struct nvt_mmc_plat),
 | 
						|
	.priv_auto_alloc_size = sizeof(struct mmc_nvt_host),
 | 
						|
	.remove		= nvt_mmc_remove,
 | 
						|
	.flags		= DM_FLAG_OS_PREPARE,
 | 
						|
};
 | 
						|
#endif
 |