Root/
| 1 | #pypp 0 |
| 2 | // Iris: micro-kernel for a capability-based operating system. |
| 3 | // source/sd+mmc.ccp: sd+mmc driver. |
| 4 | // Copyright 2009 Bas Wijnen <wijnen@debian.org> |
| 5 | // |
| 6 | // This program is free software: you can redistribute it and/or modify |
| 7 | // it under the terms of the GNU General Public License as published by |
| 8 | // the Free Software Foundation, either version 3 of the License, or |
| 9 | // (at your option) any later version. |
| 10 | // |
| 11 | // This program is distributed in the hope that it will be useful, |
| 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | // GNU General Public License for more details. |
| 15 | // |
| 16 | // You should have received a copy of the GNU General Public License |
| 17 | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 18 | |
| 19 | #include "devices.hh" |
| 20 | #define ARCH |
| 21 | #include "arch.hh" |
| 22 | |
| 23 | class Mmc: |
| 24 | public: |
| 25 | enum Response_type: |
| 26 | NONE = MSC_CMDAT_RESPONSE_NONE |
| 27 | RD_DATA = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_DATA_EN | MSC_CMDAT_READ |
| 28 | WR_DATA = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_DATA_EN | MSC_CMDAT_WRITE |
| 29 | R1 = MSC_CMDAT_RESPONSE_R1 |
| 30 | R1B = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_BUSY |
| 31 | R2 = MSC_CMDAT_RESPONSE_R2 |
| 32 | R3 = MSC_CMDAT_RESPONSE_R3 |
| 33 | R4 = MSC_CMDAT_RESPONSE_R4 |
| 34 | R5 = MSC_CMDAT_RESPONSE_R5 |
| 35 | R6 = MSC_CMDAT_RESPONSE_R6 |
| 36 | R7 = MSC_CMDAT_RESPONSE_R7 |
| 37 | static unsigned const POWER_PORT = 3 |
| 38 | static unsigned const POWER_PIN = 2 |
| 39 | struct CID: |
| 40 | unsigned mid |
| 41 | char oid[2] |
| 42 | char pnm[5] |
| 43 | unsigned prv |
| 44 | unsigned psn |
| 45 | unsigned year |
| 46 | unsigned month |
| 47 | struct CSD: |
| 48 | unsigned c_size |
| 49 | unsigned c_size_mult |
| 50 | unsigned read_bl_len, write_bl_len |
| 51 | bool copy |
| 52 | bool perm_write_protect |
| 53 | bool tmp_write_protect |
| 54 | bool send (unsigned cmd, unsigned arg, Response_type response_type, unsigned *response = NULL) |
| 55 | void check_sd () |
| 56 | void check_sdmem () |
| 57 | void check_mmc () |
| 58 | public: |
| 59 | void reset () |
| 60 | void detect () |
| 61 | void release () |
| 62 | void interrupt () |
| 63 | CID const &get_cid (): |
| 64 | return cid |
| 65 | unsigned get_num_blocks (): |
| 66 | return num_blocks |
| 67 | unsigned get_read_block_size (): |
| 68 | return read_block_size |
| 69 | unsigned get_block_bits (): |
| 70 | return hc ? 9 : csd.read_bl_len > csd.write_bl_len ? csd.read_bl_len : csd.write_bl_len |
| 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 | void wait_write () |
| 74 | void add_cb (Iris::Listitem item): |
| 75 | cb_list.add_item (item) |
| 76 | private: |
| 77 | void set_block (unsigned block) |
| 78 | unsigned current_block_num |
| 79 | bool dirty |
| 80 | unsigned *current_block |
| 81 | unsigned rca |
| 82 | bool have_sdmem, have_io |
| 83 | bool hc |
| 84 | CID cid |
| 85 | CSD csd |
| 86 | unsigned num_blocks, read_block_size |
| 87 | Iris::Page buffer_page |
| 88 | Iris::List cb_list |
| 89 | static unsigned const buffer = 0x15000 |
| 90 | |
| 91 | bool Mmc::send (unsigned cmd, unsigned arg, Response_type response_type, unsigned *response): |
| 92 | MSC_CMD = cmd |
| 93 | MSC_ARG = arg |
| 94 | MSC_CMDAT = response_type |
| 95 | MSC_IMASK = ~MSC_IMASK_END_CMD_RES |
| 96 | Iris::register_interrupt (IRQ_MSC) |
| 97 | msc_start_op () |
| 98 | Iris::wait_for_interrupt () |
| 99 | MSC_IMASK = ~0 |
| 100 | //kdebug ("cmd: ") |
| 101 | //kdebug_num (cmd) |
| 102 | unsigned stat = MSC_STAT |
| 103 | //kdebug (", stat: ") |
| 104 | //kdebug_num (stat) |
| 105 | //kdebug ("\n") |
| 106 | if stat & MSC_STAT_CRC_RES_ERR: |
| 107 | Iris::panic (0, "crc error in mmc response") |
| 108 | return false |
| 109 | if stat & MSC_STAT_TIME_OUT_RES: |
| 110 | kdebug ("time out waiting for mmc response\n") |
| 111 | MSC_IREG = MSC_IREG_END_CMD_RES |
| 112 | return false |
| 113 | if response_type == R2: |
| 114 | unsigned d = MSC_RES |
| 115 | if d >> 8 != 0x3f: |
| 116 | Iris::panic (d, "invalid r2 response") |
| 117 | if cmd == 3: |
| 118 | // Read out result. |
| 119 | cid.mid = d & 0xff |
| 120 | d = MSC_RES |
| 121 | cid.oid[0] = d >> 8 |
| 122 | cid.oid[1] = d & 0xff |
| 123 | d = MSC_RES |
| 124 | cid.pnm[0] = d >> 8 |
| 125 | cid.pnm[1] = d & 0xff |
| 126 | d = MSC_RES |
| 127 | cid.pnm[2] = d >> 8 |
| 128 | cid.pnm[3] = d & 0xff |
| 129 | d = MSC_RES |
| 130 | cid.pnm[4] = d >> 8 |
| 131 | cid.prv = d & 0xff |
| 132 | d = MSC_RES |
| 133 | cid.psn = d << 16 |
| 134 | d = MSC_RES |
| 135 | cid.psn |= d |
| 136 | d = MSC_RES |
| 137 | cid.year = 2000 + (d >> 4 & 0xff) |
| 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 |
| 142 | else: |
| 143 | // Header (8) 1.0 1.0 |
| 144 | // Read out csd. |
| 145 | // Ignore csd_structure. 2 (+ 6) 1.0 2.0 *** |
| 146 | d = MSC_RES |
| 147 | // Ignore taac and nsac. 8 + 8 2.0 4.0 *** |
| 148 | d = MSC_RES |
| 149 | // Ignore tran_speed, ccc. 8 + 8/12 2.0 6.0 *** |
| 150 | d = MSC_RES |
| 151 | // Ignore rest of ccc. 4/12 0.4 6.4 |
| 152 | // 4 0.4 7.0 |
| 153 | csd.read_bl_len = (d >> 8) & 0xf |
| 154 | // Ignore read_bl_partial, write_blk_misalign, read_blk_misalign, dsr_imp. 1 + 1 + 1 + 1 (+ 2) 0.6 7.6 |
| 155 | // 2/12 0.2 8.0 *** |
| 156 | csd.c_size = (d & 0x0003) << 10 |
| 157 | d = MSC_RES |
| 158 | // 10/12 1.2 9.2 |
| 159 | csd.c_size |= d >> 6 |
| 160 | // Ignore vdd_r_cur_min, vdd_r_cur_max. 3 + 3 0.6 10.0 *** |
| 161 | d = MSC_RES |
| 162 | // Ignore vdd_w_cur_min, vdd_w_cur_max. 3 + 3 0.6 10.6 |
| 163 | // 3 0.3 11.1 |
| 164 | csd.c_size_mult = (d >> 7) & 0x7 |
| 165 | // Ignore erase_blk_enable, sector_size. 1 + 6/7 0.7 12.0 *** |
| 166 | d = MSC_RES |
| 167 | // Ignore rest of sector_size, wp_grp_size, wp_grp_enable, r2w_factor. 1/7 + 7 + 1 (+ 2) + 3 1.6 13.6 |
| 168 | // 2/4 0.4 14.0 *** |
| 169 | csd.write_bl_len = (d << 2) & 0xc |
| 170 | d = MSC_RES |
| 171 | // 2/4 0.2 14.2 |
| 172 | csd.write_bl_len |= (d >> 14) & 0x3 |
| 173 | // Ignore write_bl_partial, file_format_grp. 1 (+ 5) + 1 0.7 15.1 |
| 174 | // 1 0.1 15.2 |
| 175 | csd.copy = d & 0x40 |
| 176 | // 1 0.1 15.3 |
| 177 | csd.perm_write_protect = d & 0x20 |
| 178 | // 1 0.1 15.4 |
| 179 | csd.tmp_write_protect = d & 0x10 |
| 180 | // Ignore file_format. 2 (+ 2) 0.4 16.0 *** |
| 181 | read_block_size = hc ? 512 : 1 << csd.read_bl_len |
| 182 | num_blocks = (csd.c_size + 1) << (csd.c_size_mult + 2) |
| 183 | if hc: |
| 184 | if csd.read_bl_len < 9: |
| 185 | num_blocks >>= 9 - csd.read_bl_len |
| 186 | else: |
| 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 |
| 197 | else if response_type != NONE: |
| 198 | unsigned r = MSC_RES |
| 199 | if response_type == R3: |
| 200 | if r >> 8 != 0x3f: |
| 201 | Iris::panic (r, "r3 response was not 3f") |
| 202 | else if r >> 8 != cmd: |
| 203 | kdebug ("stat: ") |
| 204 | kdebug_num (MSC_STAT) |
| 205 | kdebug ("; response: ") |
| 206 | kdebug_num (r) |
| 207 | kdebug ("; cmd: ") |
| 208 | kdebug_num (cmd) |
| 209 | Iris::panic (r, "response doesn't match command") |
| 210 | r <<= 24 |
| 211 | r |= MSC_RES << 8 |
| 212 | r |= MSC_RES & 0xff |
| 213 | if response: |
| 214 | *response = r |
| 215 | else: |
| 216 | //kdebug ("extra response fifo read: ") |
| 217 | //for unsigned i = 0; i < 9; ++i: |
| 218 | //kdebug (" ") |
| 219 | //kdebug_num (MSC_RES, 4) |
| 220 | //kdebug ("\n") |
| 221 | MSC_IREG = MSC_IREG_END_CMD_RES |
| 222 | return true |
| 223 | |
| 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) |
| 229 | // Create a buffer to use for data transfer. |
| 230 | buffer_page = Iris::my_memory.create_page () |
| 231 | Iris::my_memory.map (buffer_page, buffer) |
| 232 | // Reset all state, by faking a release event. |
| 233 | release () |
| 234 | // Enable 25 MHz clock to msc. |
| 235 | CPM_MSCCDR = 13 |
| 236 | cpm_start_msc () |
| 237 | // Enable msc pins. |
| 238 | gpio_as_msc () |
| 239 | // Disable power to card. |
| 240 | gpio_as_gpio (POWER_PORT, 1 << POWER_PIN) |
| 241 | gpio_as_output (POWER_PORT, 1 << POWER_PIN) |
| 242 | gpio_disable_pull (POWER_PORT, 1 << POWER_PIN) |
| 243 | gpio_set (POWER_PORT, 1 << POWER_PIN) |
| 244 | |
| 245 | // Stop the clock. |
| 246 | MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP |
| 247 | while MSC_STAT & MSC_STAT_CLK_EN: |
| 248 | //kdebug (",") |
| 249 | Iris::sleep (1) |
| 250 | |
| 251 | // Reset controller and inserted devices. |
| 252 | MSC_STRPCL = MSC_STRPCL_RESET |
| 253 | while MSC_STAT & MSC_STAT_IS_RESETTING: |
| 254 | //kdebug (":") |
| 255 | Iris::sleep (1) |
| 256 | |
| 257 | // Initialize registers. |
| 258 | MSC_CLKRT = MSC_CLKRT_CLK_RATE_DIV_1 |
| 259 | MSC_RESTO = 64 |
| 260 | MSC_RDTO = ~0 |
| 261 | MSC_BLKLEN = 0x200 |
| 262 | MSC_NOB = 0 |
| 263 | MSC_IREG = ~0 |
| 264 | MSC_IMASK = ~(MSC_IMASK_END_CMD_RES | MSC_IMASK_RXFIFO_RD_REQ) |
| 265 | MSC_ARG = 0 |
| 266 | |
| 267 | // Start the clock. |
| 268 | MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START |
| 269 | // Set cards, if any, to idle. |
| 270 | send (0, 0, NONE) |
| 271 | |
| 272 | // Reset SDIO device, if any. Don't do this, because it breaks for some reason. |
| 273 | //send (52, 0x88000c08, R5) |
| 274 | |
| 275 | void Mmc::check_mmc (): |
| 276 | //kdebug ("checking mmc\n") |
| 277 | // 1. SEND CMD1 (SEND_OP_CMD) TO VALIDATE VOLTAGE (THE GENERAL OCR VALUE IS 0X00FF88000). |
| 278 | // 2. IF THE RESPONSE IS CORRECT, THEN CONTINUE, ELSE GOTO 9. |
| 279 | // 3. IF THE INITIALIZATION HAS FINISHED, GO TO 5. (THE RESPONSE IS THE OCR REGISTER AND IT INCLUDES A STATUS INFORMATION BIT (BIT [31]). THIS STATUS BIT IS SET IF THE CARD POWER UP PROCEDURE HAS BEEN FINISHED. AS LONG AS THE CARD IS BUSY, THE CORRESPONDING BIT[31] IS SET TO LOW.) |
| 280 | // 4. Send CMD1 (SEND_OP_CMD) to validate voltage, and then go to 3. |
| 281 | // 5. Send CMD2 (ALL_SEND_CID) to get the card CID. |
| 282 | // 6. If the response timeout occurs, goto 9. |
| 283 | // 7. Send CMD3 (SET_RELATIVE_ADDR) to assign the card a RCA. |
| 284 | |
| 285 | void Mmc::check_sdmem (): |
| 286 | kdebug ("checking sdmem\n") |
| 287 | // 2. Send CMD55. Here the default RCA 0x0000 is used for CMD55. |
| 288 | // 3. If the response is correct (CMD55 has response), then continue, else go to check MMC. |
| 289 | unsigned code |
| 290 | hc = false |
| 291 | if send (8, 0x1aa, R7, &code) && (code & 0xff) == 0xaa: |
| 292 | kdebug ("hc\n") |
| 293 | hc = true |
| 294 | if !send (55, 0, R1, &code): |
| 295 | check_mmc () |
| 296 | return |
| 297 | // 4. Send ACMD41 (SD_SEND_OP_CMD) to validate voltage (the general OCR value is 0x00FF8000). |
| 298 | if !send (41, hc ? 0x40800000 : 0x00800000, R3, &code): |
| 299 | check_mmc () |
| 300 | return |
| 301 | // 5. If the initialization has finished, go to 7. (The response is the OCR register and it includes a status information bit (bit [31]). This status bit is set if the card power up procedure has been finished. As long as the card is busy, the corresponding bit[31] is set to LOW.) |
| 302 | // 6. Send CMD55 and ACMD41 to validate voltage, and then go to 5. |
| 303 | unsigned retries = 100 |
| 304 | while !(code & (1 << 31)) && --retries: |
| 305 | if !send (55, 0, R1, &code): |
| 306 | return |
| 307 | if !send (41, hc ? 0x40800000 : 0x00800000, R3, &code): |
| 308 | return |
| 309 | Iris::sleep (1) |
| 310 | if !(code & (1 << 31)): |
| 311 | Iris::panic (code, "card fails to finish setting up") |
| 312 | // 7. Send CMD2 (ALL_SEND_CID) to get the card CID. |
| 313 | if !send (2, 0, R2): |
| 314 | Iris::panic (0, "card failed to send CID") |
| 315 | // 8. Send CMD3 (SET_RELATIVE_ADDR) to let card publish a RCA. The RCA is returned from the response. |
| 316 | // 9. If do not accept the new RCA, go to 8, else record the new RCA. |
| 317 | rca = 0 |
| 318 | while !rca: |
| 319 | if !send (3, 0, R6, &rca): |
| 320 | Iris::panic (0, "card failed to provide rca") |
| 321 | rca &= 0xffff0000 |
| 322 | kdebug ("received rca ") |
| 323 | kdebug_num (rca >> 16, 4) |
| 324 | kdebug ("\n") |
| 325 | have_sdmem = true |
| 326 | |
| 327 | void Mmc::check_sd (): |
| 328 | //kdebug ("checking sdio\n") |
| 329 | if !send (0, 0, NONE): |
| 330 | Iris::panic (0, "unable to reset cards?") |
| 331 | // 2. Send CMD5 (IO_SEND_OP_CMD) to validate voltage. |
| 332 | // 3. If the response is correct and the number of IO functions > 0, then continue, else go to check SDMEM. |
| 333 | unsigned code |
| 334 | if !send (5, 1 << 20, R4, &code) || !(code & (7 << 28)): |
| 335 | check_sdmem () |
| 336 | return |
| 337 | // 4. If C-bit in the response is ready (the initialization has finished), go to 6. |
| 338 | // 5. Send CMD5 (IO_SEND_OP_CMD) to validate voltage, then go to 4. |
| 339 | while !(code & (1 << 31)): |
| 340 | if !send (5, 1 << 20, R4, &code): |
| 341 | Iris::panic (0, "invalid response to cmd 5") |
| 342 | // 6. If memory-present-bit in the response is true, then it is a combo card (SDIO + Memory), else it is only a SDIO card. |
| 343 | // 7. If it is a combo card, go to check SDMEM to initialize the memory part. |
| 344 | have_io = true |
| 345 | if code & (1 << 27): |
| 346 | check_sdmem () |
| 347 | return |
| 348 | // 8. Send CMD3 (SET_RELATIVE_ADDR) to let the card publish a RCA. The RCA is returned from the response. |
| 349 | // 9. If do not accept the new RCA, go to 8, else record the new RCA. |
| 350 | rca = 0 |
| 351 | while rca == 0: |
| 352 | if !send (3, 0, R6, &rca): |
| 353 | Iris::panic (0, "unable to set rca") |
| 354 | rca &= 0xffff0000 |
| 355 | check_mmc () |
| 356 | |
| 357 | void Mmc::detect (): |
| 358 | kdebug ("mmc detect\n") |
| 359 | gpio_clear (POWER_PORT, 1 << POWER_PIN) |
| 360 | check_sd () |
| 361 | check_mmc () |
| 362 | if have_sdmem: |
| 363 | if !send (9, rca, R2): |
| 364 | Iris::panic (0, "unable to request csd") |
| 365 | if !send (7, rca, R1B): |
| 366 | Iris::panic (0, "unable to select sdmem") |
| 367 | kdebug ("found device; size = ") |
| 368 | kdebug_num (num_blocks) |
| 369 | kdebug (" * ") |
| 370 | kdebug_num (read_block_size) |
| 371 | kdebug (" = ") |
| 372 | kdebug_num (num_blocks * read_block_size) |
| 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 |
| 388 | |
| 389 | void Mmc::release (): |
| 390 | kdebug ("mmc release\n") |
| 391 | gpio_set (POWER_PORT, 1 << POWER_PIN) |
| 392 | have_sdmem = false |
| 393 | have_io = false |
| 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 |
| 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 |
| 413 | |
| 414 | void Mmc::interrupt (): |
| 415 | kdebug ("mmc interrupt\n") |
| 416 | |
| 417 | void Mmc::set_block (unsigned block): |
| 418 | if current_block_num == block: |
| 419 | return |
| 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 () |
| 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 |
| 436 | MSC_NOB = 1 |
| 437 | MSC_BLKLEN = 1 << 9 |
| 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): |
| 440 | Iris::panic (0, "unable to request data") |
| 441 | MSC_IMASK = ~MSC_IMASK_RXFIFO_RD_REQ |
| 442 | for unsigned aa = 0; aa < 1 << 9; aa += 4: |
| 443 | while MSC_STAT & MSC_STAT_DATA_FIFO_EMPTY: |
| 444 | Iris::register_interrupt (IRQ_MSC) |
| 445 | Iris::wait_for_interrupt () |
| 446 | current_block[(a + aa) >> 2] = MSC_RXFIFO |
| 447 | MSC_IMASK = ~0 |
| 448 | MSC_IREG = MSC_IREG_DATA_TRAN_DONE |
| 449 | //kdebug ("done filling page\n") |
| 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.set_flags (Iris::Page::PAYING | Iris::Page::FRAME) |
| 463 | page.share (buffer_page) |
| 464 | buffer_page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME) |
| 465 | page.set_flags (0, Iris::Page::PAYING) |
| 466 | for unsigned i = 0; i < size; i += 4: |
| 467 | ((unsigned *)buffer)[(offset + i) >> 2] = current_block[(start_pos + i) >> 2] |
| 468 | |
| 469 | void Mmc::write_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset): |
| 470 | if address.value () >> (csd.write_bl_len + 32): |
| 471 | Iris::panic (address.h, "page too high: not supported") |
| 472 | unsigned block = address.value () >> csd.write_bl_len |
| 473 | unsigned start_pos = address.l & (1 << csd.write_bl_len) - 1 |
| 474 | set_block (block) |
| 475 | unsigned blockmask = ~((1 << 9) - 1) |
| 476 | size &= blockmask |
| 477 | offset &= ~PAGE_MASK & ~3 |
| 478 | if size + offset > PAGE_SIZE: |
| 479 | size = PAGE_SIZE - offset |
| 480 | page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME) |
| 481 | page.share (buffer_page) |
| 482 | buffer_page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME) |
| 483 | page.set_flags (0, Iris::Page::PAYING) |
| 484 | for unsigned i = 0; i < size; i += 4: |
| 485 | current_block[(start_pos + i) >> 2] = ((unsigned *)buffer)[(offset + i) >> 2] |
| 486 | dirty = true |
| 487 | |
| 488 | void Mmc::wait_write (): |
| 489 | MSC_IMASK = ~MSC_IMASK_PRG_DONE |
| 490 | while !MSC_STAT & MSC_STAT_PRG_DONE: |
| 491 | Iris::register_interrupt (IRQ_MSC) |
| 492 | Iris::wait_for_interrupt () |
| 493 | MSC_IREG = MSC_IREG_PRG_DONE |
| 494 | |
| 495 | static Mmc mmc |
| 496 | |
| 497 | enum types: |
| 498 | DETECT = 1 |
| 499 | REQUEST |
| 500 | |
| 501 | Iris::Num start (): |
| 502 | map_msc () |
| 503 | map_gpio () |
| 504 | map_cpm () |
| 505 | |
| 506 | mmc.reset () |
| 507 | |
| 508 | Iris::Event detect = Iris::my_parent.get_capability <Iris::Event> () |
| 509 | Iris::Cap cap = Iris::my_receiver.create_capability (DETECT) |
| 510 | detect.set_cb (cap.copy ()) |
| 511 | cap.invoke (~0) |
| 512 | Iris::free_cap (cap) |
| 513 | |
| 514 | // Get a message from the queue. This is either the "there is no card" message, or the message we just sent. |
| 515 | Iris::wait () |
| 516 | if Iris::recv.data[0].l != ~0: |
| 517 | // If it was "there is no card", the message we sent is still in the queue. |
| 518 | Iris::wait () |
| 519 | else: |
| 520 | // Otherwise, there is a card. |
| 521 | mmc.detect () |
| 522 | |
| 523 | cap = Iris::my_receiver.create_capability (REQUEST) |
| 524 | Iris::my_parent.provide_capability <Iris::WBlock> (cap.copy ()) |
| 525 | Iris::free_cap (cap) |
| 526 | |
| 527 | Iris::my_parent.init_done () |
| 528 | |
| 529 | while true: |
| 530 | Iris::wait () |
| 531 | switch Iris::recv.protected_data.l: |
| 532 | case 0: |
| 533 | mmc.interrupt () |
| 534 | break |
| 535 | case DETECT: |
| 536 | if Iris::recv.data[0].l: |
| 537 | mmc.detect () |
| 538 | else: |
| 539 | mmc.release () |
| 540 | break |
| 541 | case REQUEST: |
| 542 | //kdebug ("sd+mmc request ") |
| 543 | //kdebug_num (Iris::recv.data[0].l) |
| 544 | //kdebug ("\n") |
| 545 | switch Iris::recv.data[0].l: |
| 546 | case Iris::Block::GET_SIZE: |
| 547 | Iris::debug ("get size\n") |
| 548 | unsigned long long size = mmc.get_num_blocks () * mmc.get_read_block_size () |
| 549 | Iris::recv.reply.invoke (size) |
| 550 | break |
| 551 | case Iris::Block::GET_ALIGN_BITS: |
| 552 | Iris::debug ("get align bits\n") |
| 553 | Iris::recv.reply.invoke (9) |
| 554 | break |
| 555 | case Iris::Block::GET_BLOCK: |
| 556 | //Iris::debug ("get block\n") |
| 557 | Iris::Cap reply = Iris::get_reply () |
| 558 | Iris::Page page = Iris::get_arg () |
| 559 | mmc.read_page (page, Iris::recv.data[1], Iris::recv.data[0].h >> 16, Iris::recv.data[0].h & 0xffff) |
| 560 | reply.invoke () |
| 561 | Iris::free_cap (page) |
| 562 | Iris::free_cap (reply) |
| 563 | break |
| 564 | case Iris::WBlock::SET_BLOCK: |
| 565 | Iris::debug ("set block\n") |
| 566 | Iris::Cap reply = Iris::get_reply () |
| 567 | Iris::Page page = Iris::get_arg () |
| 568 | mmc.write_page (page, Iris::recv.data[1], Iris::recv.data[0].h >> 16, Iris::recv.data[0].h & 0xffff) |
| 569 | reply.invoke () |
| 570 | Iris::free_cap (page) |
| 571 | Iris::free_cap (reply) |
| 572 | mmc.wait_write () |
| 573 | break |
| 574 | case Iris::Block::SET_CHANGE_CB: |
| 575 | Iris::debug ("set change cb\n") |
| 576 | Iris::Listitem item = Iris::get_arg () |
| 577 | Iris::Cap reply = Iris::get_reply () |
| 578 | mmc.add_cb (item) |
| 579 | reply.invoke () |
| 580 | Iris::free_cap (item) |
| 581 | Iris::free_cap (reply) |
| 582 | break |
| 583 | case Iris::WBlock::TRUNCATE: |
| 584 | Iris::debug ("truncate\n") |
| 585 | // Fall through: don't support resizing. |
| 586 | default: |
| 587 | Iris::panic (0, "unexpected event for sd+mmc") |
| 588 | break |
| 589 | default: |
| 590 | Iris::panic (0, "unexpected request source for sd+mmc") |
| 591 |
Branches:
master
