aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/mmc
diff options
context:
space:
mode:
authorMarius Strobl <marius@FreeBSD.org>2017-03-19 23:27:17 +0000
committerMarius Strobl <marius@FreeBSD.org>2017-03-19 23:27:17 +0000
commit0f34084f95f70116d2f38cf7053f0afcea4b5e4f (patch)
tree8e96f65397174a1159f784a1fb4761209cd90b2c /sys/dev/mmc
parentac46d386556cb3ff16dc45099935c18153d95c02 (diff)
Notes
Diffstat (limited to 'sys/dev/mmc')
-rw-r--r--sys/dev/mmc/bridge.h40
-rw-r--r--sys/dev/mmc/mmc.c425
-rw-r--r--sys/dev/mmc/mmcbr_if.m20
-rw-r--r--sys/dev/mmc/mmcbrvar.h9
-rw-r--r--sys/dev/mmc/mmcreg.h66
5 files changed, 473 insertions, 87 deletions
diff --git a/sys/dev/mmc/bridge.h b/sys/dev/mmc/bridge.h
index 4e5e11c5f050..a780ffaeea41 100644
--- a/sys/dev/mmc/bridge.h
+++ b/sys/dev/mmc/bridge.h
@@ -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); \
diff --git a/sys/dev/mmc/mmc.c b/sys/dev/mmc/mmc.c
index 2760bc07525b..af34bd76acbd 100644
--- a/sys/dev/mmc/mmc.c
+++ b/sys/dev/mmc/mmc.c
@@ -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)
{
- u_char switch_res[64];
- uint8_t value;
- int err;
+ device_t dev;
+ const uint8_t *ext_csd;
+ uint32_t clock;
+ uint8_t value;
- switch (timing) {
- case bus_timing_normal:
- value = 0;
+ 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 bus_timing_hs:
- value = 1;
+ 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;
+
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);
diff --git a/sys/dev/mmc/mmcbr_if.m b/sys/dev/mmc/mmcbr_if.m
index b30e5c75fd93..34ffdb031ed7 100644
--- a/sys/dev/mmc/mmcbr_if.m
+++ b/sys/dev/mmc/mmcbr_if.m
@@ -65,6 +65,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
# type of SPI chip select, power mode and bus width.
@@ -75,6 +87,14 @@ METHOD int update_ios {
};
#
+# 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
# of the status of the request, who then notifies the requesting device
diff --git a/sys/dev/mmc/mmcbrvar.h b/sys/dev/mmc/mmcbrvar.h
index f7066c7d2b14..d8f79156b81d 100644
--- a/sys/dev/mmc/mmcbrvar.h
+++ b/sys/dev/mmc/mmcbrvar.h
@@ -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)
@@ -107,6 +109,13 @@ mmcbr_update_ios(device_t 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)
{
diff --git a/sys/dev/mmc/mmcreg.h b/sys/dev/mmc/mmcreg.h
index 202652f44429..359f31d50c78 100644
--- a/sys/dev/mmc/mmcreg.h
+++ b/sys/dev/mmc/mmcreg.h
@@ -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 */