| /* |
| * (C) Copyright 2012 SAMSUNG Electronics |
| * Jaehoon Chung <jh80.chung@samsung.com> |
| * Rajeshawari Shinde <rajeshwari.s@samsung.com> |
| * |
| * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| * |
| */ |
| |
| #include <common.h> |
| #include <malloc.h> |
| #include <mmc.h> |
| #include <dwmmc.h> |
| //#include <asm/arch/clk.h> |
| #include <asm/arch/hardware.h> |
| |
| #include <asm-generic/errno.h> |
| #include "zx234290.h" |
| |
| #define PAGE_SIZE 4096 |
| unsigned char *idma_desc = NULL;/*dw_mmc idma descriptor buffer*/ |
| unsigned char *idma_buffer = NULL;/*dw_mmc idma buffer*/ |
| |
| static int dwmci_wait_reset(struct dwmci_host *host, u32 value) |
| { |
| unsigned long timeout = 1000; |
| u32 ctrl; |
| |
| dwmci_writel(host, DWMCI_CTRL, value); |
| |
| while (timeout--) { |
| ctrl = dwmci_readl(host, DWMCI_CTRL); |
| if (!(ctrl & DWMCI_RESET_ALL)) |
| return 1; |
| } |
| return 0; |
| } |
| |
| |
| static void dwmci_set_idma_desc(struct dwmci_idmac *idmac, |
| u32 desc0, u32 desc1, u32 desc2) |
| { |
| struct dwmci_idmac *desc = idmac; |
| |
| desc->flags = desc0; |
| desc->cnt = desc1; |
| desc->addr = desc2; |
| desc->next_addr = (unsigned int)desc + sizeof(struct dwmci_idmac); |
| |
| } |
| |
| static void dwmci_prepare_data(struct dwmci_host *host, |
| struct mmc_data *data,struct dwmci_idmac *cur_idmac) |
| { |
| |
| #if DWMCI_USE_IDMA |
| unsigned long ctrl = 0; |
| unsigned int i = 0, cnt, blk_cnt; |
| unsigned int flags = 0; |
| ulong start_addr = 0; |
| blk_cnt = data->blocks; |
| #endif |
| dwmci_wait_reset(host, DWMCI_CTRL_FIFO_RESET); |
| #if DWMCI_USE_IDMA |
| if (data->flags == MMC_DATA_READ) |
| { |
| //start_addr = (unsigned int)data->dest; |
| start_addr = (unsigned int)idma_buffer; |
| } |
| else |
| { |
| memcpy(idma_buffer,data->dest,blk_cnt*data->blocksize); |
| start_addr = (unsigned int)idma_buffer; |
| } |
| |
| dwmci_writel(host, DWMCI_DBADDR, (unsigned int)cur_idmac); |
| |
| ctrl = dwmci_readl(host, DWMCI_CTRL); //enable idma |
| ctrl |= DWMCI_IDMAC_EN ; |
| dwmci_writel(host, DWMCI_CTRL, ctrl); |
| |
| dwmci_writel(host, DWMCI_BMOD, 1); |
| |
| ctrl=0; |
| ctrl = dwmci_readl(host, DWMCI_INTMASK); |
| ctrl&=0xffffffcf; |
| dwmci_writel(host, DWMCI_INTMASK, ctrl); //DWMCI_INTMASK set |
| |
| ctrl=0; |
| ctrl = dwmci_readl(host, DWMCI_RINTSTS); //clear RINTSTS |
| ctrl &= 0x0fffe; |
| dwmci_writel(host, DWMCI_RINTSTS, ctrl); |
| |
| ctrl = 0; |
| ctrl = dwmci_readl(host, DWMCI_CTRL); //reset idma |
| ctrl |= 0x4; |
| dwmci_writel(host, DWMCI_CTRL, ctrl); |
| //Wait till IDMA Reset bit gets cleared. |
| do |
| { |
| ctrl = dwmci_readl(host, DWMCI_CTRL); |
| }while (ctrl & 0x4); |
| |
| do { |
| flags = DWMCI_IDMAC_OWN | DWMCI_IDMAC_CH ; |
| flags |= (i == 0) ? DWMCI_IDMAC_FS : 0; |
| if (blk_cnt <= 8) { |
| flags |= DWMCI_IDMAC_LD; |
| cnt = data->blocksize * blk_cnt; |
| } else |
| cnt = data->blocksize * 8; |
| |
| dwmci_set_idma_desc(cur_idmac, flags, cnt, |
| start_addr + (i * PAGE_SIZE)); |
| |
| if(blk_cnt <= 8) |
| break; |
| blk_cnt -= 8; |
| cur_idmac++; |
| i++; |
| } while(1); |
| |
| ctrl = 0; |
| ctrl = dwmci_readl(host, DWMCI_BMOD); |
| ctrl |= DWMCI_BMOD_IDMAC_FB | DWMCI_BMOD_IDMAC_EN; |
| dwmci_writel(host, DWMCI_BMOD, ctrl); |
| |
| |
| dwmci_writel(host, DWMCI_PLDMND, 1); |
| |
| #endif |
| dwmci_writel(host, DWMCI_BLKSIZ, data->blocksize); |
| dwmci_writel(host, DWMCI_BYTCNT, data->blocksize * data->blocks); |
| } |
| |
| static int dwmci_set_transfer_mode(struct dwmci_host *host, |
| struct mmc_data *data) |
| { |
| unsigned long mode; |
| |
| mode = DWMCI_CMD_DATA_EXP; |
| if (data->flags & MMC_DATA_WRITE) |
| mode |= DWMCI_CMD_RW; |
| |
| return mode; |
| } |
| |
| static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, |
| struct mmc_data *data) |
| { |
| struct dwmci_host *host = (struct dwmci_host *)mmc->priv; |
| int flags = 0, i; |
| //unsigned int timeout = 100000; |
| int timeout = 0xffffffff; |
| u32 retry = 10000; |
| u32 mask, ctrl; |
| |
| struct dwmci_idmac *cur_idmac = (struct dwmci_idmac *)idma_desc; |
| |
| while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) { |
| if (timeout == 0) { |
| printf("Timeout on data busy,status = %x\n",dwmci_readl(host, DWMCI_STATUS)); |
| return TIMEOUT; |
| } |
| timeout--; |
| } |
| |
| dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL); |
| |
| if (data) |
| dwmci_prepare_data(host, data,cur_idmac); |
| |
| |
| dwmci_writel(host, DWMCI_CMDARG, cmd->cmdarg); |
| |
| if (data) |
| flags = dwmci_set_transfer_mode(host, data ); |
| |
| if ((cmd->resp_type & MMC_RSP_136) && (cmd->resp_type & MMC_RSP_BUSY)) |
| return -1; |
| |
| if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) |
| flags |= DWMCI_CMD_ABORT_STOP; |
| else |
| flags |= DWMCI_CMD_PRV_DAT_WAIT; |
| |
| if (cmd->cmdidx == MMC_CMD_GO_IDLE_STATE) |
| flags |= DWMCI_CMD_SEND_INIT; //temp add for mmc reset |
| |
| if (cmd->resp_type & MMC_RSP_PRESENT) { |
| flags |= DWMCI_CMD_RESP_EXP; |
| if (cmd->resp_type & MMC_RSP_136) |
| flags |= DWMCI_CMD_RESP_LENGTH; |
| } |
| |
| if (cmd->resp_type & MMC_RSP_CRC) |
| flags |= DWMCI_CMD_CHECK_CRC; |
| |
| if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK) ||(cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK) ) |
| flags |= DWMCI_CMD_SEND_STOP; |
| |
| flags |= (cmd->cmdidx | DWMCI_CMD_START | DWMCI_CMD_USE_HOLD_REG); |
| |
| //printf("Sending CMD%d,flag is %x\n",cmd->cmdidx,flags); |
| |
| dwmci_writel(host, DWMCI_CMD, flags); |
| |
| for (i = 0; i < retry; i++) { |
| mask = dwmci_readl(host, DWMCI_RINTSTS); |
| if (mask & DWMCI_INTMSK_CDONE) { |
| if (!data) |
| dwmci_writel(host, DWMCI_RINTSTS, mask); |
| break; |
| } |
| } |
| |
| if (i == retry) |
| { |
| printf("CMD DONE Timeout..\n"); |
| return TIMEOUT; |
| } |
| |
| if (mask & DWMCI_INTMSK_RTO) { |
| printf("Response Timeout.. mask =%x\n", (unsigned int)mask); |
| return TIMEOUT; |
| } else if (mask & DWMCI_INTMSK_RE) { |
| printf("Response Error..\n"); |
| return -1; |
| } |
| #if (!DWMCI_USE_IDMA) |
| if(data) |
| { |
| dwmci_cpu_transfer_data(host,data); |
| } |
| #endif |
| |
| |
| if (cmd->resp_type & MMC_RSP_PRESENT) { |
| if (cmd->resp_type & MMC_RSP_136) { |
| cmd->response[0] = dwmci_readl(host, DWMCI_RESP3); |
| cmd->response[1] = dwmci_readl(host, DWMCI_RESP2); |
| cmd->response[2] = dwmci_readl(host, DWMCI_RESP1); |
| cmd->response[3] = dwmci_readl(host, DWMCI_RESP0); |
| } else { |
| cmd->response[0] = dwmci_readl(host, DWMCI_RESP0); |
| } |
| } |
| |
| if (data) { |
| do { |
| mask = dwmci_readl(host, DWMCI_RINTSTS); |
| if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) { |
| printf("DATA ERROR,mask = 0x%x!\n",mask); |
| return -1; |
| } |
| } while (!(mask & DWMCI_INTMSK_DTO)); |
| |
| dwmci_writel(host, DWMCI_RINTSTS, mask); |
| |
| ctrl = dwmci_readl(host, DWMCI_CTRL); |
| ctrl &= ~(DWMCI_DMA_EN); |
| dwmci_writel(host, DWMCI_CTRL, ctrl); |
| #if (DWMCI_USE_IDMA) |
| if (data->flags == MMC_DATA_READ) |
| { |
| memcpy(data->src,idma_buffer,data->blocks*data->blocksize); |
| } |
| #endif |
| } |
| //udelay(100); |
| |
| mmc_delay(100); |
| return 0; |
| } |
| u32 status1 = 0; |
| static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) |
| { |
| u32 div, status; |
| //int timeout = 10000; |
| int timeout = 0xffff; //mod temp |
| unsigned long sclk; |
| |
| if (freq == host->clock) |
| return 0; |
| |
| /* |
| * If host->mmc_clk didn't define, |
| * then assume that host->bus_hz is source clock value. |
| * host->bus_hz should be set from user. |
| */ |
| if (host->mmc_clk) |
| sclk = host->mmc_clk(host->dev_index); |
| else if (host->bus_hz) |
| sclk = host->bus_hz; |
| else { |
| printf("Didn't get source clock value..\n"); |
| return -EINVAL; |
| } |
| |
| //div = DIV_ROUND_UP(sclk, 2 * freq); |
| div = (sclk != freq) ? DIV_ROUND_UP(sclk, 2 * freq) : 0; |
| dwmci_writel(host, DWMCI_CLKENA, 0); |
| dwmci_writel(host, DWMCI_CLKSRC, 0); |
| |
| dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT | |
| DWMCI_CMD_UPD_CLK | DWMCI_CMD_START); |
| |
| do { |
| status = dwmci_readl(host, DWMCI_CMD); |
| if (timeout-- < 0) { |
| printf("TIMEOUT1 error!!,STATUS = %x\n", (unsigned int)status); |
| return -ETIMEDOUT; |
| } |
| } while (status & DWMCI_CMD_START); |
| status1 = timeout; |
| dwmci_writel(host, DWMCI_CLKDIV, div); |
| dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT | |
| DWMCI_CMD_UPD_CLK | DWMCI_CMD_START); |
| timeout = 0xffff; //mod temp |
| do { |
| status = dwmci_readl(host, DWMCI_CMD); |
| if (timeout-- < 0) { |
| printf("TIMEOUT2 error!!\n"); |
| return -ETIMEDOUT; |
| } |
| } while (status & DWMCI_CMD_START); |
| |
| printf("TIMEOUT is %x\n",status1); |
| |
| /*dwmci_writel(host, DWMCI_CLKENA, DWMCI_CLKEN_ENABLE | |
| DWMCI_CLKEN_LOW_PWR);*/ |
| dwmci_writel(host, DWMCI_CLKENA, DWMCI_CLKEN_ENABLE); |
| |
| dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT | |
| DWMCI_CMD_UPD_CLK | DWMCI_CMD_START); |
| |
| //timeout = 10000; |
| timeout = 0xffff; //mod temp |
| do { |
| status = dwmci_readl(host, DWMCI_CMD); |
| if (timeout-- < 0) { |
| printf("TIMEOUT3 error!!\n"); |
| return -ETIMEDOUT; |
| } |
| } while (status & DWMCI_CMD_START); |
| |
| host->clock = freq; |
| |
| return 0; |
| } |
| |
| static void dwmci_set_ios(struct mmc *mmc) |
| { |
| struct dwmci_host *host = (struct dwmci_host *)mmc->priv; |
| u32 ctype; |
| |
| printf("Buswidth = %d, clock: %d\n",mmc->bus_width, mmc->clock); |
| |
| dwmci_setup_bus(host, mmc->clock); |
| switch (mmc->bus_width) { |
| case 8: |
| ctype = DWMCI_CTYPE_8BIT; |
| break; |
| case 4: |
| ctype = DWMCI_CTYPE_4BIT; |
| break; |
| default: |
| ctype = DWMCI_CTYPE_1BIT; |
| break; |
| } |
| |
| dwmci_writel(host, DWMCI_CTYPE, ctype); |
| |
| if (host->clksel) |
| host->clksel(host); |
| } |
| |
| static int dwmci_init(struct mmc *mmc) |
| { |
| struct dwmci_host *host = (struct dwmci_host *)mmc->priv; |
| u32 fifo_size, fifoth_val; |
| |
| |
| |
| if (!dwmci_wait_reset(host, DWMCI_RESET_ALL)) { |
| debug("%s[%d] Fail-reset!!\n",__func__,__LINE__); |
| return -1; |
| } |
| |
| dwmci_writel(host, DWMCI_CTRL, 0); |
| dwmci_writel(host, DWMCI_PWREN, 1); |
| |
| dwmci_writel(host, DWMCI_RINTSTS, 0xFFFFFFFF); |
| //dwmci_writel(host, DWMCI_INTMASK, 0); |
| dwmci_writel(host, DWMCI_INTMASK, 0xfffffffe); |
| |
| dwmci_writel(host, DWMCI_TMOUT, 0xFFFFFFFF); |
| |
| dwmci_writel(host, DWMCI_IDINTEN, 0); |
| dwmci_writel(host, DWMCI_BMOD, 1); |
| |
| dwmci_writel(host, DWMCI_DEBNCE, 0xfffff); |
| dwmci_writel(host, DWMCI_CARDRDTHRCTRL, 0x1|(0x200<<16)); //512 byte cardthr |
| |
| fifo_size = 128; |
| if (host->fifoth_val) |
| fifoth_val = host->fifoth_val; |
| else |
| fifoth_val = MSIZE(0x2) | RX_WMARK(fifo_size/2 -1) | |
| TX_WMARK(fifo_size/2); |
| dwmci_writel(host, DWMCI_FIFOTH, fifoth_val); |
| |
| dwmci_writel(host, DWMCI_CLKENA, 0); |
| dwmci_writel(host, DWMCI_CLKSRC, 0); |
| |
| return 0; |
| } |
| |
| |
| int dwmci_getcd(struct mmc *mmc) |
| { |
| struct dwmci_host *host = (struct dwmci_host *)mmc->priv; |
| int num = 0; |
| |
| num = dwmci_readl(host,DWMCI_CDETECT)&(0x3fffffff); |
| |
| return (num != 0x01); |
| } |
| |
| void zx29_dwmci_clksel(void) |
| { |
| int clkdiv = 0; |
| //7520 mmc clk |
| clkdiv = readl(SYS_STD_CRM_BASE+0x5c); |
| clkdiv |= 0x3<<16; //clk enable |
| writel(clkdiv,SYS_STD_CRM_BASE+0x5c); |
| clkdiv = 0; |
| |
| //udelay(80); |
| mmc_delay(80); |
| clkdiv = readl(SYS_STD_CRM_BASE+0x40); |
| clkdiv &= 0xffffffcf; //clk 52M |
| writel(clkdiv,SYS_STD_CRM_BASE+0x40); |
| clkdiv = 0; |
| mmc_delay(80); |
| |
| clkdiv = readl(SYS_STD_CRM_BASE+0x60); |
| clkdiv |= 0x1<<16; //reset release |
| writel(clkdiv,SYS_STD_CRM_BASE+0x60); |
| clkdiv = 0; |
| |
| //udelay(1000); |
| mmc_delay(1000); |
| |
| } |
| |
| int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk) |
| { |
| struct mmc *mmc; |
| int err = 0; |
| |
| mmc = malloc(sizeof(struct mmc)); |
| if (!mmc) { |
| printf("mmc malloc fail!\n"); |
| return -1; |
| } |
| memset(mmc,0x0,sizeof(struct mmc)); |
| mmc->priv = host; |
| host->mmc = mmc; |
| |
| sprintf(mmc->name, "%s", host->name); |
| mmc->send_cmd = dwmci_send_cmd; |
| mmc->set_ios = dwmci_set_ios; |
| mmc->init = dwmci_init; |
| |
| mmc->getcd = dwmci_getcd; //get card num |
| |
| mmc->f_min = min_clk; |
| mmc->f_max = max_clk; |
| |
| mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; |
| |
| mmc->host_caps = host->caps; |
| |
| if (host->buswidth == 8) { |
| mmc->host_caps |= MMC_MODE_8BIT; |
| mmc->host_caps &= ~MMC_MODE_4BIT; |
| } else { |
| mmc->host_caps |= MMC_MODE_4BIT; |
| mmc->host_caps &= ~MMC_MODE_8BIT; |
| } |
| mmc->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_HC; |
| |
| err = mmc_register(mmc); |
| |
| return err; |
| } |
| |
| static char *ZX29_NAME = "ZX29 DWMMC"; |
| |
| int zx29_dwmci_init(unsigned int regbase,int bus_width,int index) |
| { |
| struct dwmci_host *host = NULL; |
| int reg = 0x3c; |
| host = malloc(sizeof(struct dwmci_host)); |
| if (!host) { |
| printf("dwmci_host malloc fail!\n"); |
| return 1; |
| } |
| memset(host,0x0,sizeof(struct dwmci_host)); |
| host->name = ZX29_NAME; |
| host->ioaddr = (void *)regbase; |
| host->buswidth = bus_width; |
| host->dev_index = index; |
| host->clksel = zx29_dwmci_clksel; //7520 fpga temp |
| host->bus_hz = 52000000; |
| |
| add_dwmci(host, 52000000, 400000); |
| zx234290_i2c_write_reg(MMC_CTRL, ®); |
| |
| idma_desc = (unsigned char*)(CONFIG_NAND_DMA_BUF_ADDR+0x4400); /*dw_mmc idma_descriptor*/ |
| idma_buffer = (unsigned char*)(CONFIG_NAND_DMA_BUF_ADDR+0x5400); /*dw_mmc idma_buffer*/ |
| return 0; |
| |
| } |
| |
| int test1 = 0; |
| int dwmci_cpu_transfer_data(struct dwmci_host *host, |
| struct mmc_data *data) |
| { |
| u32 nTempStatus; |
| u32 nTransLen; |
| u32 i; |
| u32 nDepthMod, nAlignDepthLen; |
| u32 nWidthMod, nAlignWidthLen; |
| u32 nTempData; |
| u32 len = 0; |
| //BYTE *pbTempData; |
| |
| //DMA is not used. |
| |
| len = data->blocksize * data->blocks; |
| |
| nDepthMod = len % MMC_FIFO_LEN; |
| nWidthMod = len % MMC_WIDTH_LEN; |
| |
| //length align to fifo depth |
| nAlignDepthLen = len - nDepthMod; |
| nAlignWidthLen = nDepthMod - nWidthMod; |
| |
| nTransLen = 0; |
| |
| //read command |
| if (data->flags == MMC_DATA_READ) |
| { |
| |
| while (nTransLen < nAlignDepthLen) |
| { |
| nTempStatus = dwmci_readl(host,DWMCI_STATUS); |
| if (nTempStatus & MMC_STATUS_FIFO_FULL) |
| { |
| for (i=0; i< MMC_FIFO_DEPTH; i++, nTransLen += MMC_WIDTH_LEN) |
| |
| { |
| *(u32 *)((unsigned char *)data->dest + nTransLen) = dwmci_readl(host,DWMCI_DATA); |
| } |
| |
| } |
| |
| else if (dwmci_readl(host,DWMCI_RINTSTS) & DWMCI_INTMSK_HLE) |
| { |
| return UNUSABLE_ERR; |
| } |
| |
| else if (dwmci_readl(host,DWMCI_RINTSTS) & DWMCI_DATA_ERR) |
| return -1; |
| |
| else if (dwmci_readl(host,DWMCI_RINTSTS) & DWMCI_DATA_TOUT) |
| return TIMEOUT; |
| |
| } |
| |
| for (i=0; i < nAlignWidthLen;) |
| { |
| if ((dwmci_readl(host,DWMCI_STATUS) & MMC_STATUS_FIFO_EMPTY) == 0) |
| { |
| *(u32 *)((unsigned char *)data->dest + nTransLen) = dwmci_readl(host,DWMCI_DATA); |
| |
| i+= MMC_WIDTH_LEN; |
| nTransLen += MMC_WIDTH_LEN; |
| |
| } |
| |
| else if (dwmci_readl(host,DWMCI_RINTSTS) & DWMCI_DATA_ERR) |
| return -1; |
| |
| else if (dwmci_readl(host,DWMCI_RINTSTS) & DWMCI_DATA_TOUT) |
| return TIMEOUT; |
| |
| |
| } |
| |
| //not word align |
| if (nWidthMod) |
| { |
| while (dwmci_readl(host,DWMCI_STATUS) & MMC_STATUS_FIFO_EMPTY) |
| { |
| if (dwmci_readl(host,DWMCI_RINTSTS) & DWMCI_DATA_ERR) |
| return -1; |
| |
| if (dwmci_readl(host,DWMCI_RINTSTS) & DWMCI_DATA_TOUT) |
| return TIMEOUT; |
| } |
| |
| nTempData= dwmci_readl(host,DWMCI_DATA); |
| |
| memcpy(((unsigned char *)data->dest + nTransLen), &nTempData, nWidthMod); |
| } |
| |
| return 0; |
| |
| } |
| |
| |
| //write command |
| else |
| { |
| while (nTransLen < nAlignDepthLen) |
| { |
| if (dwmci_readl(host,DWMCI_STATUS) & MMC_STATUS_FIFO_EMPTY) |
| { |
| |
| for (i=0; i< MMC_FIFO_DEPTH; i=i+1,nTransLen=nTransLen + MMC_WIDTH_LEN) |
| { |
| dwmci_writel(host,DWMCI_DATA, *((u32 *)((unsigned char *)data->src + nTransLen))); |
| |
| } |
| |
| } |
| |
| else if (dwmci_readl(host,DWMCI_RINTSTS) & DWMCI_DATA_ERR) |
| return -1; |
| |
| else if (dwmci_readl(host,DWMCI_RINTSTS) & DWMCI_DATA_TOUT) |
| return TIMEOUT; |
| |
| |
| |
| } |
| |
| for (i=0; i < nAlignWidthLen;) |
| { |
| if ((dwmci_readl(host,DWMCI_STATUS) & MMC_STATUS_FIFO_FULL) == 0) |
| { |
| |
| dwmci_writel(host,DWMCI_DATA,*((u32 *)((unsigned char *)data->src + nTransLen))); |
| i+=MMC_WIDTH_LEN; |
| nTransLen += MMC_WIDTH_LEN; |
| } |
| |
| else if (dwmci_readl(host,DWMCI_RINTSTS) & DWMCI_DATA_ERR) |
| return -1; |
| |
| else if (dwmci_readl(host,DWMCI_RINTSTS) & DWMCI_DATA_TOUT) |
| return TIMEOUT; |
| |
| } |
| |
| //not word align |
| if (nWidthMod) |
| { |
| while (dwmci_readl(host,DWMCI_STATUS) & MMC_STATUS_FIFO_FULL) |
| { |
| if (dwmci_readl(host,DWMCI_RINTSTS) & DWMCI_DATA_ERR) |
| return -1; |
| |
| if (dwmci_readl(host,DWMCI_RINTSTS) & DWMCI_DATA_TOUT) |
| return TIMEOUT; |
| } |
| |
| memcpy(&nTempData,((unsigned char *)data->src + nTransLen), nWidthMod); |
| |
| dwmci_writel(host,DWMCI_DATA, nTempData); |
| } |
| |
| return 0; |
| |
| } |
| |
| |
| } |
| |
| int board_mmc_init(bd_t *bis) |
| { |
| int err; |
| struct mmc *mmc; |
| unsigned int regbase = ZX29_SDMMC0_BASE; |
| int bus_width = 8; |
| int index = 0; |
| |
| /*initialize synpsys dw mmc controler*/ |
| err = zx29_dwmci_init(regbase,bus_width,index); |
| return err; |
| } |
| |
| |
| |
| /*temp use usdelay*/ |
| void mmc_delay(unsigned long us) |
| { |
| #if 0 |
| int i = 0; /* approximate */ |
| for(i=0;i<5000;i++) |
| { |
| ; |
| } |
| #else |
| udelay(us); |
| #endif |
| } |
| |