source/sd+mmc.ccp |
68 | 68 | return read_block_size |
69 | 69 | unsigned get_block_bits (): |
70 | 70 | return hc ? 9 : csd.read_bl_len > csd.write_bl_len ? csd.read_bl_len : csd.write_bl_len |
71 | | void fill_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset) |
72 | 71 | void write_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset) |
| 72 | void read_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset) |
73 | 73 | void wait_write () |
| 74 | void add_cb (Iris::Listitem item): |
| 75 | cb_list.add_item (item) |
74 | 76 | private: |
| 77 | void set_block (unsigned block) |
| 78 | unsigned current_block_num |
| 79 | bool dirty |
| 80 | unsigned *current_block |
75 | 81 | unsigned rca |
76 | 82 | bool have_sdmem, have_io |
77 | 83 | bool hc |
... | ... | |
79 | 85 | CSD csd |
80 | 86 | unsigned num_blocks, read_block_size |
81 | 87 | Iris::Page buffer_page |
| 88 | Iris::List cb_list |
82 | 89 | static unsigned const buffer = 0x15000 |
83 | 90 | |
84 | 91 | bool Mmc::send (unsigned cmd, unsigned arg, Response_type response_type, unsigned *response): |
... | ... | |
129 | 136 | d = MSC_RES |
130 | 137 | cid.year = 2000 + (d >> 4 & 0xff) |
131 | 138 | cid.month = d & 0xf |
| 139 | #if 1 |
| 140 | Iris::debug ("CID: mid=%x, oid=%x %x, pnm=%x %x %x %x %x, prv=%x, psn=%x, year=%x, month=%x\n", cid.mid, cid.oid[0], cid.oid[1], cid.pnm[0], cid.pnm[1], cid.pnm[2], cid.pnm[3], cid.pnm[4], cid.prv, cid.psn, cid.year, cid.month) |
| 141 | #endif |
132 | 142 | else: |
133 | 143 | // Header (8) 1.0 1.0 |
134 | 144 | // Read out csd. |
... | ... | |
175 | 185 | num_blocks >>= 9 - csd.read_bl_len |
176 | 186 | else: |
177 | 187 | num_blocks <<= csd.read_bl_len - 9 |
| 188 | #if 1 |
| 189 | Iris::debug ("CSD: size=%x<<%x, r/w len=%x/%x, %s, %s, %s\n", csd.c_size, csd.c_size_mult, csd.read_bl_len, csd.write_bl_len, csd.copy ? "copy" : "no copy", csd.perm_write_protect ? "fixed write protect" : "no fixed write protect", csd.tmp_write_protect ? "write protect" : "no write protect") |
| 190 | #endif |
| 191 | unsigned c_size |
| 192 | unsigned c_size_mult |
| 193 | unsigned read_bl_len, write_bl_len |
| 194 | bool copy |
| 195 | bool perm_write_protect |
| 196 | bool tmp_write_protect |
178 | 197 | else if response_type != NONE: |
179 | 198 | unsigned r = MSC_RES |
180 | 199 | if response_type == R3: |
... | ... | |
203 | 222 | return true |
204 | 223 | |
205 | 224 | void Mmc::reset (): |
| 225 | current_block_num = ~0 |
| 226 | dirty = false |
| 227 | cb_list = Iris::my_memory.create_list () |
| 228 | current_block = (unsigned *)(buffer + PAGE_SIZE) |
206 | 229 | // Create a buffer to use for data transfer. |
207 | 230 | buffer_page = Iris::my_memory.create_page () |
208 | 231 | Iris::my_memory.map (buffer_page, buffer) |
... | ... | |
348 | 371 | kdebug (" = ") |
349 | 372 | kdebug_num (num_blocks * read_block_size) |
350 | 373 | kdebug ("\n") |
| 374 | // Set up buffer memory. |
| 375 | for unsigned i = 0; i < 1 << csd.write_bl_len; i += PAGE_SIZE: |
| 376 | Iris::Page p = Iris::my_memory.create_page () |
| 377 | p.set_flags (Iris::Page::PAYING | Iris::Page::FRAME) |
| 378 | Iris::my_memory.map (p, (unsigned)current_block + i) |
| 379 | Iris::free_cap (p) |
| 380 | Iris::Listitem item = cb_list.get_next () |
| 381 | while item.code != Iris::Cap ().code: |
| 382 | Iris::Cap c = cb_list.get_cap (item) |
| 383 | c.invoke (0, ~0) |
| 384 | Iris::free_cap (c) |
| 385 | Iris::Listitem nextitem = cb_list.get_next (item); |
| 386 | Iris::free_cap (item) |
| 387 | item = nextitem |
351 | 388 | |
352 | 389 | void Mmc::release (): |
353 | 390 | kdebug ("mmc release\n") |
... | ... | |
355 | 392 | have_sdmem = false |
356 | 393 | have_io = false |
357 | 394 | read_block_size = 0 |
| 395 | if num_blocks != 0: |
| 396 | for unsigned i = 0; i < 1 << csd.write_bl_len; i += PAGE_SIZE: |
| 397 | Iris::Page p = Iris::my_memory.mapping ((void *)((unsigned)current_block + i)) |
| 398 | Iris::my_memory.destroy (p) |
| 399 | Iris::free_cap (p) |
| 400 | if dirty: |
| 401 | Iris::debug ("Warning: sd/mmc card removed before data was written to it") |
| 402 | current_block_num = ~0 |
| 403 | dirty = false |
358 | 404 | num_blocks = 0 |
| 405 | Iris::Listitem item = cb_list.get_next () |
| 406 | while item.code != Iris::Cap ().code: |
| 407 | Iris::Cap c = cb_list.get_cap (item) |
| 408 | c.invoke (0, ~0) |
| 409 | Iris::free_cap (c) |
| 410 | Iris::Listitem nextitem = cb_list.get_next (item); |
| 411 | Iris::free_cap (item) |
| 412 | item = nextitem |
359 | 413 | |
360 | 414 | void Mmc::interrupt (): |
361 | 415 | kdebug ("mmc interrupt\n") |
362 | 416 | |
363 | | void Mmc::fill_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset): |
364 | | if address.h: |
365 | | Iris::panic (0, "page too high: not supported") |
| 417 | void Mmc::set_block (unsigned block): |
| 418 | if current_block_num == block: |
366 | 419 | return |
367 | | //kdebug ("smc get page ") |
368 | | //kdebug_num (address.l) |
369 | | //kdebug ("+") |
370 | | //kdebug_num (size) |
371 | | //kdebug ("@") |
372 | | //kdebug_num (offset) |
373 | | //kdebug ("\n") |
374 | | unsigned blockmask = ~((1 << 9) - 1) |
375 | | unsigned p = address.l & blockmask |
376 | | size &= blockmask |
377 | | offset &= ~PAGE_MASK |
378 | | if size + offset > PAGE_SIZE: |
379 | | size = PAGE_SIZE - offset |
380 | | page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME) |
381 | | page.share (buffer_page) |
382 | | buffer_page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME) |
| 420 | if dirty && current_block_num != ~0: |
| 421 | MSC_NOB = 1 |
| 422 | MSC_BLKLEN = 1 << csd.write_bl_len |
| 423 | if !send (24, (current_block_num << csd.write_bl_len), WR_DATA): |
| 424 | Iris::panic (0, "unable to send data") |
| 425 | MSC_IMASK = ~MSC_IMASK_TXFIFO_WR_REQ |
| 426 | for unsigned a = 0; a < 1 << csd.write_bl_len; a += 4: |
| 427 | while MSC_STAT & MSC_STAT_DATA_FIFO_FULL: |
| 428 | Iris::register_interrupt (IRQ_MSC) |
| 429 | Iris::wait_for_interrupt (IRQ_MSC) |
| 430 | MSC_TXFIFO = current_block[a >> 2] |
| 431 | MSC_IMASK = ~0 |
| 432 | MSC_IREG = MSC_IREG_DATA_TRAN_DONE |
| 433 | //kdebug ("done writing page\n") |
| 434 | current_block_num = block |
| 435 | dirty = false |
383 | 436 | MSC_NOB = 1 |
384 | 437 | MSC_BLKLEN = 1 << 9 |
385 | | for unsigned a = 0; a < size; a += 1 << 9: |
386 | | //kdebug_num (a) |
387 | | //kdebug ("/") |
388 | | //kdebug_num (size) |
389 | | //kdebug (" ==> ") |
390 | | if !send (17, p + a, RD_DATA): |
| 438 | for unsigned a = 0; a < 1 << csd.write_bl_len; a += 1 << 9: |
| 439 | if !send (17, (block << csd.write_bl_len) + a, RD_DATA): |
391 | 440 | Iris::panic (0, "unable to request data") |
392 | 441 | MSC_IMASK = ~MSC_IMASK_RXFIFO_RD_REQ |
393 | 442 | for unsigned aa = 0; aa < 1 << 9; aa += 4: |
394 | 443 | while MSC_STAT & MSC_STAT_DATA_FIFO_EMPTY: |
395 | 444 | Iris::register_interrupt (IRQ_MSC) |
396 | 445 | Iris::wait_for_interrupt (IRQ_MSC) |
397 | | *(unsigned *)(buffer + a + aa + offset) = MSC_RXFIFO |
398 | | //unsigned d = *(unsigned *)(buffer + a + aa + offset) |
399 | | //if (aa & 0x3f) == 0: |
400 | | //kdebug ("\n") |
401 | | //for unsigned i = 0; i < 4; ++i: |
402 | | //kdebug (" ") |
403 | | //kdebug_num (d >> (8 * i), 2) |
404 | | //kdebug ("\n") |
| 446 | current_block[(a + aa) >> 2] = MSC_RXFIFO |
405 | 447 | MSC_IMASK = ~0 |
406 | 448 | MSC_IREG = MSC_IREG_DATA_TRAN_DONE |
407 | 449 | //kdebug ("done filling page\n") |
408 | 450 | |
| 451 | void Mmc::read_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset): |
| 452 | if address.value () >> (csd.write_bl_len + 32): |
| 453 | Iris::panic (address.h, "page too high: not supported") |
| 454 | unsigned block = address.value () >> csd.write_bl_len |
| 455 | unsigned start_pos = address.l & (1 << csd.write_bl_len) - 1 |
| 456 | set_block (block) |
| 457 | unsigned blockmask = ~((1 << 9) - 1) |
| 458 | size &= blockmask |
| 459 | offset &= ~PAGE_MASK & ~3 |
| 460 | if size + offset > PAGE_SIZE: |
| 461 | size = PAGE_SIZE - offset |
| 462 | page.share (buffer_page) |
| 463 | buffer_page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME) |
| 464 | for unsigned i = 0; i < size; i += 4: |
| 465 | ((unsigned *)buffer)[(offset + i) >> 2] = current_block[(start_pos + i) >> 2] |
| 466 | |
409 | 467 | void Mmc::write_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset): |
410 | | if address.h: |
411 | | Iris::panic (1, "page too high: not supported") |
412 | | return |
| 468 | if address.value () >> (csd.write_bl_len + 32): |
| 469 | Iris::panic (address.h, "page too high: not supported") |
| 470 | unsigned block = address.value () >> csd.write_bl_len |
| 471 | unsigned start_pos = address.l & (1 << csd.write_bl_len) - 1 |
| 472 | set_block (block) |
413 | 473 | unsigned blockmask = ~((1 << 9) - 1) |
414 | | unsigned p = address.l & blockmask |
415 | 474 | size &= blockmask |
416 | | offset &= ~PAGE_MASK |
| 475 | offset &= ~PAGE_MASK & ~3 |
417 | 476 | if size + offset > PAGE_SIZE: |
418 | 477 | size = PAGE_SIZE - offset |
419 | 478 | page.share (buffer_page) |
420 | 479 | buffer_page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME) |
421 | | MSC_NOB = 1 |
422 | | MSC_BLKLEN = 1 << 9 |
423 | | for unsigned a = 0; a < size; a += 1 << 9: |
424 | | //kdebug_num (a) |
425 | | //kdebug ("/") |
426 | | //kdebug_num (size) |
427 | | //kdebug ("\n") |
428 | | if !send (24, p + a, WR_DATA): |
429 | | Iris::panic (0, "unable to send data") |
430 | | MSC_IMASK = ~MSC_IMASK_TXFIFO_WR_REQ |
431 | | for unsigned aa = 0; aa < 1 << 9; aa += 4: |
432 | | while MSC_STAT & MSC_STAT_DATA_FIFO_FULL: |
433 | | Iris::register_interrupt (IRQ_MSC) |
434 | | Iris::wait_for_interrupt (IRQ_MSC) |
435 | | MSC_TXFIFO = *(unsigned *)(buffer + a + aa + offset) |
436 | | MSC_IMASK = ~0 |
437 | | MSC_IREG = MSC_IREG_DATA_TRAN_DONE |
438 | | //kdebug ("done writing page\n") |
| 480 | for unsigned i = 0; i < size; i += 4: |
| 481 | current_block[(start_pos + i) >> 2] = ((unsigned *)buffer)[(offset + i) >> 2] |
| 482 | dirty = true |
439 | 483 | |
440 | 484 | void Mmc::wait_write (): |
441 | 485 | MSC_IMASK = ~MSC_IMASK_PRG_DONE |
... | ... | |
473 | 517 | mmc.detect () |
474 | 518 | |
475 | 519 | cap = Iris::my_receiver.create_capability (REQUEST) |
476 | | Iris::my_parent.provide_capability <Iris::WString> (cap.copy ()) |
| 520 | Iris::my_parent.provide_capability <Iris::WBlock> (cap.copy ()) |
477 | 521 | Iris::free_cap (cap) |
478 | 522 | |
479 | 523 | Iris::my_parent.init_done () |
... | ... | |
496 | 540 | //kdebug ("\n") |
497 | 541 | switch Iris::recv.data[0].l: |
498 | 542 | case Iris::Block::GET_SIZE: |
| 543 | Iris::debug ("get size\n") |
499 | 544 | unsigned long long size = mmc.get_num_blocks () * mmc.get_read_block_size () |
500 | 545 | Iris::recv.reply.invoke (size) |
501 | 546 | break |
502 | 547 | case Iris::Block::GET_ALIGN_BITS: |
| 548 | Iris::debug ("get align bits\n") |
503 | 549 | Iris::recv.reply.invoke (9) |
504 | 550 | break |
505 | 551 | case Iris::Block::GET_BLOCK: |
| 552 | //Iris::debug ("get block\n") |
506 | 553 | Iris::Cap reply = Iris::get_reply () |
507 | 554 | Iris::Page page = Iris::get_arg () |
508 | | mmc.fill_page (page, Iris::recv.data[1], Iris::recv.data[0].h >> 16, Iris::recv.data[0].h & 0xffff) |
| 555 | mmc.read_page (page, Iris::recv.data[1], Iris::recv.data[0].h >> 16, Iris::recv.data[0].h & 0xffff) |
509 | 556 | reply.invoke () |
510 | 557 | Iris::free_cap (page) |
511 | 558 | Iris::free_cap (reply) |
512 | 559 | break |
513 | 560 | case Iris::WBlock::SET_BLOCK: |
| 561 | Iris::debug ("set block\n") |
514 | 562 | Iris::Cap reply = Iris::get_reply () |
515 | 563 | Iris::Page page = Iris::get_arg () |
516 | 564 | mmc.write_page (page, Iris::recv.data[1], Iris::recv.data[0].h >> 16, Iris::recv.data[0].h & 0xffff) |
... | ... | |
519 | 567 | Iris::free_cap (reply) |
520 | 568 | mmc.wait_write () |
521 | 569 | break |
522 | | case Iris::WString::TRUNCATE: |
| 570 | case Iris::Block::SET_CHANGE_CB: |
| 571 | Iris::debug ("set change cb\n") |
| 572 | Iris::Listitem item = Iris::get_arg () |
| 573 | Iris::Cap reply = Iris::get_reply () |
| 574 | mmc.add_cb (item) |
| 575 | reply.invoke () |
| 576 | Iris::free_cap (item) |
| 577 | Iris::free_cap (reply) |
| 578 | break |
| 579 | case Iris::WBlock::TRUNCATE: |
| 580 | Iris::debug ("truncate\n") |
523 | 581 | // Fall through: don't support resizing. |
524 | 582 | default: |
525 | 583 | Iris::panic (0, "unexpected event for sd+mmc") |