support re-tuning modes 1 and 2
This commit is contained in:
parent
e5ced7d3cc
commit
03f2930ea5
@ -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).
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user