From owner-svn-src-all@FreeBSD.ORG Wed Oct 8 17:35:42 2008 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 2ADB610656B1; Wed, 8 Oct 2008 17:35:42 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id D26518FC1F; Wed, 8 Oct 2008 17:35:41 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id m98HZf6P039559; Wed, 8 Oct 2008 17:35:41 GMT (envelope-from mav@svn.freebsd.org) Received: (from mav@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id m98HZfoI039553; Wed, 8 Oct 2008 17:35:41 GMT (envelope-from mav@svn.freebsd.org) Message-Id: <200810081735.m98HZfoI039553@svn.freebsd.org> From: Alexander Motin Date: Wed, 8 Oct 2008 17:35:41 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r183704 - head/sys/dev/mmc X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 08 Oct 2008 17:35:42 -0000 Author: mav Date: Wed Oct 8 17:35:41 2008 New Revision: 183704 URL: http://svn.freebsd.org/changeset/base/183704 Log: Set of mmc layer improvements: - add MMC support. - add SDHC support. - add 4 and 8 bit bus width support. - add High Speed bus timing support. Modified: head/sys/dev/mmc/bridge.h head/sys/dev/mmc/mmc.c head/sys/dev/mmc/mmcbrvar.h head/sys/dev/mmc/mmcreg.h head/sys/dev/mmc/mmcsd.c head/sys/dev/mmc/mmcvar.h Modified: head/sys/dev/mmc/bridge.h ============================================================================== --- head/sys/dev/mmc/bridge.h Wed Oct 8 16:46:36 2008 (r183703) +++ head/sys/dev/mmc/bridge.h Wed Oct 8 17:35:41 2008 (r183704) @@ -104,6 +104,10 @@ enum mmc_bus_width { bus_width_1 = 0, bus_width_4 = 2, bus_width_8 = 3 }; +enum mmc_bus_timing { + bus_timing_normal = 0, bus_timing_hs +}; + 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/ */ @@ -111,6 +115,7 @@ struct mmc_ios { enum mmc_chip_select chip_select; enum mmc_bus_width bus_width; enum mmc_power_mode power_mode; + enum mmc_bus_timing timing; }; enum mmc_card_mode { @@ -125,6 +130,7 @@ struct mmc_host { uint32_t caps; #define MMC_CAP_4_BIT_DATA (1 << 0) /* Can do 4-bit data transfers */ #define MMC_CAP_8_BIT_DATA (1 << 1) /* Can do 8-bit data transfers */ +#define MMC_CAP_HSPEED (1 << 2) /* Can do High Speed transfers */ enum mmc_card_mode mode; struct mmc_ios ios; /* Current state of the host */ }; Modified: head/sys/dev/mmc/mmc.c ============================================================================== --- head/sys/dev/mmc/mmc.c Wed Oct 8 16:46:36 2008 (r183703) +++ head/sys/dev/mmc/mmc.c Wed Oct 8 17:35:41 2008 (r183704) @@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -82,11 +83,19 @@ struct mmc_softc { struct mmc_ivars { uint32_t raw_cid[4]; /* Raw bits of the CID */ uint32_t raw_csd[4]; /* Raw bits of the CSD */ + uint32_t raw_scr[2]; /* Raw bits of the SCR */ + uint8_t raw_ext_csd[512]; /* Raw bits of the EXT_CSD */ uint16_t rca; enum mmc_card_mode mode; struct mmc_cid cid; /* cid decoded */ struct mmc_csd csd; /* csd decoded */ + struct mmc_scr scr; /* scr decoded */ u_char read_only; /* True when the device is read-only */ + u_char bus_width; /* Bus width to use */ + u_char timing; /* Bus timing support */ + u_char high_cap; /* High Capacity card */ + uint32_t tran_speed; /* Max speed in normal mode */ + uint32_t hs_tran_speed; /* Max speed in high speed mode */ }; #define CMD_RETRIES 3 @@ -111,6 +120,11 @@ static int mmc_wait_for_cmd(struct mmc_s int retries); static int mmc_wait_for_command(struct mmc_softc *sc, uint32_t opcode, uint32_t arg, uint32_t flags, uint32_t *resp, int retries); +static int mmc_select_card(struct mmc_softc *sc, uint16_t rca); +static int mmc_set_bus_width(struct mmc_softc *sc, uint16_t rca, int width); +static int mmc_app_send_scr(struct mmc_softc *sc, uint16_t rca, uint32_t *rawscr); +static void mmc_app_decode_scr(uint32_t *raw_scr, struct mmc_scr *scr); +static int mmc_send_ext_csd(struct mmc_softc *sc, uint8_t *rawextcsd); static void mmc_ms_delay(int ms) @@ -173,6 +187,7 @@ static int mmc_acquire_bus(device_t busdev, device_t dev) { struct mmc_softc *sc; + struct mmc_ivars *ivar; int err; int rca; @@ -195,21 +210,26 @@ mmc_acquire_bus(device_t busdev, device_ */ 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); + mmc_select_card(sc, rca); sc->last_rca = rca; + /* Prepare bus width for the new card. */ + ivar = device_get_ivars(dev); + device_printf(busdev, + "setting bus width to %d bits\n", + (ivar->bus_width == bus_width_4)?4: + (ivar->bus_width == bus_width_8)?8:1); + mmc_set_bus_width(sc, rca, ivar->bus_width); + mmcbr_set_bus_width(busdev, ivar->bus_width); + mmcbr_update_ios(busdev); } - /* 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); + mmc_select_card(sc, 0); sc->last_rca = 0; } - /* XXX should set bus width here? */ } return (0); @@ -444,6 +464,22 @@ mmc_send_op_cond(struct mmc_softc *sc, u 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, &cmd, CMD_RETRIES); + return (err); +} + static void mmc_power_up(struct mmc_softc *sc) { @@ -460,6 +496,7 @@ mmc_power_up(struct mmc_softc *sc) mmc_ms_delay(1); mmcbr_set_clock(dev, mmcbr_get_f_min(sc->dev)); + mmcbr_set_timing(dev, bus_timing_normal); mmcbr_set_power_mode(dev, power_on); mmcbr_update_ios(dev); mmc_ms_delay(2); @@ -475,9 +512,207 @@ mmc_power_down(struct mmc_softc *sc) 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) +{ + return (mmc_wait_for_command(sc, MMC_SELECT_CARD, ((uint32_t)rca) << 16, + MMC_RSP_R1B | MMC_CMD_AC, NULL, CMD_RETRIES)); +} + +static int +mmc_switch(struct mmc_softc *sc, uint8_t set, uint8_t index, uint8_t value) +{ + struct mmc_command cmd; + int err; + + cmd.opcode = MMC_SWITCH_FUNC; + cmd.arg = (MMC_SWITCH_FUNC_WR << 24) | + (index << 16) | + (value << 8) | + set; + cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + cmd.data = NULL; + err = mmc_wait_for_cmd(sc, &cmd, 0); + 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(struct mmc_command)); + memset(&data, 0, sizeof(struct mmc_data)); + + memset(res, 0, 64); + cmd.opcode = SD_SWITCH_FUNC; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + cmd.arg = mode << 31; + cmd.arg |= 0x00FFFFFF; + cmd.arg &= ~(0xF << grp); + cmd.arg |= value << grp; + cmd.data = &data; + + data.data = res; + data.len = 64; + data.flags = MMC_DATA_READ; + + err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); + return (err); +} + +static int +mmc_set_bus_width(struct mmc_softc *sc, uint16_t rca, int width) +{ + int err; + + if (mmcbr_get_mode(sc->dev) == mode_sd) { + struct mmc_command cmd; + + memset(&cmd, 0, sizeof(struct mmc_command)); + cmd.opcode = ACMD_SET_BUS_WIDTH; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + switch (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, rca, &cmd, CMD_RETRIES); + } else { + uint8_t value; + + switch (width) { + case bus_width_1: + value = EXT_CSD_BUS_WIDTH_1; + break; + case bus_width_4: + value = EXT_CSD_BUS_WIDTH_4; + break; + case bus_width_8: + value = EXT_CSD_BUS_WIDTH_8; + break; + default: + return (MMC_ERR_INVALID); + } + err = mmc_switch(sc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, value); + } + return (err); +} + +static int +mmc_set_timing(struct mmc_softc *sc, int timing) +{ + int err; + uint8_t value; + + switch (timing) { + case bus_timing_normal: + value = 0; + break; + case bus_timing_hs: + value = 1; + break; + default: + return (MMC_ERR_INVALID); + } + if (mmcbr_get_mode(sc->dev) == mode_sd) { + u_char switch_res[64]; + + err = mmc_sd_switch(sc, 1, 0, value, switch_res); + } else { + err = mmc_switch(sc, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_HS_TIMING, value); + } + return (err); +} + +static int +mmc_test_bus_width(struct mmc_softc *sc) +{ + struct mmc_command cmd; + struct mmc_data data; + int err; + uint8_t buf[8]; + uint8_t p8[8] = { 0x55, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t p8ok[8] = { 0xAA, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t p4[4] = { 0x5A, 0x00, 0x00, 0x00, }; + uint8_t p4ok[4] = { 0xA5, 0x00, 0x00, 0x00, }; + + 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); + + cmd.opcode = MMC_BUSTEST_W; + cmd.arg = 0; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + cmd.data = &data; + + data.data = p8; + data.len = 8; + data.flags = MMC_DATA_WRITE; + mmc_wait_for_cmd(sc, &cmd, 0); + + 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, &cmd, 0); + + 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); + + cmd.opcode = MMC_BUSTEST_W; + cmd.arg = 0; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + cmd.data = &data; + + data.data = p4; + data.len = 4; + data.flags = MMC_DATA_WRITE; + mmc_wait_for_cmd(sc, &cmd, 0); + + 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, &cmd, 0); + + 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 start, int size) { @@ -506,8 +741,14 @@ mmc_decode_cid(int is_sd, uint32_t *raw_ 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"); + cid->mid = mmc_get_bits(raw_cid, 120, 8); + cid->oid = mmc_get_bits(raw_cid, 104, 8); + for (i = 0; i < 6; i++) + cid->pnm[i] = mmc_get_bits(raw_cid, 96 - i * 8, 8); + cid->prv = mmc_get_bits(raw_cid, 48, 8); + cid->psn = mmc_get_bits(raw_cid, 16, 32); + cid->mdt_month = mmc_get_bits(raw_cid, 12, 4); + cid->mdt_year = mmc_get_bits(raw_cid, 8, 4) + 1997; } } @@ -563,12 +804,82 @@ mmc_decode_csd(int is_sd, uint32_t *raw_ 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"); + 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->capacity = ((uint64_t)mmc_get_bits(raw_csd, 48, 22) + 1) * + 512 * 1024; + 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 panic("unknown SD CSD version"); } else { - panic("Write a MMC CSD parser"); + csd->csd_structure = mmc_get_bits(raw_csd, 126, 2); + csd->spec_vers = mmc_get_bits(raw_csd, 122, 4); + 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, 5); + 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); + } +} + +static void +mmc_app_decode_scr(uint32_t *raw_scr, struct mmc_scr *scr) +{ + unsigned int scr_struct; + uint32_t tmp[4]; + + tmp[3] = raw_scr[1]; + tmp[2] = raw_scr[0]; + + memset(scr, 0, sizeof(*scr)); + + scr_struct = mmc_get_bits(tmp, 60, 4); + if (scr_struct != 0) { + printf("Unrecognised SCR structure version %d\n", + scr_struct); + return; } + scr->sda_vsn = mmc_get_bits(tmp, 56, 4); + scr->bus_widths = mmc_get_bits(tmp, 48, 4); } static int @@ -602,6 +913,70 @@ mmc_send_csd(struct mmc_softc *sc, uint1 } 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(struct mmc_command)); + memset(&data, 0, sizeof(struct mmc_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, rca, &cmd, CMD_RETRIES); + rawscr[0] = be32toh(rawscr[0]); + rawscr[1] = be32toh(rawscr[1]); + return (err); +} + +static int +mmc_send_ext_csd(struct mmc_softc *sc, uint8_t *rawextcsd) +{ + int err; + struct mmc_command cmd; + struct mmc_data data; + + memset(&cmd, 0, sizeof(struct mmc_command)); + memset(&data, 0, sizeof(struct mmc_data)); + + memset(rawextcsd, 0, 512); + cmd.opcode = MMC_SEND_EXT_CSD; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + cmd.arg = 0; + cmd.data = &data; + + data.data = rawextcsd; + data.len = 512; + data.flags = MMC_DATA_READ; + + err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); + return (err); +} + +static int +mmc_set_relative_addr(struct mmc_softc *sc, uint16_t resp) +{ + struct mmc_command cmd; + int err; + + 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, &cmd, 0); + return (err); +} + +static int mmc_send_relative_addr(struct mmc_softc *sc, uint32_t *resp) { struct mmc_command cmd; @@ -623,6 +998,8 @@ mmc_discover_cards(struct mmc_softc *sc) int err; uint32_t resp; device_t child; + uint16_t rca = 2; + u_char switch_res[64]; while (1) { ivar = malloc(sizeof(struct mmc_ivars), M_DEVBUF, @@ -636,22 +1013,75 @@ mmc_discover_cards(struct mmc_softc *sc) device_printf(sc->dev, "Error reading CID %d\n", err); break; } - if (mmcbr_get_mode(sc->dev) == mode_sd) { - ivar->mode = mode_sd; + if (mmcbr_get_ro(sc->dev)) + ivar->read_only = 1; + ivar->bus_width = bus_width_1; + ivar->mode = mmcbr_get_mode(sc->dev); + if (ivar->mode == mode_sd) { mmc_decode_cid(1, ivar->raw_cid, &ivar->cid); mmc_send_relative_addr(sc, &resp); ivar->rca = resp >> 16; - if (mmcbr_get_ro(sc->dev)) - ivar->read_only = 1; + /* Get card CSD. */ 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); + if (ivar->csd.csd_structure > 0) + ivar->high_cap = 1; + ivar->tran_speed = ivar->csd.tran_speed; + /* Get card SCR. Card must be selected to fetch it. */ + mmc_select_card(sc, ivar->rca); + mmc_app_send_scr(sc, ivar->rca, ivar->raw_scr); + mmc_app_decode_scr(ivar->raw_scr, &ivar->scr); + /* Get card switch capabilities. */ + if ((ivar->scr.sda_vsn >= 1) && + (ivar->csd.ccc & (1<<10))) { + mmc_sd_switch(sc, 0, 0, 0xF, switch_res); + if (switch_res[13] & 2) { + ivar->timing = bus_timing_hs; + ivar->hs_tran_speed = 50000000; + } + } + mmc_select_card(sc, 0); + /* Find max supported bus width. */ + if ((mmcbr_get_caps(sc->dev) & MMC_CAP_4_BIT_DATA) && + (ivar->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) + ivar->bus_width = bus_width_4; + /* Add device. */ child = device_add_child(sc->dev, NULL, -1); device_set_ivars(child, ivar); return; } - panic("Write MMC card code here"); + mmc_decode_cid(0, ivar->raw_cid, &ivar->cid); + ivar->rca = rca++; + mmc_set_relative_addr(sc, ivar->rca); + /* Get card CSD. */ + mmc_send_csd(sc, ivar->rca, ivar->raw_csd); + mmc_decode_csd(0, ivar->raw_csd, &ivar->csd); + ivar->tran_speed = ivar->csd.tran_speed; + /* Only MMC >= 4.x cards support EXT_CSD. */ + if (ivar->csd.spec_vers >= 4) { + /* Card must be selected to fetch EXT_CSD. */ + mmc_select_card(sc, ivar->rca); + mmc_send_ext_csd(sc, ivar->raw_ext_csd); + /* Get card speed in high speed mode. */ + ivar->timing = bus_timing_hs; + if (((uint8_t *)(ivar->raw_ext_csd))[EXT_CSD_CARD_TYPE] + & EXT_CSD_CARD_TYPE_52) + ivar->hs_tran_speed = 52000000; + else if (((uint8_t *)(ivar->raw_ext_csd))[EXT_CSD_CARD_TYPE] + & EXT_CSD_CARD_TYPE_26) + ivar->hs_tran_speed = 26000000; + else + ivar->hs_tran_speed = ivar->tran_speed; + /* Find max supported bus width. */ + ivar->bus_width = mmc_test_bus_width(sc); + mmc_select_card(sc, 0); + } else { + ivar->bus_width = bus_width_1; + ivar->timing = bus_timing_normal; + } + /* Add device. */ + child = device_add_child(sc->dev, NULL, -1); + device_set_ivars(child, ivar); } free(ivar, M_DEVBUF); } @@ -661,6 +1091,7 @@ 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) { @@ -671,7 +1102,9 @@ mmc_go_discovery(struct mmc_softc *sc) 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) { + err = mmc_send_if_cond(sc, 1); + if (mmc_send_app_op_cond(sc, err?0:MMC_OCR_CCS, &ocr) != + MMC_ERR_NONE) { /* * Failed, try MMC */ @@ -697,9 +1130,11 @@ mmc_go_discovery(struct mmc_softc *sc) /* * 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 + 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, mmcbr_get_ocr(dev), NULL); mmc_discover_cards(sc); @@ -712,22 +1147,47 @@ mmc_go_discovery(struct mmc_softc *sc) static int mmc_calculate_clock(struct mmc_softc *sc) { - int max_dtr = 0; + int max_dtr, max_hs_dtr, max_timing; int nkid, i, f_min, f_max; device_t *kids; + struct mmc_ivars *ivar; f_min = mmcbr_get_f_min(sc->dev); f_max = mmcbr_get_f_max(sc->dev); - max_dtr = f_max; + max_dtr = max_hs_dtr = f_max; + if ((mmcbr_get_caps(sc->dev) & MMC_CAP_HSPEED)) + max_timing = bus_timing_hs; + else + max_timing = bus_timing_normal; 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]); + for (i = 0; i < nkid; i++) { + ivar = device_get_ivars(kids[i]); + if (ivar->timing < max_timing) + max_timing = ivar->timing; + if (ivar->tran_speed < max_dtr) + max_dtr = ivar->tran_speed; + if (ivar->hs_tran_speed < max_dtr) + max_hs_dtr = ivar->hs_tran_speed; + } + for (i = 0; i < nkid; i++) { + ivar = device_get_ivars(kids[i]); + if (ivar->timing == bus_timing_normal) + continue; + mmc_select_card(sc, ivar->rca); + mmc_set_timing(sc, max_timing); + } + mmc_select_card(sc, 0); free(kids, M_TEMP); - device_printf(sc->dev, "setting transfer rate to %d.%03dMHz\n", - max_dtr / 1000000, (max_dtr / 1000) % 1000); - return (max_dtr); + if (max_timing == bus_timing_hs) + max_dtr = max_hs_dtr; + device_printf(sc->dev, "setting transfer rate to %d.%03dMHz%s\n", + max_dtr / 1000000, (max_dtr / 1000) % 1000, + (max_timing == bus_timing_hs)?" with high speed timing":""); + mmcbr_set_timing(sc->dev, max_timing); + mmcbr_set_clock(sc->dev, max_dtr); + mmcbr_update_ios(sc->dev); + return max_dtr; } static void @@ -741,8 +1201,7 @@ mmc_scan(struct mmc_softc *sc) 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_calculate_clock(sc); mmc_release_bus(dev, dev); /* XXX probe/attach/detach children? */ @@ -774,6 +1233,9 @@ mmc_read_ivar(device_t bus, device_t chi case MMC_IVAR_READ_ONLY: *(int *)result = ivar->read_only; break; + case MMC_IVAR_HIGH_CAP: + *(int *)result = ivar->high_cap; + break; } return (0); } Modified: head/sys/dev/mmc/mmcbrvar.h ============================================================================== --- head/sys/dev/mmc/mmcbrvar.h Wed Oct 8 16:46:36 2008 (r183703) +++ head/sys/dev/mmc/mmcbrvar.h Wed Oct 8 17:35:41 2008 (r183704) @@ -71,6 +71,7 @@ enum mmcbr_device_ivars { MMCBR_IVAR_POWER_MODE, MMCBR_IVAR_VDD, MMCBR_IVAR_CAPS, + MMCBR_IVAR_TIMING, // MMCBR_IVAR_, }; @@ -92,6 +93,7 @@ MMCBR_ACCESSOR(ocr, OCR, int) MMCBR_ACCESSOR(power_mode, POWER_MODE, int) MMCBR_ACCESSOR(vdd, VDD, int) MMCBR_ACCESSOR(caps, CAPS, int) +MMCBR_ACCESSOR(timing, TIMING, int) static int __inline mmcbr_update_ios(device_t dev) Modified: head/sys/dev/mmc/mmcreg.h ============================================================================== --- head/sys/dev/mmc/mmcreg.h Wed Oct 8 16:46:36 2008 (r183703) +++ head/sys/dev/mmc/mmcreg.h Wed Oct 8 17:35:41 2008 (r183704) @@ -86,7 +86,7 @@ struct mmc_command { #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_R7 (MMC_RSP_PRESENT | MMC_RSP_CRC) #define MMC_RSP(x) ((x) & MMC_RSP_MASK) uint32_t retries; uint32_t error; @@ -181,16 +181,23 @@ struct mmc_request { #define SD_SEND_RELATIVE_ADDR 3 #define MMC_SET_DSR 4 /* reserved: 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_IF_COND 8 +#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 - /* reserved: 14 */ +#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 @@ -277,6 +284,37 @@ struct mmc_request { #define ACMD_SET_CLR_CARD_DETECT 42 #define ACMD_SEND_SCR 51 +/* + * EXT_CSD fields + */ + +#define EXT_CSD_BUS_WIDTH 183 /* R/W */ +#define EXT_CSD_HS_TIMING 185 /* R/W */ +#define EXT_CSD_CARD_TYPE 196 /* RO */ +#define EXT_CSD_REV 192 /* RO */ +#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ + +/* + * EXT_CSD field definitions + */ + +#define EXT_CSD_CMD_SET_NORMAL 1 +#define EXT_CSD_CMD_SET_SECURE 2 +#define EXT_CSD_CMD_SET_CPSECURE 4 + +#define EXT_CSD_CARD_TYPE_26 1 +#define EXT_CSD_CARD_TYPE_52 2 + +#define EXT_CSD_BUS_WIDTH_1 0 +#define EXT_CSD_BUS_WIDTH_4 1 +#define EXT_CSD_BUS_WIDTH_8 2 + +/* + * SD bus widths + */ +#define SD_BUS_WIDTH_1 0 +#define SD_BUS_WIDTH_4 2 + /* OCR bits */ /* @@ -328,6 +366,7 @@ struct mmc_cid { struct mmc_csd { uint8_t csd_structure; + uint8_t spec_vers; uint16_t ccc; uint16_t tacc; uint32_t nsac; @@ -351,6 +390,14 @@ struct mmc_csd 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) +}; + /* * 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 Modified: head/sys/dev/mmc/mmcsd.c ============================================================================== --- head/sys/dev/mmc/mmcsd.c Wed Oct 8 16:46:36 2008 (r183703) +++ head/sys/dev/mmc/mmcsd.c Wed Oct 8 17:35:41 2008 (r183704) @@ -106,6 +106,7 @@ static int mmcsd_probe(device_t dev) { + device_quiet(dev); device_set_desc(dev, "MMC/SD Memory Card"); return (0); } @@ -256,7 +257,9 @@ mmcsd_task(void *arg) else cmd.opcode = MMC_WRITE_BLOCK; } - cmd.arg = block << 9; + cmd.arg = block; + if (!mmc_get_high_cap(dev)) + cmd.arg <<= 9; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; data.data = vaddr; data.mrq = &req; Modified: head/sys/dev/mmc/mmcvar.h ============================================================================== --- head/sys/dev/mmc/mmcvar.h Wed Oct 8 16:46:36 2008 (r183703) +++ head/sys/dev/mmc/mmcvar.h Wed Oct 8 17:35:41 2008 (r183704) @@ -62,6 +62,7 @@ enum mmc_device_ivars { MMC_IVAR_SECTOR_SIZE, MMC_IVAR_TRAN_SPEED, MMC_IVAR_READ_ONLY, + MMC_IVAR_HIGH_CAP, // MMC_IVAR_, }; @@ -77,5 +78,6 @@ MMC_ACCESSOR(rca, RCA, int) MMC_ACCESSOR(sector_size, SECTOR_SIZE, int) MMC_ACCESSOR(tran_speed, TRAN_SPEED, int) MMC_ACCESSOR(read_only, READ_ONLY, int) +MMC_ACCESSOR(high_cap, HIGH_CAP, int) #endif /* DEV_MMC_MMCVAR_H */