| /* |
| * (C) Copyright 2003 |
| * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net |
| * |
| * See file CREDITS for list of people who contributed to this |
| * project. |
| * |
| * 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 "zx_mmc.h" |
| #include "type.h" |
| #include <asm/io.h> |
| #include <image.h> |
| #include <linux/byteorder/generic.h> |
| |
| |
| u32 mmc_rca; |
| static u32 ocr_avail = 0; |
| static u32 block_addr = 0; |
| |
| #define MMC_BLOCK_SIZE 512 |
| |
| static u32 emmc_cmd(u32 cmd, u32 arg, |
| void *resp, u32 flags) |
| { |
| u32 *response = resp; |
| u32 i,response_words = 0; |
| u32 status,err_status = ZXMCI_STS_RE | ZXMCI_STS_RCRC | ZXMCI_STS_RTO; |
| u32 cmdreg; |
| |
| /*Clear all raw interrupt status*/ |
| REG32(SYS_EMMC_REGS_BASE+ZXMCI_RINTSTS) = 0xffffffff; |
| |
| cmdreg = cmd & ZXMCI_CMD_INDEX_MASK; |
| cmdreg |= flags | ZXMCI_CMD_START; |
| |
| cmdreg |= (0x1 << 29); |
| |
| if(flags & ZXMCI_CMD_RSPLEN) |
| { |
| response_words = 4; |
| } |
| else if(flags & ZXMCI_CMD_RSPEXP) |
| { |
| response_words = 1; |
| } |
| |
| REG32(SYS_EMMC_REGS_BASE+ZXMCI_CMDARG) = arg; |
| REG32(SYS_EMMC_REGS_BASE+ZXMCI_CMD) = cmdreg; |
| |
| /*check command done*/ |
| do { |
| status = REG32(SYS_EMMC_REGS_BASE+ZXMCI_RINTSTS); |
| |
| } while (!(status & ZXMCI_STS_CD)); |
| /*check error*/ |
| if(status & err_status) |
| { |
| printf("send cmd error\n"); |
| return 1; |
| } |
| |
| for(i = 0;i < response_words;i++) |
| { |
| response[i] = REG32(SYS_EMMC_REGS_BASE+ZXMCI_RESP0 + i*4); |
| } |
| |
| return 0; |
| } |
| |
| s32 zx_mmc_read(u32 src, u8 * dst, u32 size) |
| { |
| u32 ret, i = 0,j = 0; |
| u32 resp; |
| u32 data; |
| u32 wordcount; |
| u32 *p = (u32 *)dst; |
| u32 status; |
| u32 start_addr; |
| u32 fifo_cnt; |
| |
| if (size == 0) |
| return -1; |
| |
| while((REG32(SYS_EMMC_REGS_BASE+ZXMCI_STATUS) & ZXMCI_STA_DATBUSY) != 0) |
| { |
| i++; |
| mmcdelay((80)); |
| if(i>200) |
| break; |
| } |
| |
| |
| start_addr = src; |
| |
| |
| data = REG32(SYS_EMMC_REGS_BASE+ZXMCI_CTRL); |
| data |=(1<<1) ; |
| REG32(SYS_EMMC_REGS_BASE+ZXMCI_CTRL) = data; |
| |
| i = 0; |
| do |
| { |
| i++; |
| mmcdelay((80)); |
| if(i>100) |
| { |
| printf("fifo reset failure"); |
| break; |
| } |
| }while(REG32(SYS_EMMC_REGS_BASE+ZXMCI_CTRL) & 2); |
| |
| |
| REG32(SYS_EMMC_REGS_BASE+ZXMCI_BYTCNT) = size; |
| REG32(SYS_EMMC_REGS_BASE+ZXMCI_BLKSIZ) = MMC_DEFAULT_BLKLEN; |
| |
| if (size > MMC_DEFAULT_BLKLEN) |
| { |
| ret = emmc_cmd(MMC_CMD_READ_MULTIPLE_BLOCK,start_addr, &resp,(R1 | CF_DATA)); |
| if (ret) |
| { |
| return -MMC_CMD_READ_MULTIPLE_BLOCK; |
| } |
| } |
| else |
| { |
| ret = emmc_cmd(MMC_CMD_READ_SINGLE_BLOCK,start_addr, &resp,(R1 | CF_DATA)); |
| if (ret) |
| { |
| return -MMC_CMD_READ_SINGLE_BLOCK; |
| } |
| } |
| |
| wordcount = 0; |
| do { |
| |
| status = REG32(SYS_EMMC_REGS_BASE+ZXMCI_STATUS); |
| fifo_cnt =(status >> 17) & 0x1fff; |
| for(j = 0;j < fifo_cnt;j++) |
| { |
| data = REG32(SYS_EMMC_REGS_BASE+ZXMCI_FIFO); |
| *p++ = data; |
| wordcount++; |
| } |
| |
| } while(wordcount < (size/4)); |
| |
| return 0; |
| |
| } |
| |
| static u32 mmc_bread(u32 dev_num, u32 blknr, u32 blkcnt, void *dst) |
| { |
| u32 src = 0; |
| s32 ret; |
| |
| if (block_addr == 0) |
| { |
| src = blknr * MMC_BLOCK_SIZE; |
| } |
| else |
| { |
| src = blknr; |
| } |
| |
| ret = zx_mmc_read(src, (u8 *) dst, blkcnt * MMC_BLOCK_SIZE); |
| if (ret < 0) |
| { |
| printf("mmc read error\n"); |
| return 1; |
| } |
| |
| return blkcnt; |
| } |
| |
| |
| void mmcdelay(unsigned long us) |
| { |
| volatile int i = 0; /* approximate */ |
| for(i=0;i<5000;i++) |
| { |
| ; |
| } |
| } |
| |
| int mmc_read( u32 src, u32 length, void *dst) |
| { |
| u32 blkcnt = 0; |
| u32 start_blk = 0; |
| int ret = 0; |
| |
| if(length%MMC_DEFAULT_BLKLEN) |
| blkcnt = (length/MMC_DEFAULT_BLKLEN)+1; |
| else |
| blkcnt = (length/MMC_DEFAULT_BLKLEN); |
| |
| start_blk = src/MMC_DEFAULT_BLKLEN; |
| block_addr = 1; |
| |
| printf("entry mmc_bread\n"); |
| ret = mmc_bread(0, start_blk, blkcnt, (void *)dst); |
| |
| if(ret == blkcnt ) |
| return 0; |
| else |
| return -1; |
| |
| } |
| |
| uint32_t page_align(uint32_t offset) |
| { |
| uint32_t page_size = 2048; |
| if( offset & (page_size - 1) ) |
| { |
| offset &= (~(page_size - 1)); |
| offset += page_size; |
| } |
| return offset; |
| } |
| |
| /******************************************************************************* |
| * Function: nand_init |
| * Description: mmc init |
| * Parameters: |
| * Input: |
| * |
| * Output: |
| * |
| * Returns: |
| * |
| * |
| * Others: |
| ********************************************************************************/ |
| int32_t mmc_init (void) |
| { |
| return 0; |
| |
| } |
| |
| |