Date: Thu, 16 Mar 2017 22:23:04 +0000 (UTC) From: Marius Strobl <marius@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r315430 - in head: . etc/mtree include sys/arm/ti sys/conf sys/dev/mmc sys/dev/sdhci sys/modules/mmc sys/modules/mmcsd sys/sys Message-ID: <201703162223.v2GMN4F4075490@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: marius Date: Thu Mar 16 22:23:04 2017 New Revision: 315430 URL: https://svnweb.freebsd.org/changeset/base/315430 Log: - Add support for eMMC "partitions". Besides the user data area, i. e. the default partition, eMMC v4.41 and later devices can additionally provide up to: 1 enhanced user data area partition 2 boot partitions 1 RPMB (Replay Protected Memory Block) partition 4 general purpose partitions (optionally with a enhanced or extended attribute) Of these "partitions", only the enhanced user data area one actually slices the user data area partition and, thus, gets handled with the help of geom_flashmap(4). The other types of partitions have address space independent from the default partition and need to be switched to via CMD6 (SWITCH), i. e. constitute a set of additional "disks". The second kind of these "partitions" doesn't fit that well into the design of mmc(4) and mmcsd(4). I've decided to let mmcsd(4) hook all of these "partitions" up as disk(9)'s (except for the RPMB partition as it didn't seem to make much sense to be able to put a file-system there and may require authentication; therefore, RPMB partitions are solely accessible via the newly added IOCTL interface currently; see also below). This approach for one resulted in cleaner code. Second, it retains the notion of mmcsd(4) children corresponding to a single physical device each. With the addition of some layering violations, it also would have been possible for mmc(4) to add separate mmcsd(4) instances with one disk each for all of these "partitions", however. Still, both mmc(4) and mmcsd(4) share some common code now e. g. for issuing CMD6, which has been factored out into mmc_subr.c. Besides simply subdividing eMMC devices, some Intel NUCs having UEFI code in the boot partitions etc., another use case for the partition support is the activation of pseudo-SLC mode, which manufacturers of eMMC chips typically associate with the enhanced user data area and/ or the enhanced attribute of general purpose partitions. CAVEAT EMPTOR: Partitioning eMMC devices is a one-time operation. - Now that properly issuing CMD6 is crucial (so data isn't written to the wrong partition for example), make a step into the direction of correctly handling the timeout for these commands in the MMC layer. Also, do a SEND_STATUS when CMD6 is invoked with an R1B response as recommended by relevant specifications. However, quite some work is left to be done in this regard; all other R1B-type commands done by the MMC layer also should be followed by a SEND_STATUS (CMD13), the erase timeout calculations/handling as documented in specifications are entirely ignored so far, the MMC layer doesn't provide timeouts applicable up to the bridge drivers and at least sdhci(4) currently is hardcoding 1 s as timeout for all command types unconditionally. Let alone already available return codes often not being checked in the MMC layer ... - Add an IOCTL interface to mmcsd(4); this is sufficiently compatible with Linux so that the GNU mmc-utils can be ported to and used with FreeBSD (note that due to the remaining deficiencies outlined above SANITIZE operations issued by/with `mmc` currently most likely will fail). These latter will be added to ports as sysutils/mmc-utils in a bit. Among others, the `mmc` tool of the GNU mmc-utils allows for partitioning eMMC devices (tested working). - For devices following the eMMC specification v4.41 or later, year 0 is 2013 rather than 1997; so correct this for assembling the device ID string properly. - Let mmcsd.ko depend on mmc.ko. Additionally, bump MMC_VERSION as at least for some of the above a matching pair is required. - In the ACPI front-end of sdhci(4) describe the Intel eMMC and SDXC controllers as such in order to match the PCI one. Additionally, in the entry for the 80860F14 SDXC controller remove the eMMC-only SDHCI_QUIRK_INTEL_POWER_UP_RESET. OKed by: imp Submitted by: ian (mmc_switch_status() implementation) Added: head/sys/dev/mmc/mmc_ioctl.h (contents, props changed) head/sys/dev/mmc/mmc_private.h (contents, props changed) head/sys/dev/mmc/mmc_subr.c - copied, changed from r313250, head/sys/dev/mmc/mmc.c head/sys/dev/mmc/mmc_subr.h (contents, props changed) Modified: head/UPDATING head/etc/mtree/BSD.include.dist head/include/Makefile head/sys/arm/ti/ti_sdhci.c head/sys/conf/files head/sys/dev/mmc/bridge.h head/sys/dev/mmc/mmc.c head/sys/dev/mmc/mmcbrvar.h head/sys/dev/mmc/mmcreg.h head/sys/dev/mmc/mmcsd.c head/sys/dev/mmc/mmcvar.h head/sys/dev/sdhci/sdhci.c head/sys/dev/sdhci/sdhci.h head/sys/dev/sdhci/sdhci_acpi.c head/sys/dev/sdhci/sdhci_pci.c head/sys/modules/mmc/Makefile head/sys/modules/mmcsd/Makefile head/sys/sys/param.h Modified: head/UPDATING ============================================================================== --- head/UPDATING Thu Mar 16 22:15:43 2017 (r315429) +++ head/UPDATING Thu Mar 16 22:23:04 2017 (r315430) @@ -51,6 +51,13 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 12 ****************************** SPECIAL WARNING: ****************************** +20170316: + The mmcsd.ko module now additionally depends on geom_flashmap.ko. + Also, mmc.ko and mmcsd.ko need to be a matching pair built from the + same source (previously, the dependency of mmcsd.ko on mmc.ko was + missing, but mmcsd.ko now will refuse to load if it is incompatible + with mmc.ko). + 20170315: The syntax of ipfw(8) named states was changed to avoid ambiguity. If you have used named states in the firewall rules, you need to modify Modified: head/etc/mtree/BSD.include.dist ============================================================================== --- head/etc/mtree/BSD.include.dist Thu Mar 16 22:15:43 2017 (r315429) +++ head/etc/mtree/BSD.include.dist Thu Mar 16 22:23:04 2017 (r315430) @@ -130,6 +130,8 @@ .. mfi .. + mmc + .. mpt mpilib .. Modified: head/include/Makefile ============================================================================== --- head/include/Makefile Thu Mar 16 22:15:43 2017 (r315429) +++ head/include/Makefile Thu Mar 16 22:23:04 2017 (r315430) @@ -45,7 +45,7 @@ LDIRS= bsm cam geom net net80211 netgrap LSUBDIRS= cam/ata cam/nvme cam/scsi \ dev/acpica dev/agp dev/an dev/bktr dev/ciss dev/filemon dev/firewire \ dev/hwpmc dev/hyperv \ - dev/ic dev/iicbus dev/io dev/lmc dev/mfi dev/nvme \ + dev/ic dev/iicbus dev/io dev/lmc dev/mfi dev/mmc dev/nvme \ dev/ofw dev/pbio dev/pci ${_dev_powermac_nvram} dev/ppbus dev/smbus \ dev/speaker dev/utopia dev/vkbd dev/wi \ fs/devfs fs/fdescfs fs/msdosfs fs/nandfs fs/nfs fs/nullfs \ Modified: head/sys/arm/ti/ti_sdhci.c ============================================================================== --- head/sys/arm/ti/ti_sdhci.c Thu Mar 16 22:15:43 2017 (r315429) +++ head/sys/arm/ti/ti_sdhci.c Thu Mar 16 22:23:04 2017 (r315430) @@ -606,6 +606,11 @@ ti_sdhci_attach(device_t dev) * before waiting to see them de-asserted. */ sc->slot.quirks |= SDHCI_QUIRK_WAITFOR_RESET_ASSERTED; + + /* + * The controller waits for busy responses. + */ + sc->slot.quirks |= SDHCI_QUIRK_WAIT_WHILE_BUSY; /* * DMA is not really broken, I just haven't implemented it yet. Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Thu Mar 16 22:15:43 2017 (r315429) +++ head/sys/conf/files Thu Mar 16 22:23:04 2017 (r315430) @@ -2218,6 +2218,7 @@ dev/mlx/mlx.c optional mlx dev/mlx/mlx_disk.c optional mlx dev/mlx/mlx_pci.c optional mlx pci dev/mly/mly.c optional mly +dev/mmc/mmc_subr.c optional mmc | mmcsd dev/mmc/mmc.c optional mmc dev/mmc/mmcbr_if.m standard dev/mmc/mmcbus_if.m standard @@ -3429,7 +3430,7 @@ geom/geom_disk.c standard geom/geom_dump.c standard geom/geom_event.c standard geom/geom_fox.c optional geom_fox -geom/geom_flashmap.c optional fdt cfi | fdt nand | fdt mx25l +geom/geom_flashmap.c optional fdt cfi | fdt nand | fdt mx25l | mmcsd geom/geom_io.c standard geom/geom_kern.c standard geom/geom_map.c optional geom_map Modified: head/sys/dev/mmc/bridge.h ============================================================================== --- head/sys/dev/mmc/bridge.h Thu Mar 16 22:15:43 2017 (r315429) +++ head/sys/dev/mmc/bridge.h Thu Mar 16 22:23:04 2017 (r315430) @@ -132,6 +132,8 @@ struct mmc_host { #define MMC_CAP_4_BIT_DATA (1 << 0) /* Can do 4-bit data transfers */ #define MMC_CAP_8_BIT_DATA (1 << 1) /* Can do 8-bit data transfers */ #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 */ enum mmc_card_mode mode; struct mmc_ios ios; /* Current state of the host */ }; @@ -139,10 +141,12 @@ struct mmc_host { extern driver_t mmc_driver; extern devclass_t mmc_devclass; -#define MMC_VERSION 1 +#define MMC_VERSION 2 #define MMC_DECLARE_BRIDGE(name) \ DRIVER_MODULE(mmc, name, mmc_driver, mmc_devclass, NULL, NULL); \ MODULE_DEPEND(name, mmc, MMC_VERSION, MMC_VERSION, MMC_VERSION); +#define MMC_DEPEND(name) \ + MODULE_DEPEND(name, mmc, MMC_VERSION, MMC_VERSION, MMC_VERSION); #endif /* DEV_MMC_BRIDGE_H */ Modified: head/sys/dev/mmc/mmc.c ============================================================================== --- head/sys/dev/mmc/mmc.c Thu Mar 16 22:15:43 2017 (r315429) +++ head/sys/dev/mmc/mmc.c Thu Mar 16 22:23:04 2017 (r315430) @@ -65,25 +65,16 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <sys/time.h> +#include <dev/mmc/bridge.h> +#include <dev/mmc/mmc_private.h> +#include <dev/mmc/mmc_subr.h> #include <dev/mmc/mmcreg.h> #include <dev/mmc/mmcbrvar.h> #include <dev/mmc/mmcvar.h> + #include "mmcbr_if.h" #include "mmcbus_if.h" -struct mmc_softc { - device_t dev; - struct mtx sc_mtx; - struct intr_config_hook config_intrhook; - device_t owner; - uint32_t last_rca; - int squelched; /* suppress reporting of (expected) errors */ - int log_count; - struct timeval log_time; -}; - -#define LOG_PPS 5 /* Log no more than 5 errors per second. */ - /* * Per-card data */ @@ -91,7 +82,7 @@ struct mmc_ivars { uint32_t raw_cid[4]; /* Raw bits of the CID */ uint32_t raw_csd[4]; /* Raw bits of the CSD */ uint32_t raw_scr[2]; /* Raw bits of the SCR */ - uint8_t raw_ext_csd[512]; /* Raw bits of the EXT_CSD */ + uint8_t raw_ext_csd[MMC_EXTCSD_SIZE]; /* Raw bits of the EXT_CSD */ uint32_t raw_sd_status[16]; /* Raw bits of the SD_STATUS */ uint16_t rca; enum mmc_card_mode mode; @@ -107,6 +98,7 @@ struct mmc_ivars { 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 */ + uint32_t cmd6_time; /* Generic switch timeout [us] */ char card_id_string[64];/* Formatted CID info (serial, MFG, etc) */ char card_sn_string[16];/* Formatted serial # for disk->d_ident */ }; @@ -156,7 +148,8 @@ static int mmc_app_sd_status(struct mmc_ static int mmc_app_send_scr(struct mmc_softc *sc, uint16_t rca, uint32_t *rawscr); static int mmc_calculate_clock(struct mmc_softc *sc); -static void mmc_decode_cid_mmc(uint32_t *raw_cid, struct mmc_cid *cid); +static void mmc_decode_cid_mmc(uint32_t *raw_cid, struct mmc_cid *cid, + bool is_4_41p); static void mmc_decode_cid_sd(uint32_t *raw_cid, struct mmc_cid *cid); static void mmc_decode_csd_mmc(uint32_t *raw_csd, struct mmc_csd *csd); static void mmc_decode_csd_sd(uint32_t *raw_csd, struct mmc_csd *csd); @@ -182,25 +175,17 @@ static uint32_t mmc_select_vdd(struct mm static int mmc_send_app_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr); static int mmc_send_csd(struct mmc_softc *sc, uint16_t rca, uint32_t *rawcsd); -static int mmc_send_ext_csd(struct mmc_softc *sc, uint8_t *rawextcsd); static int mmc_send_if_cond(struct mmc_softc *sc, uint8_t vhs); 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_send_status(struct mmc_softc *sc, uint16_t rca, - uint32_t *status); static int mmc_set_blocklen(struct mmc_softc *sc, uint32_t len); -static int mmc_set_card_bus_width(struct mmc_softc *sc, uint16_t rca, - int width); +static int mmc_set_card_bus_width(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, int timing); -static int mmc_switch(struct mmc_softc *sc, uint8_t set, uint8_t index, - uint8_t value); +static int mmc_set_timing(struct mmc_softc *sc, struct mmc_ivars *ivar, + int timing); static int mmc_test_bus_width(struct mmc_softc *sc); -static int mmc_wait_for_app_cmd(struct mmc_softc *sc, uint32_t rca, - struct mmc_command *cmd, int retries); -static int mmc_wait_for_cmd(struct mmc_softc *sc, struct mmc_command *cmd, - int retries); 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); @@ -299,19 +284,19 @@ mmc_acquire_bus(device_t busdev, device_ * unselect unless the bus code itself wants the mmc * bus, and constantly reselecting causes problems. */ - rca = mmc_get_rca(dev); + ivar = device_get_ivars(dev); + rca = ivar->rca; if (sc->last_rca != rca) { mmc_select_card(sc, rca); sc->last_rca = rca; /* Prepare bus width for the new card. */ - ivar = device_get_ivars(dev); if (bootverbose || mmc_debug) { device_printf(busdev, "setting bus width to %d bits\n", (ivar->bus_width == bus_width_4) ? 4 : (ivar->bus_width == bus_width_8) ? 8 : 1); } - mmc_set_card_bus_width(sc, rca, ivar->bus_width); + mmc_set_card_bus_width(sc, ivar); mmcbr_set_bus_width(busdev, ivar->bus_width); mmcbr_update_ios(busdev); } @@ -417,74 +402,6 @@ mmc_wait_for_request(device_t brdev, dev } static int -mmc_wait_for_cmd(struct mmc_softc *sc, struct mmc_command *cmd, int retries) -{ - struct mmc_request mreq; - int err; - - do { - memset(&mreq, 0, sizeof(mreq)); - memset(cmd->resp, 0, sizeof(cmd->resp)); - cmd->retries = 0; /* Retries done here, not in hardware. */ - cmd->mrq = &mreq; - mreq.cmd = cmd; - if (mmc_wait_for_req(sc, &mreq) != 0) - err = MMC_ERR_FAILED; - else - err = cmd->error; - } while (err != MMC_ERR_NONE && retries-- > 0); - - if (err != MMC_ERR_NONE && sc->squelched == 0) { - if (ppsratecheck(&sc->log_time, &sc->log_count, LOG_PPS)) { - device_printf(sc->dev, "CMD%d failed, RESULT: %d\n", - cmd->opcode, err); - } - } - - return (err); -} - -static int -mmc_wait_for_app_cmd(struct mmc_softc *sc, uint32_t rca, - struct mmc_command *cmd, int retries) -{ - struct mmc_command appcmd; - int err; - - /* Squelch error reporting at lower levels, we report below. */ - sc->squelched++; - do { - memset(&appcmd, 0, sizeof(appcmd)); - appcmd.opcode = MMC_APP_CMD; - appcmd.arg = rca << 16; - appcmd.flags = MMC_RSP_R1 | MMC_CMD_AC; - appcmd.data = NULL; - if (mmc_wait_for_cmd(sc, &appcmd, 0) != 0) - err = MMC_ERR_FAILED; - else - err = appcmd.error; - if (err == MMC_ERR_NONE) { - if (!(appcmd.resp[0] & R1_APP_CMD)) - err = MMC_ERR_FAILED; - else if (mmc_wait_for_cmd(sc, cmd, 0) != 0) - err = MMC_ERR_FAILED; - else - err = cmd->error; - } - } while (err != MMC_ERR_NONE && retries-- > 0); - sc->squelched--; - - if (err != MMC_ERR_NONE && sc->squelched == 0) { - if (ppsratecheck(&sc->log_time, &sc->log_count, LOG_PPS)) { - device_printf(sc->dev, "ACMD%d failed, RESULT: %d\n", - cmd->opcode, err); - } - } - - return (err); -} - -static int mmc_wait_for_command(struct mmc_softc *sc, uint32_t opcode, uint32_t arg, uint32_t flags, uint32_t *resp, int retries) { @@ -496,7 +413,7 @@ mmc_wait_for_command(struct mmc_softc *s cmd.arg = arg; cmd.flags = flags; cmd.data = NULL; - err = mmc_wait_for_cmd(sc, &cmd, retries); + err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, retries); if (err) return (err); if (resp) { @@ -524,7 +441,7 @@ mmc_idle_cards(struct mmc_softc *sc) cmd.arg = 0; cmd.flags = MMC_RSP_NONE | MMC_CMD_BC; cmd.data = NULL; - mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); + mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); mmc_ms_delay(1); mmcbr_set_chip_select(dev, cs_dontcare); @@ -545,7 +462,8 @@ mmc_send_app_op_cond(struct mmc_softc *s cmd.data = NULL; for (i = 0; i < 1000; i++) { - err = mmc_wait_for_app_cmd(sc, 0, &cmd, CMD_RETRIES); + err = mmc_wait_for_app_cmd(sc->dev, sc->dev, 0, &cmd, + CMD_RETRIES); if (err != MMC_ERR_NONE) break; if ((cmd.resp[0] & MMC_OCR_CARD_BUSY) || @@ -572,7 +490,7 @@ mmc_send_op_cond(struct mmc_softc *sc, u cmd.data = NULL; for (i = 0; i < 1000; i++) { - err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); + err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); if (err != MMC_ERR_NONE) break; if ((cmd.resp[0] & MMC_OCR_CARD_BUSY) || @@ -598,7 +516,7 @@ mmc_send_if_cond(struct mmc_softc *sc, u cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR; cmd.data = NULL; - err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); + err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); return (err); } @@ -649,24 +567,6 @@ mmc_select_card(struct mmc_softc *sc, ui } static int -mmc_switch(struct mmc_softc *sc, uint8_t set, uint8_t index, uint8_t value) -{ - struct mmc_command cmd; - int err; - - memset(&cmd, 0, sizeof(cmd)); - cmd.opcode = MMC_SWITCH_FUNC; - cmd.arg = (MMC_SWITCH_FUNC_WR << 24) | - (index << 16) | - (value << 8) | - set; - cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; - cmd.data = NULL; - err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); - return (err); -} - -static int mmc_sd_switch(struct mmc_softc *sc, uint8_t mode, uint8_t grp, uint8_t value, uint8_t *res) { @@ -690,12 +590,12 @@ mmc_sd_switch(struct mmc_softc *sc, uint data.len = 64; data.flags = MMC_DATA_READ; - err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); + err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); return (err); } static int -mmc_set_card_bus_width(struct mmc_softc *sc, uint16_t rca, int width) +mmc_set_card_bus_width(struct mmc_softc *sc, struct mmc_ivars *ivar) { struct mmc_command cmd; int err; @@ -706,13 +606,14 @@ mmc_set_card_bus_width(struct mmc_softc cmd.opcode = ACMD_SET_CLR_CARD_DETECT; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; cmd.arg = SD_CLR_CARD_DETECT; - err = mmc_wait_for_app_cmd(sc, rca, &cmd, CMD_RETRIES); + err = mmc_wait_for_app_cmd(sc->dev, sc->dev, ivar->rca, &cmd, + CMD_RETRIES); if (err != 0) return (err); memset(&cmd, 0, sizeof(cmd)); cmd.opcode = ACMD_SET_BUS_WIDTH; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; - switch (width) { + switch (ivar->bus_width) { case bus_width_1: cmd.arg = SD_BUS_WIDTH_1; break; @@ -722,9 +623,10 @@ mmc_set_card_bus_width(struct mmc_softc default: return (MMC_ERR_INVALID); } - err = mmc_wait_for_app_cmd(sc, rca, &cmd, CMD_RETRIES); + err = mmc_wait_for_app_cmd(sc->dev, sc->dev, ivar->rca, &cmd, + CMD_RETRIES); } else { - switch (width) { + switch (ivar->bus_width) { case bus_width_1: value = EXT_CSD_BUS_WIDTH_1; break; @@ -737,18 +639,19 @@ mmc_set_card_bus_width(struct mmc_softc default: return (MMC_ERR_INVALID); } - err = mmc_switch(sc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, - value); + err = mmc_switch(sc->dev, sc->dev, ivar->rca, + EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, value, + ivar->cmd6_time, true); } return (err); } static int -mmc_set_timing(struct mmc_softc *sc, int timing) +mmc_set_timing(struct mmc_softc *sc, struct mmc_ivars *ivar, int timing) { u_char switch_res[64]; - int err; uint8_t value; + int err; switch (timing) { case bus_timing_normal: @@ -760,12 +663,26 @@ mmc_set_timing(struct mmc_softc *sc, int default: return (MMC_ERR_INVALID); } - if (mmcbr_get_mode(sc->dev) == mode_sd) + if (mmcbr_get_mode(sc->dev) == mode_sd) { err = mmc_sd_switch(sc, SD_SWITCH_MODE_SET, SD_SWITCH_GROUP1, value, switch_res); - else - err = mmc_switch(sc, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_HS_TIMING, value); + if (err != MMC_ERR_NONE) + return (err); + if ((switch_res[16] & 0xf) != value) + return (MMC_ERR_FAILED); + mmcbr_set_timing(sc->dev, timing); + mmcbr_update_ios(sc->dev); + } else { + err = mmc_switch(sc->dev, sc->dev, ivar->rca, + EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, value, + ivar->cmd6_time, false); + if (err != MMC_ERR_NONE) + return (err); + mmcbr_set_timing(sc->dev, timing); + mmcbr_update_ios(sc->dev); + err = mmc_switch_status(sc->dev, sc->dev, ivar->rca, + ivar->cmd6_time); + } return (err); } @@ -808,7 +725,7 @@ mmc_test_bus_width(struct mmc_softc *sc) data.data = __DECONST(void *, p8); data.len = 8; data.flags = MMC_DATA_WRITE; - mmc_wait_for_cmd(sc, &cmd, 0); + mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, 0); memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); @@ -820,7 +737,7 @@ mmc_test_bus_width(struct mmc_softc *sc) data.data = buf; data.len = 8; data.flags = MMC_DATA_READ; - err = mmc_wait_for_cmd(sc, &cmd, 0); + err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, 0); sc->squelched--; mmcbr_set_bus_width(sc->dev, bus_width_1); @@ -845,7 +762,7 @@ mmc_test_bus_width(struct mmc_softc *sc) data.data = __DECONST(void *, p4); data.len = 4; data.flags = MMC_DATA_WRITE; - mmc_wait_for_cmd(sc, &cmd, 0); + mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, 0); memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); @@ -857,7 +774,7 @@ mmc_test_bus_width(struct mmc_softc *sc) data.data = buf; data.len = 4; data.flags = MMC_DATA_READ; - err = mmc_wait_for_cmd(sc, &cmd, 0); + err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, 0); sc->squelched--; mmcbr_set_bus_width(sc->dev, bus_width_1); @@ -899,7 +816,7 @@ mmc_decode_cid_sd(uint32_t *raw_cid, str } static void -mmc_decode_cid_mmc(uint32_t *raw_cid, struct mmc_cid *cid) +mmc_decode_cid_mmc(uint32_t *raw_cid, struct mmc_cid *cid, bool is_4_41p) { int i; @@ -913,7 +830,11 @@ mmc_decode_cid_mmc(uint32_t *raw_cid, st cid->prv = mmc_get_bits(raw_cid, 128, 48, 8); cid->psn = mmc_get_bits(raw_cid, 128, 16, 32); cid->mdt_month = mmc_get_bits(raw_cid, 128, 12, 4); - cid->mdt_year = mmc_get_bits(raw_cid, 128, 8, 4) + 1997; + cid->mdt_year = mmc_get_bits(raw_cid, 128, 8, 4); + if (is_4_41p) + cid->mdt_year += 2013; + else + cid->mdt_year += 1997; } static void @@ -1125,7 +1046,7 @@ mmc_all_send_cid(struct mmc_softc *sc, u cmd.arg = 0; cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR; cmd.data = NULL; - err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); + err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); memcpy(rawcid, cmd.resp, 4 * sizeof(uint32_t)); return (err); } @@ -1141,7 +1062,7 @@ mmc_send_csd(struct mmc_softc *sc, uint1 cmd.arg = rca << 16; cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR; cmd.data = NULL; - err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); + err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); memcpy(rawcsd, cmd.resp, 4 * sizeof(uint32_t)); return (err); } @@ -1166,37 +1087,13 @@ mmc_app_send_scr(struct mmc_softc *sc, u data.len = 8; data.flags = MMC_DATA_READ; - err = mmc_wait_for_app_cmd(sc, rca, &cmd, CMD_RETRIES); + err = mmc_wait_for_app_cmd(sc->dev, sc->dev, rca, &cmd, CMD_RETRIES); rawscr[0] = be32toh(rawscr[0]); rawscr[1] = be32toh(rawscr[1]); return (err); } static int -mmc_send_ext_csd(struct mmc_softc *sc, uint8_t *rawextcsd) -{ - struct mmc_command cmd; - struct mmc_data data; - int err; - - memset(&cmd, 0, sizeof(cmd)); - memset(&data, 0, sizeof(data)); - - memset(rawextcsd, 0, 512); - cmd.opcode = MMC_SEND_EXT_CSD; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; - cmd.arg = 0; - cmd.data = &data; - - data.data = rawextcsd; - data.len = 512; - data.flags = MMC_DATA_READ; - - err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); - return (err); -} - -static int mmc_app_sd_status(struct mmc_softc *sc, uint16_t rca, uint32_t *rawsdstatus) { struct mmc_command cmd; @@ -1216,7 +1113,7 @@ mmc_app_sd_status(struct mmc_softc *sc, data.len = 64; data.flags = MMC_DATA_READ; - err = mmc_wait_for_app_cmd(sc, rca, &cmd, CMD_RETRIES); + err = mmc_wait_for_app_cmd(sc->dev, sc->dev, rca, &cmd, CMD_RETRIES); for (i = 0; i < 16; i++) rawsdstatus[i] = be32toh(rawsdstatus[i]); return (err); @@ -1233,7 +1130,7 @@ mmc_set_relative_addr(struct mmc_softc * cmd.arg = resp << 16; cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR; cmd.data = NULL; - err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); + err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); return (err); } @@ -1248,28 +1145,12 @@ mmc_send_relative_addr(struct mmc_softc cmd.arg = 0; cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR; cmd.data = NULL; - err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); + err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); *resp = cmd.resp[0]; return (err); } static int -mmc_send_status(struct mmc_softc *sc, uint16_t rca, uint32_t *status) -{ - struct mmc_command cmd; - int err; - - memset(&cmd, 0, sizeof(cmd)); - cmd.opcode = MMC_SEND_STATUS; - cmd.arg = rca << 16; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; - cmd.data = NULL; - err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); - *status = cmd.resp[0]; - return (err); -} - -static int mmc_set_blocklen(struct mmc_softc *sc, uint32_t len) { struct mmc_command cmd; @@ -1280,13 +1161,14 @@ mmc_set_blocklen(struct mmc_softc *sc, u cmd.arg = len; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; cmd.data = NULL; - err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); + err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); return (err); } static void mmc_log_card(device_t dev, struct mmc_ivars *ivar, int newcard) { + 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); @@ -1374,7 +1256,8 @@ mmc_discover_cards(struct mmc_softc *sc) ivar->erase_sector = ivar->csd.erase_sector * ivar->csd.write_bl_len / MMC_SECTOR_SIZE; - err = mmc_send_status(sc, ivar->rca, &status); + err = mmc_send_status(sc->dev, sc->dev, ivar->rca, + &status); if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error reading card status %d\n", err); @@ -1386,7 +1269,7 @@ mmc_discover_cards(struct mmc_softc *sc) break; } - /* Get card SCR. Card must be selected to fetch it. */ + /* 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); mmc_app_decode_scr(ivar->raw_scr, &ivar->scr); @@ -1396,7 +1279,7 @@ mmc_discover_cards(struct mmc_softc *sc) mmc_sd_switch(sc, SD_SWITCH_MODE_CHECK, SD_SWITCH_GROUP1, SD_SWITCH_NOCHANGE, switch_res); - if (switch_res[13] & 2) { + if (switch_res[13] & (1 << SD_SWITCH_HS_MODE)) { ivar->timing = bus_timing_hs; ivar->hs_tran_speed = SD_MAX_HS; } @@ -1453,7 +1336,6 @@ mmc_discover_cards(struct mmc_softc *sc) mmc_select_card(sc, 0); return; } - mmc_decode_cid_mmc(ivar->raw_cid, &ivar->cid); ivar->rca = rca++; mmc_set_relative_addr(sc, ivar->rca); /* Get card CSD. */ @@ -1471,7 +1353,7 @@ mmc_discover_cards(struct mmc_softc *sc) ivar->erase_sector = ivar->csd.erase_sector * ivar->csd.write_bl_len / MMC_SECTOR_SIZE; - err = mmc_send_status(sc, ivar->rca, &status); + err = mmc_send_status(sc->dev, sc->dev, ivar->rca, &status); if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error reading card status %d\n", err); @@ -1485,9 +1367,15 @@ mmc_discover_cards(struct mmc_softc *sc) mmc_select_card(sc, ivar->rca); - /* Only MMC >= 4.x cards support EXT_CSD. */ + /* Only MMC >= 4.x devices support EXT_CSD. */ if (ivar->csd.spec_vers >= 4) { - mmc_send_ext_csd(sc, ivar->raw_ext_csd); + err = mmc_send_ext_csd(sc->dev, sc->dev, + ivar->raw_ext_csd); + if (err != MMC_ERR_NONE) { + device_printf(sc->dev, + "Error reading EXT_CSD %d\n", err); + break; + } /* Handle extended capacity from EXT_CSD */ sec_count = ivar->raw_ext_csd[EXT_CSD_SEC_CNT] + (ivar->raw_ext_csd[EXT_CSD_SEC_CNT + 1] << 8) + @@ -1507,14 +1395,31 @@ mmc_discover_cards(struct mmc_softc *sc) ivar->hs_tran_speed = MMC_TYPE_26_MAX_HS; else ivar->hs_tran_speed = ivar->tran_speed; + /* + * Determine generic switch timeout (provided in + * units of 10 ms), defaulting to 500 ms. + */ + ivar->cmd6_time = 500 * 1000; + if (ivar->csd.spec_vers >= 6) + ivar->cmd6_time = 10 * + ivar->raw_ext_csd[EXT_CSD_GEN_CMD6_TIME]; /* Find max supported bus width. */ ivar->bus_width = mmc_test_bus_width(sc); /* Handle HC erase sector size. */ if (ivar->raw_ext_csd[EXT_CSD_ERASE_GRP_SIZE] != 0) { ivar->erase_sector = 1024 * ivar->raw_ext_csd[EXT_CSD_ERASE_GRP_SIZE]; - mmc_switch(sc, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_ERASE_GRP_DEF, 1); + err = mmc_switch(sc->dev, sc->dev, ivar->rca, + EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_ERASE_GRP_DEF, + EXT_CSD_ERASE_GRP_DEF_EN, + ivar->cmd6_time, true); + if (err != MMC_ERR_NONE) { + device_printf(sc->dev, + "Error setting erase group %d\n", + err); + break; + } } } else { ivar->bus_width = bus_width_1; @@ -1533,6 +1438,8 @@ mmc_discover_cards(struct mmc_softc *sc) ivar->csd.write_bl_len != MMC_SECTOR_SIZE) mmc_set_blocklen(sc, MMC_SECTOR_SIZE); + mmc_decode_cid_mmc(ivar->raw_cid, &ivar->cid, + ivar->raw_ext_csd[EXT_CSD_REV] >= 5); mmc_format_card_id_string(ivar); if (bootverbose || mmc_debug) @@ -1672,8 +1579,6 @@ mmc_go_discovery(struct mmc_softc *sc) mmcbr_set_bus_mode(dev, pushpull); mmcbr_update_ios(dev); mmc_calculate_clock(sc); - bus_generic_attach(dev); -/* mmc_update_children_sysctl(dev);*/ } static int @@ -1700,27 +1605,26 @@ mmc_calculate_clock(struct mmc_softc *sc if (ivar->hs_tran_speed < max_hs_dtr) max_hs_dtr = ivar->hs_tran_speed; } + if (bootverbose || mmc_debug) { + device_printf(sc->dev, + "setting transfer rate to %d.%03dMHz%s\n", + max_dtr / 1000000, (max_dtr / 1000) % 1000, + max_timing == bus_timing_hs ? " (high speed timing)" : ""); + } for (i = 0; i < nkid; i++) { ivar = device_get_ivars(kids[i]); if (ivar->timing == bus_timing_normal) continue; mmc_select_card(sc, ivar->rca); - mmc_set_timing(sc, max_timing); + mmc_set_timing(sc, ivar, max_timing); } mmc_select_card(sc, 0); free(kids, M_TEMP); if (max_timing == bus_timing_hs) max_dtr = max_hs_dtr; - if (bootverbose || mmc_debug) { - device_printf(sc->dev, - "setting transfer rate to %d.%03dMHz%s\n", - max_dtr / 1000000, (max_dtr / 1000) % 1000, - max_timing == bus_timing_hs ? " (high speed timing)" : ""); - } - mmcbr_set_timing(sc->dev, max_timing); mmcbr_set_clock(sc->dev, max_dtr); mmcbr_update_ios(sc->dev); - return max_dtr; + return (max_dtr); } static void @@ -1731,6 +1635,8 @@ mmc_scan(struct mmc_softc *sc) mmc_acquire_bus(dev, dev); mmc_go_discovery(sc); mmc_release_bus(dev, dev); + + bus_generic_attach(dev); } static int @@ -1741,6 +1647,9 @@ mmc_read_ivar(device_t bus, device_t chi switch (which) { default: return (EINVAL); + case MMC_IVAR_SPEC_VERS: + *result = ivar->csd.spec_vers; + break; case MMC_IVAR_DSR_IMP: *result = ivar->csd.dsr_imp; break; @@ -1840,4 +1749,4 @@ driver_t mmc_driver = { }; devclass_t mmc_devclass; -MODULE_VERSION(mmc, 1); +MODULE_VERSION(mmc, MMC_VERSION); Added: head/sys/dev/mmc/mmc_ioctl.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/mmc/mmc_ioctl.h Thu Mar 16 22:23:04 2017 (r315430) @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 2017 Marius Strobl <marius@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _DEV_MMC_MMC_IOCTL_H_ +#define _DEV_MMC_MMC_IOCTL_H_ + +struct mmc_ioc_cmd { + int write_flag; /* 0: RD, 1: WR, (1 << 31): reliable WR */ + int is_acmd; /* 0: normal, 1: use CMD55 */ + uint32_t opcode; + uint32_t arg; + uint32_t response[4]; + u_int flags; + u_int blksz; + u_int blocks; + u_int __spare[4]; + uint32_t __pad; + uint64_t data_ptr; +}; + +#define mmc_ioc_cmd_set_data(mic, ptr) \ + (mic).data_ptr = (uint64_t)(uintptr_t)(ptr) + +struct mmc_ioc_multi_cmd { + uint64_t num_of_cmds; + struct mmc_ioc_cmd cmds[0]; +}; + +#define MMC_IOC_BASE 'M' + +#define MMC_IOC_CMD _IOWR(MMC_IOC_BASE, 0, struct mmc_ioc_cmd) +#define MMC_IOC_CMD_MULTI _IOWR(MMC_IOC_BASE, 1, struct mmc_ioc_multi_cmd) + +/* Maximum accepted data transfer size */ +#define MMC_IOC_MAX_BYTES (512 * 256) +/* Maximum accepted number of commands */ +#define MMC_IOC_MAX_CMDS 255 + +#endif /* _DEV_MMC_MMC_IOCTL_H_ */ Added: head/sys/dev/mmc/mmc_private.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/mmc/mmc_private.h Thu Mar 16 22:23:04 2017 (r315430) @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 2006 Bernd Walter. All rights reserved. + * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Portions of this software may have been developed with reference to + * the SD Simplified Specification. The following disclaimer may apply: + * + * The following conditions apply to the release of the simplified + * specification ("Simplified Specification") by the SD Card Association and + * the SD Group. The Simplified Specification is a subset of the complete SD + * Specification which is owned by the SD Card Association and the SD + * Group. This Simplified Specification is provided on a non-confidential + * basis subject to the disclaimers below. Any implementation of the + * Simplified Specification may require a license from the SD Card + * Association, SD Group, SD-3C LLC or other third parties. + * + * Disclaimers: + * + * The information contained in the Simplified Specification is presented only + * as a standard specification for SD Cards and SD Host/Ancillary products and + * is provided "AS-IS" without any representations or warranties of any + * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD + * Card Association for any damages, any infringements of patents or other + * right of the SD Group, SD-3C LLC, the SD Card Association or any third + * parties, which may result from its use. No license is granted by + * implication, estoppel or otherwise under any patent or other rights of the + * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing + * herein shall be construed as an obligation by the SD Group, the SD-3C LLC + * or the SD Card Association to disclose or distribute any technical + * information, know-how or other confidential information to any third party. + * + * $FreeBSD$ + */ + +#ifndef DEV_MMC_PRIVATE_H +#define DEV_MMC_PRIVATE_H + +struct mmc_softc { + device_t dev; + struct mtx sc_mtx; + struct intr_config_hook config_intrhook; + device_t owner; + uint32_t last_rca; + int squelched; /* suppress reporting of (expected) errors */ + int log_count; + struct timeval log_time; +}; + +#endif /* DEV_MMC_PRIVATE_H */ Copied and modified: head/sys/dev/mmc/mmc_subr.c (from r313250, head/sys/dev/mmc/mmc.c) ============================================================================== --- head/sys/dev/mmc/mmc.c Sat Feb 4 19:35:38 2017 (r313250, copy source) +++ head/sys/dev/mmc/mmc_subr.c Thu Mar 16 22:23:04 2017 (r315430) @@ -56,369 +56,27 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> -#include <sys/malloc.h> #include <sys/lock.h> -#include <sys/module.h> #include <sys/mutex.h> -#include <sys/bus.h> -#include <sys/endian.h> -#include <sys/sysctl.h> #include <sys/time.h> +#include <dev/mmc/bridge.h> +#include <dev/mmc/mmc_private.h> +#include <dev/mmc/mmc_subr.h> #include <dev/mmc/mmcreg.h> #include <dev/mmc/mmcbrvar.h> -#include <dev/mmc/mmcvar.h> -#include "mmcbr_if.h" -#include "mmcbus_if.h" - -struct mmc_softc { - device_t dev; - struct mtx sc_mtx; - struct intr_config_hook config_intrhook; - device_t owner; - uint32_t last_rca; - int squelched; /* suppress reporting of (expected) errors */ - int log_count; - struct timeval log_time; -}; - -#define LOG_PPS 5 /* Log no more than 5 errors per second. */ -/* - * Per-card data - */ -struct mmc_ivars { - uint32_t raw_cid[4]; /* Raw bits of the CID */ - uint32_t raw_csd[4]; /* Raw bits of the CSD */ - uint32_t raw_scr[2]; /* Raw bits of the SCR */ - uint8_t raw_ext_csd[512]; /* Raw bits of the EXT_CSD */ - uint32_t raw_sd_status[16]; /* Raw bits of the SD_STATUS */ - uint16_t rca; - enum mmc_card_mode mode; - struct mmc_cid cid; /* cid decoded */ - struct mmc_csd csd; /* csd decoded */ - struct mmc_scr scr; /* scr decoded */ - struct mmc_sd_status sd_status; /* SD_STATUS decoded */ *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201703162223.v2GMN4F4075490>