Index: stable/11/sys/dev/mmc/mmc.c =================================================================== --- stable/11/sys/dev/mmc/mmc.c (revision 338636) +++ stable/11/sys/dev/mmc/mmc.c (revision 338637) @@ -1,2584 +1,2577 @@ /*- * 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 * 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 #include #include #include #include #include #include "mmcbr_if.h" #include "mmcbus_if.h" CTASSERT(bus_timing_max <= sizeof(uint32_t) * NBBY); /* * Per-card data */ struct mmc_ivars { uint32_t raw_cid[4]; /* Raw bits of the CID */ uint32_t raw_csd[4]; /* Raw bits of the CSD */ uint32_t raw_scr[2]; /* Raw bits of the SCR */ uint8_t raw_ext_csd[MMC_EXTCSD_SIZE]; /* Raw bits of the EXT_CSD */ uint32_t raw_sd_status[16]; /* Raw bits of the SD_STATUS */ uint16_t rca; u_char read_only; /* True when the device is read-only */ u_char high_cap; /* High Capacity device (block addressed) */ enum mmc_card_mode mode; enum mmc_bus_width bus_width; /* Bus width to use */ struct mmc_cid cid; /* cid decoded */ struct mmc_csd csd; /* csd decoded */ struct mmc_scr scr; /* scr decoded */ struct mmc_sd_status sd_status; /* SD_STATUS decoded */ uint32_t sec_count; /* Card capacity in 512byte blocks */ uint32_t timings; /* Mask of bus timings supported */ uint32_t vccq_120; /* Mask of bus timings at VCCQ of 1.2 V */ uint32_t vccq_180; /* Mask of bus timings at VCCQ of 1.8 V */ uint32_t tran_speed; /* Max speed in normal mode */ uint32_t hs_tran_speed; /* Max speed in high speed mode */ uint32_t erase_sector; /* Card native erase sector size */ uint32_t cmd6_time; /* Generic switch timeout [us] */ uint32_t quirks; /* Quirks as per mmc_quirk->quirks */ 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 static const struct mmc_quirk mmc_quirks[] = { /* * For some SanDisk iNAND devices, the CMD38 argument needs to be * provided in EXT_CSD[113]. */ { 0x2, 0x100, "SEM02G", MMC_QUIRK_INAND_CMD38 }, { 0x2, 0x100, "SEM04G", MMC_QUIRK_INAND_CMD38 }, { 0x2, 0x100, "SEM08G", MMC_QUIRK_INAND_CMD38 }, { 0x2, 0x100, "SEM16G", MMC_QUIRK_INAND_CMD38 }, { 0x2, 0x100, "SEM32G", MMC_QUIRK_INAND_CMD38 }, /* * Disable TRIM for Kingston eMMCs where a firmware bug can lead to * unrecoverable data corruption. */ { 0x70, MMC_QUIRK_OID_ANY, "V10008", MMC_QUIRK_BROKEN_TRIM }, { 0x70, MMC_QUIRK_OID_ANY, "V10016", MMC_QUIRK_BROKEN_TRIM }, { 0x0, 0x0, NULL, 0x0 } }; static SYSCTL_NODE(_hw, OID_AUTO, mmc, CTLFLAG_RD, NULL, "mmc driver"); static int mmc_debug; 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); static int mmc_attach(device_t dev); static int mmc_child_location_str(device_t dev, device_t child, char *buf, size_t buflen); static int mmc_detach(device_t dev); static int mmc_probe(device_t dev); static int mmc_read_ivar(device_t bus, device_t child, int which, uintptr_t *result); static int mmc_release_bus(device_t busdev, device_t dev); static int mmc_resume(device_t dev); static void mmc_retune_pause(device_t busdev, device_t dev, bool retune); static void mmc_retune_unpause(device_t busdev, device_t dev); static int mmc_suspend(device_t dev); static int mmc_wait_for_request(device_t busdev, device_t dev, struct mmc_request *req); 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_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) #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); 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); static void mmc_app_decode_sd_status(uint32_t *raw_sd_status, struct mmc_sd_status *sd_status); static int mmc_app_sd_status(struct mmc_softc *sc, uint16_t rca, uint32_t *rawsdstatus); 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, 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 int mmc_decode_csd_sd(uint32_t *raw_csd, struct mmc_csd *csd); static void mmc_delayed_attach(void *xsc); static int mmc_delete_cards(struct mmc_softc *sc, bool final); static void mmc_discover_cards(struct mmc_softc *sc); static void mmc_format_card_id_string(struct mmc_ivars *ivar); static void mmc_go_discovery(struct mmc_softc *sc); static uint32_t mmc_get_bits(uint32_t *bits, int bit_len, int start, int size); static int mmc_highest_voltage(uint32_t ocr); static bool mmc_host_timing(device_t dev, enum mmc_bus_timing timing); static void mmc_idle_cards(struct mmc_softc *sc); static void mmc_ms_delay(int ms); static void mmc_log_card(device_t dev, struct mmc_ivars *ivar, int newcard); static void mmc_power_down(struct mmc_softc *sc); static void mmc_power_up(struct mmc_softc *sc); static void mmc_rescan_cards(struct mmc_softc *sc); static int mmc_retune(device_t busdev, device_t dev, bool reset); static void mmc_scan(struct mmc_softc *sc); static int mmc_sd_switch(struct mmc_softc *sc, uint8_t mode, uint8_t grp, uint8_t value, uint8_t *res); static int mmc_select_card(struct mmc_softc *sc, uint16_t rca); 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_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_set_blocklen(struct mmc_softc *sc, uint32_t len); static int mmc_set_card_bus_width(struct mmc_softc *sc, struct mmc_ivars *ivar, enum mmc_bus_timing timing); static int mmc_set_power_class(struct mmc_softc *sc, struct mmc_ivars *ivar); static int mmc_set_relative_addr(struct mmc_softc *sc, uint16_t resp); static int mmc_set_timing(struct mmc_softc *sc, struct mmc_ivars *ivar, enum mmc_bus_timing timing); static int mmc_set_vccq(struct mmc_softc *sc, struct mmc_ivars *ivar, enum mmc_bus_timing timing); static int mmc_switch_to_hs200(struct mmc_softc *sc, struct mmc_ivars *ivar, uint32_t clock); static int mmc_switch_to_hs400(struct mmc_softc *sc, struct mmc_ivars *ivar, uint32_t max_dtr, enum mmc_bus_timing max_timing); static int mmc_test_bus_width(struct mmc_softc *sc); static uint32_t mmc_timing_to_dtr(struct mmc_ivars *ivar, enum mmc_bus_timing timing); static const char *mmc_timing_to_string(enum mmc_bus_timing timing); static void mmc_update_child_list(struct mmc_softc *sc); 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); static void mmc_wakeup(struct mmc_request *req); static void mmc_ms_delay(int ms) { DELAY(1000 * ms); /* XXX BAD */ } static int mmc_probe(device_t dev) { device_set_desc(dev, "MMC/SD bus"); return (0); } static int mmc_attach(device_t dev) { struct mmc_softc *sc; sc = device_get_softc(dev); sc->dev = dev; MMC_LOCK_INIT(sc); /* We'll probe and attach our children later, but before / mount */ sc->config_intrhook.ich_func = mmc_delayed_attach; sc->config_intrhook.ich_arg = sc; if (config_intrhook_establish(&sc->config_intrhook) != 0) device_printf(dev, "config_intrhook_establish failed\n"); return (0); } static int mmc_detach(device_t dev) { struct mmc_softc *sc = device_get_softc(dev); int err; err = mmc_delete_cards(sc, true); if (err != 0) return (err); mmc_power_down(sc); MMC_LOCK_DESTROY(sc); return (0); } static int mmc_suspend(device_t dev) { struct mmc_softc *sc = device_get_softc(dev); int err; err = bus_generic_suspend(dev); if (err != 0) return (err); /* * We power down with the bus acquired here, mainly so that no device * is selected any longer and sc->last_rca gets set to 0. Otherwise, * the deselect as part of the bus acquisition in mmc_scan() may fail * during resume, as the bus isn't powered up again before later in * mmc_go_discovery(). */ err = mmc_acquire_bus(dev, dev); if (err != 0) return (err); mmc_power_down(sc); err = mmc_release_bus(dev, dev); return (err); } static int mmc_resume(device_t dev) { struct mmc_softc *sc = device_get_softc(dev); mmc_scan(sc); return (bus_generic_resume(dev)); } static int mmc_acquire_bus(device_t busdev, device_t dev) { struct mmc_softc *sc; struct mmc_ivars *ivar; int err; uint16_t rca; enum mmc_bus_timing timing; err = MMCBR_ACQUIRE_HOST(device_get_parent(busdev), busdev); if (err) return (err); sc = device_get_softc(busdev); MMC_LOCK(sc); if (sc->owner) panic("mmc: host bridge didn't serialize us."); sc->owner = dev; MMC_UNLOCK(sc); if (busdev != dev) { /* * Keep track of the last rca that we've selected. If * we're asked to do it again, don't. We never * unselect unless the bus code itself wants the mmc * bus, and constantly reselecting causes problems. */ ivar = device_get_ivars(dev); rca = ivar->rca; if (sc->last_rca != rca) { if (mmc_select_card(sc, rca) != MMC_ERR_NONE) { device_printf(busdev, "Card at relative " "address %d failed to select\n", rca); return (ENXIO); } sc->last_rca = rca; timing = mmcbr_get_timing(busdev); /* * For eMMC modes, setting/updating bus width and VCCQ * only really is necessary if there actually is more * than one device on the bus as generally that already * had to be done by mmc_calculate_clock() or one of * its calees. Moreover, setting the bus width anew * can trigger re-tuning (via a CRC error on the next * CMD), even if not switching between devices an the * previously selected one is still tuned. Obviously, * we need to re-tune the host controller if devices * are actually switched, though. */ if (timing >= bus_timing_mmc_ddr52 && sc->child_count == 1) return (0); /* Prepare bus width for the new card. */ if (bootverbose || mmc_debug) { device_printf(busdev, "setting bus width to %d bits %s timing\n", (ivar->bus_width == bus_width_4) ? 4 : (ivar->bus_width == bus_width_8) ? 8 : 1, mmc_timing_to_string(timing)); } if (mmc_set_card_bus_width(sc, ivar, timing) != MMC_ERR_NONE) { device_printf(busdev, "Card at relative " "address %d failed to set bus width\n", rca); return (ENXIO); } mmcbr_set_bus_width(busdev, ivar->bus_width); mmcbr_update_ios(busdev); if (mmc_set_vccq(sc, ivar, timing) != MMC_ERR_NONE) { device_printf(busdev, "Failed to set VCCQ " "for card at relative address %d\n", rca); return (ENXIO); } if (timing >= bus_timing_mmc_hs200 && mmc_retune(busdev, dev, true) != 0) { device_printf(busdev, "Card at relative " "address %d failed to re-tune\n", rca); return (ENXIO); } } } else { /* * If there's a card selected, stand down. */ if (sc->last_rca != 0) { if (mmc_select_card(sc, 0) != MMC_ERR_NONE) return (ENXIO); sc->last_rca = 0; } } return (0); } static int mmc_release_bus(device_t busdev, device_t dev) { struct mmc_softc *sc; int err; sc = device_get_softc(busdev); MMC_LOCK(sc); if (!sc->owner) panic("mmc: releasing unowned bus."); if (sc->owner != dev) panic("mmc: you don't own the bus. game over."); MMC_UNLOCK(sc); err = MMCBR_RELEASE_HOST(device_get_parent(busdev), busdev); if (err) return (err); MMC_LOCK(sc); sc->owner = NULL; MMC_UNLOCK(sc); return (0); } static uint32_t mmc_select_vdd(struct mmc_softc *sc, uint32_t ocr) { return (ocr & MMC_OCR_VOLTAGE); } static int mmc_highest_voltage(uint32_t ocr) { int i; for (i = MMC_OCR_MAX_VOLTAGE_SHIFT; i >= MMC_OCR_MIN_VOLTAGE_SHIFT; i--) if (ocr & (1 << i)) return (i); return (-1); } static void mmc_wakeup(struct mmc_request *req) { struct mmc_softc *sc; sc = (struct mmc_softc *)req->done_data; MMC_LOCK(sc); req->flags |= MMC_REQ_DONE; MMC_UNLOCK(sc); wakeup(req); } static int mmc_wait_for_req(struct mmc_softc *sc, struct mmc_request *req) { req->done = mmc_wakeup; req->done_data = sc; if (__predict_false(mmc_debug > 1)) { device_printf(sc->dev, "REQUEST: CMD%d arg %#x flags %#x", req->cmd->opcode, req->cmd->arg, req->cmd->flags); if (req->cmd->data) { printf(" data %d\n", (int)req->cmd->data->len); } else printf("\n"); } MMCBR_REQUEST(device_get_parent(sc->dev), sc->dev, req); MMC_LOCK(sc); while ((req->flags & MMC_REQ_DONE) == 0) msleep(req, &sc->sc_mtx, 0, "mmcreq", 0); MMC_UNLOCK(sc); if (__predict_false(mmc_debug > 2 || (mmc_debug > 0 && req->cmd->error != MMC_ERR_NONE))) device_printf(sc->dev, "CMD%d RESULT: %d\n", req->cmd->opcode, req->cmd->error); return (0); } static int mmc_wait_for_request(device_t busdev, device_t dev, struct mmc_request *req) { struct mmc_softc *sc; struct mmc_ivars *ivar; int err, i; enum mmc_retune_req retune_req; sc = device_get_softc(busdev); KASSERT(sc->owner != NULL, ("%s: Request from %s without bus being acquired.", __func__, device_get_nameunit(dev))); /* * Unless no device is selected or re-tuning is already ongoing, * execute re-tuning if a) the bridge is requesting to do so and * re-tuning hasn't been otherwise paused, or b) if a child asked * to be re-tuned prior to pausing (see also mmc_retune_pause()). */ if (__predict_false(sc->last_rca != 0 && sc->retune_ongoing == 0 && (((retune_req = mmcbr_get_retune_req(busdev)) != retune_req_none && sc->retune_paused == 0) || sc->retune_needed == 1))) { if (__predict_false(mmc_debug > 1)) { device_printf(busdev, "Re-tuning with%s circuit reset required\n", retune_req == retune_req_reset ? "" : "out"); } if (device_get_parent(dev) == busdev) ivar = device_get_ivars(dev); else { for (i = 0; i < sc->child_count; i++) { ivar = device_get_ivars(sc->child_list[i]); if (ivar->rca == sc->last_rca) break; } if (ivar->rca != sc->last_rca) return (EINVAL); } sc->retune_ongoing = 1; err = mmc_retune(busdev, dev, retune_req == retune_req_reset); sc->retune_ongoing = 0; switch (err) { case MMC_ERR_NONE: case MMC_ERR_FAILED: /* Re-tune error but still might work */ break; case MMC_ERR_BADCRC: /* Switch failure on HS400 recovery */ return (ENXIO); case MMC_ERR_INVALID: /* Driver implementation b0rken */ default: /* Unknown error, should not happen */ return (EINVAL); } sc->retune_needed = 0; } return (mmc_wait_for_req(sc, req)); } static int mmc_wait_for_command(struct mmc_softc *sc, uint32_t opcode, uint32_t arg, uint32_t flags, uint32_t *resp, int retries) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = opcode; cmd.arg = arg; cmd.flags = flags; cmd.data = NULL; err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, retries); if (err) return (err); if (resp) { if (flags & MMC_RSP_136) memcpy(resp, cmd.resp, 4 * sizeof(uint32_t)); else *resp = cmd.resp[0]; } return (0); } static void mmc_idle_cards(struct mmc_softc *sc) { device_t dev; struct mmc_command cmd; dev = sc->dev; mmcbr_set_chip_select(dev, cs_high); mmcbr_update_ios(dev); mmc_ms_delay(1); memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_GO_IDLE_STATE; cmd.arg = 0; cmd.flags = MMC_RSP_NONE | MMC_CMD_BC; cmd.data = NULL; mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); mmc_ms_delay(1); mmcbr_set_chip_select(dev, cs_dontcare); mmcbr_update_ios(dev); mmc_ms_delay(1); } static int mmc_send_app_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr) { struct mmc_command cmd; int err = MMC_ERR_NONE, i; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = ACMD_SD_SEND_OP_COND; cmd.arg = ocr; cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; cmd.data = NULL; for (i = 0; i < 1000; i++) { 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) || (ocr & MMC_OCR_VOLTAGE) == 0) break; err = MMC_ERR_TIMEOUT; mmc_ms_delay(10); } if (rocr && err == MMC_ERR_NONE) *rocr = cmd.resp[0]; return (err); } static int mmc_send_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr) { struct mmc_command cmd; int err = MMC_ERR_NONE, i; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_SEND_OP_COND; cmd.arg = ocr; cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; cmd.data = NULL; for (i = 0; i < 1000; i++) { 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) || (ocr & MMC_OCR_VOLTAGE) == 0) break; err = MMC_ERR_TIMEOUT; mmc_ms_delay(10); } if (rocr && err == MMC_ERR_NONE) *rocr = cmd.resp[0]; return (err); } static int mmc_send_if_cond(struct mmc_softc *sc, uint8_t vhs) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = SD_SEND_IF_COND; cmd.arg = (vhs << 8) + 0xAA; cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR; cmd.data = NULL; err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); return (err); } static void mmc_power_up(struct mmc_softc *sc) { device_t dev; enum mmc_vccq vccq; dev = sc->dev; mmcbr_set_vdd(dev, mmc_highest_voltage(mmcbr_get_host_ocr(dev))); mmcbr_set_bus_mode(dev, opendrain); mmcbr_set_chip_select(dev, cs_dontcare); mmcbr_set_bus_width(dev, bus_width_1); mmcbr_set_power_mode(dev, power_up); mmcbr_set_clock(dev, 0); mmcbr_update_ios(dev); for (vccq = vccq_330; ; vccq--) { mmcbr_set_vccq(dev, vccq); if (mmcbr_switch_vccq(dev) == 0 || vccq == vccq_120) break; } mmc_ms_delay(1); mmcbr_set_clock(dev, SD_MMC_CARD_ID_FREQUENCY); mmcbr_set_timing(dev, bus_timing_normal); mmcbr_set_power_mode(dev, power_on); mmcbr_update_ios(dev); mmc_ms_delay(2); } static void mmc_power_down(struct mmc_softc *sc) { device_t dev = sc->dev; mmcbr_set_bus_mode(dev, opendrain); mmcbr_set_chip_select(dev, cs_dontcare); mmcbr_set_bus_width(dev, bus_width_1); mmcbr_set_power_mode(dev, power_off); mmcbr_set_clock(dev, 0); mmcbr_set_timing(dev, bus_timing_normal); mmcbr_update_ios(dev); } static int mmc_select_card(struct mmc_softc *sc, uint16_t rca) { int err, flags; flags = (rca ? MMC_RSP_R1B : MMC_RSP_NONE) | MMC_CMD_AC; sc->retune_paused++; err = mmc_wait_for_command(sc, MMC_SELECT_CARD, (uint32_t)rca << 16, flags, NULL, CMD_RETRIES); sc->retune_paused--; return (err); } static int mmc_sd_switch(struct mmc_softc *sc, uint8_t mode, uint8_t grp, uint8_t value, uint8_t *res) { int err; struct mmc_command cmd; struct mmc_data data; memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); memset(res, 0, 64); cmd.opcode = SD_SWITCH_FUNC; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.arg = mode << 31; /* 0 - check, 1 - set */ cmd.arg |= 0x00FFFFFF; cmd.arg &= ~(0xF << (grp * 4)); cmd.arg |= value << (grp * 4); cmd.data = &data; data.data = res; data.len = 64; data.flags = MMC_DATA_READ; 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, struct mmc_ivars *ivar, enum mmc_bus_timing timing) { struct mmc_command cmd; int err; uint8_t value; if (mmcbr_get_mode(sc->dev) == mode_sd) { memset(&cmd, 0, sizeof(cmd)); 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->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 (ivar->bus_width) { case bus_width_1: cmd.arg = SD_BUS_WIDTH_1; break; case bus_width_4: cmd.arg = SD_BUS_WIDTH_4; break; default: return (MMC_ERR_INVALID); } err = mmc_wait_for_app_cmd(sc->dev, sc->dev, ivar->rca, &cmd, CMD_RETRIES); } else { switch (ivar->bus_width) { case bus_width_1: if (timing == bus_timing_mmc_hs400 || timing == bus_timing_mmc_hs400es) return (MMC_ERR_INVALID); value = EXT_CSD_BUS_WIDTH_1; break; case bus_width_4: switch (timing) { case bus_timing_mmc_ddr52: value = EXT_CSD_BUS_WIDTH_4_DDR; break; case bus_timing_mmc_hs400: case bus_timing_mmc_hs400es: return (MMC_ERR_INVALID); default: value = EXT_CSD_BUS_WIDTH_4; break; } break; case bus_width_8: value = 0; switch (timing) { case bus_timing_mmc_hs400es: value = EXT_CSD_BUS_WIDTH_ES; /* FALLTHROUGH */ case bus_timing_mmc_ddr52: case bus_timing_mmc_hs400: value |= EXT_CSD_BUS_WIDTH_8_DDR; break; default: value = EXT_CSD_BUS_WIDTH_8; break; } break; default: return (MMC_ERR_INVALID); } 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_power_class(struct mmc_softc *sc, struct mmc_ivars *ivar) { device_t dev; const uint8_t *ext_csd; uint32_t clock; uint8_t value; dev = sc->dev; if (mmcbr_get_mode(dev) != mode_mmc || ivar->csd.spec_vers < 4) return (MMC_ERR_NONE); value = 0; ext_csd = ivar->raw_ext_csd; clock = mmcbr_get_clock(dev); switch (1 << mmcbr_get_vdd(dev)) { case MMC_OCR_LOW_VOLTAGE: if (clock <= MMC_TYPE_HS_26_MAX) value = ext_csd[EXT_CSD_PWR_CL_26_195]; else if (clock <= MMC_TYPE_HS_52_MAX) { if (mmcbr_get_timing(dev) >= bus_timing_mmc_ddr52 && ivar->bus_width >= bus_width_4) value = ext_csd[EXT_CSD_PWR_CL_52_195_DDR]; else value = ext_csd[EXT_CSD_PWR_CL_52_195]; } else if (clock <= MMC_TYPE_HS200_HS400ES_MAX) value = ext_csd[EXT_CSD_PWR_CL_200_195]; break; case MMC_OCR_270_280: case MMC_OCR_280_290: case MMC_OCR_290_300: case MMC_OCR_300_310: case MMC_OCR_310_320: case MMC_OCR_320_330: case MMC_OCR_330_340: case MMC_OCR_340_350: case MMC_OCR_350_360: if (clock <= MMC_TYPE_HS_26_MAX) value = ext_csd[EXT_CSD_PWR_CL_26_360]; else if (clock <= MMC_TYPE_HS_52_MAX) { if (mmcbr_get_timing(dev) == bus_timing_mmc_ddr52 && ivar->bus_width >= bus_width_4) value = ext_csd[EXT_CSD_PWR_CL_52_360_DDR]; else value = ext_csd[EXT_CSD_PWR_CL_52_360]; } else if (clock <= MMC_TYPE_HS200_HS400ES_MAX) { if (ivar->bus_width == bus_width_8) value = ext_csd[EXT_CSD_PWR_CL_200_360_DDR]; else value = ext_csd[EXT_CSD_PWR_CL_200_360]; } break; default: device_printf(dev, "No power class support for VDD 0x%x\n", 1 << mmcbr_get_vdd(dev)); return (MMC_ERR_INVALID); } if (ivar->bus_width == bus_width_8) value = (value & EXT_CSD_POWER_CLASS_8BIT_MASK) >> EXT_CSD_POWER_CLASS_8BIT_SHIFT; else value = (value & EXT_CSD_POWER_CLASS_4BIT_MASK) >> EXT_CSD_POWER_CLASS_4BIT_SHIFT; if (value == 0) return (MMC_ERR_NONE); return (mmc_switch(dev, dev, ivar->rca, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_POWER_CLASS, value, ivar->cmd6_time, true)); } static int mmc_set_timing(struct mmc_softc *sc, struct mmc_ivars *ivar, enum mmc_bus_timing timing) { u_char switch_res[64]; uint8_t value; int err; if (mmcbr_get_mode(sc->dev) == mode_sd) { switch (timing) { case bus_timing_normal: value = SD_SWITCH_NORMAL_MODE; break; case bus_timing_hs: value = SD_SWITCH_HS_MODE; break; default: return (MMC_ERR_INVALID); } err = mmc_sd_switch(sc, SD_SWITCH_MODE_SET, SD_SWITCH_GROUP1, value, switch_res); if (err != MMC_ERR_NONE) return (err); if ((switch_res[16] & 0xf) != value) return (MMC_ERR_FAILED); mmcbr_set_timing(sc->dev, timing); mmcbr_update_ios(sc->dev); } else { switch (timing) { case bus_timing_normal: value = EXT_CSD_HS_TIMING_BC; break; case bus_timing_hs: case bus_timing_mmc_ddr52: value = EXT_CSD_HS_TIMING_HS; break; case bus_timing_mmc_hs200: value = EXT_CSD_HS_TIMING_HS200; break; case bus_timing_mmc_hs400: case bus_timing_mmc_hs400es: value = EXT_CSD_HS_TIMING_HS400; break; default: return (MMC_ERR_INVALID); } err = mmc_switch(sc->dev, sc->dev, ivar->rca, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, value, ivar->cmd6_time, false); 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 int mmc_set_vccq(struct mmc_softc *sc, struct mmc_ivars *ivar, enum mmc_bus_timing timing) { if (isset(&ivar->vccq_120, timing)) mmcbr_set_vccq(sc->dev, vccq_120); else if (isset(&ivar->vccq_180, timing)) mmcbr_set_vccq(sc->dev, vccq_180); else mmcbr_set_vccq(sc->dev, vccq_330); if (mmcbr_switch_vccq(sc->dev) != 0) return (MMC_ERR_INVALID); else return (MMC_ERR_NONE); } 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; uint8_t buf[8]; int err; if (mmcbr_get_caps(sc->dev) & MMC_CAP_8_BIT_DATA) { mmcbr_set_bus_width(sc->dev, bus_width_8); mmcbr_update_ios(sc->dev); sc->squelched++; /* Errors are expected, squelch reporting. */ memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); cmd.opcode = MMC_BUSTEST_W; cmd.arg = 0; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.data = &data; data.data = __DECONST(void *, p8); data.len = 8; data.flags = MMC_DATA_WRITE; mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, 0); memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); cmd.opcode = MMC_BUSTEST_R; cmd.arg = 0; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.data = &data; data.data = buf; data.len = 8; data.flags = MMC_DATA_READ; err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, 0); sc->squelched--; mmcbr_set_bus_width(sc->dev, bus_width_1); mmcbr_update_ios(sc->dev); if (err == MMC_ERR_NONE && memcmp(buf, p8ok, 8) == 0) return (bus_width_8); } if (mmcbr_get_caps(sc->dev) & MMC_CAP_4_BIT_DATA) { mmcbr_set_bus_width(sc->dev, bus_width_4); mmcbr_update_ios(sc->dev); sc->squelched++; /* Errors are expected, squelch reporting. */ memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); cmd.opcode = MMC_BUSTEST_W; cmd.arg = 0; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.data = &data; data.data = __DECONST(void *, p4); data.len = 4; data.flags = MMC_DATA_WRITE; mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, 0); memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); cmd.opcode = MMC_BUSTEST_R; cmd.arg = 0; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.data = &data; data.data = buf; data.len = 4; data.flags = MMC_DATA_READ; err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, 0); sc->squelched--; mmcbr_set_bus_width(sc->dev, bus_width_1); mmcbr_update_ios(sc->dev); if (err == MMC_ERR_NONE && memcmp(buf, p4ok, 4) == 0) return (bus_width_4); } return (bus_width_1); } static uint32_t 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)); } static void mmc_decode_cid_sd(uint32_t *raw_cid, struct mmc_cid *cid) { int i; /* There's no version info, so we take it on faith */ memset(cid, 0, sizeof(*cid)); cid->mid = mmc_get_bits(raw_cid, 128, 120, 8); cid->oid = mmc_get_bits(raw_cid, 128, 104, 16); for (i = 0; i < 5; i++) cid->pnm[i] = mmc_get_bits(raw_cid, 128, 96 - i * 8, 8); cid->pnm[5] = 0; cid->prv = mmc_get_bits(raw_cid, 128, 56, 8); cid->psn = mmc_get_bits(raw_cid, 128, 24, 32); cid->mdt_year = mmc_get_bits(raw_cid, 128, 12, 8) + 2000; cid->mdt_month = mmc_get_bits(raw_cid, 128, 8, 4); } static void mmc_decode_cid_mmc(uint32_t *raw_cid, struct mmc_cid *cid, bool is_4_41p) { int i; /* There's no version info, so we take it on faith */ memset(cid, 0, sizeof(*cid)); cid->mid = mmc_get_bits(raw_cid, 128, 120, 8); cid->oid = mmc_get_bits(raw_cid, 128, 104, 8); for (i = 0; i < 6; i++) cid->pnm[i] = mmc_get_bits(raw_cid, 128, 96 - i * 8, 8); cid->pnm[6] = 0; 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); if (is_4_41p) cid->mdt_year += 2013; else cid->mdt_year += 1997; } static void mmc_format_card_id_string(struct mmc_ivars *ivar) { char oidstr[8]; uint8_t c1; uint8_t c2; /* * Format a card ID string for use by the mmcsd driver, it's what * appears between the <> in the following: * mmcsd0: 968MB at mmc0 * 22.5MHz/4bit/128-block * * Also format just the card serial number, which the mmcsd driver will * use as the disk->d_ident string. * * The card_id_string in mmc_ivars is currently allocated as 64 bytes, * and our max formatted length is currently 55 bytes if every field * contains the largest value. * * Sometimes the oid is two printable ascii chars; when it's not, * format it as 0xnnnn instead. */ c1 = (ivar->cid.oid >> 8) & 0x0ff; c2 = ivar->cid.oid & 0x0ff; if (c1 > 0x1f && c1 < 0x7f && c2 > 0x1f && c2 < 0x7f) snprintf(oidstr, sizeof(oidstr), "%c%c", c1, c2); else snprintf(oidstr, sizeof(oidstr), "0x%04x", ivar->cid.oid); snprintf(ivar->card_sn_string, sizeof(ivar->card_sn_string), "%08X", ivar->cid.psn); snprintf(ivar->card_id_string, sizeof(ivar->card_id_string), "%s%s %s %d.%d SN %08X MFG %02d/%04d by %d %s", ivar->mode == mode_sd ? "SD" : "MMC", ivar->high_cap ? "HC" : "", ivar->cid.pnm, ivar->cid.prv >> 4, ivar->cid.prv & 0x0f, ivar->cid.psn, ivar->cid.mdt_month, ivar->cid.mdt_year, ivar->cid.mid, oidstr); } static const int exp[8] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 }; static const int mant[16] = { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 }; static const int cur_min[8] = { 500, 1000, 5000, 10000, 25000, 35000, 60000, 100000 }; static const int cur_max[8] = { 1000, 5000, 10000, 25000, 35000, 45000, 800000, 200000 }; static int mmc_decode_csd_sd(uint32_t *raw_csd, struct mmc_csd *csd) { int v; int m; int e; memset(csd, 0, sizeof(*csd)); csd->csd_structure = v = mmc_get_bits(raw_csd, 128, 126, 2); if (v == 0) { m = mmc_get_bits(raw_csd, 128, 115, 4); e = mmc_get_bits(raw_csd, 128, 112, 3); csd->tacc = (exp[e] * mant[m] + 9) / 10; csd->nsac = mmc_get_bits(raw_csd, 128, 104, 8) * 100; m = mmc_get_bits(raw_csd, 128, 99, 4); e = mmc_get_bits(raw_csd, 128, 96, 3); csd->tran_speed = exp[e] * 10000 * mant[m]; csd->ccc = mmc_get_bits(raw_csd, 128, 84, 12); csd->read_bl_len = 1 << mmc_get_bits(raw_csd, 128, 80, 4); csd->read_bl_partial = mmc_get_bits(raw_csd, 128, 79, 1); 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)]; 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; 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); csd->wp_grp_enable = mmc_get_bits(raw_csd, 128, 31, 1); csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 128, 26, 3); csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 128, 22, 4); csd->write_bl_partial = mmc_get_bits(raw_csd, 128, 21, 1); return (MMC_ERR_NONE); } else if (v == 1) { m = mmc_get_bits(raw_csd, 128, 115, 4); e = mmc_get_bits(raw_csd, 128, 112, 3); csd->tacc = (exp[e] * mant[m] + 9) / 10; csd->nsac = mmc_get_bits(raw_csd, 128, 104, 8) * 100; m = mmc_get_bits(raw_csd, 128, 99, 4); e = mmc_get_bits(raw_csd, 128, 96, 3); csd->tran_speed = exp[e] * 10000 * mant[m]; csd->ccc = mmc_get_bits(raw_csd, 128, 84, 12); csd->read_bl_len = 1 << mmc_get_bits(raw_csd, 128, 80, 4); csd->read_bl_partial = mmc_get_bits(raw_csd, 128, 79, 1); 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->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); csd->wp_grp_enable = mmc_get_bits(raw_csd, 128, 31, 1); csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 128, 26, 3); csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 128, 22, 4); csd->write_bl_partial = mmc_get_bits(raw_csd, 128, 21, 1); return (MMC_ERR_NONE); } return (MMC_ERR_INVALID); } static void mmc_decode_csd_mmc(uint32_t *raw_csd, struct mmc_csd *csd) { int m; int e; memset(csd, 0, sizeof(*csd)); csd->csd_structure = mmc_get_bits(raw_csd, 128, 126, 2); csd->spec_vers = mmc_get_bits(raw_csd, 128, 122, 4); m = mmc_get_bits(raw_csd, 128, 115, 4); e = mmc_get_bits(raw_csd, 128, 112, 3); csd->tacc = exp[e] * mant[m] + 9 / 10; csd->nsac = mmc_get_bits(raw_csd, 128, 104, 8) * 100; m = mmc_get_bits(raw_csd, 128, 99, 4); e = mmc_get_bits(raw_csd, 128, 96, 3); csd->tran_speed = exp[e] * 10000 * mant[m]; csd->ccc = mmc_get_bits(raw_csd, 128, 84, 12); csd->read_bl_len = 1 << mmc_get_bits(raw_csd, 128, 80, 4); csd->read_bl_partial = mmc_get_bits(raw_csd, 128, 79, 1); 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)]; 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; csd->erase_blk_en = 0; csd->erase_sector = (mmc_get_bits(raw_csd, 128, 42, 5) + 1) * (mmc_get_bits(raw_csd, 128, 37, 5) + 1); csd->wp_grp_size = mmc_get_bits(raw_csd, 128, 32, 5); csd->wp_grp_enable = mmc_get_bits(raw_csd, 128, 31, 1); csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 128, 26, 3); csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 128, 22, 4); csd->write_bl_partial = mmc_get_bits(raw_csd, 128, 21, 1); } static void mmc_app_decode_scr(uint32_t *raw_scr, struct mmc_scr *scr) { unsigned int scr_struct; memset(scr, 0, sizeof(*scr)); scr_struct = mmc_get_bits(raw_scr, 64, 60, 4); if (scr_struct != 0) { printf("Unrecognised SCR structure version %d\n", scr_struct); return; } scr->sda_vsn = mmc_get_bits(raw_scr, 64, 56, 4); scr->bus_widths = mmc_get_bits(raw_scr, 64, 48, 4); } static void mmc_app_decode_sd_status(uint32_t *raw_sd_status, struct mmc_sd_status *sd_status) { memset(sd_status, 0, sizeof(*sd_status)); sd_status->bus_width = mmc_get_bits(raw_sd_status, 512, 510, 2); sd_status->secured_mode = mmc_get_bits(raw_sd_status, 512, 509, 1); sd_status->card_type = mmc_get_bits(raw_sd_status, 512, 480, 16); sd_status->prot_area = mmc_get_bits(raw_sd_status, 512, 448, 12); sd_status->speed_class = mmc_get_bits(raw_sd_status, 512, 440, 8); sd_status->perf_move = mmc_get_bits(raw_sd_status, 512, 432, 8); sd_status->au_size = mmc_get_bits(raw_sd_status, 512, 428, 4); sd_status->erase_size = mmc_get_bits(raw_sd_status, 512, 408, 16); sd_status->erase_timeout = mmc_get_bits(raw_sd_status, 512, 402, 6); sd_status->erase_offset = mmc_get_bits(raw_sd_status, 512, 400, 2); } static int mmc_all_send_cid(struct mmc_softc *sc, uint32_t *rawcid) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_ALL_SEND_CID; cmd.arg = 0; cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR; cmd.data = NULL; err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); memcpy(rawcid, cmd.resp, 4 * sizeof(uint32_t)); return (err); } static int mmc_send_csd(struct mmc_softc *sc, uint16_t rca, uint32_t *rawcsd) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_SEND_CSD; cmd.arg = rca << 16; cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR; cmd.data = NULL; err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); memcpy(rawcsd, cmd.resp, 4 * sizeof(uint32_t)); return (err); } static int mmc_app_send_scr(struct mmc_softc *sc, uint16_t rca, uint32_t *rawscr) { int err; struct mmc_command cmd; struct mmc_data data; memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); memset(rawscr, 0, 8); cmd.opcode = ACMD_SEND_SCR; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.arg = 0; cmd.data = &data; data.data = rawscr; data.len = 8; data.flags = MMC_DATA_READ; 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_app_sd_status(struct mmc_softc *sc, uint16_t rca, uint32_t *rawsdstatus) { struct mmc_command cmd; struct mmc_data data; int err, i; memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); memset(rawsdstatus, 0, 64); cmd.opcode = ACMD_SD_STATUS; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.arg = 0; cmd.data = &data; data.data = rawsdstatus; data.len = 64; data.flags = MMC_DATA_READ; 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); } static int mmc_set_relative_addr(struct mmc_softc *sc, uint16_t resp) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_SET_RELATIVE_ADDR; cmd.arg = resp << 16; cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR; cmd.data = NULL; err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); return (err); } static int mmc_send_relative_addr(struct mmc_softc *sc, uint32_t *resp) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = SD_SEND_RELATIVE_ADDR; cmd.arg = 0; cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR; cmd.data = NULL; err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); *resp = cmd.resp[0]; return (err); } static int mmc_set_blocklen(struct mmc_softc *sc, uint32_t len) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_SET_BLOCKLEN; cmd.arg = len; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; cmd.data = NULL; err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES); return (err); } static uint32_t mmc_timing_to_dtr(struct mmc_ivars *ivar, enum mmc_bus_timing timing) { switch (timing) { case bus_timing_normal: return (ivar->tran_speed); case bus_timing_hs: return (ivar->hs_tran_speed); case bus_timing_uhs_sdr12: return (SD_SDR12_MAX); case bus_timing_uhs_sdr25: return (SD_SDR25_MAX); case bus_timing_uhs_ddr50: return (SD_DDR50_MAX); case bus_timing_uhs_sdr50: return (SD_SDR50_MAX); case bus_timing_uhs_sdr104: return (SD_SDR104_MAX); case bus_timing_mmc_ddr52: return (MMC_TYPE_DDR52_MAX); case bus_timing_mmc_hs200: case bus_timing_mmc_hs400: case bus_timing_mmc_hs400es: return (MMC_TYPE_HS200_HS400ES_MAX); } return (0); } static const char * mmc_timing_to_string(enum mmc_bus_timing timing) { switch (timing) { case bus_timing_normal: return ("normal speed"); case bus_timing_hs: return ("high speed"); case bus_timing_uhs_sdr12: case bus_timing_uhs_sdr25: case bus_timing_uhs_sdr50: case bus_timing_uhs_sdr104: return ("single data rate"); case bus_timing_uhs_ddr50: case bus_timing_mmc_ddr52: return ("dual data rate"); case bus_timing_mmc_hs200: return ("HS200"); case bus_timing_mmc_hs400: return ("HS400"); case bus_timing_mmc_hs400es: return ("HS400 with enhanced strobe"); } return (""); } static bool mmc_host_timing(device_t dev, enum mmc_bus_timing timing) { int host_caps; host_caps = mmcbr_get_caps(dev); #define HOST_TIMING_CAP(host_caps, cap) ({ \ bool retval; \ if (((host_caps) & (cap)) == (cap)) \ retval = true; \ else \ retval = false; \ retval; \ }) switch (timing) { case bus_timing_normal: return (true); case bus_timing_hs: return (HOST_TIMING_CAP(host_caps, MMC_CAP_HSPEED)); case bus_timing_uhs_sdr12: return (HOST_TIMING_CAP(host_caps, MMC_CAP_UHS_SDR12)); case bus_timing_uhs_sdr25: return (HOST_TIMING_CAP(host_caps, MMC_CAP_UHS_SDR25)); case bus_timing_uhs_ddr50: return (HOST_TIMING_CAP(host_caps, MMC_CAP_UHS_DDR50)); case bus_timing_uhs_sdr50: return (HOST_TIMING_CAP(host_caps, MMC_CAP_UHS_SDR50)); case bus_timing_uhs_sdr104: return (HOST_TIMING_CAP(host_caps, MMC_CAP_UHS_SDR104)); case bus_timing_mmc_ddr52: return (HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_DDR52)); case bus_timing_mmc_hs200: return (HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_HS200)); case bus_timing_mmc_hs400: return (HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_HS400)); case bus_timing_mmc_hs400es: return (HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_HS400 | MMC_CAP_MMC_ENH_STROBE)); } #undef HOST_TIMING_CAP return (false); } static void mmc_log_card(device_t dev, struct mmc_ivars *ivar, int newcard) { enum mmc_bus_timing max_timing, timing; device_printf(dev, "Card at relative address 0x%04x%s:\n", ivar->rca, newcard ? " added" : ""); device_printf(dev, " card: %s\n", ivar->card_id_string); max_timing = bus_timing_normal; for (timing = bus_timing_max; timing > bus_timing_normal; timing--) { if (isset(&ivar->timings, timing)) { max_timing = timing; break; } } device_printf(dev, " quirks: %b\n", ivar->quirks, MMC_QUIRKS_FMT); device_printf(dev, " bus: %ubit, %uMHz (%s timing)\n", (ivar->bus_width == bus_width_1 ? 1 : (ivar->bus_width == bus_width_4 ? 4 : 8)), mmc_timing_to_dtr(ivar, timing) / 1000000, mmc_timing_to_string(timing)); device_printf(dev, " memory: %u blocks, erase sector %u blocks%s\n", ivar->sec_count, ivar->erase_sector, ivar->read_only ? ", read-only" : ""); } static void mmc_discover_cards(struct mmc_softc *sc) { u_char switch_res[64]; uint32_t raw_cid[4]; struct mmc_ivars *ivar = NULL; const struct mmc_quirk *quirk; + const uint8_t *ext_csd; device_t child; int err, host_caps, i, newcard; uint32_t resp, sec_count, status; uint16_t rca = 2; + int16_t rev; + uint8_t card_type; host_caps = mmcbr_get_caps(sc->dev); if (bootverbose || mmc_debug) device_printf(sc->dev, "Probing cards\n"); while (1) { child = NULL; sc->squelched++; /* Errors are expected, squelch reporting. */ err = mmc_all_send_cid(sc, raw_cid); sc->squelched--; if (err == MMC_ERR_TIMEOUT) break; if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error reading CID %d\n", err); break; } newcard = 1; for (i = 0; i < sc->child_count; i++) { ivar = device_get_ivars(sc->child_list[i]); if (memcmp(ivar->raw_cid, raw_cid, sizeof(raw_cid)) == 0) { newcard = 0; break; } } if (bootverbose || mmc_debug) { 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]); } if (newcard) { ivar = malloc(sizeof(struct mmc_ivars), M_DEVBUF, M_WAITOK | M_ZERO); memcpy(ivar->raw_cid, raw_cid, sizeof(raw_cid)); } if (mmcbr_get_ro(sc->dev)) ivar->read_only = 1; ivar->bus_width = bus_width_1; setbit(&ivar->timings, bus_timing_normal); ivar->mode = mmcbr_get_mode(sc->dev); if (ivar->mode == mode_sd) { mmc_decode_cid_sd(ivar->raw_cid, &ivar->cid); err = mmc_send_relative_addr(sc, &resp); if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error getting RCA %d\n", err); goto free_ivar; } ivar->rca = resp >> 16; /* Get card CSD. */ err = mmc_send_csd(sc, ivar->rca, ivar->raw_csd); if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error getting CSD %d\n", err); goto free_ivar; } if (bootverbose || mmc_debug) device_printf(sc->dev, "%sard detected (CSD %08x%08x%08x%08x)\n", newcard ? "New c" : "C", ivar->raw_csd[0], ivar->raw_csd[1], ivar->raw_csd[2], ivar->raw_csd[3]); err = mmc_decode_csd_sd(ivar->raw_csd, &ivar->csd); if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error decoding CSD\n"); goto free_ivar; } ivar->sec_count = ivar->csd.capacity / MMC_SECTOR_SIZE; if (ivar->csd.csd_structure > 0) ivar->high_cap = 1; ivar->tran_speed = ivar->csd.tran_speed; ivar->erase_sector = ivar->csd.erase_sector * ivar->csd.write_bl_len / MMC_SECTOR_SIZE; 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); goto free_ivar; } if ((status & R1_CARD_IS_LOCKED) != 0) { device_printf(sc->dev, "Card is password protected, skipping\n"); goto free_ivar; } /* Get card SCR. Card must be selected to fetch it. */ err = mmc_select_card(sc, ivar->rca); if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error selecting card %d\n", err); goto free_ivar; } err = mmc_app_send_scr(sc, ivar->rca, ivar->raw_scr); if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error reading SCR %d\n", err); goto free_ivar; } 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))) { err = mmc_sd_switch(sc, SD_SWITCH_MODE_CHECK, SD_SWITCH_GROUP1, SD_SWITCH_NOCHANGE, switch_res); if (err == MMC_ERR_NONE && switch_res[13] & (1 << SD_SWITCH_HS_MODE)) { setbit(&ivar->timings, bus_timing_hs); ivar->hs_tran_speed = SD_HS_MAX; } } /* * We deselect then reselect the card here. Some cards * become unselected and timeout with the above two * 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 * 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 * it is still nice to get that right. */ (void)mmc_select_card(sc, 0); (void)mmc_select_card(sc, ivar->rca); (void)mmc_app_sd_status(sc, ivar->rca, ivar->raw_sd_status); mmc_app_decode_sd_status(ivar->raw_sd_status, &ivar->sd_status); if (ivar->sd_status.au_size != 0) { ivar->erase_sector = 16 << ivar->sd_status.au_size; } /* Find maximum supported bus width. */ if ((host_caps & MMC_CAP_4_BIT_DATA) && (ivar->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) ivar->bus_width = bus_width_4; goto child_common; } ivar->rca = rca++; err = mmc_set_relative_addr(sc, ivar->rca); if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error setting RCA %d\n", err); goto free_ivar; } /* Get card CSD. */ err = mmc_send_csd(sc, ivar->rca, ivar->raw_csd); if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error getting CSD %d\n", err); goto free_ivar; } if (bootverbose || mmc_debug) device_printf(sc->dev, "%sard detected (CSD %08x%08x%08x%08x)\n", newcard ? "New c" : "C", ivar->raw_csd[0], ivar->raw_csd[1], ivar->raw_csd[2], ivar->raw_csd[3]); mmc_decode_csd_mmc(ivar->raw_csd, &ivar->csd); ivar->sec_count = ivar->csd.capacity / MMC_SECTOR_SIZE; ivar->tran_speed = ivar->csd.tran_speed; ivar->erase_sector = ivar->csd.erase_sector * ivar->csd.write_bl_len / MMC_SECTOR_SIZE; 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); goto free_ivar; } if ((status & R1_CARD_IS_LOCKED) != 0) { device_printf(sc->dev, "Card is password protected, skipping\n"); goto free_ivar; } err = mmc_select_card(sc, ivar->rca); if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error selecting card %d\n", err); goto free_ivar; } + rev = -1; /* Only MMC >= 4.x devices support EXT_CSD. */ if (ivar->csd.spec_vers >= 4) { 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); goto free_ivar; } + ext_csd = ivar->raw_ext_csd; + rev = ext_csd[EXT_CSD_REV]; /* 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) + - (ivar->raw_ext_csd[EXT_CSD_SEC_CNT + 2] << 16) + - (ivar->raw_ext_csd[EXT_CSD_SEC_CNT + 3] << 24); + sec_count = le32dec(&ext_csd[EXT_CSD_SEC_CNT]); if (sec_count != 0) { ivar->sec_count = sec_count; ivar->high_cap = 1; } /* Find maximum supported bus width. */ ivar->bus_width = mmc_test_bus_width(sc); /* Get device speeds beyond normal mode. */ - if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] & - EXT_CSD_CARD_TYPE_HS_52) != 0) { + card_type = ext_csd[EXT_CSD_CARD_TYPE]; + if ((card_type & EXT_CSD_CARD_TYPE_HS_52) != 0) { setbit(&ivar->timings, bus_timing_hs); ivar->hs_tran_speed = MMC_TYPE_HS_52_MAX; - } else if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] & - EXT_CSD_CARD_TYPE_HS_26) != 0) { + } else if ((card_type & EXT_CSD_CARD_TYPE_HS_26) != 0) { setbit(&ivar->timings, bus_timing_hs); ivar->hs_tran_speed = MMC_TYPE_HS_26_MAX; } - if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] & - EXT_CSD_CARD_TYPE_DDR_52_1_2V) != 0 && + if ((card_type & EXT_CSD_CARD_TYPE_DDR_52_1_2V) != 0 && (host_caps & MMC_CAP_SIGNALING_120) != 0) { setbit(&ivar->timings, bus_timing_mmc_ddr52); setbit(&ivar->vccq_120, bus_timing_mmc_ddr52); } - if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] & - EXT_CSD_CARD_TYPE_DDR_52_1_8V) != 0 && + if ((card_type & EXT_CSD_CARD_TYPE_DDR_52_1_8V) != 0 && (host_caps & MMC_CAP_SIGNALING_180) != 0) { setbit(&ivar->timings, bus_timing_mmc_ddr52); setbit(&ivar->vccq_180, bus_timing_mmc_ddr52); } - if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] & - EXT_CSD_CARD_TYPE_HS200_1_2V) != 0 && + if ((card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) != 0 && (host_caps & MMC_CAP_SIGNALING_120) != 0) { setbit(&ivar->timings, bus_timing_mmc_hs200); setbit(&ivar->vccq_120, bus_timing_mmc_hs200); } - if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] & - EXT_CSD_CARD_TYPE_HS200_1_8V) != 0 && + if ((card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) != 0 && (host_caps & MMC_CAP_SIGNALING_180) != 0) { setbit(&ivar->timings, bus_timing_mmc_hs200); setbit(&ivar->vccq_180, bus_timing_mmc_hs200); } - if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] & - EXT_CSD_CARD_TYPE_HS400_1_2V) != 0 && + if ((card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) != 0 && (host_caps & MMC_CAP_SIGNALING_120) != 0 && ivar->bus_width == bus_width_8) { setbit(&ivar->timings, bus_timing_mmc_hs400); setbit(&ivar->vccq_120, bus_timing_mmc_hs400); } - if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] & - EXT_CSD_CARD_TYPE_HS400_1_8V) != 0 && + if ((card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) != 0 && (host_caps & MMC_CAP_SIGNALING_180) != 0 && ivar->bus_width == bus_width_8) { setbit(&ivar->timings, bus_timing_mmc_hs400); setbit(&ivar->vccq_180, bus_timing_mmc_hs400); } - if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] & - EXT_CSD_CARD_TYPE_HS400_1_2V) != 0 && - (ivar->raw_ext_csd[EXT_CSD_STROBE_SUPPORT] & + if ((card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) != 0 && + (ext_csd[EXT_CSD_STROBE_SUPPORT] & EXT_CSD_STROBE_SUPPORT_EN) != 0 && (host_caps & MMC_CAP_SIGNALING_120) != 0 && ivar->bus_width == bus_width_8) { setbit(&ivar->timings, bus_timing_mmc_hs400es); setbit(&ivar->vccq_120, bus_timing_mmc_hs400es); } - if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] & - EXT_CSD_CARD_TYPE_HS400_1_8V) != 0 && - (ivar->raw_ext_csd[EXT_CSD_STROBE_SUPPORT] & + if ((card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) != 0 && + (ext_csd[EXT_CSD_STROBE_SUPPORT] & EXT_CSD_STROBE_SUPPORT_EN) != 0 && (host_caps & MMC_CAP_SIGNALING_180) != 0 && ivar->bus_width == bus_width_8) { setbit(&ivar->timings, bus_timing_mmc_hs400es); setbit(&ivar->vccq_180, bus_timing_mmc_hs400es); } /* * Determine generic switch timeout (provided in * units of 10 ms), defaulting to 500 ms. */ ivar->cmd6_time = 500 * 1000; - if (ivar->raw_ext_csd[EXT_CSD_REV] >= 6) + if (rev >= 6) ivar->cmd6_time = 10 * - ivar->raw_ext_csd[EXT_CSD_GEN_CMD6_TIME]; + ext_csd[EXT_CSD_GEN_CMD6_TIME]; /* Handle HC erase sector size. */ - if (ivar->raw_ext_csd[EXT_CSD_ERASE_GRP_SIZE] != 0) { + if (ext_csd[EXT_CSD_ERASE_GRP_SIZE] != 0) { ivar->erase_sector = 1024 * - ivar->raw_ext_csd[EXT_CSD_ERASE_GRP_SIZE]; + ext_csd[EXT_CSD_ERASE_GRP_SIZE]; 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); goto free_ivar; } } } - mmc_decode_cid_mmc(ivar->raw_cid, &ivar->cid, - ivar->raw_ext_csd[EXT_CSD_REV] >= 5); + mmc_decode_cid_mmc(ivar->raw_cid, &ivar->cid, rev >= 5); child_common: for (quirk = &mmc_quirks[0]; quirk->mid != 0x0; quirk++) { if ((quirk->mid == MMC_QUIRK_MID_ANY || quirk->mid == ivar->cid.mid) && (quirk->oid == MMC_QUIRK_OID_ANY || quirk->oid == ivar->cid.oid) && strncmp(quirk->pnm, ivar->cid.pnm, sizeof(ivar->cid.pnm)) == 0) { ivar->quirks = quirk->quirks; break; } } /* * Some cards that report maximum I/O block sizes greater * than 512 require the block length to be set to 512, even * though that is supposed to be the default. Example: * * Transcend 2GB SDSC card, CID: * mid=0x1b oid=0x534d pnm="00000" prv=1.0 mdt=00.2000 */ if (ivar->csd.read_bl_len != MMC_SECTOR_SIZE || ivar->csd.write_bl_len != MMC_SECTOR_SIZE) mmc_set_blocklen(sc, MMC_SECTOR_SIZE); mmc_format_card_id_string(ivar); if (bootverbose || mmc_debug) mmc_log_card(sc->dev, ivar, newcard); if (newcard) { /* Add device. */ child = device_add_child(sc->dev, NULL, -1); if (child != NULL) { device_set_ivars(child, ivar); sc->child_list = realloc(sc->child_list, sizeof(device_t) * sc->child_count + 1, M_DEVBUF, M_WAITOK); sc->child_list[sc->child_count++] = child; } else device_printf(sc->dev, "Error adding child\n"); } free_ivar: if (newcard && child == NULL) free(ivar, M_DEVBUF); (void)mmc_select_card(sc, 0); /* * Not returning here when one MMC device could no be added * potentially would mean looping forever when that device * is broken (in which case it also may impact the remainder * of the bus anyway, though). */ if ((newcard && child == NULL) || mmcbr_get_mode(sc->dev) == mode_sd) return; } } static void mmc_update_child_list(struct mmc_softc *sc) { device_t child; int i, j; if (sc->child_count == 0) { free(sc->child_list, M_DEVBUF); return; } for (i = j = 0; i < sc->child_count; i++) { for (;;) { child = sc->child_list[j++]; if (child != NULL) break; } if (i != j) sc->child_list[i] = child; } sc->child_list = realloc(sc->child_list, sizeof(device_t) * sc->child_count, M_DEVBUF, M_WAITOK); } static void mmc_rescan_cards(struct mmc_softc *sc) { struct mmc_ivars *ivar; int err, i, j; for (i = j = 0; i < sc->child_count; i++) { ivar = device_get_ivars(sc->child_list[i]); 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", ivar->rca); err = device_delete_child(sc->dev, sc->child_list[i]); if (err != 0) { j++; continue; } free(ivar, M_DEVBUF); } else j++; } if (sc->child_count == j) goto out; sc->child_count = j; mmc_update_child_list(sc); out: (void)mmc_select_card(sc, 0); } static int mmc_delete_cards(struct mmc_softc *sc, bool final) { struct mmc_ivars *ivar; int err, i, j; err = 0; for (i = j = 0; i < sc->child_count; i++) { ivar = device_get_ivars(sc->child_list[i]); if (bootverbose || mmc_debug) device_printf(sc->dev, "Card at relative address %d deleted\n", ivar->rca); err = device_delete_child(sc->dev, sc->child_list[i]); if (err != 0) { j++; if (final == false) continue; else break; } free(ivar, M_DEVBUF); } sc->child_count = j; mmc_update_child_list(sc); return (err); } static void mmc_go_discovery(struct mmc_softc *sc) { uint32_t ocr; device_t dev; int err; dev = sc->dev; if (mmcbr_get_power_mode(dev) != power_on) { /* * First, try SD modes */ sc->squelched++; /* Errors are expected, squelch reporting. */ mmcbr_set_mode(dev, mode_sd); mmc_power_up(sc); mmcbr_set_bus_mode(dev, pushpull); if (bootverbose || mmc_debug) device_printf(sc->dev, "Probing bus\n"); 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"); if (mmc_send_app_op_cond(sc, 0, &ocr) != MMC_ERR_NONE) { if (bootverbose || mmc_debug) device_printf(sc->dev, "SD probe: failed\n"); /* * Failed, try MMC */ 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"); 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); sc->squelched--; mmcbr_set_ocr(dev, mmc_select_vdd(sc, ocr)); if (mmcbr_get_ocr(dev) != 0) mmc_idle_cards(sc); } else { mmcbr_set_bus_mode(dev, opendrain); mmcbr_set_clock(dev, SD_MMC_CARD_ID_FREQUENCY); mmcbr_update_ios(dev); /* XXX recompute vdd based on new cards? */ } /* * Make sure that we have a mutually agreeable voltage to at least * one card on the bus. */ if (bootverbose || mmc_debug) 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"); (void)mmc_delete_cards(sc, false); mmc_power_down(sc); return; } /* * Reselect the cards after we've idled them above. */ if (mmcbr_get_mode(dev) == mode_sd) { err = mmc_send_if_cond(sc, 1); mmc_send_app_op_cond(sc, (err ? 0 : MMC_OCR_CCS) | mmcbr_get_ocr(dev), NULL); } else mmc_send_op_cond(sc, MMC_OCR_CCS | mmcbr_get_ocr(dev), NULL); mmc_discover_cards(sc); mmc_rescan_cards(sc); mmcbr_set_bus_mode(dev, pushpull); mmcbr_update_ios(dev); mmc_calculate_clock(sc); } static int mmc_calculate_clock(struct mmc_softc *sc) { device_t dev; struct mmc_ivars *ivar; int i; uint32_t dtr, max_dtr; uint16_t rca; enum mmc_bus_timing max_timing, timing; bool changed, hs400; dev = sc->dev; max_dtr = mmcbr_get_f_max(dev); max_timing = bus_timing_max; do { changed = false; for (i = 0; i < sc->child_count; i++) { ivar = device_get_ivars(sc->child_list[i]); if (isclr(&ivar->timings, max_timing) || !mmc_host_timing(dev, max_timing)) { for (timing = max_timing - 1; timing >= bus_timing_normal; timing--) { if (isset(&ivar->timings, timing) && mmc_host_timing(dev, timing)) { max_timing = timing; break; } } changed = true; } dtr = mmc_timing_to_dtr(ivar, max_timing); if (dtr < max_dtr) { max_dtr = dtr; changed = true; } } } while (changed == true); if (bootverbose || mmc_debug) { device_printf(dev, "setting transfer rate to %d.%03dMHz (%s timing)\n", max_dtr / 1000000, (max_dtr / 1000) % 1000, mmc_timing_to_string(max_timing)); } /* * HS400 must be tuned in HS200 mode, so in case of HS400 we begin * with HS200 following the sequence as described in "6.6.2.2 HS200 * timing mode selection" of the eMMC specification v5.1, too, and * switch to max_timing later. HS400ES requires no tuning and, thus, * can be switch to directly, but requires the same detour via high * speed mode as does HS400 (see mmc_switch_to_hs400()). */ hs400 = max_timing == bus_timing_mmc_hs400; timing = hs400 == true ? bus_timing_mmc_hs200 : max_timing; for (i = 0; i < sc->child_count; i++) { ivar = device_get_ivars(sc->child_list[i]); if ((ivar->timings & ~(1 << bus_timing_normal)) == 0) continue; rca = ivar->rca; if (mmc_select_card(sc, rca) != MMC_ERR_NONE) { device_printf(dev, "Card at relative address %d " "failed to select\n", rca); continue; } if (timing == bus_timing_mmc_hs200 || /* includes HS400 */ timing == bus_timing_mmc_hs400es) { if (mmc_set_vccq(sc, ivar, timing) != MMC_ERR_NONE) { device_printf(dev, "Failed to set VCCQ for " "card at relative address %d\n", rca); continue; } } if (timing == bus_timing_mmc_hs200) { /* includes HS400 */ /* Set bus width (required for initial tuning). */ if (mmc_set_card_bus_width(sc, ivar, timing) != MMC_ERR_NONE) { device_printf(dev, "Card at relative address " "%d failed to set bus width\n", rca); continue; } mmcbr_set_bus_width(dev, ivar->bus_width); mmcbr_update_ios(dev); } else if (timing == bus_timing_mmc_hs400es) { if (mmc_switch_to_hs400(sc, ivar, max_dtr, timing) != MMC_ERR_NONE) { device_printf(dev, "Card at relative address " "%d failed to set %s timing\n", rca, mmc_timing_to_string(timing)); continue; } goto power_class; } if (mmc_set_timing(sc, ivar, timing) != MMC_ERR_NONE) { device_printf(dev, "Card at relative address %d " "failed to set %s timing\n", rca, mmc_timing_to_string(timing)); continue; } if (timing == bus_timing_mmc_ddr52) { /* * Set EXT_CSD_BUS_WIDTH_n_DDR in EXT_CSD_BUS_WIDTH * (must be done after switching to EXT_CSD_HS_TIMING). */ if (mmc_set_card_bus_width(sc, ivar, timing) != MMC_ERR_NONE) { device_printf(dev, "Card at relative address " "%d failed to set bus width\n", rca); continue; } mmcbr_set_bus_width(dev, ivar->bus_width); mmcbr_update_ios(dev); if (mmc_set_vccq(sc, ivar, timing) != MMC_ERR_NONE) { device_printf(dev, "Failed to set VCCQ for " "card at relative address %d\n", rca); continue; } } /* Set clock (must be done before initial tuning). */ mmcbr_set_clock(dev, max_dtr); mmcbr_update_ios(dev); if (mmcbr_tune(dev, hs400) != 0) { device_printf(dev, "Card at relative address %d " "failed to execute initial tuning\n", rca); continue; } if (hs400 == true && mmc_switch_to_hs400(sc, ivar, max_dtr, max_timing) != MMC_ERR_NONE) { device_printf(dev, "Card at relative address %d " "failed to set %s timing\n", rca, mmc_timing_to_string(max_timing)); continue; } power_class: if (mmc_set_power_class(sc, ivar) != MMC_ERR_NONE) { device_printf(dev, "Card at relative address %d " "failed to set power class\n", rca); } } (void)mmc_select_card(sc, 0); return (max_dtr); } /* * Switch from HS200 to HS400 (either initially or for re-tuning) or directly * to HS400ES. This follows the sequences described in "6.6.2.3 HS400 timing * mode selection" of the eMMC specification v5.1. */ static int mmc_switch_to_hs400(struct mmc_softc *sc, struct mmc_ivars *ivar, uint32_t clock, enum mmc_bus_timing max_timing) { device_t dev; int err; uint16_t rca; dev = sc->dev; rca = ivar->rca; /* * Both clock and timing must be set as appropriate for high speed * before eventually switching to HS400/HS400ES; mmc_set_timing() * will issue mmcbr_update_ios(). */ mmcbr_set_clock(dev, ivar->hs_tran_speed); err = mmc_set_timing(sc, ivar, bus_timing_hs); if (err != MMC_ERR_NONE) return (err); /* * Set EXT_CSD_BUS_WIDTH_8_DDR in EXT_CSD_BUS_WIDTH (and additionally * EXT_CSD_BUS_WIDTH_ES for HS400ES). */ err = mmc_set_card_bus_width(sc, ivar, max_timing); if (err != MMC_ERR_NONE) return (err); mmcbr_set_bus_width(dev, ivar->bus_width); mmcbr_update_ios(dev); /* Finally, switch to HS400/HS400ES mode. */ err = mmc_set_timing(sc, ivar, max_timing); if (err != MMC_ERR_NONE) return (err); mmcbr_set_clock(dev, clock); mmcbr_update_ios(dev); return (MMC_ERR_NONE); } /* * Switch from HS400 to HS200 (for re-tuning). */ static int mmc_switch_to_hs200(struct mmc_softc *sc, struct mmc_ivars *ivar, uint32_t clock) { device_t dev; int err; uint16_t rca; dev = sc->dev; rca = ivar->rca; /* * Both clock and timing must initially be set as appropriate for * DDR52 before eventually switching to HS200; mmc_set_timing() * will issue mmcbr_update_ios(). */ mmcbr_set_clock(dev, ivar->hs_tran_speed); err = mmc_set_timing(sc, ivar, bus_timing_mmc_ddr52); if (err != MMC_ERR_NONE) return (err); /* * Next, switch to high speed. Thus, clear EXT_CSD_BUS_WIDTH_n_DDR * in EXT_CSD_BUS_WIDTH and update bus width and timing in ios. */ err = mmc_set_card_bus_width(sc, ivar, bus_timing_hs); if (err != MMC_ERR_NONE) return (err); mmcbr_set_bus_width(dev, ivar->bus_width); mmcbr_set_timing(sc->dev, bus_timing_hs); mmcbr_update_ios(dev); /* Finally, switch to HS200 mode. */ err = mmc_set_timing(sc, ivar, bus_timing_mmc_hs200); if (err != MMC_ERR_NONE) return (err); mmcbr_set_clock(dev, clock); mmcbr_update_ios(dev); return (MMC_ERR_NONE); } static int mmc_retune(device_t busdev, device_t dev, bool reset) { struct mmc_softc *sc; struct mmc_ivars *ivar; int err; uint32_t clock; enum mmc_bus_timing timing; if (device_get_parent(dev) != busdev) return (MMC_ERR_INVALID); sc = device_get_softc(busdev); if (sc->retune_needed != 1 && sc->retune_paused != 0) return (MMC_ERR_INVALID); timing = mmcbr_get_timing(busdev); if (timing == bus_timing_mmc_hs400) { /* * Controllers use the data strobe line to latch data from * the devices in HS400 mode so periodic re-tuning isn't * expected to be required, i. e. only if a CRC or tuning * error is signaled to the bridge. In these latter cases * we are asked to reset the tuning circuit and need to do * the switch timing dance. */ if (reset == false) return (0); ivar = device_get_ivars(dev); clock = mmcbr_get_clock(busdev); if (mmc_switch_to_hs200(sc, ivar, clock) != MMC_ERR_NONE) return (MMC_ERR_BADCRC); } err = mmcbr_retune(busdev, reset); if (err != 0 && timing == bus_timing_mmc_hs400) return (MMC_ERR_BADCRC); switch (err) { case 0: break; case EIO: return (MMC_ERR_FAILED); default: return (MMC_ERR_INVALID); } if (timing == bus_timing_mmc_hs400) { if (mmc_switch_to_hs400(sc, ivar, clock, timing) != MMC_ERR_NONE) return (MMC_ERR_BADCRC); } return (MMC_ERR_NONE); } static void mmc_retune_pause(device_t busdev, device_t dev, bool retune) { struct mmc_softc *sc; sc = device_get_softc(busdev); KASSERT(device_get_parent(dev) == busdev, ("%s: %s is not a child of %s", __func__, device_get_nameunit(dev), device_get_nameunit(busdev))); KASSERT(sc->owner != NULL, ("%s: Request from %s without bus being acquired.", __func__, device_get_nameunit(dev))); if (retune == true && sc->retune_paused == 0) sc->retune_needed = 1; sc->retune_paused++; } static void mmc_retune_unpause(device_t busdev, device_t dev) { struct mmc_softc *sc; sc = device_get_softc(busdev); KASSERT(device_get_parent(dev) == busdev, ("%s: %s is not a child of %s", __func__, device_get_nameunit(dev), device_get_nameunit(busdev))); KASSERT(sc->owner != NULL, ("%s: Request from %s without bus being acquired.", __func__, device_get_nameunit(dev))); KASSERT(sc->retune_paused != 0, ("%s: Re-tune pause count already at 0", __func__)); sc->retune_paused--; } static void mmc_scan(struct mmc_softc *sc) { device_t dev = sc->dev; int err; err = mmc_acquire_bus(dev, dev); if (err != 0) { device_printf(dev, "Failed to acquire bus for scanning\n"); return; } mmc_go_discovery(sc); err = mmc_release_bus(dev, dev); if (err != 0) { device_printf(dev, "Failed to release bus after scanning\n"); return; } (void)bus_generic_attach(dev); } static int mmc_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) { struct mmc_ivars *ivar = device_get_ivars(child); 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; case MMC_IVAR_MEDIA_SIZE: *result = ivar->sec_count; break; case MMC_IVAR_RCA: *result = ivar->rca; break; case MMC_IVAR_SECTOR_SIZE: *result = MMC_SECTOR_SIZE; break; case MMC_IVAR_TRAN_SPEED: *result = mmcbr_get_clock(bus); break; case MMC_IVAR_READ_ONLY: *result = ivar->read_only; break; case MMC_IVAR_HIGH_CAP: *result = ivar->high_cap; break; case MMC_IVAR_CARD_TYPE: *result = ivar->mode; break; case MMC_IVAR_BUS_WIDTH: *result = ivar->bus_width; break; case MMC_IVAR_ERASE_SECTOR: *result = ivar->erase_sector; break; case MMC_IVAR_MAX_DATA: *result = mmcbr_get_max_data(bus); break; case MMC_IVAR_CMD6_TIMEOUT: *result = ivar->cmd6_time; break; case MMC_IVAR_QUIRKS: *result = ivar->quirks; break; case MMC_IVAR_CARD_ID_STRING: *(char **)result = ivar->card_id_string; break; case MMC_IVAR_CARD_SN_STRING: *(char **)result = ivar->card_sn_string; break; } return (0); } static int mmc_write_ivar(device_t bus, device_t child, int which, uintptr_t value) { /* * None are writable ATM */ return (EINVAL); } static void mmc_delayed_attach(void *xsc) { struct mmc_softc *sc = xsc; mmc_scan(sc); config_intrhook_disestablish(&sc->config_intrhook); } static int mmc_child_location_str(device_t dev, device_t child, char *buf, size_t buflen) { snprintf(buf, buflen, "rca=0x%04x", mmc_get_rca(child)); return (0); } static device_method_t mmc_methods[] = { /* device_if */ DEVMETHOD(device_probe, mmc_probe), DEVMETHOD(device_attach, mmc_attach), DEVMETHOD(device_detach, mmc_detach), DEVMETHOD(device_suspend, mmc_suspend), DEVMETHOD(device_resume, mmc_resume), /* Bus interface */ DEVMETHOD(bus_read_ivar, mmc_read_ivar), DEVMETHOD(bus_write_ivar, mmc_write_ivar), DEVMETHOD(bus_child_location_str, mmc_child_location_str), /* MMC Bus interface */ DEVMETHOD(mmcbus_retune_pause, mmc_retune_pause), DEVMETHOD(mmcbus_retune_unpause, mmc_retune_unpause), DEVMETHOD(mmcbus_wait_for_request, mmc_wait_for_request), DEVMETHOD(mmcbus_acquire_bus, mmc_acquire_bus), DEVMETHOD(mmcbus_release_bus, mmc_release_bus), DEVMETHOD_END }; driver_t mmc_driver = { "mmc", mmc_methods, sizeof(struct mmc_softc), }; devclass_t mmc_devclass; MODULE_VERSION(mmc, MMC_VERSION); Index: stable/11/sys/dev/mmc/mmcreg.h =================================================================== --- stable/11/sys/dev/mmc/mmcreg.h (revision 338636) +++ stable/11/sys/dev/mmc/mmcreg.h (revision 338637) @@ -1,606 +1,617 @@ /*- * 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 * 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_MMCREG_H #define DEV_MMC_MMCREG_H /* * This file contains the register definitions for the mmc and sd busses. * They are taken from publicly available sources. */ struct mmc_data; struct mmc_request; struct mmc_command { uint32_t opcode; uint32_t arg; uint32_t resp[4]; uint32_t flags; /* Expected responses */ #define MMC_RSP_PRESENT (1ul << 0) /* Response */ #define MMC_RSP_136 (1ul << 1) /* 136 bit response */ #define MMC_RSP_CRC (1ul << 2) /* Expect valid crc */ #define MMC_RSP_BUSY (1ul << 3) /* Card may send busy */ #define MMC_RSP_OPCODE (1ul << 4) /* Response include opcode */ #define MMC_RSP_MASK 0x1ful #define MMC_CMD_AC (0ul << 5) /* Addressed Command, no data */ #define MMC_CMD_ADTC (1ul << 5) /* Addressed Data transfer cmd */ #define MMC_CMD_BC (2ul << 5) /* Broadcast command, no response */ #define MMC_CMD_BCR (3ul << 5) /* Broadcast command with response */ #define MMC_CMD_MASK (3ul << 5) /* Possible response types defined in the standard: */ #define MMC_RSP_NONE (0) #define MMC_RSP_R1 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) #define MMC_RSP_R1B (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | MMC_RSP_BUSY) #define MMC_RSP_R2 (MMC_RSP_PRESENT | MMC_RSP_136 | MMC_RSP_CRC) #define MMC_RSP_R3 (MMC_RSP_PRESENT) #define MMC_RSP_R4 (MMC_RSP_PRESENT) #define MMC_RSP_R5 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) #define MMC_RSP_R5B (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | MMC_RSP_BUSY) #define MMC_RSP_R6 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) #define MMC_RSP_R7 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) #define MMC_RSP(x) ((x) & MMC_RSP_MASK) uint32_t retries; uint32_t error; #define MMC_ERR_NONE 0 #define MMC_ERR_TIMEOUT 1 #define MMC_ERR_BADCRC 2 #define MMC_ERR_FIFO 3 #define MMC_ERR_FAILED 4 #define MMC_ERR_INVALID 5 #define MMC_ERR_NO_MEMORY 6 #define MMC_ERR_MAX 6 struct mmc_data *data; /* Data segment with cmd */ struct mmc_request *mrq; /* backpointer to request */ }; /* * R1 responses * * Types (per SD 2.0 standard) * e : error bit * s : status bit * r : detected and set for the actual command response * x : Detected and set during command execution. The host can get * the status by issuing a command with R1 response. * * Clear Condition (per SD 2.0 standard) * a : according to the card current state. * b : always related to the previous command. reception of a valid * command will clear it (with a delay of one command). * c : clear by read */ #define R1_OUT_OF_RANGE (1u << 31) /* erx, c */ #define R1_ADDRESS_ERROR (1u << 30) /* erx, c */ #define R1_BLOCK_LEN_ERROR (1u << 29) /* erx, c */ #define R1_ERASE_SEQ_ERROR (1u << 28) /* er, c */ #define R1_ERASE_PARAM (1u << 27) /* erx, c */ #define R1_WP_VIOLATION (1u << 26) /* erx, c */ #define R1_CARD_IS_LOCKED (1u << 25) /* sx, a */ #define R1_LOCK_UNLOCK_FAILED (1u << 24) /* erx, c */ #define R1_COM_CRC_ERROR (1u << 23) /* er, b */ #define R1_ILLEGAL_COMMAND (1u << 22) /* er, b */ #define R1_CARD_ECC_FAILED (1u << 21) /* erx, c */ #define R1_CC_ERROR (1u << 20) /* erx, c */ #define R1_ERROR (1u << 19) /* erx, c */ #define R1_CSD_OVERWRITE (1u << 16) /* erx, c */ #define R1_WP_ERASE_SKIP (1u << 15) /* erx, c */ #define R1_CARD_ECC_DISABLED (1u << 14) /* sx, a */ #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) #define R1_CURRENT_STATE(x) (((x) & R1_CURRENT_STATE_MASK) >> 9) #define R1_STATE_IDLE 0 #define R1_STATE_READY 1 #define R1_STATE_IDENT 2 #define R1_STATE_STBY 3 #define R1_STATE_TRAN 4 #define R1_STATE_DATA 5 #define R1_STATE_RCV 6 #define R1_STATE_PRG 7 #define R1_STATE_DIS 8 struct mmc_data { size_t len; /* size of the data */ size_t xfer_len; void *data; /* data buffer */ uint32_t flags; #define MMC_DATA_WRITE (1UL << 0) #define MMC_DATA_READ (1UL << 1) #define MMC_DATA_STREAM (1UL << 2) #define MMC_DATA_MULTI (1UL << 3) struct mmc_request *mrq; }; struct mmc_request { struct mmc_command *cmd; struct mmc_command *stop; void (*done)(struct mmc_request *); /* Completion function */ void *done_data; /* requestor set data */ uint32_t flags; #define MMC_REQ_DONE 1 #define MMC_TUNE_DONE 2 }; /* Command definitions */ /* Class 0 and 1: Basic commands & read stream commands */ #define MMC_GO_IDLE_STATE 0 #define MMC_SEND_OP_COND 1 #define MMC_ALL_SEND_CID 2 #define MMC_SET_RELATIVE_ADDR 3 #define SD_SEND_RELATIVE_ADDR 3 #define MMC_SET_DSR 4 #define MMC_SLEEP_AWAKE 5 #define MMC_SWITCH_FUNC 6 #define MMC_SWITCH_FUNC_CMDS 0 #define MMC_SWITCH_FUNC_SET 1 #define MMC_SWITCH_FUNC_CLR 2 #define MMC_SWITCH_FUNC_WR 3 #define MMC_SELECT_CARD 7 #define MMC_DESELECT_CARD 7 #define MMC_SEND_EXT_CSD 8 #define SD_SEND_IF_COND 8 #define MMC_SEND_CSD 9 #define MMC_SEND_CID 10 #define MMC_READ_DAT_UNTIL_STOP 11 #define MMC_STOP_TRANSMISSION 12 #define MMC_SEND_STATUS 13 #define MMC_BUSTEST_R 14 #define MMC_GO_INACTIVE_STATE 15 #define MMC_BUSTEST_W 19 /* Class 2: Block oriented read commands */ #define MMC_SET_BLOCKLEN 16 #define MMC_READ_SINGLE_BLOCK 17 #define MMC_READ_MULTIPLE_BLOCK 18 #define MMC_SEND_TUNING_BLOCK 19 #define MMC_SEND_TUNING_BLOCK_HS200 21 /* Class 3: Stream write commands */ #define MMC_WRITE_DAT_UNTIL_STOP 20 /* reserved: 22 */ /* Class 4: Block oriented write commands */ #define MMC_SET_BLOCK_COUNT 23 #define MMC_WRITE_BLOCK 24 #define MMC_WRITE_MULTIPLE_BLOCK 25 #define MMC_PROGARM_CID 26 #define MMC_PROGRAM_CSD 27 /* Class 6: Block oriented write protection commands */ #define MMC_SET_WRITE_PROT 28 #define MMC_CLR_WRITE_PROT 29 #define MMC_SEND_WRITE_PROT 30 /* reserved: 31 */ /* Class 5: Erase commands */ #define SD_ERASE_WR_BLK_START 32 #define SD_ERASE_WR_BLK_END 33 /* 34 -- reserved old command */ #define MMC_ERASE_GROUP_START 35 #define MMC_ERASE_GROUP_END 36 /* 37 -- reserved old command */ #define MMC_ERASE 38 #define MMC_ERASE_ERASE 0x00000000 #define MMC_ERASE_TRIM 0x00000001 #define MMC_ERASE_FULE 0x00000002 #define MMC_ERASE_DISCARD 0x00000003 #define MMC_ERASE_SECURE_ERASE 0x80000000 #define MMC_ERASE_SECURE_TRIM1 0x80000001 #define MMC_ERASE_SECURE_TRIM2 0x80008000 /* Class 9: I/O mode commands */ #define MMC_FAST_IO 39 #define MMC_GO_IRQ_STATE 40 /* reserved: 41 */ /* Class 7: Lock card */ #define MMC_LOCK_UNLOCK 42 /* reserved: 43 */ /* reserved: 44 */ /* reserved: 45 */ /* reserved: 46 */ /* reserved: 47 */ /* reserved: 48 */ /* reserved: 49 */ /* reserved: 50 */ /* reserved: 51 */ /* reserved: 54 */ /* Class 8: Application specific commands */ #define MMC_APP_CMD 55 #define MMC_GEN_CMD 56 /* reserved: 57 */ /* reserved: 58 */ /* reserved: 59 */ /* reserved for mfg: 60 */ /* reserved for mfg: 61 */ /* reserved for mfg: 62 */ /* reserved for mfg: 63 */ /* Class 9: I/O cards (sd) */ #define SD_IO_RW_DIRECT 52 #define SD_IO_RW_EXTENDED 53 /* Class 10: Switch function commands */ #define SD_SWITCH_FUNC 6 /* reserved: 34 */ /* reserved: 35 */ /* reserved: 36 */ /* reserved: 37 */ /* reserved: 50 */ /* reserved: 57 */ /* Application specific commands for SD */ #define ACMD_SET_BUS_WIDTH 6 #define ACMD_SD_STATUS 13 #define ACMD_SEND_NUM_WR_BLOCKS 22 #define ACMD_SET_WR_BLK_ERASE_COUNT 23 #define ACMD_SD_SEND_OP_COND 41 #define ACMD_SET_CLR_CARD_DETECT 42 #define ACMD_SEND_SCR 51 /* * EXT_CSD fields */ +#define EXT_CSD_FLUSH_CACHE 32 /* W/E */ +#define EXT_CSD_CACHE_CTRL 33 /* R/W/E */ #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_STROBE_SUPPORT 184 /* RO */ #define EXT_CSD_HS_TIMING 185 /* R/W */ #define EXT_CSD_POWER_CLASS 187 /* R/W */ #define EXT_CSD_CARD_TYPE 196 /* RO */ #define EXT_CSD_DRIVER_STRENGTH 197 /* RO */ #define EXT_CSD_REV 192 /* RO */ #define EXT_CSD_PART_SWITCH_TO 199 /* RO */ #define EXT_CSD_PWR_CL_52_195 200 /* RO */ #define EXT_CSD_PWR_CL_26_195 201 /* RO */ #define EXT_CSD_PWR_CL_52_360 202 /* RO */ #define EXT_CSD_PWR_CL_26_360 203 /* RO */ #define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ #define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */ #define EXT_CSD_ERASE_TO_MULT 223 /* RO */ #define EXT_CSD_ERASE_GRP_SIZE 224 /* RO */ #define EXT_CSD_BOOT_SIZE_MULT 226 /* RO */ #define EXT_CSD_SEC_FEATURE_SUPPORT 231 /* RO */ #define EXT_CSD_PWR_CL_200_195 236 /* RO */ #define EXT_CSD_PWR_CL_200_360 237 /* RO */ #define EXT_CSD_PWR_CL_52_195_DDR 238 /* RO */ #define EXT_CSD_PWR_CL_52_360_DDR 239 /* RO */ +#define EXT_CSD_CACHE_FLUSH_POLICY 249 /* RO */ #define EXT_CSD_GEN_CMD6_TIME 248 /* RO */ +#define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */ #define EXT_CSD_PWR_CL_200_360_DDR 253 /* RO */ /* * EXT_CSD field definitions */ +#define EXT_CSD_FLUSH_CACHE_FLUSH 0x01 +#define EXT_CSD_FLUSH_CACHE_BARRIER 0x02 + +#define EXT_CSD_CACHE_CTRL_CACHE_EN 0x01 + #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_HS_TIMING_BC 0 #define EXT_CSD_HS_TIMING_HS 1 #define EXT_CSD_HS_TIMING_HS200 2 #define EXT_CSD_HS_TIMING_HS400 3 #define EXT_CSD_HS_TIMING_DRV_STR_SHIFT 4 #define EXT_CSD_POWER_CLASS_8BIT_MASK 0xf0 #define EXT_CSD_POWER_CLASS_8BIT_SHIFT 4 #define EXT_CSD_POWER_CLASS_4BIT_MASK 0x0f #define EXT_CSD_POWER_CLASS_4BIT_SHIFT 0 #define EXT_CSD_CARD_TYPE_HS_26 0x0001 #define EXT_CSD_CARD_TYPE_HS_52 0x0002 #define EXT_CSD_CARD_TYPE_DDR_52_1_8V 0x0004 #define EXT_CSD_CARD_TYPE_DDR_52_1_2V 0x0008 #define EXT_CSD_CARD_TYPE_HS200_1_8V 0x0010 #define EXT_CSD_CARD_TYPE_HS200_1_2V 0x0020 #define EXT_CSD_CARD_TYPE_HS400_1_8V 0x0040 #define EXT_CSD_CARD_TYPE_HS400_1_2V 0x0080 #define EXT_CSD_BUS_WIDTH_1 0 #define EXT_CSD_BUS_WIDTH_4 1 #define EXT_CSD_BUS_WIDTH_8 2 #define EXT_CSD_BUS_WIDTH_4_DDR 5 #define EXT_CSD_BUS_WIDTH_8_DDR 6 #define EXT_CSD_BUS_WIDTH_ES 0x80 #define EXT_CSD_STROBE_SUPPORT_EN 0x01 #define EXT_CSD_SEC_FEATURE_SUPPORT_ER_EN 0x01 #define EXT_CSD_SEC_FEATURE_SUPPORT_BD_BLK_EN 0x04 #define EXT_CSD_SEC_FEATURE_SUPPORT_GB_CL_EN 0x10 #define EXT_CSD_SEC_FEATURE_SUPPORT_SANITIZE 0x40 + +#define EXT_CSD_CACHE_FLUSH_POLICY_FIFO 0x01 /* * Vendor specific EXT_CSD fields */ /* SanDisk iNAND */ #define EXT_CSD_INAND_CMD38 113 #define EXT_CSD_INAND_CMD38_ERASE 0x00 #define EXT_CSD_INAND_CMD38_TRIM 0x01 #define EXT_CSD_INAND_CMD38_SECURE_ERASE 0x80 #define EXT_CSD_INAND_CMD38_SECURE_TRIM1 0x81 #define EXT_CSD_INAND_CMD38_SECURE_TRIM2 0x82 #define MMC_TYPE_HS_26_MAX 26000000 #define MMC_TYPE_HS_52_MAX 52000000 #define MMC_TYPE_DDR52_MAX 52000000 #define MMC_TYPE_HS200_HS400ES_MAX 200000000 /* * SD bus widths */ #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_SDR50_MODE 2 #define SD_SWITCH_SDR104_MODE 3 #define SD_SWITCH_DDR50 4 #define SD_SWITCH_NOCHANGE 0xF #define SD_CLR_CARD_DETECT 0 #define SD_SET_CARD_DETECT 1 #define SD_HS_MAX 50000000 #define SD_DDR50_MAX 50000000 #define SD_SDR12_MAX 25000000 #define SD_SDR25_MAX 50000000 #define SD_SDR50_MAX 100000000 #define SD_SDR104_MAX 208000000 /* Specifications require 400 kHz max. during ID phase. */ #define SD_MMC_CARD_ID_FREQUENCY 400000 /* OCR bits */ /* * in SD 2.0 spec, bits 8-14 are now marked reserved * Low voltage in SD2.0 spec is bit 7, TBD voltage * Low voltage in MC 3.31 spec is bit 7, 1.65-1.95V * Specs prior to MMC 3.31 defined bits 0-7 as voltages down to 1.5V. * 3.31 redefined them to be reserved and also said that cards had to * support the 2.7-3.6V and fixed the OCR to be 0xfff8000 for high voltage * cards. MMC 4.0 says that a dual voltage card responds with 0xfff8080. * Looks like the fine-grained control of the voltage tolerance ranges * was abandoned. * * The MMC_OCR_CCS appears to be valid for only SD cards. */ #define MMC_OCR_VOLTAGE 0x3fffffffU /* Vdd Voltage mask */ #define MMC_OCR_LOW_VOLTAGE (1u << 7) /* Low Voltage Range -- tbd */ #define MMC_OCR_MIN_VOLTAGE_SHIFT 7 #define MMC_OCR_200_210 (1U << 8) /* Vdd voltage 2.00 ~ 2.10 */ #define MMC_OCR_210_220 (1U << 9) /* Vdd voltage 2.10 ~ 2.20 */ #define MMC_OCR_220_230 (1U << 10) /* Vdd voltage 2.20 ~ 2.30 */ #define MMC_OCR_230_240 (1U << 11) /* Vdd voltage 2.30 ~ 2.40 */ #define MMC_OCR_240_250 (1U << 12) /* Vdd voltage 2.40 ~ 2.50 */ #define MMC_OCR_250_260 (1U << 13) /* Vdd voltage 2.50 ~ 2.60 */ #define MMC_OCR_260_270 (1U << 14) /* Vdd voltage 2.60 ~ 2.70 */ #define MMC_OCR_270_280 (1U << 15) /* Vdd voltage 2.70 ~ 2.80 */ #define MMC_OCR_280_290 (1U << 16) /* Vdd voltage 2.80 ~ 2.90 */ #define MMC_OCR_290_300 (1U << 17) /* Vdd voltage 2.90 ~ 3.00 */ #define MMC_OCR_300_310 (1U << 18) /* Vdd voltage 3.00 ~ 3.10 */ #define MMC_OCR_310_320 (1U << 19) /* Vdd voltage 3.10 ~ 3.20 */ #define MMC_OCR_320_330 (1U << 20) /* Vdd voltage 3.20 ~ 3.30 */ #define MMC_OCR_330_340 (1U << 21) /* Vdd voltage 3.30 ~ 3.40 */ #define MMC_OCR_340_350 (1U << 22) /* Vdd voltage 3.40 ~ 3.50 */ #define MMC_OCR_350_360 (1U << 23) /* Vdd voltage 3.50 ~ 3.60 */ #define MMC_OCR_MAX_VOLTAGE_SHIFT 23 #define MMC_OCR_S18R (1U << 24) /* Switching to 1.8 V requested (SD) */ #define MMC_OCR_S18A MMC_OCR_S18R /* Switching to 1.8 V accepted (SD) */ #define MMC_OCR_XPC (1U << 28) /* SDXC Power Control */ #define MMC_OCR_ACCESS_MODE_BYTE (0U << 29) /* Access Mode Byte (MMC) */ #define MMC_OCR_ACCESS_MODE_SECT (1U << 29) /* Access Mode Sector (MMC) */ #define MMC_OCR_ACCESS_MODE_MASK (3U << 29) #define MMC_OCR_CCS (1u << 30) /* Card Capacity status (SD vs SDHC) */ #define MMC_OCR_CARD_BUSY (1U << 31) /* Card Power up status */ /* CSD -- decoded structure */ struct mmc_cid { uint32_t mid; char pnm[8]; uint32_t psn; uint16_t oid; uint16_t mdt_year; uint8_t mdt_month; uint8_t prv; uint8_t fwrev; }; struct mmc_csd { uint8_t csd_structure; uint8_t spec_vers; uint16_t ccc; uint16_t tacc; uint32_t nsac; uint32_t r2w_factor; uint32_t tran_speed; uint32_t read_bl_len; uint32_t write_bl_len; uint32_t vdd_r_curr_min; uint32_t vdd_r_curr_max; uint32_t vdd_w_curr_min; uint32_t vdd_w_curr_max; uint32_t wp_grp_size; uint32_t erase_sector; uint64_t capacity; unsigned int read_bl_partial:1, read_blk_misalign:1, write_bl_partial:1, write_blk_misalign:1, dsr_imp:1, erase_blk_en:1, wp_grp_enable:1; }; 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) }; struct mmc_sd_status { uint8_t bus_width; uint8_t secured_mode; uint16_t card_type; uint16_t prot_area; uint8_t speed_class; uint8_t perf_move; uint8_t au_size; uint16_t erase_size; uint8_t erase_timeout; uint8_t erase_offset; }; struct mmc_quirk { uint32_t mid; #define MMC_QUIRK_MID_ANY ((uint32_t)-1) uint16_t oid; #define MMC_QUIRK_OID_ANY ((uint16_t)-1) const char *pnm; uint32_t quirks; #define MMC_QUIRK_INAND_CMD38 0x0001 #define MMC_QUIRK_BROKEN_TRIM 0x0002 }; #define MMC_QUIRKS_FMT "\020" "\001INAND_CMD38" "\002BROKEN_TRIM" /* * 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 #define MMC_TUNING_MAX 64 /* Maximum tuning iterations */ #define MMC_TUNING_LEN 64 /* Size of tuning data */ #define MMC_TUNING_LEN_HS200 128 /* Size of tuning data in HS200 mode */ /* * 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 existence in passing here... */ #define MMC_SECTOR_SIZE 512 #endif /* DEV_MMCREG_H */ Index: stable/11/sys/dev/mmc/mmcsd.c =================================================================== --- stable/11/sys/dev/mmc/mmcsd.c (revision 338636) +++ stable/11/sys/dev/mmc/mmcsd.c (revision 338637) @@ -1,1490 +1,1576 @@ /*- * 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 * 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 #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include "mmcbus_if.h" #if __FreeBSD_version < 800002 #define kproc_create kthread_create #define kproc_exit kthread_exit #endif #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 disk_mtx; struct mtx ioctl_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; int ioctl; bool ro; char name[MMCSD_PART_NAMELEN]; }; struct mmcsd_softc { device_t dev; device_t mmcbus; struct mmcsd_part *part[MMC_PART_MAX]; enum mmc_card_mode mode; u_int max_data; /* Maximum data size [blocks] */ u_int erase_sector; /* Device native erase sector size [blocks] */ uint8_t high_cap; /* High Capacity device (block addressed) */ uint8_t part_curr; /* Partition currently switched to */ uint8_t ext_csd[MMC_EXTCSD_SIZE]; uint16_t rca; uint32_t flags; #define MMCSD_INAND_CMD38 0x0001 #define MMCSD_USE_TRIM 0x0002 +#define MMCSD_FLUSH_CACHE 0x0004 +#define MMCSD_DIRTY 0x0008 uint32_t cmd6_time; /* Generic switch timeout [us] */ 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[] = { "None", "Timeout", "Bad CRC", "Fifo", "Failed", "Invalid", "NO MEMORY" }; +static SYSCTL_NODE(_hw, OID_AUTO, mmcsd, CTLFLAG_RD, NULL, "mmcsd driver"); + +static int mmcsd_cache = 1; +SYSCTL_INT(_hw_mmcsd, OID_AUTO, cache, CTLFLAG_RDTUN, &mmcsd_cache, 0, + "Device R/W cache enabled if present"); + #define LOG_PPS 5 /* Log no more than 5 errors per second. */ /* bus entry points */ static int mmcsd_attach(device_t dev); static int mmcsd_detach(device_t dev); static int mmcsd_probe(device_t dev); +static int mmcsd_shutdown(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); 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, bool ro); static int mmcsd_bus_bit_width(device_t dev); static daddr_t mmcsd_delete(struct mmcsd_part *part, struct bio *bp); static const char *mmcsd_errmsg(int e); +static int mmcsd_flush_cache(struct mmcsd_softc *sc); static int mmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void *data, int fflag, struct thread *td); 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_DISK_LOCK(_part) mtx_lock(&(_part)->disk_mtx) #define MMCSD_DISK_UNLOCK(_part) mtx_unlock(&(_part)->disk_mtx) #define MMCSD_DISK_LOCK_INIT(_part) \ mtx_init(&(_part)->disk_mtx, (_part)->name, "mmcsd disk", MTX_DEF) #define MMCSD_DISK_LOCK_DESTROY(_part) mtx_destroy(&(_part)->disk_mtx); #define MMCSD_DISK_ASSERT_LOCKED(_part) \ mtx_assert(&(_part)->disk_mtx, MA_OWNED); #define MMCSD_DISK_ASSERT_UNLOCKED(_part) \ mtx_assert(&(_part)->disk_mtx, MA_NOTOWNED); #define MMCSD_IOCTL_LOCK(_part) mtx_lock(&(_part)->ioctl_mtx) #define MMCSD_IOCTL_UNLOCK(_part) mtx_unlock(&(_part)->ioctl_mtx) #define MMCSD_IOCTL_LOCK_INIT(_part) \ mtx_init(&(_part)->ioctl_mtx, (_part)->name, "mmcsd IOCTL", MTX_DEF) #define MMCSD_IOCTL_LOCK_DESTROY(_part) mtx_destroy(&(_part)->ioctl_mtx); #define MMCSD_IOCTL_ASSERT_LOCKED(_part) \ mtx_assert(&(_part)->ioctl_mtx, MA_OWNED); #define MMCSD_IOCLT_ASSERT_UNLOCKED(_part) \ mtx_assert(&(_part)->ioctl_mtx, MA_NOTOWNED); static int mmcsd_probe(device_t dev) { device_quiet(dev); device_set_desc(dev, "MMC/SD Memory Card"); return (0); } static int mmcsd_attach(device_t dev) { device_t mmcbus; struct mmcsd_softc *sc; const uint8_t *ext_csd; off_t erase_size, sector_size, size, wp_size; uintmax_t bytes; int err, i; uint32_t quirks; uint8_t rev; bool comp, ro; char unit[2]; sc = device_get_softc(dev); sc->dev = dev; sc->mmcbus = mmcbus = device_get_parent(dev); - sc->mode = mmcbr_get_mode(mmcbus); + sc->mode = mmc_get_card_type(dev); /* * Note that in principle with an SDHCI-like re-tuning implementation, * the maximum data size can change at runtime due to a device removal/ * insertion that results in switches to/from a transfer mode involving * re-tuning, iff there are multiple devices on a given bus. Until now * mmc(4) lacks support for rescanning already attached buses, however, * and sdhci(4) to date has no support for shared buses in the first * place either. */ sc->max_data = mmc_get_max_data(dev); sc->high_cap = mmc_get_high_cap(dev); sc->rca = mmc_get_rca(dev); sc->cmd6_time = mmc_get_cmd6_timeout(dev); quirks = mmc_get_quirks(dev); /* Only MMC >= 4.x devices support EXT_CSD. */ if (mmc_get_spec_vers(dev) >= 4) { MMCBUS_ACQUIRE_BUS(mmcbus, dev); err = mmc_send_ext_csd(mmcbus, dev, sc->ext_csd); MMCBUS_RELEASE_BUS(mmcbus, dev); if (err != MMC_ERR_NONE) { device_printf(dev, "Error reading EXT_CSD %s\n", mmcsd_errmsg(err)); return (ENXIO); } } ext_csd = sc->ext_csd; if ((quirks & MMC_QUIRK_INAND_CMD38) != 0) { if (mmc_get_spec_vers(dev) < 4) { device_printf(dev, "MMC_QUIRK_INAND_CMD38 set but no EXT_CSD\n"); return (EINVAL); } sc->flags |= MMCSD_INAND_CMD38; } /* * EXT_CSD_SEC_FEATURE_SUPPORT_GB_CL_EN denotes support for both * insecure and secure TRIM. */ if ((ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] & EXT_CSD_SEC_FEATURE_SUPPORT_GB_CL_EN) != 0 && (quirks & MMC_QUIRK_BROKEN_TRIM) == 0) { if (bootverbose) device_printf(dev, "taking advantage of TRIM\n"); sc->flags |= MMCSD_USE_TRIM; sc->erase_sector = 1; } else sc->erase_sector = mmc_get_erase_sector(dev); /* * 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. */ rev = ext_csd[EXT_CSD_REV]; /* + * With revision 1.5 (MMC v4.5, EXT_CSD_REV == 6) and later, take + * advantage of the device R/W cache if present and useage is not + * disabled. + */ + if (rev >= 6 && mmcsd_cache != 0) { + size = le32dec(&ext_csd[EXT_CSD_CACHE_SIZE]); + if (bootverbose) + device_printf(dev, "cache size %juKB\n", size); + if (size > 0) { + MMCBUS_ACQUIRE_BUS(mmcbus, dev); + err = mmc_switch(mmcbus, dev, sc->rca, + EXT_CSD_CMD_SET_NORMAL, EXT_CSD_CACHE_CTRL, + EXT_CSD_CACHE_CTRL_CACHE_EN, sc->cmd6_time, true); + MMCBUS_RELEASE_BUS(mmcbus, dev); + if (err != MMC_ERR_NONE) + device_printf(dev, "failed to enable cache\n"); + else + sc->flags |= MMCSD_FLUSH_CACHE; + } + } + + /* * 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)) * + sc->enh_base = + le32dec(&ext_csd[EXT_CSD_ENH_START_ADDR]) * (sc->high_cap != 0 ? MMC_SECTOR_SIZE : 1); } else if (bootverbose) device_printf(dev, "enhanced user data area spans entire device\n"); } /* * Add default partition. This may be the only one or the user * data area in case partitions are supported. */ 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, 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(mmcbus) & MMC_CAP_BOOT_NOACC) == 0) { mmcsd_add_part(sc, EXT_CSD_PART_CONFIG_ACC_BOOT0, MMCSD_FMT_BOOT, 0, 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, 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, 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, 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, bool ro) { struct make_dev_args args; device_t dev, mmcbus; 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; mmcbus = sc->mmcbus; 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)); MMCSD_IOCTL_LOCK_INIT(part); /* * For the RPMB partition, allow IOCTL access only. * NB: If ever attaching RPMB partitions to disk(9), the re-tuning * implementation and especially its pausing need to be revisited, * because then re-tuning requests may be issued by the IOCTL half * of this driver while re-tuning is already paused by the disk(9) * one and vice versa. */ 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_DISK_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 = sc->max_data * d->d_sectorsize; d->d_mediasize = media_size; d->d_stripesize = sc->erase_sector * d->d_sectorsize; d->d_unit = cnt; d->d_flags = DISKFLAG_CANDELETE; + if ((sc->flags & MMCSD_FLUSH_CACHE) != 0) + d->d_flags |= DISKFLAG_CANFLUSHCACHE; 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; 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(mmcbus); 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(mmcbus), speed / 1000000, (speed / 100000) % 10, mmcsd_bus_bit_width(dev), sc->max_data); } 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); } static int mmcsd_detach(device_t dev) { struct mmcsd_softc *sc = device_get_softc(dev); struct mmcsd_part *part; int i; for (i = 0; i < MMC_PART_MAX; i++) { part = sc->part[i]; if (part != NULL) { if (part->disk != NULL) { MMCSD_DISK_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->disk_mtx, 0, "mmcsd disk detach", 0); } MMCSD_DISK_UNLOCK(part); } MMCSD_IOCTL_LOCK(part); while (part->ioctl > 0) msleep(part, &part->ioctl_mtx, 0, "mmcsd IOCTL detach", 0); part->ioctl = -1; MMCSD_IOCTL_UNLOCK(part); } } if (sc->rpmb_dev != NULL) destroy_dev(sc->rpmb_dev); 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_DISK_LOCK_DESTROY(part); } MMCSD_IOCTL_LOCK_DESTROY(part); free(part, M_DEVBUF); } } + if (mmcsd_flush_cache(sc) != MMC_ERR_NONE) + device_printf(dev, "failed to flush cache\n"); return (0); } static int +mmcsd_shutdown(device_t dev) +{ + struct mmcsd_softc *sc = device_get_softc(dev); + + if (mmcsd_flush_cache(sc) != MMC_ERR_NONE) + device_printf(dev, "failed to flush cache\n"); + return (0); +} + +static int mmcsd_suspend(device_t dev) { struct mmcsd_softc *sc = device_get_softc(dev); struct mmcsd_part *part; int i; for (i = 0; i < MMC_PART_MAX; i++) { part = sc->part[i]; if (part != NULL) { if (part->disk != NULL) { MMCSD_DISK_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->disk_mtx, 0, "mmcsd disk suspension", 0); } MMCSD_DISK_UNLOCK(part); } MMCSD_IOCTL_LOCK(part); while (part->ioctl > 0) msleep(part, &part->ioctl_mtx, 0, "mmcsd IOCTL suspension", 0); part->ioctl = -1; MMCSD_IOCTL_UNLOCK(part); } } + if (mmcsd_flush_cache(sc) != MMC_ERR_NONE) + device_printf(dev, "failed to flush cache\n"); return (0); } static int mmcsd_resume(device_t dev) { struct mmcsd_softc *sc = device_get_softc(dev); struct mmcsd_part *part; int i; for (i = 0; i < MMC_PART_MAX; i++) { part = sc->part[i]; if (part != NULL) { if (part->disk != NULL) { MMCSD_DISK_LOCK(part); part->suspend = 0; if (part->running <= 0) { part->running = 1; MMCSD_DISK_UNLOCK(part); kproc_create(&mmcsd_task, part, &part->p, 0, 0, "%s%d: mmc/sd card", part->name, part->cnt); } else MMCSD_DISK_UNLOCK(part); } MMCSD_IOCTL_LOCK(part); part->ioctl = 0; MMCSD_IOCTL_UNLOCK(part); } } return (0); } static int -mmcsd_open(struct disk *dp __unused) +mmcsd_close(struct disk *dp) { + struct mmcsd_softc *sc; + if ((dp->d_flags & DISKFLAG_OPEN) != 0) { + sc = ((struct mmcsd_part *)dp->d_drv1)->sc; + if (mmcsd_flush_cache(sc) != MMC_ERR_NONE) + device_printf(sc->dev, "failed to flush cache\n"); + } return (0); } -static int -mmcsd_close(struct disk *dp __unused) -{ - - return (0); -} - static void mmcsd_strategy(struct bio *bp) { struct mmcsd_softc *sc; struct mmcsd_part *part; part = bp->bio_disk->d_drv1; sc = part->sc; MMCSD_DISK_LOCK(part); if (part->running > 0 || part->suspend > 0) { bioq_disksort(&part->bio_queue, bp); MMCSD_DISK_UNLOCK(part); wakeup(part); } else { MMCSD_DISK_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) { return (mmcsd_ioctl(dev->si_drv1, cmd, data, fflag, td)); } static int mmcsd_ioctl_disk(struct disk *disk, u_long cmd, void *data, int fflag, struct thread *td) { return (mmcsd_ioctl(disk->d_drv1, cmd, data, fflag, td)); } static int mmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void *data, int fflag, struct thread *td) { 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 = priv_check(td, PRIV_DRIVER); if (err != 0) return (err); err = 0; switch (cmd) { case MMC_IOC_CMD: mic = data; err = mmcsd_ioctl_cmd(part, mic, fflag); break; case MMC_IOC_MULTI_CMD: 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) { 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, mmcbus; 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); /* * We don't need to explicitly lock against the disk(9) half of this * driver as MMCBUS_ACQUIRE_BUS() will serialize us. However, it's * necessary to protect against races with detachment and suspension, * especially since it's required to switch away from RPMB partitions * again after an access (see mmcsd_switch_part()). */ MMCSD_IOCTL_LOCK(part); while (part->ioctl != 0) { if (part->ioctl < 0) { MMCSD_IOCTL_UNLOCK(part); return (ENXIO); } msleep(part, &part->ioctl_mtx, 0, "mmcsd IOCTL", 0); } part->ioctl = 1; MMCSD_IOCTL_UNLOCK(part); err = 0; dp = NULL; len = mic->blksz * mic->blocks; if (len > MMC_IOC_MAX_BYTES) { err = EOVERFLOW; goto out; } 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; } /* * No partition switching in userland; it's almost impossible * to recover from that, especially if things go wrong. */ if (cmd.opcode == MMC_SWITCH_FUNC && dp != NULL && (((uint8_t *)dp)[EXT_CSD_PART_CONFIG] & EXT_CSD_PART_CONFIG_ACC_MASK) != part->type) { err = EINVAL; goto out; } } dev = sc->dev; mmcbus = sc->mmcbus; MMCBUS_ACQUIRE_BUS(mmcbus, dev); err = mmcsd_switch_part(mmcbus, 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 switch_back; } + if (mic->write_flag != 0) + sc->flags |= MMCSD_DIRTY; if (mic->is_acmd != 0) (void)mmc_wait_for_app_cmd(mmcbus, dev, rca, &cmd, 0); else (void)mmc_wait_for_cmd(mmcbus, 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(mmcbus, 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); } /* * 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(mmcbus, dev, sc->ext_csd); if (err != MMC_ERR_NONE) goto release; } switch_back: if (part->type == EXT_CSD_PART_CONFIG_ACC_RPMB) { /* * If the request went to the RPMB partition, always switch * back to the default partition (see mmcsd_switch_part()). */ err = mmcsd_switch_part(mmcbus, dev, rca, EXT_CSD_PART_CONFIG_ACC_DEFAULT); if (err != MMC_ERR_NONE) goto release; } MMCBUS_RELEASE_BUS(mmcbus, 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(mmcbus, dev); err = EIO; out: MMCSD_IOCTL_LOCK(part); part->ioctl = 0; MMCSD_IOCTL_UNLOCK(part); wakeup(part); 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->mmcbus, 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->mode == mode_sd) return (MMC_ERR_NONE); /* * According to section "6.2.2 Command restrictions" of the eMMC * specification v5.1, CMD19/CMD21 aren't allowed to be used with * RPMB partitions. So we pause re-tuning along with triggering * it up-front to decrease the likelihood of re-tuning becoming * necessary while accessing an RPMB partition. Consequently, an * RPMB partition should immediately be switched away from again * after an access in order to allow for re-tuning to take place * anew. */ if (part == EXT_CSD_PART_CONFIG_ACC_RPMB) MMCBUS_RETUNE_PAUSE(sc->mmcbus, sc->dev, true); if (sc->part_curr == part) 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) { if (part == EXT_CSD_PART_CONFIG_ACC_RPMB) MMCBUS_RETUNE_UNPAUSE(sc->mmcbus, sc->dev); return (err); } sc->ext_csd[EXT_CSD_PART_CONFIG] = value; if (sc->part_curr == EXT_CSD_PART_CONFIG_ACC_RPMB) MMCBUS_RETUNE_UNPAUSE(sc->mmcbus, sc->dev); 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_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; struct mmcsd_softc *sc; device_t dev, mmcbus; u_int numblocks, sz; char *vaddr; sc = part->sc; dev = sc->dev; mmcbus = sc->mmcbus; block = bp->bio_pblkno; sz = part->disk->d_sectorsize; end = bp->bio_pblkno + (bp->bio_bcount / sz); while (block < end) { vaddr = bp->bio_data + (block - bp->bio_pblkno) * sz; numblocks = min(end - block, sc->max_data); memset(&req, 0, sizeof(req)); memset(&cmd, 0, sizeof(cmd)); memset(&stop, 0, sizeof(stop)); memset(&data, 0, sizeof(data)); cmd.mrq = &req; req.cmd = &cmd; cmd.data = &data; if (bp->bio_cmd == BIO_READ) { if (numblocks > 1) cmd.opcode = MMC_READ_MULTIPLE_BLOCK; else cmd.opcode = MMC_READ_SINGLE_BLOCK; } else { + sc->flags |= MMCSD_DIRTY; if (numblocks > 1) cmd.opcode = MMC_WRITE_MULTIPLE_BLOCK; else cmd.opcode = MMC_WRITE_BLOCK; } cmd.arg = block; if (sc->high_cap == 0) cmd.arg <<= 9; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; data.data = vaddr; data.mrq = &req; if (bp->bio_cmd == BIO_READ) data.flags = MMC_DATA_READ; else data.flags = MMC_DATA_WRITE; data.len = numblocks * sz; if (numblocks > 1) { data.flags |= MMC_DATA_MULTI; stop.opcode = MMC_STOP_TRANSMISSION; stop.arg = 0; stop.flags = MMC_RSP_R1B | MMC_CMD_AC; stop.mrq = &req; req.stop = &stop; } MMCBUS_WAIT_FOR_REQUEST(mmcbus, dev, &req); if (req.cmd->error != MMC_ERR_NONE) { 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)); break; } block += numblocks; } return (block); } static daddr_t mmcsd_delete(struct mmcsd_part *part, struct bio *bp) { daddr_t block, end, start, stop; struct mmc_command cmd; struct mmc_request req; struct mmcsd_softc *sc; device_t dev, mmcbus; u_int erase_sector, sz; int err; bool use_trim; sc = part->sc; dev = sc->dev; mmcbus = sc->mmcbus; block = bp->bio_pblkno; sz = part->disk->d_sectorsize; end = bp->bio_pblkno + (bp->bio_bcount / sz); use_trim = sc->flags & MMCSD_USE_TRIM; if (use_trim == true) { start = block; stop = end; } else { /* Coalesce with the remainder of the previous request. */ if (block > part->eblock && block <= part->eend) block = part->eblock; if (end >= part->eblock && end < part->eend) end = part->eend; /* Safely round to the erase sector boundaries. */ erase_sector = sc->erase_sector; start = block + erase_sector - 1; /* Round up. */ start -= start % erase_sector; stop = end; /* Round down. */ stop -= end % erase_sector; /* * We can't erase an area smaller than an erase sector, so * store it for later. */ if (start >= stop) { part->eblock = block; part->eend = end; return (end); } } if ((sc->flags & MMCSD_INAND_CMD38) != 0) { err = mmc_switch(mmcbus, dev, sc->rca, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_INAND_CMD38, use_trim == true ? EXT_CSD_INAND_CMD38_TRIM : EXT_CSD_INAND_CMD38_ERASE, sc->cmd6_time, true); if (err != MMC_ERR_NONE) { device_printf(dev, "Setting iNAND erase command failed %s\n", mmcsd_errmsg(err)); return (block); } } /* * Pause re-tuning so it won't interfere with the order of erase * commands. Note that these latter don't use the data lines, so * re-tuning shouldn't actually become necessary during erase. */ MMCBUS_RETUNE_PAUSE(mmcbus, dev, false); /* Set erase start position. */ memset(&req, 0, sizeof(req)); memset(&cmd, 0, sizeof(cmd)); cmd.mrq = &req; req.cmd = &cmd; - if (mmc_get_card_type(dev) == mode_sd) + if (sc->mode == mode_sd) cmd.opcode = SD_ERASE_WR_BLK_START; else cmd.opcode = MMC_ERASE_GROUP_START; cmd.arg = start; if (sc->high_cap == 0) cmd.arg <<= 9; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; MMCBUS_WAIT_FOR_REQUEST(mmcbus, dev, &req); if (req.cmd->error != MMC_ERR_NONE) { device_printf(dev, "Setting erase start position failed %s\n", mmcsd_errmsg(req.cmd->error)); block = bp->bio_pblkno; goto unpause; } /* Set erase stop position. */ memset(&req, 0, sizeof(req)); memset(&cmd, 0, sizeof(cmd)); req.cmd = &cmd; - if (mmc_get_card_type(dev) == mode_sd) + if (sc->mode == mode_sd) cmd.opcode = SD_ERASE_WR_BLK_END; else cmd.opcode = MMC_ERASE_GROUP_END; cmd.arg = stop; if (sc->high_cap == 0) cmd.arg <<= 9; cmd.arg--; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; MMCBUS_WAIT_FOR_REQUEST(mmcbus, dev, &req); if (req.cmd->error != MMC_ERR_NONE) { device_printf(dev, "Setting erase stop position failed %s\n", mmcsd_errmsg(req.cmd->error)); block = bp->bio_pblkno; goto unpause; } /* Erase range. */ memset(&req, 0, sizeof(req)); memset(&cmd, 0, sizeof(cmd)); req.cmd = &cmd; cmd.opcode = MMC_ERASE; cmd.arg = use_trim == true ? MMC_ERASE_TRIM : MMC_ERASE_ERASE; cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; MMCBUS_WAIT_FOR_REQUEST(mmcbus, dev, &req); if (req.cmd->error != MMC_ERR_NONE) { device_printf(dev, "Issuing erase command failed %s\n", mmcsd_errmsg(req.cmd->error)); block = bp->bio_pblkno; goto unpause; } if (use_trim == false) { /* Store one of the remaining parts for the next call. */ if (bp->bio_pblkno >= part->eblock || block == start) { part->eblock = stop; /* Predict next forward. */ part->eend = end; } else { part->eblock = block; /* Predict next backward. */ part->eend = start; } } block = end; unpause: MMCBUS_RETUNE_UNPAUSE(mmcbus, dev); return (block); } static int mmcsd_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length) { struct bio bp; daddr_t block, end; struct disk *disk; struct mmcsd_softc *sc; struct mmcsd_part *part; device_t dev, mmcbus; 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; + + /* length zero is special and really means flush buffers to media */ + if (length == 0) { + err = mmcsd_flush_cache(sc); + if (err != MMC_ERR_NONE) + return (EIO); + return (0); + } + dev = sc->dev; mmcbus = sc->mmcbus; g_reset_bio(&bp); 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 / disk->d_sectorsize; MMCBUS_ACQUIRE_BUS(mmcbus, dev); err = mmcsd_switch_part(mmcbus, 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(mmcbus, dev); return (EIO); } block = mmcsd_rw(part, &bp); MMCBUS_RELEASE_BUS(mmcbus, dev); return ((end < block) ? EIO : 0); } static void mmcsd_task(void *arg) { daddr_t block, end; struct mmcsd_part *part; struct mmcsd_softc *sc; struct bio *bp; device_t dev, mmcbus; int err, sz; part = arg; sc = part->sc; dev = sc->dev; mmcbus = sc->mmcbus; while (1) { MMCSD_DISK_LOCK(part); do { if (part->running == 0) goto out; bp = bioq_takefirst(&part->bio_queue); if (bp == NULL) msleep(part, &part->disk_mtx, PRIBIO, "mmcsd disk jobqueue", 0); } while (bp == NULL); MMCSD_DISK_UNLOCK(part); + if (__predict_false(bp->bio_cmd == BIO_FLUSH)) { + if (mmcsd_flush_cache(sc) != MMC_ERR_NONE) { + bp->bio_error = EIO; + bp->bio_flags |= BIO_ERROR; + } + biodone(bp); + continue; + } if (bp->bio_cmd != BIO_READ && part->ro) { bp->bio_error = EROFS; bp->bio_resid = bp->bio_bcount; bp->bio_flags |= BIO_ERROR; biodone(bp); continue; } MMCBUS_ACQUIRE_BUS(mmcbus, dev); sz = part->disk->d_sectorsize; block = bp->bio_pblkno; end = bp->bio_pblkno + (bp->bio_bcount / sz); err = mmcsd_switch_part(mmcbus, 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 < 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(part, bp); } release: MMCBUS_RELEASE_BUS(mmcbus, dev); if (block < end) { bp->bio_error = EIO; bp->bio_resid = (end - block) * sz; bp->bio_flags |= BIO_ERROR; } else { bp->bio_resid = 0; } biodone(bp); } out: /* tell parent we're done */ part->running = -1; MMCSD_DISK_UNLOCK(part); wakeup(part); kproc_exit(0); } static int mmcsd_bus_bit_width(device_t dev) { if (mmc_get_bus_width(dev) == bus_width_1) return (1); if (mmc_get_bus_width(dev) == bus_width_4) return (4); return (8); } +static int +mmcsd_flush_cache(struct mmcsd_softc *sc) +{ + device_t dev, mmcbus; + int err; + + if ((sc->flags & MMCSD_FLUSH_CACHE) == 0) + return (MMC_ERR_NONE); + + dev = sc->dev; + mmcbus = sc->mmcbus; + MMCBUS_ACQUIRE_BUS(mmcbus, dev); + if ((sc->flags & MMCSD_DIRTY) == 0) { + MMCBUS_RELEASE_BUS(mmcbus, dev); + return (MMC_ERR_NONE); + } + err = mmc_switch(mmcbus, dev, sc->rca, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_FLUSH_CACHE, EXT_CSD_FLUSH_CACHE_FLUSH, 60 * 1000, true); + if (err == MMC_ERR_NONE) + sc->flags &= ~MMCSD_DIRTY; + MMCBUS_RELEASE_BUS(mmcbus, dev); + return (err); +} + static device_method_t mmcsd_methods[] = { DEVMETHOD(device_probe, mmcsd_probe), DEVMETHOD(device_attach, mmcsd_attach), DEVMETHOD(device_detach, mmcsd_detach), + DEVMETHOD(device_shutdown, mmcsd_shutdown), DEVMETHOD(device_suspend, mmcsd_suspend), DEVMETHOD(device_resume, mmcsd_resume), DEVMETHOD_END }; static driver_t mmcsd_driver = { "mmcsd", mmcsd_methods, sizeof(struct mmcsd_softc), }; static devclass_t mmcsd_devclass; 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); Index: stable/11 =================================================================== --- stable/11 (revision 338636) +++ stable/11 (revision 338637) Property changes on: stable/11 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r333647,338275,338280,338513