aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorJaehoon Chung <jh80.chung@samsung.com>2011-10-18 01:26:42 -0400
committerChris Ball <cjb@laptop.org>2011-10-26 16:32:29 -0400
commiteb0d8f135b6730d6d0324a064664d121334290e7 (patch)
tree74876f5d20163bb5e9b185d9357237e1f22a2262 /drivers/mmc
parent881d1c25f765938a95def5afe39486ce39f9fc96 (diff)
mmc: core: support HPI send command
HPI command is defined in eMMC4.41. This feature is important for eMMC4.5 devices. Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/core/core.c57
-rw-r--r--drivers/mmc/core/mmc.c31
-rw-r--r--drivers/mmc/core/mmc_ops.c31
-rw-r--r--drivers/mmc/core/mmc_ops.h1
4 files changed, 120 insertions, 0 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 235bb6a1f973..fe65bb377e25 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -380,6 +380,63 @@ void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
380EXPORT_SYMBOL(mmc_wait_for_req); 380EXPORT_SYMBOL(mmc_wait_for_req);
381 381
382/** 382/**
383 * mmc_interrupt_hpi - Issue for High priority Interrupt
384 * @card: the MMC card associated with the HPI transfer
385 *
386 * Issued High Priority Interrupt, and check for card status
387 * util out-of prg-state.
388 */
389int mmc_interrupt_hpi(struct mmc_card *card)
390{
391 int err;
392 u32 status;
393
394 BUG_ON(!card);
395
396 if (!card->ext_csd.hpi_en) {
397 pr_info("%s: HPI enable bit unset\n", mmc_hostname(card->host));
398 return 1;
399 }
400
401 mmc_claim_host(card->host);
402 err = mmc_send_status(card, &status);
403 if (err) {
404 pr_err("%s: Get card status fail\n", mmc_hostname(card->host));
405 goto out;
406 }
407
408 /*
409 * If the card status is in PRG-state, we can send the HPI command.
410 */
411 if (R1_CURRENT_STATE(status) == R1_STATE_PRG) {
412 do {
413 /*
414 * We don't know when the HPI command will finish
415 * processing, so we need to resend HPI until out
416 * of prg-state, and keep checking the card status
417 * with SEND_STATUS. If a timeout error occurs when
418 * sending the HPI command, we are already out of
419 * prg-state.
420 */
421 err = mmc_send_hpi_cmd(card, &status);
422 if (err)
423 pr_debug("%s: abort HPI (%d error)\n",
424 mmc_hostname(card->host), err);
425
426 err = mmc_send_status(card, &status);
427 if (err)
428 break;
429 } while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
430 } else
431 pr_debug("%s: Left prg-state\n", mmc_hostname(card->host));
432
433out:
434 mmc_release_host(card->host);
435 return err;
436}
437EXPORT_SYMBOL(mmc_interrupt_hpi);
438
439/**
383 * mmc_wait_for_cmd - start a command and wait for completion 440 * mmc_wait_for_cmd - start a command and wait for completion
384 * @host: MMC host to start command 441 * @host: MMC host to start command
385 * @cmd: MMC command to start 442 * @cmd: MMC command to start
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index de5900aa81cd..fb5bf01dd1b2 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -448,6 +448,21 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
448 } 448 }
449 449
450 if (card->ext_csd.rev >= 5) { 450 if (card->ext_csd.rev >= 5) {
451 /* check whether the eMMC card supports HPI */
452 if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) {
453 card->ext_csd.hpi = 1;
454 if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2)
455 card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION;
456 else
457 card->ext_csd.hpi_cmd = MMC_SEND_STATUS;
458 /*
459 * Indicate the maximum timeout to close
460 * a command interrupted by HPI
461 */
462 card->ext_csd.out_of_int_time =
463 ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] * 10;
464 }
465
451 card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM]; 466 card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
452 card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION]; 467 card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION];
453 } 468 }
@@ -896,6 +911,22 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
896 } 911 }
897 912
898 /* 913 /*
914 * Enable HPI feature (if supported)
915 */
916 if (card->ext_csd.hpi) {
917 err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
918 EXT_CSD_HPI_MGMT, 1, 0);
919 if (err && err != -EBADMSG)
920 goto free_card;
921 if (err) {
922 pr_warning("%s: Enabling HPI failed\n",
923 mmc_hostname(card->host));
924 err = 0;
925 } else
926 card->ext_csd.hpi_en = 1;
927 }
928
929 /*
899 * Compute bus speed. 930 * Compute bus speed.
900 */ 931 */
901 max_dtr = (unsigned int)-1; 932 max_dtr = (unsigned int)-1;
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 4e11d56b3f70..007863eea4fb 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -547,3 +547,34 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width)
547 err = mmc_send_bus_test(card, card->host, MMC_BUS_TEST_R, width); 547 err = mmc_send_bus_test(card, card->host, MMC_BUS_TEST_R, width);
548 return err; 548 return err;
549} 549}
550
551int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
552{
553 struct mmc_command cmd = {0};
554 unsigned int opcode;
555 unsigned int flags;
556 int err;
557
558 opcode = card->ext_csd.hpi_cmd;
559 if (opcode == MMC_STOP_TRANSMISSION)
560 flags = MMC_RSP_R1 | MMC_CMD_AC;
561 else if (opcode == MMC_SEND_STATUS)
562 flags = MMC_RSP_R1 | MMC_CMD_AC;
563
564 cmd.opcode = opcode;
565 cmd.arg = card->rca << 16 | 1;
566 cmd.flags = flags;
567 cmd.cmd_timeout_ms = card->ext_csd.out_of_int_time;
568
569 err = mmc_wait_for_cmd(card->host, &cmd, 0);
570 if (err) {
571 pr_warn("%s: error %d interrupting operation. "
572 "HPI command response %#x\n", mmc_hostname(card->host),
573 err, cmd.resp[0]);
574 return err;
575 }
576 if (status)
577 *status = cmd.resp[0];
578
579 return 0;
580}
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 9276946fa5b7..3dd8941c2980 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -26,6 +26,7 @@ int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
26int mmc_spi_set_crc(struct mmc_host *host, int use_crc); 26int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
27int mmc_card_sleepawake(struct mmc_host *host, int sleep); 27int mmc_card_sleepawake(struct mmc_host *host, int sleep);
28int mmc_bus_test(struct mmc_card *card, u8 bus_width); 28int mmc_bus_test(struct mmc_card *card, u8 bus_width);
29int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status);
29 30
30#endif 31#endif
31 32