1/** 2 * \file 3 * \brief IMX8x uSDHC Digital Host Controller Driver 4 */ 5 6/* 7 * Copyright (c) 2007, 2008, 2010, 2011, 2012,2020 ETH Zurich. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, CAB F.78, Universitaetstrasse 6, CH-8092 Zurich, 13 * Attn: Systems Group. 14 */ 15 16/* 17 * In U-boot drivers/mmc/fsl_esdhc.c is talking to the 18 * same controller. This driver follows the i.MX 8DualXPlus/8QuadXPlus 19 * Applications Processor Reference Manual register definitions and 20 * descriptions, except for the vendor specific register, which is 21 * used differently in U-Boot, and that seems the correct way. 22 * 23 * Card detection on Toradex boards: 24 * =========== 25 * The Toradex boards dont break out the SDHC card detection pin, instead 26 * a GPIO (Bank4, Pin22) has to be checked for card present. Currently, 27 * this driver simply assumes a card is present. 28 */ 29 30#include <barrelfish/barrelfish.h> 31#include <int_route/int_route_client.h> 32#include <pci/pci.h> 33#include <dev/imx8x/sdhc_dev.h> 34#include <driverkit/driverkit.h> 35#include <barrelfish/deferred.h> 36#include <barrelfish/systime.h> 37 38//#define DEBUG_ON 39 40#if defined(DEBUG_ON) || defined(GLOBAL_DEBUG) 41# define DEBUG(x...) debug_printf(x) 42#else 43# define DEBUG(x...) ((void)0) 44#endif 45 46#define MMC_CMD_GO_IDLE_STATE 0 47#define MMC_CMD_SEND_OP_COND 1 48#define MMC_CMD_ALL_SEND_CID 2 49#define MMC_CMD_SET_RELATIVE_ADDR 3 50#define MMC_CMD_SET_DSR 4 51#define MMC_CMD_SWITCH 6 52#define MMC_CMD_SELECT_CARD 7 53#define MMC_CMD_SEND_EXT_CSD 8 54#define MMC_CMD_SEND_CSD 9 55#define MMC_CMD_SEND_CID 10 56#define MMC_CMD_STOP_TRANSMISSION 12 57#define MMC_CMD_SEND_STATUS 13 58#define MMC_CMD_SET_BLOCKLEN 16 59#define MMC_CMD_READ_SINGLE_BLOCK 17 60#define MMC_CMD_READ_MULTIPLE_BLOCK 18 61#define MMC_CMD_SEND_TUNING_BLOCK 19 62#define MMC_CMD_SEND_TUNING_BLOCK_HS200 21 63#define MMC_CMD_SET_BLOCK_COUNT 23 64#define MMC_CMD_WRITE_SINGLE_BLOCK 24 65#define MMC_CMD_WRITE_MULTIPLE_BLOCK 25 66#define MMC_CMD_ERASE_GROUP_START 35 67#define MMC_CMD_ERASE_GROUP_END 36 68#define MMC_CMD_ERASE 38 69#define MMC_CMD_APP_CMD 55 70#define MMC_CMD_SPI_READ_OCR 58 71#define MMC_CMD_SPI_CRC_ON_OFF 59 72#define MMC_CMD_RES_MAN 62 73 74#define SD_CMD_SEND_RELATIVE_ADDR 3 75#define SD_CMD_SWITCH_FUNC 6 76#define SD_CMD_SEND_IF_COND 8 77#define SD_CMD_SWITCH_UHS18V 11 78#define SD_CMD_APP_SET_BUS_WIDTH 6 79#define SD_CMD_APP_SD_STATUS 13 80#define SD_CMD_ERASE_WR_BLK_START 32 81#define SD_CMD_ERASE_WR_BLK_END 33 82#define SD_CMD_APP_SEND_OP_COND 41 83#define SD_CMD_APP_SEND_SCR 51 84 85 86#define MMC_RSP_PRESENT (1 << 0) 87#define MMC_RSP_136 (1 << 1) /* 136 bit response */ 88#define MMC_RSP_CRC (1 << 2) /* expect valid crc */ 89#define MMC_RSP_BUSY (1 << 3) /* card may send busy */ 90#define MMC_RSP_OPCODE (1 << 4) /* response contains opcode */ 91 92#define MMC_RSP_NONE (0) 93#define MMC_RSP_R1 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) 94#define MMC_RSP_R1b (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE| \ 95 MMC_RSP_BUSY) 96#define MMC_RSP_R2 (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC) 97#define MMC_RSP_R3 (MMC_RSP_PRESENT) 98#define MMC_RSP_R4 (MMC_RSP_PRESENT) 99#define MMC_RSP_R5 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) 100#define MMC_RSP_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) 101#define MMC_RSP_R7 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) 102 103#define OCR_BUSY 0x80000000 104#define OCR_HCS 0x40000000 105#define OCR_S18R 0x1000000 106 107#define BLOCK_SIZE 512 108 109struct sdhc { 110 sdhc_t dev; 111 uintptr_t vbase; 112 uint32_t caps; 113 114 // Card properties 115 uint8_t cid[16]; 116 uint32_t csd[4]; 117 uint16_t rca; 118 int high_capacity; 119 120 uint64_t read_bl_len; 121 uint64_t write_bl_len ; 122 uint64_t capacity_user; 123}; 124 125struct cmd { 126 uint16_t cmdidx; 127 unsigned int cmdarg; 128 unsigned int resp_type; 129 unsigned int response[4]; // The response of the command 130 genpaddr_t dma_base; // If a data transfer is necessary, use this 131 // physical base address for read/write. 132}; 133 134#define dump(sd) do {\ 135 char buf[1024];\ 136 sdhc_int_status_pr(buf, 1024, &sd->dev);\ 137 DEBUG("%s:%d: %s\n", __FUNCTION__, __LINE__, buf);\ 138 } while(0) 139 140#define dump_all(sd) do {\ 141 char buf[16*1024];\ 142 sdhc_pr(buf, 16*1024, &sd->dev);\ 143 printf("%s\n", buf);\ 144 } while(0) 145 146 147static void int_handler(void *arg) 148{ 149 DEBUG("%s: enter\n", __FUNCTION__); 150 struct sdhc * sd = (struct sdhc *)arg; 151 dump(sd); 152} 153 154__attribute__((used)) 155static errval_t software_reset(struct sdhc *sd){ 156 sdhc_sys_ctrl_rsta_wrf(&sd->dev, 1); 157 volatile uint64_t timeout = 1000000; 158 while(sdhc_sys_ctrl_rsta_rdf(&sd->dev)){ 159 timeout--; 160 if(timeout == 0){ 161 DEBUG("Reset TIMEOUT!\n"); 162 return SDHC_ERR_RESET_TIMEOUT; 163 } 164 } 165 166 // Set sensible defaults 167 sdhc_mmc_boot_rawwr(&sd->dev, 0); 168 sdhc_mix_ctrl_rawwr(&sd->dev, 0); 169 sdhc_clk_tune_ctrl_status_rawwr(&sd->dev, 0); 170 sdhc_dll_rawwr(&sd->dev, 0); 171 172 sdhc_vend_spec_t vs = 0; 173 vs = sdhc_vend_spec_ipgen_insert(vs, 1); 174 vs = sdhc_vend_spec_hcken_insert(vs, 1); 175 sdhc_vend_spec_wr(&sd->dev, vs); 176 177 DEBUG("Reset complete!\n"); 178 179 sd->caps = sdhc_host_ctrl_cap_rawrd(&sd->dev); 180 181 //Setting clock to initial 40mhz 182 sdhc_vend_spec_cken_wrf(&sd->dev, 0); 183 184 sdhc_sys_ctrl_t s = 0; 185 s = sdhc_sys_ctrl_dvs_insert(s, 0xf); 186 s = sdhc_sys_ctrl_sdclkfs_insert(s, 0x10); 187 s = sdhc_sys_ctrl_dtocv_insert(s, 0xc); 188 sdhc_sys_ctrl_wr(&sd->dev, s); 189 190 barrelfish_usleep(10000); 191 vs = sdhc_vend_spec_rd(&sd->dev); 192 vs = sdhc_vend_spec_peren_insert(vs, 1); 193 vs = sdhc_vend_spec_cken_insert(vs, 1); 194 sdhc_vend_spec_wr(&sd->dev, vs); 195 196 sdhc_prot_ctrl_dtw_wrf(&sd->dev, 0); // Bus width: 1-bit mode 197 sdhc_prot_ctrl_emode_wrf(&sd->dev, 0x2); // Little endian mode 198 sdhc_sys_ctrl_dtocv_wrf(&sd->dev, 0xe); 199 200 return SYS_ERR_OK; 201} 202 203 204 205__attribute__((used)) 206static sdhc_cmd_xfr_typ_t xfr_typ_for_cmd(struct cmd *cmd){ 207 sdhc_cmd_xfr_typ_t c = 0; 208 209 if(cmd->cmdidx == MMC_CMD_READ_SINGLE_BLOCK || 210 cmd->cmdidx == MMC_CMD_WRITE_SINGLE_BLOCK) 211 { 212 c = sdhc_cmd_xfr_typ_dpsel_insert(c, 1); 213 } 214 215 c = sdhc_cmd_xfr_typ_cmdinx_insert(c, cmd->cmdidx); 216 if (cmd->resp_type & MMC_RSP_CRC) 217 c = sdhc_cmd_xfr_typ_cccen_insert(c, 1); 218 if (cmd->resp_type & MMC_RSP_OPCODE) 219 c = sdhc_cmd_xfr_typ_cicen_insert(c, 1); 220 221 222 c = sdhc_cmd_xfr_typ_rsptyp_insert(c, sdhc_rsp_tp_none); 223 if (cmd->resp_type & MMC_RSP_136) 224 c = sdhc_cmd_xfr_typ_rsptyp_insert(c, sdhc_rsp_tp_136); 225 else if (cmd->resp_type & MMC_RSP_BUSY) 226 c = sdhc_cmd_xfr_typ_rsptyp_insert(c, sdhc_rsp_tp_48cb); 227 else if (cmd->resp_type & MMC_RSP_PRESENT) 228 c = sdhc_cmd_xfr_typ_rsptyp_insert(c, sdhc_rsp_tp_48); 229 230 c = sdhc_cmd_xfr_typ_cmdtyp_insert(c, sdhc_cmd_tp_norm); 231 if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) 232 c = sdhc_cmd_xfr_typ_cmdtyp_insert(c, sdhc_cmd_tp_abrt); 233 234 return c; 235} 236 237__attribute__((used)) 238static errval_t sdhc_send_cmd(struct sdhc * sd, struct cmd * cmd) { 239 DEBUG("sdhc_send_cmd: cmdidx=%d,cmdarg=%d\n", cmd->cmdidx, cmd->cmdarg); 240 241 uint32_t mask; // TODO: in some cases we don't need to wait for all 242 if(cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) { 243 mask = 1; 244 } else { 245 mask = 3; 246 } 247 while(sdhc_pres_state_rawrd(&sd->dev) & mask){ 248 DEBUG("Card busy!\n"); 249 } 250 DEBUG("Card ready (data & cmd inhibit are clear)!\n"); 251 barrelfish_usleep(10000); 252 253 // Clear interrupts 254 sdhc_int_status_rawwr(&sd->dev, ~0x0); 255 256 // Mask interrupts. 257 sdhc_int_signal_en_rawwr(&sd->dev, 0); 258 259 // CMD argument 260 sdhc_cmd_arg_wr(&sd->dev, cmd->cmdarg); 261 262 // Mixer controler 263 int is_read = cmd->cmdidx == MMC_CMD_READ_SINGLE_BLOCK; 264 int is_write = cmd->cmdidx == MMC_CMD_WRITE_SINGLE_BLOCK; 265 sdhc_mix_ctrl_wr(&sd->dev, 0); 266 sdhc_mix_ctrl_dmaen_wrf(&sd->dev, is_read || is_write); 267 sdhc_mix_ctrl_dtdsel_wrf(&sd->dev, is_read); 268 269 if(is_read || is_write){ 270 // DMA address setup 271 assert((cmd->dma_base >> 32) == 0); 272 sdhc_vend_spec2_acmd23_argu2_en_wrf(&sd->dev, 0); 273 sdhc_ds_addr_wr(&sd->dev, cmd->dma_base); 274 275 //Set watermark 276 sdhc_wtmk_lvl_rd_wml_wrf(&sd->dev, 16); 277 sdhc_wtmk_lvl_wr_wml_wrf(&sd->dev, 16); 278 } 279 280 sdhc_cmd_xfr_typ_t c = xfr_typ_for_cmd(cmd); 281 sdhc_cmd_xfr_typ_wr(&sd->dev, c); 282 283 //DEBUG("%s:%d: Wait until irq_stat.tc || irq_stat.cc \n", __FUNCTION__, __LINE__); 284 uint32_t tc = 0; 285 uint32_t cc = 0; 286 size_t i = 0; 287 do { 288 uint32_t ctoe = sdhc_int_status_ctoe_rdf(&sd->dev); 289 uint32_t cce = sdhc_int_status_cce_rdf(&sd->dev); 290 tc = sdhc_int_status_tc_rdf(&sd->dev); 291 cc = sdhc_int_status_cc_rdf(&sd->dev); 292 293 if (ctoe == 0x1 && cce == 0x1) { 294 DEBUG("%s:%d: ctoe = 1 ccrc = 1: Conflict on cmd line.\n", 295 __FUNCTION__, __LINE__); 296 dump(sd); 297 return SDHC_ERR_CMD_CONFLICT; 298 } 299 if (ctoe == 0x1 && cce == 0x0) { 300 DEBUG("%s:%d: cto = 1 ccrc = 0: Abort.\n", __FUNCTION__, __LINE__); 301 dump(sd); 302 return SDHC_ERR_CMD_TIMEOUT; 303 } 304 305 if (i++ > 1000) { 306 dump(sd); 307 USER_PANIC("Command not Ackd?"); 308 } 309 barrelfish_usleep(100); 310 if(tc || cc) break; 311 } while (true); 312 DEBUG("Command complete!\n"); 313 314 if(cmd->resp_type & MMC_RSP_136){ 315 uint32_t r0 = sdhc_cmd_rsp0_rd(&sd->dev); 316 uint32_t r1 = sdhc_cmd_rsp1_rd(&sd->dev); 317 uint32_t r2 = sdhc_cmd_rsp2_rd(&sd->dev); 318 uint32_t r3 = sdhc_cmd_rsp3_rd(&sd->dev); 319 cmd->response[0] = (r3 << 8) | (r2 >> 24); 320 cmd->response[1] = (r2 << 8) | (r1 >> 24); 321 cmd->response[2] = (r1 << 8) | (r0 >> 24); 322 cmd->response[3] = (r0 << 8); 323 } else { 324 cmd->response[0] = sdhc_cmd_rsp0_rd(&sd->dev); 325 } 326 return SYS_ERR_OK; 327} 328 329static errval_t sdhc_go_idle(struct sdhc *sd) { 330 errval_t err; 331 struct cmd init = { 332 .cmdidx = MMC_CMD_GO_IDLE_STATE, 333 .cmdarg = 0, 334 .resp_type = MMC_RSP_NONE 335 }; 336 err = sdhc_send_cmd(sd, &init); 337 if(err_is_ok(err)){ 338 DEBUG("Successfully sent GO_IDLE transaction\n"); 339 } 340 barrelfish_usleep(2000); 341 return err; 342} 343 344static errval_t sdhc_send_if_cond(struct sdhc *sd) { 345 errval_t err; 346 uint32_t pattern = 0xde; 347 struct cmd cmd = { 348 .cmdidx = SD_CMD_SEND_IF_COND, 349 .cmdarg = 0x100 | pattern, // Offer 3V voltage followed by pattern 350 .resp_type = MMC_RSP_R7 351 }; 352 353 err = sdhc_send_cmd(sd, &cmd); 354 if(err_is_ok(err)){ 355 if(cmd.response[0] == (0x100 | pattern)){ 356 DEBUG("IF_COND: Success! Got (at least) SD Version 2\n"); 357 return SYS_ERR_OK; 358 } else { 359 DEBUG("IF_COND: Legacy cards not supported!\n"); 360 err = SDHC_ERR_CMD_TIMEOUT; 361 } 362 } 363 return err; 364} 365 366/* 367 * This function queries the card to determine operating voltage/standard 368 * etc. It does not perform a card initialization. 369 */ 370static errval_t sdhc_get_ocr(struct sdhc *sd){ 371 errval_t err; 372 uint32_t ocr=0; 373 374 while(1){ 375 struct cmd app_cmd = { 376 .cmdidx = MMC_CMD_APP_CMD, 377 .cmdarg = 0, 378 .resp_type = MMC_RSP_R1 379 }; 380 381 err = sdhc_send_cmd(sd, &app_cmd); 382 if(err_is_fail(err)){ 383 DEBUG_ERR(err, "send app_cmd"); 384 return err; 385 } 386 387 struct cmd op_cond_cmd = { 388 .cmdidx = SD_CMD_APP_SEND_OP_COND, 389 .cmdarg = 0x40300000, // Have OCS and default voltages 390 .resp_type = MMC_RSP_R3 391 }; 392 err = sdhc_send_cmd(sd, &op_cond_cmd); 393 if(err_is_fail(err)) { 394 DEBUG_ERR(err, "send op_cond_cmd"); 395 return err; 396 } 397 398 if(op_cond_cmd.response[0] & OCR_BUSY) { 399 ocr = op_cond_cmd.response[0]; 400 break; 401 } 402 403 barrelfish_usleep(10000); 404 } 405 406 DEBUG("Received OCR! ocr=0x%"PRIx32"\n", ocr); 407 408 if((ocr & OCR_HCS) == OCR_HCS){ 409 DEBUG("High capacity card found!\n"); 410 sd->high_capacity = 1; 411 } else { 412 DEBUG("Non high capacity card. NOT TESTED\n"); 413 sd->high_capacity = 0; 414 } 415 sd->rca = 0; 416 return SYS_ERR_OK; 417} 418 419 420 421/** 422 * Here we perform the actual card initialization 423 */ 424static errval_t sdhc_card_init(struct sdhc* sd){ 425 errval_t err; 426 // Put card in identify mode 427 struct cmd cid = { 428 .cmdidx = MMC_CMD_ALL_SEND_CID, 429 .resp_type = MMC_RSP_R2, 430 .cmdarg = 0 431 }; 432 err = sdhc_send_cmd(sd, &cid); 433 if(err_is_fail(err)){ 434 DEBUG_ERR(err, "cid command"); 435 } 436 memcpy(sd->cid, cid.response, 16); 437 438 struct cmd send_addr = { 439 .cmdidx = SD_CMD_SEND_RELATIVE_ADDR, 440 .cmdarg = sd->rca << 16, 441 .resp_type = MMC_RSP_R6 442 }; 443 444 err = sdhc_send_cmd(sd, &send_addr); 445 if(err_is_fail(err)){ 446 DEBUG_ERR(err, "send addr command"); 447 } 448 sd->rca = send_addr.response[0] >> 16 & 0xffff; 449 DEBUG("Determined RCA=0x%"PRIx16".\n", sd->rca); 450 451 struct cmd send_csd = { 452 .cmdidx = MMC_CMD_SEND_CSD, 453 .resp_type = MMC_RSP_R2, 454 .cmdarg = sd->rca << 16 455 }; 456 err = sdhc_send_cmd(sd, &send_csd); 457 if(err_is_fail(err)){ 458 DEBUG_ERR(err, "send csd command"); 459 } 460 sd->csd[0] = send_csd.response[0]; 461 sd->csd[1] = send_csd.response[1]; 462 sd->csd[2] = send_csd.response[2]; 463 sd->csd[3] = send_csd.response[3]; 464 DEBUG("CSD: [0]=%"PRIx32", [1]=%"PRIx32", [2]=%"PRIx32", [3]=%"PRIx32"\n", 465 sd->csd[0], sd->csd[1], sd->csd[2], sd->csd[3]); 466 sd->read_bl_len = 1 << ((sd->csd[1]>>16) & 0xf); 467 DEBUG("SD read_bl_len: %"PRIx64"\n", sd->read_bl_len); 468 sd->write_bl_len = sd->read_bl_len; 469 470 if(sd->high_capacity) { 471 unsigned int csize, cmult; 472 csize = (sd->csd[1] & 0x3f) << 16 | (sd->csd[2] & 0xffff0000) >> 16; 473 cmult = 8; 474 sd->capacity_user = ((csize + 1) << (cmult + 2)) * sd->read_bl_len; 475 DEBUG("SD capacity: %"PRIx64"\n", sd->capacity_user); 476 } 477 478 // Select the card, this puts it into the "transfer" state 479 struct cmd select_card = { 480 .cmdidx = MMC_CMD_SELECT_CARD, 481 .resp_type = MMC_RSP_R1, 482 .cmdarg = sd->rca << 16 483 }; 484 err = sdhc_send_cmd(sd, &select_card); 485 if(err_is_fail(err)) { 486 DEBUG_ERR(err, "select_card cmd"); 487 return err; 488 } 489 490 return SYS_ERR_OK; 491} 492 493/* Read BLOCK_SIZE bytes block index into buffer */ 494static errval_t sdhc_read_block(struct sdhc * sd, int index, void **buffer){ 495 errval_t err; 496 497 // allocate and map frame for buffer 498 struct capref frame; 499 struct frame_identity frameid; 500 size_t retbytes; 501 err = frame_alloc(&frame, 4096, &retbytes); 502 assert(err_is_ok(err)); 503 assert(retbytes == 4096); 504 err = vspace_map_one_frame_attr(buffer, retbytes, frame, 505 VREGION_FLAGS_READ_WRITE_NOCACHE, NULL, NULL); 506 for(int i=0; i<128;i++) ((uint32_t*)*buffer)[i] = 0xdead; 507 assert(err_is_ok(err)); 508 err = frame_identify(frame, &frameid); 509 assert(err_is_ok(err)); 510 511 512 //Clear interrupts 513 sdhc_int_status_rawwr(&sd->dev, ~0x0); 514 515 struct cmd set_blocklen = { 516 .cmdidx = MMC_CMD_SET_BLOCKLEN, 517 .cmdarg = BLOCK_SIZE, 518 .resp_type = MMC_RSP_R1 519 }; 520 err = sdhc_send_cmd(sd, &set_blocklen); 521 if(err_is_fail(err)){ 522 DEBUG_ERR(err, "set_blocklen"); 523 return err; 524 } 525 526 struct cmd read_block = { 527 .cmdidx = MMC_CMD_READ_SINGLE_BLOCK, 528 .cmdarg = index, 529 .resp_type = MMC_RSP_R1, 530 .dma_base = frameid.base 531 532 }; 533 err = sdhc_send_cmd(sd, &read_block); 534 if(err_is_fail(err)){ 535 DEBUG_ERR(err, "read_block"); 536 return err; 537 } 538 539 return SYS_ERR_OK; 540} 541 542/* Write BLOCK_SIZE bytes to block index from data */ 543static errval_t sdhc_write_block(struct sdhc * sd, int index, void *data){ 544 errval_t err; 545 546 // allocate and map frame for buffer 547 struct capref frame; 548 struct frame_identity frameid; 549 size_t retbytes; 550 err = frame_alloc(&frame, 4096, &retbytes); 551 assert(err_is_ok(err)); 552 assert(retbytes == 4096); 553 void *data_dest; 554 err = vspace_map_one_frame_attr(&data_dest, retbytes, frame, 555 VREGION_FLAGS_READ_WRITE_NOCACHE, NULL, NULL); 556 assert(err_is_ok(err)); 557 err = frame_identify(frame, &frameid); 558 assert(err_is_ok(err)); 559 560 memcpy(data_dest, data, BLOCK_SIZE); 561 562 563 struct cmd set_blocklen = { 564 .cmdidx = MMC_CMD_SET_BLOCKLEN, 565 .cmdarg = BLOCK_SIZE, 566 .resp_type = MMC_RSP_R1 567 }; 568 err = sdhc_send_cmd(sd, &set_blocklen); 569 if(err_is_fail(err)){ 570 DEBUG_ERR(err, "set_blocklen"); 571 return err; 572 } 573 574 struct cmd write_block = { 575 .cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK, 576 .cmdarg = index, 577 .resp_type = MMC_RSP_R1, 578 .dma_base = frameid.base 579 580 }; 581 err = sdhc_send_cmd(sd, &write_block); 582 if(err_is_fail(err)){ 583 DEBUG_ERR(err, "read_block"); 584 return err; 585 } 586 587 return SYS_ERR_OK; 588} 589 590static errval_t sdhc_init(struct sdhc * sd){ 591 //Initialize and identify the card. Roughly following SDHC specification, 592 //3.6 Card Initialization and Identification. 593 errval_t err; 594 595 DEBUG("Sending go idle transaction...\n"); err = sdhc_go_idle(sd); 596 if(err_is_fail(err)) return err; 597 598 DEBUG("Sending if_cond transaction...\n"); 599 err = sdhc_send_if_cond(sd); 600 if(err_is_fail(err)) return err; 601 602 DEBUG("Query OCR (CMD 55/41)...\n"); 603 err = sdhc_get_ocr(sd); 604 if(err_is_fail(err)) return err; 605 606 DEBUG("Card initialization...\n"); 607 err = sdhc_card_init(sd); 608 if(err_is_fail(err)) return err; 609 610 DEBUG("Card in transfer state!"); 611 612 return SYS_ERR_OK; 613} 614 615static errval_t sdhc_test(struct sdhc *sd) { 616 errval_t err; 617 DEBUG("... testing read block...\n"); 618 void *buf; 619 err = sdhc_read_block(sd, 0, &buf); 620 if(err_is_fail(err)) return err; 621 for(int i=0; i<16;i++){ 622 DEBUG(" buf[%d] = %"PRIx32"\n", i, ((uint32_t*)buf)[i]); 623 } 624 625 DEBUG("... testing write block...\n"); 626 627 uint32_t data[128]; 628 for(int i=0; i<128; i+=4){ 629 data[i] = 0xdead; 630 data[i+1] = 0xbeef; 631 data[i+2] = 0xc0c0; 632 data[i+3] = 0xcaca; 633 }; 634 err = sdhc_write_block(sd, 20, data); 635 636 DEBUG("... reading just written data\n"); 637 void *buf2t; 638 err = sdhc_read_block(sd, 20, &buf2t); 639 uint32_t *buf2 = (uint32_t*) buf2t; 640 if(err_is_fail(err)) return err; 641 for(int i=0; i<16;i++){ 642 DEBUG(" buf2[%d] = %"PRIx32"\n", i, buf2[i]); 643 } 644 if(buf2[0] == 0xdead && buf2[1] ==0xbeef){ 645 return SYS_ERR_OK; 646 } else { 647 return SDHC_ERR_TEST_FAILED; 648 } 649} 650 651static errval_t init(struct bfdriver_instance *bfi, uint64_t flags, iref_t *dev) 652{ 653 DEBUG("sdhc entering init\n"); 654 errval_t err; 655 struct sdhc *sd = malloc(sizeof(struct sdhc)); 656 bfi->dstate = sd; 657 struct capref devframe_cap = { .slot = DRIVERKIT_ARGCN_SLOT_BAR0, 658 .cnode = bfi->argcn }; 659 err = map_device_cap(devframe_cap, &sd->vbase); 660 if(err_is_fail(err)){ 661 DEBUG_ERR(err, "map devframe"); 662 return err; 663 } 664 sdhc_initialize(&sd->dev, (mackerel_addr_t)sd->vbase); 665 666 struct capref irq_src; 667 irq_src.cnode = bfi->argcn; 668 irq_src.slot = PCIARG_SLOT_INT; 669 670 // Register interrupt handler 671 err = int_route_client_route_and_connect(irq_src, 0, 672 get_default_waitset(), int_handler, sd); 673 if (err_is_fail(err)) { 674 USER_PANIC_ERR(err, "interrupt setup failed."); 675 } 676 DEBUG("interrupt setup complete\n"); 677 678 err = software_reset(sd); 679 if (err_is_fail(err)) { 680 DEBUG_ERR(err, "software reset failed"); 681 return err; 682 } 683 DEBUG("reset done.\n"); 684 685 err = sdhc_init(sd); 686 if (err_is_fail(err)) { 687 DEBUG_ERR(err, "mmc init failed (No card present?)"); 688 return err; 689 } 690 691 err = sdhc_test(sd); 692 if (err_is_fail(err)) { 693 DEBUG_ERR(err, "mmc test failed"); 694 return err; 695 } 696 printf("SHDC test suceeded!\n"); 697 698 return SYS_ERR_OK; 699} 700 701static errval_t attach(struct bfdriver_instance *bfi) 702{ 703 return SYS_ERR_OK; 704} 705 706static errval_t detach(struct bfdriver_instance *bfi) 707{ 708 return SYS_ERR_OK; 709} 710 711static errval_t set_sleep_level(struct bfdriver_instance *bfi, uint32_t level) 712{ 713 return SYS_ERR_OK; 714} 715 716static errval_t destroy(struct bfdriver_instance *bfi) 717{ 718 struct sdhc *sd = bfi->dstate; 719 free(sd); 720 bfi->dstate = NULL; 721 bfi->device = 0x0; 722 return SYS_ERR_OK; 723} 724 725static errval_t get_ep(struct bfdriver_instance *bfi, bool lmp, struct capref *ret_cap) 726{ 727 USER_PANIC("NIY \n"); 728 return SYS_ERR_OK; 729} 730 731DEFINE_MODULE(sdhc, init, attach, detach, set_sleep_level, destroy, get_ep); 732