Add support for sampling clock tuning, required for some UHS modes and
MMC HS200.
This commit is contained in:
parent
1c4105dcf6
commit
a9e7784b4a
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: sdmmc_mem.c,v 1.44 2015/08/04 01:21:55 jmcneill Exp $ */
|
||||
/* $NetBSD: sdmmc_mem.c,v 1.45 2015/08/05 10:29:37 jmcneill Exp $ */
|
||||
/* $OpenBSD: sdmmc_mem.c,v 1.10 2009/01/09 10:55:22 jsg Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -45,7 +45,7 @@
|
|||
/* Routines for SD/MMC memory cards. */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.44 2015/08/04 01:21:55 jmcneill Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.45 2015/08/05 10:29:37 jmcneill Exp $");
|
||||
|
||||
#ifdef _KERNEL_OPT
|
||||
#include "opt_sdmmc.h"
|
||||
|
@ -142,13 +142,6 @@ sdmmc_mem_enable(struct sdmmc_softc *sc)
|
|||
/* Reset memory (*must* do that before CMD55 or CMD1). */
|
||||
sdmmc_go_idle_state(sc);
|
||||
|
||||
/* Set 3.3V signaling */
|
||||
if (sc->sc_sct->signal_voltage) {
|
||||
error = sdmmc_mem_signal_voltage(sc, SDMMC_SIGNAL_VOLTAGE_330);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE)) {
|
||||
/* Check SD Ver.2 */
|
||||
error = sdmmc_mem_send_if_cond(sc, 0x1aa, &card_ocr);
|
||||
|
@ -740,6 +733,44 @@ sdmmc_mem_select_transfer_mode(struct sdmmc_softc *sc, int support_func)
|
|||
return SD_ACCESS_MODE_SDR12;
|
||||
}
|
||||
|
||||
static int
|
||||
sdmmc_mem_execute_tuning(struct sdmmc_softc *sc, struct sdmmc_function *sf)
|
||||
{
|
||||
int timing = -1;
|
||||
|
||||
if (!ISSET(sc->sc_flags, SMF_UHS_MODE))
|
||||
return 0;
|
||||
|
||||
if (ISSET(sc->sc_flags, SMF_SD_MODE)) {
|
||||
if (!ISSET(sc->sc_flags, SMF_UHS_MODE))
|
||||
return 0;
|
||||
|
||||
switch (sf->csd.tran_speed) {
|
||||
case 100000:
|
||||
timing = SDMMC_TIMING_UHS_SDR50;
|
||||
break;
|
||||
case 208000:
|
||||
timing = SDMMC_TIMING_UHS_SDR104;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
switch (sf->csd.tran_speed) {
|
||||
case 200000:
|
||||
timing = SDMMC_TIMING_MMC_HS200;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
DPRINTF(("%s: execute tuning for timing %d\n", SDMMCDEVNAME(sc),
|
||||
timing));
|
||||
|
||||
return sdmmc_chip_execute_tuning(sc->sc_sct, sc->sc_sch, timing);
|
||||
}
|
||||
|
||||
static int
|
||||
sdmmc_mem_sd_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
|
||||
{
|
||||
|
@ -854,6 +885,13 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
|
|||
sc->sc_transfer_mode = switch_group0_functions[best_func].name;
|
||||
sc->sc_busddr = ddr;
|
||||
|
||||
/* execute tuning (UHS) */
|
||||
error = sdmmc_mem_execute_tuning(sc, sf);
|
||||
if (error) {
|
||||
aprint_error_dev(sc->sc_dev, "can't execute SD tuning\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -994,6 +1032,14 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
|
|||
|
||||
if (hs_timing == 2) {
|
||||
sc->sc_transfer_mode = "HS200";
|
||||
|
||||
/* execute tuning (HS200) */
|
||||
error = sdmmc_mem_execute_tuning(sc, sf);
|
||||
if (error) {
|
||||
aprint_error_dev(sc->sc_dev,
|
||||
"can't execute MMC tuning\n");
|
||||
return error;
|
||||
}
|
||||
} else {
|
||||
sc->sc_transfer_mode = NULL;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: sdmmcchip.h,v 1.6 2015/08/03 10:08:51 jmcneill Exp $ */
|
||||
/* $NetBSD: sdmmcchip.h,v 1.7 2015/08/05 10:29:37 jmcneill Exp $ */
|
||||
/* $OpenBSD: sdmmcchip.h,v 1.3 2007/05/31 10:09:01 uwe Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -61,6 +61,7 @@ struct sdmmc_chip_functions {
|
|||
/* UHS functions */
|
||||
int (*signal_voltage)(sdmmc_chipset_handle_t, int);
|
||||
int (*bus_clock_ddr)(sdmmc_chipset_handle_t, int, bool);
|
||||
int (*execute_tuning)(sdmmc_chipset_handle_t, int);
|
||||
};
|
||||
|
||||
/* host controller reset */
|
||||
|
@ -95,8 +96,10 @@ struct sdmmc_chip_functions {
|
|||
#define sdmmc_chip_card_intr_ack(tag, handle) \
|
||||
((tag)->card_intr_ack((handle)))
|
||||
/* UHS functions */
|
||||
#define sdmmc_chip_signal_voltage(tag, handle, voltage) \
|
||||
#define sdmmc_chip_signal_voltage(tag, handle, voltage) \
|
||||
((tag)->signal_voltage((handle), (voltage)))
|
||||
#define sdmmc_chip_execute_tuning(tag, handle, timing) \
|
||||
((tag)->execute_tuning ? (tag)->execute_tuning((handle), (timing)) : EINVAL)
|
||||
|
||||
/* clock frequencies for sdmmc_chip_bus_clock() */
|
||||
#define SDMMC_SDCLK_OFF 0
|
||||
|
@ -106,6 +109,11 @@ struct sdmmc_chip_functions {
|
|||
#define SDMMC_SIGNAL_VOLTAGE_330 0
|
||||
#define SDMMC_SIGNAL_VOLTAGE_180 1
|
||||
|
||||
/* timings for sdmmc_chip_execute_tuning() */
|
||||
#define SDMMC_TIMING_UHS_SDR50 0
|
||||
#define SDMMC_TIMING_UHS_SDR104 1
|
||||
#define SDMMC_TIMING_MMC_HS200 2
|
||||
|
||||
/* SPI mode */
|
||||
struct sdmmc_spi_chip_functions {
|
||||
/* card initialize */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: sdmmcreg.h,v 1.18 2015/08/03 10:08:51 jmcneill Exp $ */
|
||||
/* $NetBSD: sdmmcreg.h,v 1.19 2015/08/05 10:29:37 jmcneill Exp $ */
|
||||
/* $OpenBSD: sdmmcreg.h,v 1.4 2009/01/09 10:55:22 jsg Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -36,6 +36,8 @@
|
|||
#define MMC_SET_BLOCKLEN 16 /* R1 */
|
||||
#define MMC_READ_BLOCK_SINGLE 17 /* R1 */
|
||||
#define MMC_READ_BLOCK_MULTIPLE 18 /* R1 */
|
||||
#define MMC_SEND_TUNING_BLOCK 19 /* R1 */
|
||||
#define MMC_SEND_TUNING_BLOCK_HS200 21 /* R1 */
|
||||
#define MMC_SET_BLOCK_COUNT 23 /* R1 */
|
||||
#define MMC_WRITE_BLOCK_SINGLE 24 /* R1 */
|
||||
#define MMC_WRITE_BLOCK_MULTIPLE 25 /* R1 */
|
||||
|
|
Loading…
Reference in New Issue