Module Name: src
Committed By: kiyohara
Date: Thu Oct 7 12:24:23 UTC 2010
Modified Files:
src/sys/dev/sdmmc: sdmmc.c sdmmc_io.c sdmmc_mem.c sdmmcreg.h sdmmcvar.h
Log Message:
Support High-Speed mode.
To generate a diff of this commit:
cvs rdiff -u -r1.4 -r1.5 src/sys/dev/sdmmc/sdmmc.c \
src/sys/dev/sdmmc/sdmmcreg.h
cvs rdiff -u -r1.2 -r1.3 src/sys/dev/sdmmc/sdmmc_io.c
cvs rdiff -u -r1.12 -r1.13 src/sys/dev/sdmmc/sdmmc_mem.c
cvs rdiff -u -r1.7 -r1.8 src/sys/dev/sdmmc/sdmmcvar.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/sdmmc/sdmmc.c
diff -u src/sys/dev/sdmmc/sdmmc.c:1.4 src/sys/dev/sdmmc/sdmmc.c:1.5
--- src/sys/dev/sdmmc/sdmmc.c:1.4 Fri Oct 1 09:50:42 2010
+++ src/sys/dev/sdmmc/sdmmc.c Thu Oct 7 12:24:23 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: sdmmc.c,v 1.4 2010/10/01 09:50:42 kiyohara Exp $ */
+/* $NetBSD: sdmmc.c,v 1.5 2010/10/07 12:24:23 kiyohara Exp $ */
/* $OpenBSD: sdmmc.c,v 1.18 2009/01/09 10:58:38 jsg Exp $ */
/*
@@ -50,7 +50,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sdmmc.c,v 1.4 2010/10/01 09:50:42 kiyohara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdmmc.c,v 1.5 2010/10/07 12:24:23 kiyohara Exp $");
#include <sys/param.h>
#include <sys/device.h>
@@ -369,20 +369,6 @@
goto err;
}
- /*
- * Set SD/MMC bus clock.
- */
-#ifdef SDMMC_DEBUG
- if ((sc->sc_busclk / 1000) != 0) {
- DPRINTF(1,("%s: bus clock: %u.%03u MHz\n", DEVNAME(sc),
- sc->sc_busclk / 1000, sc->sc_busclk % 1000));
- } else {
- DPRINTF(1,("%s: bus clock: %u KHz\n", DEVNAME(sc),
- sc->sc_busclk % 1000));
- }
-#endif
- (void)sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, sc->sc_busclk);
-
SIMPLEQ_FOREACH(sf, &sc->sf_head, sf_list) {
if (ISSET(sc->sc_flags, SMF_IO_MODE) && sf->number < 1)
continue;
Index: src/sys/dev/sdmmc/sdmmcreg.h
diff -u src/sys/dev/sdmmc/sdmmcreg.h:1.4 src/sys/dev/sdmmc/sdmmcreg.h:1.5
--- src/sys/dev/sdmmc/sdmmcreg.h:1.4 Tue Apr 6 15:10:09 2010
+++ src/sys/dev/sdmmc/sdmmcreg.h Thu Oct 7 12:24:23 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: sdmmcreg.h,v 1.4 2010/04/06 15:10:09 nonaka Exp $ */
+/* $NetBSD: sdmmcreg.h,v 1.5 2010/10/07 12:24:23 kiyohara Exp $ */
/* $OpenBSD: sdmmcreg.h,v 1.4 2009/01/09 10:55:22 jsg Exp $ */
/*
@@ -56,6 +56,7 @@
/* SD commands */ /* response type */
#define SD_SEND_RELATIVE_ADDR 3 /* R6 */
+#define SD_SEND_SWITCH_FUNC 6 /* R1 */
#define SD_SEND_IF_COND 8 /* R7 */
/* SD application commands */ /* response type */
@@ -108,7 +109,11 @@
#define SD_ARG_BUS_WIDTH_4 2
/* EXT_CSD fields */
-#define EXT_CSD_BUS_WIDTH 183 /* R/W */
+#define EXT_CSD_BUS_WIDTH 183 /* WO */
+#define EXT_CSD_HS_TIMING 185 /* R/W */
+#define EXT_CSD_REV 192 /* RO */
+#define EXT_CSD_STRUCTURE 194 /* RO */
+#define EXT_CSD_CARD_TYPE 196 /* RO */
/* EXT_CSD field definitions */
#define EXT_CSD_CMD_SET_NORMAL (1U << 0)
@@ -120,6 +125,15 @@
#define EXT_CSD_BUS_WIDTH_4 1 /* 4 bit mode */
#define EXT_CSD_BUS_WIDTH_8 2 /* 8 bit mode */
+/* EXT_CSD_STRUCTURE */
+#define EXT_CSD_STRUCTURE_VER_1_0 0 /* CSD Version No.1.0 */
+#define EXT_CSD_STRUCTURE_VER_1_1 1 /* CSD Version No.1.1 */
+#define EXT_CSD_STRUCTURE_VER_1_2 2 /* Version 4.1-4.2-4.3 */
+
+/* EXT_CSD_CARD_TYPE */
+#define EXT_CSD_CARD_TYPE_26M (1 << 0)
+#define EXT_CSD_CARD_TYPE_52M (1 << 1)
+
/* MMC_SWITCH access mode */
#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */
#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits in value */
@@ -219,7 +233,15 @@
#define SD_CSD_SPEED_25_MHZ 0x32
#define SD_CSD_SPEED_50_MHZ 0x5a
#define SD_CSD_CCC(resp) MMC_RSP_BITS((resp), 84, 12)
-#define SD_CSD_CCC_ALL 0x5f5
+#define SD_CSD_CCC_BASIC (1 << 0) /* basic */
+#define SD_CSD_CCC_BR (1 << 2) /* block read */
+#define SD_CSD_CCC_BW (1 << 4) /* block write */
+#define SD_CSD_CCC_ERACE (1 << 5) /* erase */
+#define SD_CSD_CCC_WP (1 << 6) /* write protection */
+#define SD_CSD_CCC_LC (1 << 7) /* lock card */
+#define SD_CSD_CCC_AS (1 << 8) /*application specific*/
+#define SD_CSD_CCC_IOM (1 << 9) /* I/O mode */
+#define SD_CSD_CCC_SWITCH (1 << 10) /* switch */
#define SD_CSD_READ_BL_LEN(resp) MMC_RSP_BITS((resp), 80, 4)
#define SD_CSD_READ_BL_PARTIAL(resp) MMC_RSP_BITS((resp), 79, 1)
#define SD_CSD_WRITE_BLK_MISALIGN(resp) MMC_RSP_BITS((resp), 78, 1)
@@ -273,7 +295,9 @@
#define SCR_STRUCTURE(scr) MMC_RSP_BITS((scr), 60, 4)
#define SCR_STRUCTURE_VER_1_0 0 /* Version 1.0 */
#define SCR_SD_SPEC(scr) MMC_RSP_BITS((scr), 56, 4)
-#define SCR_SD_SPEC_VER_1_0 0 /* Version 1.0 */
+#define SCR_SD_SPEC_VER_1_0 0 /* Version 1.0 and 1.01 */
+#define SCR_SD_SPEC_VER_1_10 1 /* Version 1.10 */
+#define SCR_SD_SPEC_VER_2 2 /* Version 2.00 or Version 3.0X */
#define SCR_DATA_STAT_AFTER_ERASE(scr) MMC_RSP_BITS((scr), 55, 1)
#define SCR_SD_SECURITY(scr) MMC_RSP_BITS((scr), 52, 3)
#define SCR_SD_SECURITY_NONE 0 /* no security */
@@ -285,6 +309,10 @@
#define SCR_RESERVED(scr) MMC_RSP_BITS((scr), 32, 16)
#define SCR_RESERVED2(scr) MMC_RSP_BITS((scr), 0, 32)
+/* Status of Switch Function */
+#define SFUNC_STATUS_GROUP(status, group) \
+ be16toh(__bitfield((uint32_t *)(status), (7 - (group)) << 4, 16))
+
/* Might be slow, but it should work on big and little endian systems. */
#define MMC_RSP_BITS(resp, start, len) __bitfield((resp), (start)-8, (len))
static inline int
Index: src/sys/dev/sdmmc/sdmmc_io.c
diff -u src/sys/dev/sdmmc/sdmmc_io.c:1.2 src/sys/dev/sdmmc/sdmmc_io.c:1.3
--- src/sys/dev/sdmmc/sdmmc_io.c:1.2 Sat Dec 5 22:34:43 2009
+++ src/sys/dev/sdmmc/sdmmc_io.c Thu Oct 7 12:24:23 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: sdmmc_io.c,v 1.2 2009/12/05 22:34:43 pooka Exp $ */
+/* $NetBSD: sdmmc_io.c,v 1.3 2010/10/07 12:24:23 kiyohara Exp $ */
/* $OpenBSD: sdmmc_io.c,v 1.10 2007/09/17 01:33:33 krw Exp $ */
/*
@@ -20,7 +20,7 @@
/* Routines for SD I/O cards. */
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sdmmc_io.c,v 1.2 2009/12/05 22:34:43 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdmmc_io.c,v 1.3 2010/10/07 12:24:23 kiyohara Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
@@ -158,6 +158,9 @@
sc->sc_fn0 = sf0;
SIMPLEQ_INSERT_TAIL(&sc->sf_head, sf0, sf_list);
+ /* Go to Data Transfer Mode, if possible. */
+ sdmmc_chip_bus_rod(sc->sc_sct, sc->sc_sch, 0);
+
/* Verify that the RCA has been set by selecting the card. */
error = sdmmc_select_card(sc, sf0);
if (error) {
@@ -204,6 +207,14 @@
if (sdmmcdebug)
sdmmc_print_cis(sf);
#endif
+
+ if (sc->sc_busclk > sf->csd.tran_speed)
+ sc->sc_busclk = sf->csd.tran_speed;
+ error =
+ sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, sc->sc_busclk);
+ if (error)
+ aprint_error_dev(sc->sc_dev,
+ "can't change bus clock\n");
}
out:
Index: src/sys/dev/sdmmc/sdmmc_mem.c
diff -u src/sys/dev/sdmmc/sdmmc_mem.c:1.12 src/sys/dev/sdmmc/sdmmc_mem.c:1.13
--- src/sys/dev/sdmmc/sdmmc_mem.c:1.12 Fri Oct 1 09:50:42 2010
+++ src/sys/dev/sdmmc/sdmmc_mem.c Thu Oct 7 12:24:23 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: sdmmc_mem.c,v 1.12 2010/10/01 09:50:42 kiyohara Exp $ */
+/* $NetBSD: sdmmc_mem.c,v 1.13 2010/10/07 12:24:23 kiyohara Exp $ */
/* $OpenBSD: sdmmc_mem.c,v 1.10 2009/01/09 10:55:22 jsg Exp $ */
/*
@@ -46,7 +46,7 @@
/* Routines for SD/MMC memory cards. */
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.12 2010/10/01 09:50:42 kiyohara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.13 2010/10/07 12:24:23 kiyohara Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
@@ -66,6 +66,8 @@
#define DPRINTF(s) do {} while (/*CONSTCOND*/0)
#endif
+static int sdmmc_mem_sd_init(struct sdmmc_softc *, struct sdmmc_function *);
+static int sdmmc_mem_mmc_init(struct sdmmc_softc *, struct sdmmc_function *);
static int sdmmc_mem_send_cid(struct sdmmc_softc *, sdmmc_response *);
static int sdmmc_mem_send_csd(struct sdmmc_softc *, struct sdmmc_function *,
sdmmc_response *);
@@ -74,6 +76,7 @@
static int sdmmc_mem_decode_scr(struct sdmmc_softc *, struct sdmmc_function *);
static int sdmmc_mem_send_cxd_data(struct sdmmc_softc *, int, void *, size_t);
static int sdmmc_set_bus_width(struct sdmmc_function *, int);
+static int sdmmc_mem_sd_switch(struct sdmmc_function *, int, int, int, void *);
static int sdmmc_mem_mmc_switch(struct sdmmc_function *, uint8_t, uint8_t,
uint8_t);
static int sdmmc_mem_spi_read_ocr(struct sdmmc_softc *, uint32_t, uint32_t *);
@@ -253,6 +256,10 @@
break;
}
+ if (!ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE))
+ /* Go to Data Transfer Mode, if possible. */
+ sdmmc_chip_bus_rod(sc->sc_sct, sc->sc_sch, 0);
+
/*
* All cards are either inactive or awaiting further commands.
* Read the CSDs and decode the raw CID for each card.
@@ -313,6 +320,7 @@
SET(sf->flags, SFF_SDHC);
csd->capacity = SD_CSD_V2_CAPACITY(resp);
csd->read_bl_len = SD_CSD_V2_BL_LEN;
+ csd->ccc = SD_CSD_CCC(resp);
break;
case SD_CSD_CSDVER_1_0:
@@ -356,9 +364,6 @@
if ((1 << csd->read_bl_len) > SDMMC_SECTOR_SIZE)
csd->capacity *= (1 << csd->read_bl_len) / SDMMC_SECTOR_SIZE;
- if (sc->sc_busclk > csd->tran_speed)
- sc->sc_busclk = csd->tran_speed;
-
#ifdef SDMMC_DUMP_CSD
sdmmc_print_csd(resp, csd);
#endif
@@ -436,7 +441,7 @@
int
sdmmc_mem_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
{
- int width, value, error = 0;
+ int error = 0;
SDMMC_LOCK(sc);
@@ -452,58 +457,10 @@
goto out;
}
- /* change bus width if supported */
- sf->width = 1;
- if (ISSET(sc->sc_flags, SMF_SD_MODE)) {
- error = sdmmc_mem_send_scr(sc, sf, sf->raw_scr);
- if (error) {
- DPRINTF(("%s: SD_SEND_SCR send failed.\n",
- SDMMCDEVNAME(sc)));
- goto out;
- }
- error = sdmmc_mem_decode_scr(sc, sf);
- if (error)
- goto out;
-
- if (ISSET(sc->sc_caps, SMC_CAPS_4BIT_MODE) &&
- ISSET(sf->scr.bus_width, SCR_SD_BUS_WIDTHS_4BIT)) {
- error = sdmmc_set_bus_width(sf, 4);
- if (error) {
- DPRINTF(("%s: can't change bus width"
- " (%d bit)\n", SDMMCDEVNAME(sc), 4));
- goto out;
- }
- sf->width = 4;
- }
- } else if (sf->csd.mmcver >= MMC_CSD_MMCVER_4_0) {
- if (ISSET(sc->sc_caps, SMC_CAPS_8BIT_MODE)) {
- width = 8;
- value = EXT_CSD_BUS_WIDTH_8;
- } else if (ISSET(sc->sc_caps, SMC_CAPS_4BIT_MODE)) {
- width = 4;
- value = EXT_CSD_BUS_WIDTH_4;
- } else {
- width = 1;
- value = EXT_CSD_BUS_WIDTH_1;
- }
-
- if (width != 1) {
- error = sdmmc_mem_mmc_switch(sf, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_BUS_WIDTH, value);
- if (error == 0)
- error = sdmmc_chip_bus_width(sc->sc_sct,
- sc->sc_sch, width);
- else {
- DPRINTF(("%s: can't change bus width"
- " (%d bit)\n", SDMMCDEVNAME(sc), width));
- goto out;
- }
-
- /* XXXX: need bus test? (using by CMD14 & CMD19) */
-
- sf->width = width;
- }
- }
+ if (ISSET(sc->sc_flags, SMF_SD_MODE))
+ error = sdmmc_mem_sd_init(sc, sf);
+ else
+ error = sdmmc_mem_mmc_init(sc, sf);
out:
SDMMC_UNLOCK(sc);
@@ -617,6 +574,215 @@
}
static int
+sdmmc_mem_sd_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
+{
+ struct {
+ int v;
+ int freq;
+ } switch_group0_functions [] = {
+ /* Default/SDR12 */
+ { MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V |
+ MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V, 25000 },
+
+ /* High-Speed/SDR25 */
+ { MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V |
+ MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V, 50000 },
+
+ /* SDR50 */
+ { MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V, 100000 },
+
+ /* SDR104 */
+ { MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V, 208000 },
+
+ /* DDR50 */
+ { MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V, 50000 },
+ };
+ int host_ocr, support_func, best_func, error, g, i;
+ char status[64];
+
+ error = sdmmc_mem_send_scr(sc, sf, sf->raw_scr);
+ if (error) {
+ aprint_error_dev(sc->sc_dev, "SD_SEND_SCR send failed.\n");
+ return error;
+ }
+ error = sdmmc_mem_decode_scr(sc, sf);
+ if (error)
+ return error;
+
+ if (ISSET(sc->sc_caps, SMC_CAPS_4BIT_MODE) &&
+ ISSET(sf->scr.bus_width, SCR_SD_BUS_WIDTHS_4BIT)) {
+ error = sdmmc_set_bus_width(sf, 4);
+ if (error) {
+ aprint_error_dev(sc->sc_dev,
+ "can't change bus width (%d bit)\n", 4);
+ return error;
+ }
+ sf->width = 4;
+ } else
+ sf->width = 1;
+
+ if (sf->scr.sd_spec >= SCR_SD_SPEC_VER_1_10 &&
+ ISSET(sf->csd.ccc, SD_CSD_CCC_SWITCH)) {
+ error = sdmmc_mem_sd_switch(sf, 0, 1, 0, status);
+ if (error) {
+ aprint_error_dev(sc->sc_dev,
+ "switch func mode 0 failed\n");
+ return error;
+ }
+
+ host_ocr = sdmmc_chip_host_ocr(sc->sc_sct, sc->sc_sch);
+ support_func = SFUNC_STATUS_GROUP(status, 1);
+ best_func = 0;
+ for (i = 0, g = 1;
+ i < __arraycount(switch_group0_functions); i++, g <<= 1) {
+ if (!(switch_group0_functions[i].v & host_ocr))
+ continue;
+ if (g & support_func)
+ best_func = i;
+ }
+ if (best_func != 0) {
+ error =
+ sdmmc_mem_sd_switch(sf, 1, 1, best_func, status);
+ if (error) {
+ aprint_error_dev(sc->sc_dev,
+ "switch func mode 1 failed:"
+ " group 1 function %d(0x%2x)\n",
+ best_func, support_func);
+ return error;
+ }
+ sf->csd.tran_speed =
+ switch_group0_functions[best_func].freq;
+
+ /* Wait 400KHz x 8 clock */
+ delay(1);
+ if (sc->sc_busclk > sf->csd.tran_speed)
+ sc->sc_busclk = sf->csd.tran_speed;
+
+ error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch,
+ sc->sc_busclk);
+ if (error) {
+ aprint_error_dev(sc->sc_dev,
+ "can't change bus clock\n");
+ return error;
+ }
+ } else
+ if (sc->sc_busclk > sf->csd.tran_speed)
+ sc->sc_busclk = sf->csd.tran_speed;
+ }
+
+ return 0;
+}
+
+static int
+sdmmc_mem_mmc_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
+{
+ int width, value, hs_timing, error;
+ char ext_csd[512];
+
+ if (sf->csd.mmcver >= MMC_CSD_MMCVER_4_0) {
+ error = sdmmc_mem_send_cxd_data(sc,
+ MMC_SEND_EXT_CSD, ext_csd, sizeof(ext_csd));
+ if (error) {
+ aprint_error_dev(sc->sc_dev, "can't read EXT_CSD\n");
+ return error;
+ }
+ if (ext_csd[EXT_CSD_STRUCTURE] > EXT_CSD_STRUCTURE_VER_1_2) {
+ aprint_error_dev(sc->sc_dev,
+ "unrecognised future version\n");
+ return error;
+ }
+ hs_timing = 0;
+ switch (ext_csd[EXT_CSD_CARD_TYPE]) {
+ case EXT_CSD_CARD_TYPE_26M:
+ sf->csd.tran_speed = 26000; /* 26MHz */
+ break;
+
+ case EXT_CSD_CARD_TYPE_52M | EXT_CSD_CARD_TYPE_26M:
+ sf->csd.tran_speed = 52000; /* 52MHz */
+ hs_timing = 1;
+
+ error = sdmmc_mem_mmc_switch(sf, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_HS_TIMING, hs_timing);
+ if (error) {
+ aprint_error_dev(sc->sc_dev,
+ "can't change high speed\n");
+ return error;
+ }
+ break;
+
+ default:
+ aprint_error_dev(sc->sc_dev,
+ "unknwon CARD_TYPE: 0x%x\n",
+ ext_csd[EXT_CSD_CARD_TYPE]);
+ return error;
+ }
+ if (sc->sc_busclk > sf->csd.tran_speed)
+ sc->sc_busclk = sf->csd.tran_speed;
+ error =
+ sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, sc->sc_busclk);
+ if (error) {
+ aprint_error_dev(sc->sc_dev,
+ "can't change bus clock\n");
+ return error;
+ }
+ if (hs_timing) {
+ error = sdmmc_mem_send_cxd_data(sc,
+ MMC_SEND_EXT_CSD, ext_csd, sizeof(ext_csd));
+ if (error) {
+ aprint_error_dev(sc->sc_dev,
+ "can't re-read EXT_CSD\n");
+ return error;
+ }
+ if (ext_csd[EXT_CSD_HS_TIMING] != hs_timing) {
+ aprint_error_dev(sc->sc_dev,
+ "HS_TIMING set failed\n");
+ return EINVAL;
+ }
+ }
+
+ if (ISSET(sc->sc_caps, SMC_CAPS_8BIT_MODE)) {
+ width = 8;
+ value = EXT_CSD_BUS_WIDTH_8;
+ } else if (ISSET(sc->sc_caps, SMC_CAPS_4BIT_MODE)) {
+ width = 4;
+ value = EXT_CSD_BUS_WIDTH_4;
+ } else {
+ width = 1;
+ value = EXT_CSD_BUS_WIDTH_1;
+ }
+
+ if (width != 1) {
+ error = sdmmc_mem_mmc_switch(sf, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BUS_WIDTH, value);
+ if (error == 0)
+ error = sdmmc_chip_bus_width(sc->sc_sct,
+ sc->sc_sch, width);
+ else {
+ DPRINTF(("%s: can't change bus width"
+ " (%d bit)\n", SDMMCDEVNAME(sc), width));
+ return error;
+ }
+
+ /* XXXX: need bus test? (using by CMD14 & CMD19) */
+ }
+ sf->width = width;
+ } else {
+ if (sc->sc_busclk > sf->csd.tran_speed)
+ sc->sc_busclk = sf->csd.tran_speed;
+ error =
+ sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, sc->sc_busclk);
+ if (error) {
+ aprint_error_dev(sc->sc_dev,
+ "can't change bus clock\n");
+ return error;
+ }
+ sf->width = 1;
+ }
+
+ return 0;
+}
+
+static int
sdmmc_mem_send_cid(struct sdmmc_softc *sc, sdmmc_response *resp)
{
struct sdmmc_command cmd;
@@ -842,19 +1008,6 @@
return error;
}
-int
-sdmmc_mem_send_extcsd(struct sdmmc_softc *sc)
-{
- char buf[512];
- int error;
-
- error = sdmmc_mem_send_cxd_data(sc, MMC_SEND_EXT_CSD, buf, 512);
-
- /*XXX*/
-
- return error;
-}
-
static int
sdmmc_set_bus_width(struct sdmmc_function *sf, int width)
{
@@ -889,6 +1042,84 @@
}
static int
+sdmmc_mem_sd_switch(struct sdmmc_function *sf, int mode, int group,
+ int function, void *status)
+{
+ struct sdmmc_softc *sc = sf->sc;
+ struct sdmmc_command cmd;
+ bus_dma_segment_t ds[1];
+ void *ptr = NULL;
+ int gsft, rseg, error = 0;
+ const int statlen = 64;
+
+ if (sf->scr.sd_spec >= SCR_SD_SPEC_VER_1_10 &&
+ !ISSET(sf->csd.ccc, SD_CSD_CCC_SWITCH))
+ return EINVAL;
+
+ if (group <= 0 || group > 6 ||
+ function < 0 || function > 16)
+ return EINVAL;
+
+ gsft = (group - 1) << 2;
+
+ if (ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
+ error = bus_dmamem_alloc(sc->sc_dmat, statlen, PAGE_SIZE, 0, ds,
+ 1, &rseg, BUS_DMA_NOWAIT);
+ if (error)
+ goto out;
+ error = bus_dmamem_map(sc->sc_dmat, ds, 1, statlen, &ptr,
+ BUS_DMA_NOWAIT);
+ if (error)
+ goto dmamem_free;
+ error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmap, ptr, statlen,
+ NULL, BUS_DMA_NOWAIT|BUS_DMA_STREAMING|BUS_DMA_READ);
+ if (error)
+ goto dmamem_unmap;
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, statlen,
+ BUS_DMASYNC_PREREAD);
+ } else {
+ ptr = malloc(statlen, M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (ptr == NULL)
+ goto out;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.c_data = ptr;
+ cmd.c_datalen = statlen;
+ cmd.c_blklen = statlen;
+ cmd.c_opcode = SD_SEND_SWITCH_FUNC;
+ cmd.c_arg =
+ (!!mode << 31) | (function << gsft) | (0x00ffffff & ~(0xf << gsft));
+ cmd.c_flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1 | SCF_RSP_SPI_R1;
+ if (ISSET(sc->sc_caps, SMC_CAPS_DMA))
+ cmd.c_dmamap = sc->sc_dmap;
+
+ error = sdmmc_mmc_command(sc, &cmd);
+ if (error == 0) {
+ if (ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, statlen,
+ BUS_DMASYNC_POSTREAD);
+ }
+ memcpy(status, ptr, statlen);
+ }
+
+out:
+ if (ptr != NULL) {
+ if (ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
+ bus_dmamap_unload(sc->sc_dmat, sc->sc_dmap);
+dmamem_unmap:
+ bus_dmamem_unmap(sc->sc_dmat, ptr, statlen);
+dmamem_free:
+ bus_dmamem_free(sc->sc_dmat, ds, rseg);
+ } else {
+ free(ptr, M_DEVBUF);
+ }
+ }
+ return error;
+}
+
+static int
sdmmc_mem_mmc_switch(struct sdmmc_function *sf, uint8_t set, uint8_t index,
uint8_t value)
{
Index: src/sys/dev/sdmmc/sdmmcvar.h
diff -u src/sys/dev/sdmmc/sdmmcvar.h:1.7 src/sys/dev/sdmmc/sdmmcvar.h:1.8
--- src/sys/dev/sdmmc/sdmmcvar.h:1.7 Fri Oct 1 09:50:42 2010
+++ src/sys/dev/sdmmc/sdmmcvar.h Thu Oct 7 12:24:23 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: sdmmcvar.h,v 1.7 2010/10/01 09:50:42 kiyohara Exp $ */
+/* $NetBSD: sdmmcvar.h,v 1.8 2010/10/07 12:24:23 kiyohara Exp $ */
/* $OpenBSD: sdmmcvar.h,v 1.13 2009/01/09 10:55:22 jsg Exp $ */
/*
@@ -40,6 +40,7 @@
int write_bl_len; /* block length for writes */
int r2w_factor;
int tran_speed; /* transfer speed (kbit/s) */
+ int ccc; /* Card Command Class for SD */
/* ... */
};
@@ -163,6 +164,7 @@
/* common members */
struct sdmmc_softc *sc; /* card slot softc */
uint16_t rca; /* relative card address */
+ int interface; /* SD/MMC:0, SDIO:standard interface */
int width; /* bus width */
int flags;
#define SFF_ERROR 0x0001 /* function is poo; ignore it */
@@ -178,6 +180,7 @@
sdmmc_response raw_cid; /* temp. storage for decoding */
uint32_t raw_scr[2];
struct sdmmc_scr scr; /* decoded CSR value */
+
void *bbuf; /* bounce buffer */
bus_dmamap_t bbuf_dmap; /* DMA map for bounce buffer */
};
@@ -252,6 +255,7 @@
struct sdmmc_attach_args {
uint16_t manufacturer;
uint16_t product;
+ int interface;
struct sdmmc_function *sf;
};
@@ -329,7 +333,6 @@
int sdmmc_mem_send_op_cond(struct sdmmc_softc *, uint32_t, uint32_t *);
int sdmmc_mem_send_if_cond(struct sdmmc_softc *, uint32_t, uint32_t *);
int sdmmc_mem_set_blocklen(struct sdmmc_softc *, struct sdmmc_function *);
-int sdmmc_mem_send_extcsd(struct sdmmc_softc *sc);
int sdmmc_mem_read_block(struct sdmmc_function *, uint32_t, u_char *,
size_t);
int sdmmc_mem_write_block(struct sdmmc_function *, uint32_t, u_char *,