From 4b2f3989c028365201afccd9865fa38fb4dbe971 Mon Sep 17 00:00:00 2001 From: marius Date: Thu, 11 May 2017 21:01:02 +0000 Subject: [PATCH] MFC: r292180 (partial), r297127 (partial), r311911, r311923, r312939, r313250, r313712, r314811 (partial), r314887 (partial), r315430, r317981, r315466 o Move the DRIVER_MODULE() statements that declare mmc(4) to be a child of the various bridge drivers out of dev/mmc.c and into the bridge drivers. o Add ACPI platform support for SDHCI driver. o Fix some overly long lines, whitespace and other bugs according to style(9) as well as spelling etc. in mmc(4), mmcsd(4) and sdhci(4). o In the mmc(4) bridges and sdhci(4) (bus) front-ends: - Remove redundant assignments of the default bus_generic_print_child device method, - use DEVMETHOD_END, - use NULL instead of 0 for pointers. o Trim/adjust includes. o Add and use a MMC_DECLARE_BRIDGE macro for declaring mmc(4) bridges as kernel drivers and their dependency onto mmc(4). o 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) 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. o 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. o 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 have been added to ports as sysutils/mmc-utils. Among others, the `mmc` tool of mmc-utils allows for partitioning eMMC devices (tested working). o 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. o Let mmcsd.ko depend on mmc.ko. Additionally, bump MMC_VERSION as at least for some of the above a matching pair is required. git-svn-id: svn://svn.freebsd.org/base/stable/10@318198 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- UPDATING | 7 + etc/mtree/BSD.include.dist | 2 + include/Makefile | 3 +- sys/arm/at91/at91_mci.c | 10 +- sys/arm/broadcom/bcm2835/bcm2835_sdhci.c | 10 +- sys/arm/freescale/imx/imx_sdhci.c | 3 +- sys/arm/lpc/lpc_mmc.c | 17 +- sys/arm/ti/ti_sdhci.c | 10 +- sys/conf/files | 4 +- sys/dev/mmc/bridge.h | 30 +- sys/dev/mmc/mmc.c | 455 ++++------ sys/dev/mmc/mmc_ioctl.h | 64 ++ sys/dev/mmc/mmc_private.h | 69 ++ sys/dev/mmc/mmc_subr.c | 252 ++++++ sys/dev/mmc/mmc_subr.h | 72 ++ sys/dev/mmc/mmcbr_if.m | 9 +- sys/dev/mmc/mmcbrvar.h | 16 +- sys/dev/mmc/mmcreg.h | 136 ++- sys/dev/mmc/mmcsd.c | 1053 ++++++++++++++++++---- sys/dev/mmc/mmcvar.h | 6 +- sys/dev/sdhci/sdhci.c | 252 +++--- sys/dev/sdhci/sdhci.h | 437 ++++----- sys/dev/sdhci/sdhci_acpi.c | 375 ++++++++ sys/dev/sdhci/sdhci_fdt.c | 70 +- sys/dev/sdhci/sdhci_if.m | 9 +- sys/dev/sdhci/sdhci_pci.c | 123 +-- sys/modules/Makefile | 2 + sys/modules/mmc/Makefile | 2 +- sys/modules/sdhci_acpi/Makefile | 9 + sys/powerpc/mpc85xx/fsl_sdhc.c | 3 +- sys/sys/param.h | 2 +- 31 files changed, 2560 insertions(+), 952 deletions(-) create mode 100644 sys/dev/mmc/mmc_ioctl.h create mode 100644 sys/dev/mmc/mmc_private.h create mode 100644 sys/dev/mmc/mmc_subr.c create mode 100644 sys/dev/mmc/mmc_subr.h create mode 100644 sys/dev/sdhci/sdhci_acpi.c create mode 100644 sys/modules/sdhci_acpi/Makefile diff --git a/UPDATING b/UPDATING index bcc948f22..56ca44fc2 100644 --- a/UPDATING +++ b/UPDATING @@ -16,6 +16,13 @@ from older versions of FreeBSD, try WITHOUT_CLANG to bootstrap to the tip of stable/10, and then rebuild without this option. The bootstrap process from older version of current is a bit fragile. +20170511: + 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). + 20170413: As of r316810 for ipfilter, keep frags is no longer assumed when keep state is specified in a rule. r316810 aligns ipfilter with diff --git a/etc/mtree/BSD.include.dist b/etc/mtree/BSD.include.dist index efffe064c..51a023dfe 100644 --- a/etc/mtree/BSD.include.dist +++ b/etc/mtree/BSD.include.dist @@ -132,6 +132,8 @@ .. mfi .. + mmc + .. mpt mpilib .. diff --git a/include/Makefile b/include/Makefile index aab46a797..0ef9de6a9 100644 --- a/include/Makefile +++ b/include/Makefile @@ -45,7 +45,8 @@ LDIRS= bsm cam geom net net80211 netatalk netgraph netinet netinet6 \ LSUBDIRS= cam/ata 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_ieee488} dev/io dev/lmc dev/mfi dev/nvme \ + dev/ic dev/iicbus ${_dev_ieee488} 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 \ diff --git a/sys/arm/at91/at91_mci.c b/sys/arm/at91/at91_mci.c index a506715a0..8ae4e389e 100644 --- a/sys/arm/at91/at91_mci.c +++ b/sys/arm/at91/at91_mci.c @@ -32,23 +32,16 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include -#include #include #include -#include #include #include #include #include -#include #include #include #include -#include -#include -#include #include #include @@ -61,7 +54,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include #ifdef FDT @@ -1410,3 +1402,5 @@ DRIVER_MODULE(at91_mci, simplebus, at91_mci_driver, at91_mci_devclass, NULL, DRIVER_MODULE(at91_mci, atmelarm, at91_mci_driver, at91_mci_devclass, NULL, NULL); #endif + +MMC_DECLARE_BRIDGE(at91_mci); diff --git a/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c b/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c index 11cf3bc36..b2b8df32c 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c +++ b/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c @@ -47,9 +47,10 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include + +#include "mmcbr_if.h" #include "sdhci_if.h" #include "bcm2835_dma.h" @@ -637,7 +638,6 @@ static device_method_t bcm_sdhci_methods[] = { /* Bus interface */ DEVMETHOD(bus_read_ivar, sdhci_generic_read_ivar), DEVMETHOD(bus_write_ivar, sdhci_generic_write_ivar), - DEVMETHOD(bus_print_child, bus_generic_print_child), /* MMC bridge interface */ DEVMETHOD(mmcbr_update_ios, sdhci_generic_update_ios), @@ -660,7 +660,7 @@ static device_method_t bcm_sdhci_methods[] = { DEVMETHOD(sdhci_write_4, bcm_sdhci_write_4), DEVMETHOD(sdhci_write_multi_4, bcm_sdhci_write_multi_4), - { 0, 0 } + DEVMETHOD_END }; static devclass_t bcm_sdhci_devclass; @@ -671,5 +671,7 @@ static driver_t bcm_sdhci_driver = { sizeof(struct bcm_sdhci_softc), }; -DRIVER_MODULE(sdhci_bcm, simplebus, bcm_sdhci_driver, bcm_sdhci_devclass, 0, 0); +DRIVER_MODULE(sdhci_bcm, simplebus, bcm_sdhci_driver, bcm_sdhci_devclass, + NULL, NULL); MODULE_DEPEND(sdhci_bcm, sdhci, 1, 1, 1); +MMC_DECLARE_BRIDGE(sdhci_bcm); diff --git a/sys/arm/freescale/imx/imx_sdhci.c b/sys/arm/freescale/imx/imx_sdhci.c index 98d5e238e..c31546385 100644 --- a/sys/arm/freescale/imx/imx_sdhci.c +++ b/sys/arm/freescale/imx/imx_sdhci.c @@ -835,4 +835,5 @@ static driver_t imx_sdhci_driver = { DRIVER_MODULE(sdhci_imx, simplebus, imx_sdhci_driver, imx_sdhci_devclass, 0, 0); MODULE_DEPEND(sdhci_imx, sdhci, 1, 1, 1); - +DRIVER_MODULE(mmc, sdhci_imx, mmc_driver, mmc_devclass, NULL, NULL); +MODULE_DEPEND(sdhci_imx, mmc, 1, 1, 1); diff --git a/sys/arm/lpc/lpc_mmc.c b/sys/arm/lpc/lpc_mmc.c index 5dc6722b4..f3d8cf28d 100644 --- a/sys/arm/lpc/lpc_mmc.c +++ b/sys/arm/lpc/lpc_mmc.c @@ -29,24 +29,14 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include -#include -#include #include -#include #include #include #include #include -#include #include #include -#include -#include -#include - -#include #include #include @@ -58,7 +48,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include #include @@ -754,7 +743,6 @@ static device_method_t lpc_mmc_methods[] = { /* Bus interface */ DEVMETHOD(bus_read_ivar, lpc_mmc_read_ivar), DEVMETHOD(bus_write_ivar, lpc_mmc_write_ivar), - DEVMETHOD(bus_print_child, bus_generic_print_child), /* MMC bridge interface */ DEVMETHOD(mmcbr_update_ios, lpc_mmc_update_ios), @@ -763,7 +751,7 @@ static device_method_t lpc_mmc_methods[] = { DEVMETHOD(mmcbr_acquire_host, lpc_mmc_acquire_host), DEVMETHOD(mmcbr_release_host, lpc_mmc_release_host), - { 0, 0 } + DEVMETHOD_END }; static devclass_t lpc_mmc_devclass; @@ -774,4 +762,5 @@ static driver_t lpc_mmc_driver = { sizeof(struct lpc_mmc_softc), }; -DRIVER_MODULE(lpcmmc, simplebus, lpc_mmc_driver, lpc_mmc_devclass, 0, 0); +DRIVER_MODULE(lpcmmc, simplebus, lpc_mmc_driver, lpc_mmc_devclass, NULL, NULL); +MMC_DECLARE_BRIDGE(lpcmmc); diff --git a/sys/arm/ti/ti_sdhci.c b/sys/arm/ti/ti_sdhci.c index 63645cc88..3af4a4fbb 100644 --- a/sys/arm/ti/ti_sdhci.c +++ b/sys/arm/ti/ti_sdhci.c @@ -599,6 +599,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. @@ -685,7 +690,6 @@ static device_method_t ti_sdhci_methods[] = { /* Bus interface */ DEVMETHOD(bus_read_ivar, sdhci_generic_read_ivar), DEVMETHOD(bus_write_ivar, sdhci_generic_write_ivar), - DEVMETHOD(bus_print_child, bus_generic_print_child), /* MMC bridge interface */ DEVMETHOD(mmcbr_update_ios, ti_sdhci_update_ios), @@ -715,5 +719,7 @@ static driver_t ti_sdhci_driver = { sizeof(struct ti_sdhci_softc), }; -DRIVER_MODULE(sdhci_ti, simplebus, ti_sdhci_driver, ti_sdhci_devclass, 0, 0); +DRIVER_MODULE(sdhci_ti, simplebus, ti_sdhci_driver, ti_sdhci_devclass, NULL, + NULL); MODULE_DEPEND(sdhci_ti, sdhci, 1, 1, 1); +MMC_DECLARE_BRIDGE(sdhci_ti); diff --git a/sys/conf/files b/sys/conf/files index 0501db9c5..88ae06d5c 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1899,6 +1899,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 @@ -2288,6 +2289,7 @@ dev/scd/scd.c optional scd isa dev/scd/scd_isa.c optional scd isa dev/sdhci/sdhci.c optional sdhci dev/sdhci/sdhci_if.m optional sdhci +dev/sdhci/sdhci_acpi.c optional sdhci acpi dev/sdhci/sdhci_pci.c optional sdhci pci dev/sf/if_sf.c optional sf pci dev/sge/if_sge.c optional sge pci @@ -2898,7 +2900,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 +geom/geom_flashmap.c optional fdt cfi | fdt nand | mmcsd geom/geom_io.c standard geom/geom_kern.c standard geom/geom_map.c optional geom_map diff --git a/sys/dev/mmc/bridge.h b/sys/dev/mmc/bridge.h index bd61c15ae..4e5e11c5f 100644 --- a/sys/dev/mmc/bridge.h +++ b/sys/dev/mmc/bridge.h @@ -52,13 +52,15 @@ */ #ifndef DEV_MMC_BRIDGE_H -#define DEV_MMC_BRIDGE_H +#define DEV_MMC_BRIDGE_H + +#include /* * This file defines interfaces for the mmc bridge. The names chosen * are similar to or the same as the names used in Linux to allow for * easy porting of what Linux calls mmc host drivers. I use the - * FreeBSD terminology of bridge and bus for consistancy with other + * FreeBSD terminology of bridge and bus for consistency with other * drivers in the system. This file corresponds roughly to the Linux * linux/mmc/host.h file. * @@ -71,10 +73,9 @@ * to be added to the mmcbus file). * * Attached to the mmc bridge is an mmcbus. The mmcbus is described - * in dev/mmc/bus.h. + * in dev/mmc/mmcbus_if.m. */ - /* * mmc_ios is a structure that is used to store the state of the mmc/sd * bus configuration. This include the bus' clock speed, its voltage, @@ -110,7 +111,7 @@ enum mmc_bus_timing { struct mmc_ios { uint32_t clock; /* Speed of the clock in Hz to move data */ - enum mmc_vdd vdd; /* Voltage to apply to the power pins/ */ + enum mmc_vdd vdd; /* Voltage to apply to the power pins */ enum mmc_bus_mode bus_mode; enum mmc_chip_select chip_select; enum mmc_bus_width bus_width; @@ -128,11 +129,24 @@ struct mmc_host { uint32_t host_ocr; uint32_t ocr; uint32_t caps; -#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_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 */ }; +extern driver_t mmc_driver; +extern devclass_t mmc_devclass; + +#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 */ diff --git a/sys/dev/mmc/mmc.c b/sys/dev/mmc/mmc.c index 1fabed25a..ff4468f4c 100644 --- a/sys/dev/mmc/mmc.c +++ b/sys/dev/mmc/mmc.c @@ -65,25 +65,16 @@ __FBSDID("$FreeBSD$"); #include #include +#include +#include +#include #include #include #include + #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,11 +98,12 @@ 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 */ }; -#define CMD_RETRIES 3 +#define CMD_RETRIES 3 #define CARD_ID_FREQUENCY 400000 /* Spec requires 400kHz max during ID phase. */ @@ -119,7 +111,8 @@ static SYSCTL_NODE(_hw, OID_AUTO, mmc, CTLFLAG_RD, NULL, "mmc driver"); static int mmc_debug; TUNABLE_INT("hw.mmc.debug", &mmc_debug); -SYSCTL_INT(_hw_mmc, OID_AUTO, debug, CTLFLAG_RWTUN, &mmc_debug, 0, "Debug level"); +SYSCTL_INT(_hw_mmc, OID_AUTO, debug, CTLFLAG_RWTUN, &mmc_debug, 0, + "Debug level"); /* bus entry points */ static int mmc_acquire_bus(device_t busdev, device_t dev); @@ -138,14 +131,14 @@ static int mmc_wait_for_request(device_t brdev, device_t reqdev, static int mmc_write_ivar(device_t bus, device_t child, int which, uintptr_t value); -#define MMC_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) +#define MMC_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define MMC_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) -#define MMC_LOCK_INIT(_sc) \ - mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \ +#define MMC_LOCK_INIT(_sc) \ + mtx_init(&(_sc)->sc_mtx, device_get_nameunit((_sc)->dev), \ "mmc", MTX_DEF) -#define MMC_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); -#define MMC_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); -#define MMC_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); +#define MMC_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx); +#define MMC_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED); +#define MMC_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_NOTOWNED); static int mmc_all_send_cid(struct mmc_softc *sc, uint32_t *rawcid); static void mmc_app_decode_scr(uint32_t *raw_scr, struct mmc_scr *scr); @@ -156,7 +149,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 +176,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); @@ -260,7 +246,7 @@ mmc_suspend(device_t dev) err = bus_generic_suspend(dev); if (err) - return (err); + return (err); mmc_power_down(sc); return (0); } @@ -299,19 +285,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); } @@ -408,81 +394,14 @@ mmc_wait_for_req(struct mmc_softc *sc, struct mmc_request *req) } static int -mmc_wait_for_request(device_t brdev, device_t reqdev, struct mmc_request *req) +mmc_wait_for_request(device_t brdev, device_t reqdev __unused, + struct mmc_request *req) { struct mmc_softc *sc = device_get_softc(brdev); 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) @@ -495,7 +414,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) { @@ -523,7 +442,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); @@ -544,7 +463,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) || @@ -571,7 +491,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) || @@ -597,7 +517,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); } @@ -647,24 +567,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) @@ -689,12 +591,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; @@ -705,13 +607,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; @@ -721,9 +624,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; @@ -736,18 +640,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) { - int err; - uint8_t value; u_char switch_res[64]; + uint8_t value; + int err; switch (timing) { case bus_timing_normal: @@ -759,26 +664,52 @@ 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); } +static const uint8_t p8[8] = { + 0x55, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const uint8_t p8ok[8] = { + 0xAA, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const uint8_t p4[4] = { + 0x5A, 0x00, 0x00, 0x00 +}; + +static const uint8_t p4ok[4] = { + 0xA5, 0x00, 0x00, 0x00 +}; + static int mmc_test_bus_width(struct mmc_softc *sc) { struct mmc_command cmd; struct mmc_data data; - int err; uint8_t buf[8]; - uint8_t p8[8] = { 0x55, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - uint8_t p8ok[8] = { 0xAA, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - uint8_t p4[4] = { 0x5A, 0x00, 0x00, 0x00, }; - uint8_t p4ok[4] = { 0xA5, 0x00, 0x00, 0x00, }; + int err; if (mmcbr_get_caps(sc->dev) & MMC_CAP_8_BIT_DATA) { mmcbr_set_bus_width(sc->dev, bus_width_8); @@ -792,10 +723,10 @@ mmc_test_bus_width(struct mmc_softc *sc) cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.data = &data; - data.data = p8; + 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)); @@ -807,7 +738,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); @@ -829,10 +760,10 @@ mmc_test_bus_width(struct mmc_softc *sc) cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.data = &data; - data.data = p4; + 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)); @@ -844,7 +775,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); @@ -862,6 +793,7 @@ mmc_get_bits(uint32_t *bits, int bit_len, int start, int size) const int i = (bit_len / 32) - (start / 32) - 1; const int shift = start & 31; uint32_t retval = bits[i] >> shift; + if (size + shift > 32) retval |= bits[i - 1] << (32 - shift); return (retval & ((1llu << size) - 1)); @@ -886,7 +818,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; @@ -900,7 +832,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 @@ -981,10 +917,14 @@ mmc_decode_csd_sd(uint32_t *raw_csd, struct mmc_csd *csd) csd->write_blk_misalign = mmc_get_bits(raw_csd, 128, 78, 1); csd->read_blk_misalign = mmc_get_bits(raw_csd, 128, 77, 1); csd->dsr_imp = mmc_get_bits(raw_csd, 128, 76, 1); - csd->vdd_r_curr_min = cur_min[mmc_get_bits(raw_csd, 128, 59, 3)]; - csd->vdd_r_curr_max = cur_max[mmc_get_bits(raw_csd, 128, 56, 3)]; - csd->vdd_w_curr_min = cur_min[mmc_get_bits(raw_csd, 128, 53, 3)]; - csd->vdd_w_curr_max = cur_max[mmc_get_bits(raw_csd, 128, 50, 3)]; + csd->vdd_r_curr_min = + cur_min[mmc_get_bits(raw_csd, 128, 59, 3)]; + csd->vdd_r_curr_max = + cur_max[mmc_get_bits(raw_csd, 128, 56, 3)]; + csd->vdd_w_curr_min = + cur_min[mmc_get_bits(raw_csd, 128, 53, 3)]; + csd->vdd_w_curr_max = + cur_max[mmc_get_bits(raw_csd, 128, 50, 3)]; m = mmc_get_bits(raw_csd, 128, 62, 12); e = mmc_get_bits(raw_csd, 128, 47, 3); csd->capacity = ((1 + m) << (e + 2)) * csd->read_bl_len; @@ -1009,8 +949,8 @@ mmc_decode_csd_sd(uint32_t *raw_csd, struct mmc_csd *csd) csd->write_blk_misalign = mmc_get_bits(raw_csd, 128, 78, 1); csd->read_blk_misalign = mmc_get_bits(raw_csd, 128, 77, 1); csd->dsr_imp = mmc_get_bits(raw_csd, 128, 76, 1); - csd->capacity = ((uint64_t)mmc_get_bits(raw_csd, 128, 48, 22) + 1) * - 512 * 1024; + csd->capacity = ((uint64_t)mmc_get_bits(raw_csd, 128, 48, 22) + + 1) * 512 * 1024; csd->erase_blk_en = mmc_get_bits(raw_csd, 128, 46, 1); csd->erase_sector = mmc_get_bits(raw_csd, 128, 39, 7) + 1; csd->wp_grp_size = mmc_get_bits(raw_csd, 128, 32, 7); @@ -1108,7 +1048,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); } @@ -1124,7 +1064,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); } @@ -1149,42 +1089,18 @@ 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) -{ - int err; - struct mmc_command cmd; - struct mmc_data data; - - 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) { - int err, i; struct mmc_command cmd; struct mmc_data data; + int err, i; memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); @@ -1199,7 +1115,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); @@ -1216,7 +1132,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); } @@ -1231,27 +1147,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) { @@ -1263,13 +1163,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); @@ -1287,13 +1188,14 @@ mmc_log_card(device_t dev, struct mmc_ivars *ivar, int newcard) static void mmc_discover_cards(struct mmc_softc *sc) { + u_char switch_res[64]; + uint32_t raw_cid[4]; struct mmc_ivars *ivar = NULL; device_t *devlist; - int err, i, devcount, newcard; - uint32_t raw_cid[4], resp, sec_count, status; device_t child; + int err, i, devcount, newcard; + uint32_t resp, sec_count, status; uint16_t rca = 2; - u_char switch_res[64]; if (bootverbose || mmc_debug) device_printf(sc->dev, "Probing cards\n"); @@ -1308,18 +1210,21 @@ mmc_discover_cards(struct mmc_softc *sc) break; } newcard = 1; - if ((err = device_get_children(sc->dev, &devlist, &devcount)) != 0) + if ((err = device_get_children(sc->dev, &devlist, + &devcount)) != 0) return; for (i = 0; i < devcount; i++) { ivar = device_get_ivars(devlist[i]); - if (memcmp(ivar->raw_cid, raw_cid, sizeof(raw_cid)) == 0) { + if (memcmp(ivar->raw_cid, raw_cid, sizeof(raw_cid)) == + 0) { newcard = 0; break; } } free(devlist, M_TEMP); if (bootverbose || mmc_debug) { - device_printf(sc->dev, "%sard detected (CID %08x%08x%08x%08x)\n", + device_printf(sc->dev, + "%sard detected (CID %08x%08x%08x%08x)\n", newcard ? "New c" : "C", raw_cid[0], raw_cid[1], raw_cid[2], raw_cid[3]); } @@ -1353,7 +1258,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); @@ -1365,17 +1271,17 @@ 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); /* Get card switch capabilities (command class 10). */ if ((ivar->scr.sda_vsn >= 1) && - (ivar->csd.ccc & (1<<10))) { + (ivar->csd.ccc & (1 << 10))) { 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; } @@ -1387,7 +1293,7 @@ mmc_discover_cards(struct mmc_softc *sc) * commands, although the state tables / diagrams in the * standard suggest they go back to the transfer state. * Other cards don't become deselected, and if we - * atttempt to blindly re-select them, we get timeout + * attempt to blindly re-select them, we get timeout * errors from some controllers. So we deselect then * reselect to handle all situations. The only thing we * use from the sd_status is the erase sector size, but @@ -1432,7 +1338,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. */ @@ -1450,7 +1355,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); @@ -1464,9 +1369,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) + @@ -1486,14 +1397,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; @@ -1512,6 +1440,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) @@ -1528,7 +1458,7 @@ mmc_discover_cards(struct mmc_softc *sc) static void mmc_rescan_cards(struct mmc_softc *sc) { - struct mmc_ivars *ivar = NULL; + struct mmc_ivars *ivar; device_t *devlist; int err, i, devcount; @@ -1536,9 +1466,10 @@ mmc_rescan_cards(struct mmc_softc *sc) return; for (i = 0; i < devcount; i++) { ivar = device_get_ivars(devlist[i]); - if (mmc_select_card(sc, ivar->rca)) { + if (mmc_select_card(sc, ivar->rca) != MMC_ERR_NONE) { if (bootverbose || mmc_debug) - device_printf(sc->dev, "Card at relative address %d lost.\n", + device_printf(sc->dev, + "Card at relative address %d lost.\n", ivar->rca); device_delete_child(sc->dev, devlist[i]); free(ivar, M_DEVBUF); @@ -1560,7 +1491,8 @@ mmc_delete_cards(struct mmc_softc *sc) for (i = 0; i < devcount; i++) { ivar = device_get_ivars(devlist[i]); if (bootverbose || mmc_debug) - device_printf(sc->dev, "Card at relative address %d deleted.\n", + device_printf(sc->dev, + "Card at relative address %d deleted.\n", ivar->rca); device_delete_child(sc->dev, devlist[i]); free(ivar, M_DEVBUF); @@ -1590,7 +1522,8 @@ mmc_go_discovery(struct mmc_softc *sc) mmc_idle_cards(sc); err = mmc_send_if_cond(sc, 1); if ((bootverbose || mmc_debug) && err == 0) - device_printf(sc->dev, "SD 2.0 interface conditions: OK\n"); + device_printf(sc->dev, + "SD 2.0 interface conditions: OK\n"); if (mmc_send_app_op_cond(sc, 0, &ocr) != MMC_ERR_NONE) { if (bootverbose || mmc_debug) device_printf(sc->dev, "SD probe: failed\n"); @@ -1600,13 +1533,15 @@ mmc_go_discovery(struct mmc_softc *sc) mmcbr_set_mode(dev, mode_mmc); if (mmc_send_op_cond(sc, 0, &ocr) != MMC_ERR_NONE) { if (bootverbose || mmc_debug) - device_printf(sc->dev, "MMC probe: failed\n"); + device_printf(sc->dev, + "MMC probe: failed\n"); ocr = 0; /* Failed both, powerdown. */ } else if (bootverbose || mmc_debug) device_printf(sc->dev, "MMC probe: OK (OCR: 0x%08x)\n", ocr); } else if (bootverbose || mmc_debug) - device_printf(sc->dev, "SD probe: OK (OCR: 0x%08x)\n", ocr); + device_printf(sc->dev, "SD probe: OK (OCR: 0x%08x)\n", + ocr); sc->squelched--; mmcbr_set_ocr(dev, mmc_select_vdd(sc, ocr)); @@ -1623,7 +1558,8 @@ mmc_go_discovery(struct mmc_softc *sc) * one card on the bus. */ if (bootverbose || mmc_debug) - device_printf(sc->dev, "Current OCR: 0x%08x\n", mmcbr_get_ocr(dev)); + device_printf(sc->dev, "Current OCR: 0x%08x\n", + mmcbr_get_ocr(dev)); if (mmcbr_get_ocr(dev) == 0) { device_printf(sc->dev, "No compatible cards found on bus\n"); mmc_delete_cards(sc); @@ -1645,21 +1581,18 @@ 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 mmc_calculate_clock(struct mmc_softc *sc) { - int max_dtr, max_hs_dtr, max_timing; - int nkid, i, f_max; device_t *kids; struct mmc_ivars *ivar; + int i, f_max, max_dtr, max_hs_dtr, max_timing, nkid; f_max = mmcbr_get_f_max(sc->dev); max_dtr = max_hs_dtr = f_max; - if ((mmcbr_get_caps(sc->dev) & MMC_CAP_HSPEED)) + if (mmcbr_get_caps(sc->dev) & MMC_CAP_HSPEED) max_timing = bus_timing_hs; else max_timing = bus_timing_normal; @@ -1674,27 +1607,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 @@ -1705,6 +1637,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 @@ -1715,6 +1649,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; @@ -1761,6 +1698,7 @@ mmc_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) static int mmc_write_ivar(device_t bus, device_t child, int which, uintptr_t value) { + /* * None are writable ATM */ @@ -1806,18 +1744,11 @@ static device_method_t mmc_methods[] = { DEVMETHOD_END }; -static driver_t mmc_driver = { +driver_t mmc_driver = { "mmc", mmc_methods, sizeof(struct mmc_softc), }; -static devclass_t mmc_devclass; - -DRIVER_MODULE(mmc, at91_mci, mmc_driver, mmc_devclass, NULL, NULL); -DRIVER_MODULE(mmc, sdhci_bcm, mmc_driver, mmc_devclass, NULL, NULL); -DRIVER_MODULE(mmc, sdhci_fdt, mmc_driver, mmc_devclass, NULL, NULL); -DRIVER_MODULE(mmc, sdhci_imx, mmc_driver, mmc_devclass, NULL, NULL); -DRIVER_MODULE(mmc, sdhci_pci, mmc_driver, mmc_devclass, NULL, NULL); -DRIVER_MODULE(mmc, sdhci_ti, mmc_driver, mmc_devclass, NULL, NULL); -DRIVER_MODULE(mmc, ti_mmchs, mmc_driver, mmc_devclass, NULL, NULL); +devclass_t mmc_devclass; +MODULE_VERSION(mmc, MMC_VERSION); diff --git a/sys/dev/mmc/mmc_ioctl.h b/sys/dev/mmc/mmc_ioctl.h new file mode 100644 index 000000000..97cff0683 --- /dev/null +++ b/sys/dev/mmc/mmc_ioctl.h @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 2017 Marius Strobl + * 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_ */ diff --git a/sys/dev/mmc/mmc_private.h b/sys/dev/mmc/mmc_private.h new file mode 100644 index 000000000..bbca0c601 --- /dev/null +++ b/sys/dev/mmc/mmc_private.h @@ -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 */ diff --git a/sys/dev/mmc/mmc_subr.c b/sys/dev/mmc/mmc_subr.c new file mode 100644 index 000000000..7f0317a5c --- /dev/null +++ b/sys/dev/mmc/mmc_subr.c @@ -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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#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); +} diff --git a/sys/dev/mmc/mmc_subr.h b/sys/dev/mmc/mmc_subr.h new file mode 100644 index 000000000..6e300d2fa --- /dev/null +++ b/sys/dev/mmc/mmc_subr.h @@ -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 */ diff --git a/sys/dev/mmc/mmcbr_if.m b/sys/dev/mmc/mmcbr_if.m index e82293de3..b30e5c75f 100644 --- a/sys/dev/mmc/mmcbr_if.m +++ b/sys/dev/mmc/mmcbr_if.m @@ -65,8 +65,9 @@ INTERFACE mmcbr; # -# Called by the mmcbus to setup the IO pins correctly, the voltage to use -# for the card, the type of selects, power modes and bus width. +# Called by the mmcbus to set up the IO pins correctly, the common/core +# supply voltage (VDD/VCC) to use for the device, the clock frequency, the +# type of SPI chip select, power mode and bus width. # METHOD int update_ios { device_t brdev; @@ -76,8 +77,8 @@ METHOD int update_ios { # # Called by the mmcbus or its children to schedule a mmc request. These # requests are queued. Time passes. The bridge then gets notification -# of the status of request, who then notifies the requesting device via -# the xfer_done mmcbus method. +# of the status of the request, who then notifies the requesting device +# by calling the completion function supplied as part of the request. # METHOD int request { device_t brdev; diff --git a/sys/dev/mmc/mmcbrvar.h b/sys/dev/mmc/mmcbrvar.h index 9fc1ab893..f7066c7d2 100644 --- a/sys/dev/mmc/mmcbrvar.h +++ b/sys/dev/mmc/mmcbrvar.h @@ -49,14 +49,14 @@ * or the SD Card Association to disclose or distribute any technical * information, know-how or other confidential information to any third party. * - * "$FreeBSD$" + * $FreeBSD$ */ #ifndef DEV_MMC_MMCBRVAR_H -#define DEV_MMC_MMCBRVAR_H +#define DEV_MMC_MMCBRVAR_H -#include #include + #include "mmcbr_if.h" enum mmcbr_device_ivars { @@ -73,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) @@ -96,16 +97,19 @@ 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) { + return (MMCBR_UPDATE_IOS(device_get_parent(dev), dev)); } static int __inline mmcbr_get_ro(device_t dev) { + return (MMCBR_GET_RO(device_get_parent(dev), dev)); } diff --git a/sys/dev/mmc/mmcreg.h b/sys/dev/mmc/mmcreg.h index 080c14ef8..c4a264401 100644 --- a/sys/dev/mmc/mmcreg.h +++ b/sys/dev/mmc/mmcreg.h @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2017 Marius Strobl * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -100,7 +101,7 @@ struct mmc_command { #define MMC_ERR_FAILED 4 #define MMC_ERR_INVALID 5 #define MMC_ERR_NO_MEMORY 6 -#define MMC_ERR_MAX 6 +#define MMC_ERR_MAX 6 struct mmc_data *data; /* Data segment with cmd */ struct mmc_request *mrq; /* backpointer to request */ }; @@ -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,47 +292,102 @@ struct mmc_request { /* * EXT_CSD fields */ -#define EXT_CSD_ERASE_GRP_DEF 175 /* 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_SEC_CNT 212 /* RO, 4 bytes */ -#define EXT_CSD_ERASE_TO_MULT 223 /* RO */ -#define EXT_CSD_ERASE_GRP_SIZE 224 /* RO */ +#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_CMD_SET_NORMAL 1 -#define EXT_CSD_CMD_SET_SECURE 2 -#define EXT_CSD_CMD_SET_CPSECURE 4 - -#define EXT_CSD_CARD_TYPE_26 1 -#define EXT_CSD_CARD_TYPE_52 2 - -#define EXT_CSD_BUS_WIDTH_1 0 -#define EXT_CSD_BUS_WIDTH_4 1 -#define EXT_CSD_BUS_WIDTH_8 2 - -#define MMC_TYPE_26_MAX_HS 26000000 -#define MMC_TYPE_52_MAX_HS 52000000 +#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 + +#define EXT_CSD_CARD_TYPE_26 1 +#define EXT_CSD_CARD_TYPE_52 2 + +#define EXT_CSD_BUS_WIDTH_1 0 +#define EXT_CSD_BUS_WIDTH_4 1 +#define EXT_CSD_BUS_WIDTH_8 2 + +#define MMC_TYPE_26_MAX_HS 26000000 +#define MMC_TYPE_52_MAX_HS 52000000 /* * SD bus widths */ -#define SD_BUS_WIDTH_1 0 -#define SD_BUS_WIDTH_4 2 +#define SD_BUS_WIDTH_1 0 +#define SD_BUS_WIDTH_4 2 /* * SD Switch */ -#define SD_SWITCH_MODE_CHECK 0 -#define SD_SWITCH_MODE_SET 1 -#define SD_SWITCH_GROUP1 0 -#define SD_SWITCH_NORMAL_MODE 0 -#define SD_SWITCH_HS_MODE 1 -#define SD_SWITCH_NOCHANGE 0xF +#define SD_SWITCH_MODE_CHECK 0 +#define SD_SWITCH_MODE_SET 1 +#define SD_SWITCH_GROUP1 0 +#define SD_SWITCH_NORMAL_MODE 0 +#define SD_SWITCH_HS_MODE 1 +#define SD_SWITCH_NOCHANGE 0xF #define SD_CLR_CARD_DETECT 0 #define SD_SET_CARD_DETECT 1 @@ -419,8 +475,8 @@ struct mmc_scr { unsigned char sda_vsn; unsigned char bus_widths; -#define SD_SCR_BUS_WIDTH_1 (1<<0) -#define SD_SCR_BUS_WIDTH_4 (1<<2) +#define SD_SCR_BUS_WIDTH_1 (1 << 0) +#define SD_SCR_BUS_WIDTH_4 (1 << 2) }; struct mmc_sd_status @@ -437,12 +493,22 @@ 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 * byte sector size anywhere, so we assume that such cards are very rare * and only note their existance in passing here... */ -#define MMC_SECTOR_SIZE 512 +#define MMC_SECTOR_SIZE 512 #endif /* DEV_MMCREG_H */ diff --git a/sys/dev/mmc/mmcsd.c b/sys/dev/mmc/mmcsd.c index 1931f7b48..2decb4ee0 100644 --- a/sys/dev/mmc/mmcsd.c +++ b/sys/dev/mmc/mmcsd.c @@ -1,6 +1,7 @@ /*- * Copyright (c) 2006 Bernd Walter. All rights reserved. * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2017 Marius Strobl * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -58,15 +59,23 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include #include #include #include #include #include #include +#include #include + +#include #include +#include +#include +#include #include #include #include @@ -78,17 +87,46 @@ __FBSDID("$FreeBSD$"); #define kproc_exit kthread_exit #endif -struct mmcsd_softc { - device_t dev; - struct mtx sc_mtx; +#define MMCSD_CMD_RETRIES 5 + +#define MMCSD_FMT_BOOT "mmcsd%dboot" +#define MMCSD_FMT_GP "mmcsd%dgp" +#define MMCSD_FMT_RPMB "mmcsd%drpmb" +#define MMCSD_LABEL_ENH "enh" + +#define MMCSD_PART_NAMELEN (16 + 1) + +struct mmcsd_softc; + +struct mmcsd_part { + struct mtx part_mtx; + struct mmcsd_softc *sc; struct disk *disk; struct proc *p; struct bio_queue_head bio_queue; daddr_t eblock, eend; /* Range remaining after the last erase. */ + u_int cnt; + u_int type; int running; int suspend; + bool ro; + char name[MMCSD_PART_NAMELEN]; +}; + +struct mmcsd_softc { + device_t dev; + device_t mmcbr; + struct mmcsd_part *part[MMC_PART_MAX]; + enum mmc_card_mode mode; + uint8_t part_curr; /* Partition currently switched to */ + uint8_t ext_csd[MMC_EXTCSD_SIZE]; + uint16_t rca; + uint32_t part_time; /* Partition switch timeout [us] */ + off_t enh_base; /* Enhanced user data area slice base ... */ + off_t enh_size; /* ... and size [bytes] */ int log_count; struct timeval log_time; + struct cdev *rpmb_dev; }; static const char *errmsg[] = @@ -112,23 +150,43 @@ static int mmcsd_probe(device_t dev); /* disk routines */ static int mmcsd_close(struct disk *dp); static int mmcsd_dump(void *arg, void *virtual, vm_offset_t physical, - off_t offset, size_t length); + off_t offset, size_t length); +static int mmcsd_getattr(struct bio *); +static int mmcsd_ioctl_disk(struct disk *disk, u_long cmd, void *data, + int fflag, struct thread *td); static int mmcsd_open(struct disk *dp); static void mmcsd_strategy(struct bio *bp); static void mmcsd_task(void *arg); +/* RMPB cdev interface */ +static int mmcsd_ioctl_rpmb(struct cdev *dev, u_long cmd, caddr_t data, + int fflag, struct thread *td); + +static void mmcsd_add_part(struct mmcsd_softc *sc, u_int type, + const char *name, u_int cnt, off_t media_size, off_t erase_size, bool ro); static int mmcsd_bus_bit_width(device_t dev); -static daddr_t mmcsd_delete(struct mmcsd_softc *sc, struct bio *bp); -static daddr_t mmcsd_rw(struct mmcsd_softc *sc, struct bio *bp); - -#define MMCSD_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) -#define MMCSD_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) -#define MMCSD_LOCK_INIT(_sc) \ - mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \ - "mmcsd", MTX_DEF) -#define MMCSD_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); -#define MMCSD_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); -#define MMCSD_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); +static daddr_t mmcsd_delete(struct mmcsd_part *part, struct bio *bp); +static int mmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void *data, + int fflag); +static int mmcsd_ioctl_cmd(struct mmcsd_part *part, struct mmc_ioc_cmd *mic, + int fflag); +static uintmax_t mmcsd_pretty_size(off_t size, char *unit); +static daddr_t mmcsd_rw(struct mmcsd_part *part, struct bio *bp); +static int mmcsd_set_blockcount(struct mmcsd_softc *sc, u_int count, bool rel); +static int mmcsd_slicer(device_t dev, const char *provider, + struct flash_slice *slices, int *nslices); +static int mmcsd_switch_part(device_t bus, device_t dev, uint16_t rca, + u_int part); + +#define MMCSD_PART_LOCK(_part) mtx_lock(&(_part)->part_mtx) +#define MMCSD_PART_UNLOCK(_part) mtx_unlock(&(_part)->part_mtx) +#define MMCSD_PART_LOCK_INIT(_part) \ + mtx_init(&(_part)->part_mtx, (_part)->name, "mmcsd part", MTX_DEF) +#define MMCSD_PART_LOCK_DESTROY(_part) mtx_destroy(&(_part)->part_mtx); +#define MMCSD_PART_ASSERT_LOCKED(_part) \ + mtx_assert(&(_part)->part_mtx, MA_OWNED); +#define MMCSD_PART_ASSERT_UNLOCKED(_part) \ + mtx_assert(&(_part)->part_mtx, MA_NOTOWNED); static int mmcsd_probe(device_t dev) @@ -142,74 +200,353 @@ mmcsd_probe(device_t dev) static int mmcsd_attach(device_t dev) { + device_t mmcbr; struct mmcsd_softc *sc; - struct disk *d; - intmax_t mb; - uint32_t speed; - uint32_t maxblocks; - char unit; + const uint8_t *ext_csd; + off_t erase_size, sector_size, size, wp_size; + uintmax_t bytes; + int err, i; + uint8_t rev; + bool comp, ro; + char unit[2]; sc = device_get_softc(dev); sc->dev = dev; - MMCSD_LOCK_INIT(sc); - - d = sc->disk = disk_alloc(); - d->d_open = mmcsd_open; - d->d_close = mmcsd_close; - d->d_strategy = mmcsd_strategy; - d->d_dump = mmcsd_dump; - d->d_name = "mmcsd"; - d->d_drv1 = sc; - d->d_sectorsize = mmc_get_sector_size(dev); - d->d_maxsize = mmc_get_max_data(dev) * d->d_sectorsize; - d->d_mediasize = (off_t)mmc_get_media_size(dev) * d->d_sectorsize; - d->d_stripesize = mmc_get_erase_sector(dev) * d->d_sectorsize; - d->d_unit = device_get_unit(dev); - d->d_flags = DISKFLAG_CANDELETE; - d->d_delmaxsize = mmc_get_erase_sector(dev) * d->d_sectorsize; - strlcpy(d->d_ident, mmc_get_card_sn_string(dev), sizeof(d->d_ident)); - strlcpy(d->d_descr, mmc_get_card_id_string(dev), sizeof(d->d_descr)); - d->d_rotation_rate = DISK_RR_NON_ROTATING; + sc->mmcbr = mmcbr = device_get_parent(dev); + sc->mode = mmcbr_get_mode(mmcbr); + sc->rca = mmc_get_rca(dev); + + /* Only MMC >= 4.x devices support EXT_CSD. */ + if (mmc_get_spec_vers(dev) >= 4) { + MMCBUS_ACQUIRE_BUS(mmcbr, dev); + err = mmc_send_ext_csd(mmcbr, dev, sc->ext_csd); + MMCBUS_RELEASE_BUS(mmcbr, dev); + if (err != MMC_ERR_NONE) + bzero(sc->ext_csd, sizeof(sc->ext_csd)); + } + ext_csd = sc->ext_csd; /* - * Display in most natural units. There's no cards < 1MB. The SD - * standard goes to 2GiB due to its reliance on FAT, but the data - * format supports up to 4GiB and some card makers push it up to this - * limit. The SDHC standard only goes to 32GiB due to FAT32, but the - * data format supports up to 2TiB however. 2048GB isn't too ugly, so - * we note it in passing here and don't add the code to print - * TB). Since these cards are sold in terms of MB and GB not MiB and - * GiB, report them like that. We also round to the nearest unit, since - * many cards are a few percent short, even of the power of 10 size. + * Enhanced user data area and general purpose partitions are only + * supported in revision 1.4 (EXT_CSD_REV == 4) and later, the RPMB + * partition in revision 1.5 (MMC v4.41, EXT_CSD_REV == 5) and later. */ - mb = (d->d_mediasize + 1000000 / 2 - 1) / 1000000; - unit = 'M'; - if (mb >= 1000) { - unit = 'G'; - mb = (mb + 1000 / 2 - 1) / 1000; + rev = ext_csd[EXT_CSD_REV]; + + /* + * Ignore user-creatable enhanced user data area and general purpose + * partitions partitions as long as partitioning hasn't been finished. + */ + comp = (ext_csd[EXT_CSD_PART_SET] & EXT_CSD_PART_SET_COMPLETED) != 0; + + /* + * Add enhanced user data area slice, unless it spans the entirety of + * the user data area. The enhanced area is of a multiple of high + * capacity write protect groups ((ERASE_GRP_SIZE + HC_WP_GRP_SIZE) * + * 512 KB) and its offset given in either sectors or bytes, depending + * on whether it's a high capacity device or not. + * NB: The slicer and its slices need to be registered before adding + * the disk for the corresponding user data area as re-tasting is + * racy. + */ + sector_size = mmc_get_sector_size(dev); + size = ext_csd[EXT_CSD_ENH_SIZE_MULT] + + (ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) + + (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16); + if (rev >= 4 && comp == TRUE && size > 0 && + (ext_csd[EXT_CSD_PART_SUPPORT] & + EXT_CSD_PART_SUPPORT_ENH_ATTR_EN) != 0 && + (ext_csd[EXT_CSD_PART_ATTR] & (EXT_CSD_PART_ATTR_ENH_USR)) != 0) { + erase_size = ext_csd[EXT_CSD_ERASE_GRP_SIZE] * 1024 * + MMC_SECTOR_SIZE; + wp_size = ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; + size *= erase_size * wp_size; + if (size != mmc_get_media_size(dev) * sector_size) { + sc->enh_size = size; + sc->enh_base = (ext_csd[EXT_CSD_ENH_START_ADDR] + + (ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) + + (ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) + + (ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24)) * + (mmc_get_high_cap(dev) ? MMC_SECTOR_SIZE : 1); + } else if (bootverbose) + device_printf(dev, + "enhanced user data area spans entire device\n"); } + /* - * Report the clock speed of the underlying hardware, which might be - * different than what the card reports due to hardware limitations. - * Report how many blocks the hardware transfers at once. + * Add default partition. This may be the only one or the user + * data area in case partitions are supported. */ - speed = mmcbr_get_clock(device_get_parent(dev)); - maxblocks = mmc_get_max_data(dev); - device_printf(dev, "%ju%cB <%s>%s at %s %d.%01dMHz/%dbit/%d-block\n", - mb, unit, d->d_descr, - mmc_get_read_only(dev) ? " (read-only)" : "", - device_get_nameunit(device_get_parent(dev)), - speed / 1000000, (speed / 100000) % 10, - mmcsd_bus_bit_width(dev), maxblocks); - disk_create(d, DISK_VERSION); - bioq_init(&sc->bio_queue); - - sc->running = 1; - sc->suspend = 0; - sc->eblock = sc->eend = 0; - kproc_create(&mmcsd_task, sc, &sc->p, 0, 0, "%s: mmc/sd card", - device_get_nameunit(dev)); + ro = mmc_get_read_only(dev); + mmcsd_add_part(sc, EXT_CSD_PART_CONFIG_ACC_DEFAULT, "mmcsd", + device_get_unit(dev), mmc_get_media_size(dev) * sector_size, + mmc_get_erase_sector(dev) * sector_size, ro); + + if (mmc_get_spec_vers(dev) < 3) + return (0); + + /* Belatedly announce enhanced user data slice. */ + if (sc->enh_size != 0) { + bytes = mmcsd_pretty_size(size, unit); + printf(FLASH_SLICES_FMT ": %ju%sB enhanced user data area " + "slice offset 0x%jx at %s\n", device_get_nameunit(dev), + MMCSD_LABEL_ENH, bytes, unit, (uintmax_t)sc->enh_base, + device_get_nameunit(dev)); + } + + /* + * Determine partition switch timeout (provided in units of 10 ms) + * and ensure it's at least 300 ms as some eMMC chips lie. + */ + sc->part_time = max(ext_csd[EXT_CSD_PART_SWITCH_TO] * 10 * 1000, + 300 * 1000); + + /* Add boot partitions, which are of a fixed multiple of 128 KB. */ + size = ext_csd[EXT_CSD_BOOT_SIZE_MULT] * MMC_BOOT_RPMB_BLOCK_SIZE; + if (size > 0 && (mmcbr_get_caps(mmcbr) & MMC_CAP_BOOT_NOACC) == 0) { + mmcsd_add_part(sc, EXT_CSD_PART_CONFIG_ACC_BOOT0, + MMCSD_FMT_BOOT, 0, size, MMC_BOOT_RPMB_BLOCK_SIZE, + ro | ((ext_csd[EXT_CSD_BOOT_WP_STATUS] & + EXT_CSD_BOOT_WP_STATUS_BOOT0_MASK) != 0)); + mmcsd_add_part(sc, EXT_CSD_PART_CONFIG_ACC_BOOT1, + MMCSD_FMT_BOOT, 1, size, MMC_BOOT_RPMB_BLOCK_SIZE, + ro | ((ext_csd[EXT_CSD_BOOT_WP_STATUS] & + EXT_CSD_BOOT_WP_STATUS_BOOT1_MASK) != 0)); + } + + /* Add RPMB partition, which also is of a fixed multiple of 128 KB. */ + size = ext_csd[EXT_CSD_RPMB_MULT] * MMC_BOOT_RPMB_BLOCK_SIZE; + if (rev >= 5 && size > 0) + mmcsd_add_part(sc, EXT_CSD_PART_CONFIG_ACC_RPMB, + MMCSD_FMT_RPMB, 0, size, MMC_BOOT_RPMB_BLOCK_SIZE, ro); + + if (rev <= 3 || comp == FALSE) + return (0); + + /* + * Add general purpose partitions, which are of a multiple of high + * capacity write protect groups, too. + */ + if ((ext_csd[EXT_CSD_PART_SUPPORT] & EXT_CSD_PART_SUPPORT_EN) != 0) { + erase_size = ext_csd[EXT_CSD_ERASE_GRP_SIZE] * 1024 * + MMC_SECTOR_SIZE; + wp_size = ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; + for (i = 0; i < MMC_PART_GP_MAX; i++) { + size = ext_csd[EXT_CSD_GP_SIZE_MULT + i * 3] + + (ext_csd[EXT_CSD_GP_SIZE_MULT + i * 3 + 1] << 8) + + (ext_csd[EXT_CSD_GP_SIZE_MULT + i * 3 + 2] << 16); + if (size == 0) + continue; + mmcsd_add_part(sc, EXT_CSD_PART_CONFIG_ACC_GP0 + i, + MMCSD_FMT_GP, i, size * erase_size * wp_size, + erase_size, ro); + } + } + return (0); +} + +static uintmax_t +mmcsd_pretty_size(off_t size, char *unit) +{ + uintmax_t bytes; + int i; + + /* + * Display in most natural units. There's no card < 1MB. However, + * RPMB partitions occasionally are smaller than that, though. The + * SD standard goes to 2 GiB due to its reliance on FAT, but the data + * format supports up to 4 GiB and some card makers push it up to this + * limit. The SDHC standard only goes to 32 GiB due to FAT32, but the + * data format supports up to 2 TiB however. 2048 GB isn't too ugly, + * so we note it in passing here and don't add the code to print TB). + * Since these cards are sold in terms of MB and GB not MiB and GiB, + * report them like that. We also round to the nearest unit, since + * many cards are a few percent short, even of the power of 10 size. + */ + bytes = size; + unit[0] = unit[1] = '\0'; + for (i = 0; i <= 2 && bytes >= 1000; i++) { + bytes = (bytes + 1000 / 2 - 1) / 1000; + switch (i) { + case 0: + unit[0] = 'k'; + break; + case 1: + unit[0] = 'M'; + break; + case 2: + unit[0] = 'G'; + break; + default: + break; + } + } + return (bytes); +} + +static struct cdevsw mmcsd_rpmb_cdevsw = { + .d_version = D_VERSION, + .d_name = "mmcsdrpmb", + .d_ioctl = mmcsd_ioctl_rpmb +}; + +static void +mmcsd_add_part(struct mmcsd_softc *sc, u_int type, const char *name, u_int cnt, + off_t media_size, off_t erase_size, bool ro) +{ + struct make_dev_args args; + device_t dev, mmcbr; + const char *ext; + const uint8_t *ext_csd; + struct mmcsd_part *part; + struct disk *d; + uintmax_t bytes; + u_int gp; + uint32_t speed; + uint8_t extattr; + bool enh; + char unit[2]; + + dev = sc->dev; + mmcbr = sc->mmcbr; + part = sc->part[type] = malloc(sizeof(*part), M_DEVBUF, + M_WAITOK | M_ZERO); + part->sc = sc; + part->cnt = cnt; + part->type = type; + part->ro = ro; + snprintf(part->name, sizeof(part->name), name, device_get_unit(dev)); + /* For the RPMB partition, allow IOCTL access only. */ + if (type == EXT_CSD_PART_CONFIG_ACC_RPMB) { + make_dev_args_init(&args); + args.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_WAITOK; + args.mda_devsw = &mmcsd_rpmb_cdevsw; + args.mda_uid = UID_ROOT; + args.mda_gid = GID_OPERATOR; + args.mda_mode = 0640; + args.mda_si_drv1 = part; + if (make_dev_s(&args, &sc->rpmb_dev, "%s", part->name) != 0) { + device_printf(dev, "Failed to make RPMB device\n"); + free(part, M_DEVBUF); + return; + } + } else { + MMCSD_PART_LOCK_INIT(part); + + d = part->disk = disk_alloc(); + d->d_open = mmcsd_open; + d->d_close = mmcsd_close; + d->d_strategy = mmcsd_strategy; + d->d_ioctl = mmcsd_ioctl_disk; + d->d_dump = mmcsd_dump; + d->d_getattr = mmcsd_getattr; + d->d_name = part->name; + d->d_drv1 = part; + d->d_sectorsize = mmc_get_sector_size(dev); + d->d_maxsize = mmc_get_max_data(dev) * d->d_sectorsize; + d->d_mediasize = media_size; + d->d_stripesize = erase_size; + d->d_unit = cnt; + d->d_flags = DISKFLAG_CANDELETE; + d->d_delmaxsize = erase_size; + strlcpy(d->d_ident, mmc_get_card_sn_string(dev), + sizeof(d->d_ident)); + strlcpy(d->d_descr, mmc_get_card_id_string(dev), + sizeof(d->d_descr)); + d->d_rotation_rate = DISK_RR_NON_ROTATING; + + disk_create(d, DISK_VERSION); + bioq_init(&part->bio_queue); + + part->running = 1; + kproc_create(&mmcsd_task, part, &part->p, 0, 0, + "%s%d: mmc/sd card", part->name, cnt); + } + + bytes = mmcsd_pretty_size(media_size, unit); + if (type == EXT_CSD_PART_CONFIG_ACC_DEFAULT) { + speed = mmcbr_get_clock(mmcbr); + printf("%s%d: %ju%sB <%s>%s at %s %d.%01dMHz/%dbit/%d-block\n", + part->name, cnt, bytes, unit, mmc_get_card_id_string(dev), + ro ? " (read-only)" : "", device_get_nameunit(mmcbr), + speed / 1000000, (speed / 100000) % 10, + mmcsd_bus_bit_width(dev), mmc_get_max_data(dev)); + } else if (type == EXT_CSD_PART_CONFIG_ACC_RPMB) { + printf("%s: %ju%sB partion %d%s at %s\n", part->name, bytes, + unit, type, ro ? " (read-only)" : "", + device_get_nameunit(dev)); + } else { + enh = false; + ext = NULL; + extattr = 0; + if (type >= EXT_CSD_PART_CONFIG_ACC_GP0 && + type <= EXT_CSD_PART_CONFIG_ACC_GP3) { + ext_csd = sc->ext_csd; + gp = type - EXT_CSD_PART_CONFIG_ACC_GP0; + if ((ext_csd[EXT_CSD_PART_SUPPORT] & + EXT_CSD_PART_SUPPORT_ENH_ATTR_EN) != 0 && + (ext_csd[EXT_CSD_PART_ATTR] & + (EXT_CSD_PART_ATTR_ENH_GP0 << gp)) != 0) + enh = true; + else if ((ext_csd[EXT_CSD_PART_SUPPORT] & + EXT_CSD_PART_SUPPORT_EXT_ATTR_EN) != 0) { + extattr = (ext_csd[EXT_CSD_EXT_PART_ATTR + + (gp / 2)] >> (4 * (gp % 2))) & 0xF; + switch (extattr) { + case EXT_CSD_EXT_PART_ATTR_DEFAULT: + break; + case EXT_CSD_EXT_PART_ATTR_SYSTEMCODE: + ext = "system code"; + break; + case EXT_CSD_EXT_PART_ATTR_NPERSISTENT: + ext = "non-persistent"; + break; + default: + ext = "reserved"; + break; + } + } + } + if (ext == NULL) + printf("%s%d: %ju%sB partion %d%s%s at %s\n", + part->name, cnt, bytes, unit, type, enh ? + " enhanced" : "", ro ? " (read-only)" : "", + device_get_nameunit(dev)); + else + printf("%s%d: %ju%sB partion %d extended 0x%x " + "(%s)%s at %s\n", part->name, cnt, bytes, unit, + type, extattr, ext, ro ? " (read-only)" : "", + device_get_nameunit(dev)); + } +} + +static int +mmcsd_slicer(device_t dev, const char *provider, + struct flash_slice *slices, int *nslices) +{ + char name[MMCSD_PART_NAMELEN]; + struct mmcsd_softc *sc; + struct mmcsd_part *part; + + *nslices = 0; + if (slices == NULL) + return (ENOMEM); + + sc = device_get_softc(dev); + if (sc->enh_size == 0) + return (ENXIO); + + part = sc->part[EXT_CSD_PART_CONFIG_ACC_DEFAULT]; + snprintf(name, sizeof(name), "%s%d", part->disk->d_name, + part->disk->d_unit); + if (strcmp(name, provider) != 0) + return (ENXIO); + + *nslices = 1; + slices[0].base = sc->enh_base; + slices[0].size = sc->enh_size; + slices[0].label = MMCSD_LABEL_ENH; return (0); } @@ -217,26 +554,44 @@ static int mmcsd_detach(device_t dev) { struct mmcsd_softc *sc = device_get_softc(dev); + struct mmcsd_part *part; + int i; - MMCSD_LOCK(sc); - sc->suspend = 0; - if (sc->running > 0) { - /* kill thread */ - sc->running = 0; - wakeup(sc); - /* wait for thread to finish. */ - while (sc->running != -1) - msleep(sc, &sc->sc_mtx, 0, "detach", 0); + for (i = 0; i < MMC_PART_MAX; i++) { + part = sc->part[i]; + if (part != NULL && part->disk != NULL) { + MMCSD_PART_LOCK(part); + part->suspend = 0; + if (part->running > 0) { + /* kill thread */ + part->running = 0; + wakeup(part); + /* wait for thread to finish. */ + while (part->running != -1) + msleep(part, &part->part_mtx, 0, + "detach", 0); + } + MMCSD_PART_UNLOCK(part); + } } - MMCSD_UNLOCK(sc); - /* Flush the request queue. */ - bioq_flush(&sc->bio_queue, NULL, ENXIO); - /* kill disk */ - disk_destroy(sc->disk); + if (sc->rpmb_dev != NULL) + destroy_dev(sc->rpmb_dev); - MMCSD_LOCK_DESTROY(sc); + for (i = 0; i < MMC_PART_MAX; i++) { + part = sc->part[i]; + if (part != NULL) { + if (part->disk != NULL) { + /* Flush the request queue. */ + bioq_flush(&part->bio_queue, NULL, ENXIO); + /* kill disk */ + disk_destroy(part->disk); + MMCSD_PART_LOCK_DESTROY(part); + } + free(part, M_DEVBUF); + } + } return (0); } @@ -244,18 +599,26 @@ static int mmcsd_suspend(device_t dev) { struct mmcsd_softc *sc = device_get_softc(dev); + struct mmcsd_part *part; + int i; - MMCSD_LOCK(sc); - sc->suspend = 1; - if (sc->running > 0) { - /* kill thread */ - sc->running = 0; - wakeup(sc); - /* wait for thread to finish. */ - while (sc->running != -1) - msleep(sc, &sc->sc_mtx, 0, "detach", 0); - } - MMCSD_UNLOCK(sc); + for (i = 0; i < MMC_PART_MAX; i++) { + part = sc->part[i]; + if (part != NULL && part->disk != NULL) { + MMCSD_PART_LOCK(part); + part->suspend = 1; + if (part->running > 0) { + /* kill thread */ + part->running = 0; + wakeup(part); + /* wait for thread to finish. */ + while (part->running != -1) + msleep(part, &part->part_mtx, 0, + "detach", 0); + } + MMCSD_PART_UNLOCK(part); + } + } return (0); } @@ -263,28 +626,35 @@ static int mmcsd_resume(device_t dev) { struct mmcsd_softc *sc = device_get_softc(dev); + struct mmcsd_part *part; + int i; - MMCSD_LOCK(sc); - sc->suspend = 0; - if (sc->running <= 0) { - sc->running = 1; - MMCSD_UNLOCK(sc); - kproc_create(&mmcsd_task, sc, &sc->p, 0, 0, "%s: mmc/sd card", - device_get_nameunit(dev)); - } else - MMCSD_UNLOCK(sc); + for (i = 0; i < MMC_PART_MAX; i++) { + part = sc->part[i]; + if (part != NULL && part->disk != NULL) { + MMCSD_PART_LOCK(part); + part->suspend = 0; + if (part->running <= 0) { + part->running = 1; + kproc_create(&mmcsd_task, part, &part->p, 0, 0, + "%s%d: mmc/sd card", part->name, part->cnt); + MMCSD_PART_UNLOCK(part); + } else + MMCSD_PART_UNLOCK(part); + } + } return (0); } static int -mmcsd_open(struct disk *dp) +mmcsd_open(struct disk *dp __unused) { return (0); } static int -mmcsd_close(struct disk *dp) +mmcsd_close(struct disk *dp __unused) { return (0); @@ -294,47 +664,333 @@ static void mmcsd_strategy(struct bio *bp) { struct mmcsd_softc *sc; + struct mmcsd_part *part; - sc = (struct mmcsd_softc *)bp->bio_disk->d_drv1; - MMCSD_LOCK(sc); - if (sc->running > 0 || sc->suspend > 0) { - bioq_disksort(&sc->bio_queue, bp); - MMCSD_UNLOCK(sc); - wakeup(sc); + part = bp->bio_disk->d_drv1; + sc = part->sc; + MMCSD_PART_LOCK(part); + if (part->running > 0 || part->suspend > 0) { + bioq_disksort(&part->bio_queue, bp); + MMCSD_PART_UNLOCK(part); + wakeup(part); } else { - MMCSD_UNLOCK(sc); + MMCSD_PART_UNLOCK(part); biofinish(bp, NULL, ENXIO); } } +static int +mmcsd_ioctl_rpmb(struct cdev *dev, u_long cmd, caddr_t data, + int fflag, struct thread *td __unused) +{ + + return (mmcsd_ioctl(dev->si_drv1, cmd, data, fflag)); +} + +static int +mmcsd_ioctl_disk(struct disk *disk, u_long cmd, void *data, int fflag, + struct thread *td __unused) +{ + + return (mmcsd_ioctl(disk->d_drv1, cmd, data, fflag)); +} + +static int +mmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void *data, int fflag) +{ + struct mmc_ioc_cmd *mic; + struct mmc_ioc_multi_cmd *mimc; + int i, err; + u_long cnt, size; + + if ((fflag & FREAD) == 0) + return (EBADF); + + err = 0; + switch (cmd) { + case MMC_IOC_CMD: + mic = data; + err = mmcsd_ioctl_cmd(part, data, fflag); + break; + case MMC_IOC_CMD_MULTI: + mimc = data; + if (mimc->num_of_cmds == 0) + break; + if (mimc->num_of_cmds > MMC_IOC_MAX_CMDS) + return (EINVAL); + cnt = mimc->num_of_cmds; + size = sizeof(*mic) * cnt; + mic = malloc(size, M_TEMP, M_WAITOK); + err = copyin((const void *)mimc->cmds, mic, size); + if (err != 0) + break; + for (i = 0; i < cnt; i++) { + err = mmcsd_ioctl_cmd(part, &mic[i], fflag); + if (err != 0) + break; + } + free(mic, M_TEMP); + break; + default: + return (ENOIOCTL); + } + return (err); +} + +static int +mmcsd_ioctl_cmd(struct mmcsd_part *part, struct mmc_ioc_cmd *mic, int fflag) +{ + struct mmc_command cmd; + struct mmc_data data; + struct mmcsd_softc *sc; + device_t dev, mmcbr; + void *dp; + u_long len; + int err, retries; + uint32_t status; + uint16_t rca; + + if ((fflag & FWRITE) == 0 && mic->write_flag != 0) + return (EBADF); + + if (part->ro == TRUE && mic->write_flag != 0) + return (EROFS); + + err = 0; + dp = NULL; + len = mic->blksz * mic->blocks; + if (len > MMC_IOC_MAX_BYTES) + return (EOVERFLOW); + if (len != 0) { + dp = malloc(len, M_TEMP, M_WAITOK); + err = copyin((void *)(uintptr_t)mic->data_ptr, dp, len); + if (err != 0) + goto out; + } + memset(&cmd, 0, sizeof(cmd)); + memset(&data, 0, sizeof(data)); + cmd.opcode = mic->opcode; + cmd.arg = mic->arg; + cmd.flags = mic->flags; + if (len != 0) { + data.len = len; + data.data = dp; + data.flags = mic->write_flag != 0 ? MMC_DATA_WRITE : + MMC_DATA_READ; + cmd.data = &data; + } + sc = part->sc; + rca = sc->rca; + if (mic->is_acmd == 0) { + /* Enforce/patch/restrict RCA-based commands */ + switch (cmd.opcode) { + case MMC_SET_RELATIVE_ADDR: + case MMC_SELECT_CARD: + err = EPERM; + goto out; + case MMC_STOP_TRANSMISSION: + if ((cmd.arg & 0x1) == 0) + break; + /* FALLTHROUGH */ + case MMC_SLEEP_AWAKE: + case MMC_SEND_CSD: + case MMC_SEND_CID: + case MMC_SEND_STATUS: + case MMC_GO_INACTIVE_STATE: + case MMC_FAST_IO: + case MMC_APP_CMD: + cmd.arg = (cmd.arg & 0x0000FFFF) | (rca << 16); + break; + default: + break; + } + } + dev = sc->dev; + mmcbr = sc->mmcbr; + MMCBUS_ACQUIRE_BUS(mmcbr, dev); + err = mmcsd_switch_part(mmcbr, dev, rca, part->type); + if (err != MMC_ERR_NONE) + goto release; + if (part->type == EXT_CSD_PART_CONFIG_ACC_RPMB) { + err = mmcsd_set_blockcount(sc, mic->blocks, + mic->write_flag & (1 << 31)); + if (err != MMC_ERR_NONE) + goto release; + } + if (mic->is_acmd != 0) + (void)mmc_wait_for_app_cmd(mmcbr, dev, rca, &cmd, 0); + else + (void)mmc_wait_for_cmd(mmcbr, dev, &cmd, 0); + if (part->type == EXT_CSD_PART_CONFIG_ACC_RPMB) { + /* + * If the request went to the RPMB partition, try to ensure + * that the command actually has completed ... + */ + retries = MMCSD_CMD_RETRIES; + do { + err = mmc_send_status(mmcbr, dev, rca, &status); + if (err != MMC_ERR_NONE) + break; + if (R1_STATUS(status) == 0 && + R1_CURRENT_STATE(status) != R1_STATE_PRG) + break; + DELAY(1000); + } while (retries-- > 0); + + /* ... and always switch back to the default partition. */ + err = mmcsd_switch_part(mmcbr, dev, rca, + EXT_CSD_PART_CONFIG_ACC_DEFAULT); + if (err != MMC_ERR_NONE) + goto release; + } + /* + * If EXT_CSD was changed, our copy is outdated now. Specifically, + * the upper bits of EXT_CSD_PART_CONFIG used in mmcsd_switch_part(), + * so retrieve EXT_CSD again. + */ + if (cmd.opcode == MMC_SWITCH_FUNC) { + err = mmc_send_ext_csd(mmcbr, dev, sc->ext_csd); + if (err != MMC_ERR_NONE) + goto release; + } + MMCBUS_RELEASE_BUS(mmcbr, dev); + if (cmd.error != MMC_ERR_NONE) { + switch (cmd.error) { + case MMC_ERR_TIMEOUT: + err = ETIMEDOUT; + break; + case MMC_ERR_BADCRC: + err = EILSEQ; + break; + case MMC_ERR_INVALID: + err = EINVAL; + break; + case MMC_ERR_NO_MEMORY: + err = ENOMEM; + break; + default: + err = EIO; + break; + } + goto out; + } + memcpy(mic->response, cmd.resp, 4 * sizeof(uint32_t)); + if (mic->write_flag == 0 && len != 0) { + err = copyout(dp, (void *)(uintptr_t)mic->data_ptr, len); + if (err != 0) + goto out; + } + goto out; + +release: + MMCBUS_RELEASE_BUS(mmcbr, dev); + err = EIO; + +out: + if (dp != NULL) + free(dp, M_TEMP); + return (err); +} + +static int +mmcsd_getattr(struct bio *bp) +{ + struct mmcsd_part *part; + device_t dev; + + if (strcmp(bp->bio_attribute, "MMC::device") == 0) { + if (bp->bio_length != sizeof(dev)) + return (EFAULT); + part = bp->bio_disk->d_drv1; + dev = part->sc->dev; + bcopy(&dev, bp->bio_data, sizeof(dev)); + bp->bio_completed = bp->bio_length; + return (0); + } + return (-1); +} + +static int +mmcsd_set_blockcount(struct mmcsd_softc *sc, u_int count, bool reliable) +{ + struct mmc_command cmd; + struct mmc_request req; + + memset(&req, 0, sizeof(req)); + memset(&cmd, 0, sizeof(cmd)); + cmd.mrq = &req; + req.cmd = &cmd; + cmd.opcode = MMC_SET_BLOCK_COUNT; + cmd.arg = count & 0x0000FFFF; + if (reliable) + cmd.arg |= 1 << 31; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + MMCBUS_WAIT_FOR_REQUEST(sc->mmcbr, sc->dev, &req); + return (cmd.error); +} + +static int +mmcsd_switch_part(device_t bus, device_t dev, uint16_t rca, u_int part) +{ + struct mmcsd_softc *sc; + int err; + uint8_t value; + + sc = device_get_softc(dev); + + if (sc->part_curr == part) + return (MMC_ERR_NONE); + + if (sc->mode == mode_sd) + return (MMC_ERR_NONE); + + value = (sc->ext_csd[EXT_CSD_PART_CONFIG] & + ~EXT_CSD_PART_CONFIG_ACC_MASK) | part; + /* Jump! */ + err = mmc_switch(bus, dev, rca, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_PART_CONFIG, value, sc->part_time, true); + if (err != MMC_ERR_NONE) + return (err); + + sc->ext_csd[EXT_CSD_PART_CONFIG] = value; + sc->part_curr = part; + return (MMC_ERR_NONE); +} + static const char * mmcsd_errmsg(int e) { + if (e < 0 || e > MMC_ERR_MAX) return "Bad error code"; return errmsg[e]; } static daddr_t -mmcsd_rw(struct mmcsd_softc *sc, struct bio *bp) +mmcsd_rw(struct mmcsd_part *part, struct bio *bp) { daddr_t block, end; struct mmc_command cmd; struct mmc_command stop; struct mmc_request req; struct mmc_data data; - device_t dev = sc->dev; - int sz = sc->disk->d_sectorsize; - device_t mmcbr = device_get_parent(dev); + struct mmcsd_softc *sc; + device_t dev, mmcbr; + int numblocks, sz; + char *vaddr; + + sc = part->sc; + dev = sc->dev; + mmcbr = sc->mmcbr; block = bp->bio_pblkno; + sz = part->disk->d_sectorsize; end = bp->bio_pblkno + (bp->bio_bcount / sz); while (block < end) { - char *vaddr = bp->bio_data + - (block - bp->bio_pblkno) * sz; - int numblocks = min(end - block, mmc_get_max_data(dev)); + vaddr = bp->bio_data + (block - bp->bio_pblkno) * sz; + numblocks = min(end - block, mmc_get_max_data(dev)); memset(&req, 0, sizeof(req)); - memset(&cmd, 0, sizeof(cmd)); + memset(&cmd, 0, sizeof(cmd)); memset(&stop, 0, sizeof(stop)); memset(&data, 0, sizeof(data)); cmd.mrq = &req; @@ -372,10 +1028,11 @@ mmcsd_rw(struct mmcsd_softc *sc, struct bio *bp) } MMCBUS_WAIT_FOR_REQUEST(mmcbr, dev, &req); if (req.cmd->error != MMC_ERR_NONE) { - if (ppsratecheck(&sc->log_time, &sc->log_count, LOG_PPS)) { + if (ppsratecheck(&sc->log_time, &sc->log_count, + LOG_PPS)) device_printf(dev, "Error indicated: %d %s\n", - req.cmd->error, mmcsd_errmsg(req.cmd->error)); - } + req.cmd->error, + mmcsd_errmsg(req.cmd->error)); break; } block += numblocks; @@ -384,33 +1041,37 @@ mmcsd_rw(struct mmcsd_softc *sc, struct bio *bp) } static daddr_t -mmcsd_delete(struct mmcsd_softc *sc, struct bio *bp) +mmcsd_delete(struct mmcsd_part *part, struct bio *bp) { daddr_t block, end, start, stop; struct mmc_command cmd; struct mmc_request req; - device_t dev = sc->dev; - int sz = sc->disk->d_sectorsize; - int erase_sector; - device_t mmcbr = device_get_parent(dev); + struct mmcsd_softc *sc; + device_t dev, mmcbr; + int erase_sector, sz; + + sc = part->sc; + dev = sc->dev; + mmcbr = sc->mmcbr; block = bp->bio_pblkno; + sz = part->disk->d_sectorsize; end = bp->bio_pblkno + (bp->bio_bcount / sz); /* Coalesce with part remaining from previous request. */ - if (block > sc->eblock && block <= sc->eend) - block = sc->eblock; - if (end >= sc->eblock && end < sc->eend) - end = sc->eend; + if (block > part->eblock && block <= part->eend) + block = part->eblock; + if (end >= part->eblock && end < part->eend) + end = part->eend; /* Safe round to the erase sector boundaries. */ erase_sector = mmc_get_erase_sector(dev); start = block + erase_sector - 1; /* Round up. */ start -= start % erase_sector; stop = end; /* Round down. */ - stop -= end % erase_sector; - /* We can't erase area smaller then sector, store it for later. */ + stop -= end % erase_sector; + /* We can't erase an area smaller than a sector, store it for later. */ if (start >= stop) { - sc->eblock = block; - sc->eend = end; + part->eblock = block; + part->eend = end; return (end); } @@ -463,40 +1124,54 @@ mmcsd_delete(struct mmcsd_softc *sc, struct bio *bp) return (block); } /* Store one of remaining parts for the next call. */ - if (bp->bio_pblkno >= sc->eblock || block == start) { - sc->eblock = stop; /* Predict next forward. */ - sc->eend = end; + if (bp->bio_pblkno >= part->eblock || block == start) { + part->eblock = stop; /* Predict next forward. */ + part->eend = end; } else { - sc->eblock = block; /* Predict next backward. */ - sc->eend = start; + part->eblock = block; /* Predict next backward. */ + part->eend = start; } return (end); } static int -mmcsd_dump(void *arg, void *virtual, vm_offset_t physical, - off_t offset, size_t length) +mmcsd_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, + size_t length) { - struct disk *disk = arg; - struct mmcsd_softc *sc = (struct mmcsd_softc *)disk->d_drv1; - device_t dev = sc->dev; struct bio bp; daddr_t block, end; - device_t mmcbr = device_get_parent(dev); + struct disk *disk; + struct mmcsd_softc *sc; + struct mmcsd_part *part; + device_t dev, mmcbr; + int err; /* length zero is special and really means flush buffers to media */ if (!length) return (0); + disk = arg; + part = disk->d_drv1; + sc = part->sc; + dev = sc->dev; + mmcbr = sc->mmcbr; + bzero(&bp, sizeof(struct bio)); bp.bio_disk = disk; bp.bio_pblkno = offset / disk->d_sectorsize; bp.bio_bcount = length; bp.bio_data = virtual; bp.bio_cmd = BIO_WRITE; - end = bp.bio_pblkno + bp.bio_bcount / sc->disk->d_sectorsize; + end = bp.bio_pblkno + bp.bio_bcount / disk->d_sectorsize; MMCBUS_ACQUIRE_BUS(mmcbr, dev); - block = mmcsd_rw(sc, &bp); + err = mmcsd_switch_part(mmcbr, dev, sc->rca, part->type); + if (err != MMC_ERR_NONE) { + if (ppsratecheck(&sc->log_time, &sc->log_count, LOG_PPS)) + device_printf(dev, "Partition switch error\n"); + MMCBUS_RELEASE_BUS(mmcbr, dev); + return (EIO); + } + block = mmcsd_rw(part, &bp); MMCBUS_RELEASE_BUS(mmcbr, dev); return ((end < block) ? EIO : 0); } @@ -504,24 +1179,30 @@ mmcsd_dump(void *arg, void *virtual, vm_offset_t physical, static void mmcsd_task(void *arg) { - struct mmcsd_softc *sc = (struct mmcsd_softc*)arg; - struct bio *bp; - int sz; daddr_t block, end; - device_t dev = sc->dev; - device_t mmcbr = device_get_parent(sc->dev); + struct mmcsd_part *part; + struct mmcsd_softc *sc; + struct bio *bp; + device_t dev, mmcbr; + int err, sz; + + part = arg; + sc = part->sc; + dev = sc->dev; + mmcbr = sc->mmcbr; while (1) { - MMCSD_LOCK(sc); + MMCSD_PART_LOCK(part); do { - if (sc->running == 0) + if (part->running == 0) goto out; - bp = bioq_takefirst(&sc->bio_queue); + bp = bioq_takefirst(&part->bio_queue); if (bp == NULL) - msleep(sc, &sc->sc_mtx, PRIBIO, "jobqueue", 0); + msleep(part, &part->part_mtx, PRIBIO, + "jobqueue", 0); } while (bp == NULL); - MMCSD_UNLOCK(sc); - if (bp->bio_cmd != BIO_READ && mmc_get_read_only(dev)) { + MMCSD_PART_UNLOCK(part); + if (bp->bio_cmd != BIO_READ && part->ro) { bp->bio_error = EROFS; bp->bio_resid = bp->bio_bcount; bp->bio_flags |= BIO_ERROR; @@ -529,17 +1210,25 @@ mmcsd_task(void *arg) continue; } MMCBUS_ACQUIRE_BUS(mmcbr, dev); - sz = sc->disk->d_sectorsize; + sz = part->disk->d_sectorsize; block = bp->bio_pblkno; end = bp->bio_pblkno + (bp->bio_bcount / sz); + err = mmcsd_switch_part(mmcbr, dev, sc->rca, part->type); + if (err != MMC_ERR_NONE) { + if (ppsratecheck(&sc->log_time, &sc->log_count, + LOG_PPS)) + device_printf(dev, "Partition switch error\n"); + goto release; + } if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) { /* Access to the remaining erase block obsoletes it. */ - if (block < sc->eend && end > sc->eblock) - sc->eblock = sc->eend = 0; - block = mmcsd_rw(sc, bp); + if (block < part->eend && end > part->eblock) + part->eblock = part->eend = 0; + block = mmcsd_rw(part, bp); } else if (bp->bio_cmd == BIO_DELETE) { - block = mmcsd_delete(sc, bp); + block = mmcsd_delete(part, bp); } +release: MMCBUS_RELEASE_BUS(mmcbr, dev); if (block < end) { bp->bio_error = EIO; @@ -552,9 +1241,9 @@ mmcsd_task(void *arg) } out: /* tell parent we're done */ - sc->running = -1; - MMCSD_UNLOCK(sc); - wakeup(sc); + part->running = -1; + MMCSD_PART_UNLOCK(part); + wakeup(part); kproc_exit(0); } @@ -586,4 +1275,22 @@ static driver_t mmcsd_driver = { }; static devclass_t mmcsd_devclass; -DRIVER_MODULE(mmcsd, mmc, mmcsd_driver, mmcsd_devclass, NULL, NULL); +static int +mmcsd_handler(module_t mod __unused, int what, void *arg __unused) +{ + + switch (what) { + case MOD_LOAD: + flash_register_slicer(mmcsd_slicer, FLASH_SLICES_TYPE_MMC, + TRUE); + return (0); + case MOD_UNLOAD: + flash_register_slicer(NULL, FLASH_SLICES_TYPE_MMC, TRUE); + return (0); + } + return (0); +} + +DRIVER_MODULE(mmcsd, mmc, mmcsd_driver, mmcsd_devclass, mmcsd_handler, NULL); +MODULE_DEPEND(mmcsd, g_flashmap, 0, 0, 0); +MMC_DEPEND(mmcsd); diff --git a/sys/dev/mmc/mmcvar.h b/sys/dev/mmc/mmcvar.h index c7a4af994..9f62b1126 100644 --- a/sys/dev/mmc/mmcvar.h +++ b/sys/dev/mmc/mmcvar.h @@ -49,15 +49,14 @@ * or the SD Card Association to disclose or distribute any technical * information, know-how or other confidential information to any third party. * - * "$FreeBSD$" + * $FreeBSD$ */ #ifndef DEV_MMC_MMCVAR_H #define DEV_MMC_MMCVAR_H -#include - 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) diff --git a/sys/dev/sdhci/sdhci.c b/sys/dev/sdhci/sdhci.c index d1b0ecf65..f1f2a70a3 100644 --- a/sys/dev/sdhci/sdhci.c +++ b/sys/dev/sdhci/sdhci.c @@ -56,18 +56,19 @@ SYSCTL_NODE(_hw, OID_AUTO, sdhci, CTLFLAG_RD, 0, "sdhci driver"); static int sdhci_debug; TUNABLE_INT("hw.sdhci.debug", &sdhci_debug); -SYSCTL_INT(_hw_sdhci, OID_AUTO, debug, CTLFLAG_RWTUN, &sdhci_debug, 0, "Debug level"); +SYSCTL_INT(_hw_sdhci, OID_AUTO, debug, CTLFLAG_RWTUN, &sdhci_debug, 0, + "Debug level"); -#define RD1(slot, off) SDHCI_READ_1((slot)->bus, (slot), (off)) -#define RD2(slot, off) SDHCI_READ_2((slot)->bus, (slot), (off)) -#define RD4(slot, off) SDHCI_READ_4((slot)->bus, (slot), (off)) -#define RD_MULTI_4(slot, off, ptr, count) \ +#define RD1(slot, off) SDHCI_READ_1((slot)->bus, (slot), (off)) +#define RD2(slot, off) SDHCI_READ_2((slot)->bus, (slot), (off)) +#define RD4(slot, off) SDHCI_READ_4((slot)->bus, (slot), (off)) +#define RD_MULTI_4(slot, off, ptr, count) \ SDHCI_READ_MULTI_4((slot)->bus, (slot), (off), (ptr), (count)) -#define WR1(slot, off, val) SDHCI_WRITE_1((slot)->bus, (slot), (off), (val)) -#define WR2(slot, off, val) SDHCI_WRITE_2((slot)->bus, (slot), (off), (val)) -#define WR4(slot, off, val) SDHCI_WRITE_4((slot)->bus, (slot), (off), (val)) -#define WR_MULTI_4(slot, off, ptr, count) \ +#define WR1(slot, off, val) SDHCI_WRITE_1((slot)->bus, (slot), (off), (val)) +#define WR2(slot, off, val) SDHCI_WRITE_2((slot)->bus, (slot), (off), (val)) +#define WR4(slot, off, val) SDHCI_WRITE_4((slot)->bus, (slot), (off), (val)) +#define WR_MULTI_4(slot, off, ptr, count) \ SDHCI_WRITE_MULTI_4((slot)->bus, (slot), (off), (ptr), (count)) static void sdhci_set_clock(struct sdhci_slot *slot, uint32_t clock); @@ -78,13 +79,13 @@ static void sdhci_card_poll(void *); static void sdhci_card_task(void *, int); /* helper routines */ -#define SDHCI_LOCK(_slot) mtx_lock(&(_slot)->mtx) +#define SDHCI_LOCK(_slot) mtx_lock(&(_slot)->mtx) #define SDHCI_UNLOCK(_slot) mtx_unlock(&(_slot)->mtx) -#define SDHCI_LOCK_INIT(_slot) \ +#define SDHCI_LOCK_INIT(_slot) \ mtx_init(&_slot->mtx, "SD slot mtx", "sdhci", MTX_DEF) -#define SDHCI_LOCK_DESTROY(_slot) mtx_destroy(&_slot->mtx); -#define SDHCI_ASSERT_LOCKED(_slot) mtx_assert(&_slot->mtx, MA_OWNED); -#define SDHCI_ASSERT_UNLOCKED(_slot) mtx_assert(&_slot->mtx, MA_NOTOWNED); +#define SDHCI_LOCK_DESTROY(_slot) mtx_destroy(&_slot->mtx); +#define SDHCI_ASSERT_LOCKED(_slot) mtx_assert(&_slot->mtx, MA_OWNED); +#define SDHCI_ASSERT_UNLOCKED(_slot) mtx_assert(&_slot->mtx, MA_NOTOWNED); #define SDHCI_DEFAULT_MAX_FREQ 50 @@ -97,19 +98,21 @@ static void sdhci_card_task(void *, int); /* * Broadcom BCM577xx Controller Constants */ -#define BCM577XX_DEFAULT_MAX_DIVIDER 256 /* Maximum divider supported by the default clock source. */ -#define BCM577XX_ALT_CLOCK_BASE 63000000 /* Alternative clock's base frequency. */ - -#define BCM577XX_HOST_CONTROL 0x198 -#define BCM577XX_CTRL_CLKSEL_MASK 0xFFFFCFFF -#define BCM577XX_CTRL_CLKSEL_SHIFT 12 -#define BCM577XX_CTRL_CLKSEL_DEFAULT 0x0 -#define BCM577XX_CTRL_CLKSEL_64MHZ 0x3 +/* Maximum divider supported by the default clock source. */ +#define BCM577XX_DEFAULT_MAX_DIVIDER 256 +/* Alternative clock's base frequency. */ +#define BCM577XX_ALT_CLOCK_BASE 63000000 +#define BCM577XX_HOST_CONTROL 0x198 +#define BCM577XX_CTRL_CLKSEL_MASK 0xFFFFCFFF +#define BCM577XX_CTRL_CLKSEL_SHIFT 12 +#define BCM577XX_CTRL_CLKSEL_DEFAULT 0x0 +#define BCM577XX_CTRL_CLKSEL_64MHZ 0x3 static void sdhci_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) { + if (error != 0) { printf("getaddr: error %d\n", error); return; @@ -123,7 +126,7 @@ slot_printf(struct sdhci_slot *slot, const char * fmt, ...) va_list ap; int retval; - retval = printf("%s-slot%d: ", + retval = printf("%s-slot%d: ", device_get_nameunit(slot->bus), slot->num); va_start(ap, fmt); @@ -135,6 +138,7 @@ slot_printf(struct sdhci_slot *slot, const char * fmt, ...) static void sdhci_dumpregs(struct sdhci_slot *slot) { + slot_printf(slot, "============== REGISTER DUMP ==============\n"); @@ -167,6 +171,7 @@ static void sdhci_reset(struct sdhci_slot *slot, uint8_t mask) { int timeout; + uint32_t clock; if (slot->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) { if (!SDHCI_GET_CARD_PRESENT(slot->bus, slot)) @@ -176,8 +181,6 @@ sdhci_reset(struct sdhci_slot *slot, uint8_t mask) /* Some controllers need this kick or reset won't work. */ if ((mask & SDHCI_RESET_ALL) == 0 && (slot->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)) { - uint32_t clock; - /* This is to force an update */ clock = slot->clock; slot->clock = 0; @@ -196,7 +199,7 @@ sdhci_reset(struct sdhci_slot *slot, uint8_t mask) * Resets on TI OMAPs and AM335x are incompatible with SDHCI * specification. The reset bit has internal propagation delay, * so a fast read after write returns 0 even if reset process is - * in progress. The workaround is to poll for 1 before polling + * in progress. The workaround is to poll for 1 before polling * for 0. In the worst case, if we miss seeing it asserted the * time we spent waiting is enough to ensure the reset finishes. */ @@ -264,23 +267,28 @@ sdhci_set_clock(struct sdhci_slot *slot, uint32_t clock) /* Turn off the clock. */ clk = RD2(slot, SDHCI_CLOCK_CONTROL); WR2(slot, SDHCI_CLOCK_CONTROL, clk & ~SDHCI_CLOCK_CARD_EN); - /* If no clock requested - left it so. */ + /* If no clock requested - leave it so. */ if (clock == 0) return; - + /* Determine the clock base frequency */ clk_base = slot->max_clk; if (slot->quirks & SDHCI_QUIRK_BCM577XX_400KHZ_CLKSRC) { - clk_sel = RD2(slot, BCM577XX_HOST_CONTROL) & BCM577XX_CTRL_CLKSEL_MASK; + clk_sel = RD2(slot, BCM577XX_HOST_CONTROL) & + BCM577XX_CTRL_CLKSEL_MASK; - /* Select clock source appropriate for the requested frequency. */ + /* + * Select clock source appropriate for the requested frequency. + */ if ((clk_base / BCM577XX_DEFAULT_MAX_DIVIDER) > clock) { clk_base = BCM577XX_ALT_CLOCK_BASE; - clk_sel |= (BCM577XX_CTRL_CLKSEL_64MHZ << BCM577XX_CTRL_CLKSEL_SHIFT); + clk_sel |= (BCM577XX_CTRL_CLKSEL_64MHZ << + BCM577XX_CTRL_CLKSEL_SHIFT); } else { - clk_sel |= (BCM577XX_CTRL_CLKSEL_DEFAULT << BCM577XX_CTRL_CLKSEL_SHIFT); + clk_sel |= (BCM577XX_CTRL_CLKSEL_DEFAULT << + BCM577XX_CTRL_CLKSEL_SHIFT); } - + WR2(slot, BCM577XX_HOST_CONTROL, clk_sel); } @@ -298,14 +306,13 @@ sdhci_set_clock(struct sdhci_slot *slot, uint32_t clock) } /* Divider 1:1 is 0x00, 2:1 is 0x01, 256:1 is 0x80 ... */ div >>= 1; - } - else { - /* Version 3.0 divisors are multiples of two up to 1023*2 */ + } else { + /* Version 3.0 divisors are multiples of two up to 1023 * 2 */ if (clock >= clk_base) div = 0; else { - for (div = 2; div < SDHCI_300_MAX_DIVIDER; div += 2) { - if ((clk_base / div) <= clock) + for (div = 2; div < SDHCI_300_MAX_DIVIDER; div += 2) { + if ((clk_base / div) <= clock) break; } } @@ -313,7 +320,7 @@ sdhci_set_clock(struct sdhci_slot *slot, uint32_t clock) } if (bootverbose || sdhci_debug) - slot_printf(slot, "Divider %d for freq %d (base %d)\n", + slot_printf(slot, "Divider %d for freq %d (base %d)\n", div, clock, clk_base); /* Now we have got divider, set it. */ @@ -330,7 +337,7 @@ sdhci_set_clock(struct sdhci_slot *slot, uint32_t clock) while (!((clk = RD2(slot, SDHCI_CLOCK_CONTROL)) & SDHCI_CLOCK_INT_STABLE)) { if (timeout == 0) { - slot_printf(slot, + slot_printf(slot, "Internal clock never stabilised.\n"); sdhci_dumpregs(slot); return; @@ -356,7 +363,7 @@ sdhci_set_power(struct sdhci_slot *slot, u_char power) /* Turn off the power. */ pwr = 0; WR1(slot, SDHCI_POWER_CONTROL, pwr); - /* If power down requested - left it so. */ + /* If power down requested - leave it so. */ if (power == 0) return; /* Set voltage. */ @@ -492,9 +499,10 @@ sdhci_transfer_pio(struct sdhci_slot *slot) } static void -sdhci_card_task(void *arg, int pending) +sdhci_card_task(void *arg, int pending __unused) { struct sdhci_slot *slot = arg; + device_t d; SDHCI_LOCK(slot); if (SDHCI_GET_CARD_PRESENT(slot->bus, slot)) { @@ -513,7 +521,7 @@ sdhci_card_task(void *arg, int pending) /* If no card present - detach mmc bus. */ if (bootverbose || sdhci_debug) slot_printf(slot, "Card removed\n"); - device_t d = slot->dev; + d = slot->dev; slot->dev = NULL; SDHCI_UNLOCK(slot); device_delete_child(slot->bus, d); @@ -556,7 +564,7 @@ sdhci_handle_card_present(struct sdhci_slot *slot, bool is_present) SDHCI_UNLOCK(slot); } -static void +static void sdhci_card_poll(void *arg) { struct sdhci_slot *slot = arg; @@ -566,7 +574,7 @@ sdhci_card_poll(void *arg) callout_reset(&slot->card_poll_callout, SDHCI_CARD_PRESENT_TICKS, sdhci_card_poll, slot); } - + int sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num) { @@ -604,7 +612,7 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num) if (err != 0 || slot->paddr == 0) { device_printf(dev, "Can't load DMA memory\n"); SDHCI_LOCK_DESTROY(slot); - if(err) + if (err) return (err); else return (EFAULT); @@ -612,7 +620,7 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num) /* Initialize slot. */ sdhci_init(slot); - slot->version = (RD2(slot, SDHCI_HOST_VERSION) + slot->version = (RD2(slot, SDHCI_HOST_VERSION) >> SDHCI_SPEC_VER_SHIFT) & SDHCI_SPEC_VER_MASK; if (slot->quirks & SDHCI_QUIRK_MISSING_CAPS) caps = slot->caps; @@ -622,7 +630,7 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num) if (slot->version >= SDHCI_SPEC_300) freq = (caps & SDHCI_CLOCK_V3_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; - else + else freq = (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; if (freq != 0) @@ -635,7 +643,8 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num) if (slot->max_clk == 0) { slot->max_clk = SDHCI_DEFAULT_MAX_FREQ * 1000000; device_printf(dev, "Hardware doesn't specify base clock " - "frequency, using %dMHz as default.\n", SDHCI_DEFAULT_MAX_FREQ); + "frequency, using %dMHz as default.\n", + SDHCI_DEFAULT_MAX_FREQ); } /* Calculate/set timeout clock frequency. */ if (slot->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK) { @@ -643,8 +652,8 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num) } else if (slot->quirks & SDHCI_QUIRK_DATA_TIMEOUT_1MHZ) { slot->timeout_clk = 1000; } else { - slot->timeout_clk = - (caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT; + slot->timeout_clk = (caps & SDHCI_TIMEOUT_CLK_MASK) >> + SDHCI_TIMEOUT_CLK_SHIFT; if (caps & SDHCI_TIMEOUT_CLK_UNIT) slot->timeout_clk *= 1000; } @@ -677,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; @@ -688,7 +701,7 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num) if (slot->quirks & SDHCI_QUIRK_ALL_SLOTS_NON_REMOVABLE) slot->opt |= SDHCI_NON_REMOVABLE; - /* + /* * Use platform-provided transfer backend * with PIO as a fallback mechanism */ @@ -732,6 +745,7 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num) void sdhci_start_slot(struct sdhci_slot *slot) { + sdhci_card_task(slot, 0); } @@ -767,6 +781,7 @@ sdhci_cleanup_slot(struct sdhci_slot *slot) int sdhci_generic_suspend(struct sdhci_slot *slot) { + sdhci_reset(slot, SDHCI_RESET_ALL); return (0); @@ -775,14 +790,16 @@ sdhci_generic_suspend(struct sdhci_slot *slot) int sdhci_generic_resume(struct sdhci_slot *slot) { + sdhci_init(slot); return (0); } uint32_t -sdhci_generic_min_freq(device_t brdev, struct sdhci_slot *slot) +sdhci_generic_min_freq(device_t brdev __unused, struct sdhci_slot *slot) { + if (slot->version >= SDHCI_SPEC_300) return (slot->max_clk / SDHCI_300_MAX_DIVIDER); else @@ -790,7 +807,7 @@ sdhci_generic_min_freq(device_t brdev, struct sdhci_slot *slot) } bool -sdhci_generic_get_card_present(device_t brdev, struct sdhci_slot *slot) +sdhci_generic_get_card_present(device_t brdev __unused, struct sdhci_slot *slot) { if (slot->opt & SDHCI_NON_REMOVABLE) @@ -826,21 +843,21 @@ sdhci_generic_update_ios(device_t brdev, device_t reqdev) } else { panic("Invalid bus width: %d", ios->bus_width); } - if (ios->timing == bus_timing_hs && + if (ios->timing == bus_timing_hs && !(slot->quirks & SDHCI_QUIRK_DONT_SET_HISPD_BIT)) slot->hostctrl |= SDHCI_CTRL_HISPD; else slot->hostctrl &= ~SDHCI_CTRL_HISPD; WR1(slot, SDHCI_HOST_CONTROL, slot->hostctrl); /* Some controllers like reset after bus changes. */ - if(slot->quirks & SDHCI_QUIRK_RESET_ON_IOS) + if (slot->quirks & SDHCI_QUIRK_RESET_ON_IOS) sdhci_reset(slot, SDHCI_RESET_CMD | SDHCI_RESET_DATA); SDHCI_UNLOCK(slot); return (0); } -static void +static void sdhci_req_done(struct sdhci_slot *slot) { struct mmc_request *req; @@ -853,8 +870,8 @@ sdhci_req_done(struct sdhci_slot *slot) req->done(req); } } - -static void + +static void sdhci_timeout(void *arg) { struct sdhci_slot *slot = arg; @@ -862,17 +879,16 @@ sdhci_timeout(void *arg) if (slot->curcmd != NULL) { slot_printf(slot, " Controller timeout\n"); sdhci_dumpregs(slot); - sdhci_reset(slot, SDHCI_RESET_CMD|SDHCI_RESET_DATA); + sdhci_reset(slot, SDHCI_RESET_CMD | SDHCI_RESET_DATA); slot->curcmd->error = MMC_ERR_TIMEOUT; sdhci_req_done(slot); } else { slot_printf(slot, " Spurious timeout - no active command\n"); } } - + static void -sdhci_set_transfer_mode(struct sdhci_slot *slot, - struct mmc_data *data) +sdhci_set_transfer_mode(struct sdhci_slot *slot, struct mmc_data *data) { uint16_t mode; @@ -911,8 +927,10 @@ sdhci_start_command(struct sdhci_slot *slot, struct mmc_command *cmd) return; } - /* Do not issue command if there is no card, clock or power. - * Controller will not detect timeout without clock active. */ + /* + * Do not issue command if there is no card, clock or power. + * Controller will not detect timeout without clock active. + */ if (!SDHCI_GET_CARD_PRESENT(slot->bus, slot) || slot->power == 0 || slot->clock == 0) { @@ -971,7 +989,7 @@ sdhci_start_command(struct sdhci_slot *slot, struct mmc_command *cmd) flags |= SDHCI_CMD_TYPE_ABORT; /* Prepare data. */ sdhci_start_data(slot, cmd->data); - /* + /* * Interrupt aggregation: To reduce total number of interrupts * group response interrupt with data interrupt when possible. * If there going to be data interrupt, mask response one. @@ -995,11 +1013,15 @@ static void sdhci_finish_command(struct sdhci_slot *slot) { int i; + uint32_t val; + 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) { @@ -1012,13 +1034,14 @@ sdhci_finish_command(struct sdhci_slot *slot) if (slot->curcmd->flags & MMC_RSP_PRESENT) { if (slot->curcmd->flags & MMC_RSP_136) { /* CRC is stripped so we need one byte shift. */ - uint8_t extra = 0; + extra = 0; for (i = 0; i < 4; i++) { - uint32_t val = RD4(slot, SDHCI_RESPONSE + i * 4); - if (slot->quirks & SDHCI_QUIRK_DONT_SHIFT_RESPONSE) + val = RD4(slot, SDHCI_RESPONSE + i * 4); + if (slot->quirks & + SDHCI_QUIRK_DONT_SHIFT_RESPONSE) slot->curcmd->resp[3 - i] = val; else { - slot->curcmd->resp[3 - i] = + slot->curcmd->resp[3 - i] = (val << 8) | extra; extra = val >> 24; } @@ -1057,7 +1080,7 @@ sdhci_start_data(struct sdhci_slot *slot, struct mmc_data *data) current_timeout <<= 1; } /* Compensate for an off-by-one error in the CaFe chip.*/ - if (div < 0xE && + if (div < 0xE && (slot->quirks & SDHCI_QUIRK_INCR_TIMEOUT_CONTROL)) { ++div; } @@ -1081,13 +1104,13 @@ sdhci_start_data(struct sdhci_slot *slot, struct mmc_data *data) /* Load DMA buffer. */ if (slot->flags & SDHCI_USE_DMA) { if (data->flags & MMC_DATA_READ) - bus_dmamap_sync(slot->dmatag, slot->dmamap, + bus_dmamap_sync(slot->dmatag, slot->dmamap, BUS_DMASYNC_PREREAD); else { memcpy(slot->dmamem, data->data, - (data->len < DMA_BLOCK_SIZE) ? + (data->len < DMA_BLOCK_SIZE) ? data->len : DMA_BLOCK_SIZE); - bus_dmamap_sync(slot->dmatag, slot->dmamap, + bus_dmamap_sync(slot->dmatag, slot->dmamap, BUS_DMASYNC_PREWRITE); } WR4(slot, SDHCI_DMA_ADDRESS, slot->paddr); @@ -1102,8 +1125,8 @@ sdhci_start_data(struct sdhci_slot *slot, struct mmc_data *data) /* Current data offset for both PIO and DMA. */ slot->offset = 0; /* Set block size and request IRQ on 4K border. */ - WR2(slot, SDHCI_BLOCK_SIZE, - SDHCI_MAKE_BLKSZ(DMA_BOUNDARY, (data->len < 512)?data->len:512)); + WR2(slot, SDHCI_BLOCK_SIZE, SDHCI_MAKE_BLKSZ(DMA_BOUNDARY, + (data->len < 512) ? data->len : 512)); /* Set block count. */ WR2(slot, SDHCI_BLOCK_COUNT, (data->len + 511) / 512); } @@ -1112,6 +1135,7 @@ void sdhci_finish_data(struct sdhci_slot *slot) { struct mmc_data *data = slot->curcmd->data; + size_t left; /* Interrupt aggregation: Restore command interrupt. * Auxiliary restore point for the case when data interrupt @@ -1123,13 +1147,13 @@ sdhci_finish_data(struct sdhci_slot *slot) /* Unload rest of data from DMA buffer. */ if (!slot->data_done && (slot->flags & SDHCI_USE_DMA)) { if (data->flags & MMC_DATA_READ) { - size_t left = data->len - slot->offset; - bus_dmamap_sync(slot->dmatag, slot->dmamap, + left = data->len - slot->offset; + bus_dmamap_sync(slot->dmatag, slot->dmamap, BUS_DMASYNC_POSTREAD); memcpy((u_char*)data->data + slot->offset, slot->dmamem, - (left < DMA_BLOCK_SIZE)?left:DMA_BLOCK_SIZE); + (left < DMA_BLOCK_SIZE) ? left : DMA_BLOCK_SIZE); } else - bus_dmamap_sync(slot->dmatag, slot->dmamap, + bus_dmamap_sync(slot->dmatag, slot->dmamap, BUS_DMASYNC_POSTWRITE); } slot->data_done = 1; @@ -1178,7 +1202,8 @@ sdhci_start(struct sdhci_slot *slot) } int -sdhci_generic_request(device_t brdev, device_t reqdev, struct mmc_request *req) +sdhci_generic_request(device_t brdev __unused, device_t reqdev, + struct mmc_request *req) { struct sdhci_slot *slot = device_get_ivars(reqdev); @@ -1188,9 +1213,10 @@ sdhci_generic_request(device_t brdev, device_t reqdev, struct mmc_request *req) return (EBUSY); } if (sdhci_debug > 1) { - slot_printf(slot, "CMD%u arg %#x flags %#x dlen %u dflags %#x\n", - req->cmd->opcode, req->cmd->arg, req->cmd->flags, - (req->cmd->data)?(u_int)req->cmd->data->len:0, + slot_printf(slot, + "CMD%u arg %#x flags %#x dlen %u dflags %#x\n", + req->cmd->opcode, req->cmd->arg, req->cmd->flags, + (req->cmd->data)?(u_int)req->cmd->data->len:0, (req->cmd->data)?req->cmd->data->flags:0); } slot->req = req; @@ -1207,7 +1233,7 @@ sdhci_generic_request(device_t brdev, device_t reqdev, struct mmc_request *req) } int -sdhci_generic_get_ro(device_t brdev, device_t reqdev) +sdhci_generic_get_ro(device_t brdev __unused, device_t reqdev) { struct sdhci_slot *slot = device_get_ivars(reqdev); uint32_t val; @@ -1219,7 +1245,7 @@ sdhci_generic_get_ro(device_t brdev, device_t reqdev) } int -sdhci_generic_acquire_host(device_t brdev, device_t reqdev) +sdhci_generic_acquire_host(device_t brdev __unused, device_t reqdev) { struct sdhci_slot *slot = device_get_ivars(reqdev); int err = 0; @@ -1235,7 +1261,7 @@ sdhci_generic_acquire_host(device_t brdev, device_t reqdev) } int -sdhci_generic_release_host(device_t brdev, device_t reqdev) +sdhci_generic_release_host(device_t brdev __unused, device_t reqdev) { struct sdhci_slot *slot = device_get_ivars(reqdev); @@ -1271,6 +1297,8 @@ sdhci_cmd_irq(struct sdhci_slot *slot, uint32_t intmask) static void sdhci_data_irq(struct sdhci_slot *slot, uint32_t intmask) { + struct mmc_data *data; + size_t left; if (!slot->curcmd) { slot_printf(slot, "Got data interrupt 0x%08x, but " @@ -1305,25 +1333,25 @@ sdhci_data_irq(struct sdhci_slot *slot, uint32_t intmask) /* Handle PIO interrupt. */ if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)) { - if ((slot->opt & SDHCI_PLATFORM_TRANSFER) && + if ((slot->opt & SDHCI_PLATFORM_TRANSFER) && SDHCI_PLATFORM_WILL_HANDLE(slot->bus, slot)) { - SDHCI_PLATFORM_START_TRANSFER(slot->bus, slot, &intmask); + SDHCI_PLATFORM_START_TRANSFER(slot->bus, slot, + &intmask); slot->flags |= PLATFORM_DATA_STARTED; } else sdhci_transfer_pio(slot); } /* Handle DMA border. */ if (intmask & SDHCI_INT_DMA_END) { - struct mmc_data *data = slot->curcmd->data; - size_t left; + data = slot->curcmd->data; - /* Unload DMA buffer... */ + /* Unload DMA buffer ... */ left = data->len - slot->offset; if (data->flags & MMC_DATA_READ) { bus_dmamap_sync(slot->dmatag, slot->dmamap, BUS_DMASYNC_POSTREAD); memcpy((u_char*)data->data + slot->offset, slot->dmamem, - (left < DMA_BLOCK_SIZE)?left:DMA_BLOCK_SIZE); + (left < DMA_BLOCK_SIZE) ? left : DMA_BLOCK_SIZE); } else { bus_dmamap_sync(slot->dmatag, slot->dmamap, BUS_DMASYNC_POSTWRITE); @@ -1336,7 +1364,7 @@ sdhci_data_irq(struct sdhci_slot *slot, uint32_t intmask) BUS_DMASYNC_PREREAD); } else { memcpy(slot->dmamem, (u_char*)data->data + slot->offset, - (left < DMA_BLOCK_SIZE)?left:DMA_BLOCK_SIZE); + (left < DMA_BLOCK_SIZE)? left : DMA_BLOCK_SIZE); bus_dmamap_sync(slot->dmatag, slot->dmamap, BUS_DMASYNC_PREWRITE); } @@ -1364,7 +1392,6 @@ done: SDHCI_PLATFORM_FINISH_TRANSFER(slot->bus, slot); } else sdhci_finish_data(slot); - return; } } @@ -1372,7 +1399,7 @@ static void sdhci_acmd_irq(struct sdhci_slot *slot) { uint16_t err; - + err = RD4(slot, SDHCI_ACMD12_ERR); if (!slot->curcmd) { slot_printf(slot, "Got AutoCMD12 error 0x%04x, but " @@ -1388,7 +1415,7 @@ void sdhci_generic_intr(struct sdhci_slot *slot) { uint32_t intmask, present; - + SDHCI_LOCK(slot); /* Read slot interrupt status. */ intmask = RD4(slot, SDHCI_INT_STATUS); @@ -1408,7 +1435,7 @@ sdhci_generic_intr(struct sdhci_slot *slot) SDHCI_INT_CARD_INSERT; WR4(slot, SDHCI_INT_ENABLE, slot->intmask); WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask); - WR4(slot, SDHCI_INT_STATUS, intmask & + WR4(slot, SDHCI_INT_STATUS, intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)); sdhci_handle_card_present_locked(slot, present); intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE); @@ -1421,7 +1448,7 @@ sdhci_generic_intr(struct sdhci_slot *slot) /* Handle data interrupts. */ if (intmask & SDHCI_INT_DATA_MASK) { WR4(slot, SDHCI_INT_STATUS, intmask & SDHCI_INT_DATA_MASK); - /* Dont call data_irq in case of errored command */ + /* Don't call data_irq in case of errored command. */ if ((intmask & SDHCI_INT_CMD_ERROR_MASK) == 0) sdhci_data_irq(slot, intmask & SDHCI_INT_DATA_MASK); } @@ -1447,12 +1474,13 @@ sdhci_generic_intr(struct sdhci_slot *slot) intmask); sdhci_dumpregs(slot); } - + SDHCI_UNLOCK(slot); } int -sdhci_generic_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) +sdhci_generic_read_ivar(device_t bus, device_t child, int which, + uintptr_t *result) { struct sdhci_slot *slot = device_get_ivars(child); @@ -1501,14 +1529,23 @@ sdhci_generic_read_ivar(device_t bus, device_t child, int which, uintptr_t *resu 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); } int -sdhci_generic_write_ivar(device_t bus, device_t child, int which, uintptr_t value) +sdhci_generic_write_ivar(device_t bus, device_t child, int which, + uintptr_t value) { struct sdhci_slot *slot = device_get_ivars(child); + uint32_t clock, max_clock; + int i; switch (which) { default: @@ -1524,10 +1561,6 @@ sdhci_generic_write_ivar(device_t bus, device_t child, int which, uintptr_t valu break; case MMCBR_IVAR_CLOCK: if (value > 0) { - uint32_t max_clock; - uint32_t clock; - int i; - max_clock = slot->max_clk; clock = max_clock; @@ -1538,8 +1571,7 @@ sdhci_generic_write_ivar(device_t bus, device_t child, int which, uintptr_t valu break; clock >>= 1; } - } - else { + } else { for (i = 0; i < SDHCI_300_MAX_DIVIDER; i += 2) { if (clock <= value) diff --git a/sys/dev/sdhci/sdhci.h b/sys/dev/sdhci/sdhci.h index 4626816a5..28fd3c020 100644 --- a/sys/dev/sdhci/sdhci.h +++ b/sys/dev/sdhci/sdhci.h @@ -28,246 +28,250 @@ #ifndef __SDHCI_H__ #define __SDHCI_H__ -#define DMA_BLOCK_SIZE 4096 -#define DMA_BOUNDARY 0 /* DMA reload every 4K */ +#define DMA_BLOCK_SIZE 4096 +#define DMA_BOUNDARY 0 /* DMA reload every 4K */ /* Controller doesn't honor resets unless we touch the clock register */ -#define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0) +#define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1 << 0) /* Controller really supports DMA */ -#define SDHCI_QUIRK_FORCE_DMA (1<<1) +#define SDHCI_QUIRK_FORCE_DMA (1 << 1) /* Controller has unusable DMA engine */ -#define SDHCI_QUIRK_BROKEN_DMA (1<<2) +#define SDHCI_QUIRK_BROKEN_DMA (1 << 2) /* Controller doesn't like to be reset when there is no card inserted. */ -#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<3) +#define SDHCI_QUIRK_NO_CARD_NO_RESET (1 << 3) /* Controller has flaky internal state so reset it on each ios change */ -#define SDHCI_QUIRK_RESET_ON_IOS (1<<4) +#define SDHCI_QUIRK_RESET_ON_IOS (1 << 4) /* Controller can only DMA chunk sizes that are a multiple of 32 bits */ -#define SDHCI_QUIRK_32BIT_DMA_SIZE (1<<5) +#define SDHCI_QUIRK_32BIT_DMA_SIZE (1 << 5) /* Controller needs to be reset after each request to stay stable */ -#define SDHCI_QUIRK_RESET_AFTER_REQUEST (1<<6) +#define SDHCI_QUIRK_RESET_AFTER_REQUEST (1 << 6) /* Controller has an off-by-one issue with timeout value */ -#define SDHCI_QUIRK_INCR_TIMEOUT_CONTROL (1<<7) +#define SDHCI_QUIRK_INCR_TIMEOUT_CONTROL (1 << 7) /* Controller has broken read timings */ -#define SDHCI_QUIRK_BROKEN_TIMINGS (1<<8) +#define SDHCI_QUIRK_BROKEN_TIMINGS (1 << 8) /* Controller needs lowered frequency */ -#define SDHCI_QUIRK_LOWER_FREQUENCY (1<<9) +#define SDHCI_QUIRK_LOWER_FREQUENCY (1 << 9) /* Data timeout is invalid, should use SD clock */ -#define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK (1<<10) +#define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK (1 << 10) /* Timeout value is invalid, should be overriden */ -#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1<<11) +#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1 << 11) /* SDHCI_CAPABILITIES is invalid */ -#define SDHCI_QUIRK_MISSING_CAPS (1<<12) +#define SDHCI_QUIRK_MISSING_CAPS (1 << 12) /* Hardware shifts the 136-bit response, don't do it in software. */ -#define SDHCI_QUIRK_DONT_SHIFT_RESPONSE (1<<13) +#define SDHCI_QUIRK_DONT_SHIFT_RESPONSE (1 << 13) /* Wait to see reset bit asserted before waiting for de-asserted */ -#define SDHCI_QUIRK_WAITFOR_RESET_ASSERTED (1<<14) +#define SDHCI_QUIRK_WAITFOR_RESET_ASSERTED (1 << 14) /* Leave controller in standard mode when putting card in HS mode. */ -#define SDHCI_QUIRK_DONT_SET_HISPD_BIT (1<<15) +#define SDHCI_QUIRK_DONT_SET_HISPD_BIT (1 << 15) /* Alternate clock source is required when supplying a 400 KHz clock. */ -#define SDHCI_QUIRK_BCM577XX_400KHZ_CLKSRC (1<<16) +#define SDHCI_QUIRK_BCM577XX_400KHZ_CLKSRC (1 << 16) /* Card insert/remove interrupts don't work, polling required. */ -#define SDHCI_QUIRK_POLL_CARD_PRESENT (1<<17) +#define SDHCI_QUIRK_POLL_CARD_PRESENT (1 << 17) /* All controller slots are non-removable. */ -#define SDHCI_QUIRK_ALL_SLOTS_NON_REMOVABLE (1<<18) +#define SDHCI_QUIRK_ALL_SLOTS_NON_REMOVABLE (1 << 18) /* Issue custom Intel controller reset sequence after power-up. */ -#define SDHCI_QUIRK_INTEL_POWER_UP_RESET (1<<19) +#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) +#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 */ -#define SDHCI_DMA_ADDRESS 0x00 - -#define SDHCI_BLOCK_SIZE 0x04 -#define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF)) - -#define SDHCI_BLOCK_COUNT 0x06 - -#define SDHCI_ARGUMENT 0x08 - -#define SDHCI_TRANSFER_MODE 0x0C -#define SDHCI_TRNS_DMA 0x01 -#define SDHCI_TRNS_BLK_CNT_EN 0x02 -#define SDHCI_TRNS_ACMD12 0x04 -#define SDHCI_TRNS_READ 0x10 -#define SDHCI_TRNS_MULTI 0x20 - -#define SDHCI_COMMAND_FLAGS 0x0E -#define SDHCI_CMD_RESP_NONE 0x00 -#define SDHCI_CMD_RESP_LONG 0x01 -#define SDHCI_CMD_RESP_SHORT 0x02 -#define SDHCI_CMD_RESP_SHORT_BUSY 0x03 -#define SDHCI_CMD_RESP_MASK 0x03 -#define SDHCI_CMD_CRC 0x08 -#define SDHCI_CMD_INDEX 0x10 -#define SDHCI_CMD_DATA 0x20 -#define SDHCI_CMD_TYPE_NORMAL 0x00 -#define SDHCI_CMD_TYPE_SUSPEND 0x40 -#define SDHCI_CMD_TYPE_RESUME 0x80 -#define SDHCI_CMD_TYPE_ABORT 0xc0 -#define SDHCI_CMD_TYPE_MASK 0xc0 - -#define SDHCI_COMMAND 0x0F - -#define SDHCI_RESPONSE 0x10 - -#define SDHCI_BUFFER 0x20 - -#define SDHCI_PRESENT_STATE 0x24 -#define SDHCI_CMD_INHIBIT 0x00000001 -#define SDHCI_DAT_INHIBIT 0x00000002 -#define SDHCI_DAT_ACTIVE 0x00000004 -#define SDHCI_RETUNE_REQUEST 0x00000008 -#define SDHCI_DOING_WRITE 0x00000100 -#define SDHCI_DOING_READ 0x00000200 -#define SDHCI_SPACE_AVAILABLE 0x00000400 -#define SDHCI_DATA_AVAILABLE 0x00000800 -#define SDHCI_CARD_PRESENT 0x00010000 -#define SDHCI_CARD_STABLE 0x00020000 -#define SDHCI_CARD_PIN 0x00040000 -#define SDHCI_WRITE_PROTECT 0x00080000 -#define SDHCI_STATE_DAT_MASK 0x00f00000 -#define SDHCI_STATE_CMD 0x01000000 - -#define SDHCI_HOST_CONTROL 0x28 -#define SDHCI_CTRL_LED 0x01 -#define SDHCI_CTRL_4BITBUS 0x02 -#define SDHCI_CTRL_HISPD 0x04 -#define SDHCI_CTRL_SDMA 0x08 -#define SDHCI_CTRL_ADMA2 0x10 -#define SDHCI_CTRL_ADMA264 0x18 -#define SDHCI_CTRL_DMA_MASK 0x18 -#define SDHCI_CTRL_8BITBUS 0x20 -#define SDHCI_CTRL_CARD_DET 0x40 -#define SDHCI_CTRL_FORCE_CARD 0x80 - -#define SDHCI_POWER_CONTROL 0x29 -#define SDHCI_POWER_ON 0x01 -#define SDHCI_POWER_180 0x0A -#define SDHCI_POWER_300 0x0C -#define SDHCI_POWER_330 0x0E - -#define SDHCI_BLOCK_GAP_CONTROL 0x2A - -#define SDHCI_WAKE_UP_CONTROL 0x2B - -#define SDHCI_CLOCK_CONTROL 0x2C -#define SDHCI_DIVIDER_MASK 0xff -#define SDHCI_DIVIDER_MASK_LEN 8 -#define SDHCI_DIVIDER_SHIFT 8 -#define SDHCI_DIVIDER_HI_MASK 3 -#define SDHCI_DIVIDER_HI_SHIFT 6 -#define SDHCI_CLOCK_CARD_EN 0x0004 -#define SDHCI_CLOCK_INT_STABLE 0x0002 -#define SDHCI_CLOCK_INT_EN 0x0001 -#define SDHCI_DIVIDERS_MASK \ +#define SDHCI_DMA_ADDRESS 0x00 + +#define SDHCI_BLOCK_SIZE 0x04 +#define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF)) + +#define SDHCI_BLOCK_COUNT 0x06 + +#define SDHCI_ARGUMENT 0x08 + +#define SDHCI_TRANSFER_MODE 0x0C +#define SDHCI_TRNS_DMA 0x01 +#define SDHCI_TRNS_BLK_CNT_EN 0x02 +#define SDHCI_TRNS_ACMD12 0x04 +#define SDHCI_TRNS_READ 0x10 +#define SDHCI_TRNS_MULTI 0x20 + +#define SDHCI_COMMAND_FLAGS 0x0E +#define SDHCI_CMD_RESP_NONE 0x00 +#define SDHCI_CMD_RESP_LONG 0x01 +#define SDHCI_CMD_RESP_SHORT 0x02 +#define SDHCI_CMD_RESP_SHORT_BUSY 0x03 +#define SDHCI_CMD_RESP_MASK 0x03 +#define SDHCI_CMD_CRC 0x08 +#define SDHCI_CMD_INDEX 0x10 +#define SDHCI_CMD_DATA 0x20 +#define SDHCI_CMD_TYPE_NORMAL 0x00 +#define SDHCI_CMD_TYPE_SUSPEND 0x40 +#define SDHCI_CMD_TYPE_RESUME 0x80 +#define SDHCI_CMD_TYPE_ABORT 0xc0 +#define SDHCI_CMD_TYPE_MASK 0xc0 + +#define SDHCI_COMMAND 0x0F + +#define SDHCI_RESPONSE 0x10 + +#define SDHCI_BUFFER 0x20 + +#define SDHCI_PRESENT_STATE 0x24 +#define SDHCI_CMD_INHIBIT 0x00000001 +#define SDHCI_DAT_INHIBIT 0x00000002 +#define SDHCI_DAT_ACTIVE 0x00000004 +#define SDHCI_RETUNE_REQUEST 0x00000008 +#define SDHCI_DOING_WRITE 0x00000100 +#define SDHCI_DOING_READ 0x00000200 +#define SDHCI_SPACE_AVAILABLE 0x00000400 +#define SDHCI_DATA_AVAILABLE 0x00000800 +#define SDHCI_CARD_PRESENT 0x00010000 +#define SDHCI_CARD_STABLE 0x00020000 +#define SDHCI_CARD_PIN 0x00040000 +#define SDHCI_WRITE_PROTECT 0x00080000 +#define SDHCI_STATE_DAT_MASK 0x00f00000 +#define SDHCI_STATE_CMD 0x01000000 + +#define SDHCI_HOST_CONTROL 0x28 +#define SDHCI_CTRL_LED 0x01 +#define SDHCI_CTRL_4BITBUS 0x02 +#define SDHCI_CTRL_HISPD 0x04 +#define SDHCI_CTRL_SDMA 0x08 +#define SDHCI_CTRL_ADMA2 0x10 +#define SDHCI_CTRL_ADMA264 0x18 +#define SDHCI_CTRL_DMA_MASK 0x18 +#define SDHCI_CTRL_8BITBUS 0x20 +#define SDHCI_CTRL_CARD_DET 0x40 +#define SDHCI_CTRL_FORCE_CARD 0x80 + +#define SDHCI_POWER_CONTROL 0x29 +#define SDHCI_POWER_ON 0x01 +#define SDHCI_POWER_180 0x0A +#define SDHCI_POWER_300 0x0C +#define SDHCI_POWER_330 0x0E + +#define SDHCI_BLOCK_GAP_CONTROL 0x2A + +#define SDHCI_WAKE_UP_CONTROL 0x2B + +#define SDHCI_CLOCK_CONTROL 0x2C +#define SDHCI_DIVIDER_MASK 0xff +#define SDHCI_DIVIDER_MASK_LEN 8 +#define SDHCI_DIVIDER_SHIFT 8 +#define SDHCI_DIVIDER_HI_MASK 3 +#define SDHCI_DIVIDER_HI_SHIFT 6 +#define SDHCI_CLOCK_CARD_EN 0x0004 +#define SDHCI_CLOCK_INT_STABLE 0x0002 +#define SDHCI_CLOCK_INT_EN 0x0001 +#define SDHCI_DIVIDERS_MASK \ ((SDHCI_DIVIDER_MASK << SDHCI_DIVIDER_SHIFT) | \ (SDHCI_DIVIDER_HI_MASK << SDHCI_DIVIDER_HI_SHIFT)) -#define SDHCI_TIMEOUT_CONTROL 0x2E - -#define SDHCI_SOFTWARE_RESET 0x2F -#define SDHCI_RESET_ALL 0x01 -#define SDHCI_RESET_CMD 0x02 -#define SDHCI_RESET_DATA 0x04 - -#define SDHCI_INT_STATUS 0x30 -#define SDHCI_INT_ENABLE 0x34 -#define SDHCI_SIGNAL_ENABLE 0x38 -#define SDHCI_INT_RESPONSE 0x00000001 -#define SDHCI_INT_DATA_END 0x00000002 -#define SDHCI_INT_BLOCK_GAP 0x00000004 -#define SDHCI_INT_DMA_END 0x00000008 -#define SDHCI_INT_SPACE_AVAIL 0x00000010 -#define SDHCI_INT_DATA_AVAIL 0x00000020 -#define SDHCI_INT_CARD_INSERT 0x00000040 -#define SDHCI_INT_CARD_REMOVE 0x00000080 -#define SDHCI_INT_CARD_INT 0x00000100 -#define SDHCI_INT_INT_A 0x00000200 -#define SDHCI_INT_INT_B 0x00000400 -#define SDHCI_INT_INT_C 0x00000800 -#define SDHCI_INT_RETUNE 0x00001000 -#define SDHCI_INT_ERROR 0x00008000 -#define SDHCI_INT_TIMEOUT 0x00010000 -#define SDHCI_INT_CRC 0x00020000 -#define SDHCI_INT_END_BIT 0x00040000 -#define SDHCI_INT_INDEX 0x00080000 -#define SDHCI_INT_DATA_TIMEOUT 0x00100000 -#define SDHCI_INT_DATA_CRC 0x00200000 -#define SDHCI_INT_DATA_END_BIT 0x00400000 -#define SDHCI_INT_BUS_POWER 0x00800000 -#define SDHCI_INT_ACMD12ERR 0x01000000 -#define SDHCI_INT_ADMAERR 0x02000000 -#define SDHCI_INT_TUNEERR 0x04000000 - -#define SDHCI_INT_NORMAL_MASK 0x00007FFF -#define SDHCI_INT_ERROR_MASK 0xFFFF8000 - -#define SDHCI_INT_CMD_ERROR_MASK (SDHCI_INT_TIMEOUT | \ +#define SDHCI_TIMEOUT_CONTROL 0x2E + +#define SDHCI_SOFTWARE_RESET 0x2F +#define SDHCI_RESET_ALL 0x01 +#define SDHCI_RESET_CMD 0x02 +#define SDHCI_RESET_DATA 0x04 + +#define SDHCI_INT_STATUS 0x30 +#define SDHCI_INT_ENABLE 0x34 +#define SDHCI_SIGNAL_ENABLE 0x38 +#define SDHCI_INT_RESPONSE 0x00000001 +#define SDHCI_INT_DATA_END 0x00000002 +#define SDHCI_INT_BLOCK_GAP 0x00000004 +#define SDHCI_INT_DMA_END 0x00000008 +#define SDHCI_INT_SPACE_AVAIL 0x00000010 +#define SDHCI_INT_DATA_AVAIL 0x00000020 +#define SDHCI_INT_CARD_INSERT 0x00000040 +#define SDHCI_INT_CARD_REMOVE 0x00000080 +#define SDHCI_INT_CARD_INT 0x00000100 +#define SDHCI_INT_INT_A 0x00000200 +#define SDHCI_INT_INT_B 0x00000400 +#define SDHCI_INT_INT_C 0x00000800 +#define SDHCI_INT_RETUNE 0x00001000 +#define SDHCI_INT_ERROR 0x00008000 +#define SDHCI_INT_TIMEOUT 0x00010000 +#define SDHCI_INT_CRC 0x00020000 +#define SDHCI_INT_END_BIT 0x00040000 +#define SDHCI_INT_INDEX 0x00080000 +#define SDHCI_INT_DATA_TIMEOUT 0x00100000 +#define SDHCI_INT_DATA_CRC 0x00200000 +#define SDHCI_INT_DATA_END_BIT 0x00400000 +#define SDHCI_INT_BUS_POWER 0x00800000 +#define SDHCI_INT_ACMD12ERR 0x01000000 +#define SDHCI_INT_ADMAERR 0x02000000 +#define SDHCI_INT_TUNEERR 0x04000000 + +#define SDHCI_INT_NORMAL_MASK 0x00007FFF +#define SDHCI_INT_ERROR_MASK 0xFFFF8000 + +#define SDHCI_INT_CMD_ERROR_MASK (SDHCI_INT_TIMEOUT | \ SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX) -#define SDHCI_INT_CMD_MASK (SDHCI_INT_RESPONSE | SDHCI_INT_CMD_ERROR_MASK) +#define SDHCI_INT_CMD_MASK (SDHCI_INT_RESPONSE | SDHCI_INT_CMD_ERROR_MASK) -#define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \ +#define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \ SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \ SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \ SDHCI_INT_DATA_END_BIT) -#define SDHCI_ACMD12_ERR 0x3C -#define SDHCI_HOST_CONTROL2 0x3E - -#define SDHCI_CAPABILITIES 0x40 -#define SDHCI_TIMEOUT_CLK_MASK 0x0000003F -#define SDHCI_TIMEOUT_CLK_SHIFT 0 -#define SDHCI_TIMEOUT_CLK_UNIT 0x00000080 -#define SDHCI_CLOCK_BASE_MASK 0x00003F00 -#define SDHCI_CLOCK_V3_BASE_MASK 0x0000FF00 -#define SDHCI_CLOCK_BASE_SHIFT 8 -#define SDHCI_MAX_BLOCK_MASK 0x00030000 -#define SDHCI_MAX_BLOCK_SHIFT 16 -#define SDHCI_CAN_DO_8BITBUS 0x00040000 -#define SDHCI_CAN_DO_ADMA2 0x00080000 -#define SDHCI_CAN_DO_HISPD 0x00200000 -#define SDHCI_CAN_DO_DMA 0x00400000 -#define SDHCI_CAN_DO_SUSPEND 0x00800000 -#define SDHCI_CAN_VDD_330 0x01000000 -#define SDHCI_CAN_VDD_300 0x02000000 -#define SDHCI_CAN_VDD_180 0x04000000 -#define SDHCI_CAN_DO_64BIT 0x10000000 -#define SDHCI_CAN_ASYNC_INTR 0x20000000 - -#define SDHCI_CAPABILITIES2 0x44 -#define SDHCI_CAN_SDR50 0x00000001 -#define SDHCI_CAN_SDR104 0x00000002 -#define SDHCI_CAN_DDR50 0x00000004 -#define SDHCI_CAN_DRIVE_TYPE_A 0x00000010 -#define SDHCI_CAN_DRIVE_TYPE_B 0x00000020 -#define SDHCI_CAN_DRIVE_TYPE_C 0x00000040 -#define SDHCI_RETUNE_CNT_MASK 0x00000F00 -#define SDHCI_RETUNE_CNT_SHIFT 8 -#define SDHCI_TUNE_SDR50 0x00002000 -#define SDHCI_RETUNE_MODES_MASK 0x0000C000 -#define SDHCI_RETUNE_MODES_SHIFT 14 -#define SDHCI_CLOCK_MULT_MASK 0x00FF0000 -#define SDHCI_CLOCK_MULT_SHIFT 16 - -#define SDHCI_MAX_CURRENT 0x48 -#define SDHCI_FORCE_AUTO_EVENT 0x50 -#define SDHCI_FORCE_INTR_EVENT 0x52 -#define SDHCI_ADMA_ERR 0x54 -#define SDHCI_ADMA_ADDRESS_LOW 0x58 -#define SDHCI_ADMA_ADDRESS_HI 0x5C -#define SDHCI_PRESET_VALUE 0x60 -#define SDHCI_SHARED_BUS_CTRL 0xE0 - -#define SDHCI_SLOT_INT_STATUS 0xFC - -#define SDHCI_HOST_VERSION 0xFE -#define SDHCI_VENDOR_VER_MASK 0xFF00 -#define SDHCI_VENDOR_VER_SHIFT 8 -#define SDHCI_SPEC_VER_MASK 0x00FF -#define SDHCI_SPEC_VER_SHIFT 0 +#define SDHCI_ACMD12_ERR 0x3C +#define SDHCI_HOST_CONTROL2 0x3E + +#define SDHCI_CAPABILITIES 0x40 +#define SDHCI_TIMEOUT_CLK_MASK 0x0000003F +#define SDHCI_TIMEOUT_CLK_SHIFT 0 +#define SDHCI_TIMEOUT_CLK_UNIT 0x00000080 +#define SDHCI_CLOCK_BASE_MASK 0x00003F00 +#define SDHCI_CLOCK_V3_BASE_MASK 0x0000FF00 +#define SDHCI_CLOCK_BASE_SHIFT 8 +#define SDHCI_MAX_BLOCK_MASK 0x00030000 +#define SDHCI_MAX_BLOCK_SHIFT 16 +#define SDHCI_CAN_DO_8BITBUS 0x00040000 +#define SDHCI_CAN_DO_ADMA2 0x00080000 +#define SDHCI_CAN_DO_HISPD 0x00200000 +#define SDHCI_CAN_DO_DMA 0x00400000 +#define SDHCI_CAN_DO_SUSPEND 0x00800000 +#define SDHCI_CAN_VDD_330 0x01000000 +#define SDHCI_CAN_VDD_300 0x02000000 +#define SDHCI_CAN_VDD_180 0x04000000 +#define SDHCI_CAN_DO_64BIT 0x10000000 +#define SDHCI_CAN_ASYNC_INTR 0x20000000 + +#define SDHCI_CAPABILITIES2 0x44 +#define SDHCI_CAN_SDR50 0x00000001 +#define SDHCI_CAN_SDR104 0x00000002 +#define SDHCI_CAN_DDR50 0x00000004 +#define SDHCI_CAN_DRIVE_TYPE_A 0x00000010 +#define SDHCI_CAN_DRIVE_TYPE_B 0x00000020 +#define SDHCI_CAN_DRIVE_TYPE_C 0x00000040 +#define SDHCI_RETUNE_CNT_MASK 0x00000F00 +#define SDHCI_RETUNE_CNT_SHIFT 8 +#define SDHCI_TUNE_SDR50 0x00002000 +#define SDHCI_RETUNE_MODES_MASK 0x0000C000 +#define SDHCI_RETUNE_MODES_SHIFT 14 +#define SDHCI_CLOCK_MULT_MASK 0x00FF0000 +#define SDHCI_CLOCK_MULT_SHIFT 16 + +#define SDHCI_MAX_CURRENT 0x48 +#define SDHCI_FORCE_AUTO_EVENT 0x50 +#define SDHCI_FORCE_INTR_EVENT 0x52 +#define SDHCI_ADMA_ERR 0x54 +#define SDHCI_ADMA_ADDRESS_LOW 0x58 +#define SDHCI_ADMA_ADDRESS_HI 0x5C +#define SDHCI_PRESET_VALUE 0x60 +#define SDHCI_SHARED_BUS_CTRL 0xE0 + +#define SDHCI_SLOT_INT_STATUS 0xFC + +#define SDHCI_HOST_VERSION 0xFE +#define SDHCI_VENDOR_VER_MASK 0xFF00 +#define SDHCI_VENDOR_VER_SHIFT 8 +#define SDHCI_SPEC_VER_MASK 0x00FF +#define SDHCI_SPEC_VER_SHIFT 0 #define SDHCI_SPEC_100 0 #define SDHCI_SPEC_200 1 #define SDHCI_SPEC_300 2 @@ -288,19 +292,19 @@ struct sdhci_slot { int timeout; /* Transfer timeout */ uint32_t max_clk; /* Max possible freq */ uint32_t timeout_clk; /* Timeout freq */ - bus_dma_tag_t dmatag; - bus_dmamap_t dmamap; + bus_dma_tag_t dmatag; + bus_dmamap_t dmamap; u_char *dmamem; bus_addr_t paddr; /* DMA buffer address */ struct task card_task; /* Card presence check task */ - struct timeout_task + struct timeout_task card_delayed_task;/* Card insert delayed task */ struct callout card_poll_callout;/* Card present polling callout */ struct callout timeout_callout;/* Card command/data response timeout */ struct mmc_host host; /* Host parameters */ struct mmc_request *req; /* Current request */ struct mmc_command *curcmd; /* Current command of current request */ - + uint32_t intmask; /* Current interrupt mask */ uint32_t clock; /* Current clock freq. */ size_t offset; /* Data buffer offset */ @@ -310,15 +314,17 @@ struct sdhci_slot { u_char cmd_done; /* CMD command part done flag */ u_char data_done; /* DAT command part done flag */ u_char flags; /* Request execution flags */ -#define CMD_STARTED 1 -#define STOP_STARTED 2 -#define SDHCI_USE_DMA 4 /* Use DMA for this req. */ -#define PLATFORM_DATA_STARTED 8 /* Data transfer is handled by platform */ +#define CMD_STARTED 1 +#define STOP_STARTED 2 +#define SDHCI_USE_DMA 4 /* Use DMA for this req. */ +#define PLATFORM_DATA_STARTED 8 /* Data xfer is handled by platform */ struct mtx mtx; /* Slot mutex */ }; -int sdhci_generic_read_ivar(device_t bus, device_t child, int which, uintptr_t *result); -int sdhci_generic_write_ivar(device_t bus, device_t child, int which, uintptr_t value); +int sdhci_generic_read_ivar(device_t bus, device_t child, int which, + uintptr_t *result); +int sdhci_generic_write_ivar(device_t bus, device_t child, int which, + uintptr_t value); int sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num); void sdhci_start_slot(struct sdhci_slot *slot); /* performs generic clean-up for platform transfers */ @@ -327,7 +333,8 @@ int sdhci_cleanup_slot(struct sdhci_slot *slot); int sdhci_generic_suspend(struct sdhci_slot *slot); int sdhci_generic_resume(struct sdhci_slot *slot); int sdhci_generic_update_ios(device_t brdev, device_t reqdev); -int sdhci_generic_request(device_t brdev, device_t reqdev, struct mmc_request *req); +int sdhci_generic_request(device_t brdev, device_t reqdev, + struct mmc_request *req); int sdhci_generic_get_ro(device_t brdev, device_t reqdev); int sdhci_generic_acquire_host(device_t brdev, device_t reqdev); int sdhci_generic_release_host(device_t brdev, device_t reqdev); diff --git a/sys/dev/sdhci/sdhci_acpi.c b/sys/dev/sdhci/sdhci_acpi.c new file mode 100644 index 000000000..3924820ab --- /dev/null +++ b/sys/dev/sdhci/sdhci_acpi.c @@ -0,0 +1,375 @@ +/*- + * Copyright (c) 2017 Oleksandr Tymoshenko + * 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#include "mmcbr_if.h" +#include "sdhci_if.h" + +static const struct sdhci_acpi_device { + const char* hid; + int uid; + const char *desc; + u_int quirks; +} sdhci_acpi_devices[] = { + { "80860F14", 1, "Intel Bay Trail eMMC 4.5 Controller", + SDHCI_QUIRK_ALL_SLOTS_NON_REMOVABLE | + SDHCI_QUIRK_INTEL_POWER_UP_RESET | + SDHCI_QUIRK_WAIT_WHILE_BUSY }, + { "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} +}; + +static char *sdhci_ids[] = { + "80860F14", + "80860F16", + NULL +}; + +struct sdhci_acpi_softc { + u_int quirks; /* Chip specific quirks */ + struct resource *irq_res; /* IRQ resource */ + void *intrhand; /* Interrupt handle */ + + struct sdhci_slot slot; + struct resource *mem_res; /* Memory resource */ +}; + +static void sdhci_acpi_intr(void *arg); +static int sdhci_acpi_detach(device_t dev); + +static uint8_t +sdhci_acpi_read_1(device_t dev, struct sdhci_slot *slot __unused, + bus_size_t off) +{ + struct sdhci_acpi_softc *sc = device_get_softc(dev); + + bus_barrier(sc->mem_res, 0, 0xFF, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); + return bus_read_1(sc->mem_res, off); +} + +static void +sdhci_acpi_write_1(device_t dev, struct sdhci_slot *slot __unused, + bus_size_t off, uint8_t val) +{ + struct sdhci_acpi_softc *sc = device_get_softc(dev); + + bus_barrier(sc->mem_res, 0, 0xFF, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); + bus_write_1(sc->mem_res, off, val); +} + +static uint16_t +sdhci_acpi_read_2(device_t dev, struct sdhci_slot *slot __unused, + bus_size_t off) +{ + struct sdhci_acpi_softc *sc = device_get_softc(dev); + + bus_barrier(sc->mem_res, 0, 0xFF, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); + return bus_read_2(sc->mem_res, off); +} + +static void +sdhci_acpi_write_2(device_t dev, struct sdhci_slot *slot __unused, + bus_size_t off, uint16_t val) +{ + struct sdhci_acpi_softc *sc = device_get_softc(dev); + + bus_barrier(sc->mem_res, 0, 0xFF, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); + bus_write_2(sc->mem_res, off, val); +} + +static uint32_t +sdhci_acpi_read_4(device_t dev, struct sdhci_slot *slot __unused, + bus_size_t off) +{ + struct sdhci_acpi_softc *sc = device_get_softc(dev); + + bus_barrier(sc->mem_res, 0, 0xFF, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); + return bus_read_4(sc->mem_res, off); +} + +static void +sdhci_acpi_write_4(device_t dev, struct sdhci_slot *slot __unused, + bus_size_t off, uint32_t val) +{ + struct sdhci_acpi_softc *sc = device_get_softc(dev); + + bus_barrier(sc->mem_res, 0, 0xFF, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); + bus_write_4(sc->mem_res, off, val); +} + +static void +sdhci_acpi_read_multi_4(device_t dev, struct sdhci_slot *slot __unused, + bus_size_t off, uint32_t *data, bus_size_t count) +{ + struct sdhci_acpi_softc *sc = device_get_softc(dev); + + bus_read_multi_stream_4(sc->mem_res, off, data, count); +} + +static void +sdhci_acpi_write_multi_4(device_t dev, struct sdhci_slot *slot __unused, + bus_size_t off, uint32_t *data, bus_size_t count) +{ + struct sdhci_acpi_softc *sc = device_get_softc(dev); + + bus_write_multi_stream_4(sc->mem_res, off, data, count); +} + +static const struct sdhci_acpi_device * +sdhci_acpi_find_device(device_t dev) +{ + const char *hid; + int i, uid; + ACPI_HANDLE handle; + ACPI_STATUS status; + + hid = ACPI_ID_PROBE(device_get_parent(dev), dev, sdhci_ids); + if (hid == NULL) + return (NULL); + + handle = acpi_get_handle(dev); + status = acpi_GetInteger(handle, "_UID", &uid); + if (ACPI_FAILURE(status)) + uid = 0; + + for (i = 0; sdhci_acpi_devices[i].hid != NULL; i++) { + if (strcmp(sdhci_acpi_devices[i].hid, hid) != 0) + continue; + if ((sdhci_acpi_devices[i].uid != 0) && + (sdhci_acpi_devices[i].uid != uid)) + continue; + return (&sdhci_acpi_devices[i]); + } + + return (NULL); +} + +static int +sdhci_acpi_probe(device_t dev) +{ + const struct sdhci_acpi_device *acpi_dev; + + acpi_dev = sdhci_acpi_find_device(dev); + if (acpi_dev == NULL) + return (ENXIO); + + device_set_desc(dev, acpi_dev->desc); + + return (BUS_PROBE_DEFAULT); +} + +static int +sdhci_acpi_attach(device_t dev) +{ + struct sdhci_acpi_softc *sc = device_get_softc(dev); + int rid, err; + const struct sdhci_acpi_device *acpi_dev; + + acpi_dev = sdhci_acpi_find_device(dev); + if (acpi_dev == NULL) + return (ENXIO); + + sc->quirks = acpi_dev->quirks; + + /* Allocate IRQ. */ + rid = 0; + sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_ACTIVE); + if (sc->irq_res == NULL) { + device_printf(dev, "can't allocate IRQ\n"); + return (ENOMEM); + } + + rid = 0; + sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &rid, RF_ACTIVE); + if (sc->mem_res == NULL) { + device_printf(dev, "can't allocate memory resource for slot\n"); + sdhci_acpi_detach(dev); + return (ENOMEM); + } + + sc->slot.quirks = sc->quirks; + + err = sdhci_init_slot(dev, &sc->slot, 0); + if (err) { + device_printf(dev, "failed to init slot\n"); + sdhci_acpi_detach(dev); + return (err); + } + + /* Activate the interrupt */ + err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, + NULL, sdhci_acpi_intr, sc, &sc->intrhand); + if (err) { + device_printf(dev, "can't setup IRQ\n"); + sdhci_acpi_detach(dev); + return (err); + } + + /* Process cards detection. */ + sdhci_start_slot(&sc->slot); + + return (0); +} + +static int +sdhci_acpi_detach(device_t dev) +{ + struct sdhci_acpi_softc *sc = device_get_softc(dev); + + if (sc->intrhand) + bus_teardown_intr(dev, sc->irq_res, sc->intrhand); + if (sc->irq_res) + bus_release_resource(dev, SYS_RES_IRQ, + rman_get_rid(sc->irq_res), sc->irq_res); + + if (sc->mem_res) { + sdhci_cleanup_slot(&sc->slot); + bus_release_resource(dev, SYS_RES_MEMORY, + rman_get_rid(sc->mem_res), sc->mem_res); + } + + return (0); +} + +static int +sdhci_acpi_shutdown(device_t dev) +{ + + return (0); +} + +static int +sdhci_acpi_suspend(device_t dev) +{ + struct sdhci_acpi_softc *sc = device_get_softc(dev); + int err; + + err = bus_generic_suspend(dev); + if (err) + return (err); + sdhci_generic_suspend(&sc->slot); + return (0); +} + +static int +sdhci_acpi_resume(device_t dev) +{ + struct sdhci_acpi_softc *sc = device_get_softc(dev); + int err; + + sdhci_generic_resume(&sc->slot); + err = bus_generic_resume(dev); + if (err) + return (err); + return (0); +} + +static void +sdhci_acpi_intr(void *arg) +{ + struct sdhci_acpi_softc *sc = (struct sdhci_acpi_softc *)arg; + + sdhci_generic_intr(&sc->slot); +} + +static device_method_t sdhci_methods[] = { + /* device_if */ + DEVMETHOD(device_probe, sdhci_acpi_probe), + DEVMETHOD(device_attach, sdhci_acpi_attach), + DEVMETHOD(device_detach, sdhci_acpi_detach), + DEVMETHOD(device_shutdown, sdhci_acpi_shutdown), + DEVMETHOD(device_suspend, sdhci_acpi_suspend), + DEVMETHOD(device_resume, sdhci_acpi_resume), + + /* Bus interface */ + DEVMETHOD(bus_read_ivar, sdhci_generic_read_ivar), + DEVMETHOD(bus_write_ivar, sdhci_generic_write_ivar), + + /* mmcbr_if */ + DEVMETHOD(mmcbr_update_ios, sdhci_generic_update_ios), + DEVMETHOD(mmcbr_request, sdhci_generic_request), + DEVMETHOD(mmcbr_get_ro, sdhci_generic_get_ro), + DEVMETHOD(mmcbr_acquire_host, sdhci_generic_acquire_host), + DEVMETHOD(mmcbr_release_host, sdhci_generic_release_host), + + /* SDHCI registers accessors */ + DEVMETHOD(sdhci_read_1, sdhci_acpi_read_1), + DEVMETHOD(sdhci_read_2, sdhci_acpi_read_2), + DEVMETHOD(sdhci_read_4, sdhci_acpi_read_4), + DEVMETHOD(sdhci_read_multi_4, sdhci_acpi_read_multi_4), + DEVMETHOD(sdhci_write_1, sdhci_acpi_write_1), + DEVMETHOD(sdhci_write_2, sdhci_acpi_write_2), + DEVMETHOD(sdhci_write_4, sdhci_acpi_write_4), + DEVMETHOD(sdhci_write_multi_4, sdhci_acpi_write_multi_4), + + DEVMETHOD_END +}; + +static driver_t sdhci_acpi_driver = { + "sdhci_acpi", + sdhci_methods, + sizeof(struct sdhci_acpi_softc), +}; +static devclass_t sdhci_acpi_devclass; + +DRIVER_MODULE(sdhci_acpi, acpi, sdhci_acpi_driver, sdhci_acpi_devclass, NULL, + NULL); +MODULE_DEPEND(sdhci_acpi, sdhci, 1, 1, 1); +MMC_DECLARE_BRIDGE(sdhci_acpi); diff --git a/sys/dev/sdhci/sdhci_fdt.c b/sys/dev/sdhci/sdhci_fdt.c index b89bc6119..2e1b30e4b 100644 --- a/sys/dev/sdhci/sdhci_fdt.c +++ b/sys/dev/sdhci/sdhci_fdt.c @@ -34,7 +34,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include #include @@ -46,21 +45,19 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include #include #include #include -#include -#include + #include #include "mmcbr_if.h" #include "sdhci_if.h" -#define MAX_SLOTS 6 +#define MAX_SLOTS 6 struct sdhci_fdt_softc { device_t dev; /* Controller device */ @@ -68,7 +65,7 @@ struct sdhci_fdt_softc { u_int caps; /* If we override SDHCI_CAPABILITIES */ uint32_t max_clk; /* Max possible freq */ struct resource *irq_res; /* IRQ resource */ - void *intrhand; /* Interrupt handle */ + void *intrhand; /* Interrupt handle */ int num_slots; /* Number of slots on this controller*/ struct sdhci_slot slots[MAX_SLOTS]; @@ -79,14 +76,16 @@ static uint8_t sdhci_fdt_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off) { struct sdhci_fdt_softc *sc = device_get_softc(dev); + return (bus_read_1(sc->mem_res[slot->num], off)); } static void sdhci_fdt_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off, - uint8_t val) + uint8_t val) { struct sdhci_fdt_softc *sc = device_get_softc(dev); + bus_write_1(sc->mem_res[slot->num], off, val); } @@ -94,14 +93,16 @@ static uint16_t sdhci_fdt_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t off) { struct sdhci_fdt_softc *sc = device_get_softc(dev); + return (bus_read_2(sc->mem_res[slot->num], off)); } static void sdhci_fdt_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, - uint16_t val) + uint16_t val) { struct sdhci_fdt_softc *sc = device_get_softc(dev); + bus_write_2(sc->mem_res[slot->num], off, val); } @@ -109,14 +110,16 @@ static uint32_t sdhci_fdt_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off) { struct sdhci_fdt_softc *sc = device_get_softc(dev); + return (bus_read_4(sc->mem_res[slot->num], off)); } static void sdhci_fdt_write_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, - uint32_t val) + uint32_t val) { struct sdhci_fdt_softc *sc = device_get_softc(dev); + bus_write_4(sc->mem_res[slot->num], off, val); } @@ -125,6 +128,7 @@ sdhci_fdt_read_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t *data, bus_size_t count) { struct sdhci_fdt_softc *sc = device_get_softc(dev); + bus_read_multi_4(sc->mem_res[slot->num], off, data, count); } @@ -133,6 +137,7 @@ sdhci_fdt_write_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t *data, bus_size_t count) { struct sdhci_fdt_softc *sc = device_get_softc(dev); + bus_write_multi_4(sc->mem_res[slot->num], off, data, count); } @@ -142,10 +147,8 @@ sdhci_fdt_intr(void *arg) struct sdhci_fdt_softc *sc = (struct sdhci_fdt_softc *)arg; int i; - for (i = 0; i < sc->num_slots; i++) { - struct sdhci_slot *slot = &sc->slots[i]; - sdhci_generic_intr(slot); - } + for (i = 0; i < sc->num_slots; i++) + sdhci_generic_intr(&sc->slots[i]); } static int @@ -187,6 +190,7 @@ static int sdhci_fdt_attach(device_t dev) { struct sdhci_fdt_softc *sc = device_get_softc(dev); + struct sdhci_slot *slot; int err, slots, rid, i; sc->dev = dev; @@ -194,7 +198,7 @@ sdhci_fdt_attach(device_t dev) /* Allocate IRQ. */ rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_ACTIVE); + RF_ACTIVE); if (sc->irq_res == NULL) { device_printf(dev, "Can't allocate IRQ\n"); return (ENOMEM); @@ -204,15 +208,15 @@ sdhci_fdt_attach(device_t dev) slots = sc->num_slots; /* number of slots determined in probe(). */ sc->num_slots = 0; for (i = 0; i < slots; i++) { - struct sdhci_slot *slot = &sc->slots[sc->num_slots]; + slot = &sc->slots[sc->num_slots]; /* Allocate memory. */ rid = 0; sc->mem_res[i] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res[i] == NULL) { - device_printf(dev, "Can't allocate memory for " - "slot %d\n", i); + device_printf(dev, + "Can't allocate memory for slot %d\n", i); continue; } @@ -236,10 +240,8 @@ sdhci_fdt_attach(device_t dev) } /* Process cards detection. */ - for (i = 0; i < sc->num_slots; i++) { - struct sdhci_slot *slot = &sc->slots[i]; - sdhci_start_slot(slot); - } + for (i = 0; i < sc->num_slots; i++) + sdhci_start_slot(&sc->slots[i]); return (0); } @@ -253,15 +255,12 @@ sdhci_fdt_detach(device_t dev) bus_generic_detach(dev); bus_teardown_intr(dev, sc->irq_res, sc->intrhand); bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq_res), - sc->irq_res); + sc->irq_res); for (i = 0; i < sc->num_slots; i++) { - struct sdhci_slot *slot = &sc->slots[i]; - - sdhci_cleanup_slot(slot); + sdhci_cleanup_slot(&sc->slots[i]); bus_release_resource(dev, SYS_RES_MEMORY, - rman_get_rid(sc->mem_res[i]), - sc->mem_res[i]); + rman_get_rid(sc->mem_res[i]), sc->mem_res[i]); } return (0); @@ -269,20 +268,20 @@ sdhci_fdt_detach(device_t dev) static device_method_t sdhci_fdt_methods[] = { /* device_if */ - DEVMETHOD(device_probe, sdhci_fdt_probe), - DEVMETHOD(device_attach, sdhci_fdt_attach), - DEVMETHOD(device_detach, sdhci_fdt_detach), + DEVMETHOD(device_probe, sdhci_fdt_probe), + DEVMETHOD(device_attach, sdhci_fdt_attach), + DEVMETHOD(device_detach, sdhci_fdt_detach), /* Bus interface */ DEVMETHOD(bus_read_ivar, sdhci_generic_read_ivar), DEVMETHOD(bus_write_ivar, sdhci_generic_write_ivar), /* mmcbr_if */ - DEVMETHOD(mmcbr_update_ios, sdhci_generic_update_ios), - DEVMETHOD(mmcbr_request, sdhci_generic_request), - DEVMETHOD(mmcbr_get_ro, sdhci_generic_get_ro), - DEVMETHOD(mmcbr_acquire_host, sdhci_generic_acquire_host), - DEVMETHOD(mmcbr_release_host, sdhci_generic_release_host), + DEVMETHOD(mmcbr_update_ios, sdhci_generic_update_ios), + DEVMETHOD(mmcbr_request, sdhci_generic_request), + DEVMETHOD(mmcbr_get_ro, sdhci_generic_get_ro), + DEVMETHOD(mmcbr_acquire_host, sdhci_generic_acquire_host), + DEVMETHOD(mmcbr_release_host, sdhci_generic_release_host), /* SDHCI registers accessors */ DEVMETHOD(sdhci_read_1, sdhci_fdt_read_1), @@ -307,3 +306,4 @@ static devclass_t sdhci_fdt_devclass; DRIVER_MODULE(sdhci_fdt, simplebus, sdhci_fdt_driver, sdhci_fdt_devclass, NULL, NULL); MODULE_DEPEND(sdhci_fdt, sdhci, 1, 1, 1); +MMC_DECLARE_BRIDGE(sdhci_fdt); diff --git a/sys/dev/sdhci/sdhci_if.m b/sys/dev/sdhci/sdhci_if.m index da02d31bf..66e8c861b 100644 --- a/sys/dev/sdhci/sdhci_if.m +++ b/sys/dev/sdhci/sdhci_if.m @@ -59,22 +59,15 @@ # #include -#include -#include -#include +#include #include #include #include #include -#include #include -CODE { - struct sdhci_slot; -} - INTERFACE sdhci; METHOD uint8_t read_1 { diff --git a/sys/dev/sdhci/sdhci_pci.c b/sys/dev/sdhci/sdhci_pci.c index d8e88975d..87d487677 100644 --- a/sys/dev/sdhci/sdhci_pci.c +++ b/sys/dev/sdhci/sdhci_pci.c @@ -29,7 +29,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include #include @@ -44,27 +43,24 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include -#include -#include -#include "sdhci.h" +#include + #include "mmcbr_if.h" #include "sdhci_if.h" /* * PCI registers */ +#define PCI_SDHCI_IFPIO 0x00 +#define PCI_SDHCI_IFDMA 0x01 +#define PCI_SDHCI_IFVENDOR 0x02 -#define PCI_SDHCI_IFPIO 0x00 -#define PCI_SDHCI_IFDMA 0x01 -#define PCI_SDHCI_IFVENDOR 0x02 - -#define PCI_SLOT_INFO 0x40 /* 8 bits */ -#define PCI_SLOT_INFO_SLOTS(x) (((x >> 4) & 7) + 1) -#define PCI_SLOT_INFO_FIRST_BAR(x) ((x) & 7) +#define PCI_SLOT_INFO 0x40 /* 8 bits */ +#define PCI_SLOT_INFO_SLOTS(x) (((x >> 4) & 7) + 1) +#define PCI_SLOT_INFO_FIRST_BAR(x) ((x) & 7) /* * RICOH specific PCI registers @@ -81,45 +77,55 @@ static const struct sdhci_device { const char *desc; u_int quirks; } sdhci_devices[] = { - { 0x08221180, 0xffff, "RICOH R5C822 SD", + { 0x08221180, 0xffff, "RICOH R5C822 SD", SDHCI_QUIRK_FORCE_DMA }, - { 0xe8221180, 0xffff, "RICOH R5CE822 SD", + { 0xe8221180, 0xffff, "RICOH R5CE822 SD", SDHCI_QUIRK_FORCE_DMA | SDHCI_QUIRK_LOWER_FREQUENCY }, - { 0xe8231180, 0xffff, "RICOH R5CE823 SD", + { 0xe8231180, 0xffff, "RICOH R5CE823 SD", SDHCI_QUIRK_LOWER_FREQUENCY }, - { 0x8034104c, 0xffff, "TI XX21/XX11 SD", + { 0x8034104c, 0xffff, "TI XX21/XX11 SD", SDHCI_QUIRK_FORCE_DMA }, - { 0x05501524, 0xffff, "ENE CB712 SD", + { 0x05501524, 0xffff, "ENE CB712 SD", SDHCI_QUIRK_BROKEN_TIMINGS }, - { 0x05511524, 0xffff, "ENE CB712 SD 2", + { 0x05511524, 0xffff, "ENE CB712 SD 2", SDHCI_QUIRK_BROKEN_TIMINGS }, - { 0x07501524, 0xffff, "ENE CB714 SD", + { 0x07501524, 0xffff, "ENE CB714 SD", SDHCI_QUIRK_RESET_ON_IOS | SDHCI_QUIRK_BROKEN_TIMINGS }, - { 0x07511524, 0xffff, "ENE CB714 SD 2", + { 0x07511524, 0xffff, "ENE CB714 SD 2", SDHCI_QUIRK_RESET_ON_IOS | SDHCI_QUIRK_BROKEN_TIMINGS }, - { 0x410111ab, 0xffff, "Marvell CaFe SD", + { 0x410111ab, 0xffff, "Marvell CaFe SD", SDHCI_QUIRK_INCR_TIMEOUT_CONTROL }, - { 0x2381197B, 0xffff, "JMicron JMB38X SD", + { 0x2381197B, 0xffff, "JMicron JMB38X SD", SDHCI_QUIRK_32BIT_DMA_SIZE | SDHCI_QUIRK_RESET_AFTER_REQUEST }, { 0x16bc14e4, 0xffff, "Broadcom BCM577xx SDXC/MMC Card Reader", 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 } }; @@ -127,7 +133,7 @@ static const struct sdhci_device { struct sdhci_pci_softc { u_int quirks; /* Chip specific quirks */ struct resource *irq_res; /* IRQ resource */ - void *intrhand; /* Interrupt handle */ + void *intrhand; /* Interrupt handle */ int num_slots; /* Number of slots on this controller */ struct sdhci_slot slots[6]; @@ -142,7 +148,7 @@ SYSCTL_INT(_hw_sdhci, OID_AUTO, enable_msi, CTLFLAG_RDTUN, &sdhci_enable_msi, 0, "Enable MSI interrupts"); static uint8_t -sdhci_pci_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off) +sdhci_pci_read_1(device_t dev, struct sdhci_slot *slot __unused, bus_size_t off) { struct sdhci_pci_softc *sc = device_get_softc(dev); @@ -152,7 +158,8 @@ sdhci_pci_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off) } static void -sdhci_pci_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint8_t val) +sdhci_pci_write_1(device_t dev, struct sdhci_slot *slot __unused, + bus_size_t off, uint8_t val) { struct sdhci_pci_softc *sc = device_get_softc(dev); @@ -162,7 +169,7 @@ sdhci_pci_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint8_t } static uint16_t -sdhci_pci_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t off) +sdhci_pci_read_2(device_t dev, struct sdhci_slot *slot __unused, bus_size_t off) { struct sdhci_pci_softc *sc = device_get_softc(dev); @@ -172,7 +179,8 @@ sdhci_pci_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t off) } static void -sdhci_pci_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint16_t val) +sdhci_pci_write_2(device_t dev, struct sdhci_slot *slot __unused, + bus_size_t off, uint16_t val) { struct sdhci_pci_softc *sc = device_get_softc(dev); @@ -182,7 +190,7 @@ sdhci_pci_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint16_ } static uint32_t -sdhci_pci_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off) +sdhci_pci_read_4(device_t dev, struct sdhci_slot *slot __unused, bus_size_t off) { struct sdhci_pci_softc *sc = device_get_softc(dev); @@ -192,7 +200,8 @@ sdhci_pci_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off) } static void -sdhci_pci_write_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t val) +sdhci_pci_write_4(device_t dev, struct sdhci_slot *slot __unused, + bus_size_t off, uint32_t val) { struct sdhci_pci_softc *sc = device_get_softc(dev); @@ -202,7 +211,7 @@ sdhci_pci_write_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_ } static void -sdhci_pci_read_multi_4(device_t dev, struct sdhci_slot *slot, +sdhci_pci_read_multi_4(device_t dev, struct sdhci_slot *slot __unused, bus_size_t off, uint32_t *data, bus_size_t count) { struct sdhci_pci_softc *sc = device_get_softc(dev); @@ -211,7 +220,7 @@ sdhci_pci_read_multi_4(device_t dev, struct sdhci_slot *slot, } static void -sdhci_pci_write_multi_4(device_t dev, struct sdhci_slot *slot, +sdhci_pci_write_multi_4(device_t dev, struct sdhci_slot *slot __unused, bus_size_t off, uint32_t *data, bus_size_t count) { struct sdhci_pci_softc *sc = device_get_softc(dev); @@ -298,6 +307,7 @@ static int sdhci_pci_attach(device_t dev) { struct sdhci_pci_softc *sc = device_get_softc(dev); + struct sdhci_slot *slot; uint32_t model; uint16_t subvendor; int bar, err, rid, slots, i; @@ -340,17 +350,18 @@ sdhci_pci_attach(device_t dev) } /* Scan all slots. */ for (i = 0; i < slots; i++) { - struct sdhci_slot *slot = &sc->slots[sc->num_slots]; + slot = &sc->slots[sc->num_slots]; /* Allocate memory. */ rid = PCIR_BAR(bar + i); sc->mem_res[i] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res[i] == NULL) { - device_printf(dev, "Can't allocate memory for slot %d\n", i); + device_printf(dev, + "Can't allocate memory for slot %d\n", i); continue; } - + slot->quirks = sc->quirks; if (sdhci_init_slot(dev, slot, i) != 0) @@ -366,11 +377,8 @@ sdhci_pci_attach(device_t dev) device_printf(dev, "Can't setup IRQ\n"); pci_enable_busmaster(dev); /* Process cards detection. */ - for (i = 0; i < sc->num_slots; i++) { - struct sdhci_slot *slot = &sc->slots[i]; - - sdhci_start_slot(slot); - } + for (i = 0; i < sc->num_slots; i++) + sdhci_start_slot(&sc->slots[i]); return (0); } @@ -387,9 +395,7 @@ sdhci_pci_detach(device_t dev) pci_release_msi(dev); for (i = 0; i < sc->num_slots; i++) { - struct sdhci_slot *slot = &sc->slots[i]; - - sdhci_cleanup_slot(slot); + sdhci_cleanup_slot(&sc->slots[i]); bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->mem_res[i]), sc->mem_res[i]); } @@ -444,29 +450,27 @@ sdhci_pci_intr(void *arg) struct sdhci_pci_softc *sc = (struct sdhci_pci_softc *)arg; int i; - for (i = 0; i < sc->num_slots; i++) { - struct sdhci_slot *slot = &sc->slots[i]; - sdhci_generic_intr(slot); - } + for (i = 0; i < sc->num_slots; i++) + sdhci_generic_intr(&sc->slots[i]); } static device_method_t sdhci_methods[] = { /* device_if */ - DEVMETHOD(device_probe, sdhci_pci_probe), - DEVMETHOD(device_attach, sdhci_pci_attach), - DEVMETHOD(device_detach, sdhci_pci_detach), - DEVMETHOD(device_shutdown, sdhci_pci_shutdown), - DEVMETHOD(device_suspend, sdhci_pci_suspend), - DEVMETHOD(device_resume, sdhci_pci_resume), + DEVMETHOD(device_probe, sdhci_pci_probe), + DEVMETHOD(device_attach, sdhci_pci_attach), + DEVMETHOD(device_detach, sdhci_pci_detach), + DEVMETHOD(device_shutdown, sdhci_pci_shutdown), + DEVMETHOD(device_suspend, sdhci_pci_suspend), + DEVMETHOD(device_resume, sdhci_pci_resume), /* Bus interface */ DEVMETHOD(bus_read_ivar, sdhci_generic_read_ivar), DEVMETHOD(bus_write_ivar, sdhci_generic_write_ivar), /* mmcbr_if */ - DEVMETHOD(mmcbr_update_ios, sdhci_generic_update_ios), - DEVMETHOD(mmcbr_request, sdhci_generic_request), - DEVMETHOD(mmcbr_get_ro, sdhci_generic_get_ro), + DEVMETHOD(mmcbr_update_ios, sdhci_generic_update_ios), + DEVMETHOD(mmcbr_request, sdhci_generic_request), + DEVMETHOD(mmcbr_get_ro, sdhci_generic_get_ro), DEVMETHOD(mmcbr_acquire_host, sdhci_generic_acquire_host), DEVMETHOD(mmcbr_release_host, sdhci_generic_release_host), @@ -493,3 +497,4 @@ static devclass_t sdhci_pci_devclass; DRIVER_MODULE(sdhci_pci, pci, sdhci_pci_driver, sdhci_pci_devclass, NULL, NULL); MODULE_DEPEND(sdhci_pci, sdhci, 1, 1, 1); +MMC_DECLARE_BRIDGE(sdhci_pci); diff --git a/sys/modules/Makefile b/sys/modules/Makefile index 8b926a817..e183bf065 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -311,6 +311,7 @@ SUBDIR= \ scd \ ${_scsi_low} \ sdhci \ + ${_sdhci_acpi} \ sdhci_pci \ sem \ send \ @@ -657,6 +658,7 @@ _wpifw= wpifw _padlock= padlock .endif _s3= s3 +_sdhci_acpi= sdhci_acpi _twa= twa _vesa= vesa _virtio= virtio diff --git a/sys/modules/mmc/Makefile b/sys/modules/mmc/Makefile index b97e2a3e5..507b45e62 100644 --- a/sys/modules/mmc/Makefile +++ b/sys/modules/mmc/Makefile @@ -3,6 +3,6 @@ .PATH: ${.CURDIR}/../../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 diff --git a/sys/modules/sdhci_acpi/Makefile b/sys/modules/sdhci_acpi/Makefile new file mode 100644 index 000000000..0d348050d --- /dev/null +++ b/sys/modules/sdhci_acpi/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../dev/sdhci + +KMOD= sdhci_acpi +SRCS= sdhci_acpi.c sdhci.h sdhci_if.h +SRCS+= acpi_if.h device_if.h bus_if.h opt_acpi.h pci_if.h mmcbr_if.h + +.include diff --git a/sys/powerpc/mpc85xx/fsl_sdhc.c b/sys/powerpc/mpc85xx/fsl_sdhc.c index 12b18b124..5105e7ec6 100644 --- a/sys/powerpc/mpc85xx/fsl_sdhc.c +++ b/sys/powerpc/mpc85xx/fsl_sdhc.c @@ -125,7 +125,8 @@ static driver_t fsl_sdhc_driver = { static devclass_t fsl_sdhc_devclass; DRIVER_MODULE(sdhci, simplebus, fsl_sdhc_driver, fsl_sdhc_devclass, 0, 0); - +DRIVER_MODULE(mmc, sdhci_fsl, mmc_driver, mmc_devclass, NULL, NULL); +MODULE_DEPEND(sdhci_fsl, mmc, 1, 1, 1); /***************************************************************************** * Private methods diff --git a/sys/sys/param.h b/sys/sys/param.h index 378b1d3b7..d83cb8847 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -58,7 +58,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 1003513 /* Master, propagated to newvers */ +#define __FreeBSD_version 1003514 /* Master, propagated to newvers */ /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, -- 2.42.0