Current-Users archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
sdmmc(4) High-Speed support
Hi! all,
I support high-speed for sdmmc(4).
It test on Marvell Sheevaplug only. Sheevaplug supports 3.3V 50MHz.
In a word not test over 50MHz... ;-)
And, this will work for mvsdio and sdhc@pci now.
My microSD card:
ld0 at sdmmc0: <SU04G>
ld0: 3781 MB, 1920 cyl, 64 head, 63 sec, 512 bytes/sect x 7744512 sectors
ld0: 4-bit width, bus clock 50.000 MHz
# dd if=/dev/rld0c of=/dev/null bs=1m
result:
1. 3965190144 bytes transferred in 637.395 secs (6220930 bytes/sec)
2. 3965190144 bytes transferred in 215.435 secs (18405505 bytes/sec)
3. 3965190144 bytes transferred in 636.993 secs (6224856 bytes/sec)
4. 3965190144 bytes transferred in 215.857 secs (18369523 bytes/sec)
5. 3965190144 bytes transferred in 639.168 secs (6203674 bytes/sec)
We have the possibility of using the bounce buffer. X-<
And, it is slower to write.
Thanks,
--
kiyohara
Index: arch/arm/xscale/pxa2x0_mci.c
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/xscale/pxa2x0_mci.c,v
retrieving revision 1.6
diff -u -r1.6 pxa2x0_mci.c
--- arch/arm/xscale/pxa2x0_mci.c 1 Oct 2010 09:54:56 -0000 1.6
+++ arch/arm/xscale/pxa2x0_mci.c 1 Oct 2010 13:24:35 -0000
@@ -101,6 +101,7 @@
static int pxamci_bus_power(sdmmc_chipset_handle_t, uint32_t);
static int pxamci_bus_clock(sdmmc_chipset_handle_t, int);
static int pxamci_bus_width(sdmmc_chipset_handle_t, int);
+static int pxamci_bus_rod(sdmmc_chipset_handle_t, int);
static void pxamci_exec_command(sdmmc_chipset_handle_t,
struct sdmmc_command *);
static void pxamci_card_enable_intr(sdmmc_chipset_handle_t, int);
@@ -124,6 +125,7 @@
.bus_power = pxamci_bus_power,
.bus_clock = pxamci_bus_clock,
.bus_width = pxamci_bus_width,
+ .bus_rod = pxamci_bus_rod,
/* command execution */
.exec_command = pxamci_exec_command,
@@ -548,6 +550,14 @@
return rv;
}
+static int
+pxamci_bus_rod(sdmmc_chipset_handle_t sch, int on)
+{
+
+ /* not support */
+ return -1;
+}
+
static void
pxamci_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
{
Index: dev/ic/w83l518d_sdmmc.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/w83l518d_sdmmc.c,v
retrieving revision 1.2
diff -u -r1.2 w83l518d_sdmmc.c
--- dev/ic/w83l518d_sdmmc.c 19 Aug 2010 14:58:22 -0000 1.2
+++ dev/ic/w83l518d_sdmmc.c 1 Oct 2010 13:24:44 -0000
@@ -75,6 +75,7 @@
static int wb_sdmmc_bus_power(sdmmc_chipset_handle_t, uint32_t);
static int wb_sdmmc_bus_clock(sdmmc_chipset_handle_t, int);
static int wb_sdmmc_bus_width(sdmmc_chipset_handle_t, int);
+static int wb_sdmmc_bus_rod(sdmmc_chipset_handle_t, int);
static void wb_sdmmc_exec_command(sdmmc_chipset_handle_t,
struct sdmmc_command *);
static void wb_sdmmc_card_enable_intr(sdmmc_chipset_handle_t, int);
@@ -89,6 +90,7 @@
.bus_power = wb_sdmmc_bus_power,
.bus_clock = wb_sdmmc_bus_clock,
.bus_width = wb_sdmmc_bus_width,
+ .bus_width = wb_sdmmc_bus_rod,
.exec_command = wb_sdmmc_exec_command,
.card_enable_intr = wb_sdmmc_card_enable_intr,
.card_intr_ack = wb_sdmmc_card_intr_ack,
@@ -311,6 +313,14 @@
return 0;
}
+static int
+wb_sdmmc_bus_rod(sdmmc_chipset_handle_t sch, int on)
+{
+
+ /* Not support */
+ return -1;
+}
+
static void
wb_sdmmc_rsp_read_long(struct wb_softc *wb, struct sdmmc_command *cmd)
Index: dev/marvell/mvsdio.c
===================================================================
RCS file: /cvsroot/src/sys/dev/marvell/mvsdio.c,v
retrieving revision 1.1
diff -u -r1.1 mvsdio.c
--- dev/marvell/mvsdio.c 23 Sep 2010 12:36:01 -0000 1.1
+++ dev/marvell/mvsdio.c 1 Oct 2010 13:24:45 -0000
@@ -236,7 +236,7 @@
saa.saa_sct = &mvsdio_chip_functions;
saa.saa_sch = sc;
saa.saa_dmat = sc->sc_dmat;
- saa.saa_clkmin = 100; /* XXXX: 100 kHz */
+ saa.saa_clkmin = 100; /* XXXX: 100 kHz from SheevaPlug LSP */
saa.saa_clkmax = MVSDIO_MAX_CLOCK;
saa.saa_caps = SMC_CAPS_AUTO_STOP | SMC_CAPS_4BIT_MODE | SMC_CAPS_DMA;
#ifndef MVSDIO_CARD_DETECT
Index: dev/sdmmc/sdhc.c
===================================================================
RCS file: /cvsroot/src/sys/dev/sdmmc/sdhc.c,v
retrieving revision 1.7
diff -u -r1.7 sdhc.c
--- dev/sdmmc/sdhc.c 27 Mar 2010 03:04:52 -0000 1.7
+++ dev/sdmmc/sdhc.c 1 Oct 2010 13:24:46 -0000
@@ -112,6 +112,7 @@
static int sdhc_bus_power(sdmmc_chipset_handle_t, uint32_t);
static int sdhc_bus_clock(sdmmc_chipset_handle_t, int);
static int sdhc_bus_width(sdmmc_chipset_handle_t, int);
+static int sdhc_bus_rod(sdmmc_chipset_handle_t, int);
static void sdhc_card_enable_intr(sdmmc_chipset_handle_t, int);
static void sdhc_card_intr_ack(sdmmc_chipset_handle_t);
static void sdhc_exec_command(sdmmc_chipset_handle_t,
@@ -144,6 +145,7 @@
sdhc_bus_power,
sdhc_bus_clock,
sdhc_bus_width,
+ sdhc_bus_rod,
/* command execution */
sdhc_exec_command,
@@ -630,6 +632,11 @@
*/
HSET2(hp, SDHC_CLOCK_CTL, SDHC_SDCLK_ENABLE);
+ if (freq > 25000)
+ HSET1(hp, SDHC_HOST_CTL, SDHC_HIGH_SPEED);
+ else
+ HCLR1(hp, SDHC_HOST_CTL, SDHC_HIGH_SPEED);
+
out:
mutex_exit(&hp->host_mtx);
@@ -664,6 +671,14 @@
return 0;
}
+static int
+sdhc_bus_rod(sdmmc_chipset_handle_t sch, int on)
+{
+
+ /* Nothing ?? */
+ return 0;
+}
+
static void
sdhc_card_enable_intr(sdmmc_chipset_handle_t sch, int enable)
{
Index: dev/sdmmc/sdmmc.c
===================================================================
RCS file: /cvsroot/src/sys/dev/sdmmc/sdmmc.c,v
retrieving revision 1.4
diff -u -r1.4 sdmmc.c
--- dev/sdmmc/sdmmc.c 1 Oct 2010 09:50:42 -0000 1.4
+++ dev/sdmmc/sdmmc.c 1 Oct 2010 13:24:46 -0000
@@ -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: dev/sdmmc/sdmmc_io.c
===================================================================
RCS file: /cvsroot/src/sys/dev/sdmmc/sdmmc_io.c,v
retrieving revision 1.2
diff -u -r1.2 sdmmc_io.c
--- dev/sdmmc/sdmmc_io.c 5 Dec 2009 22:34:43 -0000 1.2
+++ dev/sdmmc/sdmmc_io.c 1 Oct 2010 13:24:46 -0000
@@ -206,6 +206,12 @@
#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:
SDMMC_UNLOCK(sc);
Index: dev/sdmmc/sdmmc_mem.c
===================================================================
RCS file: /cvsroot/src/sys/dev/sdmmc/sdmmc_mem.c,v
retrieving revision 1.12
diff -u -r1.12 sdmmc_mem.c
--- dev/sdmmc/sdmmc_mem.c 1 Oct 2010 09:50:42 -0000 1.12
+++ dev/sdmmc/sdmmc_mem.c 1 Oct 2010 13:24:47 -0000
@@ -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,13 @@
break;
}
+ if (!ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE))
+ /*
+ * Change ROD to Push-pull.
+ * 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 +323,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 +367,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 +444,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 +460,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 +577,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 +1011,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 +1045,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: dev/sdmmc/sdmmcchip.h
===================================================================
RCS file: /cvsroot/src/sys/dev/sdmmc/sdmmcchip.h,v
retrieving revision 1.2
diff -u -r1.2 sdmmcchip.h
--- dev/sdmmc/sdmmcchip.h 6 Apr 2010 15:10:09 -0000 1.2
+++ dev/sdmmc/sdmmcchip.h 1 Oct 2010 13:24:47 -0000
@@ -44,10 +44,11 @@
/* write protect */
int (*write_protect)(sdmmc_chipset_handle_t);
- /* bus power, clock frequency and width */
+ /* bus power, clock frequency, width and ROD(OpenDrain/PushPull) */
int (*bus_power)(sdmmc_chipset_handle_t, uint32_t);
int (*bus_clock)(sdmmc_chipset_handle_t, int);
int (*bus_width)(sdmmc_chipset_handle_t, int);
+ int (*bus_rod)(sdmmc_chipset_handle_t, int);
/* command execution */
void (*exec_command)(sdmmc_chipset_handle_t,
@@ -72,13 +73,15 @@
/* write protect */
#define sdmmc_chip_write_protect(tag, handle) \
((tag)->write_protect((handle)))
-/* bus power, clock frequency and width */
+/* bus power, clock frequency, width and rod */
#define sdmmc_chip_bus_power(tag, handle, ocr) \
((tag)->bus_power((handle), (ocr)))
#define sdmmc_chip_bus_clock(tag, handle, freq)
\
((tag)->bus_clock((handle), (freq)))
#define sdmmc_chip_bus_width(tag, handle, width) \
((tag)->bus_width((handle), (width)))
+#define sdmmc_chip_bus_rod(tag, handle, width) \
+ ((tag)->bus_rod((handle), (width)))
/* command execution */
#define sdmmc_chip_exec_command(tag, handle, cmdp) \
((tag)->exec_command((handle), (cmdp)))
Index: dev/sdmmc/sdmmcreg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/sdmmc/sdmmcreg.h,v
retrieving revision 1.4
diff -u -r1.4 sdmmcreg.h
--- dev/sdmmc/sdmmcreg.h 6 Apr 2010 15:10:09 -0000 1.4
+++ dev/sdmmc/sdmmcreg.h 1 Oct 2010 13:24:47 -0000
@@ -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: dev/sdmmc/sdmmcvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/sdmmc/sdmmcvar.h,v
retrieving revision 1.7
diff -u -r1.7 sdmmcvar.h
--- dev/sdmmc/sdmmcvar.h 1 Oct 2010 09:50:42 -0000 1.7
+++ dev/sdmmc/sdmmcvar.h 1 Oct 2010 13:24:47 -0000
@@ -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 */
/* ... */
};
@@ -329,7 +330,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 *,
Home |
Main Index |
Thread Index |
Old Index