o Add support for eMMC DDR bus speed mode at 52 MHz to sdhci(4) and
mmc(4). For the most part, this consists of support for: - Switching the signal voltage (VCCQ) to 1.8 V or (if supported by the host controller) to 1.2 V, - setting the UHS mode as appropriate in the SDHCI_HOST_CONTROL2 register, - setting the power class in the eMMC device according to the core supply voltage (VCC), - using different bits for enabling a bus width of 4 and 8 bits in the the eMMC device at DDR or higher timings respectively, - arbitrating timings faster than high speed if there actually are additional devices on the same MMC bus. Given that support for DDR52 is not denoted by SDHCI capability registers, availability of that timing is indicated by a new quirk SDHCI_QUIRK_MMC_DDR52 and only enabled for Intel SDHCI controllers so far. Generally, what it takes for a sdhci(4) front-end to enable support for DDR52 is to hook up the bridge method mmcbr_switch_vccq (which especially for 1.2 V signaling support is chip/board specific) and the sdhci_set_uhs_timing sdhci(4) method. As a side-effect, this change also fixes communication with some eMMC devices at SDR high speed mode with 52 MHz due to the signaling voltage and UHS bits in the SDHCI controller no longer being left in an inappropriate state. Compared to 52 MHz at SDR high speed which typically yields ~45 MB/s with the eMMC chips tested, throughput goes up to ~80 MB/s at DDR52. Additionally, this change already adds infrastructure and quite some code for modes up to HS400ES and SDR104 respectively (I did not want to add to much stuff at a time, though). Essentially, what is still missing in order to be able to activate support for these latter is is support for and handling of (re-)tuning. o In sdhci(4), add two tunables hw.sdhci.quirk_clear as well as hw.sdhci.quirk_set, which (when hooked up in the front-end) allow to set/clear sdhci(4) quirks for debugging and testing purposes. However, especially for SDHCI controllers on the PCI bus which have no specific support code so far and, thus, are picked up as generic SDHCI controllers, hw.sdhci.quirk_set allows for setting the necessary quirks (if required). o In mmc(4), check and handle the return values of some more function calls instead of assuming that everything went right. In case failures actually are not problematic, indicate that by casting the return value to void. Reviewed by: jmcneill
This commit is contained in:
parent
ac46d38655
commit
0f34084f95
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=315598
@ -89,6 +89,10 @@ enum mmc_vdd {
|
||||
vdd_330, vdd_340, vdd_350, vdd_360
|
||||
};
|
||||
|
||||
enum mmc_vccq {
|
||||
vccq_120 = 0, vccq_180, vccq_330
|
||||
};
|
||||
|
||||
enum mmc_power_mode {
|
||||
power_off = 0, power_up, power_on
|
||||
};
|
||||
@ -105,18 +109,28 @@ enum mmc_bus_width {
|
||||
bus_width_1 = 0, bus_width_4 = 2, bus_width_8 = 3
|
||||
};
|
||||
|
||||
enum mmc_drv_type {
|
||||
drv_type_b = 0, drv_type_a, drv_type_c, drv_type_d
|
||||
};
|
||||
|
||||
enum mmc_bus_timing {
|
||||
bus_timing_normal = 0, bus_timing_hs
|
||||
bus_timing_normal = 0, bus_timing_hs, bus_timing_uhs_sdr12,
|
||||
bus_timing_uhs_sdr25, bus_timing_uhs_sdr50, bus_timing_uhs_ddr50,
|
||||
bus_timing_uhs_sdr104, bus_timing_mmc_ddr52, bus_timing_mmc_hs200,
|
||||
bus_timing_mmc_hs400, bus_timing_mmc_hs400es, bus_timing_max =
|
||||
bus_timing_mmc_hs400es
|
||||
};
|
||||
|
||||
struct mmc_ios {
|
||||
uint32_t clock; /* Speed of the clock in Hz to move data */
|
||||
enum mmc_vdd vdd; /* Voltage to apply to the power pins */
|
||||
enum mmc_vccq vccq; /* Voltage to use for signaling */
|
||||
enum mmc_bus_mode bus_mode;
|
||||
enum mmc_chip_select chip_select;
|
||||
enum mmc_bus_width bus_width;
|
||||
enum mmc_power_mode power_mode;
|
||||
enum mmc_bus_timing timing;
|
||||
enum mmc_drv_type drv_type;
|
||||
};
|
||||
|
||||
enum mmc_card_mode {
|
||||
@ -134,6 +148,28 @@ struct mmc_host {
|
||||
#define MMC_CAP_HSPEED (1 << 2) /* Can do High Speed transfers */
|
||||
#define MMC_CAP_BOOT_NOACC (1 << 4) /* Cannot access boot partitions */
|
||||
#define MMC_CAP_WAIT_WHILE_BUSY (1 << 5) /* Host waits for busy responses */
|
||||
#define MMC_CAP_UHS_SDR12 (1 << 6) /* Can do UHS SDR12 */
|
||||
#define MMC_CAP_UHS_SDR25 (1 << 7) /* Can do UHS SDR25 */
|
||||
#define MMC_CAP_UHS_SDR50 (1 << 8) /* Can do UHS SDR50 */
|
||||
#define MMC_CAP_UHS_SDR104 (1 << 9) /* Can do UHS SDR104 */
|
||||
#define MMC_CAP_UHS_DDR50 (1 << 10) /* Can do UHS DDR50 */
|
||||
#define MMC_CAP_MMC_DDR52_120 (1 << 11) /* Can do eMMC DDR52 at 1.2 V */
|
||||
#define MMC_CAP_MMC_DDR52_180 (1 << 12) /* Can do eMMC DDR52 at 1.8 V */
|
||||
#define MMC_CAP_MMC_DDR52 (MMC_CAP_MMC_DDR52_120 | MMC_CAP_MMC_DDR52_180)
|
||||
#define MMC_CAP_MMC_HS200_120 (1 << 13) /* Can do eMMC HS200 at 1.2 V */
|
||||
#define MMC_CAP_MMC_HS200_180 (1 << 14) /* Can do eMMC HS200 at 1.8 V */
|
||||
#define MMC_CAP_MMC_HS200 (MMC_CAP_MMC_HS200_120| MMC_CAP_MMC_HS200_180)
|
||||
#define MMC_CAP_MMC_HS400_120 (1 << 15) /* Can do eMMC HS400 at 1.2 V */
|
||||
#define MMC_CAP_MMC_HS400_180 (1 << 16) /* Can do eMMC HS400 at 1.8 V */
|
||||
#define MMC_CAP_MMC_HS400 (MMC_CAP_MMC_HS400_120 | MMC_CAP_MMC_HS400_180)
|
||||
#define MMC_CAP_MMC_HSX00_120 (MMC_CAP_MMC_HS200_120 | MMC_CAP_MMC_HS400_120)
|
||||
#define MMC_CAP_MMC_ENH_STROBE (1 << 17) /* Can do eMMC Enhanced Strobe */
|
||||
#define MMC_CAP_SIGNALING_120 (1 << 18) /* Can do signaling at 1.2 V */
|
||||
#define MMC_CAP_SIGNALING_180 (1 << 19) /* Can do signaling at 1.8 V */
|
||||
#define MMC_CAP_SIGNALING_330 (1 << 20) /* Can do signaling at 3.3 V */
|
||||
#define MMC_CAP_DRIVER_TYPE_A (1 << 21) /* Can do Driver Type A */
|
||||
#define MMC_CAP_DRIVER_TYPE_C (1 << 22) /* Can do Driver Type C */
|
||||
#define MMC_CAP_DRIVER_TYPE_D (1 << 23) /* Can do Driver Type D */
|
||||
enum mmc_card_mode mode;
|
||||
struct mmc_ios ios; /* Current state of the host */
|
||||
};
|
||||
@ -141,7 +177,7 @@ struct mmc_host {
|
||||
extern driver_t mmc_driver;
|
||||
extern devclass_t mmc_devclass;
|
||||
|
||||
#define MMC_VERSION 2
|
||||
#define MMC_VERSION 3
|
||||
|
||||
#define MMC_DECLARE_BRIDGE(name) \
|
||||
DRIVER_MODULE(mmc, name, mmc_driver, mmc_devclass, NULL, NULL); \
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*-
|
||||
* Copyright (c) 2006 Bernd Walter. All rights reserved.
|
||||
* Copyright (c) 2006 M. Warner Losh. All rights reserved.
|
||||
* Copyright (c) 2017 Marius Strobl <marius@FreeBSD.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -75,6 +76,8 @@ __FBSDID("$FreeBSD$");
|
||||
#include "mmcbr_if.h"
|
||||
#include "mmcbus_if.h"
|
||||
|
||||
CTASSERT(bus_timing_max <= sizeof(uint32_t) * NBBY);
|
||||
|
||||
/*
|
||||
* Per-card data
|
||||
*/
|
||||
@ -92,9 +95,11 @@ struct mmc_ivars {
|
||||
struct mmc_sd_status sd_status; /* SD_STATUS decoded */
|
||||
u_char read_only; /* True when the device is read-only */
|
||||
u_char bus_width; /* Bus width to use */
|
||||
u_char timing; /* Bus timing support */
|
||||
u_char high_cap; /* High Capacity card (block addressed) */
|
||||
uint32_t sec_count; /* Card capacity in 512byte blocks */
|
||||
uint32_t timings; /* Mask of bus timings supported */
|
||||
uint32_t vccq_120; /* Mask of bus timings at VCCQ of 1.2 V */
|
||||
uint32_t vccq_180; /* Mask of bus timings at VCCQ of 1.8 V */
|
||||
uint32_t tran_speed; /* Max speed in normal mode */
|
||||
uint32_t hs_tran_speed; /* Max speed in high speed mode */
|
||||
uint32_t erase_sector; /* Card native erase sector size */
|
||||
@ -105,8 +110,6 @@ struct mmc_ivars {
|
||||
|
||||
#define CMD_RETRIES 3
|
||||
|
||||
#define CARD_ID_FREQUENCY 400000 /* Spec requires 400kHz max during ID phase. */
|
||||
|
||||
static SYSCTL_NODE(_hw, OID_AUTO, mmc, CTLFLAG_RD, NULL, "mmc driver");
|
||||
|
||||
static int mmc_debug;
|
||||
@ -180,12 +183,15 @@ static int mmc_send_op_cond(struct mmc_softc *sc, uint32_t ocr,
|
||||
uint32_t *rocr);
|
||||
static int mmc_send_relative_addr(struct mmc_softc *sc, uint32_t *resp);
|
||||
static int mmc_set_blocklen(struct mmc_softc *sc, uint32_t len);
|
||||
static int mmc_set_card_bus_width(struct mmc_softc *sc,
|
||||
struct mmc_ivars *ivar);
|
||||
static int mmc_set_card_bus_width(struct mmc_softc *sc, struct mmc_ivars *ivar);
|
||||
static int mmc_set_power_class(struct mmc_softc *sc, struct mmc_ivars *ivar);
|
||||
static int mmc_set_relative_addr(struct mmc_softc *sc, uint16_t resp);
|
||||
static int mmc_set_timing(struct mmc_softc *sc, struct mmc_ivars *ivar,
|
||||
int timing);
|
||||
enum mmc_bus_timing timing);
|
||||
static int mmc_test_bus_width(struct mmc_softc *sc);
|
||||
static uint32_t mmc_timing_to_dtr(struct mmc_ivars *ivar,
|
||||
enum mmc_bus_timing timing);
|
||||
static const char *mmc_timing_to_string(enum mmc_bus_timing timing);
|
||||
static int mmc_wait_for_command(struct mmc_softc *sc, uint32_t opcode,
|
||||
uint32_t arg, uint32_t flags, uint32_t *resp, int retries);
|
||||
static int mmc_wait_for_req(struct mmc_softc *sc, struct mmc_request *req);
|
||||
@ -264,8 +270,8 @@ mmc_acquire_bus(device_t busdev, device_t dev)
|
||||
{
|
||||
struct mmc_softc *sc;
|
||||
struct mmc_ivars *ivar;
|
||||
int err;
|
||||
int rca;
|
||||
int err, rca;
|
||||
enum mmc_bus_timing timing;
|
||||
|
||||
err = MMCBR_ACQUIRE_HOST(device_get_parent(busdev), busdev);
|
||||
if (err)
|
||||
@ -287,16 +293,44 @@ mmc_acquire_bus(device_t busdev, device_t dev)
|
||||
ivar = device_get_ivars(dev);
|
||||
rca = ivar->rca;
|
||||
if (sc->last_rca != rca) {
|
||||
mmc_select_card(sc, rca);
|
||||
if (mmc_select_card(sc, rca) != MMC_ERR_NONE) {
|
||||
device_printf(sc->dev, "Card at relative "
|
||||
"address %d failed to select.\n", rca);
|
||||
return (ENXIO);
|
||||
}
|
||||
sc->last_rca = rca;
|
||||
timing = mmcbr_get_timing(busdev);
|
||||
/* Prepare bus width for the new card. */
|
||||
if (bootverbose || mmc_debug) {
|
||||
device_printf(busdev,
|
||||
"setting bus width to %d bits\n",
|
||||
"setting bus width to %d bits %s timing\n",
|
||||
(ivar->bus_width == bus_width_4) ? 4 :
|
||||
(ivar->bus_width == bus_width_8) ? 8 : 1);
|
||||
(ivar->bus_width == bus_width_8) ? 8 : 1,
|
||||
mmc_timing_to_string(timing));
|
||||
}
|
||||
if (mmc_set_card_bus_width(sc, ivar) != MMC_ERR_NONE) {
|
||||
device_printf(sc->dev, "Card at relative "
|
||||
"address %d failed to set bus width.\n",
|
||||
rca);
|
||||
return (ENXIO);
|
||||
}
|
||||
if (isset(&ivar->vccq_120, timing))
|
||||
mmcbr_set_vccq(busdev, vccq_120);
|
||||
else if (isset(&ivar->vccq_180, timing))
|
||||
mmcbr_set_vccq(busdev, vccq_180);
|
||||
else
|
||||
mmcbr_set_vccq(busdev, vccq_330);
|
||||
if (mmcbr_switch_vccq(busdev) != 0) {
|
||||
device_printf(sc->dev, "Failed to set VCCQ "
|
||||
"for card at relative address %d.\n", rca);
|
||||
return (ENXIO);
|
||||
}
|
||||
if (mmc_set_power_class(sc, ivar) != MMC_ERR_NONE) {
|
||||
device_printf(sc->dev, "Card at relative "
|
||||
"address %d failed to set power class.\n",
|
||||
rca);
|
||||
return (ENXIO);
|
||||
}
|
||||
mmc_set_card_bus_width(sc, ivar);
|
||||
mmcbr_set_bus_width(busdev, ivar->bus_width);
|
||||
mmcbr_update_ios(busdev);
|
||||
}
|
||||
@ -524,6 +558,7 @@ static void
|
||||
mmc_power_up(struct mmc_softc *sc)
|
||||
{
|
||||
device_t dev;
|
||||
enum mmc_vccq vccq;
|
||||
|
||||
dev = sc->dev;
|
||||
mmcbr_set_vdd(dev, mmc_highest_voltage(mmcbr_get_host_ocr(dev)));
|
||||
@ -533,9 +568,14 @@ mmc_power_up(struct mmc_softc *sc)
|
||||
mmcbr_set_power_mode(dev, power_up);
|
||||
mmcbr_set_clock(dev, 0);
|
||||
mmcbr_update_ios(dev);
|
||||
for (vccq = vccq_330; ; vccq--) {
|
||||
mmcbr_set_vccq(dev, vccq);
|
||||
if (mmcbr_switch_vccq(dev) == 0 || vccq == vccq_120)
|
||||
break;
|
||||
}
|
||||
mmc_ms_delay(1);
|
||||
|
||||
mmcbr_set_clock(dev, CARD_ID_FREQUENCY);
|
||||
mmcbr_set_clock(dev, SD_MMC_CARD_ID_FREQUENCY);
|
||||
mmcbr_set_timing(dev, bus_timing_normal);
|
||||
mmcbr_set_power_mode(dev, power_on);
|
||||
mmcbr_update_ios(dev);
|
||||
@ -631,10 +671,30 @@ mmc_set_card_bus_width(struct mmc_softc *sc, struct mmc_ivars *ivar)
|
||||
value = EXT_CSD_BUS_WIDTH_1;
|
||||
break;
|
||||
case bus_width_4:
|
||||
value = EXT_CSD_BUS_WIDTH_4;
|
||||
switch (mmcbr_get_timing(sc->dev)) {
|
||||
case bus_timing_mmc_ddr52:
|
||||
case bus_timing_mmc_hs200:
|
||||
case bus_timing_mmc_hs400:
|
||||
case bus_timing_mmc_hs400es:
|
||||
value = EXT_CSD_BUS_WIDTH_4_DDR;
|
||||
break;
|
||||
default:
|
||||
value = EXT_CSD_BUS_WIDTH_4;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case bus_width_8:
|
||||
value = EXT_CSD_BUS_WIDTH_8;
|
||||
switch (mmcbr_get_timing(sc->dev)) {
|
||||
case bus_timing_mmc_ddr52:
|
||||
case bus_timing_mmc_hs200:
|
||||
case bus_timing_mmc_hs400:
|
||||
case bus_timing_mmc_hs400es:
|
||||
value = EXT_CSD_BUS_WIDTH_8_DDR;
|
||||
break;
|
||||
default:
|
||||
value = EXT_CSD_BUS_WIDTH_8;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return (MMC_ERR_INVALID);
|
||||
@ -647,23 +707,96 @@ mmc_set_card_bus_width(struct mmc_softc *sc, struct mmc_ivars *ivar)
|
||||
}
|
||||
|
||||
static int
|
||||
mmc_set_timing(struct mmc_softc *sc, struct mmc_ivars *ivar, int timing)
|
||||
mmc_set_power_class(struct mmc_softc *sc, struct mmc_ivars *ivar)
|
||||
{
|
||||
device_t dev;
|
||||
const uint8_t *ext_csd;
|
||||
uint32_t clock;
|
||||
uint8_t value;
|
||||
|
||||
dev = sc->dev;
|
||||
if (mmcbr_get_mode(dev) != mode_mmc || ivar->csd.spec_vers < 4)
|
||||
return (MMC_ERR_NONE);
|
||||
|
||||
value = 0;
|
||||
ext_csd = ivar->raw_ext_csd;
|
||||
clock = mmcbr_get_clock(dev);
|
||||
switch (1 << mmcbr_get_vdd(dev)) {
|
||||
case MMC_OCR_LOW_VOLTAGE:
|
||||
if (clock <= MMC_TYPE_HS_26_MAX)
|
||||
value = ext_csd[EXT_CSD_PWR_CL_26_195];
|
||||
else if (clock <= MMC_TYPE_HS_52_MAX) {
|
||||
if (mmcbr_get_timing(dev) >= bus_timing_mmc_ddr52 &&
|
||||
ivar->bus_width >= bus_width_4)
|
||||
value = ext_csd[EXT_CSD_PWR_CL_52_195_DDR];
|
||||
else
|
||||
value = ext_csd[EXT_CSD_PWR_CL_52_195];
|
||||
} else if (clock <= MMC_TYPE_HS200_HS400ES_MAX)
|
||||
value = ext_csd[EXT_CSD_PWR_CL_200_195];
|
||||
break;
|
||||
case MMC_OCR_270_280:
|
||||
case MMC_OCR_280_290:
|
||||
case MMC_OCR_290_300:
|
||||
case MMC_OCR_300_310:
|
||||
case MMC_OCR_310_320:
|
||||
case MMC_OCR_320_330:
|
||||
case MMC_OCR_330_340:
|
||||
case MMC_OCR_340_350:
|
||||
case MMC_OCR_350_360:
|
||||
if (clock <= MMC_TYPE_HS_26_MAX)
|
||||
value = ext_csd[EXT_CSD_PWR_CL_26_360];
|
||||
else if (clock <= MMC_TYPE_HS_52_MAX) {
|
||||
if (mmcbr_get_timing(dev) == bus_timing_mmc_ddr52 &&
|
||||
ivar->bus_width >= bus_width_4)
|
||||
value = ext_csd[EXT_CSD_PWR_CL_52_360_DDR];
|
||||
else
|
||||
value = ext_csd[EXT_CSD_PWR_CL_52_360];
|
||||
} else if (clock <= MMC_TYPE_HS200_HS400ES_MAX) {
|
||||
if (ivar->bus_width == bus_width_8)
|
||||
value = ext_csd[EXT_CSD_PWR_CL_200_360_DDR];
|
||||
else
|
||||
value = ext_csd[EXT_CSD_PWR_CL_200_360];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
device_printf(dev, "No power class support for VDD 0x%x\n",
|
||||
1 << mmcbr_get_vdd(dev));
|
||||
return (MMC_ERR_INVALID);
|
||||
}
|
||||
|
||||
if (ivar->bus_width == bus_width_8)
|
||||
value = (value & EXT_CSD_POWER_CLASS_8BIT_MASK) >>
|
||||
EXT_CSD_POWER_CLASS_8BIT_SHIFT;
|
||||
else
|
||||
value = (value & EXT_CSD_POWER_CLASS_4BIT_MASK) >>
|
||||
EXT_CSD_POWER_CLASS_4BIT_SHIFT;
|
||||
|
||||
if (value == 0)
|
||||
return (MMC_ERR_NONE);
|
||||
|
||||
return (mmc_switch(dev, dev, ivar->rca, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_POWER_CLASS, value, ivar->cmd6_time, true));
|
||||
}
|
||||
|
||||
static int
|
||||
mmc_set_timing(struct mmc_softc *sc, struct mmc_ivars *ivar,
|
||||
enum mmc_bus_timing timing)
|
||||
{
|
||||
u_char switch_res[64];
|
||||
uint8_t value;
|
||||
int err;
|
||||
|
||||
switch (timing) {
|
||||
case bus_timing_normal:
|
||||
value = 0;
|
||||
break;
|
||||
case bus_timing_hs:
|
||||
value = 1;
|
||||
break;
|
||||
default:
|
||||
return (MMC_ERR_INVALID);
|
||||
}
|
||||
if (mmcbr_get_mode(sc->dev) == mode_sd) {
|
||||
switch (timing) {
|
||||
case bus_timing_normal:
|
||||
value = SD_SWITCH_NORMAL_MODE;
|
||||
break;
|
||||
case bus_timing_hs:
|
||||
value = SD_SWITCH_HS_MODE;
|
||||
break;
|
||||
default:
|
||||
return (MMC_ERR_INVALID);
|
||||
}
|
||||
err = mmc_sd_switch(sc, SD_SWITCH_MODE_SET, SD_SWITCH_GROUP1,
|
||||
value, switch_res);
|
||||
if (err != MMC_ERR_NONE)
|
||||
@ -673,6 +806,17 @@ mmc_set_timing(struct mmc_softc *sc, struct mmc_ivars *ivar, int timing)
|
||||
mmcbr_set_timing(sc->dev, timing);
|
||||
mmcbr_update_ios(sc->dev);
|
||||
} else {
|
||||
switch (timing) {
|
||||
case bus_timing_normal:
|
||||
value = EXT_CSD_HS_TIMING_BC;
|
||||
break;
|
||||
case bus_timing_hs:
|
||||
case bus_timing_mmc_ddr52:
|
||||
value = EXT_CSD_HS_TIMING_HS;
|
||||
break;
|
||||
default:
|
||||
return (MMC_ERR_INVALID);
|
||||
}
|
||||
err = mmc_switch(sc->dev, sc->dev, ivar->rca,
|
||||
EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, value,
|
||||
ivar->cmd6_time, false);
|
||||
@ -1166,19 +1310,82 @@ mmc_set_blocklen(struct mmc_softc *sc, uint32_t len)
|
||||
return (err);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
mmc_timing_to_dtr(struct mmc_ivars *ivar, enum mmc_bus_timing timing)
|
||||
{
|
||||
|
||||
switch (timing) {
|
||||
case bus_timing_normal:
|
||||
return (ivar->tran_speed);
|
||||
case bus_timing_hs:
|
||||
return (ivar->hs_tran_speed);
|
||||
case bus_timing_uhs_sdr12:
|
||||
return (SD_SDR12_MAX);
|
||||
case bus_timing_uhs_sdr25:
|
||||
return (SD_SDR25_MAX);
|
||||
case bus_timing_uhs_ddr50:
|
||||
return (SD_DDR50_MAX);
|
||||
case bus_timing_uhs_sdr50:
|
||||
return (SD_SDR50_MAX);
|
||||
case bus_timing_uhs_sdr104:
|
||||
return (SD_SDR104_MAX);
|
||||
case bus_timing_mmc_ddr52:
|
||||
return (MMC_TYPE_DDR52_MAX);
|
||||
case bus_timing_mmc_hs200:
|
||||
case bus_timing_mmc_hs400:
|
||||
case bus_timing_mmc_hs400es:
|
||||
return (MMC_TYPE_HS200_HS400ES_MAX);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static const char *
|
||||
mmc_timing_to_string(enum mmc_bus_timing timing)
|
||||
{
|
||||
|
||||
switch (timing) {
|
||||
case bus_timing_normal:
|
||||
return ("normal speed");
|
||||
case bus_timing_hs:
|
||||
return ("high speed");
|
||||
case bus_timing_uhs_sdr12:
|
||||
case bus_timing_uhs_sdr25:
|
||||
case bus_timing_uhs_sdr50:
|
||||
case bus_timing_uhs_sdr104:
|
||||
return ("single data rate");
|
||||
case bus_timing_uhs_ddr50:
|
||||
case bus_timing_mmc_ddr52:
|
||||
return ("dual data rate");
|
||||
case bus_timing_mmc_hs200:
|
||||
return ("HS200");
|
||||
case bus_timing_mmc_hs400:
|
||||
return ("HS400");
|
||||
case bus_timing_mmc_hs400es:
|
||||
return ("HS400 with enhanced strobe");
|
||||
}
|
||||
return ("");
|
||||
}
|
||||
|
||||
static void
|
||||
mmc_log_card(device_t dev, struct mmc_ivars *ivar, int newcard)
|
||||
{
|
||||
enum mmc_bus_timing max_timing, timing;
|
||||
|
||||
device_printf(dev, "Card at relative address 0x%04x%s:\n",
|
||||
ivar->rca, newcard ? " added" : "");
|
||||
device_printf(dev, " card: %s\n", ivar->card_id_string);
|
||||
device_printf(dev, " bus: %ubit, %uMHz%s\n",
|
||||
max_timing = bus_timing_normal;
|
||||
for (timing = bus_timing_max; timing > bus_timing_normal; timing--) {
|
||||
if (isset(&ivar->timings, timing)) {
|
||||
max_timing = timing;
|
||||
break;
|
||||
}
|
||||
}
|
||||
device_printf(dev, " bus: %ubit, %uMHz (%s timing)\n",
|
||||
(ivar->bus_width == bus_width_1 ? 1 :
|
||||
(ivar->bus_width == bus_width_4 ? 4 : 8)),
|
||||
(ivar->timing == bus_timing_hs ?
|
||||
ivar->hs_tran_speed : ivar->tran_speed) / 1000000,
|
||||
ivar->timing == bus_timing_hs ? ", high speed timing" : "");
|
||||
mmc_timing_to_dtr(ivar, timing) / 1000000,
|
||||
mmc_timing_to_string(timing));
|
||||
device_printf(dev, " memory: %u blocks, erase sector %u blocks%s\n",
|
||||
ivar->sec_count, ivar->erase_sector,
|
||||
ivar->read_only ? ", read-only" : "");
|
||||
@ -1192,10 +1399,11 @@ mmc_discover_cards(struct mmc_softc *sc)
|
||||
struct mmc_ivars *ivar = NULL;
|
||||
device_t *devlist;
|
||||
device_t child;
|
||||
int err, i, devcount, newcard;
|
||||
int devcount, err, host_caps, i, newcard;
|
||||
uint32_t resp, sec_count, status;
|
||||
uint16_t rca = 2;
|
||||
|
||||
host_caps = mmcbr_get_caps(sc->dev);
|
||||
if (bootverbose || mmc_debug)
|
||||
device_printf(sc->dev, "Probing cards\n");
|
||||
while (1) {
|
||||
@ -1235,14 +1443,24 @@ mmc_discover_cards(struct mmc_softc *sc)
|
||||
if (mmcbr_get_ro(sc->dev))
|
||||
ivar->read_only = 1;
|
||||
ivar->bus_width = bus_width_1;
|
||||
ivar->timing = bus_timing_normal;
|
||||
setbit(&ivar->timings, bus_timing_normal);
|
||||
ivar->mode = mmcbr_get_mode(sc->dev);
|
||||
if (ivar->mode == mode_sd) {
|
||||
mmc_decode_cid_sd(ivar->raw_cid, &ivar->cid);
|
||||
mmc_send_relative_addr(sc, &resp);
|
||||
err = mmc_send_relative_addr(sc, &resp);
|
||||
if (err != MMC_ERR_NONE) {
|
||||
device_printf(sc->dev,
|
||||
"Error getting RCA %d\n", err);
|
||||
break;
|
||||
}
|
||||
ivar->rca = resp >> 16;
|
||||
/* Get card CSD. */
|
||||
mmc_send_csd(sc, ivar->rca, ivar->raw_csd);
|
||||
err = mmc_send_csd(sc, ivar->rca, ivar->raw_csd);
|
||||
if (err != MMC_ERR_NONE) {
|
||||
device_printf(sc->dev,
|
||||
"Error getting CSD %d\n", err);
|
||||
break;
|
||||
}
|
||||
if (bootverbose || mmc_debug)
|
||||
device_printf(sc->dev,
|
||||
"%sard detected (CSD %08x%08x%08x%08x)\n",
|
||||
@ -1271,18 +1489,29 @@ mmc_discover_cards(struct mmc_softc *sc)
|
||||
}
|
||||
|
||||
/* Get card SCR. Card must be selected to fetch it. */
|
||||
mmc_select_card(sc, ivar->rca);
|
||||
mmc_app_send_scr(sc, ivar->rca, ivar->raw_scr);
|
||||
err = mmc_select_card(sc, ivar->rca);
|
||||
if (err != MMC_ERR_NONE) {
|
||||
device_printf(sc->dev,
|
||||
"Error selecting card %d\n", err);
|
||||
break;
|
||||
}
|
||||
err = mmc_app_send_scr(sc, ivar->rca, ivar->raw_scr);
|
||||
if (err != MMC_ERR_NONE) {
|
||||
device_printf(sc->dev,
|
||||
"Error reading SCR %d\n", err);
|
||||
break;
|
||||
}
|
||||
mmc_app_decode_scr(ivar->raw_scr, &ivar->scr);
|
||||
/* Get card switch capabilities (command class 10). */
|
||||
if ((ivar->scr.sda_vsn >= 1) &&
|
||||
(ivar->csd.ccc & (1 << 10))) {
|
||||
mmc_sd_switch(sc, SD_SWITCH_MODE_CHECK,
|
||||
err = mmc_sd_switch(sc, SD_SWITCH_MODE_CHECK,
|
||||
SD_SWITCH_GROUP1, SD_SWITCH_NOCHANGE,
|
||||
switch_res);
|
||||
if (switch_res[13] & (1 << SD_SWITCH_HS_MODE)) {
|
||||
ivar->timing = bus_timing_hs;
|
||||
ivar->hs_tran_speed = SD_MAX_HS;
|
||||
if (err == MMC_ERR_NONE &&
|
||||
switch_res[13] & (1 << SD_SWITCH_HS_MODE)) {
|
||||
setbit(&ivar->timings, bus_timing_hs);
|
||||
ivar->hs_tran_speed = SD_HS_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1299,8 +1528,9 @@ mmc_discover_cards(struct mmc_softc *sc)
|
||||
* it is still nice to get that right.
|
||||
*/
|
||||
mmc_select_card(sc, 0);
|
||||
mmc_select_card(sc, ivar->rca);
|
||||
mmc_app_sd_status(sc, ivar->rca, ivar->raw_sd_status);
|
||||
(void)mmc_select_card(sc, ivar->rca);
|
||||
(void)mmc_app_sd_status(sc, ivar->rca,
|
||||
ivar->raw_sd_status);
|
||||
mmc_app_decode_sd_status(ivar->raw_sd_status,
|
||||
&ivar->sd_status);
|
||||
if (ivar->sd_status.au_size != 0) {
|
||||
@ -1308,7 +1538,7 @@ mmc_discover_cards(struct mmc_softc *sc)
|
||||
16 << ivar->sd_status.au_size;
|
||||
}
|
||||
/* Find max supported bus width. */
|
||||
if ((mmcbr_get_caps(sc->dev) & MMC_CAP_4_BIT_DATA) &&
|
||||
if ((host_caps & MMC_CAP_4_BIT_DATA) &&
|
||||
(ivar->scr.bus_widths & SD_SCR_BUS_WIDTH_4))
|
||||
ivar->bus_width = bus_width_4;
|
||||
|
||||
@ -1338,9 +1568,17 @@ mmc_discover_cards(struct mmc_softc *sc)
|
||||
return;
|
||||
}
|
||||
ivar->rca = rca++;
|
||||
mmc_set_relative_addr(sc, ivar->rca);
|
||||
err = mmc_set_relative_addr(sc, ivar->rca);
|
||||
if (err != MMC_ERR_NONE) {
|
||||
device_printf(sc->dev, "Error setting RCA %d\n", err);
|
||||
break;
|
||||
}
|
||||
/* Get card CSD. */
|
||||
mmc_send_csd(sc, ivar->rca, ivar->raw_csd);
|
||||
err = mmc_send_csd(sc, ivar->rca, ivar->raw_csd);
|
||||
if (err != MMC_ERR_NONE) {
|
||||
device_printf(sc->dev, "Error getting CSD %d\n", err);
|
||||
break;
|
||||
}
|
||||
if (bootverbose || mmc_debug)
|
||||
device_printf(sc->dev,
|
||||
"%sard detected (CSD %08x%08x%08x%08x)\n",
|
||||
@ -1366,7 +1604,12 @@ mmc_discover_cards(struct mmc_softc *sc)
|
||||
break;
|
||||
}
|
||||
|
||||
mmc_select_card(sc, ivar->rca);
|
||||
err = mmc_select_card(sc, ivar->rca);
|
||||
if (err != MMC_ERR_NONE) {
|
||||
device_printf(sc->dev, "Error selecting card %d\n",
|
||||
err);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Only MMC >= 4.x devices support EXT_CSD. */
|
||||
if (ivar->csd.spec_vers >= 4) {
|
||||
@ -1386,16 +1629,28 @@ mmc_discover_cards(struct mmc_softc *sc)
|
||||
ivar->sec_count = sec_count;
|
||||
ivar->high_cap = 1;
|
||||
}
|
||||
/* Get card speed in high speed mode. */
|
||||
ivar->timing = bus_timing_hs;
|
||||
if (ivar->raw_ext_csd[EXT_CSD_CARD_TYPE]
|
||||
& EXT_CSD_CARD_TYPE_52)
|
||||
ivar->hs_tran_speed = MMC_TYPE_52_MAX_HS;
|
||||
else if (ivar->raw_ext_csd[EXT_CSD_CARD_TYPE]
|
||||
& EXT_CSD_CARD_TYPE_26)
|
||||
ivar->hs_tran_speed = MMC_TYPE_26_MAX_HS;
|
||||
else
|
||||
ivar->hs_tran_speed = ivar->tran_speed;
|
||||
/* Get device speeds beyond normal mode. */
|
||||
if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
|
||||
EXT_CSD_CARD_TYPE_HS_52) != 0) {
|
||||
setbit(&ivar->timings, bus_timing_hs);
|
||||
ivar->hs_tran_speed = MMC_TYPE_HS_52_MAX;
|
||||
} else if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
|
||||
EXT_CSD_CARD_TYPE_HS_26) != 0) {
|
||||
setbit(&ivar->timings, bus_timing_hs);
|
||||
ivar->hs_tran_speed = MMC_TYPE_HS_26_MAX;
|
||||
}
|
||||
if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
|
||||
EXT_CSD_CARD_TYPE_DDR_52_1_2V) != 0 &&
|
||||
(host_caps & MMC_CAP_SIGNALING_120) != 0) {
|
||||
setbit(&ivar->timings, bus_timing_mmc_ddr52);
|
||||
setbit(&ivar->vccq_120, bus_timing_mmc_ddr52);
|
||||
}
|
||||
if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
|
||||
EXT_CSD_CARD_TYPE_DDR_52_1_8V) != 0 &&
|
||||
(host_caps & MMC_CAP_SIGNALING_180) != 0) {
|
||||
setbit(&ivar->timings, bus_timing_mmc_ddr52);
|
||||
setbit(&ivar->vccq_180, bus_timing_mmc_ddr52);
|
||||
}
|
||||
/*
|
||||
* Determine generic switch timeout (provided in
|
||||
* units of 10 ms), defaulting to 500 ms.
|
||||
@ -1422,9 +1677,6 @@ mmc_discover_cards(struct mmc_softc *sc)
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ivar->bus_width = bus_width_1;
|
||||
ivar->timing = bus_timing_normal;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1548,7 +1800,7 @@ mmc_go_discovery(struct mmc_softc *sc)
|
||||
mmc_idle_cards(sc);
|
||||
} else {
|
||||
mmcbr_set_bus_mode(dev, opendrain);
|
||||
mmcbr_set_clock(dev, CARD_ID_FREQUENCY);
|
||||
mmcbr_set_clock(dev, SD_MMC_CARD_ID_FREQUENCY);
|
||||
mmcbr_update_ios(dev);
|
||||
/* XXX recompute vdd based on new cards? */
|
||||
}
|
||||
@ -1587,42 +1839,59 @@ mmc_calculate_clock(struct mmc_softc *sc)
|
||||
{
|
||||
device_t *kids;
|
||||
struct mmc_ivars *ivar;
|
||||
int i, f_max, max_dtr, max_hs_dtr, max_timing, nkid;
|
||||
int host_caps, i, nkid;
|
||||
uint32_t dtr, max_dtr;
|
||||
enum mmc_bus_timing max_timing, timing;
|
||||
bool changed;
|
||||
|
||||
f_max = mmcbr_get_f_max(sc->dev);
|
||||
max_dtr = max_hs_dtr = f_max;
|
||||
if (mmcbr_get_caps(sc->dev) & MMC_CAP_HSPEED)
|
||||
max_dtr = mmcbr_get_f_max(sc->dev);
|
||||
host_caps = mmcbr_get_caps(sc->dev);
|
||||
if ((host_caps & MMC_CAP_MMC_DDR52) != 0)
|
||||
max_timing = bus_timing_mmc_ddr52;
|
||||
else if ((host_caps & MMC_CAP_HSPEED) != 0)
|
||||
max_timing = bus_timing_hs;
|
||||
else
|
||||
max_timing = bus_timing_normal;
|
||||
if (device_get_children(sc->dev, &kids, &nkid) != 0)
|
||||
panic("can't get children");
|
||||
for (i = 0; i < nkid; i++) {
|
||||
ivar = device_get_ivars(kids[i]);
|
||||
if (ivar->timing < max_timing)
|
||||
max_timing = ivar->timing;
|
||||
if (ivar->tran_speed < max_dtr)
|
||||
max_dtr = ivar->tran_speed;
|
||||
if (ivar->hs_tran_speed < max_hs_dtr)
|
||||
max_hs_dtr = ivar->hs_tran_speed;
|
||||
}
|
||||
do {
|
||||
changed = false;
|
||||
for (i = 0; i < nkid; i++) {
|
||||
ivar = device_get_ivars(kids[i]);
|
||||
if (isclr(&ivar->timings, max_timing)) {
|
||||
for (timing = max_timing; timing >=
|
||||
bus_timing_normal; timing--) {
|
||||
if (isset(&ivar->timings, timing)) {
|
||||
max_timing = timing;
|
||||
break;
|
||||
}
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
dtr = mmc_timing_to_dtr(ivar, max_timing);
|
||||
if (dtr < max_dtr) {
|
||||
max_dtr = dtr;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
} while (changed == true);
|
||||
if (bootverbose || mmc_debug) {
|
||||
device_printf(sc->dev,
|
||||
"setting transfer rate to %d.%03dMHz%s\n",
|
||||
"setting transfer rate to %d.%03dMHz (%s timing)\n",
|
||||
max_dtr / 1000000, (max_dtr / 1000) % 1000,
|
||||
max_timing == bus_timing_hs ? " (high speed timing)" : "");
|
||||
mmc_timing_to_string(max_timing));
|
||||
}
|
||||
for (i = 0; i < nkid; i++) {
|
||||
ivar = device_get_ivars(kids[i]);
|
||||
if (ivar->timing == bus_timing_normal)
|
||||
if ((ivar->timings & ~(1 << bus_timing_normal)) == 0)
|
||||
continue;
|
||||
mmc_select_card(sc, ivar->rca);
|
||||
mmc_set_timing(sc, ivar, max_timing);
|
||||
if (mmc_select_card(sc, ivar->rca) != MMC_ERR_NONE ||
|
||||
mmc_set_timing(sc, ivar, max_timing) != MMC_ERR_NONE)
|
||||
device_printf(sc->dev, "Card at relative address %d "
|
||||
"failed to set timing.\n", ivar->rca);
|
||||
}
|
||||
mmc_select_card(sc, 0);
|
||||
free(kids, M_TEMP);
|
||||
if (max_timing == bus_timing_hs)
|
||||
max_dtr = max_hs_dtr;
|
||||
mmcbr_set_clock(sc->dev, max_dtr);
|
||||
mmcbr_update_ios(sc->dev);
|
||||
return (max_dtr);
|
||||
|
@ -64,6 +64,18 @@
|
||||
|
||||
INTERFACE mmcbr;
|
||||
|
||||
#
|
||||
# Default implementations of some methods.
|
||||
#
|
||||
CODE {
|
||||
static int
|
||||
null_switch_vccq(device_t brdev __unused, device_t reqdev __unused)
|
||||
{
|
||||
|
||||
return (0);
|
||||
}
|
||||
};
|
||||
|
||||
#
|
||||
# Called by the mmcbus to set up the IO pins correctly, the common/core
|
||||
# supply voltage (VDD/VCC) to use for the device, the clock frequency, the
|
||||
@ -74,6 +86,14 @@ METHOD int update_ios {
|
||||
device_t reqdev;
|
||||
};
|
||||
|
||||
#
|
||||
# Called by the mmcbus to switch the signaling voltage (VCCQ).
|
||||
#
|
||||
METHOD int switch_vccq {
|
||||
device_t brdev;
|
||||
device_t reqdev;
|
||||
} DEFAULT null_switch_vccq;
|
||||
|
||||
#
|
||||
# Called by the mmcbus or its children to schedule a mmc request. These
|
||||
# requests are queued. Time passes. The bridge then gets notification
|
||||
|
@ -71,6 +71,7 @@ enum mmcbr_device_ivars {
|
||||
MMCBR_IVAR_OCR,
|
||||
MMCBR_IVAR_POWER_MODE,
|
||||
MMCBR_IVAR_VDD,
|
||||
MMCBR_IVAR_VCCQ,
|
||||
MMCBR_IVAR_CAPS,
|
||||
MMCBR_IVAR_TIMING,
|
||||
MMCBR_IVAR_MAX_DATA,
|
||||
@ -94,6 +95,7 @@ MMCBR_ACCESSOR(mode, MODE, int)
|
||||
MMCBR_ACCESSOR(ocr, OCR, int)
|
||||
MMCBR_ACCESSOR(power_mode, POWER_MODE, int)
|
||||
MMCBR_ACCESSOR(vdd, VDD, int)
|
||||
MMCBR_ACCESSOR(vccq, VCCQ, int)
|
||||
MMCBR_ACCESSOR(caps, CAPS, int)
|
||||
MMCBR_ACCESSOR(timing, TIMING, int)
|
||||
MMCBR_ACCESSOR(max_data, MAX_DATA, int)
|
||||
@ -106,6 +108,13 @@ mmcbr_update_ios(device_t dev)
|
||||
return (MMCBR_UPDATE_IOS(device_get_parent(dev), dev));
|
||||
}
|
||||
|
||||
static int __inline
|
||||
mmcbr_switch_vccq(device_t dev)
|
||||
{
|
||||
|
||||
return (MMCBR_SWITCH_VCCQ(device_get_parent(dev), dev));
|
||||
}
|
||||
|
||||
static int __inline
|
||||
mmcbr_get_ro(device_t dev)
|
||||
{
|
||||
|
@ -209,11 +209,11 @@ struct mmc_request {
|
||||
#define MMC_SET_BLOCKLEN 16
|
||||
#define MMC_READ_SINGLE_BLOCK 17
|
||||
#define MMC_READ_MULTIPLE_BLOCK 18
|
||||
/* reserved: 19 */
|
||||
#define MMC_SEND_TUNING_BLOCK 19
|
||||
#define MMC_SEND_TUNING_BLOCK_HS200 21
|
||||
|
||||
/* Class 3: Stream write commands */
|
||||
#define MMC_WRITE_DAT_UNTIL_STOP 20
|
||||
/* reserved: 21 */
|
||||
/* reserved: 22 */
|
||||
|
||||
/* Class 4: Block oriented write commands */
|
||||
@ -304,16 +304,28 @@ struct mmc_request {
|
||||
#define EXT_CSD_ERASE_GRP_DEF 175 /* R/W */
|
||||
#define EXT_CSD_PART_CONFIG 179 /* R/W */
|
||||
#define EXT_CSD_BUS_WIDTH 183 /* R/W */
|
||||
#define EXT_CSD_STROBE_SUPPORT 184 /* RO */
|
||||
#define EXT_CSD_HS_TIMING 185 /* R/W */
|
||||
#define EXT_CSD_POWER_CLASS 187 /* R/W */
|
||||
#define EXT_CSD_CARD_TYPE 196 /* RO */
|
||||
#define EXT_CSD_DRIVER_STRENGTH 197 /* RO */
|
||||
#define EXT_CSD_REV 192 /* RO */
|
||||
#define EXT_CSD_PART_SWITCH_TO 199 /* RO */
|
||||
#define EXT_CSD_PWR_CL_52_195 200 /* RO */
|
||||
#define EXT_CSD_PWR_CL_26_195 201 /* RO */
|
||||
#define EXT_CSD_PWR_CL_52_360 202 /* RO */
|
||||
#define EXT_CSD_PWR_CL_26_360 203 /* RO */
|
||||
#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
|
||||
#define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */
|
||||
#define EXT_CSD_ERASE_TO_MULT 223 /* RO */
|
||||
#define EXT_CSD_ERASE_GRP_SIZE 224 /* RO */
|
||||
#define EXT_CSD_BOOT_SIZE_MULT 226 /* RO */
|
||||
#define EXT_CSD_PWR_CL_200_195 236 /* RO */
|
||||
#define EXT_CSD_PWR_CL_200_360 237 /* RO */
|
||||
#define EXT_CSD_PWR_CL_52_195_DDR 238 /* RO */
|
||||
#define EXT_CSD_PWR_CL_52_360_DDR 239 /* RO */
|
||||
#define EXT_CSD_GEN_CMD6_TIME 248 /* RO */
|
||||
#define EXT_CSD_PWR_CL_200_360_DDR 253 /* RO */
|
||||
|
||||
/*
|
||||
* EXT_CSD field definitions
|
||||
@ -363,15 +375,38 @@ struct mmc_request {
|
||||
#define EXT_CSD_CMD_SET_SECURE 2
|
||||
#define EXT_CSD_CMD_SET_CPSECURE 4
|
||||
|
||||
#define EXT_CSD_CARD_TYPE_26 1
|
||||
#define EXT_CSD_CARD_TYPE_52 2
|
||||
#define EXT_CSD_HS_TIMING_BC 0
|
||||
#define EXT_CSD_HS_TIMING_HS 1
|
||||
#define EXT_CSD_HS_TIMING_DDR200 2
|
||||
#define EXT_CSD_HS_TIMING_DDR400 3
|
||||
#define EXT_CSD_HS_TIMING_DRV_STR_SHIFT 4
|
||||
|
||||
#define EXT_CSD_POWER_CLASS_8BIT_MASK 0xf0
|
||||
#define EXT_CSD_POWER_CLASS_8BIT_SHIFT 4
|
||||
#define EXT_CSD_POWER_CLASS_4BIT_MASK 0x0f
|
||||
#define EXT_CSD_POWER_CLASS_4BIT_SHIFT 0
|
||||
|
||||
#define EXT_CSD_CARD_TYPE_HS_26 0x0001
|
||||
#define EXT_CSD_CARD_TYPE_HS_52 0x0002
|
||||
#define EXT_CSD_CARD_TYPE_DDR_52_1_8V 0x0004
|
||||
#define EXT_CSD_CARD_TYPE_DDR_52_1_2V 0x0008
|
||||
#define EXT_CSD_CARD_TYPE_HS200_1_8V 0x0010
|
||||
#define EXT_CSD_CARD_TYPE_HS200_1_2V 0x0020
|
||||
#define EXT_CSD_CARD_TYPE_HS400_1_8V 0x0040
|
||||
#define EXT_CSD_CARD_TYPE_HS400_1_2V 0x0080
|
||||
#define EXT_CSD_CARD_TYPE_HS400ES 0x0100
|
||||
|
||||
#define EXT_CSD_BUS_WIDTH_1 0
|
||||
#define EXT_CSD_BUS_WIDTH_4 1
|
||||
#define EXT_CSD_BUS_WIDTH_8 2
|
||||
#define EXT_CSD_BUS_WIDTH_4_DDR 5
|
||||
#define EXT_CSD_BUS_WIDTH_8_DDR 6
|
||||
#define EXT_CSD_BUS_WIDTH_ES 0x80
|
||||
|
||||
#define MMC_TYPE_26_MAX_HS 26000000
|
||||
#define MMC_TYPE_52_MAX_HS 52000000
|
||||
#define MMC_TYPE_HS_26_MAX 26000000
|
||||
#define MMC_TYPE_HS_52_MAX 52000000
|
||||
#define MMC_TYPE_DDR52_MAX 52000000
|
||||
#define MMC_TYPE_HS200_HS400ES_MAX 200000000
|
||||
|
||||
/*
|
||||
* SD bus widths
|
||||
@ -387,12 +422,23 @@ struct mmc_request {
|
||||
#define SD_SWITCH_GROUP1 0
|
||||
#define SD_SWITCH_NORMAL_MODE 0
|
||||
#define SD_SWITCH_HS_MODE 1
|
||||
#define SD_SWITCH_SDR50_MODE 2
|
||||
#define SD_SWITCH_SDR104_MODE 3
|
||||
#define SD_SWITCH_DDR50 4
|
||||
#define SD_SWITCH_NOCHANGE 0xF
|
||||
|
||||
#define SD_CLR_CARD_DETECT 0
|
||||
#define SD_SET_CARD_DETECT 1
|
||||
|
||||
#define SD_MAX_HS 50000000
|
||||
#define SD_HS_MAX 50000000
|
||||
#define SD_DDR50_MAX 50000000
|
||||
#define SD_SDR12_MAX 25000000
|
||||
#define SD_SDR25_MAX 50000000
|
||||
#define SD_SDR50_MAX 100000000
|
||||
#define SD_SDR104_MAX 208000000
|
||||
|
||||
/* Specifications require 400 kHz max. during ID phase. */
|
||||
#define SD_MMC_CARD_ID_FREQUENCY 400000
|
||||
|
||||
/* OCR bits */
|
||||
|
||||
@ -429,6 +475,12 @@ struct mmc_request {
|
||||
#define MMC_OCR_340_350 (1U << 22) /* Vdd voltage 3.40 ~ 3.50 */
|
||||
#define MMC_OCR_350_360 (1U << 23) /* Vdd voltage 3.50 ~ 3.60 */
|
||||
#define MMC_OCR_MAX_VOLTAGE_SHIFT 23
|
||||
#define MMC_OCR_S18R (1U << 24) /* Switching to 1.8 V requested (SD) */
|
||||
#define MMC_OCR_S18A MMC_OCR_S18R /* Switching to 1.8 V accepted (SD) */
|
||||
#define MMC_OCR_XPC (1U << 28) /* SDXC Power Control */
|
||||
#define MMC_OCR_ACCESS_MODE_BYTE (0U << 29) /* Access Mode Byte (MMC) */
|
||||
#define MMC_OCR_ACCESS_MODE_SECT (1U << 29) /* Access Mode Sector (MMC) */
|
||||
#define MMC_OCR_ACCESS_MODE_MASK (3U << 29)
|
||||
#define MMC_OCR_CCS (1u << 30) /* Card Capacity status (SD vs SDHC) */
|
||||
#define MMC_OCR_CARD_BUSY (1U << 31) /* Card Power up status */
|
||||
|
||||
|
@ -57,6 +57,12 @@ SYSCTL_NODE(_hw, OID_AUTO, sdhci, CTLFLAG_RD, 0, "sdhci driver");
|
||||
static int sdhci_debug;
|
||||
SYSCTL_INT(_hw_sdhci, OID_AUTO, debug, CTLFLAG_RWTUN, &sdhci_debug, 0,
|
||||
"Debug level");
|
||||
u_int sdhci_quirk_clear = 0;
|
||||
SYSCTL_INT(_hw_sdhci, OID_AUTO, quirk_clear, CTLFLAG_RWTUN, &sdhci_quirk_clear,
|
||||
0, "Mask of quirks to clear");
|
||||
u_int sdhci_quirk_set = 0;
|
||||
SYSCTL_INT(_hw_sdhci, OID_AUTO, quirk_set, CTLFLAG_RWTUN, &sdhci_quirk_set, 0,
|
||||
"Mask of quirks to set");
|
||||
|
||||
#define RD1(slot, off) SDHCI_READ_1((slot)->bus, (slot), (off))
|
||||
#define RD2(slot, off) SDHCI_READ_2((slot)->bus, (slot), (off))
|
||||
@ -78,6 +84,10 @@ static void sdhci_card_poll(void *);
|
||||
static void sdhci_card_task(void *, int);
|
||||
|
||||
/* helper routines */
|
||||
static void sdhci_dumpregs(struct sdhci_slot *slot);
|
||||
static int slot_printf(struct sdhci_slot *slot, const char * fmt, ...)
|
||||
__printflike(2, 3);
|
||||
|
||||
#define SDHCI_LOCK(_slot) mtx_lock(&(_slot)->mtx)
|
||||
#define SDHCI_UNLOCK(_slot) mtx_unlock(&(_slot)->mtx)
|
||||
#define SDHCI_LOCK_INIT(_slot) \
|
||||
@ -581,7 +591,7 @@ sdhci_card_poll(void *arg)
|
||||
int
|
||||
sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
|
||||
{
|
||||
uint32_t caps, freq;
|
||||
uint32_t caps, caps2, freq, host_caps;
|
||||
int err;
|
||||
|
||||
SDHCI_LOCK_INIT(slot);
|
||||
@ -625,10 +635,16 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
|
||||
sdhci_init(slot);
|
||||
slot->version = (RD2(slot, SDHCI_HOST_VERSION)
|
||||
>> SDHCI_SPEC_VER_SHIFT) & SDHCI_SPEC_VER_MASK;
|
||||
if (slot->quirks & SDHCI_QUIRK_MISSING_CAPS)
|
||||
if (slot->quirks & SDHCI_QUIRK_MISSING_CAPS) {
|
||||
caps = slot->caps;
|
||||
else
|
||||
caps2 = slot->caps2;
|
||||
} else {
|
||||
caps = RD4(slot, SDHCI_CAPABILITIES);
|
||||
if (slot->version >= SDHCI_SPEC_300)
|
||||
caps2 = RD4(slot, SDHCI_CAPABILITIES2);
|
||||
else
|
||||
caps2 = 0;
|
||||
}
|
||||
/* Calculate base clock frequency. */
|
||||
if (slot->version >= SDHCI_SPEC_300)
|
||||
freq = (caps & SDHCI_CLOCK_V3_BASE_MASK) >>
|
||||
@ -684,15 +700,45 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
|
||||
device_printf(dev, "Hardware doesn't report any "
|
||||
"support voltages.\n");
|
||||
}
|
||||
slot->host.caps = MMC_CAP_4_BIT_DATA;
|
||||
host_caps = MMC_CAP_4_BIT_DATA;
|
||||
if (caps & SDHCI_CAN_DO_8BITBUS)
|
||||
slot->host.caps |= MMC_CAP_8_BIT_DATA;
|
||||
host_caps |= MMC_CAP_8_BIT_DATA;
|
||||
if (caps & SDHCI_CAN_DO_HISPD)
|
||||
slot->host.caps |= MMC_CAP_HSPEED;
|
||||
host_caps |= MMC_CAP_HSPEED;
|
||||
if (slot->quirks & SDHCI_QUIRK_BOOT_NOACC)
|
||||
slot->host.caps |= MMC_CAP_BOOT_NOACC;
|
||||
host_caps |= MMC_CAP_BOOT_NOACC;
|
||||
if (slot->quirks & SDHCI_QUIRK_WAIT_WHILE_BUSY)
|
||||
slot->host.caps |= MMC_CAP_WAIT_WHILE_BUSY;
|
||||
host_caps |= MMC_CAP_WAIT_WHILE_BUSY;
|
||||
if (caps2 & (SDHCI_CAN_SDR50 | SDHCI_CAN_SDR104 | SDHCI_CAN_DDR50))
|
||||
host_caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25;
|
||||
if (caps2 & SDHCI_CAN_SDR104) {
|
||||
host_caps |= MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50;
|
||||
if (!(slot->quirks & SDHCI_QUIRK_BROKEN_MMC_HS200))
|
||||
host_caps |= MMC_CAP_MMC_HS200;
|
||||
} else if (caps2 & SDHCI_CAN_SDR50)
|
||||
host_caps |= MMC_CAP_UHS_SDR50;
|
||||
if (caps2 & SDHCI_CAN_DDR50 &&
|
||||
!(slot->quirks & SDHCI_QUIRK_BROKEN_UHS_DDR50))
|
||||
host_caps |= MMC_CAP_UHS_DDR50;
|
||||
if (slot->quirks & SDHCI_QUIRK_MMC_DDR52)
|
||||
host_caps |= MMC_CAP_MMC_DDR52;
|
||||
if (slot->quirks & SDHCI_QUIRK_CAPS_BIT63_FOR_MMC_HS400 &&
|
||||
caps2 & SDHCI_CAN_MMC_HS400)
|
||||
host_caps |= MMC_CAP_MMC_HS400;
|
||||
host_caps |= MMC_CAP_SIGNALING_330;
|
||||
if (host_caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
|
||||
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50 |
|
||||
MMC_CAP_MMC_DDR52_180 | MMC_CAP_MMC_HS200_180 |
|
||||
MMC_CAP_MMC_HS400_180))
|
||||
host_caps |= MMC_CAP_SIGNALING_180;
|
||||
if (caps & SDHCI_CTRL2_DRIVER_TYPE_A)
|
||||
host_caps |= MMC_CAP_DRIVER_TYPE_A;
|
||||
if (caps & SDHCI_CTRL2_DRIVER_TYPE_C)
|
||||
host_caps |= MMC_CAP_DRIVER_TYPE_C;
|
||||
if (caps & SDHCI_CTRL2_DRIVER_TYPE_D)
|
||||
host_caps |= MMC_CAP_DRIVER_TYPE_D;
|
||||
slot->host.caps = host_caps;
|
||||
|
||||
/* Decide if we have usable DMA. */
|
||||
if (caps & SDHCI_CAN_DO_DMA)
|
||||
slot->opt |= SDHCI_HAVE_DMA;
|
||||
@ -712,16 +758,39 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
|
||||
slot->opt &= ~SDHCI_HAVE_DMA;
|
||||
|
||||
if (bootverbose || sdhci_debug) {
|
||||
slot_printf(slot, "%uMHz%s %s%s%s%s %s\n",
|
||||
slot_printf(slot,
|
||||
"%uMHz%s %s VDD:%s%s%s VCCQ: 3.3V%s%s DRV: B%s%s%s %s\n",
|
||||
slot->max_clk / 1000000,
|
||||
(caps & SDHCI_CAN_DO_HISPD) ? " HS" : "",
|
||||
(slot->host.caps & MMC_CAP_8_BIT_DATA) ? "8bits" :
|
||||
((slot->host.caps & MMC_CAP_4_BIT_DATA) ? "4bits" :
|
||||
"1bit"),
|
||||
(host_caps & MMC_CAP_8_BIT_DATA) ? "8bits" :
|
||||
((host_caps & MMC_CAP_4_BIT_DATA) ? "4bits" : "1bit"),
|
||||
(caps & SDHCI_CAN_VDD_330) ? " 3.3V" : "",
|
||||
(caps & SDHCI_CAN_VDD_300) ? " 3.0V" : "",
|
||||
(caps & SDHCI_CAN_VDD_180) ? " 1.8V" : "",
|
||||
(host_caps & MMC_CAP_SIGNALING_180) ? " 1.8V" : "",
|
||||
(host_caps & MMC_CAP_SIGNALING_120) ? " 1.2V" : "",
|
||||
(caps & SDHCI_CTRL2_DRIVER_TYPE_A) ? "A" : "",
|
||||
(caps & SDHCI_CTRL2_DRIVER_TYPE_C) ? "C" : "",
|
||||
(caps & SDHCI_CTRL2_DRIVER_TYPE_D) ? "D" : "",
|
||||
(slot->opt & SDHCI_HAVE_DMA) ? "DMA" : "PIO");
|
||||
if (host_caps & (MMC_CAP_MMC_DDR52 | MMC_CAP_MMC_HS200 |
|
||||
MMC_CAP_MMC_HS400 | MMC_CAP_MMC_ENH_STROBE))
|
||||
slot_printf(slot, "eMMC:%s%s%s%s\n",
|
||||
(host_caps & MMC_CAP_MMC_DDR52) ? " DDR52" : "",
|
||||
(host_caps & MMC_CAP_MMC_HS200) ? " HS200" : "",
|
||||
(host_caps & MMC_CAP_MMC_HS400) ? " HS400" : "",
|
||||
((host_caps &
|
||||
(MMC_CAP_MMC_HS400 | MMC_CAP_MMC_ENH_STROBE)) ==
|
||||
(MMC_CAP_MMC_HS400 | MMC_CAP_MMC_ENH_STROBE)) ?
|
||||
" HS400ES" : "");
|
||||
if (host_caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
|
||||
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104))
|
||||
slot_printf(slot, "UHS-I:%s%s%s%s%s\n",
|
||||
(host_caps & MMC_CAP_UHS_SDR12) ? " SDR12" : "",
|
||||
(host_caps & MMC_CAP_UHS_SDR25) ? " SDR25" : "",
|
||||
(host_caps & MMC_CAP_UHS_SDR50) ? " SDR50" : "",
|
||||
(host_caps & MMC_CAP_UHS_SDR104) ? " SDR104" : "",
|
||||
(host_caps & MMC_CAP_UHS_DDR50) ? " DDR50" : "");
|
||||
sdhci_dumpregs(slot);
|
||||
}
|
||||
|
||||
@ -819,6 +888,38 @@ sdhci_generic_get_card_present(device_t brdev __unused, struct sdhci_slot *slot)
|
||||
return (RD4(slot, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
|
||||
}
|
||||
|
||||
void
|
||||
sdhci_generic_set_uhs_timing(device_t brdev __unused, struct sdhci_slot *slot)
|
||||
{
|
||||
struct mmc_ios *ios;
|
||||
uint16_t hostctrl2;
|
||||
|
||||
if (slot->version < SDHCI_SPEC_300)
|
||||
return;
|
||||
|
||||
ios = &slot->host.ios;
|
||||
sdhci_set_clock(slot, 0);
|
||||
hostctrl2 = RD2(slot, SDHCI_HOST_CONTROL2);
|
||||
hostctrl2 &= ~SDHCI_CTRL2_UHS_MASK;
|
||||
if (ios->timing == bus_timing_mmc_hs400 ||
|
||||
ios->timing == bus_timing_mmc_hs400es)
|
||||
hostctrl2 |= SDHCI_CTRL2_MMC_HS400;
|
||||
else if (ios->clock > SD_SDR50_MAX)
|
||||
hostctrl2 |= SDHCI_CTRL2_UHS_SDR104;
|
||||
else if (ios->clock > SD_SDR25_MAX)
|
||||
hostctrl2 |= SDHCI_CTRL2_UHS_SDR50;
|
||||
else if (ios->clock > SD_SDR12_MAX) {
|
||||
if (ios->timing == bus_timing_uhs_ddr50 ||
|
||||
ios->timing == bus_timing_mmc_ddr52)
|
||||
hostctrl2 |= SDHCI_CTRL2_UHS_DDR50;
|
||||
else
|
||||
hostctrl2 |= SDHCI_CTRL2_UHS_SDR25;
|
||||
} else if (ios->clock > SD_MMC_CARD_ID_FREQUENCY)
|
||||
hostctrl2 |= SDHCI_CTRL2_UHS_SDR12;
|
||||
WR2(slot, SDHCI_HOST_CONTROL2, hostctrl2);
|
||||
sdhci_set_clock(slot, ios->clock);
|
||||
}
|
||||
|
||||
int
|
||||
sdhci_generic_update_ios(device_t brdev, device_t reqdev)
|
||||
{
|
||||
@ -846,12 +947,13 @@ sdhci_generic_update_ios(device_t brdev, device_t reqdev)
|
||||
} else {
|
||||
panic("Invalid bus width: %d", ios->bus_width);
|
||||
}
|
||||
if (ios->timing == bus_timing_hs &&
|
||||
if (ios->clock > SD_SDR12_MAX &&
|
||||
!(slot->quirks & SDHCI_QUIRK_DONT_SET_HISPD_BIT))
|
||||
slot->hostctrl |= SDHCI_CTRL_HISPD;
|
||||
else
|
||||
slot->hostctrl &= ~SDHCI_CTRL_HISPD;
|
||||
WR1(slot, SDHCI_HOST_CONTROL, slot->hostctrl);
|
||||
SDHCI_SET_UHS_TIMING(brdev, slot);
|
||||
/* Some controllers like reset after bus changes. */
|
||||
if (slot->quirks & SDHCI_QUIRK_RESET_ON_IOS)
|
||||
sdhci_reset(slot, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
|
||||
@ -860,6 +962,61 @@ sdhci_generic_update_ios(device_t brdev, device_t reqdev)
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
sdhci_generic_switch_vccq(device_t brdev __unused, device_t reqdev)
|
||||
{
|
||||
struct sdhci_slot *slot = device_get_ivars(reqdev);
|
||||
enum mmc_vccq vccq;
|
||||
int err;
|
||||
uint16_t hostctrl2;
|
||||
|
||||
if (slot->version < SDHCI_SPEC_300)
|
||||
return (0);
|
||||
|
||||
err = 0;
|
||||
vccq = slot->host.ios.vccq;
|
||||
SDHCI_LOCK(slot);
|
||||
sdhci_set_clock(slot, 0);
|
||||
hostctrl2 = RD2(slot, SDHCI_HOST_CONTROL2);
|
||||
switch (vccq) {
|
||||
case vccq_330:
|
||||
if (!(hostctrl2 & SDHCI_CTRL2_S18_ENABLE))
|
||||
goto done;
|
||||
hostctrl2 &= ~SDHCI_CTRL2_S18_ENABLE;
|
||||
WR2(slot, SDHCI_HOST_CONTROL2, hostctrl2);
|
||||
DELAY(5000);
|
||||
hostctrl2 = RD2(slot, SDHCI_HOST_CONTROL2);
|
||||
if (!(hostctrl2 & SDHCI_CTRL2_S18_ENABLE))
|
||||
goto done;
|
||||
err = EAGAIN;
|
||||
break;
|
||||
case vccq_180:
|
||||
if (!(slot->host.caps & MMC_CAP_SIGNALING_180)) {
|
||||
err = EINVAL;
|
||||
goto done;
|
||||
}
|
||||
if (hostctrl2 & SDHCI_CTRL2_S18_ENABLE)
|
||||
goto done;
|
||||
hostctrl2 |= SDHCI_CTRL2_S18_ENABLE;
|
||||
WR2(slot, SDHCI_HOST_CONTROL2, hostctrl2);
|
||||
DELAY(5000);
|
||||
hostctrl2 = RD2(slot, SDHCI_HOST_CONTROL2);
|
||||
if (hostctrl2 & SDHCI_CTRL2_S18_ENABLE)
|
||||
goto done;
|
||||
err = EAGAIN;
|
||||
break;
|
||||
default:
|
||||
slot_printf(slot,
|
||||
"Attempt to set unsupported signaling voltage\n");
|
||||
err = EINVAL;
|
||||
break;
|
||||
}
|
||||
done:
|
||||
sdhci_set_clock(slot, slot->host.ios.clock);
|
||||
SDHCI_UNLOCK(slot);
|
||||
return (err);
|
||||
}
|
||||
|
||||
static void
|
||||
sdhci_req_done(struct sdhci_slot *slot)
|
||||
{
|
||||
@ -1523,6 +1680,9 @@ sdhci_generic_read_ivar(device_t bus, device_t child, int which,
|
||||
case MMCBR_IVAR_VDD:
|
||||
*result = slot->host.ios.vdd;
|
||||
break;
|
||||
case MMCBR_IVAR_VCCQ:
|
||||
*result = slot->host.ios.vccq;
|
||||
break;
|
||||
case MMCBR_IVAR_CAPS:
|
||||
*result = slot->host.caps;
|
||||
break;
|
||||
@ -1599,6 +1759,9 @@ sdhci_generic_write_ivar(device_t bus, device_t child, int which,
|
||||
case MMCBR_IVAR_VDD:
|
||||
slot->host.ios.vdd = value;
|
||||
break;
|
||||
case MMCBR_IVAR_VCCQ:
|
||||
slot->host.ios.vccq = value;
|
||||
break;
|
||||
case MMCBR_IVAR_TIMING:
|
||||
slot->host.ios.timing = value;
|
||||
break;
|
||||
|
@ -77,6 +77,16 @@
|
||||
#define SDHCI_QUIRK_BOOT_NOACC (1 << 21)
|
||||
/* Controller waits for busy responses. */
|
||||
#define SDHCI_QUIRK_WAIT_WHILE_BUSY (1 << 22)
|
||||
/* Controller supports eMMC DDR52 mode. */
|
||||
#define SDHCI_QUIRK_MMC_DDR52 (1 << 23)
|
||||
/* Controller support for UHS DDR50 mode is broken. */
|
||||
#define SDHCI_QUIRK_BROKEN_UHS_DDR50 (1 << 24)
|
||||
/* Controller support for eMMC HS200 mode is broken. */
|
||||
#define SDHCI_QUIRK_BROKEN_MMC_HS200 (1 << 25)
|
||||
/* Controller reports support for eMMC HS400 mode as SDHCI_CAN_MMC_HS400. */
|
||||
#define SDHCI_QUIRK_CAPS_BIT63_FOR_MMC_HS400 (1 << 26)
|
||||
/* Controller support for SDHCI_CTRL2_PRESET_VALUE is broken. */
|
||||
#define SDHCI_QUIRK_PRESET_VALUE_BROKEN (1 << 27)
|
||||
|
||||
/*
|
||||
* Controller registers
|
||||
@ -237,6 +247,7 @@
|
||||
#define SDHCI_CTRL2_UHS_SDR50 0x0002
|
||||
#define SDHCI_CTRL2_UHS_SDR104 0x0003
|
||||
#define SDHCI_CTRL2_UHS_DDR50 0x0004
|
||||
#define SDHCI_CTRL2_MMC_HS400 0x0005 /* non-standard */
|
||||
|
||||
#define SDHCI_CAPABILITIES 0x40
|
||||
#define SDHCI_TIMEOUT_CLK_MASK 0x0000003F
|
||||
@ -276,6 +287,7 @@
|
||||
#define SDHCI_RETUNE_MODES_SHIFT 14
|
||||
#define SDHCI_CLOCK_MULT_MASK 0x00FF0000
|
||||
#define SDHCI_CLOCK_MULT_SHIFT 16
|
||||
#define SDHCI_CAN_MMC_HS400 0x80000000 /* non-standard */
|
||||
|
||||
#define SDHCI_MAX_CURRENT 0x48
|
||||
#define SDHCI_FORCE_AUTO_EVENT 0x50
|
||||
@ -308,9 +320,13 @@
|
||||
|
||||
SYSCTL_DECL(_hw_sdhci);
|
||||
|
||||
extern u_int sdhci_quirk_clear;
|
||||
extern u_int sdhci_quirk_set;
|
||||
|
||||
struct sdhci_slot {
|
||||
u_int quirks; /* Chip specific quirks */
|
||||
u_int caps; /* Override SDHCI_CAPABILITIES */
|
||||
u_int caps2; /* Override SDHCI_CAPABILITIES2 */
|
||||
device_t bus; /* Bus device */
|
||||
device_t dev; /* Slot device */
|
||||
u_char num; /* Slot number */
|
||||
@ -363,6 +379,7 @@ int sdhci_cleanup_slot(struct sdhci_slot *slot);
|
||||
int sdhci_generic_suspend(struct sdhci_slot *slot);
|
||||
int sdhci_generic_resume(struct sdhci_slot *slot);
|
||||
int sdhci_generic_update_ios(device_t brdev, device_t reqdev);
|
||||
int sdhci_generic_switch_vccq(device_t brdev, device_t reqdev);
|
||||
int sdhci_generic_request(device_t brdev, device_t reqdev,
|
||||
struct mmc_request *req);
|
||||
int sdhci_generic_get_ro(device_t brdev, device_t reqdev);
|
||||
@ -371,6 +388,7 @@ int sdhci_generic_release_host(device_t brdev, device_t reqdev);
|
||||
void sdhci_generic_intr(struct sdhci_slot *slot);
|
||||
uint32_t sdhci_generic_min_freq(device_t brdev, struct sdhci_slot *slot);
|
||||
bool sdhci_generic_get_card_present(device_t brdev, struct sdhci_slot *slot);
|
||||
void sdhci_generic_set_uhs_timing(device_t brdev, struct sdhci_slot *slot);
|
||||
void sdhci_handle_card_present(struct sdhci_slot *slot, bool is_present);
|
||||
|
||||
#endif /* __SDHCI_H__ */
|
||||
|
@ -60,11 +60,16 @@ static const struct sdhci_acpi_device {
|
||||
{ "80860F14", 1, "Intel Bay Trail eMMC 4.5 Controller",
|
||||
SDHCI_QUIRK_ALL_SLOTS_NON_REMOVABLE |
|
||||
SDHCI_QUIRK_INTEL_POWER_UP_RESET |
|
||||
SDHCI_QUIRK_WAIT_WHILE_BUSY },
|
||||
SDHCI_QUIRK_WAIT_WHILE_BUSY |
|
||||
SDHCI_QUIRK_MMC_DDR52 |
|
||||
SDHCI_QUIRK_CAPS_BIT63_FOR_MMC_HS400 |
|
||||
SDHCI_QUIRK_PRESET_VALUE_BROKEN },
|
||||
{ "80860F14", 3, "Intel Bay Trail SDXC Controller",
|
||||
SDHCI_QUIRK_WAIT_WHILE_BUSY },
|
||||
SDHCI_QUIRK_WAIT_WHILE_BUSY |
|
||||
SDHCI_QUIRK_PRESET_VALUE_BROKEN },
|
||||
{ "80860F16", 0, "Intel Bay Trail SDXC Controller",
|
||||
SDHCI_QUIRK_WAIT_WHILE_BUSY },
|
||||
SDHCI_QUIRK_WAIT_WHILE_BUSY |
|
||||
SDHCI_QUIRK_PRESET_VALUE_BROKEN },
|
||||
{ NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
@ -244,6 +249,8 @@ sdhci_acpi_attach(device_t dev)
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
sc->quirks &= ~sdhci_quirk_clear;
|
||||
sc->quirks |= sdhci_quirk_set;
|
||||
sc->slot.quirks = sc->quirks;
|
||||
|
||||
err = sdhci_init_slot(dev, &sc->slot, 0);
|
||||
@ -344,12 +351,13 @@ static device_method_t sdhci_methods[] = {
|
||||
|
||||
/* mmcbr_if */
|
||||
DEVMETHOD(mmcbr_update_ios, sdhci_generic_update_ios),
|
||||
DEVMETHOD(mmcbr_switch_vccq, sdhci_generic_switch_vccq),
|
||||
DEVMETHOD(mmcbr_request, sdhci_generic_request),
|
||||
DEVMETHOD(mmcbr_get_ro, sdhci_generic_get_ro),
|
||||
DEVMETHOD(mmcbr_acquire_host, sdhci_generic_acquire_host),
|
||||
DEVMETHOD(mmcbr_release_host, sdhci_generic_release_host),
|
||||
|
||||
/* SDHCI registers accessors */
|
||||
/* SDHCI accessors */
|
||||
DEVMETHOD(sdhci_read_1, sdhci_acpi_read_1),
|
||||
DEVMETHOD(sdhci_read_2, sdhci_acpi_read_2),
|
||||
DEVMETHOD(sdhci_read_4, sdhci_acpi_read_4),
|
||||
@ -358,6 +366,7 @@ static device_method_t sdhci_methods[] = {
|
||||
DEVMETHOD(sdhci_write_2, sdhci_acpi_write_2),
|
||||
DEVMETHOD(sdhci_write_4, sdhci_acpi_write_4),
|
||||
DEVMETHOD(sdhci_write_multi_4, sdhci_acpi_write_multi_4),
|
||||
DEVMETHOD(sdhci_set_uhs_timing, sdhci_generic_set_uhs_timing),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
@ -66,6 +66,15 @@
|
||||
#include <dev/mmc/bridge.h>
|
||||
#include <dev/sdhci/sdhci.h>
|
||||
|
||||
CODE {
|
||||
static void
|
||||
null_set_uhs_timing(device_t brdev __unused,
|
||||
struct sdhci_slot *slot __unused)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
INTERFACE sdhci;
|
||||
|
||||
METHOD uint8_t read_1 {
|
||||
@ -149,3 +158,7 @@ METHOD bool get_card_present {
|
||||
struct sdhci_slot *slot;
|
||||
} DEFAULT sdhci_generic_get_card_present;
|
||||
|
||||
METHOD void set_uhs_timing {
|
||||
device_t brdev;
|
||||
struct sdhci_slot *slot;
|
||||
} DEFAULT null_set_uhs_timing;
|
||||
|
@ -106,26 +106,41 @@ static const struct sdhci_device {
|
||||
{ 0x0f148086, 0xffff, "Intel Bay Trail eMMC 4.5 Controller",
|
||||
SDHCI_QUIRK_ALL_SLOTS_NON_REMOVABLE |
|
||||
SDHCI_QUIRK_INTEL_POWER_UP_RESET |
|
||||
SDHCI_QUIRK_WAIT_WHILE_BUSY },
|
||||
SDHCI_QUIRK_WAIT_WHILE_BUSY |
|
||||
SDHCI_QUIRK_MMC_DDR52 |
|
||||
SDHCI_QUIRK_CAPS_BIT63_FOR_MMC_HS400 |
|
||||
SDHCI_QUIRK_PRESET_VALUE_BROKEN},
|
||||
{ 0x0f158086, 0xffff, "Intel Bay Trail SDXC Controller",
|
||||
SDHCI_QUIRK_WAIT_WHILE_BUSY },
|
||||
SDHCI_QUIRK_WAIT_WHILE_BUSY |
|
||||
SDHCI_QUIRK_PRESET_VALUE_BROKEN },
|
||||
{ 0x0f508086, 0xffff, "Intel Bay Trail eMMC 4.5 Controller",
|
||||
SDHCI_QUIRK_ALL_SLOTS_NON_REMOVABLE |
|
||||
SDHCI_QUIRK_INTEL_POWER_UP_RESET |
|
||||
SDHCI_QUIRK_WAIT_WHILE_BUSY },
|
||||
SDHCI_QUIRK_WAIT_WHILE_BUSY |
|
||||
SDHCI_QUIRK_MMC_DDR52 |
|
||||
SDHCI_QUIRK_CAPS_BIT63_FOR_MMC_HS400 |
|
||||
SDHCI_QUIRK_PRESET_VALUE_BROKEN },
|
||||
{ 0x22948086, 0xffff, "Intel Braswell eMMC 4.5.1 Controller",
|
||||
SDHCI_QUIRK_ALL_SLOTS_NON_REMOVABLE |
|
||||
SDHCI_QUIRK_DATA_TIMEOUT_1MHZ |
|
||||
SDHCI_QUIRK_INTEL_POWER_UP_RESET |
|
||||
SDHCI_QUIRK_WAIT_WHILE_BUSY },
|
||||
SDHCI_QUIRK_WAIT_WHILE_BUSY |
|
||||
SDHCI_QUIRK_MMC_DDR52 |
|
||||
SDHCI_QUIRK_CAPS_BIT63_FOR_MMC_HS400 |
|
||||
SDHCI_QUIRK_PRESET_VALUE_BROKEN },
|
||||
{ 0x22968086, 0xffff, "Intel Braswell SDXC Controller",
|
||||
SDHCI_QUIRK_WAIT_WHILE_BUSY },
|
||||
SDHCI_QUIRK_WAIT_WHILE_BUSY |
|
||||
SDHCI_QUIRK_PRESET_VALUE_BROKEN },
|
||||
{ 0x5aca8086, 0xffff, "Intel Apollo Lake SDXC Controller",
|
||||
SDHCI_QUIRK_WAIT_WHILE_BUSY },
|
||||
SDHCI_QUIRK_WAIT_WHILE_BUSY |
|
||||
SDHCI_QUIRK_PRESET_VALUE_BROKEN },
|
||||
{ 0x5acc8086, 0xffff, "Intel Apollo Lake eMMC 5.0 Controller",
|
||||
SDHCI_QUIRK_ALL_SLOTS_NON_REMOVABLE |
|
||||
SDHCI_QUIRK_INTEL_POWER_UP_RESET |
|
||||
SDHCI_QUIRK_WAIT_WHILE_BUSY },
|
||||
SDHCI_QUIRK_WAIT_WHILE_BUSY |
|
||||
SDHCI_QUIRK_MMC_DDR52 |
|
||||
SDHCI_QUIRK_CAPS_BIT63_FOR_MMC_HS400 |
|
||||
SDHCI_QUIRK_PRESET_VALUE_BROKEN },
|
||||
{ 0, 0xffff, NULL,
|
||||
0 }
|
||||
};
|
||||
@ -323,6 +338,8 @@ sdhci_pci_attach(device_t dev)
|
||||
break;
|
||||
}
|
||||
}
|
||||
sc->quirks &= ~sdhci_quirk_clear;
|
||||
sc->quirks |= sdhci_quirk_set;
|
||||
/* Some controllers need to be bumped into the right mode. */
|
||||
if (sc->quirks & SDHCI_QUIRK_LOWER_FREQUENCY)
|
||||
sdhci_lower_frequency(dev);
|
||||
@ -468,12 +485,13 @@ static device_method_t sdhci_methods[] = {
|
||||
|
||||
/* mmcbr_if */
|
||||
DEVMETHOD(mmcbr_update_ios, sdhci_generic_update_ios),
|
||||
DEVMETHOD(mmcbr_switch_vccq, sdhci_generic_switch_vccq),
|
||||
DEVMETHOD(mmcbr_request, sdhci_generic_request),
|
||||
DEVMETHOD(mmcbr_get_ro, sdhci_generic_get_ro),
|
||||
DEVMETHOD(mmcbr_acquire_host, sdhci_generic_acquire_host),
|
||||
DEVMETHOD(mmcbr_release_host, sdhci_generic_release_host),
|
||||
|
||||
/* SDHCI registers accessors */
|
||||
/* SDHCI accessors */
|
||||
DEVMETHOD(sdhci_read_1, sdhci_pci_read_1),
|
||||
DEVMETHOD(sdhci_read_2, sdhci_pci_read_2),
|
||||
DEVMETHOD(sdhci_read_4, sdhci_pci_read_4),
|
||||
@ -482,6 +500,7 @@ static device_method_t sdhci_methods[] = {
|
||||
DEVMETHOD(sdhci_write_2, sdhci_pci_write_2),
|
||||
DEVMETHOD(sdhci_write_4, sdhci_pci_write_4),
|
||||
DEVMETHOD(sdhci_write_multi_4, sdhci_pci_write_multi_4),
|
||||
DEVMETHOD(sdhci_set_uhs_timing, sdhci_generic_set_uhs_timing),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user