Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 30 Sep 2006 00:36:51 GMT
From:      Warner Losh <imp@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 106924 for review
Message-ID:  <200609300036.k8U0apha070976@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200609300036.k8U0apha070976>