lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame] | 1 | /* |
| 2 | * (C) Copyright 2003 |
| 3 | * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net |
| 4 | * |
| 5 | * See file CREDITS for list of people who contributed to this |
| 6 | * project. |
| 7 | * |
| 8 | * This program is free software; you can redistribute it and/or |
| 9 | * modify it under the terms of the GNU General Public License as |
| 10 | * published by the Free Software Foundation; either version 2 of |
| 11 | * the License, or (at your option) any later version. |
| 12 | * |
| 13 | * This program is distributed in the hope that it will be useful, |
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | * GNU General Public License for more details. |
| 17 | * |
| 18 | * You should have received a copy of the GNU General Public License |
| 19 | * along with this program; if not, write to the Free Software |
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
| 21 | * MA 02111-1307 USA |
| 22 | */ |
| 23 | |
| 24 | |
| 25 | #include <common.h> |
| 26 | #include "zx_mmc.h" |
| 27 | #include "type.h" |
| 28 | #include <asm/io.h> |
| 29 | #include <image.h> |
| 30 | #include <linux/byteorder/generic.h> |
| 31 | |
| 32 | |
| 33 | u32 mmc_rca; |
| 34 | static u32 ocr_avail = 0; |
| 35 | static u32 block_addr = 0; |
| 36 | |
| 37 | #define MMC_BLOCK_SIZE 512 |
| 38 | |
| 39 | static u32 emmc_cmd(u32 cmd, u32 arg, |
| 40 | void *resp, u32 flags) |
| 41 | { |
| 42 | u32 *response = resp; |
| 43 | u32 i,response_words = 0; |
| 44 | u32 status,err_status = ZXMCI_STS_RE | ZXMCI_STS_RCRC | ZXMCI_STS_RTO; |
| 45 | u32 cmdreg; |
| 46 | |
| 47 | /*Clear all raw interrupt status*/ |
| 48 | REG32(SYS_EMMC_REGS_BASE+ZXMCI_RINTSTS) = 0xffffffff; |
| 49 | |
| 50 | cmdreg = cmd & ZXMCI_CMD_INDEX_MASK; |
| 51 | cmdreg |= flags | ZXMCI_CMD_START; |
| 52 | |
| 53 | cmdreg |= (0x1 << 29); |
| 54 | |
| 55 | if(flags & ZXMCI_CMD_RSPLEN) |
| 56 | { |
| 57 | response_words = 4; |
| 58 | } |
| 59 | else if(flags & ZXMCI_CMD_RSPEXP) |
| 60 | { |
| 61 | response_words = 1; |
| 62 | } |
| 63 | |
| 64 | REG32(SYS_EMMC_REGS_BASE+ZXMCI_CMDARG) = arg; |
| 65 | REG32(SYS_EMMC_REGS_BASE+ZXMCI_CMD) = cmdreg; |
| 66 | |
| 67 | /*check command done*/ |
| 68 | do { |
| 69 | status = REG32(SYS_EMMC_REGS_BASE+ZXMCI_RINTSTS); |
| 70 | |
| 71 | } while (!(status & ZXMCI_STS_CD)); |
| 72 | /*check error*/ |
| 73 | if(status & err_status) |
| 74 | { |
| 75 | printf("send cmd error\n"); |
| 76 | return 1; |
| 77 | } |
| 78 | |
| 79 | for(i = 0;i < response_words;i++) |
| 80 | { |
| 81 | response[i] = REG32(SYS_EMMC_REGS_BASE+ZXMCI_RESP0 + i*4); |
| 82 | } |
| 83 | |
| 84 | return 0; |
| 85 | } |
| 86 | |
| 87 | s32 zx_mmc_read(u32 src, u8 * dst, u32 size) |
| 88 | { |
| 89 | u32 ret, i = 0,j = 0; |
| 90 | u32 resp; |
| 91 | u32 data; |
| 92 | u32 wordcount; |
| 93 | u32 *p = (u32 *)dst; |
| 94 | u32 status; |
| 95 | u32 start_addr; |
| 96 | u32 fifo_cnt; |
| 97 | |
| 98 | if (size == 0) |
| 99 | return -1; |
| 100 | |
| 101 | while((REG32(SYS_EMMC_REGS_BASE+ZXMCI_STATUS) & ZXMCI_STA_DATBUSY) != 0) |
| 102 | { |
| 103 | i++; |
| 104 | mmcdelay((80)); |
| 105 | if(i>200) |
| 106 | break; |
| 107 | } |
| 108 | |
| 109 | |
| 110 | start_addr = src; |
| 111 | |
| 112 | |
| 113 | data = REG32(SYS_EMMC_REGS_BASE+ZXMCI_CTRL); |
| 114 | data |=(1<<1) ; |
| 115 | REG32(SYS_EMMC_REGS_BASE+ZXMCI_CTRL) = data; |
| 116 | |
| 117 | i = 0; |
| 118 | do |
| 119 | { |
| 120 | i++; |
| 121 | mmcdelay((80)); |
| 122 | if(i>100) |
| 123 | { |
| 124 | printf("fifo reset failure"); |
| 125 | break; |
| 126 | } |
| 127 | }while(REG32(SYS_EMMC_REGS_BASE+ZXMCI_CTRL) & 2); |
| 128 | |
| 129 | |
| 130 | REG32(SYS_EMMC_REGS_BASE+ZXMCI_BYTCNT) = size; |
| 131 | REG32(SYS_EMMC_REGS_BASE+ZXMCI_BLKSIZ) = MMC_DEFAULT_BLKLEN; |
| 132 | |
| 133 | if (size > MMC_DEFAULT_BLKLEN) |
| 134 | { |
| 135 | ret = emmc_cmd(MMC_CMD_READ_MULTIPLE_BLOCK,start_addr, &resp,(R1 | CF_DATA)); |
| 136 | if (ret) |
| 137 | { |
| 138 | return -MMC_CMD_READ_MULTIPLE_BLOCK; |
| 139 | } |
| 140 | } |
| 141 | else |
| 142 | { |
| 143 | ret = emmc_cmd(MMC_CMD_READ_SINGLE_BLOCK,start_addr, &resp,(R1 | CF_DATA)); |
| 144 | if (ret) |
| 145 | { |
| 146 | return -MMC_CMD_READ_SINGLE_BLOCK; |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | wordcount = 0; |
| 151 | do { |
| 152 | |
| 153 | status = REG32(SYS_EMMC_REGS_BASE+ZXMCI_STATUS); |
| 154 | fifo_cnt =(status >> 17) & 0x1fff; |
| 155 | for(j = 0;j < fifo_cnt;j++) |
| 156 | { |
| 157 | data = REG32(SYS_EMMC_REGS_BASE+ZXMCI_FIFO); |
| 158 | *p++ = data; |
| 159 | wordcount++; |
| 160 | } |
| 161 | |
| 162 | } while(wordcount < (size/4)); |
| 163 | |
| 164 | return 0; |
| 165 | |
| 166 | } |
| 167 | |
| 168 | static u32 mmc_bread(u32 dev_num, u32 blknr, u32 blkcnt, void *dst) |
| 169 | { |
| 170 | u32 src = 0; |
| 171 | s32 ret; |
| 172 | |
| 173 | if (block_addr == 0) |
| 174 | { |
| 175 | src = blknr * MMC_BLOCK_SIZE; |
| 176 | } |
| 177 | else |
| 178 | { |
| 179 | src = blknr; |
| 180 | } |
| 181 | |
| 182 | ret = zx_mmc_read(src, (u8 *) dst, blkcnt * MMC_BLOCK_SIZE); |
| 183 | if (ret < 0) |
| 184 | { |
| 185 | printf("mmc read error\n"); |
| 186 | return 1; |
| 187 | } |
| 188 | |
| 189 | return blkcnt; |
| 190 | } |
| 191 | |
| 192 | |
| 193 | void mmcdelay(unsigned long us) |
| 194 | { |
| 195 | volatile int i = 0; /* approximate */ |
| 196 | for(i=0;i<5000;i++) |
| 197 | { |
| 198 | ; |
| 199 | } |
| 200 | } |
| 201 | |
| 202 | int mmc_read( u32 src, u32 length, void *dst) |
| 203 | { |
| 204 | u32 blkcnt = 0; |
| 205 | u32 start_blk = 0; |
| 206 | int ret = 0; |
| 207 | |
| 208 | if(length%MMC_DEFAULT_BLKLEN) |
| 209 | blkcnt = (length/MMC_DEFAULT_BLKLEN)+1; |
| 210 | else |
| 211 | blkcnt = (length/MMC_DEFAULT_BLKLEN); |
| 212 | |
| 213 | start_blk = src/MMC_DEFAULT_BLKLEN; |
| 214 | block_addr = 1; |
| 215 | |
| 216 | printf("entry mmc_bread\n"); |
| 217 | ret = mmc_bread(0, start_blk, blkcnt, (void *)dst); |
| 218 | |
| 219 | if(ret == blkcnt ) |
| 220 | return 0; |
| 221 | else |
| 222 | return -1; |
| 223 | |
| 224 | } |
| 225 | |
| 226 | uint32_t page_align(uint32_t offset) |
| 227 | { |
| 228 | uint32_t page_size = 2048; |
| 229 | if( offset & (page_size - 1) ) |
| 230 | { |
| 231 | offset &= (~(page_size - 1)); |
| 232 | offset += page_size; |
| 233 | } |
| 234 | return offset; |
| 235 | } |
| 236 | |
| 237 | /******************************************************************************* |
| 238 | * Function: nand_init |
| 239 | * Description: mmc init |
| 240 | * Parameters: |
| 241 | * Input: |
| 242 | * |
| 243 | * Output: |
| 244 | * |
| 245 | * Returns: |
| 246 | * |
| 247 | * |
| 248 | * Others: |
| 249 | ********************************************************************************/ |
| 250 | int32_t mmc_init (void) |
| 251 | { |
| 252 | return 0; |
| 253 | |
| 254 | } |
| 255 | |
| 256 | |