| 1 | #include <qi.h> |
| 2 | #include "hs_mmc.h" |
| 3 | #include <string.h> |
| 4 | #include <glamo-mmc.h> |
| 5 | |
| 6 | #define HCLK_OPERATION |
| 7 | #undef DEBUG_HSMMC |
| 8 | #ifdef DEBUG_HSMMC |
| 9 | #define dbg(x...) printf(x) |
| 10 | #else |
| 11 | #define dbg(x...) do { } while (0) |
| 12 | #endif |
| 13 | |
| 14 | //#include <linux-mmc.h> |
| 15 | #include <linux-mmc-protocol.h> |
| 16 | #include <s3c6410.h> |
| 17 | //#include <linux/mmc/protocol.h> |
| 18 | //#include <asm/io.h> |
| 19 | //#include <movi.h> |
| 20 | |
| 21 | #include "hs_mmc.h" |
| 22 | #include <mmc.h> |
| 23 | |
| 24 | #define SDI_Tx_buffer_HSMMC (0x51000000) |
| 25 | #define SDI_Rx_buffer_HSMMC (0x51000000+(0x300000)) |
| 26 | #define SDI_Compare_buffer_HSMMC (0x51000000+(0x600000)) |
| 27 | |
| 28 | #define Card_OneBlockSize_ver1 512 |
| 29 | |
| 30 | #define MMC_DEFAULT_RCA (1<<16) |
| 31 | |
| 32 | /* Global variables */ |
| 33 | |
| 34 | static u32 HS_DMA_END = 0; |
| 35 | static u32 rca = 0; |
| 36 | |
| 37 | static ulong HCLK; |
| 38 | |
| 39 | int movi_hc = 1; /* sdhc style block indexing */ |
| 40 | enum card_type card_type; |
| 41 | |
| 42 | /* extern functions */ |
| 43 | extern ulong get_HCLK(void); |
| 44 | |
| 45 | |
| 46 | #define s3c_hsmmc_readl(x) *((unsigned int *)(((ELFIN_HSMMC_BASE + (HSMMC_CHANNEL * 0x100000)) + (x)))) |
| 47 | #define s3c_hsmmc_readw(x) *((unsigned short *)(((ELFIN_HSMMC_BASE + (HSMMC_CHANNEL * 0x100000)) + (x)))) |
| 48 | #define s3c_hsmmc_readb(x) *((unsigned char *)(((ELFIN_HSMMC_BASE + (HSMMC_CHANNEL * 0x100000)) + (x)))) |
| 49 | |
| 50 | #define s3c_hsmmc_writel(v,x) *((unsigned int *) (((ELFIN_HSMMC_BASE + (HSMMC_CHANNEL * 0x100000)) + (x)))) = v |
| 51 | #define s3c_hsmmc_writew(v,x) *((unsigned short *)(((ELFIN_HSMMC_BASE + (HSMMC_CHANNEL * 0x100000)) + (x)))) = v |
| 52 | #define s3c_hsmmc_writeb(v,x) *((unsigned char *)(((ELFIN_HSMMC_BASE + (HSMMC_CHANNEL * 0x100000)) + (x)))) = v |
| 53 | |
| 54 | #define readl(x) *((unsigned int *)(x)) |
| 55 | #define writel(v, x) *((unsigned int *)(x)) = v |
| 56 | |
| 57 | #define UNSTUFF_BITS(resp,start,size) \ |
| 58 | ({ \ |
| 59 | const int __size = size; \ |
| 60 | const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \ |
| 61 | const int __off = 3 - ((start) / 32); \ |
| 62 | const int __shft = (start) & 31; \ |
| 63 | u32 __res; \ |
| 64 | \ |
| 65 | __res = resp[__off] >> __shft; \ |
| 66 | if (__size + __shft > 32) \ |
| 67 | __res |= resp[__off-1] << ((32 - __shft) & 31); \ |
| 68 | __res & __mask; \ |
| 69 | }) |
| 70 | |
| 71 | static int wait_for_cmd_done (void) |
| 72 | { |
| 73 | u32 i; |
| 74 | ushort n_int, e_int; |
| 75 | |
| 76 | dbg("wait_for_cmd_done\n"); |
| 77 | for (i = 0; i < 0x20000000; i++) { |
| 78 | n_int = s3c_hsmmc_readw(HM_NORINTSTS); |
| 79 | dbg(" HM_NORINTSTS: %04x\n", n_int); |
| 80 | if (n_int & 0x8000) |
| 81 | /* any error */ |
| 82 | break; |
| 83 | if (n_int & 0x0001) |
| 84 | /* command complete */ |
| 85 | return 0; |
| 86 | } |
| 87 | |
| 88 | e_int = s3c_hsmmc_readw(HM_ERRINTSTS); |
| 89 | s3c_hsmmc_writew(e_int, HM_ERRINTSTS); |
| 90 | s3c_hsmmc_writew(n_int, HM_NORINTSTS); |
| 91 | puts("cmd error1: 0x"); |
| 92 | print32(e_int); |
| 93 | puts(", HM_NORINTSTS: 0x"); |
| 94 | print32(n_int); |
| 95 | puts("\n"); |
| 96 | |
| 97 | return -1; |
| 98 | } |
| 99 | |
| 100 | |
| 101 | static void ClearCommandCompleteStatus(void) |
| 102 | { |
| 103 | s3c_hsmmc_writew(1 << 0, HM_NORINTSTS); |
| 104 | while (s3c_hsmmc_readw(HM_NORINTSTS) & 0x1) { |
| 105 | s3c_hsmmc_writew(1 << 0, HM_NORINTSTS); |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | static void card_irq_enable(ushort temp) |
| 110 | { |
| 111 | s3c_hsmmc_writew((s3c_hsmmc_readw(HM_NORINTSTSEN) & 0xFEFF) | (temp << 8), HM_NORINTSTSEN); |
| 112 | } |
| 113 | |
| 114 | void hsmmc_reset (void) |
| 115 | { |
| 116 | s3c_hsmmc_writeb(0x3, HM_SWRST); |
| 117 | } |
| 118 | |
| 119 | void hsmmc_set_gpio (void) |
| 120 | { |
| 121 | u32 reg; |
| 122 | |
| 123 | reg = readl(GPGCON) & 0xf0000000; |
| 124 | writel(reg | 0x02222222, GPGCON); |
| 125 | |
| 126 | reg = readl(GPGPUD) & 0xfffff000; |
| 127 | writel(reg, GPGPUD); |
| 128 | } |
| 129 | |
| 130 | static void set_transfer_mode_register (u32 MultiBlk, u32 DataDirection, u32 AutoCmd12En, u32 BlockCntEn, u32 DmaEn) |
| 131 | { |
| 132 | s3c_hsmmc_writew((s3c_hsmmc_readw(HM_TRNMOD) & ~(0xffff)) | (MultiBlk << 5) |
| 133 | | (DataDirection << 4) | (AutoCmd12En << 2) |
| 134 | | (BlockCntEn << 1) | (DmaEn << 0), HM_TRNMOD); |
| 135 | // dbg("\nHM_TRNMOD = 0x%04x\n", HM_TRNMOD); |
| 136 | } |
| 137 | |
| 138 | static void set_arg_register (u32 arg) |
| 139 | { |
| 140 | s3c_hsmmc_writel(arg, HM_ARGUMENT); |
| 141 | } |
| 142 | |
| 143 | static void set_blkcnt_register(ushort uBlkCnt) |
| 144 | { |
| 145 | s3c_hsmmc_writew(uBlkCnt, HM_BLKCNT); |
| 146 | } |
| 147 | |
| 148 | static void SetSystemAddressReg(u32 SysAddr) |
| 149 | { |
| 150 | s3c_hsmmc_writel(SysAddr, HM_SYSAD); |
| 151 | } |
| 152 | |
| 153 | static void set_blksize_register(ushort uDmaBufBoundary, ushort uBlkSize) |
| 154 | { |
| 155 | s3c_hsmmc_writew((uDmaBufBoundary << 12) | (uBlkSize), HM_BLKSIZE); |
| 156 | } |
| 157 | |
| 158 | static void ClearErrInterruptStatus(void) |
| 159 | { |
| 160 | while (s3c_hsmmc_readw(HM_NORINTSTS) & (0x1 << 15)) { |
| 161 | s3c_hsmmc_writew(s3c_hsmmc_readw(HM_NORINTSTS), HM_NORINTSTS); |
| 162 | s3c_hsmmc_writew(s3c_hsmmc_readw(HM_ERRINTSTS), HM_ERRINTSTS); |
| 163 | } |
| 164 | } |
| 165 | |
| 166 | static void InterruptEnable(ushort NormalIntEn, ushort ErrorIntEn) |
| 167 | { |
| 168 | ClearErrInterruptStatus(); |
| 169 | s3c_hsmmc_writew(NormalIntEn, HM_NORINTSTSEN); |
| 170 | s3c_hsmmc_writew(ErrorIntEn, HM_ERRINTSTSEN); |
| 171 | } |
| 172 | |
| 173 | static void hsmmc_clock_onoff (int on) |
| 174 | { |
| 175 | u16 reg16; |
| 176 | |
| 177 | if (on == 0) { |
| 178 | reg16 = s3c_hsmmc_readw(HM_CLKCON) & ~(0x1<<2); |
| 179 | s3c_hsmmc_writew(reg16, HM_CLKCON); |
| 180 | } else { |
| 181 | reg16 = s3c_hsmmc_readw(HM_CLKCON); |
| 182 | s3c_hsmmc_writew(reg16 | (0x1<<2), HM_CLKCON); |
| 183 | |
| 184 | while (1) { |
| 185 | reg16 = s3c_hsmmc_readw(HM_CLKCON); |
| 186 | if (reg16 & (0x1<<3)) /* SD_CLKSRC is Stable */ |
| 187 | break; |
| 188 | } |
| 189 | } |
| 190 | } |
| 191 | |
| 192 | static void set_clock (u32 clksrc, u32 div) |
| 193 | { |
| 194 | u16 reg16; |
| 195 | u32 i; |
| 196 | |
| 197 | s3c_hsmmc_writel(0xC0004100 | (clksrc << 4), HM_CONTROL2); // rx feedback control |
| 198 | s3c_hsmmc_writel(0x00008080, HM_CONTROL3); // Low clock: 00008080 |
| 199 | s3c_hsmmc_writel(0x3 << 16, HM_CONTROL4); |
| 200 | |
| 201 | s3c_hsmmc_writew(s3c_hsmmc_readw(HM_CLKCON) & ~(0xff << 8), HM_CLKCON); |
| 202 | |
| 203 | /* SDCLK Value Setting + Internal Clock Enable */ |
| 204 | s3c_hsmmc_writew(((div<<8) | 0x1), HM_CLKCON); |
| 205 | |
| 206 | /* CheckInternalClockStable */ |
| 207 | for (i = 0; i < 0x10000; i++) { |
| 208 | reg16 = s3c_hsmmc_readw(HM_CLKCON); |
| 209 | if (reg16 & 0x2) |
| 210 | break; |
| 211 | } |
| 212 | if (i == 0x10000) |
| 213 | puts("internal clock stabilization failed\n"); |
| 214 | |
| 215 | hsmmc_clock_onoff(1); |
| 216 | } |
| 217 | |
| 218 | static void set_cmd_register (ushort cmd, u32 data, u32 flags) |
| 219 | { |
| 220 | ushort val = (cmd << 8); |
| 221 | |
| 222 | if (cmd == 12) |
| 223 | val |= (3 << 6); |
| 224 | |
| 225 | if (flags & MMC_RSP_136) /* Long RSP */ |
| 226 | val |= 0x01; |
| 227 | else if (flags & MMC_RSP_BUSY) /* R1B */ |
| 228 | val |= 0x03; |
| 229 | else if (flags & MMC_RSP_PRESENT) /* Normal RSP */ |
| 230 | val |= 0x02; |
| 231 | |
| 232 | if (flags & MMC_RSP_OPCODE) |
| 233 | val |= (1<<4); |
| 234 | |
| 235 | if (flags & MMC_RSP_CRC) |
| 236 | val |= (1<<3); |
| 237 | |
| 238 | if (data) |
| 239 | val |= (1<<5); |
| 240 | |
| 241 | // puts("cmdreg = 0x"); |
| 242 | // print32(val); |
| 243 | // puts("\n"); |
| 244 | s3c_hsmmc_writew(val, HM_CMDREG); |
| 245 | } |
| 246 | |
| 247 | static int issue_command (ushort cmd, u32 arg, u32 data, u32 flags) |
| 248 | { |
| 249 | int i; |
| 250 | |
| 251 | /* puts("### issue_command: "); |
| 252 | printdec(cmd); |
| 253 | puts(" 0x"); |
| 254 | print32(arg); |
| 255 | puts(" "); |
| 256 | printdec(data); |
| 257 | puts(" 0x"); |
| 258 | print32(flags); |
| 259 | puts("\n"); |
| 260 | */ |
| 261 | /* Check CommandInhibit_CMD */ |
| 262 | for (i = 0; i < 0x1000000; i++) { |
| 263 | if (!(s3c_hsmmc_readl(HM_PRNSTS) & 0x1)) |
| 264 | break; |
| 265 | } |
| 266 | if (i == 0x1000000) { |
| 267 | puts("@@@@@@1 rHM_PRNSTS: "); |
| 268 | printdec(s3c_hsmmc_readl(HM_PRNSTS)); |
| 269 | puts("\n"); |
| 270 | } |
| 271 | |
| 272 | /* Check CommandInhibit_DAT */ |
| 273 | if (flags & MMC_RSP_BUSY) { |
| 274 | for (i = 0; i < 0x1000000; i++) { |
| 275 | if (!(s3c_hsmmc_readl(HM_PRNSTS) & 0x2)) |
| 276 | break; |
| 277 | } |
| 278 | if (i == 0x1000000) { |
| 279 | puts("@@@@@@2 rHM_PRNSTS: "); |
| 280 | print32(s3c_hsmmc_readl(HM_PRNSTS)); |
| 281 | puts("\n"); |
| 282 | } |
| 283 | } |
| 284 | |
| 285 | s3c_hsmmc_writel(arg, HM_ARGUMENT); |
| 286 | |
| 287 | set_cmd_register(cmd, data, flags); |
| 288 | |
| 289 | if (wait_for_cmd_done()) |
| 290 | return 0; |
| 291 | |
| 292 | ClearCommandCompleteStatus(); |
| 293 | |
| 294 | if (!(s3c_hsmmc_readw(HM_NORINTSTS) & 0x8000)) |
| 295 | return 1; |
| 296 | |
| 297 | puts("Command = "); |
| 298 | printdec((s3c_hsmmc_readw(HM_CMDREG) >> 8)); |
| 299 | puts(", Error Stat = 0x"); |
| 300 | print32(s3c_hsmmc_readw(HM_ERRINTSTS)); |
| 301 | return 0; |
| 302 | } |
| 303 | |
| 304 | static int check_card_status(void) |
| 305 | { |
| 306 | if (!issue_command(MMC_SEND_STATUS, rca<<16, 0, MMC_RSP_R1)) |
| 307 | return 0; |
| 308 | |
| 309 | if (((s3c_hsmmc_readl(HM_RSPREG0) >> 9) & 0xf) == 4) { |
| 310 | // puts("Card is transfer status\n"); |
| 311 | return 1; |
| 312 | } |
| 313 | |
| 314 | return 1; |
| 315 | } |
| 316 | |
| 317 | static void set_hostctl_speed (u8 mode) |
| 318 | { |
| 319 | u8 reg8; |
| 320 | |
| 321 | reg8 = s3c_hsmmc_readb(HM_HOSTCTL) & ~(0x1<<2); |
| 322 | s3c_hsmmc_writeb(reg8 | (mode<<2), HM_HOSTCTL); |
| 323 | } |
| 324 | |
| 325 | /* return 0: OK |
| 326 | * return -1: error |
| 327 | */ |
| 328 | static int set_bus_width (u32 width) |
| 329 | { |
| 330 | u8 reg = s3c_hsmmc_readb(HM_HOSTCTL); |
| 331 | u8 bitmode = 0; |
| 332 | |
| 333 | card_irq_enable(0); // Disable sd card interrupt |
| 334 | |
| 335 | |
| 336 | if (!issue_command(MMC_APP_CMD, rca<<16, 0, MMC_RSP_R1)) |
| 337 | return -1; |
| 338 | else { |
| 339 | if (width == 1) { // 1-bits |
| 340 | bitmode = 0; |
| 341 | if (!issue_command(MMC_SWITCH, 0, 0, MMC_RSP_R1B)) |
| 342 | return -1; |
| 343 | } else { // 4-bits |
| 344 | bitmode = 1; |
| 345 | if (!issue_command(MMC_SWITCH, 2, 0, MMC_RSP_R1B)) |
| 346 | return -1; |
| 347 | } |
| 348 | } |
| 349 | |
| 350 | if (bitmode == 2) |
| 351 | reg |= 1 << 5; |
| 352 | else |
| 353 | reg |= bitmode << 1; |
| 354 | |
| 355 | s3c_hsmmc_writeb(reg, HM_HOSTCTL); |
| 356 | card_irq_enable(1); |
| 357 | // puts(" transfer rHM_HOSTCTL(0x28) = 0x"); |
| 358 | // print32(s3c_hsmmc_readb(HM_HOSTCTL)); |
| 359 | |
| 360 | return 0; |
| 361 | } |
| 362 | |
| 363 | static void clock_config (u32 Divisior) |
| 364 | { |
| 365 | if (100000000 / (Divisior * 2) > 25000000) // Higher than 25MHz, it is necessary to enable high speed mode of the host controller. |
| 366 | set_hostctl_speed(HIGH); |
| 367 | else |
| 368 | set_hostctl_speed(NORMAL); |
| 369 | |
| 370 | hsmmc_clock_onoff(0); // when change the sd clock frequency, need to stop sd clock. |
| 371 | set_clock(SD_EPLL, Divisior); |
| 372 | } |
| 373 | |
| 374 | static void check_dma_int (void) |
| 375 | { |
| 376 | u32 i; |
| 377 | |
| 378 | for (i = 0; i < 0x10000000; i++) { |
| 379 | if (s3c_hsmmc_readw(HM_NORINTSTS) & 0x0002) { |
| 380 | HS_DMA_END = 1; |
| 381 | s3c_hsmmc_writew(s3c_hsmmc_readw(HM_NORINTSTS) | 0x0002, HM_NORINTSTS); |
| 382 | return; |
| 383 | } |
| 384 | if (s3c_hsmmc_readw(HM_NORINTSTS) & 0x8000) { |
| 385 | puts("error found: "); |
| 386 | print32(s3c_hsmmc_readw(HM_ERRINTSTS)); |
| 387 | return; |
| 388 | } |
| 389 | } |
| 390 | |
| 391 | puts("check_dma_int: timeout\n"); |
| 392 | } |
| 393 | |
| 394 | |
| 395 | static void print_sd_cid(const struct sd_cid *cid) |
| 396 | { |
| 397 | puts(" Card Type: "); |
| 398 | switch (card_type) { |
| 399 | case CARDTYPE_NONE: |
| 400 | puts("(None) / "); |
| 401 | break; |
| 402 | case CARDTYPE_MMC: |
| 403 | puts("MMC / "); |
| 404 | break; |
| 405 | case CARDTYPE_SD: |
| 406 | puts("SD / "); |
| 407 | break; |
| 408 | case CARDTYPE_SD20: |
| 409 | puts("SD 2.0 / "); |
| 410 | break; |
| 411 | case CARDTYPE_SDHC: |
| 412 | puts("SD 2.0 SDHC / "); |
| 413 | break; |
| 414 | } |
| 415 | |
| 416 | puts("Mfr: 0x"); |
| 417 | print8(cid->mid); |
| 418 | puts(", OEM \""); |
| 419 | this_board->putc(cid->oid_0); |
| 420 | this_board->putc(cid->oid_1); |
| 421 | puts("\" / "); |
| 422 | |
| 423 | this_board->putc(cid->pnm_0); |
| 424 | this_board->putc(cid->pnm_1); |
| 425 | this_board->putc(cid->pnm_2); |
| 426 | this_board->putc(cid->pnm_3); |
| 427 | this_board->putc(cid->pnm_4); |
| 428 | puts("\", rev "); |
| 429 | printdec(cid->prv >> 4); |
| 430 | puts("."); |
| 431 | printdec(cid->prv & 15); |
| 432 | puts(" / s/n: "); |
| 433 | print32(cid->psn_0 << 24 | cid->psn_1 << 16 | cid->psn_2 << 8 | |
| 434 | cid->psn_3); |
| 435 | puts(" / date: "); |
| 436 | printdec(cid->mdt_1 & 15); |
| 437 | puts("/"); |
| 438 | printdec(2000 + ((cid->mdt_0 & 15) << 4)+((cid->mdt_1 & 0xf0) >> 4)); |
| 439 | puts("\n"); |
| 440 | } |
| 441 | |
| 442 | unsigned int s3c6410_mmc_init (int verbose) |
| 443 | { |
| 444 | u32 reg; |
| 445 | u32 width; |
| 446 | int resp; |
| 447 | int hcs; |
| 448 | int retries = 50; |
| 449 | u8 response[16]; |
| 450 | unsigned int r1[4]; |
| 451 | struct sd_cid *sd_cid = (struct sd_cid *)response; |
| 452 | struct mmc_csd *csd = (struct mmc_csd *)response; |
| 453 | u8 *p8 = (u8 *)&r1[0]; |
| 454 | unsigned int sd_sectors = 0; |
| 455 | /* we need to shift result by 8 bits spread over 4 x 32-bit regs */ |
| 456 | u8 mangle[] = { 7, 0, 1, 2, 11, 4, 5, 6, 15, 8, 9, 10, 0, 12, 13, 14 }; |
| 457 | int n; |
| 458 | |
| 459 | hsmmc_set_gpio(); |
| 460 | |
| 461 | hsmmc_reset(); |
| 462 | |
| 463 | width = 4; |
| 464 | |
| 465 | HCLK = 33000000; /* FIXME */ |
| 466 | hsmmc_clock_onoff(0); |
| 467 | |
| 468 | reg = readl(SCLK_GATE); |
| 469 | writel(reg | (1<<27), SCLK_GATE); |
| 470 | |
| 471 | set_clock(SD_EPLL, 0x80); |
| 472 | s3c_hsmmc_writeb(0xe, HM_TIMEOUTCON); |
| 473 | set_hostctl_speed(NORMAL); |
| 474 | |
| 475 | InterruptEnable(0xff, 0xff); |
| 476 | |
| 477 | // dbg("HM_NORINTSTS = %x\n", s3c_hsmmc_readw(HM_NORINTSTS)); |
| 478 | |
| 479 | /* MMC_GO_IDLE_STATE */ |
| 480 | issue_command(MMC_GO_IDLE_STATE, 0x00, 0, 0); |
| 481 | |
| 482 | udelay(100000); |
| 483 | udelay(100000); |
| 484 | udelay(100000); |
| 485 | udelay(100000); |
| 486 | |
| 487 | /* SDHC card? */ |
| 488 | |
| 489 | resp = issue_command(SD_SEND_IF_COND, 0x000001aa, |
| 490 | 0, MMC_CMD_BCR | MMC_RSP_R7); |
| 491 | if (resp && ((s3c_hsmmc_readl(HM_RSPREG0) & 0xff) == 0xaa)) { |
| 492 | card_type = CARDTYPE_SD20; /* 2.0 SD, may not be SDHC */ |
| 493 | hcs = 0x40000000; |
| 494 | } |
| 495 | |
| 496 | /* Well, either way let's say hello in SD card protocol */ |
| 497 | |
| 498 | while (retries--) { |
| 499 | |
| 500 | udelay(100000); |
| 501 | udelay(100000); |
| 502 | udelay(100000); |
| 503 | |
| 504 | resp = issue_command(MMC_APP_CMD, 0x00000000, 0, |
| 505 | MMC_RSP_R1); |
| 506 | if (!resp) |
| 507 | continue; |
| 508 | resp = issue_command(SD_APP_OP_COND, hcs | 0x00300000, 0, |
| 509 | MMC_RSP_R3); |
| 510 | if (!resp) |
| 511 | continue; |
| 512 | |
| 513 | if ((s3c_hsmmc_readl(HM_RSPREG0) >> 24) & (1 << 6)) { /* asserts block addressing */ |
| 514 | retries = -2; |
| 515 | card_type = CARDTYPE_SDHC; |
| 516 | } |
| 517 | |
| 518 | if ((s3c_hsmmc_readl(HM_RSPREG0) >> 24) & (1 << 7)) { /* not busy */ |
| 519 | retries = -2; |
| 520 | if (card_type == CARDTYPE_NONE) |
| 521 | card_type = CARDTYPE_SD; |
| 522 | break; |
| 523 | } |
| 524 | } |
| 525 | if (retries == -1) { |
| 526 | puts("no response\n"); |
| 527 | return -2; |
| 528 | } |
| 529 | |
| 530 | if (!issue_command(MMC_ALL_SEND_CID, 0, 0, MMC_RSP_R2)) { |
| 531 | puts("CID broken\n"); |
| 532 | return -3; |
| 533 | } |
| 534 | |
| 535 | r1[0] = s3c_hsmmc_readl(HM_RSPREG3); |
| 536 | r1[1] = s3c_hsmmc_readl(HM_RSPREG2); |
| 537 | r1[2] = s3c_hsmmc_readl(HM_RSPREG1); |
| 538 | r1[3] = s3c_hsmmc_readl(HM_RSPREG0); |
| 539 | |
| 540 | for (n = 0; n < 16; n++) |
| 541 | response[n] = p8[mangle[n]]; |
| 542 | |
| 543 | switch (card_type) { |
| 544 | case CARDTYPE_SD: |
| 545 | case CARDTYPE_SD20: |
| 546 | case CARDTYPE_SDHC: |
| 547 | |
| 548 | if (verbose) |
| 549 | print_sd_cid(sd_cid); |
| 550 | resp = issue_command(SD_SEND_RELATIVE_ADDR, MMC_DEFAULT_RCA, |
| 551 | 0, MMC_RSP_R6); |
| 552 | rca = s3c_hsmmc_readl(HM_RSPREG0) >> 16; |
| 553 | break; |
| 554 | |
| 555 | default: |
| 556 | return 1; |
| 557 | } |
| 558 | |
| 559 | /* grab the CSD */ |
| 560 | |
| 561 | resp = issue_command(MMC_SEND_CSD, rca << 16, 0, MMC_RSP_R2); |
| 562 | if (resp) { |
| 563 | |
| 564 | r1[0] = s3c_hsmmc_readl(HM_RSPREG3); |
| 565 | r1[1] = s3c_hsmmc_readl(HM_RSPREG2); |
| 566 | r1[2] = s3c_hsmmc_readl(HM_RSPREG1); |
| 567 | r1[3] = s3c_hsmmc_readl(HM_RSPREG0); |
| 568 | for (n = 0; n < 16; n++) |
| 569 | response[n] = p8[mangle[n]]; |
| 570 | |
| 571 | switch (card_type) { |
| 572 | case CARDTYPE_SDHC: |
| 573 | puts(" SDHC size: "); |
| 574 | sd_sectors = (UNSTUFF_BITS(((u32 *)&response[0]), 48, 22) |
| 575 | + 1) << 10; |
| 576 | break; |
| 577 | default: |
| 578 | puts(" MMC/SD size: "); |
| 579 | sd_sectors = ((((unsigned long)1 << csd->c_size_mult1) * |
| 580 | (unsigned long)(csd->c_size)) >> 9); |
| 581 | } |
| 582 | printdec(sd_sectors / 2048); |
| 583 | puts(" MiB\n"); |
| 584 | } else |
| 585 | puts("CSD grab broken\n"); |
| 586 | |
| 587 | resp = issue_command(MMC_SELECT_CARD, rca<<16, 0, MMC_RSP_R1); |
| 588 | if (!resp) |
| 589 | return 1; |
| 590 | |
| 591 | /* Operating Clock setting */ |
| 592 | clock_config(2); // Divisor 1 = Base clk /2 ,Divisor 2 = Base clk /4, Divisor 4 = Base clk /8 ... |
| 593 | |
| 594 | while (set_bus_width(width)); |
| 595 | while (!check_card_status()); |
| 596 | |
| 597 | /* MMC_SET_BLOCKLEN */ |
| 598 | while (!issue_command(MMC_SET_BLOCKLEN, 512, 0, MMC_RSP_R1)); |
| 599 | |
| 600 | s3c_hsmmc_writew(0xffff, HM_NORINTSTS); |
| 601 | |
| 602 | return sd_sectors; |
| 603 | } |
| 604 | |
| 605 | unsigned long s3c6410_mmc_bread(int dev_num, unsigned long start_blk, unsigned long blknum, |
| 606 | void *dst) |
| 607 | { |
| 608 | u32 blksize; //j, , Addr_temp = start_blk; |
| 609 | u32 dma = 0, cmd, multi; //, TotalReadByte, read_blk_cnt = 0; |
| 610 | |
| 611 | HS_DMA_END = 0; |
| 612 | |
| 613 | blksize = Card_OneBlockSize_ver1; |
| 614 | |
| 615 | while (!check_card_status()); |
| 616 | |
| 617 | s3c_hsmmc_writew(s3c_hsmmc_readw(HM_NORINTSTSEN) & ~(DMA_STS_INT_EN | BLOCKGAP_EVENT_STS_INT_EN), HM_NORINTSTSEN); |
| 618 | s3c_hsmmc_writew((HM_NORINTSIGEN & ~(0xffff)) | TRANSFERCOMPLETE_SIG_INT_EN, HM_NORINTSIGEN); |
| 619 | |
| 620 | SetSystemAddressReg((unsigned long)dst); // AHB System Address For Write |
| 621 | dma = 1; |
| 622 | |
| 623 | set_blksize_register(7, 512); // Maximum DMA Buffer Size, Block Size |
| 624 | set_blkcnt_register(blknum); // Block Numbers to Write |
| 625 | |
| 626 | if (movi_hc) |
| 627 | set_arg_register(start_blk); // Card Start Block Address to Write |
| 628 | else |
| 629 | set_arg_register(start_blk * 512); // Card Start Block Address to Write |
| 630 | |
| 631 | cmd = (blknum > 1) ? 18 : 17; |
| 632 | multi = (blknum > 1); |
| 633 | |
| 634 | set_transfer_mode_register(multi, 1, multi, 1, dma); |
| 635 | set_cmd_register(cmd, 1, MMC_RSP_R1); |
| 636 | |
| 637 | if (wait_for_cmd_done()) { |
| 638 | puts("Command NOT Complete\n"); |
| 639 | return -1; |
| 640 | } else |
| 641 | ClearCommandCompleteStatus(); |
| 642 | |
| 643 | |
| 644 | check_dma_int(); |
| 645 | while (!HS_DMA_END); |
| 646 | |
| 647 | HS_DMA_END = 0; |
| 648 | |
| 649 | return blknum; |
| 650 | } |
| 651 | |