Module Name: src Committed By: jmcneill Date: Wed Aug 5 12:28:47 UTC 2015
Modified Files: src/sys/dev/sdmmc: sdhc.c sdhcreg.h Log Message: support re-tuning modes 1 and 2 To generate a diff of this commit: cvs rdiff -u -r1.79 -r1.80 src/sys/dev/sdmmc/sdhc.c cvs rdiff -u -r1.16 -r1.17 src/sys/dev/sdmmc/sdhcreg.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/sdhc.c diff -u src/sys/dev/sdmmc/sdhc.c:1.79 src/sys/dev/sdmmc/sdhc.c:1.80 --- src/sys/dev/sdmmc/sdhc.c:1.79 Wed Aug 5 10:30:25 2015 +++ src/sys/dev/sdmmc/sdhc.c Wed Aug 5 12:28:47 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: sdhc.c,v 1.79 2015/08/05 10:30:25 jmcneill Exp $ */ +/* $NetBSD: sdhc.c,v 1.80 2015/08/05 12:28:47 jmcneill Exp $ */ /* $OpenBSD: sdhc.c,v 1.25 2009/01/13 19:44:20 grange Exp $ */ /* @@ -23,7 +23,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.79 2015/08/05 10:30:25 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.80 2015/08/05 12:28:47 jmcneill Exp $"); #ifdef _KERNEL_OPT #include "opt_sdmmc.h" @@ -36,6 +36,7 @@ __KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.7 #include <sys/systm.h> #include <sys/mutex.h> #include <sys/condvar.h> +#include <sys/atomic.h> #include <dev/sdmmc/sdhcreg.h> #include <dev/sdmmc/sdhcvar.h> @@ -78,6 +79,11 @@ struct sdhc_host { kmutex_t intr_lock; kcondvar_t intr_cv; + callout_t tuning_timer; + int tuning_timing; + u_int tuning_timer_count; + u_int tuning_timer_pending; + int specver; /* spec. version */ uint32_t flags; /* flags for this host */ @@ -184,6 +190,7 @@ static void sdhc_exec_command(sdmmc_chip struct sdmmc_command *); static int sdhc_signal_voltage(sdmmc_chipset_handle_t, int); static int sdhc_execute_tuning(sdmmc_chipset_handle_t, int); +static void sdhc_tuning_timer(void *); static int sdhc_start_command(struct sdhc_host *, struct sdmmc_command *); static int sdhc_wait_state(struct sdhc_host *, uint32_t, uint32_t); static int sdhc_soft_reset(struct sdhc_host *, int); @@ -279,6 +286,8 @@ sdhc_host_found(struct sdhc_softc *sc, b mutex_init(&hp->intr_lock, MUTEX_DEFAULT, IPL_SDMMC); cv_init(&hp->intr_cv, "sdhcintr"); + callout_init(&hp->tuning_timer, CALLOUT_MPSAFE); + callout_setfunc(&hp->tuning_timer, sdhc_tuning_timer, hp); if (ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) { sdhcver = HREAD4(hp, SDHC_ESDHC_HOST_CTL_VERSION); @@ -329,6 +338,18 @@ sdhc_host_found(struct sdhc_softc *sc, b } } + const u_int retuning_mode = (caps2 >> SDHC_RETUNING_MODES_SHIFT) & + SDHC_RETUNING_MODES_MASK; + if (retuning_mode == SDHC_RETUNING_MODE_1) { + hp->tuning_timer_count = (caps2 >> SDHC_TIMER_COUNT_SHIFT) & + SDHC_TIMER_COUNT_MASK; + if (hp->tuning_timer_count == 0xf) + hp->tuning_timer_count = 0; + if (hp->tuning_timer_count) + hp->tuning_timer_count = + 1 << (hp->tuning_timer_count - 1); + } + /* * Use DMA if the host system and the controller support it. * Suports integrated or external DMA egine, with or without @@ -442,6 +463,11 @@ sdhc_host_found(struct sdhc_softc *sc, b SET(hp->ocr, MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V); aprint_normal(" 3.3V"); } + if (hp->specver >= SDHC_SPEC_VERS_300) { + aprint_normal(", re-tuning mode %d", retuning_mode + 1); + if (hp->tuning_timer_count) + aprint_normal(" (%us timer)", hp->tuning_timer_count); + } /* * Determine the maximum block length supported by the host @@ -560,6 +586,7 @@ adma_done: return 0; err: + callout_destroy(&hp->tuning_timer); cv_destroy(&hp->intr_cv); mutex_destroy(&hp->intr_lock); free(hp, M_DEVBUF); @@ -595,6 +622,8 @@ sdhc_detach(struct sdhc_softc *sc, int f sdhc_soft_reset(hp, SDHC_RESET_ALL); mutex_exit(&hp->intr_lock); } + callout_halt(&hp->tuning_timer, NULL); + callout_destroy(&hp->tuning_timer); cv_destroy(&hp->intr_cv); mutex_destroy(&hp->intr_lock); if (hp->ios > 0) { @@ -841,6 +870,7 @@ sdhc_bus_power(sdmmc_chipset_handle_t sc /* If power is disabled, reset the host and return now. */ if (ocr == 0) { (void)sdhc_host_reset1(hp); + callout_halt(&hp->tuning_timer, &hp->intr_lock); goto out; } @@ -1241,6 +1271,8 @@ sdhc_execute_tuning(sdmmc_chipset_handle uint8_t hostctl; int opcode, error, retry = 40; + hp->tuning_timing = timing; + switch (timing) { case SDMMC_TIMING_MMC_HS200: opcode = MMC_SEND_TUNING_BLOCK_HS200; @@ -1318,9 +1350,22 @@ sdhc_execute_tuning(sdmmc_chipset_handle return EIO; /* tuning failed */ } + if (hp->tuning_timer_count) { + callout_schedule(&hp->tuning_timer, + hz * hp->tuning_timer_count); + } + return 0; /* tuning completed */ } +static void +sdhc_tuning_timer(void *arg) +{ + struct sdhc_host *hp = arg; + + atomic_swap_uint(&hp->tuning_timer_pending, 1); +} + static int sdhc_wait_state(struct sdhc_host *hp, uint32_t mask, uint32_t value) { @@ -1345,6 +1390,10 @@ sdhc_exec_command(sdmmc_chipset_handle_t mutex_enter(&hp->intr_lock); + if (atomic_cas_uint(&hp->tuning_timer_pending, 1, 0) == 1) { + (void)sdhc_execute_tuning(hp, hp->tuning_timing); + } + if (cmd->c_data && ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) { const uint16_t ready = SDHC_BUFFER_READ_READY | SDHC_BUFFER_WRITE_READY; if (ISSET(hp->flags, SHF_USE_DMA)) { @@ -2097,6 +2146,13 @@ sdhc_intr(void *arg) } /* + * Schedule re-tuning process (UHS). + */ + if (ISSET(status, SDHC_RETUNING_EVENT)) { + atomic_swap_uint(&hp->tuning_timer_pending, 1); + } + + /* * Wake up the blocking process to service command * related interrupt(s). */ Index: src/sys/dev/sdmmc/sdhcreg.h diff -u src/sys/dev/sdmmc/sdhcreg.h:1.16 src/sys/dev/sdmmc/sdhcreg.h:1.17 --- src/sys/dev/sdmmc/sdhcreg.h:1.16 Wed Aug 5 10:30:25 2015 +++ src/sys/dev/sdmmc/sdhcreg.h Wed Aug 5 12:28:47 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: sdhcreg.h,v 1.16 2015/08/05 10:30:25 jmcneill Exp $ */ +/* $NetBSD: sdhcreg.h,v 1.17 2015/08/05 12:28:47 jmcneill Exp $ */ /* $OpenBSD: sdhcreg.h,v 1.4 2006/07/30 17:20:40 fgsch Exp $ */ /* @@ -112,6 +112,7 @@ #define SDHC_RESET_ALL (1<<0) #define SDHC_NINTR_STATUS 0x30 #define SDHC_ERROR_INTERRUPT (1<<15) +#define SDHC_RETUNING_EVENT (1<<12) #define SDHC_CARD_INTERRUPT (1<<8) #define SDHC_CARD_REMOVAL (1<<7) #define SDHC_CARD_INSERTION (1<<6) @@ -121,7 +122,7 @@ #define SDHC_BLOCK_GAP_EVENT (1<<2) #define SDHC_TRANSFER_COMPLETE (1<<1) #define SDHC_COMMAND_COMPLETE (1<<0) -#define SDHC_NINTR_STATUS_MASK 0x81ff +#define SDHC_NINTR_STATUS_MASK 0x91ff #define SDHC_EINTR_STATUS 0x32 #define SDHC_DMA_ERROR (1<<12) #define SDHC_ADMA_ERROR (1<<9) @@ -190,6 +191,9 @@ #define SDHC_TUNING_SDR50 (1<<13) #define SDHC_RETUNING_MODES_SHIFT 14 #define SDHC_RETUNING_MODES_MASK 0x3 +#define SDHC_RETUNING_MODE_1 (0 << SDHC_RETUNING_MODES_SHIFT) +#define SDHC_RETUNING_MODE_2 (1 << SDHC_RETUNING_MODES_SHIFT) +#define SDHC_RETUNING_MODE_3 (2 << SDHC_RETUNING_MODES_SHIFT) #define SDHC_CLOCK_MULTIPLIER_SHIFT 16 #define SDHC_CLOCK_MULTIPLIER_MASK 0xff #define SDHC_ADMA_ERROR_STATUS 0x54