- 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)
This commit is contained in:
marius 2017-03-16 22:23:04 +00:00
parent d1ff00a05b
commit d5e149bab7
22 changed files with 1580 additions and 398 deletions

View File

@ -51,6 +51,13 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 12.x IS SLOW:
****************************** 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

View File

@ -130,6 +130,8 @@
..
mfi
..
mmc
..
mpt
mpilib
..

View File

@ -45,7 +45,7 @@ LDIRS= bsm cam geom net net80211 netgraph netinet netinet6 \
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 \

View File

@ -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.

View File

@ -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

View File

@ -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 */

View File

@ -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_softc *sc, uint16_t rca,
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 mmc_softc *sc, uint32_t ocr);
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_t dev)
* 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);
}
@ -416,74 +401,6 @@ mmc_wait_for_request(device_t brdev, device_t reqdev __unused,
return (mmc_wait_for_req(sc, req));
}
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 *sc, uint32_t opcode,
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 *sc, uint32_t ocr, uint32_t *rocr)
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, uint32_t ocr, uint32_t *rocr)
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, uint8_t vhs)
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);
}
@ -648,24 +566,6 @@ mmc_select_card(struct mmc_softc *sc, uint16_t rca)
flags, NULL, CMD_RETRIES));
}
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, uint8_t mode, uint8_t grp, uint8_t value,
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 *sc, uint16_t rca, int width)
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 *sc, uint16_t rca, int width)
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 *sc, uint16_t rca, int width)
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 timing)
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, struct mmc_cid *cid)
}
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, struct mmc_cid *cid)
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, uint32_t *rawcid)
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, uint16_t rca, uint32_t *rawcsd)
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,36 +1087,12 @@ mmc_app_send_scr(struct mmc_softc *sc, uint16_t rca, uint32_t *rawscr)
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)
{
@ -1216,7 +1113,7 @@ mmc_app_sd_status(struct mmc_softc *sc, uint16_t rca, uint32_t *rawsdstatus)
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 *sc, uint16_t resp)
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,27 +1145,11 @@ mmc_send_relative_addr(struct mmc_softc *sc, uint32_t *resp)
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)
{
@ -1280,13 +1161,14 @@ mmc_set_blocklen(struct mmc_softc *sc, uint32_t len)
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;
}
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_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);
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, ivar, max_timing);
}
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;
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 child, int which, uintptr_t *result)
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);

64
sys/dev/mmc/mmc_ioctl.h Normal file
View File

@ -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_ */

69
sys/dev/mmc/mmc_private.h Normal file
View File

@ -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 */

252
sys/dev/mmc/mmc_subr.c Normal file
View File

@ -0,0 +1,252 @@
/*-
* 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/mutex.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 "mmcbus_if.h"
#define CMD_RETRIES 3
#define LOG_PPS 5 /* Log no more than 5 errors per second. */
int
mmc_wait_for_cmd(device_t brdev, device_t reqdev, struct mmc_command *cmd,
int retries)
{
struct mmc_request mreq;
struct mmc_softc *sc;
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;
if (cmd->data != NULL)
cmd->data->mrq = &mreq;
mreq.cmd = cmd;
if (MMCBUS_WAIT_FOR_REQUEST(brdev, reqdev, &mreq) != 0)
err = MMC_ERR_FAILED;
else
err = cmd->error;
} while (err != MMC_ERR_NONE && retries-- > 0);
if (err != MMC_ERR_NONE && brdev == reqdev) {
sc = device_get_softc(brdev);
if (sc->squelched == 0 && ppsratecheck(&sc->log_time,
&sc->log_count, LOG_PPS)) {
device_printf(sc->dev, "CMD%d failed, RESULT: %d\n",
cmd->opcode, err);
}
}
return (err);
}
int
mmc_wait_for_app_cmd(device_t brdev, device_t reqdev, uint16_t rca,
struct mmc_command *cmd, int retries)
{
struct mmc_command appcmd;
struct mmc_softc *sc;
int err;
sc = device_get_softc(brdev);
/* Squelch error reporting at lower levels, we report below. */
sc->squelched++;
do {
memset(&appcmd, 0, sizeof(appcmd));
appcmd.opcode = MMC_APP_CMD;
appcmd.arg = (uint32_t)rca << 16;
appcmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
if (mmc_wait_for_cmd(brdev, reqdev, &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(brdev, reqdev, 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 && brdev == reqdev) {
sc = device_get_softc(brdev);
if (sc->squelched == 0 && ppsratecheck(&sc->log_time,
&sc->log_count, LOG_PPS)) {
device_printf(sc->dev, "ACMD%d failed, RESULT: %d\n",
cmd->opcode, err);
}
}
return (err);
}
int
mmc_switch(device_t brdev, device_t reqdev, uint16_t rca, uint8_t set,
uint8_t index, uint8_t value, u_int timeout, bool status)
{
struct mmc_command cmd;
int err;
KASSERT(timeout != 0, ("%s: no timeout", __func__));
memset(&cmd, 0, sizeof(cmd));
cmd.opcode = MMC_SWITCH_FUNC;
cmd.arg = (MMC_SWITCH_FUNC_WR << 24) | (index << 16) | (value << 8) |
set;
/*
* If the hardware supports busy detection but the switch timeout
* exceeds the maximum host timeout, use a R1 instead of a R1B
* response in order to keep the hardware from timing out.
*/
if (mmcbr_get_caps(brdev) & MMC_CAP_WAIT_WHILE_BUSY &&
timeout > mmcbr_get_max_busy_timeout(brdev))
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
else
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
err = mmc_wait_for_cmd(brdev, reqdev, &cmd, CMD_RETRIES);
if (err != MMC_ERR_NONE || status == false)
return (err);
return (mmc_switch_status(brdev, reqdev, rca, timeout));
}
int
mmc_switch_status(device_t brdev, device_t reqdev, uint16_t rca, u_int timeout)
{
struct timeval cur, end;
int err;
uint32_t status;
KASSERT(timeout != 0, ("%s: no timeout", __func__));
/*
* Note that when using a R1B response in mmc_switch(), bridges of
* type MMC_CAP_WAIT_WHILE_BUSY will issue mmc_send_status() only
* once and then exit the loop.
*/
for (;;) {
err = mmc_send_status(brdev, reqdev, rca, &status);
if (err != MMC_ERR_NONE)
break;
if (R1_CURRENT_STATE(status) == R1_STATE_TRAN)
break;
getmicrouptime(&cur);
if (end.tv_sec == 0 && end.tv_usec == 0) {
end.tv_usec = timeout;
timevaladd(&end, &cur);
}
if (timevalcmp(&cur, &end, >)) {
err = MMC_ERR_TIMEOUT;
break;
}
}
if (err == MMC_ERR_NONE && R1_CURRENT_STATE(status) == R1_SWITCH_ERROR)
return (MMC_ERR_FAILED);
return (err);
}
int
mmc_send_ext_csd(device_t brdev, device_t reqdev, 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, MMC_EXTCSD_SIZE);
cmd.opcode = MMC_SEND_EXT_CSD;
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
cmd.data = &data;
data.data = rawextcsd;
data.len = MMC_EXTCSD_SIZE;
data.flags = MMC_DATA_READ;
err = mmc_wait_for_cmd(brdev, reqdev, &cmd, CMD_RETRIES);
return (err);
}
int
mmc_send_status(device_t brdev, device_t reqdev, uint16_t rca, uint32_t *status)
{
struct mmc_command cmd;
int err;
memset(&cmd, 0, sizeof(cmd));
cmd.opcode = MMC_SEND_STATUS;
cmd.arg = (uint32_t)rca << 16;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(brdev, reqdev, &cmd, CMD_RETRIES);
*status = cmd.resp[0];
return (err);
}

72
sys/dev/mmc/mmc_subr.h Normal file
View File

@ -0,0 +1,72 @@
/*-
* 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_SUBR_H
#define DEV_MMC_SUBR_H
struct mmc_command;
int mmc_send_ext_csd(device_t brdev, device_t reqdev, uint8_t *rawextcsd);
int mmc_send_status(device_t brdev, device_t reqdev, uint16_t rca,
uint32_t *status);
int mmc_switch(device_t brdev, device_t reqdev, uint16_t rca, uint8_t set,
uint8_t index, uint8_t value, u_int timeout, bool send_status);
int mmc_switch_status(device_t brdev, device_t reqdev, uint16_t rca,
u_int timeout);
int mmc_wait_for_app_cmd(device_t brdev, device_t reqdev, uint16_t rca,
struct mmc_command *cmd, int retries);
int mmc_wait_for_cmd(device_t brdev, device_t reqdev, struct mmc_command *cmd,
int retries);
#endif /* DEV_MMC_SUBR_H */

View File

@ -53,9 +53,8 @@
*/
#ifndef DEV_MMC_MMCBRVAR_H
#define DEV_MMC_MMCBRVAR_H
#define DEV_MMC_MMCBRVAR_H
#include <dev/mmc/bridge.h>
#include <dev/mmc/mmcreg.h>
#include "mmcbr_if.h"
@ -74,13 +73,14 @@ enum mmcbr_device_ivars {
MMCBR_IVAR_VDD,
MMCBR_IVAR_CAPS,
MMCBR_IVAR_TIMING,
MMCBR_IVAR_MAX_DATA
MMCBR_IVAR_MAX_DATA,
MMCBR_IVAR_MAX_BUSY_TIMEOUT
};
/*
* Simplified accessors for pci devices
* Simplified accessors for bridge devices
*/
#define MMCBR_ACCESSOR(var, ivar, type) \
#define MMCBR_ACCESSOR(var, ivar, type) \
__BUS_ACCESSOR(mmcbr, var, MMCBR, ivar, type)
MMCBR_ACCESSOR(bus_mode, BUS_MODE, int)
@ -97,6 +97,7 @@ MMCBR_ACCESSOR(vdd, VDD, int)
MMCBR_ACCESSOR(caps, CAPS, int)
MMCBR_ACCESSOR(timing, TIMING, int)
MMCBR_ACCESSOR(max_data, MAX_DATA, int)
MMCBR_ACCESSOR(max_busy_timeout, MAX_BUSY_TIMEOUT, u_int)
static int __inline
mmcbr_update_ios(device_t dev)

View File

@ -1,5 +1,6 @@
/*-
* 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
@ -140,6 +141,7 @@ struct mmc_command {
#define R1_ERASE_RESET (1u << 13) /* sr, c */
#define R1_CURRENT_STATE_MASK (0xfu << 9) /* sx, b */
#define R1_READY_FOR_DATA (1u << 8) /* sx, a */
#define R1_SWITCH_ERROR (1u << 7) /* sx, c */
#define R1_APP_CMD (1u << 5) /* sr, c */
#define R1_AKE_SEQ_ERROR (1u << 3) /* er, c */
#define R1_STATUS(x) ((x) & 0xFFFFE000)
@ -184,7 +186,7 @@ struct mmc_request {
#define MMC_SET_RELATIVE_ADDR 3
#define SD_SEND_RELATIVE_ADDR 3
#define MMC_SET_DSR 4
/* reserved: 5 */
#define MMC_SLEEP_AWAKE 5
#define MMC_SWITCH_FUNC 6
#define MMC_SWITCH_FUNC_CMDS 0
#define MMC_SWITCH_FUNC_SET 1
@ -278,7 +280,6 @@ struct mmc_request {
/* reserved: 50 */
/* reserved: 57 */
/* Application specific commands for SD */
#define ACMD_SET_BUS_WIDTH 6
#define ACMD_SD_STATUS 13
@ -291,18 +292,73 @@ struct mmc_request {
/*
* EXT_CSD fields
*/
#define EXT_CSD_EXT_PART_ATTR 52 /* R/W, 2 bytes */
#define EXT_CSD_ENH_START_ADDR 136 /* R/W, 4 bytes */
#define EXT_CSD_ENH_SIZE_MULT 140 /* R/W, 3 bytes */
#define EXT_CSD_GP_SIZE_MULT 143 /* R/W, 12 bytes */
#define EXT_CSD_PART_SET 155 /* R/W */
#define EXT_CSD_PART_ATTR 156 /* R/W */
#define EXT_CSD_PART_SUPPORT 160 /* RO */
#define EXT_CSD_RPMB_MULT 168 /* RO */
#define EXT_CSD_BOOT_WP_STATUS 174 /* RO */
#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_HS_TIMING 185 /* R/W */
#define EXT_CSD_CARD_TYPE 196 /* RO */
#define EXT_CSD_REV 192 /* RO */
#define EXT_CSD_PART_SWITCH_TO 199 /* 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_GEN_CMD6_TIME 248 /* RO */
/*
* EXT_CSD field definitions
*/
#define EXT_CSD_EXT_PART_ATTR_DEFAULT 0x0
#define EXT_CSD_EXT_PART_ATTR_SYSTEMCODE 0x1
#define EXT_CSD_EXT_PART_ATTR_NPERSISTENT 0x2
#define EXT_CSD_PART_SET_COMPLETED 0x01
#define EXT_CSD_PART_ATTR_ENH_USR 0x01
#define EXT_CSD_PART_ATTR_ENH_GP0 0x02
#define EXT_CSD_PART_ATTR_ENH_GP1 0x04
#define EXT_CSD_PART_ATTR_ENH_GP2 0x08
#define EXT_CSD_PART_ATTR_ENH_GP3 0x10
#define EXT_CSD_PART_ATTR_ENH_MASK 0x1f
#define EXT_CSD_PART_SUPPORT_EN 0x01
#define EXT_CSD_PART_SUPPORT_ENH_ATTR_EN 0x02
#define EXT_CSD_PART_SUPPORT_EXT_ATTR_EN 0x04
#define EXT_CSD_BOOT_WP_STATUS_BOOT0_PWR 0x01
#define EXT_CSD_BOOT_WP_STATUS_BOOT0_PERM 0x02
#define EXT_CSD_BOOT_WP_STATUS_BOOT0_MASK 0x03
#define EXT_CSD_BOOT_WP_STATUS_BOOT1_PWR 0x04
#define EXT_CSD_BOOT_WP_STATUS_BOOT1_PERM 0x08
#define EXT_CSD_BOOT_WP_STATUS_BOOT1_MASK 0x0c
#define EXT_CSD_ERASE_GRP_DEF_EN 0x01
#define EXT_CSD_PART_CONFIG_ACC_DEFAULT 0x00
#define EXT_CSD_PART_CONFIG_ACC_BOOT0 0x01
#define EXT_CSD_PART_CONFIG_ACC_BOOT1 0x02
#define EXT_CSD_PART_CONFIG_ACC_RPMB 0x03
#define EXT_CSD_PART_CONFIG_ACC_GP0 0x04
#define EXT_CSD_PART_CONFIG_ACC_GP1 0x05
#define EXT_CSD_PART_CONFIG_ACC_GP2 0x06
#define EXT_CSD_PART_CONFIG_ACC_GP3 0x07
#define EXT_CSD_PART_CONFIG_ACC_MASK 0x07
#define EXT_CSD_PART_CONFIG_BOOT0 0x08
#define EXT_CSD_PART_CONFIG_BOOT1 0x10
#define EXT_CSD_PART_CONFIG_BOOT_USR 0x38
#define EXT_CSD_PART_CONFIG_BOOT_MASK 0x38
#define EXT_CSD_PART_CONFIG_BOOT_ACK 0x40
#define EXT_CSD_CMD_SET_NORMAL 1
#define EXT_CSD_CMD_SET_SECURE 2
#define EXT_CSD_CMD_SET_CPSECURE 4
@ -437,6 +493,16 @@ struct mmc_sd_status
uint8_t erase_offset;
};
/*
* Various MMC/SD constants
*/
#define MMC_BOOT_RPMB_BLOCK_SIZE (128 * 1024)
#define MMC_EXTCSD_SIZE 512
#define MMC_PART_GP_MAX 4
#define MMC_PART_MAX 8
/*
* Older versions of the MMC standard had a variable sector size. However,
* I've been able to find no old MMC or SD cards that have a non 512

File diff suppressed because it is too large Load Diff

View File

@ -55,9 +55,8 @@
#ifndef DEV_MMC_MMCVAR_H
#define DEV_MMC_MMCVAR_H
#include <dev/mmc/bridge.h>
enum mmc_device_ivars {
MMC_IVAR_SPEC_VERS,
MMC_IVAR_DSR_IMP,
MMC_IVAR_MEDIA_SIZE,
MMC_IVAR_RCA,
@ -79,6 +78,7 @@ enum mmc_device_ivars {
#define MMC_ACCESSOR(var, ivar, type) \
__BUS_ACCESSOR(mmc, var, MMC, ivar, type)
MMC_ACCESSOR(spec_vers, SPEC_VERS, uint8_t)
MMC_ACCESSOR(dsr_imp, DSR_IMP, int)
MMC_ACCESSOR(media_size, MEDIA_SIZE, long)
MMC_ACCESSOR(rca, RCA, int)

View File

@ -686,6 +686,10 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
slot->host.caps |= MMC_CAP_8_BIT_DATA;
if (caps & SDHCI_CAN_DO_HISPD)
slot->host.caps |= MMC_CAP_HSPEED;
if (slot->quirks & SDHCI_QUIRK_BOOT_NOACC)
slot->host.caps |= MMC_CAP_BOOT_NOACC;
if (slot->quirks & SDHCI_QUIRK_WAIT_WHILE_BUSY)
slot->host.caps |= MMC_CAP_WAIT_WHILE_BUSY;
/* Decide if we have usable DMA. */
if (caps & SDHCI_CAN_DO_DMA)
slot->opt |= SDHCI_HAVE_DMA;
@ -1013,9 +1017,11 @@ sdhci_finish_command(struct sdhci_slot *slot)
uint8_t extra;
slot->cmd_done = 1;
/* Interrupt aggregation: Restore command interrupt.
/*
* Interrupt aggregation: Restore command interrupt.
* Main restore point for the case when command interrupt
* happened first. */
* happened first.
*/
WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask |= SDHCI_INT_RESPONSE);
/* In case of error - reset host and return. */
if (slot->curcmd->error) {
@ -1523,6 +1529,12 @@ sdhci_generic_read_ivar(device_t bus, device_t child, int which,
case MMCBR_IVAR_MAX_DATA:
*result = 65535;
break;
case MMCBR_IVAR_MAX_BUSY_TIMEOUT:
/*
* Currently, sdhci_start_data() hardcodes 1 s for all CMDs.
*/
*result = 1000000;
break;
}
return (0);
}

View File

@ -73,6 +73,10 @@
#define SDHCI_QUIRK_INTEL_POWER_UP_RESET (1 << 19)
/* Data timeout is invalid, use 1 MHz clock instead. */
#define SDHCI_QUIRK_DATA_TIMEOUT_1MHZ (1 << 20)
/* Controller doesn't allow access boot partitions. */
#define SDHCI_QUIRK_BOOT_NOACC (1 << 21)
/* Controller waits for busy responses. */
#define SDHCI_QUIRK_WAIT_WHILE_BUSY (1 << 22)
/*
* Controller registers

View File

@ -57,13 +57,14 @@ static const struct sdhci_acpi_device {
const char *desc;
u_int quirks;
} sdhci_acpi_devices[] = {
{ "80860F14", 1, "Intel Bay Trail SD Host Controller",
{ "80860F14", 1, "Intel Bay Trail eMMC 4.5 Controller",
SDHCI_QUIRK_ALL_SLOTS_NON_REMOVABLE |
SDHCI_QUIRK_INTEL_POWER_UP_RESET },
{ "80860F14", 3, "Intel Bay Trail SD Host Controller",
SDHCI_QUIRK_INTEL_POWER_UP_RESET },
{ "80860F16", 0, "Intel Bay Trail SD Host Controller",
0 },
SDHCI_QUIRK_INTEL_POWER_UP_RESET |
SDHCI_QUIRK_WAIT_WHILE_BUSY },
{ "80860F14", 3, "Intel Bay Trail SDXC Controller",
SDHCI_QUIRK_WAIT_WHILE_BUSY },
{ "80860F16", 0, "Intel Bay Trail SDXC Controller",
SDHCI_QUIRK_WAIT_WHILE_BUSY },
{ NULL, 0, NULL, 0}
};

View File

@ -105,17 +105,27 @@ static const struct sdhci_device {
SDHCI_QUIRK_BCM577XX_400KHZ_CLKSRC },
{ 0x0f148086, 0xffff, "Intel Bay Trail eMMC 4.5 Controller",
SDHCI_QUIRK_ALL_SLOTS_NON_REMOVABLE |
SDHCI_QUIRK_INTEL_POWER_UP_RESET },
SDHCI_QUIRK_INTEL_POWER_UP_RESET |
SDHCI_QUIRK_WAIT_WHILE_BUSY },
{ 0x0f158086, 0xffff, "Intel Bay Trail SDXC Controller",
SDHCI_QUIRK_WAIT_WHILE_BUSY },
{ 0x0f508086, 0xffff, "Intel Bay Trail eMMC 4.5 Controller",
SDHCI_QUIRK_ALL_SLOTS_NON_REMOVABLE |
SDHCI_QUIRK_INTEL_POWER_UP_RESET },
SDHCI_QUIRK_INTEL_POWER_UP_RESET |
SDHCI_QUIRK_WAIT_WHILE_BUSY },
{ 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_INTEL_POWER_UP_RESET |
SDHCI_QUIRK_WAIT_WHILE_BUSY },
{ 0x22968086, 0xffff, "Intel Braswell SDXC Controller",
SDHCI_QUIRK_WAIT_WHILE_BUSY },
{ 0x5aca8086, 0xffff, "Intel Apollo Lake SDXC Controller",
SDHCI_QUIRK_WAIT_WHILE_BUSY },
{ 0x5acc8086, 0xffff, "Intel Apollo Lake eMMC 5.0 Controller",
SDHCI_QUIRK_ALL_SLOTS_NON_REMOVABLE |
SDHCI_QUIRK_INTEL_POWER_UP_RESET },
SDHCI_QUIRK_INTEL_POWER_UP_RESET |
SDHCI_QUIRK_WAIT_WHILE_BUSY },
{ 0, 0xffff, NULL,
0 }
};

View File

@ -3,6 +3,6 @@
.PATH: ${SRCTOP}/sys/dev/mmc
KMOD= mmc
SRCS= mmc.c mmcbr_if.h mmcbus_if.h device_if.h bus_if.h
SRCS= bus_if.h device_if.h mmc_subr.c mmc.c mmcbr_if.h mmcbus_if.h
.include <bsd.kmod.mk>

View File

@ -3,6 +3,6 @@
.PATH: ${SRCTOP}/sys/dev/mmc
KMOD= mmcsd
SRCS= bus_if.h device_if.h mmcbr_if.h mmcbus_if.h mmcsd.c
SRCS= bus_if.h device_if.h mmc_subr.c mmcbr_if.h mmcbus_if.h mmcsd.c
.include <bsd.kmod.mk>

View File

@ -58,7 +58,7 @@
* in the range 5 to 9.
*/
#undef __FreeBSD_version
#define __FreeBSD_version 1200024 /* Master, propagated to newvers */
#define __FreeBSD_version 1200025 /* Master, propagated to newvers */
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,