From owner-p4-projects@FreeBSD.ORG Sat Sep 30 00:36:55 2006 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id EA95B16A4EF; Sat, 30 Sep 2006 00:36:54 +0000 (UTC) X-Original-To: perforce@freebsd.org Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id C2A5016A412 for ; Sat, 30 Sep 2006 00:36:54 +0000 (UTC) (envelope-from imp@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id 663EC43D58 for ; Sat, 30 Sep 2006 00:36:52 +0000 (GMT) (envelope-from imp@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.6/8.13.6) with ESMTP id k8U0aqbp070979 for ; Sat, 30 Sep 2006 00:36:52 GMT (envelope-from imp@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.6/8.13.4/Submit) id k8U0apha070976 for perforce@freebsd.org; Sat, 30 Sep 2006 00:36:51 GMT (envelope-from imp@freebsd.org) Date: Sat, 30 Sep 2006 00:36:51 GMT Message-Id: <200609300036.k8U0apha070976@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to imp@freebsd.org using -f From: Warner Losh To: Perforce Change Reviews Cc: Subject: PERFORCE change 106924 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 30 Sep 2006 00:36:55 -0000 http://perforce.freebsd.org/chv.cgi?CH=106924 Change 106924 by imp@imp_lighthouse on 2006/09/30 00:36:29 SD 1.x cards now properly detected (1.x means standard capacity and not the newer SDHC or SD 2.0 high capacity cards). Affected files ... .. //depot/projects/arm/src/sys/dev/mmc/mmc.c#11 edit .. //depot/projects/arm/src/sys/dev/mmc/mmcreg.h#11 edit Differences ... ==== //depot/projects/arm/src/sys/dev/mmc/mmc.c#11 (text+ko) ==== @@ -52,8 +52,10 @@ struct mmc_ivars { uint32_t raw_cid[4]; /* Raw bits of the CID */ uint32_t raw_csd[4]; /* Raw bits of the CSD */ - struct mmc_cid cid; - struct mmc_csd 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 @@ -308,10 +310,23 @@ mmc_ms_delay(2); } -#if 0 +// 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 */ @@ -329,10 +344,25 @@ } } +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) { @@ -340,61 +370,114 @@ if (v == 0) { m = mmc_get_bits(raw_csd, 115, 4); e = mmc_get_bits(raw_csd, 112, 3); - csd->tacc = tacc_exp[e] * tacc_mant[m] + 9 / 10; + 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 = tran_exp[e] * tran_mant[m]; - + 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 - pacic("unknown SD CSD version"); + panic("unknown SD CSD version"); } else { panic("Write a MMC CSD parser"); } } -#endif + +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) { -#if 0 // XXX XXX XXX + struct mmc_ivars *ivar; + int err; + uint32_t resp; + while (1) { - err = mmc_all_send_cid(sc, &rca); - if (err == MMC_ERR_TIMEOUT) { - err = MMC_ERR_NONE; + ivar = malloc(sizeof(struct mmc_ivars), M_DEVBUF, M_WAITOK); + 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; } - card = find_card(sc, rca); - if (host->mode == MMC_MODE_SD) { - mmc_card_set_sd(card); - mmc_send_relative_addr(sc, 0); - card->rca = cmd.resp[0] >> 16; + 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", ivar->csd.capacity); break; } - // MMC XXX card detection - // set relative addr + panic("Write MMC card code here"); } -#endif } static void -mmc_read_csds(struct mmc_softc *sc) -{ -} - -static void -mmc_read_scrs(struct mmc_softc *sc) -{ -} - -static void mmc_go_discovery(struct mmc_softc *sc) { uint32_t ocr; @@ -427,17 +510,19 @@ * Make sure that we have a mutually agreeable voltage to at least * one card on the bus. */ - printf("Oink %x!\n", mmcbr_get_ocr(dev)); if (mmcbr_get_ocr(dev) == 0) return; - /* XXX Linux re-sends op_cond command here */ + /* + * 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); - mmc_read_csds(sc); - if (mmcbr_get_mode(dev) == mode_sd) - mmc_read_scrs(sc); } static int ==== //depot/projects/arm/src/sys/dev/mmc/mmcreg.h#11 (text+ko) ==== @@ -148,6 +148,7 @@ #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 @@ -248,12 +249,19 @@ /* 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 */ -/* Linux has defines for lower bits down to 0, which were defined in prior */ -/* specs to MMC 3.31. 3.31 redefined them to be reserved and also said that */ -/* cards had to support the 2.7-3.6V. */ +/* + * 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 */ @@ -289,18 +297,27 @@ struct mmc_csd { uint8_t csd_structure; - uint16_t cmdclass; + uint16_t ccc; uint16_t tacc; - uint32_t nsac_clks; + uint32_t nsac; uint32_t r2w_factor; uint32_t tran_speed; - uint32_t read_blkbits; - uint32_t write_blkbits; - uint32_t capacity; - unsigned int read_partial:1, - read_misalign:1, - write_partial:1, - write_misalign:1; + 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 */