Index: head/sys/dev/mmc/bridge.h =================================================================== --- head/sys/dev/mmc/bridge.h (revision 170001) +++ head/sys/dev/mmc/bridge.h (revision 170002) @@ -1,105 +1,132 @@ /*- * Copyright (c) 2006 M. Warner Losh. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * Portions of this software may have been developed with reference to + * the SD Simplified Specification. The following disclaimer may apply: + * + * The following conditions apply to the release of the simplified + * specification ("Simplified Specification") by the SD Card Association and + * the SD Group. The Simplified Specification is a subset of the complete SD + * Specification which is owned by the SD Card Association and the SD + * Group. This Simplified Specification is provided on a non-confidential + * basis subject to the disclaimers below. Any implementation of the + * Simplified Specification may require a license from the SD Card + * Association, SD Group, SD-3C LLC or other third parties. + * + * Disclaimers: + * + * The information contained in the Simplified Specification is presented only + * as a standard specification for SD Cards and SD Host/Ancillary products and + * is provided "AS-IS" without any representations or warranties of any + * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD + * Card Association for any damages, any infringements of patents or other + * right of the SD Group, SD-3C LLC, the SD Card Association or any third + * parties, which may result from its use. No license is granted by + * implication, estoppel or otherwise under any patent or other rights of the + * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing + * herein shall be construed as an obligation by the SD Group, the SD-3C LLC + * or the SD Card Association to disclose or distribute any technical + * information, know-how or other confidential information to any third party. + * * $FreeBSD$ */ #ifndef DEV_MMC_BRIDGE_H #define DEV_MMC_BRIDGE_H /* * This file defines interfaces for the mmc bridge. The names chosen * are similar to or the same as the names used in Linux to allow for * easy porting of what Linux calls mmc host drivers. I use the * FreeBSD terminology of bridge and bus for consistancy with other * drivers in the system. This file corresponds roughly to the Linux * linux/mmc/host.h file. * * A mmc bridge is a chipset that can have one or more mmc and/or sd * cards attached to it. mmc cards are attached on a bus topology, * while sd and sdio cards are attached using a star topology (meaning * in practice each sd card has its own, independent slot). Each * mmcbr is assumed to be derived from the mmcbr. This is done to * allow for easier addition of bridges (as each bridge does not need * to be added to the mmcbus file). * * Attached to the mmc bridge is an mmcbus. The mmcbus is described * in dev/mmc/bus.h. */ /* * mmc_ios is a structure that is used to store the state of the mmc/sd * bus configuration. This include the bus' clock speed, its voltage, * the bus mode for command output, the SPI chip select, some power * states and the bus width. */ enum mmc_vdd { vdd_150 = 0, vdd_155, vdd_160, vdd_165, vdd_170, vdd_180, vdd_190, vdd_200, vdd_210, vdd_220, vdd_230, vdd_240, vdd_250, vdd_260, vdd_270, vdd_280, vdd_290, vdd_300, vdd_310, vdd_320, vdd_330, vdd_340, vdd_350, vdd_360 }; enum mmc_power_mode { power_off = 0, power_up, power_on }; enum mmc_bus_mode { opendrain = 1, pushpull }; enum mmc_chip_select { cs_dontcare = 0, cs_high, cs_low }; enum mmc_bus_width { bus_width_1 = 0, bus_width_4 = 2, bus_width_8 = 3 }; struct mmc_ios { uint32_t clock; /* Speed of the clock in Hz to move data */ enum mmc_vdd vdd; /* Voltage to apply to the power pins/ */ enum mmc_bus_mode bus_mode; enum mmc_chip_select chip_select; enum mmc_bus_width bus_width; enum mmc_power_mode power_mode; }; enum mmc_card_mode { mode_mmc, mode_sd }; struct mmc_host { int f_min; int f_max; uint32_t host_ocr; uint32_t ocr; uint32_t caps; #define MMC_CAP_4_BIT_DATA (1 << 0) /* Can do 4-bit data transfers */ #define MMC_CAP_8_BIT_DATA (1 << 1) /* Can do 8-bit data transfers */ enum mmc_card_mode mode; struct mmc_ios ios; /* Current state of the host */ }; #endif /* DEV_MMC_BRIDGE_H */ Index: head/sys/dev/mmc/mmc.c =================================================================== --- head/sys/dev/mmc/mmc.c (revision 170001) +++ head/sys/dev/mmc/mmc.c (revision 170002) @@ -1,766 +1,793 @@ /*- * Copyright (c) 2006 Bernd Walter. All rights reserved. * Copyright (c) 2006 M. Warner Losh. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Portions of this software may have been developed with reference to + * the SD Simplified Specification. The following disclaimer may apply: + * + * The following conditions apply to the release of the simplified + * specification ("Simplified Specification") by the SD Card Association and + * the SD Group. The Simplified Specification is a subset of the complete SD + * Specification which is owned by the SD Card Association and the SD + * Group. This Simplified Specification is provided on a non-confidential + * basis subject to the disclaimers below. Any implementation of the + * Simplified Specification may require a license from the SD Card + * Association, SD Group, SD-3C LLC or other third parties. + * + * Disclaimers: + * + * The information contained in the Simplified Specification is presented only + * as a standard specification for SD Cards and SD Host/Ancillary products and + * is provided "AS-IS" without any representations or warranties of any + * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD + * Card Association for any damages, any infringements of patents or other + * right of the SD Group, SD-3C LLC, the SD Card Association or any third + * parties, which may result from its use. No license is granted by + * implication, estoppel or otherwise under any patent or other rights of the + * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing + * herein shall be construed as an obligation by the SD Group, the SD-3C LLC + * or the SD Card Association to disclose or distribute any technical + * information, know-how or other confidential information to any third party. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include "mmcbr_if.h" #include "mmcbus_if.h" struct mmc_softc { device_t dev; struct mtx sc_mtx; struct intr_config_hook config_intrhook; device_t owner; uint32_t last_rca; }; /* * 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 */ uint16_t rca; enum mmc_card_mode mode; struct mmc_cid cid; /* cid decoded */ struct mmc_csd csd; /* csd decoded */ }; #define CMD_RETRIES 3 /* bus entry points */ static int mmc_probe(device_t dev); static int mmc_attach(device_t dev); static int mmc_detach(device_t dev); #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 void mmc_delayed_attach(void *); static int mmc_wait_for_cmd(struct mmc_softc *sc, struct mmc_command *cmd, int retries); static int mmc_wait_for_command(struct mmc_softc *sc, uint32_t opcode, uint32_t arg, uint32_t flags, uint32_t *resp, int retries); static 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); device_t *kids; int i, nkid; /* kill children [ph33r]. -sorbo */ if (device_get_children(sc->dev, &kids, &nkid) != 0) return 0; for (i = 0; i < nkid; i++) { device_t kid = kids[i]; void *ivar = device_get_ivars(kid); device_detach(kid); device_delete_child(sc->dev, kid); free(ivar, M_DEVBUF); } free(kids, M_TEMP); MMC_LOCK_DESTROY(sc); return 0; } static int mmc_acquire_bus(device_t busdev, device_t dev) { struct mmc_softc *sc; int err; int rca; err = MMCBR_ACQUIRE_HOST(device_get_parent(busdev), dev); if (err) return (err); sc = device_get_softc(busdev); MMC_LOCK(sc); if (sc->owner) panic("mmc: host bridge didn't seralize 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. rca = mmc_get_rca(dev); if (sc->last_rca != rca) { mmc_wait_for_command(sc, MMC_SELECT_CARD, rca << 16, MMC_RSP_R1 | MMC_CMD_AC, NULL, CMD_RETRIES); sc->last_rca = rca; } // XXX should set bus width here? } else { // If there's a card selected, stand down. if (sc->last_rca != 0) { mmc_wait_for_command(sc, MMC_SELECT_CARD, 0, MMC_RSP_R1 | MMC_CMD_AC, NULL, CMD_RETRIES); sc->last_rca = 0; } // XXX should set bus width here? } 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), dev); if (err) return (err); MMC_LOCK(sc); sc->owner = NULL; MMC_UNLOCK(sc); return (0); } static void mmc_rescan_cards(struct mmc_softc *sc) { /* XXX: Look at the children and see if they respond to status */ } static uint32_t mmc_select_vdd(struct mmc_softc *sc, uint32_t ocr) { // XXX return ocr; } static int mmc_highest_voltage(uint32_t ocr) { int i; for (i = 30; i >= 0; i--) if (ocr & (1 << i)) return i; return (-1); } static void mmc_wakeup(struct mmc_request *req) { struct mmc_softc *sc; // printf("Wakeup for req %p done_data %p\n", req, req->done_data); sc = (struct mmc_softc *)req->done_data; MMC_LOCK(sc); req->flags |= MMC_REQ_DONE; wakeup(req); MMC_UNLOCK(sc); } static int mmc_wait_for_req(struct mmc_softc *sc, struct mmc_request *req) { int err; req->done = mmc_wakeup; req->done_data = sc; // printf("Submitting request %p sc %p\n", req, sc); MMCBR_REQUEST(device_get_parent(sc->dev), sc->dev, req); MMC_LOCK(sc); do { err = msleep(req, &sc->sc_mtx, PZERO | PCATCH, "mmcreq", hz / 10); } while (!(req->flags & MMC_REQ_DONE) && err == EAGAIN); // printf("Request %p done with error %d\n", req, err); MMC_UNLOCK(sc); return (err); } static int mmc_wait_for_request(device_t brdev, device_t reqdev, struct mmc_request *req) { struct mmc_softc *sc = device_get_softc(brdev); return mmc_wait_for_req(sc, req); } static int mmc_wait_for_cmd(struct mmc_softc *sc, struct mmc_command *cmd, int retries) { struct mmc_request mreq; memset(&mreq, 0, sizeof(mreq)); memset(cmd->resp, 0, sizeof(cmd->resp)); cmd->retries = retries; cmd->data = NULL; mreq.cmd = cmd; // printf("CMD: %x ARG %x\n", cmd->opcode, cmd->arg); mmc_wait_for_req(sc, &mreq); return (cmd->error); } static int mmc_wait_for_app_cmd(struct mmc_softc *sc, uint32_t rca, struct mmc_command *cmd, int retries) { struct mmc_command appcmd; int err = MMC_ERR_NONE, i; for (i = 0; i <= retries; i++) { appcmd.opcode = MMC_APP_CMD; appcmd.arg = rca << 16; appcmd.flags = MMC_RSP_R1 | MMC_CMD_AC; mmc_wait_for_cmd(sc, &appcmd, 0); err = appcmd.error; if (err != MMC_ERR_NONE) continue; if (!(appcmd.resp[0] & R1_APP_CMD)) return MMC_ERR_FAILED; mmc_wait_for_cmd(sc, cmd, 0); err = cmd->error; if (err == MMC_ERR_NONE) break; } return (err); } static int mmc_wait_for_command(struct mmc_softc *sc, uint32_t opcode, uint32_t arg, uint32_t flags, uint32_t *resp, int retries) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = opcode; cmd.arg = arg; cmd.flags = flags; err = mmc_wait_for_cmd(sc, &cmd, retries); if (err) return (err); if (cmd.error) return (cmd.error); 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; mmc_wait_for_cmd(sc, &cmd, 0); 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; for (i = 0; i < 10; i++) { err = mmc_wait_for_app_cmd(sc, 0, &cmd, CMD_RETRIES); if (err != MMC_ERR_NONE) break; if ((cmd.resp[0] & MMC_OCR_CARD_BUSY) || ocr == 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; for (i = 0; i < 100; i++) { err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); if (err != MMC_ERR_NONE) break; if ((cmd.resp[0] & MMC_OCR_CARD_BUSY) || ocr == 0) break; err = MMC_ERR_TIMEOUT; mmc_ms_delay(10); } if (rocr && err == MMC_ERR_NONE) *rocr = cmd.resp[0]; return err; } static void mmc_power_up(struct mmc_softc *sc) { device_t dev; 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); mmc_ms_delay(1); mmcbr_set_clock(dev, mmcbr_get_f_min(sc->dev)); mmcbr_set_power_mode(dev, power_on); mmcbr_update_ios(dev); mmc_ms_delay(2); } // I wonder if the following is endian safe. static uint32_t mmc_get_bits(uint32_t *bits, int start, int size) { const int i = 3 - (start / 32); const int shift = start & 31; uint32_t retval = bits[i] >> shift; if (size + shift > 32) retval |= bits[i - 1] << (32 - shift); return retval & ((1 << size) - 1); } static void mmc_decode_cid(int is_sd, uint32_t *raw_cid, struct mmc_cid *cid) { int i; memset(cid, 0, sizeof(*cid)); if (is_sd) { /* There's no version info, so we take it on faith */ cid->mid = mmc_get_bits(raw_cid, 120, 8); cid->oid = mmc_get_bits(raw_cid, 104, 16); for (i = 0; i < 5; i++) cid->pnm[i] = mmc_get_bits(raw_cid, 96 - i * 8, 8); cid->prv = mmc_get_bits(raw_cid, 56, 8); cid->psn = mmc_get_bits(raw_cid, 24, 32); cid->mdt_year = mmc_get_bits(raw_cid, 12, 8) + 2001; cid->mdt_month = mmc_get_bits(raw_cid, 8, 4); } else { // XXX write me panic("write mmc cid decoder"); } } static const int exp[8] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 }; static const int mant[16] = { 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 void mmc_decode_csd(int is_sd, uint32_t *raw_csd, struct mmc_csd *csd) { int v; int m; int e; memset(csd, 0, sizeof(*csd)); if (is_sd) { csd->csd_structure = v = mmc_get_bits(raw_csd, 126, 2); if (v == 0) { m = mmc_get_bits(raw_csd, 115, 4); e = mmc_get_bits(raw_csd, 112, 3); csd->tacc = exp[e] * mant[m] + 9 / 10; csd->nsac = mmc_get_bits(raw_csd, 104, 8) * 100; m = mmc_get_bits(raw_csd, 99, 4); e = mmc_get_bits(raw_csd, 96, 3); csd->tran_speed = exp[e] * 10000 * mant[m]; csd->ccc = mmc_get_bits(raw_csd, 84, 12); csd->read_bl_len = 1 << mmc_get_bits(raw_csd, 80, 4); csd->read_bl_partial = mmc_get_bits(raw_csd, 79, 1); csd->write_blk_misalign = mmc_get_bits(raw_csd, 78, 1); csd->read_blk_misalign = mmc_get_bits(raw_csd, 77, 1); csd->dsr_imp = mmc_get_bits(raw_csd, 76, 1); csd->vdd_r_curr_min = cur_min[mmc_get_bits(raw_csd, 59, 3)]; csd->vdd_r_curr_max = cur_max[mmc_get_bits(raw_csd, 56, 3)]; csd->vdd_w_curr_min = cur_min[mmc_get_bits(raw_csd, 53, 3)]; csd->vdd_w_curr_max = cur_max[mmc_get_bits(raw_csd, 50, 3)]; m = mmc_get_bits(raw_csd, 62, 12); e = mmc_get_bits(raw_csd, 47, 3); csd->capacity = ((1 + m) << (e + 2)) * csd->read_bl_len; csd->erase_blk_en = mmc_get_bits(raw_csd, 46, 1); csd->sector_size = mmc_get_bits(raw_csd, 39, 7); csd->wp_grp_size = mmc_get_bits(raw_csd, 32, 7); csd->wp_grp_enable = mmc_get_bits(raw_csd, 31, 1); csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 26, 3); csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 22, 4); csd->write_bl_partial = mmc_get_bits(raw_csd, 21, 1); } else if (v == 1) { panic("Write SDHC CSD parser"); } else panic("unknown SD CSD version"); } else { panic("Write a MMC CSD parser"); } } static int mmc_all_send_cid(struct mmc_softc *sc, uint32_t *rawcid) { struct mmc_command cmd; int err; cmd.opcode = MMC_ALL_SEND_CID; cmd.arg = 0; cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR; err = mmc_wait_for_cmd(sc, &cmd, 0); memcpy(rawcid, cmd.resp, 4 * sizeof(uint32_t)); return (err); } static int mmc_send_csd(struct mmc_softc *sc, uint16_t rca, uint32_t *rawcid) { struct mmc_command cmd; int err; cmd.opcode = MMC_SEND_CSD; cmd.arg = rca << 16; cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR; err = mmc_wait_for_cmd(sc, &cmd, 0); memcpy(rawcid, cmd.resp, 4 * sizeof(uint32_t)); return (err); } static int mmc_send_relative_addr(struct mmc_softc *sc, uint32_t *resp) { struct mmc_command cmd; int err; cmd.opcode = SD_SEND_RELATIVE_ADDR; cmd.arg = 0; cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR; err = mmc_wait_for_cmd(sc, &cmd, 0); *resp = cmd.resp[0]; return (err); } static void mmc_discover_cards(struct mmc_softc *sc) { struct mmc_ivars *ivar; int err; uint32_t resp; device_t child; while (1) { ivar = malloc(sizeof(struct mmc_ivars), M_DEVBUF, M_WAITOK); if (!ivar) return; err = mmc_all_send_cid(sc, ivar->raw_cid); if (err == MMC_ERR_TIMEOUT) break; if (err != MMC_ERR_NONE) { printf("Error reading CID %d\n", err); break; } if (mmcbr_get_mode(sc->dev) == mode_sd) { ivar->mode = mode_sd; mmc_decode_cid(1, ivar->raw_cid, &ivar->cid); mmc_send_relative_addr(sc, &resp); ivar->rca = resp >> 16; // RO check mmc_send_csd(sc, ivar->rca, ivar->raw_csd); mmc_decode_csd(1, ivar->raw_csd, &ivar->csd); printf("SD CARD: %lld bytes\n", (long long) ivar->csd.capacity); child = device_add_child(sc->dev, NULL, -1); device_set_ivars(child, ivar); return; } panic("Write MMC card code here"); } free(ivar, M_DEVBUF); } static void mmc_go_discovery(struct mmc_softc *sc) { uint32_t ocr; device_t dev; dev = sc->dev; if (mmcbr_get_power_mode(dev) != power_on) { // First, try SD modes mmcbr_set_mode(dev, mode_sd); mmc_power_up(sc); mmcbr_set_bus_mode(dev, pushpull); mmc_idle_cards(sc); if (mmc_send_app_op_cond(sc, 0, &ocr) != MMC_ERR_NONE) { // Failed, try MMC mmcbr_set_mode(dev, mode_mmc); if (mmc_send_op_cond(sc, 0, &ocr) != MMC_ERR_NONE) return; // Failed both, punt! XXX power down? } 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, mmcbr_get_f_min(dev)); 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 (mmcbr_get_ocr(dev) == 0) return; /* * Reselect the cards after we've idled them above. */ if (mmcbr_get_mode(dev) == mode_sd) mmc_send_app_op_cond(sc, mmcbr_get_ocr(dev), NULL); else mmc_send_op_cond(sc, mmcbr_get_ocr(dev), NULL); mmc_discover_cards(sc); mmcbr_set_bus_mode(dev, pushpull); mmcbr_update_ios(dev); bus_generic_attach(dev); // mmc_update_children_sysctl(dev); } static int mmc_calculate_clock(struct mmc_softc *sc) { int max_dtr = 0; int nkid, i, f_min, f_max; device_t *kids; f_min = mmcbr_get_f_min(sc->dev); f_max = mmcbr_get_f_max(sc->dev); max_dtr = f_max; if (device_get_children(sc->dev, &kids, &nkid) != 0) panic("can't get children"); for (i = 0; i < nkid; i++) if (mmc_get_tran_speed(kids[i]) < max_dtr) max_dtr = mmc_get_tran_speed(kids[i]); free(kids, M_TEMP); device_printf(sc->dev, "setting transfer rate to %d.%03dMHz\n", max_dtr / 1000000, (max_dtr / 1000) % 1000); return max_dtr; } static void mmc_scan(struct mmc_softc *sc) { device_t dev; dev = sc->dev; mmc_acquire_bus(dev, dev); if (mmcbr_get_power_mode(dev) == power_on) mmc_rescan_cards(sc); mmc_go_discovery(sc); mmcbr_set_clock(dev, mmc_calculate_clock(sc)); mmcbr_update_ios(dev); mmc_release_bus(dev, dev); // XXX probe/attach/detach children? } static int mmc_read_ivar(device_t bus, device_t child, int which, u_char *result) { struct mmc_ivars *ivar = device_get_ivars(child); switch (which) { default: return (EINVAL); case MMC_IVAR_DSR_IMP: *(int *)result = ivar->csd.dsr_imp; break; case MMC_IVAR_MEDIA_SIZE: *(int *)result = ivar->csd.capacity; break; case MMC_IVAR_RCA: *(int *)result = ivar->rca; break; case MMC_IVAR_SECTOR_SIZE: *(int *)result = 512; break; case MMC_IVAR_TRAN_SPEED: *(int *)result = ivar->csd.tran_speed; break; } return (0); } static int mmc_write_ivar(device_t bus, device_t child, int which, uintptr_t value) { // None are writable ATM switch (which) { default: return (EINVAL); } return (0); } static void mmc_delayed_attach(void *xsc) { struct mmc_softc *sc = xsc; mmc_scan(sc); config_intrhook_disestablish(&sc->config_intrhook); } static device_method_t mmc_methods[] = { /* device_if */ DEVMETHOD(device_probe, mmc_probe), DEVMETHOD(device_attach, mmc_attach), DEVMETHOD(device_detach, mmc_detach), /* Bus interface */ DEVMETHOD(bus_read_ivar, mmc_read_ivar), DEVMETHOD(bus_write_ivar, mmc_write_ivar), /* MMC Bus interface */ DEVMETHOD(mmcbus_wait_for_request, mmc_wait_for_request), DEVMETHOD(mmcbus_acquire_bus, mmc_acquire_bus), DEVMETHOD(mmcbus_release_bus, mmc_release_bus), {0, 0}, }; static driver_t mmc_driver = { "mmc", mmc_methods, sizeof(struct mmc_softc), }; static devclass_t mmc_devclass; DRIVER_MODULE(mmc, at91_mci, mmc_driver, mmc_devclass, 0, 0); DRIVER_MODULE(mmc, sdh, mmc_driver, mmc_devclass, 0, 0); Index: head/sys/dev/mmc/mmcbr_if.m =================================================================== --- head/sys/dev/mmc/mmcbr_if.m (revision 170001) +++ head/sys/dev/mmc/mmcbr_if.m (revision 170002) @@ -1,84 +1,111 @@ #- # Copyright (c) 2006 M. Warner Losh # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # +# 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$ # #include #include #include # # This is the interface that a mmc bridge chip gives to the mmc bus # that attaches to the mmc bridge. # INTERFACE mmcbr; # # Called by the mmcbus to setup the IO pins correctly, the voltage to use # for the card, the type of selects, power modes and bus width. # METHOD int update_ios { device_t brdev; device_t reqdev; }; # # Called by the mmcbus or its children to schedule a mmc request. These # requests are queued. Time passes. The bridge then gets notification # of the status of request, who then notifies the requesting device via # the xfer_done mmcbus method. # METHOD int request { device_t brdev; device_t reqdev; struct mmc_request *req; }; # # Called by mmcbus to get the read only status bits. # METHOD int get_ro { device_t brdev; device_t reqdev; }; # # Claim the current bridge, blocking the current thread until the host # is no longer busy. # METHOD int acquire_host { device_t brdev; device_t reqdev; } # # Release the current bridge. # METHOD int release_host { device_t brdev; device_t reqdev; } Index: head/sys/dev/mmc/mmcbrvar.h =================================================================== --- head/sys/dev/mmc/mmcbrvar.h (revision 170001) +++ head/sys/dev/mmc/mmcbrvar.h (revision 170002) @@ -1,73 +1,100 @@ /*- * Copyright (c) 2006 Bernd Walter. All rights reserved. * Copyright (c) 2006 M. Warner Losh. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * Portions of this software may have been developed with reference to + * the SD Simplified Specification. The following disclaimer may apply: + * + * The following conditions apply to the release of the simplified + * specification ("Simplified Specification") by the SD Card Association and + * the SD Group. The Simplified Specification is a subset of the complete SD + * Specification which is owned by the SD Card Association and the SD + * Group. This Simplified Specification is provided on a non-confidential + * basis subject to the disclaimers below. Any implementation of the + * Simplified Specification may require a license from the SD Card + * Association, SD Group, SD-3C LLC or other third parties. + * + * Disclaimers: + * + * The information contained in the Simplified Specification is presented only + * as a standard specification for SD Cards and SD Host/Ancillary products and + * is provided "AS-IS" without any representations or warranties of any + * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD + * Card Association for any damages, any infringements of patents or other + * right of the SD Group, SD-3C LLC, the SD Card Association or any third + * parties, which may result from its use. No license is granted by + * implication, estoppel or otherwise under any patent or other rights of the + * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing + * herein shall be construed as an obligation by the SD Group, the SD-3C LLC + * or the SD Card Association to disclose or distribute any technical + * information, know-how or other confidential information to any third party. + * * "$FreeBSD$" */ #ifndef DEV_MMC_MMCBRVAR_H #define DEV_MMC_MMCBRVAR_H #include #include "mmcbr_if.h" enum mmcbr_device_ivars { MMCBR_IVAR_BUS_MODE, MMCBR_IVAR_BUS_WIDTH, MMCBR_IVAR_CHIP_SELECT, MMCBR_IVAR_CLOCK, MMCBR_IVAR_F_MIN, MMCBR_IVAR_F_MAX, MMCBR_IVAR_HOST_OCR, MMCBR_IVAR_MODE, MMCBR_IVAR_OCR, MMCBR_IVAR_POWER_MODE, MMCBR_IVAR_VDD, // MMCBR_IVAR_, }; /* * Simplified accessors for pci devices */ #define MMCBR_ACCESSOR(var, ivar, type) \ __BUS_ACCESSOR(mmcbr, var, MMCBR, ivar, type) MMCBR_ACCESSOR(bus_mode, BUS_MODE, int) MMCBR_ACCESSOR(bus_width, BUS_WIDTH, int) MMCBR_ACCESSOR(chip_select, CHIP_SELECT, int) MMCBR_ACCESSOR(clock, CLOCK, int) MMCBR_ACCESSOR(f_max, F_MAX, int) MMCBR_ACCESSOR(f_min, F_MIN, int) MMCBR_ACCESSOR(host_ocr, HOST_OCR, int) MMCBR_ACCESSOR(mode, MODE, int) MMCBR_ACCESSOR(ocr, OCR, int) MMCBR_ACCESSOR(power_mode, POWER_MODE, int) MMCBR_ACCESSOR(vdd, VDD, int) static int __inline mmcbr_update_ios(device_t dev) { return (MMCBR_UPDATE_IOS(device_get_parent(dev), dev)); } #endif /* DEV_MMC_MMCBRVAR_H */ Index: head/sys/dev/mmc/mmcbus_if.m =================================================================== --- head/sys/dev/mmc/mmcbus_if.m (revision 170001) +++ head/sys/dev/mmc/mmcbus_if.m (revision 170002) @@ -1,63 +1,90 @@ #- # Copyright (c) 2006 M. Warner Losh # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # +# 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$ # #include #include # # This is the set of callbacks that mmc bridges call into the bus, or # that mmc/sd card drivers call to make requests. # INTERFACE mmcbus; # # Queue and wait for a request. # METHOD int wait_for_request { device_t brdev; device_t reqdev; struct mmc_request *req; }; # # Claim the current bridge, blocking the current thread until the host # is no longer busy. # METHOD int acquire_bus { device_t brdev; device_t reqdev; } # # Release the current bridge. # METHOD int release_bus { device_t brdev; device_t reqdev; } Index: head/sys/dev/mmc/mmcreg.h =================================================================== --- head/sys/dev/mmc/mmcreg.h (revision 170001) +++ head/sys/dev/mmc/mmcreg.h (revision 170002) @@ -1,326 +1,353 @@ /*- * Copyright (c) 2006 M. Warner Losh. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * Portions of this software may have been developed with reference to + * the SD Simplified Specification. The following disclaimer may apply: + * + * The following conditions apply to the release of the simplified + * specification ("Simplified Specification") by the SD Card Association and + * the SD Group. The Simplified Specification is a subset of the complete SD + * Specification which is owned by the SD Card Association and the SD + * Group. This Simplified Specification is provided on a non-confidential + * basis subject to the disclaimers below. Any implementation of the + * Simplified Specification may require a license from the SD Card + * Association, SD Group, SD-3C LLC or other third parties. + * + * Disclaimers: + * + * The information contained in the Simplified Specification is presented only + * as a standard specification for SD Cards and SD Host/Ancillary products and + * is provided "AS-IS" without any representations or warranties of any + * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD + * Card Association for any damages, any infringements of patents or other + * right of the SD Group, SD-3C LLC, the SD Card Association or any third + * parties, which may result from its use. No license is granted by + * implication, estoppel or otherwise under any patent or other rights of the + * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing + * herein shall be construed as an obligation by the SD Group, the SD-3C LLC + * or the SD Card Association to disclose or distribute any technical + * information, know-how or other confidential information to any third party. + * * $FreeBSD$ */ #ifndef DEV_MMC_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_R6 (MMC_RSP_PRESENT | MMC_RSP_CRC) /* R7 -- new in sd 2.0 */ #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 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_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 }; /* 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 /* reserved: 5 */ #define MMC_SELECT_CARD 7 #define MMC_DESELECT_CARD 7 #define MMC_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 /* reserved: 14 */ #define MMC_GO_INACTIVE_STATE 15 /* Class 2: Block oriented read commands */ #define MMC_SET_BLOCKLEN 16 #define MMC_READ_SINGLE_BLOCK 17 #define MMC_READ_MULTIPLE_BLOCK 18 /* reserved: 19 */ /* Class 3: Stream write commands */ #define MMC_WRITE_DAT_UNTIL_STOP 20 /* reserved: 21 */ /* 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 /* 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 /* 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_LOW_VOLTAGE (1u << 7) /* Low Voltage Range -- tbd */ #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_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; 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 sector_size; /* Erase sector size! */ 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; }; #endif /* DEV_MMCREG_H */ Index: head/sys/dev/mmc/mmcsd.c =================================================================== --- head/sys/dev/mmc/mmcsd.c (revision 170001) +++ head/sys/dev/mmc/mmcsd.c (revision 170002) @@ -1,278 +1,305 @@ /*- * Copyright (c) 2006 Bernd Walter. All rights reserved. * Copyright (c) 2006 M. Warner Losh. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Portions of this software may have been developed with reference to + * the SD Simplified Specification. The following disclaimer may apply: + * + * The following conditions apply to the release of the simplified + * specification ("Simplified Specification") by the SD Card Association and + * the SD Group. The Simplified Specification is a subset of the complete SD + * Specification which is owned by the SD Card Association and the SD + * Group. This Simplified Specification is provided on a non-confidential + * basis subject to the disclaimers below. Any implementation of the + * Simplified Specification may require a license from the SD Card + * Association, SD Group, SD-3C LLC or other third parties. + * + * Disclaimers: + * + * The information contained in the Simplified Specification is presented only + * as a standard specification for SD Cards and SD Host/Ancillary products and + * is provided "AS-IS" without any representations or warranties of any + * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD + * Card Association for any damages, any infringements of patents or other + * right of the SD Group, SD-3C LLC, the SD Card Association or any third + * parties, which may result from its use. No license is granted by + * implication, estoppel or otherwise under any patent or other rights of the + * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing + * herein shall be construed as an obligation by the SD Group, the SD-3C LLC + * or the SD Card Association to disclose or distribute any technical + * information, know-how or other confidential information to any third party. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mmcbus_if.h" struct mmcsd_softc { device_t dev; struct mtx sc_mtx; struct disk *disk; struct proc *p; struct bio_queue_head bio_queue; int running; }; #define MULTI_BLOCK_READ_BROKEN /* bus entry points */ static int mmcsd_probe(device_t dev); static int mmcsd_attach(device_t dev); static int mmcsd_detach(device_t dev); /* disk routines */ static int mmcsd_open(struct disk *dp); static int mmcsd_close(struct disk *dp); static void mmcsd_strategy(struct bio *bp); static void mmcsd_task(void *arg); #define MMCSD_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define MMCSD_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) #define MMCSD_LOCK_INIT(_sc) \ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \ "mmcsd", MTX_DEF) #define MMCSD_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); #define MMCSD_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); #define MMCSD_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); static int mmcsd_probe(device_t dev) { device_set_desc(dev, "mmc or sd flash card"); return (0); } static int mmcsd_attach(device_t dev) { struct mmcsd_softc *sc; sc = device_get_softc(dev); sc->dev = dev; MMCSD_LOCK_INIT(sc); sc->disk = disk_alloc(); sc->disk->d_open = mmcsd_open; sc->disk->d_close = mmcsd_close; sc->disk->d_strategy = mmcsd_strategy; // sc->disk->d_dump = mmcsd_dump; Need polling mmc layer sc->disk->d_name = "mmcsd"; sc->disk->d_drv1 = sc; sc->disk->d_maxsize = DFLTPHYS; sc->disk->d_sectorsize = mmc_get_sector_size(dev); sc->disk->d_mediasize = mmc_get_media_size(dev); sc->disk->d_unit = device_get_unit(dev); disk_create(sc->disk, DISK_VERSION); bioq_init(&sc->bio_queue); sc->running = 1; kthread_create(&mmcsd_task, sc, &sc->p, 0, 0, "task: mmc/sd card"); return (0); } static int mmcsd_detach(device_t dev) { struct mmcsd_softc *sc = device_get_softc(dev); /* kill thread */ MMCSD_LOCK(sc); sc->running = 0; wakeup(sc); MMCSD_UNLOCK(sc); /* wait for thread to finish. XXX probably want timeout. -sorbo */ MMCSD_LOCK(sc); while (sc->running != -1) msleep(sc, &sc->sc_mtx, PRIBIO, "detach", 0); MMCSD_UNLOCK(sc); /* kill disk */ disk_destroy(sc->disk); /* XXX destroy anything in queue */ MMCSD_LOCK_DESTROY(sc); return 0; } static int mmcsd_open(struct disk *dp) { return 0; } static int mmcsd_close(struct disk *dp) { return 0; } static void mmcsd_strategy(struct bio *bp) { struct mmcsd_softc *sc; sc = (struct mmcsd_softc *)bp->bio_disk->d_drv1; MMCSD_LOCK(sc); bioq_disksort(&sc->bio_queue, bp); wakeup(sc); MMCSD_UNLOCK(sc); } static void mmcsd_task(void *arg) { struct mmcsd_softc *sc = (struct mmcsd_softc*)arg; struct bio *bp; int sz; daddr_t block, end; struct mmc_command cmd; struct mmc_command stop; struct mmc_request req; struct mmc_data data; device_t dev; dev = sc->dev; while (sc->running) { MMCSD_LOCK(sc); do { bp = bioq_first(&sc->bio_queue); if (bp == NULL) msleep(sc, &sc->sc_mtx, PRIBIO, "jobqueue", 0); } while (bp == NULL && sc->running); if (bp) bioq_remove(&sc->bio_queue, bp); MMCSD_UNLOCK(sc); if (!sc->running) break; MMCBUS_ACQUIRE_BUS(device_get_parent(dev), dev); // printf("mmc_task: request %p for block %lld\n", bp, bp->bio_pblkno); sz = sc->disk->d_sectorsize; end = bp->bio_pblkno + (bp->bio_bcount / sz); // XXX should use read/write_mulit for (block = bp->bio_pblkno; block < end;) { char *vaddr = bp->bio_data + (block - bp->bio_pblkno) * sz; memset(&req, 0, sizeof(req)); memset(&cmd, 0, sizeof(cmd)); memset(&stop, 0, sizeof(stop)); req.cmd = &cmd; cmd.data = &data; if (bp->bio_cmd == BIO_READ) { #ifdef MULTI_BLOCK_READ if (end - block > 1) cmd.opcode = MMC_READ_MULTIPLE_BLOCK; else cmd.opcode = MMC_READ_SINGLE_BLOCK; #else cmd.opcode = MMC_READ_SINGLE_BLOCK; #endif } else cmd.opcode = MMC_WRITE_BLOCK; cmd.arg = block << 9; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; // data.timeout_ns = ; // data.timeout_clks = ; data.data = vaddr; data.mrq = &req; if (bp->bio_cmd == BIO_READ) { data.flags = MMC_DATA_READ; #ifdef MULTI_BLOCK_READ data.len = bp->bio_bcount; if (end - block > 1) { req.stop = &stop; data.flags |= MMC_DATA_MULTI; } printf("Len %d %lld-%lld flags %#x sz %d\n", data.len, block, end, data.flags, sz); block = end; #else data.len = sz; block++; #endif } else { data.flags = MMC_DATA_WRITE; data.len = sz; block++; } stop.opcode = MMC_STOP_TRANSMISSION; stop.arg = 0; stop.flags = MMC_RSP_R1B | MMC_CMD_AC; MMCBUS_WAIT_FOR_REQUEST(device_get_parent(dev), dev, &req); // XXX error handling //XXX while (!(mmc_send_status(dev) & R1_READY_FOR_DATA)) // continue; // XXX decode mmc status } MMCBUS_RELEASE_BUS(device_get_parent(dev), dev); biodone(bp); } /* tell parent we're done */ MMCSD_LOCK(sc); sc->running = -1; wakeup(sc); MMCSD_UNLOCK(sc); kthread_exit(0); } static device_method_t mmcsd_methods[] = { DEVMETHOD(device_probe, mmcsd_probe), DEVMETHOD(device_attach, mmcsd_attach), DEVMETHOD(device_detach, mmcsd_detach), {0, 0}, }; static driver_t mmcsd_driver = { "mmcsd", mmcsd_methods, sizeof(struct mmcsd_softc), }; static devclass_t mmcsd_devclass; DRIVER_MODULE(mmcsd, mmc, mmcsd_driver, mmcsd_devclass, 0, 0); Index: head/sys/dev/mmc/mmcvar.h =================================================================== --- head/sys/dev/mmc/mmcvar.h (revision 170001) +++ head/sys/dev/mmc/mmcvar.h (revision 170002) @@ -1,52 +1,79 @@ /*- * Copyright (c) 2006 Bernd Walter. All rights reserved. * Copyright (c) 2006 M. Warner Losh. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * Portions of this software may have been developed with reference to + * the SD Simplified Specification. The following disclaimer may apply: + * + * The following conditions apply to the release of the simplified + * specification ("Simplified Specification") by the SD Card Association and + * the SD Group. The Simplified Specification is a subset of the complete SD + * Specification which is owned by the SD Card Association and the SD + * Group. This Simplified Specification is provided on a non-confidential + * basis subject to the disclaimers below. Any implementation of the + * Simplified Specification may require a license from the SD Card + * Association, SD Group, SD-3C LLC or other third parties. + * + * Disclaimers: + * + * The information contained in the Simplified Specification is presented only + * as a standard specification for SD Cards and SD Host/Ancillary products and + * is provided "AS-IS" without any representations or warranties of any + * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD + * Card Association for any damages, any infringements of patents or other + * right of the SD Group, SD-3C LLC, the SD Card Association or any third + * parties, which may result from its use. No license is granted by + * implication, estoppel or otherwise under any patent or other rights of the + * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing + * herein shall be construed as an obligation by the SD Group, the SD-3C LLC + * or the SD Card Association to disclose or distribute any technical + * information, know-how or other confidential information to any third party. + * * "$FreeBSD$" */ #ifndef DEV_MMC_MMCVAR_H #define DEV_MMC_MMCVAR_H enum mmc_device_ivars { MMC_IVAR_DSR_IMP, MMC_IVAR_MEDIA_SIZE, MMC_IVAR_RCA, MMC_IVAR_SECTOR_SIZE, MMC_IVAR_TRAN_SPEED, // MMC_IVAR_, }; /* * Simplified accessors for pci devices */ #define MMC_ACCESSOR(var, ivar, type) \ __BUS_ACCESSOR(mmc, var, MMC, ivar, type) MMC_ACCESSOR(dsr_imp, DSR_IMP, int) MMC_ACCESSOR(media_size, MEDIA_SIZE, int) MMC_ACCESSOR(rca, RCA, int) MMC_ACCESSOR(sector_size, SECTOR_SIZE, int) MMC_ACCESSOR(tran_speed, TRAN_SPEED, int) #endif /* DEV_MMC_MMCVAR_H */