summaryrefslogtreecommitdiff
path: root/sys/dev/sdmmc
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2009-01-09 10:55:23 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2009-01-09 10:55:23 +0000
commit3ccd7f6b73bfcccf9df669950532f368f1a54e25 (patch)
treeaf86313d7112b6ba3e800446c1dfe68c35fd5ff6 /sys/dev/sdmmc
parentad17c2f6b18a6a88b72b1c98178defc52f8d5aed (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.c28
-rw-r--r--sys/dev/sdmmc/sdmmc_mem.c30
-rw-r--r--sys/dev/sdmmc/sdmmcreg.h10
-rw-r--r--sys/dev/sdmmc/sdmmcvar.h5
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 *);