diff options
author | Pierre Ossman <drzeus-list@drzeus.cx> | 2005-09-06 18:18:53 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-07 19:57:50 -0400 |
commit | b57c43ad81602589afca3948a5a7121e40026e17 (patch) | |
tree | 39592e326f498231b39e95c299ad6fcd559341ef /drivers/mmc | |
parent | a00fc09029f02ca833cf90e5d5625f08c4ac4f51 (diff) |
[PATCH] sd: SCR register
Read the SD specific SCR register from the card.
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Cc: Russell King <rmk@arm.linux.org.uk>
Cc: David Brownell <david-b@pacbell.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/mmc.c | 143 |
1 files changed, 133 insertions, 10 deletions
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 725c6ad3eb64..21d4fb3314f8 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c | |||
@@ -16,6 +16,8 @@ | |||
16 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
17 | #include <linux/pagemap.h> | 17 | #include <linux/pagemap.h> |
18 | #include <linux/err.h> | 18 | #include <linux/err.h> |
19 | #include <asm/scatterlist.h> | ||
20 | #include <linux/scatterlist.h> | ||
19 | 21 | ||
20 | #include <linux/mmc/card.h> | 22 | #include <linux/mmc/card.h> |
21 | #include <linux/mmc/host.h> | 23 | #include <linux/mmc/host.h> |
@@ -246,6 +248,8 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca, | |||
246 | 248 | ||
247 | EXPORT_SYMBOL(mmc_wait_for_app_cmd); | 249 | EXPORT_SYMBOL(mmc_wait_for_app_cmd); |
248 | 250 | ||
251 | static int mmc_select_card(struct mmc_host *host, struct mmc_card *card); | ||
252 | |||
249 | /** | 253 | /** |
250 | * __mmc_claim_host - exclusively claim a host | 254 | * __mmc_claim_host - exclusively claim a host |
251 | * @host: mmc host to claim | 255 | * @host: mmc host to claim |
@@ -278,16 +282,10 @@ int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card) | |||
278 | spin_unlock_irqrestore(&host->lock, flags); | 282 | spin_unlock_irqrestore(&host->lock, flags); |
279 | remove_wait_queue(&host->wq, &wait); | 283 | remove_wait_queue(&host->wq, &wait); |
280 | 284 | ||
281 | if (card != (void *)-1 && host->card_selected != card) { | 285 | if (card != (void *)-1) { |
282 | struct mmc_command cmd; | 286 | err = mmc_select_card(host, card); |
283 | 287 | if (err != MMC_ERR_NONE) | |
284 | host->card_selected = card; | 288 | return err; |
285 | |||
286 | cmd.opcode = MMC_SELECT_CARD; | ||
287 | cmd.arg = card->rca << 16; | ||
288 | cmd.flags = MMC_RSP_R1; | ||
289 | |||
290 | err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); | ||
291 | } | 289 | } |
292 | 290 | ||
293 | return err; | 291 | return err; |
@@ -317,6 +315,29 @@ void mmc_release_host(struct mmc_host *host) | |||
317 | 315 | ||
318 | EXPORT_SYMBOL(mmc_release_host); | 316 | EXPORT_SYMBOL(mmc_release_host); |
319 | 317 | ||
318 | static int mmc_select_card(struct mmc_host *host, struct mmc_card *card) | ||
319 | { | ||
320 | int err; | ||
321 | struct mmc_command cmd; | ||
322 | |||
323 | BUG_ON(host->card_busy == NULL); | ||
324 | |||
325 | if (host->card_selected == card) | ||
326 | return MMC_ERR_NONE; | ||
327 | |||
328 | host->card_selected = card; | ||
329 | |||
330 | cmd.opcode = MMC_SELECT_CARD; | ||
331 | cmd.arg = card->rca << 16; | ||
332 | cmd.flags = MMC_RSP_R1; | ||
333 | |||
334 | err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); | ||
335 | if (err != MMC_ERR_NONE) | ||
336 | return err; | ||
337 | |||
338 | return MMC_ERR_NONE; | ||
339 | } | ||
340 | |||
320 | /* | 341 | /* |
321 | * Ensure that no card is selected. | 342 | * Ensure that no card is selected. |
322 | */ | 343 | */ |
@@ -526,6 +547,32 @@ static void mmc_decode_csd(struct mmc_card *card) | |||
526 | } | 547 | } |
527 | 548 | ||
528 | /* | 549 | /* |
550 | * Given a 64-bit response, decode to our card SCR structure. | ||
551 | */ | ||
552 | static void mmc_decode_scr(struct mmc_card *card) | ||
553 | { | ||
554 | struct sd_scr *scr = &card->scr; | ||
555 | unsigned int scr_struct; | ||
556 | u32 resp[4]; | ||
557 | |||
558 | BUG_ON(!mmc_card_sd(card)); | ||
559 | |||
560 | resp[3] = card->raw_scr[1]; | ||
561 | resp[2] = card->raw_scr[0]; | ||
562 | |||
563 | scr_struct = UNSTUFF_BITS(resp, 60, 4); | ||
564 | if (scr_struct != 0) { | ||
565 | printk("%s: unrecognised SCR structure version %d\n", | ||
566 | mmc_hostname(card->host), scr_struct); | ||
567 | mmc_card_set_bad(card); | ||
568 | return; | ||
569 | } | ||
570 | |||
571 | scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4); | ||
572 | scr->bus_widths = UNSTUFF_BITS(resp, 48, 4); | ||
573 | } | ||
574 | |||
575 | /* | ||
529 | * Locate a MMC card on this MMC host given a raw CID. | 576 | * Locate a MMC card on this MMC host given a raw CID. |
530 | */ | 577 | */ |
531 | static struct mmc_card *mmc_find_card(struct mmc_host *host, u32 *raw_cid) | 578 | static struct mmc_card *mmc_find_card(struct mmc_host *host, u32 *raw_cid) |
@@ -789,6 +836,79 @@ static void mmc_read_csds(struct mmc_host *host) | |||
789 | } | 836 | } |
790 | } | 837 | } |
791 | 838 | ||
839 | static void mmc_read_scrs(struct mmc_host *host) | ||
840 | { | ||
841 | int err; | ||
842 | struct mmc_card *card; | ||
843 | |||
844 | struct mmc_request mrq; | ||
845 | struct mmc_command cmd; | ||
846 | struct mmc_data data; | ||
847 | |||
848 | struct scatterlist sg; | ||
849 | |||
850 | list_for_each_entry(card, &host->cards, node) { | ||
851 | if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) | ||
852 | continue; | ||
853 | if (!mmc_card_sd(card)) | ||
854 | continue; | ||
855 | |||
856 | err = mmc_select_card(host, card); | ||
857 | if (err != MMC_ERR_NONE) { | ||
858 | mmc_card_set_dead(card); | ||
859 | continue; | ||
860 | } | ||
861 | |||
862 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
863 | |||
864 | cmd.opcode = MMC_APP_CMD; | ||
865 | cmd.arg = card->rca << 16; | ||
866 | cmd.flags = MMC_RSP_R1; | ||
867 | |||
868 | err = mmc_wait_for_cmd(host, &cmd, 0); | ||
869 | if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) { | ||
870 | mmc_card_set_dead(card); | ||
871 | continue; | ||
872 | } | ||
873 | |||
874 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
875 | |||
876 | cmd.opcode = SD_APP_SEND_SCR; | ||
877 | cmd.arg = 0; | ||
878 | cmd.flags = MMC_RSP_R1; | ||
879 | |||
880 | memset(&data, 0, sizeof(struct mmc_data)); | ||
881 | |||
882 | data.timeout_ns = card->csd.tacc_ns * 10; | ||
883 | data.timeout_clks = card->csd.tacc_clks * 10; | ||
884 | data.blksz_bits = 3; | ||
885 | data.blocks = 1; | ||
886 | data.flags = MMC_DATA_READ; | ||
887 | data.sg = &sg; | ||
888 | data.sg_len = 1; | ||
889 | |||
890 | memset(&mrq, 0, sizeof(struct mmc_request)); | ||
891 | |||
892 | mrq.cmd = &cmd; | ||
893 | mrq.data = &data; | ||
894 | |||
895 | sg_init_one(&sg, (u8*)card->raw_scr, 8); | ||
896 | |||
897 | err = mmc_wait_for_req(host, &mrq); | ||
898 | if (err != MMC_ERR_NONE) { | ||
899 | mmc_card_set_dead(card); | ||
900 | continue; | ||
901 | } | ||
902 | |||
903 | card->raw_scr[0] = ntohl(card->raw_scr[0]); | ||
904 | card->raw_scr[1] = ntohl(card->raw_scr[1]); | ||
905 | |||
906 | mmc_decode_scr(card); | ||
907 | } | ||
908 | |||
909 | mmc_deselect_cards(host); | ||
910 | } | ||
911 | |||
792 | static unsigned int mmc_calculate_clock(struct mmc_host *host) | 912 | static unsigned int mmc_calculate_clock(struct mmc_host *host) |
793 | { | 913 | { |
794 | struct mmc_card *card; | 914 | struct mmc_card *card; |
@@ -912,6 +1032,9 @@ static void mmc_setup(struct mmc_host *host) | |||
912 | host->ops->set_ios(host, &host->ios); | 1032 | host->ops->set_ios(host, &host->ios); |
913 | 1033 | ||
914 | mmc_read_csds(host); | 1034 | mmc_read_csds(host); |
1035 | |||
1036 | if (host->mode == MMC_MODE_SD) | ||
1037 | mmc_read_scrs(host); | ||
915 | } | 1038 | } |
916 | 1039 | ||
917 | 1040 | ||