diff options
author | Jonathan Gray <jsg@cvs.openbsd.org> | 2009-01-09 10:55:23 +0000 |
---|---|---|
committer | Jonathan Gray <jsg@cvs.openbsd.org> | 2009-01-09 10:55:23 +0000 |
commit | 3ccd7f6b73bfcccf9df669950532f368f1a54e25 (patch) | |
tree | af86313d7112b6ba3e800446c1dfe68c35fd5ff6 /sys/dev/sdmmc | |
parent | ad17c2f6b18a6a88b72b1c98178defc52f8d5aed (diff) |
Add support for SDHC cards on SDHC capable host controllers.
Thanks to everyone who tested in particular jsing@ who found several
problems in the initial diffs.
ok dlg@ jsing@ miod@
Diffstat (limited to 'sys/dev/sdmmc')
-rw-r--r-- | sys/dev/sdmmc/sdmmc.c | 28 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmc_mem.c | 30 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmcreg.h | 10 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmcvar.h | 5 |
4 files changed, 64 insertions, 9 deletions
diff --git a/sys/dev/sdmmc/sdmmc.c b/sys/dev/sdmmc/sdmmc.c index 60edbb6f43b..891f227090e 100644 --- a/sys/dev/sdmmc/sdmmc.c +++ b/sys/dev/sdmmc/sdmmc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmc.c,v 1.16 2008/12/02 23:49:54 deraadt Exp $ */ +/* $OpenBSD: sdmmc.c,v 1.17 2009/01/09 10:55:22 jsg Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -569,6 +569,32 @@ sdmmc_go_idle_state(struct sdmmc_softc *sc) } /* + * Send the "SEND_IF_COND" command, to check operating condition + */ +int +sdmmc_send_if_cond(struct sdmmc_softc *sc, uint32_t card_ocr) +{ + struct sdmmc_command cmd; + uint8_t pat = 0x23; + uint8_t res; + + bzero(&cmd, sizeof cmd); + + cmd.c_opcode = SD_SEND_IF_COND; + cmd.c_arg = ((card_ocr & SD_OCR_VOL_MASK) != 0) << 8 | pat; + cmd.c_flags = SCF_CMD_BCR | SCF_RSP_R7; + + if (sdmmc_mmc_command(sc, &cmd) != 0) + return 1; + + res = cmd.c_resp[0]; + if (res != pat) + return 1; + else + return 0; +} + +/* * Retrieve (SD) or set (MMC) the relative card address (RCA). */ int diff --git a/sys/dev/sdmmc/sdmmc_mem.c b/sys/dev/sdmmc/sdmmc_mem.c index 8beda36b6fb..4f7246afa07 100644 --- a/sys/dev/sdmmc/sdmmc_mem.c +++ b/sys/dev/sdmmc/sdmmc_mem.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmc_mem.c,v 1.9 2008/12/02 23:49:54 deraadt Exp $ */ +/* $OpenBSD: sdmmc_mem.c,v 1.10 2009/01/09 10:55:22 jsg Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -93,6 +93,9 @@ sdmmc_mem_enable(struct sdmmc_softc *sc) /* Tell the card(s) to enter the idle state (again). */ sdmmc_go_idle_state(sc); + if (sdmmc_send_if_cond(sc, card_ocr) == 0) + host_ocr |= SD_OCR_SDHC_CAP; + /* Send the new OCR value until all cards are ready. */ if (sdmmc_mem_send_op_cond(sc, host_ocr, NULL) != 0) { DPRINTF(("%s: can't send memory OCR\n", SDMMCDEVNAME(sc))); @@ -224,14 +227,23 @@ sdmmc_decode_csd(struct sdmmc_softc *sc, sdmmc_response resp, * specification version 1.0 - 1.10. (SanDisk, 3.5.3) */ csd->csdver = SD_CSD_CSDVER(resp); - if (csd->csdver != SD_CSD_CSDVER_1_0) { + switch (csd->csdver) { + case SD_CSD_CSDVER_2_0: + sf->flags |= SFF_SDHC; + csd->capacity = SD_CSD_V2_CAPACITY(resp); + csd->read_bl_len = SD_CSD_V2_BL_LEN; + break; + case SD_CSD_CSDVER_1_0: + csd->capacity = SD_CSD_CAPACITY(resp); + csd->read_bl_len = SD_CSD_READ_BL_LEN(resp); + break; + default: printf("%s: unknown SD CSD structure version 0x%x\n", SDMMCDEVNAME(sc), csd->csdver); return 1; + break; } - csd->capacity = SD_CSD_CAPACITY(resp); - csd->read_bl_len = SD_CSD_READ_BL_LEN(resp); } else { csd->csdver = MMC_CSD_CSDVER(resp); if (csd->csdver != MMC_CSD_CSDVER_1_0 && @@ -403,7 +415,10 @@ sdmmc_mem_read_block(struct sdmmc_function *sf, int blkno, u_char *data, cmd.c_blklen = sf->csd.sector_size; cmd.c_opcode = (datalen / cmd.c_blklen) > 1 ? MMC_READ_BLOCK_MULTIPLE : MMC_READ_BLOCK_SINGLE; - cmd.c_arg = blkno << 9; + if (sf->flags & SFF_SDHC) + cmd.c_arg = blkno; + else + cmd.c_arg = blkno << 9; cmd.c_flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1; error = sdmmc_mmc_command(sc, &cmd); @@ -458,7 +473,10 @@ sdmmc_mem_write_block(struct sdmmc_function *sf, int blkno, u_char *data, cmd.c_blklen = sf->csd.sector_size; cmd.c_opcode = (datalen / cmd.c_blklen) > 1 ? MMC_WRITE_BLOCK_MULTIPLE : MMC_WRITE_BLOCK_SINGLE; - cmd.c_arg = blkno << 9; + if (sf->flags & SFF_SDHC) + cmd.c_arg = blkno; + else + cmd.c_arg = blkno << 9; cmd.c_flags = SCF_CMD_ADTC | SCF_RSP_R1; error = sdmmc_mmc_command(sc, &cmd); diff --git a/sys/dev/sdmmc/sdmmcreg.h b/sys/dev/sdmmc/sdmmcreg.h index ed060656b43..9b182deb5f8 100644 --- a/sys/dev/sdmmc/sdmmcreg.h +++ b/sys/dev/sdmmc/sdmmcreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmcreg.h,v 1.3 2007/03/18 22:21:21 uwe Exp $ */ +/* $OpenBSD: sdmmcreg.h,v 1.4 2009/01/09 10:55:22 jsg Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -38,6 +38,7 @@ /* SD commands */ /* response type */ #define SD_SEND_RELATIVE_ADDR 3 /* R6 */ +#define SD_SEND_IF_COND 8 /* R7 */ /* SD application commands */ /* response type */ #define SD_APP_SET_BUS_WIDTH 6 /* R1 */ @@ -66,6 +67,9 @@ #define MMC_OCR_1_7V_1_8V (1<<5) #define MMC_OCR_1_6V_1_7V (1<<4) +#define SD_OCR_SDHC_CAP (1<<30) +#define SD_OCR_VOL_MASK 0xFF8000 /* bits 23:15 */ + /* R1 response type bits */ #define MMC_R1_READY_FOR_DATA (1<<8) /* ready for next transfer */ #define MMC_R1_APP_CMD (1<<5) /* app. commands supported */ @@ -134,6 +138,7 @@ /* SD R2 response (CSD) */ #define SD_CSD_CSDVER(resp) MMC_RSP_BITS((resp), 126, 2) #define SD_CSD_CSDVER_1_0 0 +#define SD_CSD_CSDVER_2_0 1 #define SD_CSD_TAAC(resp) MMC_RSP_BITS((resp), 112, 8) #define SD_CSD_TAAC_1_5_MSEC 0x26 #define SD_CSD_NSAC(resp) MMC_RSP_BITS((resp), 104, 8) @@ -150,6 +155,9 @@ #define SD_CSD_C_SIZE(resp) MMC_RSP_BITS((resp), 62, 12) #define SD_CSD_CAPACITY(resp) ((SD_CSD_C_SIZE((resp))+1) << \ (SD_CSD_C_SIZE_MULT((resp))+2)) +#define SD_CSD_V2_C_SIZE(resp) MMC_RSP_BITS((resp), 48, 22) +#define SD_CSD_V2_CAPACITY(resp) ((SD_CSD_V2_C_SIZE((resp))+1) << 10) +#define SD_CSD_V2_BL_LEN 0x9 /* 512 */ #define SD_CSD_VDD_R_CURR_MIN(resp) MMC_RSP_BITS((resp), 59, 3) #define SD_CSD_VDD_R_CURR_MAX(resp) MMC_RSP_BITS((resp), 56, 3) #define SD_CSD_VDD_W_CURR_MIN(resp) MMC_RSP_BITS((resp), 53, 3) diff --git a/sys/dev/sdmmc/sdmmcvar.h b/sys/dev/sdmmc/sdmmcvar.h index e2016e7fda3..4570e9377a0 100644 --- a/sys/dev/sdmmc/sdmmcvar.h +++ b/sys/dev/sdmmc/sdmmcvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmcvar.h,v 1.12 2008/12/02 23:49:54 deraadt Exp $ */ +/* $OpenBSD: sdmmcvar.h,v 1.13 2009/01/09 10:55:22 jsg Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -98,6 +98,7 @@ struct sdmmc_command { #define SCF_RSP_R5 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) #define SCF_RSP_R5B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY) #define SCF_RSP_R6 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) +#define SCF_RSP_R7 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) int c_error; /* errno value on completion */ /* Host controller owned fields for data xfer in progress */ @@ -135,6 +136,7 @@ struct sdmmc_function { u_int16_t rca; /* relative card address */ int flags; #define SFF_ERROR 0x0001 /* function is poo; ignore it */ +#define SFF_SDHC 0x0002 /* SD High Capacity card */ SIMPLEQ_ENTRY(sdmmc_function) sf_list; /* SD card I/O function members */ int number; /* I/O function number or -1 */ @@ -200,6 +202,7 @@ void sdmmc_go_idle_state(struct sdmmc_softc *); int sdmmc_select_card(struct sdmmc_softc *, struct sdmmc_function *); int sdmmc_set_relative_addr(struct sdmmc_softc *, struct sdmmc_function *); +int sdmmc_send_if_cond(struct sdmmc_softc *, uint32_t); void sdmmc_intr_enable(struct sdmmc_function *); void sdmmc_intr_disable(struct sdmmc_function *); |