From dae1f2dba48093c739c482b35e1f62e6709d1bf8 Mon Sep 17 00:00:00 2001 From: patrick Date: Sun, 11 Feb 2018 20:58:40 +0000 Subject: [PATCH] Add sdmmc_io_set_blocklen() which allows to set the block length of an SDIO function. This is necessary for some SDIO cards that need to be talked with using smaller block lengths than the maximum supported by the host controller. ok kettenis@ --- sys/dev/sdmmc/sdmmc.c | 3 ++- sys/dev/sdmmc/sdmmc_io.c | 27 +++++++++++++++++++++++++-- sys/dev/sdmmc/sdmmc_ioreg.h | 6 +++--- sys/dev/sdmmc/sdmmcvar.h | 4 +++- 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/sys/dev/sdmmc/sdmmc.c b/sys/dev/sdmmc/sdmmc.c index 863f4ee69f4..bb7d4cc96b6 100644 --- a/sys/dev/sdmmc/sdmmc.c +++ b/sys/dev/sdmmc/sdmmc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmc.c,v 1.48 2017/12/24 12:55:52 kettenis Exp $ */ +/* $OpenBSD: sdmmc.c,v 1.49 2018/02/11 20:58:40 patrick Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler @@ -503,6 +503,7 @@ sdmmc_function_alloc(struct sdmmc_softc *sc) sf->cis.manufacturer = SDMMC_VENDOR_INVALID; sf->cis.product = SDMMC_PRODUCT_INVALID; sf->cis.function = SDMMC_FUNCTION_INVALID; + sf->cur_blklen = sdmmc_chip_host_maxblklen(sc->sct, sc->sch); return sf; } diff --git a/sys/dev/sdmmc/sdmmc_io.c b/sys/dev/sdmmc/sdmmc_io.c index 206d578f06e..4d2550f0bca 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.31 2018/02/11 20:57:57 patrick Exp $ */ +/* $OpenBSD: sdmmc_io.c,v 1.32 2018/02/11 20:58:40 patrick Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler @@ -46,6 +46,7 @@ int sdmmc_io_xchg(struct sdmmc_softc *, struct sdmmc_function *, int, u_char *); void sdmmc_io_reset(struct sdmmc_softc *); int sdmmc_io_send_op_cond(struct sdmmc_softc *, u_int32_t, u_int32_t *); +void sdmmc_io_set_blocklen(struct sdmmc_function *, unsigned int); #ifdef SDMMC_DEBUG #define DPRINTF(s) printf s @@ -415,7 +416,7 @@ sdmmc_io_rw_extended(struct sdmmc_softc *sc, struct sdmmc_function *sf, cmd.c_flags = SCF_CMD_AC | SCF_RSP_R5; cmd.c_data = datap; cmd.c_datalen = datalen; - cmd.c_blklen = MIN(datalen, sdmmc_chip_host_maxblklen(sc->sct, sc->sch)); + cmd.c_blklen = MIN(datalen, sf->cur_blklen); if (!ISSET(arg, SD_ARG_CMD53_WRITE)) cmd.c_flags |= SCF_CMD_READ; @@ -767,3 +768,25 @@ sdmmc_intr_task(void *arg) sdmmc_chip_card_intr_ack(sc->sct, sc->sch); splx(s); } + +void +sdmmc_io_set_blocklen(struct sdmmc_function *sf, unsigned int blklen) +{ + struct sdmmc_softc *sc = sf->sc; + struct sdmmc_function *sf0 = sc->sc_fn0; + + rw_assert_wrlock(&sc->sc_lock); + + if (blklen > sdmmc_chip_host_maxblklen(sc->sct, sc->sch)) + return; + + if (blklen == 0) { + blklen = min(512, sdmmc_chip_host_maxblklen(sc->sct, sc->sch)); + } + + sdmmc_io_write_1(sf0, SD_IO_FBR_BASE(sf->number) + + SD_IO_FBR_BLOCKLEN, blklen & 0xff); + sdmmc_io_write_1(sf0, SD_IO_FBR_BASE(sf->number) + + SD_IO_FBR_BLOCKLEN+ 1, (blklen >> 8) & 0xff); + sf->cur_blklen = blklen; +} diff --git a/sys/dev/sdmmc/sdmmc_ioreg.h b/sys/dev/sdmmc/sdmmc_ioreg.h index b23edd898d7..1fdea4792b7 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.6 2016/04/23 14:15:59 kettenis Exp $ */ +/* $OpenBSD: sdmmc_ioreg.h,v 1.7 2018/02/11 20:58:40 patrick Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler @@ -75,8 +75,8 @@ #define SD_IO_CCCR_CISPTR 0x09 /* XXX 9-10, 10-11, or 9-12 */ /* Function Basic Registers (FBR) */ -#define SD_IO_FBR_START 0x00100 -#define SD_IO_FBR_SIZE 0x00700 +#define SD_IO_FBR_BASE(f) ((f) * 0x100) +#define SD_IO_FBR_BLOCKLEN 0x10 /* Card Information Structure (CIS) */ #define SD_IO_CIS_START 0x01000 diff --git a/sys/dev/sdmmc/sdmmcvar.h b/sys/dev/sdmmc/sdmmcvar.h index 0b2ffce42be..0510bdaa6d1 100644 --- a/sys/dev/sdmmc/sdmmcvar.h +++ b/sys/dev/sdmmc/sdmmcvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmcvar.h,v 1.27 2018/02/11 20:57:57 patrick Exp $ */ +/* $OpenBSD: sdmmcvar.h,v 1.28 2018/02/11 20:58:40 patrick Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler @@ -151,6 +151,7 @@ struct sdmmc_function { int number; /* I/O function number or -1 */ struct device *child; /* function driver */ struct sdmmc_cis cis; /* decoded CIS */ + unsigned int cur_blklen; /* current block length */ /* SD/MMC memory card members */ struct sdmmc_csd csd; /* decoded CSD value */ struct sdmmc_cid cid; /* decoded CID value */ @@ -267,6 +268,7 @@ int sdmmc_io_write_region_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 *); +void sdmmc_io_set_blocklen(struct sdmmc_function *, unsigned int); int sdmmc_read_cis(struct sdmmc_function *, struct sdmmc_cis *); void sdmmc_print_cis(struct sdmmc_function *); -- 2.20.1