Support High-Speed mode.
This commit is contained in:
parent
370119eed5
commit
62d43dee68
|
@ -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 @@ sdmmc_card_attach(struct sdmmc_softc *sc)
|
|||
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;
|
||||
|
|
|
@ -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 @@ sdmmc_io_scan(struct sdmmc_softc *sc)
|
|||
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 @@ sdmmc_io_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
|
|||
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:
|
||||
|
|
|
@ -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 @@ __KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.12 2010/10/01 09:50:42 kiyohara Exp
|
|||
#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_send_scr(struct sdmmc_softc *, struct sdmmc_function *,
|
|||
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 @@ sdmmc_mem_scan(struct sdmmc_softc *sc)
|
|||
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 @@ sdmmc_decode_csd(struct sdmmc_softc *sc, sdmmc_response resp,
|
|||
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 @@ sdmmc_decode_csd(struct sdmmc_softc *sc, sdmmc_response resp,
|
|||
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 @@ sdmmc_print_csd(sdmmc_response resp, struct sdmmc_csd *csd)
|
|||
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 @@ sdmmc_mem_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
|
|||
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);
|
||||
|
@ -616,6 +573,215 @@ sdmmc_mem_set_blocklen(struct sdmmc_softc *sc, struct sdmmc_function *sf)
|
|||
return error;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -842,19 +1008,6 @@ dmamem_free:
|
|||
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)
|
||||
{
|
||||
|
@ -888,6 +1041,84 @@ sdmmc_set_bus_width(struct sdmmc_function *sf, int width)
|
|||
return error;
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 @@ struct sdmmc_csd {
|
|||
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 @@ struct sdmmc_function {
|
|||
/* 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 @@ struct sdmmc_function {
|
|||
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_softc {
|
|||
struct sdmmc_attach_args {
|
||||
uint16_t manufacturer;
|
||||
uint16_t product;
|
||||
int interface;
|
||||
struct sdmmc_function *sf;
|
||||
};
|
||||
|
||||
|
@ -329,7 +333,6 @@ int sdmmc_mem_init(struct sdmmc_softc *, struct sdmmc_function *);
|
|||
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 *,
|
||||
|
|
Loading…
Reference in New Issue