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 *,