support re-tuning modes 1 and 2

This commit is contained in:
jmcneill 2015-08-05 12:28:47 +00:00
parent e5ced7d3cc
commit 03f2930ea5
2 changed files with 64 additions and 4 deletions

View File

@ -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.79 2015/08/05 10:30:25 jmcneill Exp $");
#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_chipset_handle_t,
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, bus_space_tag_t iot,
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, bus_space_tag_t iot,
}
}
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, bus_space_tag_t iot,
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 flags)
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 sch, uint32_t ocr)
/* 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_t sch, int timing)
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_t sch, int timing)
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 sch, struct sdmmc_command *cmd)
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)) {
@ -2096,6 +2145,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).

View File

@ -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