diff options
author | Uwe Stuehler <uwe@cvs.openbsd.org> | 2007-05-26 18:37:46 +0000 |
---|---|---|
committer | Uwe Stuehler <uwe@cvs.openbsd.org> | 2007-05-26 18:37:46 +0000 |
commit | 7680169edbc0eb9203594512c3dc8a009a4d468f (patch) | |
tree | caad3826a928ef81d3c030f84ca44582a1233667 /sys/dev/sdmmc | |
parent | 4a9ef12b42afe54721b176d0ca16161b01736500 (diff) |
Wait until an I/O function becomes ready after enabling it, and make
sdmmc_io_rw_extended() non-incremental, by default.
Diffstat (limited to 'sys/dev/sdmmc')
-rw-r--r-- | sys/dev/sdmmc/sdmmc_io.c | 82 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmc_ioreg.h | 3 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmcvar.h | 7 |
3 files changed, 74 insertions, 18 deletions
diff --git a/sys/dev/sdmmc/sdmmc_io.c b/sys/dev/sdmmc/sdmmc_io.c index 50fdf5034a8..cfce95d6d09 100644 --- a/sys/dev/sdmmc/sdmmc_io.c +++ b/sys/dev/sdmmc/sdmmc_io.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmc_io.c,v 1.6 2006/07/18 04:10:35 uwe Exp $ */ +/* $OpenBSD: sdmmc_io.c,v 1.7 2007/05/26 18:37:45 uwe Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -19,6 +19,8 @@ /* Routines for SD I/O cards. */ #include <sys/param.h> +#include <sys/kernel.h> +#include <sys/proc.h> #include <sys/systm.h> #include <dev/sdmmc/sdmmc_ioreg.h> @@ -32,8 +34,6 @@ int sdmmc_io_rw_direct(struct sdmmc_softc *, struct sdmmc_function *, int, u_char *, int); int sdmmc_io_rw_extended(struct sdmmc_softc *, struct sdmmc_function *, int, u_char *, int, int); -int sdmmc_io_write(struct sdmmc_softc *, struct sdmmc_function *, - int, u_char); int sdmmc_io_xchg(struct sdmmc_softc *, struct sdmmc_function *, int, u_char *); void sdmmc_io_reset(struct sdmmc_softc *); @@ -158,7 +158,7 @@ int sdmmc_io_init(struct sdmmc_softc *sc, struct sdmmc_function *sf) { if (sf->number == 0) { - (void)sdmmc_io_write(sc, sf, SD_IO_CCCR_BUS_WIDTH, + sdmmc_io_write_1(sf, SD_IO_CCCR_BUS_WIDTH, CCCR_BUS_WIDTH_1); if (sdmmc_read_cis(sf, &sf->cis) != 0) { @@ -175,20 +175,53 @@ sdmmc_io_init(struct sdmmc_softc *sc, struct sdmmc_function *sf) return 0; } -void +/* + * Indicate whether the function is ready to operate. + */ +int +sdmmc_io_function_ready(struct sdmmc_function *sf) +{ + struct sdmmc_softc *sc = sf->sc; + struct sdmmc_function *sf0 = sc->sc_fn0; + u_int8_t rv; + + if (sf->number == 0) + return 1; /* FN0 is always ready */ + + rv = sdmmc_io_read_1(sf0, SD_IO_CCCR_FN_READY); + return (rv & (1 << sf->number)) != 0; +} + +/* + * Enable the I/O function. Return zero if the function was + * enabled successfully. + */ +int sdmmc_io_function_enable(struct sdmmc_function *sf) { struct sdmmc_softc *sc = sf->sc; struct sdmmc_function *sf0 = sc->sc_fn0; u_int8_t rv; + int retry = 5; + + if (sf->number == 0) + return 0; /* FN0 is always enabled */ SDMMC_LOCK(sc); rv = sdmmc_io_read_1(sf0, SD_IO_CCCR_FN_ENABLE); rv |= (1<<sf->number); sdmmc_io_write_1(sf0, SD_IO_CCCR_FN_ENABLE, rv); SDMMC_UNLOCK(sc); + + while (!sdmmc_io_function_ready(sf) && retry-- > 0) + tsleep(&lbolt, PPAUSE, "pause", 0); + return (retry >= 0) ? 0 : ETIMEDOUT; } +/* + * Disable the I/O function. Return zero if the function was + * disabled successfully. + */ void sdmmc_io_function_disable(struct sdmmc_function *sf) { @@ -196,6 +229,9 @@ sdmmc_io_function_disable(struct sdmmc_function *sf) struct sdmmc_function *sf0 = sc->sc_fn0; u_int8_t rv; + if (sf->number == 0) + return; /* FN0 is always enabled */ + SDMMC_LOCK(sc); rv = sdmmc_io_read_1(sf0, SD_IO_CCCR_FN_ENABLE); rv &= ~(1<<sf->number); @@ -322,6 +358,12 @@ sdmmc_io_rw_direct(struct sdmmc_softc *sc, struct sdmmc_function *sf, return error; } +/* + * Useful values of `arg' to pass in are either SD_ARG_CMD53_READ or + * SD_ARG_CMD53_WRITE. SD_ARG_CMD53_INCREMENT may be ORed into `arg' + * to access successive register locations instead of accessing the + * same register many times. + */ int sdmmc_io_rw_extended(struct sdmmc_softc *sc, struct sdmmc_function *sf, int reg, u_char *datap, int datalen, int arg) @@ -331,15 +373,16 @@ sdmmc_io_rw_extended(struct sdmmc_softc *sc, struct sdmmc_function *sf, SDMMC_LOCK(sc); +#if 0 /* Make sure the card is selected. */ if ((error = sdmmc_select_card(sc, sf)) != 0) { SDMMC_UNLOCK(sc); return error; } +#endif arg |= ((sf == NULL ? 0 : sf->number) & SD_ARG_CMD53_FUNC_MASK) << SD_ARG_CMD53_FUNC_SHIFT; - arg |= SD_ARG_CMD53_INCREMENT; arg |= (reg & SD_ARG_CMD53_REG_MASK) << SD_ARG_CMD53_REG_SHIFT; arg |= (datalen & SD_ARG_CMD53_LENGTH_MASK) << @@ -348,10 +391,11 @@ sdmmc_io_rw_extended(struct sdmmc_softc *sc, struct sdmmc_function *sf, bzero(&cmd, sizeof cmd); cmd.c_opcode = SD_IO_RW_EXTENDED; cmd.c_arg = arg; - cmd.c_flags = SCF_CMD_BC/* XXX */ | SCF_RSP_R5; + cmd.c_flags = SCF_CMD_ADTC/* XXX */ | SCF_RSP_R5; cmd.c_data = datap; cmd.c_datalen = datalen; - cmd.c_blklen = datalen; + cmd.c_blklen = MIN(datalen, sdmmc_chip_host_maxblklen(sc->sct, sc->sch)); + if (!ISSET(arg, SD_ARG_CMD53_WRITE)) cmd.c_flags |= SCF_CMD_READ; @@ -383,7 +427,7 @@ sdmmc_io_read_2(struct sdmmc_function *sf, int reg) u_int16_t data = 0; (void)sdmmc_io_rw_extended(sf->sc, sf, reg, (u_char *)&data, 2, - SD_ARG_CMD53_READ); + SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT); return data; } @@ -391,7 +435,7 @@ void sdmmc_io_write_2(struct sdmmc_function *sf, int reg, u_int16_t data) { (void)sdmmc_io_rw_extended(sf->sc, sf, reg, (u_char *)&data, 2, - SD_ARG_CMD53_WRITE); + SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT); } u_int32_t @@ -400,7 +444,7 @@ sdmmc_io_read_4(struct sdmmc_function *sf, int reg) u_int32_t data = 0; (void)sdmmc_io_rw_extended(sf->sc, sf, reg, (u_char *)&data, 4, - SD_ARG_CMD53_READ); + SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT); return data; } @@ -408,14 +452,22 @@ void sdmmc_io_write_4(struct sdmmc_function *sf, int reg, u_int32_t data) { (void)sdmmc_io_rw_extended(sf->sc, sf, reg, (u_char *)&data, 4, - SD_ARG_CMD53_WRITE); + SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT); +} + +int +sdmmc_io_read_multi_1(struct sdmmc_function *sf, int reg, u_char *data, + int datalen) +{ + return sdmmc_io_rw_extended(sf->sc, sf, reg, data, datalen, + SD_ARG_CMD53_READ); } int -sdmmc_io_write(struct sdmmc_softc *sc, struct sdmmc_function *sf, - int reg, u_char data) +sdmmc_io_write_multi_1(struct sdmmc_function *sf, int reg, u_char *data, + int datalen) { - return sdmmc_io_rw_direct(sc, sf, reg, &data, + return sdmmc_io_rw_extended(sf->sc, sf, reg, data, datalen, SD_ARG_CMD53_WRITE); } diff --git a/sys/dev/sdmmc/sdmmc_ioreg.h b/sys/dev/sdmmc/sdmmc_ioreg.h index 7c36d941583..481b8d56230 100644 --- a/sys/dev/sdmmc/sdmmc_ioreg.h +++ b/sys/dev/sdmmc/sdmmc_ioreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmc_ioreg.h,v 1.1 2006/06/01 21:53:41 uwe Exp $ */ +/* $OpenBSD: sdmmc_ioreg.h,v 1.2 2007/05/26 18:37:44 uwe Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -63,6 +63,7 @@ #define SD_IO_CCCR_START 0x00000 #define SD_IO_CCCR_SIZE 0x100 #define SD_IO_CCCR_FN_ENABLE 0x02 +#define SD_IO_CCCR_FN_READY 0x03 #define SD_IO_CCCR_CTL 0x06 #define CCCR_CTL_RES (1<<3) #define SD_IO_CCCR_BUS_WIDTH 0x07 diff --git a/sys/dev/sdmmc/sdmmcvar.h b/sys/dev/sdmmc/sdmmcvar.h index 2acf37c483d..960fe68daa4 100644 --- a/sys/dev/sdmmc/sdmmcvar.h +++ b/sys/dev/sdmmc/sdmmcvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmcvar.h,v 1.7 2007/03/18 22:07:16 uwe Exp $ */ +/* $OpenBSD: sdmmcvar.h,v 1.8 2007/05/26 18:37:45 uwe Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -206,10 +206,13 @@ void sdmmc_io_detach(struct sdmmc_softc *); u_int8_t sdmmc_io_read_1(struct sdmmc_function *, int); u_int16_t sdmmc_io_read_2(struct sdmmc_function *, int); u_int32_t sdmmc_io_read_4(struct sdmmc_function *, int); +int sdmmc_io_read_multi_1(struct sdmmc_function *, int, u_char *, int); void sdmmc_io_write_1(struct sdmmc_function *, int, u_int8_t); void sdmmc_io_write_2(struct sdmmc_function *, int, u_int16_t); void sdmmc_io_write_4(struct sdmmc_function *, int, u_int32_t); -void sdmmc_io_function_enable(struct sdmmc_function *); +int sdmmc_io_write_multi_1(struct sdmmc_function *, int, u_char *, int); +int sdmmc_io_function_ready(struct sdmmc_function *); +int sdmmc_io_function_enable(struct sdmmc_function *); void sdmmc_io_function_disable(struct sdmmc_function *); int sdmmc_read_cis(struct sdmmc_function *, struct sdmmc_cis *); |