PERFORCE change 106924 for review
Warner Losh
imp at FreeBSD.org
Fri Sep 29 17:36:55 PDT 2006
http://perforce.freebsd.org/chv.cgi?CH=106924
Change 106924 by imp at 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 */
More information about the p4-projects
mailing list